0

Allow using a larger-than-necessary texture as cached render pass backing

When moving a composited layer around the screen that requires a render pass,
it's not all that unusual for the required size to be slightly different from
frame to frame. This lets us use an oversized texture as the framebuffer
attachment.

BUG=161868


Review URL: https://chromiumcodereview.appspot.com/11420079

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@173112 0039d316-1c4b-4281-b951-d872f2087c98
This commit is contained in:
jamesr@chromium.org
2012-12-14 07:13:48 +00:00
parent cf64404b03
commit 66321643bd
7 changed files with 165 additions and 35 deletions

@ -113,6 +113,11 @@ DirectRenderer::~DirectRenderer()
{
}
void DirectRenderer::setEnlargePassTextureAmountForTesting(gfx::Vector2d amount)
{
m_enlargePassTextureAmount = amount;
}
void DirectRenderer::decideRenderPassAllocationsForFrame(const RenderPassList& renderPassesInDrawOrder)
{
base::hash_map<RenderPass::Id, const RenderPass*> renderPassesInFrame;
@ -134,7 +139,9 @@ void DirectRenderer::decideRenderPassAllocationsForFrame(const RenderPassList& r
CachedResource* texture = passIterator->second;
DCHECK(texture);
if (texture->id() && (texture->size() != requiredSize || texture->format() != requiredFormat))
bool sizeAppropriate = texture->size().width() >= requiredSize.width() &&
texture->size().height() >= requiredSize.height();
if (texture->id() && (!sizeAppropriate || texture->format() != requiredFormat))
texture->Free();
}
@ -267,7 +274,10 @@ bool DirectRenderer::useRenderPass(DrawingFrame& frame, const RenderPass* render
CachedResource* texture = m_renderPassTextures.get(renderPass->id);
DCHECK(texture);
if (!texture->id() && !texture->Allocate(Renderer::ImplPool, renderPassTextureSize(renderPass), renderPassTextureFormat(renderPass), ResourceProvider::TextureUsageFramebuffer))
gfx::Size size = renderPassTextureSize(renderPass);
size.Enlarge(m_enlargePassTextureAmount.x(), m_enlargePassTextureAmount.y());
if (!texture->id() && !texture->Allocate(Renderer::ImplPool, size, renderPassTextureFormat(renderPass), ResourceProvider::TextureUsageFramebuffer))
return false;
return bindFramebufferToTexture(frame, texture, renderPass->output_rect);

@ -44,6 +44,8 @@ public:
bool flippedY;
};
void setEnlargePassTextureAmountForTesting(gfx::Vector2d amount);
protected:
DirectRenderer(RendererClient* client, ResourceProvider* resourceProvider);
@ -102,6 +104,9 @@ protected:
ResourceProvider* m_resourceProvider;
private:
gfx::Vector2d m_enlargePassTextureAmount;
DISALLOW_COPY_AND_ASSIGN(DirectRenderer);
};

