diff options
author | whunt@chromium.org <whunt@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-11-30 05:41:58 +0000 |
---|---|---|
committer | whunt@chromium.org <whunt@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-11-30 05:41:58 +0000 |
commit | f2dbbf0e550887f642113820896039fceb2f8d17 (patch) | |
tree | 6d19bf9ec91de06f46708e69670f89a123e380bf | |
parent | 3043b20455e598022df8f5b3b0ee4bbd5291c0b5 (diff) | |
download | chromium_src-f2dbbf0e550887f642113820896039fceb2f8d17.zip chromium_src-f2dbbf0e550887f642113820896039fceb2f8d17.tar.gz chromium_src-f2dbbf0e550887f642113820896039fceb2f8d17.tar.bz2 |
Texture Draw Calls Coalescing
This patch batches multiple calls to DrawQuad inside GlRenderer when the calls draw textured quads that have the same texture. These quads differ only in transform for both position and UV. This patch extends the vertex shader used for drawing textures to use one of 8 matrices and UV transforms. By batching up to 8 DrawQuads into a single draw quad, we reduce the number of times many different OpenGL ES state calls are made.
The implementation maintains a cache of up to 8 quads that contain the same texture and drawing parameters (e.g. opacity). If a 9th textured quad with the same parameters or a different kind of quad is drawn or any GL state (e.g. scissor rect) is changed or the new finishDrawingQuadList() function is called then the the quads are drawn in a single call and the cache is flushed.
BUG=161372
Review URL: https://chromiumcodereview.appspot.com/11415161
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@170409 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | cc/cc.gyp | 2 | ||||
-rw-r--r-- | cc/direct_renderer.cc | 5 | ||||
-rw-r--r-- | cc/direct_renderer.h | 1 | ||||
-rw-r--r-- | cc/geometry_binding.cc | 45 | ||||
-rw-r--r-- | cc/geometry_binding.h | 9 | ||||
-rw-r--r-- | cc/gl_renderer.cc | 168 | ||||
-rw-r--r-- | cc/gl_renderer.h | 9 | ||||
-rw-r--r-- | cc/gl_renderer_draw_cache.cc | 16 | ||||
-rw-r--r-- | cc/gl_renderer_draw_cache.h | 42 | ||||
-rw-r--r-- | cc/gl_renderer_unittest.cc | 2 | ||||
-rw-r--r-- | cc/shader.cc | 9 |
11 files changed, 271 insertions, 37 deletions
@@ -55,6 +55,8 @@ 'geometry_binding.h', 'gl_renderer.cc', 'gl_renderer.h', + 'gl_renderer_draw_cache.cc', + 'gl_renderer_draw_cache.h', 'graphics_context.h', 'hash_pair.h', 'heads_up_display_layer.cc', diff --git a/cc/direct_renderer.cc b/cc/direct_renderer.cc index 9f13114..7fbd16c 100644 --- a/cc/direct_renderer.cc +++ b/cc/direct_renderer.cc @@ -207,6 +207,10 @@ void DirectRenderer::setScissorStateForQuadWithRenderPassScissor(const DrawingFr setScissorTestRect(moveScissorToWindowSpace(frame, quadScissorRect)); } +void DirectRenderer::finishDrawingQuadList() +{ +} + void DirectRenderer::drawRenderPass(DrawingFrame& frame, const RenderPass* renderPass) { TRACE_EVENT0("cc", "DirectRenderer::drawRenderPass"); @@ -236,6 +240,7 @@ void DirectRenderer::drawRenderPass(DrawingFrame& frame, const RenderPass* rende if (!shouldSkipQuad) drawQuad(frame, *it); } + finishDrawingQuadList(); CachedResource* texture = m_renderPassTextures.get(renderPass->id); if (texture) diff --git a/cc/direct_renderer.h b/cc/direct_renderer.h index c22c1a1..da82f49 100644 --- a/cc/direct_renderer.h +++ b/cc/direct_renderer.h @@ -93,6 +93,7 @@ protected: virtual void drawQuad(DrawingFrame&, const DrawQuad*) = 0; virtual void beginDrawingFrame(DrawingFrame&) = 0; virtual void finishDrawingFrame(DrawingFrame&) = 0; + virtual void finishDrawingQuadList(); virtual bool flippedFramebuffer() const = 0; virtual void ensureScissorTestEnabled() = 0; virtual void ensureScissorTestDisabled() = 0; diff --git a/cc/geometry_binding.cc b/cc/geometry_binding.cc index 3ccea1f..cef4870 100644 --- a/cc/geometry_binding.cc +++ b/cc/geometry_binding.cc @@ -17,20 +17,42 @@ GeometryBinding::GeometryBinding(WebKit::WebGraphicsContext3D* context, const gf , m_quadElementsVbo(0) , m_initialized(false) { - // Vertex positions and texture coordinates for the 4 corners of a 1x1 quad. float vertices[] = { quadVertexRect.x(), quadVertexRect.bottom(), 0.0f, 0.0f, 1.0f, quadVertexRect.x(), quadVertexRect.y(), 0.0f, 0.0f, 0.0f, quadVertexRect.right(), quadVertexRect.y(), 0.0f, 1.0f, 0.0f, - quadVertexRect.right(), quadVertexRect.bottom(), 0.0f, 1.0f, 1.0f }; - uint16_t indices[] = { 0, 1, 2, 0, 2, 3, // The two triangles that make up the layer quad. - 0, 1, 2, 3}; // A line path for drawing the layer border. + quadVertexRect.right(), quadVertexRect.bottom(), 0.0f, 1.0f, 1.0f }; + + struct Vertex { + float a_position[3]; + float a_texCoord[2]; + float a_index; // index into the matrix array for this quad + }; + struct Quad { Vertex v0, v1, v2, v3; }; + struct QuadIndex { uint16_t data[6]; }; + + COMPILE_ASSERT(sizeof(Quad) == 24 * sizeof(float), struct_is_densely_packed); + COMPILE_ASSERT(sizeof(QuadIndex) == 6 * sizeof(uint16_t), struct_is_densely_packed); + + Quad quad_list[8]; + QuadIndex quad_index_list[8]; + for (int i = 0; i < 8; i++) { + Vertex v0 = { quadVertexRect.x() , quadVertexRect.bottom(), 0.0f, 0.0f, 1.0f, (float)i }; + Vertex v1 = { quadVertexRect.x() , quadVertexRect.y() , 0.0f, 0.0f, 0.0f, (float)i }; + Vertex v2 = { quadVertexRect.right(), quadVertexRect.y() , 0.0f, 1.0f, 0.0f, (float)i }; + Vertex v3 = { quadVertexRect.right(), quadVertexRect.bottom(), 0.0f, 1.0f, 1.0f, (float)i }; + Quad x = { v0, v1, v2, v3 }; + quad_list[i] = x; + QuadIndex y = { 0 + 4 * i, 1 + 4 * i, 2 + 4 * i, 3 + 4 * i, 0 + 4 * i, 2 + 4 * i }; + quad_index_list[i] = y; + } GLC(m_context, m_quadVerticesVbo = m_context->createBuffer()); GLC(m_context, m_quadElementsVbo = m_context->createBuffer()); + GLC(m_context, m_quadListVerticesVbo = m_context->createBuffer()); GLC(m_context, m_context->bindBuffer(GL_ARRAY_BUFFER, m_quadVerticesVbo)); - GLC(m_context, m_context->bufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW)); + GLC(m_context, m_context->bufferData(GL_ARRAY_BUFFER, sizeof(quad_list), quad_list, GL_STATIC_DRAW)); GLC(m_context, m_context->bindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_quadElementsVbo)); - GLC(m_context, m_context->bufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW)); + GLC(m_context, m_context->bufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(quad_index_list), quad_index_list, GL_STATIC_DRAW)); m_initialized = true; } @@ -43,14 +65,15 @@ GeometryBinding::~GeometryBinding() void GeometryBinding::prepareForDraw() { - GLC(m_context, m_context->bindBuffer(GL_ARRAY_BUFFER, quadVerticesVbo())); GLC(m_context, m_context->bindBuffer(GL_ELEMENT_ARRAY_BUFFER, quadElementsVbo())); - unsigned offset = 0; - GLC(m_context, m_context->vertexAttribPointer(positionAttribLocation(), 3, GL_FLOAT, false, 5 * sizeof(float), offset)); - offset += 3 * sizeof(float); - GLC(m_context, m_context->vertexAttribPointer(texCoordAttribLocation(), 2, GL_FLOAT, false, 5 * sizeof(float), offset)); + + GLC(m_context, m_context->bindBuffer(GL_ARRAY_BUFFER, quadVerticesVbo())); + GLC(m_context, m_context->vertexAttribPointer(positionAttribLocation(), 3, GL_FLOAT, false, 6 * sizeof(float), 0)); + GLC(m_context, m_context->vertexAttribPointer(texCoordAttribLocation(), 2, GL_FLOAT, false, 6 * sizeof(float), 3 * sizeof(float))); + GLC(m_context, m_context->vertexAttribPointer(triangleIndexAttribLocation(), 1, GL_FLOAT, false, 6 * sizeof(float), 5 * sizeof(float))); GLC(m_context, m_context->enableVertexAttribArray(positionAttribLocation())); GLC(m_context, m_context->enableVertexAttribArray(texCoordAttribLocation())); + GLC(m_context, m_context->enableVertexAttribArray(triangleIndexAttribLocation())); } } // namespace cc diff --git a/cc/geometry_binding.h b/cc/geometry_binding.h index 717ec6b..6a8bfde 100644 --- a/cc/geometry_binding.h +++ b/cc/geometry_binding.h @@ -25,6 +25,7 @@ public: WebKit::WebGraphicsContext3D* context() const { return m_context; } unsigned quadVerticesVbo() const { return m_quadVerticesVbo; } unsigned quadElementsVbo() const { return m_quadElementsVbo; } + unsigned quadListVerticesVbo() const { return m_quadListVerticesVbo; } void prepareForDraw(); @@ -33,14 +34,18 @@ public: // rebinding attribute arrays. static int positionAttribLocation() { return 0; } static int texCoordAttribLocation() { return 1; } + static int triangleIndexAttribLocation() { return 2; } private: WebKit::WebGraphicsContext3D* m_context; + bool m_initialized; + unsigned m_quadVerticesVbo; unsigned m_quadElementsVbo; - bool m_initialized; + unsigned m_quadListVerticesVbo; }; } // namespace cc -#endif // CC_GEOMETRY_BINDING_H_ +#endif // CC_GEOMETRY_BINDING_H_ + diff --git a/cc/gl_renderer.cc b/cc/gl_renderer.cc index 94f8d83..c2646c1 100644 --- a/cc/gl_renderer.cc +++ b/cc/gl_renderer.cc @@ -241,8 +241,10 @@ void GLRenderer::beginDrawingFrame(DrawingFrame& frame) GLC(m_context, m_context->disable(GL_CULL_FACE)); GLC(m_context, m_context->colorMask(true, true, true, true)); GLC(m_context, m_context->enable(GL_BLEND)); + m_blendShadow = true; GLC(m_context, m_context->blendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA)); GLC(context(), context()->activeTexture(GL_TEXTURE0)); + m_programShadow = 0; } void GLRenderer::doNoOp() @@ -254,11 +256,10 @@ void GLRenderer::doNoOp() void GLRenderer::drawQuad(DrawingFrame& frame, const DrawQuad* quad) { DCHECK(quad->rect.Contains(quad->visible_rect)); - - if (quad->ShouldDrawWithBlending()) - GLC(m_context, m_context->enable(GL_BLEND)); - else - GLC(m_context, m_context->disable(GL_BLEND)); + if (quad->material != DrawQuad::TEXTURE_CONTENT) { + flushTextureQuadCache(); + setBlendEnabled(quad->ShouldDrawWithBlending()); + } switch (quad->material) { case DrawQuad::INVALID: @@ -283,7 +284,7 @@ void GLRenderer::drawQuad(DrawingFrame& frame, const DrawQuad* quad) drawStreamVideoQuad(frame, StreamVideoDrawQuad::MaterialCast(quad)); break; case DrawQuad::TEXTURE_CONTENT: - drawTextureQuad(frame, TextureDrawQuad::MaterialCast(quad)); + enqueueTextureQuad(frame, TextureDrawQuad::MaterialCast(quad)); break; case DrawQuad::TILED_CONTENT: drawTileQuad(frame, TileDrawQuad::MaterialCast(quad)); @@ -298,7 +299,7 @@ void GLRenderer::drawCheckerboardQuad(const DrawingFrame& frame, const Checkerbo { const TileCheckerboardProgram* program = tileCheckerboardProgram(); DCHECK(program && (program->initialized() || isContextLost())); - GLC(context(), context()->useProgram(program->program())); + setUseProgram(program->program()); SkColor color = quad->color; GLC(context(), context()->uniform4f(program->fragmentShader().colorLocation(), SkColorGetR(color) / 255.0, SkColorGetG(color) / 255.0, SkColorGetB(color) / 255.0, 1)); @@ -324,7 +325,7 @@ void GLRenderer::drawDebugBorderQuad(const DrawingFrame& frame, const DebugBorde static float glMatrix[16]; const SolidColorProgram* program = solidColorProgram(); DCHECK(program && (program->initialized() || isContextLost())); - GLC(context(), context()->useProgram(program->program())); + setUseProgram(program->program()); // Use the full quadRect for debug quads to not move the edges based on partial swaps. const gfx::Rect& layerRect = quad->rect; @@ -342,7 +343,7 @@ void GLRenderer::drawDebugBorderQuad(const DrawingFrame& frame, const DebugBorde GLC(context(), context()->lineWidth(quad->width)); // The indices for the line are stored in the same array as the triangle indices. - GLC(context(), context()->drawElements(GL_LINE_LOOP, 4, GL_UNSIGNED_SHORT, 6 * sizeof(unsigned short))); + GLC(context(), context()->drawElements(GL_LINE_LOOP, 4, GL_UNSIGNED_SHORT, 0)); } static WebGraphicsContext3D* getFilterContext(bool hasImplThread) @@ -587,7 +588,7 @@ void GLRenderer::drawRenderPassQuad(DrawingFrame& frame, const RenderPassDrawQua int shaderAlphaLocation = -1; if (useAA && maskTextureId) { const RenderPassMaskProgramAA* program = renderPassMaskProgramAA(); - GLC(context(), context()->useProgram(program->program())); + setUseProgram(program->program()); GLC(context(), context()->uniform1i(program->fragmentShader().samplerLocation(), 0)); shaderQuadLocation = program->vertexShader().pointLocation(); @@ -599,7 +600,7 @@ void GLRenderer::drawRenderPassQuad(DrawingFrame& frame, const RenderPassDrawQua shaderAlphaLocation = program->fragmentShader().alphaLocation(); } else if (!useAA && maskTextureId) { const RenderPassMaskProgram* program = renderPassMaskProgram(); - GLC(context(), context()->useProgram(program->program())); + setUseProgram(program->program()); GLC(context(), context()->uniform1i(program->fragmentShader().samplerLocation(), 0)); shaderMaskSamplerLocation = program->fragmentShader().maskSamplerLocation(); @@ -609,7 +610,7 @@ void GLRenderer::drawRenderPassQuad(DrawingFrame& frame, const RenderPassDrawQua shaderAlphaLocation = program->fragmentShader().alphaLocation(); } else if (useAA && !maskTextureId) { const RenderPassProgramAA* program = renderPassProgramAA(); - GLC(context(), context()->useProgram(program->program())); + setUseProgram(program->program()); GLC(context(), context()->uniform1i(program->fragmentShader().samplerLocation(), 0)); shaderQuadLocation = program->vertexShader().pointLocation(); @@ -618,7 +619,7 @@ void GLRenderer::drawRenderPassQuad(DrawingFrame& frame, const RenderPassDrawQua shaderAlphaLocation = program->fragmentShader().alphaLocation(); } else { const RenderPassProgram* program = renderPassProgram(); - GLC(context(), context()->useProgram(program->program())); + setUseProgram(program->program()); GLC(context(), context()->uniform1i(program->fragmentShader().samplerLocation(), 0)); shaderMatrixLocation = program->vertexShader().matrixLocation(); @@ -660,7 +661,7 @@ void GLRenderer::drawRenderPassQuad(DrawingFrame& frame, const RenderPassDrawQua void GLRenderer::drawSolidColorQuad(const DrawingFrame& frame, const SolidColorDrawQuad* quad) { const SolidColorProgram* program = solidColorProgram(); - GLC(context(), context()->useProgram(program->program())); + setUseProgram(program->program()); SkColor color = quad->color; float opacity = quad->opacity(); @@ -778,7 +779,7 @@ void GLRenderer::drawTileQuad(const DrawingFrame& frame, const TileDrawQuad* qua } } - GLC(context(), context()->useProgram(uniforms.program)); + setUseProgram(uniforms.program); GLC(context(), context()->uniform1i(uniforms.samplerLocation, 0)); ResourceProvider::ScopedReadLockGL quadResourceLock(m_resourceProvider, quad->resource_id); GLC(context(), context()->bindTexture(GL_TEXTURE_2D, quadResourceLock.textureId())); @@ -895,7 +896,7 @@ void GLRenderer::drawYUVVideoQuad(const DrawingFrame& frame, const YUVVideoDrawQ GLC(context(), context()->activeTexture(GL_TEXTURE3)); GLC(context(), context()->bindTexture(GL_TEXTURE_2D, vPlaneLock.textureId())); - GLC(context(), context()->useProgram(program->program())); + setUseProgram(program->program()); GLC(context(), context()->uniform2f(program->vertexShader().texScaleLocation(), quad->tex_scale.width(), quad->tex_scale.height())); GLC(context(), context()->uniform1i(program->fragmentShader().yTextureLocation(), 1)); @@ -938,7 +939,7 @@ void GLRenderer::drawStreamVideoQuad(const DrawingFrame& frame, const StreamVide DCHECK(m_capabilities.usingEglImage); const VideoStreamTextureProgram* program = videoStreamTextureProgram(); - GLC(context(), context()->useProgram(program->program())); + setUseProgram(program->program()); toGLMatrix(&glMatrix[0], quad->matrix); GLC(context(), context()->uniformMatrix4fv(program->vertexShader().texMatrixLocation(), 1, false, glMatrix)); @@ -977,6 +978,102 @@ struct TexTransformTextureProgramBinding : TextureProgramBinding { int texTransformLocation; }; +void GLRenderer::flushTextureQuadCache() +{ + // Check to see if we have anything to draw. + if (m_drawCache.program_id == 0) + return; + + // Set the correct blending mode. + setBlendEnabled(m_drawCache.needs_blending); + + // Bind the program to the GL state. + setUseProgram(m_drawCache.program_id); + + // Assume the current active textures is 0. + ResourceProvider::ScopedReadLockGL lockedQuad(m_resourceProvider, m_drawCache.resource_id); + GLC(context(), context()->bindTexture(GL_TEXTURE_2D, lockedQuad.textureId())); + + // set up premultiplied alpha. + if (!m_drawCache.use_premultiplied_alpha) { + // As it turns out, the premultiplied alpha blending function (ONE, ONE_MINUS_SRC_ALPHA) + // will never cause the alpha channel to be set to anything less than 1.0 if it is + // initialized to that value! Therefore, premultipliedAlpha being false is the first + // situation we can generally see an alpha channel less than 1.0 coming out of the + // compositor. This is causing platform differences in some layout tests (see + // https://bugs.webkit.org/show_bug.cgi?id=82412), so in this situation, use a separate + // blend function for the alpha channel to avoid modifying it. Don't use colorMask for this + // as it has performance implications on some platforms. + GLC(context(), context()->blendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE)); + } + + // Set the shader opacity. + setShaderOpacity(m_drawCache.alpha, m_drawCache.alpha_location); + + COMPILE_ASSERT(sizeof(Float4) == 4 * sizeof(float), struct_is_densely_packed); + COMPILE_ASSERT(sizeof(Float16) == 16 * sizeof(float), struct_is_densely_packed); + + // Upload the tranforms for both points and uvs. + GLC(m_context, m_context->uniformMatrix4fv((int)m_drawCache.matrix_location, (int)m_drawCache.matrix_data.size(), false, (float*)&m_drawCache.matrix_data.front())); + GLC(m_context, m_context->uniform4fv((int)m_drawCache.uv_xform_location, (int)m_drawCache.uv_xform_data.size(), (float*)&m_drawCache.uv_xform_data.front())); + + // Draw the quads! + GLC(m_context, m_context->drawElements(GL_TRIANGLES, 6 * m_drawCache.matrix_data.size(), GL_UNSIGNED_SHORT, 0)); + + // Clean up after ourselves (reset state set above). + if (!m_drawCache.use_premultiplied_alpha) + GLC(m_context, m_context->blendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA)); + + // Clear the cache. + m_drawCache.program_id = 0; + m_drawCache.uv_xform_data.resize(0); + m_drawCache.matrix_data.resize(0); +} + +void GLRenderer::enqueueTextureQuad(const DrawingFrame& frame, const TextureDrawQuad* quad) +{ + // Choose the correcte texture program binding + TexTransformTextureProgramBinding binding; + if (quad->flipped) + binding.set(textureProgramFlip(), context()); + else + binding.set(textureProgram(), context()); + + int resourceID = quad->resource_id; + + if (m_drawCache.program_id != binding.programId || + m_drawCache.resource_id != resourceID || + m_drawCache.alpha != quad->opacity() || + m_drawCache.use_premultiplied_alpha != quad->premultiplied_alpha || + m_drawCache.needs_blending != quad->ShouldDrawWithBlending() || + m_drawCache.matrix_data.size() >= 8) { + flushTextureQuadCache(); + m_drawCache.program_id = binding.programId; + m_drawCache.resource_id = resourceID; + m_drawCache.alpha = quad->opacity(); + m_drawCache.use_premultiplied_alpha = quad->premultiplied_alpha; + m_drawCache.needs_blending = quad->ShouldDrawWithBlending(); + + m_drawCache.alpha_location = binding.alphaLocation; + m_drawCache.uv_xform_location = binding.texTransformLocation; + m_drawCache.matrix_location = binding.matrixLocation; + } + + // Generate the uv-transform + const gfx::RectF& uvRect = quad->uv_rect; + Float4 uv = {uvRect.x(), uvRect.y(), uvRect.width(), uvRect.height()}; + m_drawCache.uv_xform_data.push_back(uv); + + // Generate the transform matrix + gfx::Transform quadRectMatrix; + quadRectTransform(&quadRectMatrix, quad->quadTransform(), quad->rect); + quadRectMatrix = frame.projectionMatrix * quadRectMatrix; + + Float16 m; + quadRectMatrix.matrix().asColMajorf(m.data); + m_drawCache.matrix_data.push_back(m); +} + void GLRenderer::drawTextureQuad(const DrawingFrame& frame, const TextureDrawQuad* quad) { TexTransformTextureProgramBinding binding; @@ -984,7 +1081,7 @@ void GLRenderer::drawTextureQuad(const DrawingFrame& frame, const TextureDrawQua binding.set(textureProgramFlip(), context()); else binding.set(textureProgram(), context()); - GLC(context(), context()->useProgram(binding.programId)); + setUseProgram(binding.programId); GLC(context(), context()->uniform1i(binding.samplerLocation, 0)); const gfx::RectF& uvRect = quad->uv_rect; GLC(context(), context()->uniform4f(binding.texTransformLocation, uvRect.x(), uvRect.y(), uvRect.width(), uvRect.height())); @@ -1016,7 +1113,7 @@ void GLRenderer::drawIOSurfaceQuad(const DrawingFrame& frame, const IOSurfaceDra TexTransformTextureProgramBinding binding; binding.set(textureIOSurfaceProgram(), context()); - GLC(context(), context()->useProgram(binding.programId)); + setUseProgram(binding.programId); GLC(context(), context()->uniform1i(binding.samplerLocation, 0)); if (quad->orientation == IOSurfaceDrawQuad::FLIPPED) GLC(context(), context()->uniform4f(binding.texTransformLocation, 0, quad->io_surface_size.height(), quad->io_surface_size.width(), quad->io_surface_size.height() * -1.0)); @@ -1037,6 +1134,12 @@ void GLRenderer::finishDrawingFrame(DrawingFrame& frame) m_swapBufferRect.Union(gfx::ToEnclosingRect(frame.rootDamageRect)); GLC(m_context, m_context->disable(GL_BLEND)); + m_blendShadow = false; +} + +void GLRenderer::finishDrawingQuadList() +{ + flushTextureQuadCache(); } bool GLRenderer::flippedFramebuffer() const @@ -1049,6 +1152,7 @@ void GLRenderer::ensureScissorTestEnabled() if (m_isScissorEnabled) return; + flushTextureQuadCache(); GLC(m_context, m_context->enable(GL_SCISSOR_TEST)); m_isScissorEnabled = true; } @@ -1058,6 +1162,7 @@ void GLRenderer::ensureScissorTestDisabled() if (!m_isScissorEnabled) return; + flushTextureQuadCache(); GLC(m_context, m_context->disable(GL_SCISSOR_TEST)); m_isScissorEnabled = false; } @@ -1090,6 +1195,26 @@ void GLRenderer::setShaderOpacity(float opacity, int alphaLocation) GLC(m_context, m_context->uniform1f(alphaLocation, opacity)); } +void GLRenderer::setBlendEnabled(bool enabled) +{ + if (enabled == m_blendShadow) + return; + + if (enabled) + GLC(m_context, m_context->enable(GL_BLEND)); + else + GLC(m_context, m_context->disable(GL_BLEND)); + m_blendShadow = enabled; +} + +void GLRenderer::setUseProgram(unsigned program) +{ + if (program == m_programShadow) + return; + GLC(m_context, m_context->useProgram(program)); + m_programShadow = program; +} + void GLRenderer::drawQuadGeometry(const DrawingFrame& frame, const gfx::Transform& drawTransform, const gfx::RectF& quadRect, int matrixLocation) { gfx::Transform quadRectMatrix; @@ -1107,7 +1232,7 @@ void GLRenderer::copyTextureToFramebuffer(const DrawingFrame& frame, int texture GLC(context(), context()->bindTexture(GL_TEXTURE_2D, textureId)); - GLC(context(), context()->useProgram(program->program())); + setUseProgram(program->program()); GLC(context(), context()->uniform1i(program->fragmentShader().samplerLocation(), 0)); setShaderOpacity(1, program->fragmentShader().alphaLocation()); drawQuadGeometry(frame, drawMatrix, rect, program->vertexShader().matrixLocation()); @@ -1358,6 +1483,7 @@ void GLRenderer::setScissorTestRect(const gfx::Rect& scissorRect) return; m_scissorRect = scissorRect; + flushTextureQuadCache(); GLC(m_context, m_context->scissor(scissorRect.x(), scissorRect.y(), scissorRect.width(), scissorRect.height())); } @@ -1527,6 +1653,7 @@ const GLRenderer::TextureProgram* GLRenderer::textureProgram() if (!m_textureProgram->initialized()) { TRACE_EVENT0("cc", "GLRenderer::textureProgram::initialize"); m_textureProgram->initialize(m_context, m_isUsingBindUniform); + GLC(context(), context()->uniform1i(m_textureProgram.get()->fragmentShader().samplerLocation(), 0)); } return m_textureProgram.get(); } @@ -1538,6 +1665,7 @@ const GLRenderer::TextureProgramFlip* GLRenderer::textureProgramFlip() if (!m_textureProgramFlip->initialized()) { TRACE_EVENT0("cc", "GLRenderer::textureProgramFlip::initialize"); m_textureProgramFlip->initialize(m_context, m_isUsingBindUniform); + GLC(context(), context()->uniform1i(m_textureProgramFlip.get()->fragmentShader().samplerLocation(), 0)); } return m_textureProgramFlip.get(); } diff --git a/cc/gl_renderer.h b/cc/gl_renderer.h index f8381ec..391790e 100644 --- a/cc/gl_renderer.h +++ b/cc/gl_renderer.h @@ -9,6 +9,7 @@ #include "cc/checkerboard_draw_quad.h" #include "cc/debug_border_draw_quad.h" #include "cc/direct_renderer.h" +#include "cc/gl_renderer_draw_cache.h" #include "cc/io_surface_draw_quad.h" #include "cc/render_pass_draw_quad.h" #include "cc/renderer.h" @@ -85,6 +86,7 @@ protected: virtual bool flippedFramebuffer() const OVERRIDE; virtual void ensureScissorTestEnabled() OVERRIDE; virtual void ensureScissorTestDisabled() OVERRIDE; + virtual void finishDrawingQuadList() OVERRIDE; private: static void toGLMatrix(float*, const gfx::Transform&); @@ -100,6 +102,8 @@ private: void drawSolidColorQuad(const DrawingFrame&, const SolidColorDrawQuad*); void drawStreamVideoQuad(const DrawingFrame&, const StreamVideoDrawQuad*); void drawTextureQuad(const DrawingFrame&, const TextureDrawQuad*); + void enqueueTextureQuad(const DrawingFrame&, const TextureDrawQuad*); + void flushTextureQuadCache(); void drawIOSurfaceQuad(const DrawingFrame&, const IOSurfaceDrawQuad*); void drawTileQuad(const DrawingFrame&, const TileDrawQuad*); void drawYUVVideoQuad(const DrawingFrame&, const YUVVideoDrawQuad*); @@ -107,6 +111,8 @@ private: void setShaderOpacity(float opacity, int alphaLocation); void setShaderQuadF(const gfx::QuadF&, int quadLocation); void drawQuadGeometry(const DrawingFrame&, const gfx::Transform& drawTransform, const gfx::RectF& quadRect, int matrixLocation); + void setBlendEnabled(bool enabled); + void setUseProgram(unsigned program); void copyTextureToFramebuffer(const DrawingFrame&, int textureId, const gfx::Rect&, const gfx::Transform& drawMatrix); @@ -219,6 +225,9 @@ private: bool m_isUsingBindUniform; bool m_visible; bool m_isScissorEnabled; + bool m_blendShadow; + unsigned m_programShadow; + TexturedQuadDrawCache m_drawCache; scoped_ptr<ResourceProvider::ScopedWriteLockGL> m_currentFramebufferLock; diff --git a/cc/gl_renderer_draw_cache.cc b/cc/gl_renderer_draw_cache.cc new file mode 100644 index 0000000..6c4c10b --- /dev/null +++ b/cc/gl_renderer_draw_cache.cc @@ -0,0 +1,16 @@ +// Copyright 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "cc/gl_renderer_draw_cache.h" + + +TexturedQuadDrawCache::TexturedQuadDrawCache() + : program_id(0) +{ +} + +TexturedQuadDrawCache::~TexturedQuadDrawCache() +{ +} + diff --git a/cc/gl_renderer_draw_cache.h b/cc/gl_renderer_draw_cache.h new file mode 100644 index 0000000..c0a2b69 --- /dev/null +++ b/cc/gl_renderer_draw_cache.h @@ -0,0 +1,42 @@ +// Copyright 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CC_GL_RENDERER_DRAW_CACHE_H_ +#define CC_GL_RENDERER_DRAW_CACHE_H_ + +#include <vector> + + +// Collects 4 floats at a time for easy upload to GL. +struct Float4 { float data[4]; }; + +// Collects 16 floats at a time for easy upload to GL. +struct Float16 { float data[16]; }; + +// A cache for storing textured quads to be drawn. Stores the minimum required +// data to tell if two back to back draws only differ in their transform. Quads +// that only differ by transform may be coalesced into a single draw call. +struct TexturedQuadDrawCache { + TexturedQuadDrawCache(); + ~TexturedQuadDrawCache(); + + // Values tracked to determine if textured quads may be coalesced. + int program_id; + int resource_id; + float alpha; + bool use_premultiplied_alpha; + bool needs_blending; + + // Information about the program binding that is required to draw. + int alpha_location; + int uv_xform_location; + int matrix_location; + + // A cache for the coalesced quad data. + std::vector<Float4> uv_xform_data; + std::vector<Float16> matrix_data; +}; + +#endif // CC_GL_RENDERER_DRAW_CACHE_H_ + diff --git a/cc/gl_renderer_unittest.cc b/cc/gl_renderer_unittest.cc index 4189db7..a8da143 100644 --- a/cc/gl_renderer_unittest.cc +++ b/cc/gl_renderer_unittest.cc @@ -105,6 +105,7 @@ public: using GLRenderer::isFramebufferDiscarded; using GLRenderer::drawQuad; using GLRenderer::beginDrawingFrame; + using GLRenderer::finishDrawingQuadList; }; class GLRendererTest : public testing::Test { @@ -544,6 +545,7 @@ TEST(GLRendererTest2, activeTextureState) it != pass->quad_list.backToFrontEnd(); ++it) { renderer.drawQuad(drawingFrame, *it); } + renderer.finishDrawingQuadList(); EXPECT_EQ(context->activeTexture(), GL_TEXTURE0); } diff --git a/cc/shader.cc b/cc/shader.cc index a9a0877..c84d88a 100644 --- a/cc/shader.cc +++ b/cc/shader.cc @@ -159,13 +159,14 @@ std::string VertexShaderPosTexTransform::getShaderString() const return SHADER( attribute vec4 a_position; attribute vec2 a_texCoord; - uniform mat4 matrix; - uniform vec4 texTransform; + attribute float a_index; + uniform mat4 matrix[8]; + uniform vec4 texTransform[8]; varying vec2 v_texCoord; void main() { - gl_Position = matrix * a_position; - v_texCoord = a_texCoord * texTransform.zw + texTransform.xy; + gl_Position = matrix[int(a_index)] * a_position; + v_texCoord = a_texCoord * texTransform[int(a_index)].zw + texTransform[int(a_index)].xy; } ); } |