From d257835507f9a304a69c40c181d4ecd2d82c0170 Mon Sep 17 00:00:00 2001 From: RuiwenTang Date: Fri, 22 Sep 2023 18:59:34 +0800 Subject: [PATCH] gl_engine: support render image --- src/renderer/gl_engine/tvgGlCommon.h | 4 + src/renderer/gl_engine/tvgGlGeometry.cpp | 91 ++++++++++++++++++++- src/renderer/gl_engine/tvgGlGeometry.h | 1 + src/renderer/gl_engine/tvgGlProgram.cpp | 2 +- src/renderer/gl_engine/tvgGlRenderer.cpp | 99 +++++++++++++++++++++-- src/renderer/gl_engine/tvgGlRenderer.h | 1 + src/renderer/gl_engine/tvgGlShaderSrc.cpp | 56 +++++++++++++ src/renderer/gl_engine/tvgGlShaderSrc.h | 2 + 8 files changed, 247 insertions(+), 9 deletions(-) diff --git a/src/renderer/gl_engine/tvgGlCommon.h b/src/renderer/gl_engine/tvgGlCommon.h index 420c6795..e9387adf 100644 --- a/src/renderer/gl_engine/tvgGlCommon.h +++ b/src/renderer/gl_engine/tvgGlCommon.h @@ -57,6 +57,10 @@ struct GlShape const RenderShape* rshape = nullptr; float viewWd; float viewHt; + GLuint texId = 0; + uint32_t texOpacity = 0; + uint32_t texFlipY = 0; + ColorSpace texColorSpace = ColorSpace::ABGR8888; RenderUpdateFlag updateFlag = None; unique_ptr geometry; }; diff --git a/src/renderer/gl_engine/tvgGlGeometry.cpp b/src/renderer/gl_engine/tvgGlGeometry.cpp index 1a9cfa5d..99d81004 100644 --- a/src/renderer/gl_engine/tvgGlGeometry.cpp +++ b/src/renderer/gl_engine/tvgGlGeometry.cpp @@ -56,6 +56,89 @@ bool GlGeometry::tesselate(const RenderShape& rshape, RenderUpdateFlag flag) return true; } +bool GlGeometry::tesselate(const Surface* image, const RenderMesh* mesh, RenderUpdateFlag flag) +{ + if (flag & RenderUpdateFlag::Image) { + fillVertex.clear(); + fillIndex.clear(); + + if (mesh && mesh->triangleCnt) { + fillVertex.reserve(mesh->triangleCnt * 3 * 5); + fillIndex.reserve(mesh->triangleCnt * 3); + + uint32_t index = 0; + for (uint32_t i = 0; i < mesh->triangleCnt; i++) { + fillVertex.push(mesh->triangles[i].vertex[0].pt.x); + fillVertex.push(mesh->triangles[i].vertex[0].pt.y); + fillVertex.push(1.f); + fillVertex.push(mesh->triangles[i].vertex[0].uv.x); + fillVertex.push(mesh->triangles[i].vertex[0].uv.y); + + fillVertex.push(mesh->triangles[i].vertex[1].pt.x); + fillVertex.push(mesh->triangles[i].vertex[1].pt.y); + fillVertex.push(1.f); + fillVertex.push(mesh->triangles[i].vertex[1].uv.x); + fillVertex.push(mesh->triangles[i].vertex[1].uv.y); + + fillVertex.push(mesh->triangles[i].vertex[2].pt.x); + fillVertex.push(mesh->triangles[i].vertex[2].pt.y); + fillVertex.push(1.f); + fillVertex.push(mesh->triangles[i].vertex[2].uv.x); + fillVertex.push(mesh->triangles[i].vertex[2].uv.y); + + fillIndex.push(index); + fillIndex.push(index + 1); + fillIndex.push(index + 2); + index += 3; + } + + } else { + fillVertex.reserve(5 * 4); + fillIndex.reserve(6); + + float left = 0.f; + float top = 0.f; + float right = image->w; + float bottom = image->h; + + // left top point + fillVertex.push(left); + fillVertex.push(top); + fillVertex.push(1.f); + fillVertex.push(0.f); + fillVertex.push(1.f); + // left bottom point + fillVertex.push(left); + fillVertex.push(bottom); + fillVertex.push(1.f); + fillVertex.push(0.f); + fillVertex.push(0.f); + // right top point + fillVertex.push(right); + fillVertex.push(top); + fillVertex.push(1.f); + fillVertex.push(1.f); + fillVertex.push(1.f); + // right bottom point + fillVertex.push(right); + fillVertex.push(bottom); + fillVertex.push(1.f); + fillVertex.push(1.f); + fillVertex.push(0.f); + + fillIndex.push(0); + fillIndex.push(1); + fillIndex.push(2); + + fillIndex.push(2); + fillIndex.push(1); + fillIndex.push(3); + } + } + + return true; +} + void GlGeometry::disableVertex(uint32_t location) { @@ -87,7 +170,13 @@ bool GlGeometry::draw(GlRenderTask* task, GlStageBuffer* gpuBuffer, RenderUpdate uint32_t indexOffset = gpuBuffer->push(indexBuffer->data, indexBuffer->count * sizeof(uint32_t)); // vertex layout - task->addVertexLayout(GlVertexLayout{0, 3, 3 * sizeof(float), vertexOffset}); + if (flag & RenderUpdateFlag::Image) { + // image has two attribute: [pos, uv] + task->addVertexLayout(GlVertexLayout{0, 3, 5 * sizeof(float), vertexOffset}); + task->addVertexLayout(GlVertexLayout{1, 2, 5 * sizeof(float), vertexOffset + 3 * sizeof(float)}); + } else { + task->addVertexLayout(GlVertexLayout{0, 3, 3 * sizeof(float), vertexOffset}); + } task->setDrawRange(indexOffset, indexBuffer->count); return true; diff --git a/src/renderer/gl_engine/tvgGlGeometry.h b/src/renderer/gl_engine/tvgGlGeometry.h index ce8f7d08..a42ddc3b 100644 --- a/src/renderer/gl_engine/tvgGlGeometry.h +++ b/src/renderer/gl_engine/tvgGlGeometry.h @@ -189,6 +189,7 @@ public: ~GlGeometry(); bool tesselate(const RenderShape& rshape, RenderUpdateFlag flag); + bool tesselate(const Surface* image, const RenderMesh* mesh, RenderUpdateFlag flag); void disableVertex(uint32_t location); bool draw(GlRenderTask* task, GlStageBuffer* gpuBuffer, RenderUpdateFlag flag); void updateTransform(const RenderTransform* transform, float w, float h); diff --git a/src/renderer/gl_engine/tvgGlProgram.cpp b/src/renderer/gl_engine/tvgGlProgram.cpp index fdaaa910..11612486 100644 --- a/src/renderer/gl_engine/tvgGlProgram.cpp +++ b/src/renderer/gl_engine/tvgGlProgram.cpp @@ -83,7 +83,7 @@ int32_t GlProgram::getAttributeLocation(const char* name) int32_t GlProgram::getUniformLocation(const char* name) { - GL_CHECK(int32_t location = glGetUniformLocation(mCurrentProgram, name)); + GL_CHECK(int32_t location = glGetUniformLocation(mProgramObj, name)); return location; } diff --git a/src/renderer/gl_engine/tvgGlRenderer.cpp b/src/renderer/gl_engine/tvgGlRenderer.cpp index 9f4e16ef..1f98b5bb 100644 --- a/src/renderer/gl_engine/tvgGlRenderer.cpp +++ b/src/renderer/gl_engine/tvgGlRenderer.cpp @@ -146,10 +146,53 @@ bool GlRenderer::blend(TVG_UNUSED BlendMethod method) } -bool GlRenderer::renderImage(TVG_UNUSED void* data) +bool GlRenderer::renderImage(void* data) { - //TODO: render requested images - return false; + auto sdata = static_cast(data); + + if (!sdata) return false; + + if ((sdata->updateFlag & RenderUpdateFlag::Image) == 0) return false; + + auto task = make_unique(mPrograms[RT_Image].get()); + + if (!sdata->geometry->draw(task.get(), mGpuBuffer.get(), RenderUpdateFlag::Image)) return false; + + // matrix buffer + { + auto matrix = sdata->geometry->getTransforMatrix(); + uint32_t loc = task->getProgram()->getUniformBlockIndex("Matrix"); + + task->addBindResource(GlBindingResource{ + 0, + loc, + mGpuBuffer->getBufferId(), + mGpuBuffer->push(matrix, 16 * sizeof(float), true), + 16 * sizeof(float), + }); + } + // image info + { + uint32_t info[4] = {sdata->texColorSpace, sdata->texFlipY, sdata->texOpacity, 0}; + uint32_t loc = task->getProgram()->getUniformBlockIndex("ColorInfo"); + + task->addBindResource(GlBindingResource{ + 1, + loc, + mGpuBuffer->getBufferId(), + mGpuBuffer->push(info, 4 * sizeof(uint32_t), true), + 4 * sizeof(uint32_t), + }); + } + // texture id + { + uint32_t loc = task->getProgram()->getUniformLocation("uTexture"); + task->addBindResource(GlBindingResource{0, sdata->texId, loc}); + } + + mRenderTasks.emplace_back(std::move(task)); + + return true; } @@ -196,15 +239,54 @@ bool GlRenderer::dispose(RenderData data) auto sdata = static_cast(data); if (!sdata) return false; + if (sdata->texId) glDeleteTextures(1, &sdata->texId); + delete sdata; return true; } - -RenderData GlRenderer::prepare(TVG_UNUSED Surface* surface, TVG_UNUSED const RenderMesh* mesh, TVG_UNUSED RenderData data, TVG_UNUSED const RenderTransform* transform, TVG_UNUSED Array& clips, TVG_UNUSED uint8_t opacity, TVG_UNUSED RenderUpdateFlag flags) +static GLuint _genTexture(Surface* image) { - //TODO: - return nullptr; + GLuint tex = 0; + + GL_CHECK(glGenTextures(1, &tex)); + + GL_CHECK(glBindTexture(GL_TEXTURE_2D, tex)); + GL_CHECK(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, image->w, image->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, image->data)); + + GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); + GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); + GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); + GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); + + GL_CHECK(glBindTexture(GL_TEXTURE_2D, 0)); + + return tex; +} + +RenderData GlRenderer::prepare(Surface* image, const RenderMesh* mesh, RenderData data, const RenderTransform* transform, TVG_UNUSED Array& clips, uint8_t opacity, RenderUpdateFlag flags) +{ + if (flags == RenderUpdateFlag::None) return nullptr; + + auto sdata = static_cast(data); + + if (!sdata) sdata = new GlShape; + + sdata->viewWd = static_cast(surface.w); + sdata->viewHt = static_cast(surface.h); + sdata->updateFlag = flags; + + sdata->texId = _genTexture(image); + sdata->texOpacity = opacity; + sdata->texColorSpace = image->cs; + sdata->texFlipY = (mesh && mesh->triangleCnt) ? 0 : 1; + sdata->geometry = make_unique(); + + sdata->geometry->updateTransform(transform, sdata->viewWd, sdata->viewHt); + + sdata->geometry->tesselate(image, mesh, flags); + + return sdata; } @@ -324,6 +406,9 @@ void GlRenderer::initShaders() // Radial Gradient Renderer mPrograms.push_back(make_unique(GlShader::gen(GRADIENT_VERT_SHADER, RADIAL_GRADIENT_FRAG_SHADER))); + + // image Renderer + mPrograms.push_back(make_unique(GlShader::gen(IMAGE_VERT_SHADER, IMAGE_FRAG_SHADER))); } diff --git a/src/renderer/gl_engine/tvgGlRenderer.h b/src/renderer/gl_engine/tvgGlRenderer.h index 88462f9c..08fdd090 100644 --- a/src/renderer/gl_engine/tvgGlRenderer.h +++ b/src/renderer/gl_engine/tvgGlRenderer.h @@ -36,6 +36,7 @@ public: RT_Color = 0, RT_LinGradient, RT_RadGradient, + RT_Image, RT_None, }; diff --git a/src/renderer/gl_engine/tvgGlShaderSrc.cpp b/src/renderer/gl_engine/tvgGlShaderSrc.cpp index 72048a0d..60562b94 100644 --- a/src/renderer/gl_engine/tvgGlShaderSrc.cpp +++ b/src/renderer/gl_engine/tvgGlShaderSrc.cpp @@ -196,3 +196,59 @@ STR_GRADIENT_FRAG_COMMON_FUNCTIONS + STR_RADIAL_GRADIENT_MAIN; const char* RADIAL_GRADIENT_FRAG_SHADER = STR_RADIAL_GRADIENT_FRAG_SHADER.c_str(); + + +const char* IMAGE_VERT_SHADER = TVG_COMPOSE_SHADER( + layout (location = 0) in vec3 aLocation; \n + layout (location = 1) in vec2 aUV; \n + layout (std140) uniform Matrix { \n + mat4 transform; \n + } uMatrix; \n + \n + out float aOpacity; \n + out vec2 vUV; \n + \n + void main() { \n + aOpacity = aLocation.z; \n + vUV = aUV; \n + gl_Position = uMatrix.transform * vec4(aLocation.xy, 0.0, 1.0); \n + } \n +); + +const char* IMAGE_FRAG_SHADER = TVG_COMPOSE_SHADER( + layout(std140) uniform ColorInfo { \n + int format; \n + int flipY; \n + int opacity; \n + int dummy; \n + } uColorInfo; \n + uniform sampler2D uTexture; \n + \n + in float aOpacity; \n + in vec2 vUV; \n + \n + out vec4 FragColor; \n + \n + void main() { \n + vec2 uv = vUV; \n + if (uColorInfo.flipY == 1) { uv.y = 1.0 - uv.y; } \n + \n + vec4 color = texture(uTexture, uv); \n + vec4 result = color; \n + if (uColorInfo.format == 1) { /* FMT_ARGB8888 */ \n + result.r = color.b; \n + result.g = color.g; \n + result.b = color.r; \n + result.a = color.a; \n + } else if (uColorInfo.format == 2) { /* FMT_ABGR8888S */ \n + result = vec4(color.rgb * color.a, color.a); \n + } else if (uColorInfo.format == 3) { /* FMT_ARGB8888S */ \n + result.r = color.b * color.a; \n + result.g = color.g * color.a; \n + result.b = color.b * color.a; \n + result.a = color.a; \n + } \n + float opacity = float(uColorInfo.opacity) / 255.0; \n + FragColor = vec4(result.rgb, result.a * opacity * aOpacity); \n + } \n +); diff --git a/src/renderer/gl_engine/tvgGlShaderSrc.h b/src/renderer/gl_engine/tvgGlShaderSrc.h index 053f1c96..5959559d 100644 --- a/src/renderer/gl_engine/tvgGlShaderSrc.h +++ b/src/renderer/gl_engine/tvgGlShaderSrc.h @@ -28,5 +28,7 @@ extern const char* COLOR_FRAG_SHADER; extern const char* GRADIENT_VERT_SHADER; extern const char* LINEAR_GRADIENT_FRAG_SHADER; extern const char* RADIAL_GRADIENT_FRAG_SHADER; +extern const char* IMAGE_VERT_SHADER; +extern const char* IMAGE_FRAG_SHADER; #endif /* _TVG_GL_SHADERSRC_H_ */