這次主要是為了看我們的OGLES driver里為什么會malloc的比mali多存捺,dumpheap發(fā)現(xiàn)排名靠前的都是與texture有關(guān)的,我記得是glTexImage2D和glTexSubImage。里面是為了Mipmap臨時malloc了system memory忱叭,但是誰知道后面會不會再用?不敢輕易free。OGL ES API我也不熟移稳,怎么也得系統(tǒng)的看看。
- 描述一下接口層的定義会油,spec和書籍會有
- 再看driver code里重點(diǎn)實(shí)現(xiàn)个粱。
書籍參考OpenGL ES 3.0 Programming Guide, www.java.1234.com可以下載,電子版翻翩,帶目錄都许。
這本書的中文版有點(diǎn)問題,他翻譯的太多了嫂冻,且不給英文原文胶征,違和感很強(qiáng)。比如在書里看了統(tǒng)一變量桨仿,上下文睛低,片段著色器,繪圖表面的知識服傍,再看代碼钱雷,卻很難在看到Uniform,context吹零,fragment shader罩抗,surface時找到共鳴。
直接看英文書又太難瘪校,還是先看了中文熟悉基本的概念澄暮,再看英文,好看一點(diǎn)阱扬。
EGL API序列:
前面的API都是給狀態(tài)泣懊,狀態(tài)保存在glContext,只有Draw才會真正讓GPU做事情麻惶,所有的draw API都會走到DrawPrimitive()馍刮,后面的Begin() => ValidateAttribute()可以看到所有的過程:
- Validate Input Assembler (IA)
- Validate Vertex Shader (VS)
- Validate Rasterization (RS)
- ValidateZlxStage1 (ZL1)
- Validate pixel shader (PS)
- Vlidate output merger (OM)
- Validate ZLx stage2 (ZL2)
上述比如vbInfo,都是保存在glContext里面的
開始是EGL調(diào)用窃蹋,EGL提供了下面的機(jī)制:
- communication with native windowing system
- query available configurations of drawing surfaces
- create drawing surface
- managing rendering resources such as texture maps
eglGetDisplay(EGL_DEFAULT_DISPLAY)=display_0;
- API : EGLDisplay eglGetDisplay(EGLNativeDisplayType displayId)
its open a connection to EGL display server, EGLNativeDisplayType is defined to match the native window system's display type. - Dirver:
EGLNativeDisplayType就是typedef int卡啰,EGL_DEFAULT_DISPLAY就是((EGLNativeDisplayType)0),而已静稻。
driver會創(chuàng)建一個_EGLdisplay *pDpy,return的是pDpy->hDpy匈辱,也就是一個handle振湾。
新創(chuàng)建的pDpy添加到了DIsplayList,這是一個__eglGlobal.pDpyList亡脸,上面的handle也在__eglGlobal維護(hù)的.
eglGlobal是一個全局的結(jié)構(gòu)體變量押搪。在attachProcess() => __eglInitGlobals() 時被init,這個函數(shù)應(yīng)該是整個EGL.so第一個被觸發(fā)的地方浅碾,誰觸發(fā)的大州?
這里寫的有問題,最早的應(yīng)該是InitDriver()而不是attachProcess()垂谢,進(jìn)而__glDpInitialization() => InitDriver()
后續(xù)的egl函數(shù)都要傳一個display過去厦画。
eglInitialize(display_0, NULL, NULL);
- API: EGLBoolean eglInitialize(EGLDisplay display, EGLint *majorVertion, EGLint *minorVertsion)
display : EGL display connection
這個函數(shù)是init EGL's internal data structures - driver:
前面說過,eglGlobal維護(hù)了pDpy的鏈表滥朱,現(xiàn)在按照hDpy找到它并取出來根暑。
這里做的事情不少,init configs tables, load es1/2 driver焚虱。
這里還填了dDpy->esDriverAPI[__EGL_ES_VETSION_2_X].createDisplay的函數(shù)指針购裙,然后調(diào)用其createDisplay()懂版,返回值保存在pDpy->esPrivateData[2_X]鹃栽,這里的函數(shù)指針都是eglXXX。也就是eglXXX前面多了下劃線躯畴。
在eglCreateDisplay()民鼓,創(chuàng)建了_EGLdisplayPrivate,返回后保存在pDpy->esPrivateData[2_x]里面蓬抄,
DEFINE POINTER name=attrib_list_0, type=egl_attrib_list, count=0, data=imm{EGL_RENDERABLE_TYPE=EGL_OPENGL_ES2_BIT, EGL_RED_SIZE=8, EGL_GREEN_SIZE=8, EGL_BLUE_SIZE=8, EGL_ALPHA_SIZE=8, EGL_DEPTH_SIZE=0, EGL_CONFIG_CAVEAT=EGL_NONE, EGL_STENCIL_SIZE=8, EGL_SURFACE_TYPE=EGL_WINDOW_BIT, EGL_NONE};
eglChooseConfig(display_0, attrib_list_0, configs_0, 1, pointer_0);
- API: 通過提供的attrib_list丰嘉,得到1個合適的EGLConfig
可以看到,AP需要的是 RGBA8888的rendering surface嚷缭,沒有depth buffer, 有stencil buffer饮亏。需要的surface type是window。 - driver:
上一步已經(jīng)創(chuàng)建好了pDpy->pConfigList阅爽,與傳入的attri_list作比較路幸,返回合適的。
eglCreateContext(display_0, configs_0[0], EGL_NO_CONTEXT, attrib_list_1)=context_0; //0x3
- API: rendering context is a data structure internal to OGLES that contains all of state info required for operation.for example, it contains references to vertex and fragment shaders and array of vertex data.
context保存了所有狀態(tài)付翁,比如vertex,fragment shaders, vertex數(shù)組简肴。 - Driver:
重要的部分還是在gl里面,egl層只是保存了個pCtx->privateData百侧,gl下glContext保存在其pCtx->privateData砰识。
DEFINE POINTER name=attrib_list_2, type=egl_attrib_list, count=0, data=imm{EGL_WIDTH=1, EGL_HEIGHT=1, EGL_NONE};
eglCreatePbufferSurface(display_0, configs_0[0], attrib_list_2)=surface_0;
- API:you can render into nonvisible off-screen surface called pbuffers(pixel buffer). is often used for generating texture maps 紋理貼圖. if render to a texture we recommend using frambuffer objects instead of pbuffers because they are more efficient.
但是pbuffer仍然有用能扒,比如在OES做offscreen surface render然后再OpenVG等其他API用這個texture.
這里給的attrib_list的寬高是1,得到一個surface_0 - Driver:
driver中surface對應(yīng)的是EGLdrawable *pDraw辫狼,同樣保存在eglGlobal里初斑,其鏈表叫pDrawList。同樣調(diào)用gl的__eglCreateDrawable()膨处,把gl創(chuàng)建的Drawable保存在pDraw->esPrivateData.
gl中創(chuàng)建的是EGLdrwablePrivate *pDraw越平,他似乎只是個外殼,_GLdrawablePrivate *glPriv才是重要的灵迫,最重要的是通過Elte層的createDrawable創(chuàng)建的drawable保存在了glPriv->dp.privateData秦叛,dp是GLdrawablePrivateRec,賦值了很多函數(shù)指針瀑粥,其中有一個是_glUpdateDrawableAllocation(glPriv, glPriv->da)挣跋,通過他create_renderbuffer真正的創(chuàng)建 buffer,不過只有置了PBUFFER_BIT才會在這個時候創(chuàng)建狞换,正常都是在__glNotifyChangeDrawableSize()時才做的避咆。
eglMakeCurrent(display_0, surface_0, surface_0, context_0);
- API:
AP may create multiple EGLContext for various purposes, we need a way to associate a EGLContext with rendering surface : make current - Driver:
做EGLcontext與EGLdrawable的綁定,這里會調(diào)用gl層的__eglUpdateDrawable()修噪,比較的是glPriv與da的寬高等是否相等查库。glPriv的寬高是在createDrawable時拿的,da的寬高是在updateDrawableAllocation()時拿的黄琼,也就是說樊销,MakeCurrent時重新同步的一下寬高等信息,平時NotifyChangeDrawableSize()也會更新脏款。記得围苫,glPriv就是_GLdrawablePrivate
這里的代碼現(xiàn)在看也覺得很亂,后面再補(bǔ)充撤师。至此剂府,EGL調(diào)用做完了,本地環(huán)境有了剃盾,開始調(diào)用GL API.
GL ES API序列:
Vertex:
DEFINE POINTER name=buffer_0, type=uint, count=1, data=imm{null};
glGenBuffers(1, buffer_0);
API : its about Vertex Buffer Object
通過vertex arrays指定的vertex data保存在client memory腺占,在調(diào)用glDrawArrays/DrawElements時必須保證這些data從client memory復(fù)制到了graphics memory。但是痒谴,不需要每次draw call都copy vertex data的衰伯,一直cache data in graphics memory更好。這就是vertex buffer objects的目的闰歪。
Vertex buffer objects 允許AP從graphics memory去allocate和cache vertex data嚎研,并從這個memory 去render,從而避免每次畫primitive時都要resending data。
不只是vertex data, 描述primitive vertex indices的element indices临扮,作為glDrawElements的arg论矾,也可以cached在這個memory。
OGLES 3.0支持兩種buffer object:
- vertex : array buffer objects, GL_ARRAY_BUFFER杆勇,store vertex data.
- primitive data: element array buffer objects贪壳,GL_ELEMENT_ARRAY_BUFFER,store indices of a primitive.
glBindBuffer(GL_ARRAY_BUFFER, buffer_0[0]);
DEFINE POINTER name=buffer_1, type=ubyte, count=64, file_offset=0, data=file{combine_0.bin};
glBufferData(GL_ARRAY_BUFFER, 64, buffer_1, GL_STATIC_DRAW);
- API: data argu can be NULL, indicating that reserved data store remains uninitialized.
if data is valid pointer, contens of data are copied to allocated data store. - Driver:
首先要拿到__GLbufferObject bufObj蚜退,根據(jù)其targetIndex(如ARRAY_BUFFER_INDEX, ELEMENT_ARRAY_BUFFER_INDEX)闰靴,從gc->bufferObject.generalBindingPoint[index].boundBufObj拿,這個變量應(yīng)該是在glBindBuffer的時候賦值的钻注。
得到BufObj和data蚂且,在Elite層的BufferData => V ertexBufferUpload()里做blt,src自然是data幅恋,因?yàn)樗麃碜詓ystem memory杏死,所以要填到createData.pPreAllocPackedInfo.pSysMem,然后為其rmCreateResource()捆交。dst就是bufobj->VertexbufferInfo *vbInfo->eltResource->rmResource淑翼。vbInfo的resource是什么時候創(chuàng)建的?
然后做blit品追,rmBufferBlt()里通過rmiCanBuf2dBlt()檢查是否只能用cpublt玄括,因?yàn)橛蠵OOL_SYSTEMMEM,所以是必須走CPUblt
CPUblt里肉瓦,先把src遭京,dst的Data lock出來,然后memcpy(dst, src, copyBytes)
對于usage=GL_STATIC_DRAW风宁,driver里面不care洁墙。
glEnableVertexAttribArray(0x0);
- API: 入?yún)ndex指generic vertex attribute index.
AP通過它指定use either constant data or data from vertex array. - Driver: 在pVertexArrayState->arrayEnabled置位了相應(yīng)的bit。
這里我已經(jīng)不明確什么是vertex arribute array了戒财,要看看OpenGL編程指南。
這里有個例子也許有幫助:
//Example 6-3 Using Constant and Vertex Array Attributes
int Init ( ESContext *esContext )
{
UserData *userData = (UserData*) esContext->userData;
const char vShaderStr[] =
"#version 300 es \n"
"layout(location = 0) in vec4 a_color; \n"
"layout(location = 1) in vec4 a_position; \n"
"out vec4 v_color; \n"
"void main() \n"
"{ v_color = a_color; \n"
" gl_Position = a_position; }\n" ;
const char fShaderStr[] =
"#version 300 es \n"
"precision mediump float; \n"
"in vec4 v_color; \n"
"out vec4 o_fragColor; \n"
"void main() \n"
"{ o_fragColor = v_color; \n } " ;
GLuint programObject;
//Create program object;
programObject = esLoadProgram(vShaderStr, fShaderStr);
if(programObject == 0) return GL_FALSE;
//Store program object
userData->programObject = programObject;
glClearColor(0.0f, 0.0f, .0.0f, 0.0f );
return GL_TRUE;
}
void Draw(ESCOntext *esContext)
{
UserData *userData = (UserData*)esContext->userData;
GLfloat color[4] = {1.0f, 0.0f, 0.0f, 1.0f};
//3 vertices, with(x,y,z)per-vertex
GLfloat vertexPos[3*3] =
{ 0.0f,0.5f,0.0f, //v0
-0.5f,-0.5f,0.0f, //v1
0.5f,-0.5f,0.0f //v2
};
glViewport(0, 0, esContext->width, esContext->height);
//
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(userData->programObject);
glVertexAttrib4fb(0, color);
glVettexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, vertexPos);
glEnableVertexAttribArray(1);
glDrawArrays(GL_TRANINGES, 0 ,3);
glDisplayVertexAttribArray(1);
}
vertex attribute:color捺弦,用glVertexAttrib4fb指定一個常量饮寞,沒有enable vertex attribute array 0。
vertexPos這個attribute,通過glVertexAttribPointer指定了使用vertex array列吼,并enable array(by glEnableVertexAttribArray)
所以幽崩,color值對所有vertices of triangle都是一樣的,但是每個vertices的vertexPos attribute是不同的寞钥。
上面的code用到了glVertexAttrib4fv(index, *values);
用于指定Vertex Attribute Data慌申,
Vertex attribute data,可以通過vertex array為每個vertex指定,也可以把一個constant value用于primitive的所有vertices蹄溉。
Constant Vertex Attribute
a constan vertex attribute is same for all vertices of a primitiveVertex Arrays
頂點(diǎn)數(shù)組指定每個vertex的attribute dataa咨油,buffer保存在client space。
void glVertexAttribPointer(index, size, type, normalized, stride, *ptr)
index : specifies generic vertex attibute index
size: 通過index引用的vertex attirbute的分量柒爵,1-4
stirde: as pitch(跨距) to get vertex data for next index.
ptr : 使用client-size vertex array時役电,指向持有vertex attibute data的buffer; 使用vertex buffer object時棉胀,表示offset in that buffer法瑟。
stirde: as pitch(跨距) to get vertex data for next index.
ptr : 使用client-size vertex array時,指向持有vertex attibute data的buffer唁奢; 使用vertex buffer object時霎挟,表示offset in that buffer。
先走著
texture:
glActiveTexture(GL_TEXTURE0);
- API: 9.1.13 Using Textures in a Shader
example : Vertex and Fragment Shaders for Perfroming 2D Texturing : Simple_Texture2D sample:
//Vertex shader
#version 300 es
layout(location = 0) in vec4 a_position;
layout(location = 1) in vec2 a_texCoord;
out vec2 v_texCorrd;
void main()
{
gl_Position = a_position;
v_texCoord = a_texCoord;
}
//Fragment shader
#version 300 es
precision mediump float;
in vec2 v_texCoord;
layout(location = 0) out vec4 outColor;
uniform sampler2D s_texture;
void main()
{
outColor = texture( s_texture, v_texCoord );
}
vertex shader以一個two-component texture coordinate作為vertex input, then passes it as output to framgnet shader.
fragment shader consumes the texture coordinate and used it for texture fetch(讀取).
fragment shader聲明了一個類型為sampler2D的uniform variable麻掸,called s_texture氓扛。
sampler是uniform變量的一個特殊類型,用來fetch from a texture map论笔,讀取紋理貼圖采郎。
sampler uniform will be loaded with a value specifying texture unit to which texture is bound;
比如,specifying a sampler with value of 0, says to fetch from unit GL_TEXTURE0狂魔,specifying a value of 1 says to fetch from GL_TEXTURE1, and so on.
Textures are bound to texture units by glActiveTexture(GLenum texture)
texture: texture unit to make active: GL_TEXTURE0/1/2/3/.../31/
glActiveTexture設(shè)置了current texture unit蒜埋,以便后續(xù)的glBindTexutre()會Bind texture to currently active uint。
example show how sampler and texture are bound to texture unit:
//get the sampler locations
userData->samplerLoc = glGetUniformLocation(userData->programObject,"s_texture");
//bind texture
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, userData->textureId);
//set sampler texture unit to 0
glUniformli(userData->samplerLoc, 0);
到這里最楷,我們已經(jīng)load了texture, texturen bound to texture unit 0 , sampler set to use texture uint 0.
回到simple_texture2D sample整份,可以看到,shader code使用了內(nèi)建函數(shù)texture,來fetch from texture map籽孙,
vec4 texture(sampler2D sampler, vec2 coord[,float bias])
sampler: sampler bound to a texture unit, 來指定要fetch的texture
coord: a 2D texture coordinate, 用來fetch from texture map
bias: 可選參數(shù)烈评,提供texture fetch所用的mipmap bias(mip貼圖 偏置),
texture()返回一個vec4,代表color fetched fromt texture map.
texture data mapped到color channels的方式犯建,依賴于texture base format讲冠。
下表展示了texture format map到vec4 color的方式,texture swizzles決定了适瓦,每個分量的值竿开,如何map到shader的分量
base format | Texel Data 紋素 |
---|---|
GL_RGB | R G B 1.0 |
GL_RGBA | R G B A |
GL_LUMINANCE | L L L 1.0 |
GL_LUMINANCE_ALPHA | L L L A |
GL_ALPHA | 0.0 .0.0 0.0 A |
這里有個texture swizzles,9.1.9紋理調(diào)配講了:texture swizzles control how color components in input R,RG,RGB,RGBA texture map to components when fetched from in the shader.
感覺和allocation->flag.swizzled不一樣玻熙,這個對應(yīng)的是tiled否彩,