Chromium Code Reviews| Index: cc/gl_renderer.cc |
| diff --git a/cc/gl_renderer.cc b/cc/gl_renderer.cc |
| index 94f8d83124f945b5118af3f5b1d07a7bbcdc5fba..3dc21ee18b2dc10a78ac98d6de48599429146bf4 100644 |
| --- a/cc/gl_renderer.cc |
| +++ b/cc/gl_renderer.cc |
| @@ -59,6 +59,58 @@ bool needsIOSurfaceReadbackWorkaround() |
| } // anonymous namespace |
| +// A basic vector class, used for vertex transforms and OpenGL vector upload |
| +struct Vector { |
|
jamesr
2012/11/28 00:00:37
cc/math_util.h has a HomogeneousCoordinate that's
whunt
2012/11/28 00:29:08
In truth we no longer need any math because I'm no
shawnsingh
2012/11/28 19:44:16
I think we should do the following:
(1) merge this
|
| + float x, y, z, w; |
| + Vector() {} |
| + Vector(float x, float y, float z = 0.0f, float w = 0.0f) |
| + : x(x), y(y), z(z), w(w) { } |
| +}; |
| + |
| +// A basic matrix class, used for vertex transforms and OpenGL matrix upload |
| +struct Matrix { |
|
danakj
2012/11/27 23:47:47
Is there some reason to not just use gfx::Transfor
whunt
2012/11/28 00:29:08
This only works if gfx::Transform is of float type
danakj
2012/11/28 00:43:58
Oh okay, thanks for the explanation. Let's call it
|
| + Vector x, y, z, w; |
| + Matrix() {} |
| + Matrix(const Vector& x, const Vector& y, const Vector& z, const Vector& w) |
| + : x(x), y(y), z(z), w(w) { } |
| +}; |
| + |
| +// An alternate vector constructor that defaults to w = 1.0f rather than w = 0.0f |
| +inline Vector const Point(float x, float y, float z = 0.0f, float w = 1.0f) { return Vector(x, y, z, w); } |
| + |
| +// The most basic math required to implement vertex transforms |
| +inline Vector const operator +(const Vector& a, const Vector& b) { return Vector(a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w); } |
| +inline Vector const operator *(const Vector& a, float b) { return Vector(a.x * b, a.y * b, a.z * b, a.w * b); } |
| +inline Vector const operator *(const Matrix& m, const Vector& v) { return m.x * v.x + m.y * v.y + m.z * v.z + m.w * v.w; } |
| + |
| +// 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 |
|
jamesr
2012/11/28 00:00:37
Could we put this in its own file? Adding a new f
whunt
2012/11/28 00:29:08
Sure, no problem.
On 2012/11/28 00:00:37, jamesr
|
| +{ |
| + // Values tracked to determine if textured quads may be coalesced |
| + int programID; |
| + int resourceID; |
| + float alpha; |
| + bool usePremultipliedAlpha; |
| + bool needsBlending; |
| + |
| + // Information about the program binding that is required to draw |
| + int alphaLocation; |
| + int uvXformLocation; |
| + int matrixLocation; |
| + |
| + // A cache for the coalesced quad data |
| + std::vector<Vector> uvXformData; |
| + std::vector<Matrix> matrixData; |
| + |
| + TexturedQuadDrawCache() |
| + : programID(0) |
| + , resourceID(0) |
|
jamesr
2012/11/28 00:00:37
could you initialize all scalars and move the cons
whunt
2012/11/28 00:29:08
Constructor moved.
About initialization. I *can*
|
| + { |
| + } |
| +}; |
| + |
| scoped_ptr<GLRenderer> GLRenderer::create(RendererClient* client, ResourceProvider* resourceProvider) |
| { |
| scoped_ptr<GLRenderer> renderer(make_scoped_ptr(new GLRenderer(client, resourceProvider))); |
| @@ -79,6 +131,7 @@ GLRenderer::GLRenderer(RendererClient* client, ResourceProvider* resourceProvide |
| , m_isUsingBindUniform(false) |
| , m_visible(true) |
| , m_isScissorEnabled(false) |
| + , m_drawCache(new TexturedQuadDrawCache()) |
|
jamesr
2012/11/28 00:00:37
if we had TextureQuadDrawCache in its own header,
whunt
2012/11/28 00:29:08
This is true, but that would make everything that
|
| { |
| DCHECK(m_context); |
| } |
| @@ -243,6 +296,8 @@ void GLRenderer::beginDrawingFrame(DrawingFrame& frame) |
| GLC(m_context, m_context->enable(GL_BLEND)); |
| GLC(m_context, m_context->blendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA)); |
| GLC(context(), context()->activeTexture(GL_TEXTURE0)); |
| + m_blendShadow = true; |
| + m_programShadow = 0; |
| } |
| void GLRenderer::doNoOp() |
| @@ -254,11 +309,11 @@ 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) |
| + { |
| + drawTextureQuadFlush(); |
| + setBlendEnabled(quad->ShouldDrawWithBlending()); |
| + } |
| switch (quad->material) { |
| case DrawQuad::INVALID: |
| @@ -283,7 +338,7 @@ void GLRenderer::drawQuad(DrawingFrame& frame, const DrawQuad* quad) |
| drawStreamVideoQuad(frame, StreamVideoDrawQuad::MaterialCast(quad)); |
| break; |
| case DrawQuad::TEXTURE_CONTENT: |
| - drawTextureQuad(frame, TextureDrawQuad::MaterialCast(quad)); |
| + drawTextureQuadPush(frame, TextureDrawQuad::MaterialCast(quad)); |
| break; |
| case DrawQuad::TILED_CONTENT: |
| drawTileQuad(frame, TileDrawQuad::MaterialCast(quad)); |
| @@ -298,7 +353,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 +379,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 +397,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 +642,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 +654,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 +664,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 +673,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 +715,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 +833,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 +950,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 +993,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 +1032,101 @@ struct TexTransformTextureProgramBinding : TextureProgramBinding { |
| int texTransformLocation; |
| }; |
| +void GLRenderer::drawTextureQuadFlush() |
| +{ |
| + // Check to see if we have anything to draw |
| + if (m_drawCache->programID == 0) |
| + return; |
| + |
| + // Set the correct blending mode |
| + setBlendEnabled(m_drawCache->needsBlending); |
| + |
| + // Bind the program to the GL state |
| + setUseProgram(m_drawCache->programID); |
| + |
| + // Bind the texture to slot 0 |
| + GLC(context(), context()->activeTexture(GL_TEXTURE0)); |
| + ResourceProvider::ScopedReadLockGL lockedQuad(m_resourceProvider, m_drawCache->resourceID); |
| + GLC(context(), context()->bindTexture(GL_TEXTURE_2D, lockedQuad.textureId())); |
| + |
| + // set up premultiplied alpha |
| + if (!m_drawCache->usePremultipliedAlpha) { |
| + // 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->alphaLocation); |
| + |
| + // Upload the tranforms for both points and uvs |
| + GLC(m_context, m_context->uniformMatrix4fv((int)m_drawCache->matrixLocation, (int)m_drawCache->matrixData.size(), false, (float*)&m_drawCache->matrixData.front())); |
| + GLC(m_context, m_context->uniform4fv((int)m_drawCache->uvXformLocation, (int)m_drawCache->uvXformData.size(), (float*)&m_drawCache->uvXformData.front())); |
| + |
| + // Draw the quads! |
| + GLC(m_context, m_context->drawElements(GL_TRIANGLES, 6 * m_drawCache->matrixData.size(), GL_UNSIGNED_SHORT, 0)); |
| + |
| + // Clean up after ourselves (reset state set above) |
| + if (!m_drawCache->usePremultipliedAlpha) |
| + GLC(m_context, m_context->blendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA)); |
| + |
| + // Clear the cache |
| + m_drawCache->programID = 0; |
| + m_drawCache->uvXformData.resize(0); |
| + m_drawCache->matrixData.resize(0); |
| +} |
| + |
| +void GLRenderer::drawTextureQuadPush(const DrawingFrame& frame, const TextureDrawQuad* quad) |
|
shawnsingh
2012/11/28 19:44:16
The name at a glance doesn't make me think about t
whunt
2012/11/28 22:01:15
I like that suggestion. Done.
On 2012/11/28 19:44
|
| +{ |
| + // 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->programID != binding.programId || |
| + m_drawCache->resourceID != resourceID || |
| + m_drawCache->alpha != quad->opacity() || |
| + m_drawCache->usePremultipliedAlpha != quad->premultiplied_alpha || |
| + m_drawCache->needsBlending != quad->ShouldDrawWithBlending() || |
| + m_drawCache->matrixData.size() >= 8) |
| + { |
| + drawTextureQuadFlush(); |
| + m_drawCache->programID = binding.programId; |
| + m_drawCache->resourceID = resourceID; |
| + m_drawCache->alpha = quad->opacity(); |
| + m_drawCache->usePremultipliedAlpha = quad->premultiplied_alpha; |
| + m_drawCache->needsBlending = quad->ShouldDrawWithBlending(); |
| + |
| + m_drawCache->alphaLocation = binding.alphaLocation; |
| + m_drawCache->uvXformLocation = binding.texTransformLocation; |
| + m_drawCache->matrixLocation = binding.matrixLocation; |
| + } |
| + |
| + // Generate the uv-transform |
| + const gfx::RectF& uvRect = quad->uv_rect; |
| + Vector uv(uvRect.x(), uvRect.y(), uvRect.width(), uvRect.height()); |
| + m_drawCache->uvXformData.push_back(uv); |
| + |
| + // Generate the transform matrix |
| + gfx::Transform quadRectMatrix; |
| + quadRectTransform(&quadRectMatrix, quad->quadTransform(), quad->rect); |
| + quadRectMatrix = frame.projectionMatrix * quadRectMatrix; |
| + |
| + Matrix m; |
| + quadRectMatrix.matrix().asColMajorf((float*)&m); |
| + m_drawCache->matrixData.push_back(m); |
| +} |
| + |
| void GLRenderer::drawTextureQuad(const DrawingFrame& frame, const TextureDrawQuad* quad) |
| { |
| TexTransformTextureProgramBinding binding; |
| @@ -984,7 +1134,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 +1166,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 +1187,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() |
| +{ |
| + drawTextureQuadFlush(); |
| } |
| bool GLRenderer::flippedFramebuffer() const |
| @@ -1049,6 +1205,7 @@ void GLRenderer::ensureScissorTestEnabled() |
| if (m_isScissorEnabled) |
| return; |
| + drawTextureQuadFlush(); |
| GLC(m_context, m_context->enable(GL_SCISSOR_TEST)); |
| m_isScissorEnabled = true; |
| } |
| @@ -1058,6 +1215,7 @@ void GLRenderer::ensureScissorTestDisabled() |
| if (!m_isScissorEnabled) |
| return; |
| + drawTextureQuadFlush(); |
| GLC(m_context, m_context->disable(GL_SCISSOR_TEST)); |
| m_isScissorEnabled = false; |
| } |
| @@ -1090,6 +1248,27 @@ void GLRenderer::setShaderOpacity(float opacity, int alphaLocation) |
| GLC(m_context, m_context->uniform1f(alphaLocation, opacity)); |
| } |
| +void GLRenderer::setBlendEnabled(bool enabled) |
| +{ |
| + if (enabled != m_blendShadow) |
| + { |
| + 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) |
| + { |
| + 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 +1286,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 +1537,7 @@ void GLRenderer::setScissorTestRect(const gfx::Rect& scissorRect) |
| return; |
| m_scissorRect = scissorRect; |
| + drawTextureQuadFlush(); |
| GLC(m_context, m_context->scissor(scissorRect.x(), scissorRect.y(), scissorRect.width(), scissorRect.height())); |
| } |
| @@ -1527,6 +1707,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 +1719,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(); |
| } |