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:
@ -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
|
||||
|
||||
|
24
cc/shader.cc
24
cc/shader.cc
@ -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 {
|
||||
|
Reference in New Issue
Block a user