@ -494,7 +494,7 @@ scoped_ptr<ScopedResource> GLRenderer::drawBackgroundFilters(
// Copy the readback pixels from device to the background texture for the surface.
gfx::Transform deviceToFramebufferTransform;
deviceToFramebufferTransform.Translate(quad->rect.width() / 2.0, quad->rect.height() / 2.0);
deviceToFramebufferTransform.Scale3d(quad->rect.width(), quad->rect.height(), 1);
deviceToFramebufferTransform.Scale(quad->rect.width(), quad->rect.height());
deviceToFramebufferTransform.PreconcatTransform(contentsDeviceTransformInverse);
copyTextureToFramebuffer(frame, filteredDeviceBackgroundTextureId, deviceRect, deviceToFramebufferTransform);
}
@ -583,6 +583,9 @@ void GLRenderer::drawRenderPassQuad(DrawingFrame& frame, const RenderPassDrawQua
int shaderMaskTexCoordOffsetLocation = -1;
int shaderMatrixLocation = -1;
int shaderAlphaLocation = -1;
int shaderTexTransformLocation = -1;
int shaderTexScaleLocation = -1;
if (useAA && maskTextureId) {
const RenderPassMaskProgramAA* program = renderPassMaskProgramAA();
setUseProgram(program->program());
@ -595,6 +598,7 @@ void GLRenderer::drawRenderPassQuad(DrawingFrame& frame, const RenderPassDrawQua
shaderMaskTexCoordOffsetLocation = program->fragmentShader().maskTexCoordOffsetLocation();
shaderMatrixLocation = program->vertexShader().matrixLocation();
shaderAlphaLocation = program->fragmentShader().alphaLocation();
shaderTexScaleLocation = program->vertexShader().texScaleLocation();
} else if (!useAA && maskTextureId) {
const RenderPassMaskProgram* program = renderPassMaskProgram();
setUseProgram(program->program());
@ -605,6 +609,7 @@ void GLRenderer::drawRenderPassQuad(DrawingFrame& frame, const RenderPassDrawQua
shaderMaskTexCoordOffsetLocation = program->fragmentShader().maskTexCoordOffsetLocation();
shaderMatrixLocation = program->vertexShader().matrixLocation();
shaderAlphaLocation = program->fragmentShader().alphaLocation();
shaderTexTransformLocation = program->vertexShader().texTransformLocation();
} else if (useAA && !maskTextureId) {
const RenderPassProgramAA* program = renderPassProgramAA();
setUseProgram(program->program());
@ -614,6 +619,7 @@ void GLRenderer::drawRenderPassQuad(DrawingFrame& frame, const RenderPassDrawQua
shaderEdgeLocation = program->fragmentShader().edgeLocation();
shaderMatrixLocation = program->vertexShader().matrixLocation();
shaderAlphaLocation = program->fragmentShader().alphaLocation();
shaderTexScaleLocation = program->vertexShader().texScaleLocation();
} else {
const RenderPassProgram* program = renderPassProgram();
setUseProgram(program->program());
@ -621,6 +627,23 @@ void GLRenderer::drawRenderPassQuad(DrawingFrame& frame, const RenderPassDrawQua
shaderMatrixLocation = program->vertexShader().matrixLocation();
shaderAlphaLocation = program->fragmentShader().alphaLocation();
shaderTexTransformLocation = program->vertexShader().texTransformLocation();
}
float tex_scale_x = quad->rect.width() / static_cast<float>(contentsTexture->size().width());
float tex_scale_y = quad->rect.height() / static_cast<float>(contentsTexture->size().height());
DCHECK_LE(tex_scale_x, 1.0f);
DCHECK_LE(tex_scale_y, 1.0f);
if (shaderTexTransformLocation != -1) {
GLC(context(), context()->uniform4f(shaderTexTransformLocation,
0.0f, 0.0f,
tex_scale_x, tex_scale_y));
} else if (shaderTexScaleLocation != -1) {
GLC(context(), context()->uniform2f(shaderTexScaleLocation,
tex_scale_x, tex_scale_y));
} else {
NOTREACHED();
}
if (shaderMaskSamplerLocation != -1) {
@ -628,8 +651,10 @@ void GLRenderer::drawRenderPassQuad(DrawingFrame& frame, const RenderPassDrawQua
DCHECK(shaderMaskTexCoordOffsetLocation != 1);
GLC(context(), context()->activeTexture(GL_TEXTURE1));
GLC(context(), context()->uniform1i(shaderMaskSamplerLocation, 1));
GLC(context(), context()->uniform2f(shaderMaskTexCoordOffsetLocation, quad->mask_uv_rect.x(), quad->mask_uv_rect.y()));
GLC(context(), context()->uniform2f(shaderMaskTexCoordScaleLocation, quad->mask_uv_rect.width(), quad->mask_uv_rect.height()));
GLC(context(), context()->uniform2f(shaderMaskTexCoordOffsetLocation,
quad->mask_uv_rect.x(), quad->mask_uv_rect.y()));
GLC(context(), context()->uniform2f(shaderMaskTexCoordScaleLocation,
quad->mask_uv_rect.width() / tex_scale_x, quad->mask_uv_rect.height() / tex_scale_y));
m_resourceProvider->bindForSampling(quad->mask_resource_id, GL_TEXTURE_2D, GL_LINEAR);
GLC(context(), context()->activeTexture(GL_TEXTURE0));
}
@ -1232,6 +1257,8 @@ void GLRenderer::copyTextureToFramebuffer(const DrawingFrame& frame, int texture
setUseProgram(program->program());
GLC(context(), context()->uniform1i(program->fragmentShader().samplerLocation(), 0));
GLC(context(), context()->uniform4f(program->vertexShader().texTransformLocation(),
0.0f, 0.0f, 1.0f, 1.0f));
setShaderOpacity(1, program->fragmentShader().alphaLocation());
drawQuadGeometry(frame, drawMatrix, rect, program->vertexShader().matrixLocation());
}

@ -97,7 +97,8 @@ private:
void drawCheckerboardQuad(const DrawingFrame&, const CheckerboardDrawQuad*);
void drawDebugBorderQuad(const DrawingFrame&, const DebugBorderDrawQuad*);
scoped_ptr<ScopedResource> drawBackgroundFilters(
DrawingFrame&, const RenderPassDrawQuad*, const WebKit::WebFilterOperations&,
DrawingFrame&, const RenderPassDrawQuad*,
const WebKit::WebFilterOperations&,
const gfx::Transform& contentsDeviceTransform,
const gfx::Transform& contentsDeviceTransformInverse);
void drawRenderPassQuad(DrawingFrame&, const RenderPassDrawQuad*);
@ -156,8 +157,8 @@ private:
typedef ProgramBinding<VertexShaderPosTex, FragmentShaderCheckerboard> TileCheckerboardProgram;
// Render surface shaders.
typedef ProgramBinding<VertexShaderPosTex, FragmentShaderRGBATexAlpha> RenderPassProgram;
typedef ProgramBinding<VertexShaderPosTex, FragmentShaderRGBATexAlphaMask> RenderPassMaskProgram;
typedef ProgramBinding<VertexShaderPosTexTransform, FragmentShaderRGBATexAlpha> RenderPassProgram;
typedef ProgramBinding<VertexShaderPosTexTransform, FragmentShaderRGBATexAlphaMask> RenderPassMaskProgram;
typedef ProgramBinding<VertexShaderQuad, FragmentShaderRGBATexAlphaAA> RenderPassProgramAA;
typedef ProgramBinding<VertexShaderQuad, FragmentShaderRGBATexAlphaMaskAA> RenderPassMaskProgramAA;

@ -43,7 +43,6 @@ class FakeRendererClient : public RendererClient {
virtual bool hasImplThread() const OVERRIDE { return false; }
};
class GLRendererPixelTest : public testing::Test {
protected:
GLRendererPixelTest() {}
@ -55,24 +54,38 @@ class GLRendererPixelTest : public testing::Test {
renderer_ = GLRenderer::create(&fake_client_, resource_provider_.get());
}
bool PixelsMatchReference(FilePath ref_file, gfx::Rect viewport_rect) {
SkBitmap bitmap;
bitmap.setConfig(SkBitmap::kARGB_8888_Config,
viewport_rect.width(), viewport_rect.height());
bitmap.allocPixels();
unsigned char* pixels = static_cast<unsigned char*>(bitmap.getPixels());
renderer_->getFramebufferPixels(pixels, viewport_rect);
FilePath test_data_dir;
if (!PathService::Get(cc::test::DIR_TEST_DATA, &test_data_dir))
return false;
return test::IsSameAsPNGFile(bitmap, test_data_dir.Append(ref_file));
}
scoped_ptr<OutputSurface> output_surface_;
FakeRendererClient fake_client_;
scoped_ptr<ResourceProvider> resource_provider_;
scoped_ptr<GLRenderer> renderer_;
};
#if !defined(OS_ANDROID)
TEST_F(GLRendererPixelTest, simpleGreenRect) {
gfx::Rect rect(0, 0, 200, 200);
RenderPass::Id id(1, 1);
scoped_ptr<RenderPass> CreateTestRenderPass(RenderPass::Id id, gfx::Rect rect) {
scoped_ptr<RenderPass> pass = RenderPass::Create();
const gfx::Rect output_rect = rect;
const gfx::RectF damage_rect = rect;
const gfx::Transform transform_to_root_target;
scoped_ptr<RenderPass> pass = RenderPass::Create();
pass->SetNew(id, output_rect, damage_rect, transform_to_root_target);
return pass.Pass();
}
const gfx::Transform content_to_target_transform;
scoped_ptr<SharedQuadState> CreateTestSharedQuadState(
gfx::Transform content_to_target_transform, gfx::Rect rect) {
const gfx::Rect visible_content_rect = rect;
const gfx::Rect clipped_rect_in_target = rect;
const gfx::Rect clip_rect = rect;
@ -85,6 +98,34 @@ TEST_F(GLRendererPixelTest, simpleGreenRect) {
clip_rect,
is_clipped,
opacity);
return shared_state.Pass();
}
scoped_ptr<DrawQuad> CreateTestRenderPassDrawQuad(
SharedQuadState* shared_state, gfx::Rect rect, RenderPass::Id pass_id) {
scoped_ptr<RenderPassDrawQuad> quad = RenderPassDrawQuad::Create();
quad->SetNew(shared_state,
rect,
pass_id,
false, // is_replica
0, // mask_resource_id
rect, // contents_changed_since_last_frame
gfx::RectF()); // mask_uv_rect
return quad.PassAs<DrawQuad>();
}
#if !defined(OS_ANDROID)
TEST_F(GLRendererPixelTest, simpleGreenRect) {
gfx::Rect rect(0, 0, 200, 200);
RenderPass::Id id(1, 1);
scoped_ptr<RenderPass> pass = CreateTestRenderPass(id, rect);
gfx::Transform content_to_target_transform;
scoped_ptr<SharedQuadState> shared_state =
CreateTestSharedQuadState(content_to_target_transform, rect);
scoped_ptr<SolidColorDrawQuad> color_quad = SolidColorDrawQuad::Create();
color_quad->SetNew(shared_state.get(), rect, SK_ColorGREEN);
@ -98,17 +139,55 @@ TEST_F(GLRendererPixelTest, simpleGreenRect) {
renderer_->drawFrame(pass_list, pass_map);
SkBitmap bitmap;
bitmap.setConfig(SkBitmap::kARGB_8888_Config, 200, 200);
bitmap.allocPixels();
unsigned char* pixels = static_cast<unsigned char*>(bitmap.getPixels());
renderer_->getFramebufferPixels(pixels, gfx::Rect(0, 0, 200, 200));
EXPECT_TRUE(PixelsMatchReference(FilePath(FILE_PATH_LITERAL("green.png")),
rect));
}
FilePath test_data_dir;
ASSERT_TRUE(PathService::Get(cc::test::DIR_TEST_DATA, &test_data_dir));
// test::WritePNGFile(bitmap, test_data_dir.AppendASCII("green.png"));
EXPECT_TRUE(test::IsSameAsPNGFile(bitmap,
test_data_dir.AppendASCII("green.png")));
TEST_F(GLRendererPixelTest, RenderPassChangesSize) {
gfx::Rect viewport_rect(200, 200);
RenderPass::Id root_pass_id(1, 1);
scoped_ptr<RenderPass> root_pass =
CreateTestRenderPass(root_pass_id, viewport_rect);
RenderPass::Id child_pass_id(2, 2);
gfx::Rect pass_rect(200, 200);
scoped_ptr<RenderPass> child_pass =
CreateTestRenderPass(child_pass_id, pass_rect);
gfx::Transform content_to_target_transform;
scoped_ptr<SharedQuadState> shared_state =
CreateTestSharedQuadState(content_to_target_transform, viewport_rect);
scoped_ptr<SolidColorDrawQuad> blue = SolidColorDrawQuad::Create();
blue->SetNew(shared_state.get(), gfx::Rect(0, 0, 100, 200), SK_ColorBLUE);
scoped_ptr<SolidColorDrawQuad> yellow = SolidColorDrawQuad::Create();
yellow->SetNew(shared_state.get(), gfx::Rect(100, 0, 100, 200), SK_ColorYELLOW);
child_pass->quad_list.append(blue.PassAs<DrawQuad>());
child_pass->quad_list.append(yellow.PassAs<DrawQuad>());
scoped_ptr<SharedQuadState> pass_shared_state =
CreateTestSharedQuadState(gfx::Transform(), pass_rect);
root_pass->quad_list.append(
CreateTestRenderPassDrawQuad(pass_shared_state.get(),
pass_rect,
child_pass_id));
RenderPassList pass_list;
pass_list.push_back(child_pass.get());
pass_list.push_back(root_pass.get());
RenderPassIdHashMap pass_map;
pass_map.add(child_pass_id, child_pass.Pass());
pass_map.add(root_pass_id, root_pass.Pass());
renderer_->setEnlargePassTextureAmountForTesting(gfx::Vector2d(50, 75));
renderer_->decideRenderPassAllocationsForFrame(pass_list);
renderer_->drawFrame(pass_list, pass_map);
EXPECT_TRUE(PixelsMatchReference(
FilePath(FILE_PATH_LITERAL("blue_yellow.png")), viewport_rect));
}
#endif

@ -171,12 +171,6 @@ std::string VertexShaderPosTexTransform::getShaderString() const
);
}
VertexShaderQuad::VertexShaderQuad()
: m_matrixLocation(-1)
, m_pointLocation(-1)
{
}
std::string VertexShaderPosTexIdentity::getShaderString() const
{
return SHADER(
@ -190,19 +184,30 @@ std::string VertexShaderPosTexIdentity::getShaderString() const
);
}
VertexShaderQuad::VertexShaderQuad()
: m_matrixLocation(-1)
, m_pointLocation(-1)
, m_texScaleLocation(-1)
{
}
void VertexShaderQuad::init(WebGraphicsContext3D* context, unsigned program, bool usingBindUniform, int* baseUniformIndex)
{
static const char* shaderUniforms[] = {
"matrix",
"point",
"texScale",
};
int locations[2];
int locations[3];
getProgramUniformLocations(context, program, shaderUniforms, arraysize(shaderUniforms), arraysize(locations), locations, usingBindUniform, baseUniformIndex);
m_matrixLocation = locations[0];
m_pointLocation = locations[1];
DCHECK(m_matrixLocation != -1 && m_pointLocation != -1);
m_texScaleLocation = locations[2];
DCHECK_NE(m_matrixLocation, -1);
DCHECK_NE(m_pointLocation, -1);
DCHECK_NE(m_texScaleLocation, -1);
}
std::string VertexShaderQuad::getShaderString() const
@ -212,6 +217,7 @@ std::string VertexShaderQuad::getShaderString() const
attribute vec2 a_texCoord;
uniform mat4 matrix;
uniform vec2 point[4];
uniform vec2 texScale;
varying vec2 v_texCoord;
void main()
{
@ -222,7 +228,7 @@ std::string VertexShaderQuad::getShaderString() const
pos.xy += (a_texCoord.x * a_texCoord.y) * point[2];
pos.xy += (complement.x * a_texCoord.y) * point[3];
gl_Position = matrix * pos;
v_texCoord = pos.xy + vec2(0.5);
v_texCoord = (pos.xy + vec2(0.5)) * texScale;
}
);
}

@ -85,10 +85,12 @@ public:
int matrixLocation() const { return m_matrixLocation; }
int pointLocation() const { return m_pointLocation; }
int texScaleLocation() const { return m_texScaleLocation; }
private:
int m_matrixLocation;
int m_pointLocation;
int m_texScaleLocation;
};
class VertexShaderTile {