diff options
author | gman@chromium.org <gman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-06-07 01:33:30 +0000 |
---|---|---|
committer | gman@chromium.org <gman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-06-07 01:33:30 +0000 |
commit | 473c01ccb10d0e459a6f06784c38ed8e2bc7215b (patch) | |
tree | 9ddc6e7fb736d2c20764f90f259a1e3613a98fca | |
parent | 0b407aea9852913d5a3825de8e9a9db017b49982 (diff) | |
download | chromium_src-473c01ccb10d0e459a6f06784c38ed8e2bc7215b.zip chromium_src-473c01ccb10d0e459a6f06784c38ed8e2bc7215b.tar.gz chromium_src-473c01ccb10d0e459a6f06784c38ed8e2bc7215b.tar.bz2 |
Optimize TexSubImage2D and BufferSubData
They now call TexImage2D and BufferData if possible.
TEST=some unit test, ran conformance tests
BUG=84977
R=apatrick@chromium.org
Review URL: http://codereview.chromium.org/6993049
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@88078 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | gpu/command_buffer/service/buffer_manager.cc | 13 | ||||
-rw-r--r-- | gpu/command_buffer/service/buffer_manager.h | 13 | ||||
-rw-r--r-- | gpu/command_buffer/service/buffer_manager_unittest.cc | 16 | ||||
-rw-r--r-- | gpu/command_buffer/service/gles2_cmd_decoder.cc | 110 | ||||
-rw-r--r-- | gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc | 7 | ||||
-rw-r--r-- | gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc | 3 |
6 files changed, 123 insertions, 39 deletions
diff --git a/gpu/command_buffer/service/buffer_manager.cc b/gpu/command_buffer/service/buffer_manager.cc index fadbbad..e5f1fbd 100644 --- a/gpu/command_buffer/service/buffer_manager.cc +++ b/gpu/command_buffer/service/buffer_manager.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 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. @@ -58,13 +58,16 @@ BufferManager::BufferInfo::BufferInfo(GLuint service_id) : service_id_(service_id), target_(0), size_(0), + usage_(GL_STATIC_DRAW), shadowed_(false) { } BufferManager::BufferInfo::~BufferInfo() { } -void BufferManager::BufferInfo::SetSize(GLsizeiptr size, bool shadow) { +void BufferManager::BufferInfo::SetInfo( + GLsizeiptr size, GLenum usage, bool shadow) { DCHECK(!IsDeleted()); + usage_ = usage; if (size != size_ || shadow != shadowed_) { shadowed_ = shadow; size_ = size; @@ -188,9 +191,11 @@ bool BufferManager::GetClientId(GLuint service_id, GLuint* client_id) const { return false; } -void BufferManager::SetSize(BufferManager::BufferInfo* info, GLsizeiptr size) { +void BufferManager::SetInfo( + BufferManager::BufferInfo* info, GLsizeiptr size, GLenum usage) { DCHECK(info); - info->SetSize(size, + info->SetInfo(size, + usage, info->target() == GL_ELEMENT_ARRAY_BUFFER || allow_buffers_on_multiple_targets_); } diff --git a/gpu/command_buffer/service/buffer_manager.h b/gpu/command_buffer/service/buffer_manager.h index 6569116..6f67e53 100644 --- a/gpu/command_buffer/service/buffer_manager.h +++ b/gpu/command_buffer/service/buffer_manager.h @@ -38,6 +38,10 @@ class BufferManager { return size_; } + GLenum usage() const { + return usage_; + } + // Sets a range of data for this buffer. Returns false if the offset or size // is out of range. bool SetRange( @@ -115,7 +119,7 @@ class BufferManager { ClearCache(); } - void SetSize(GLsizeiptr size, bool shadow); + void SetInfo(GLsizeiptr size, GLenum usage, bool shadow); // Clears any cache of index ranges. void ClearCache(); @@ -131,6 +135,9 @@ class BufferManager { // Size of buffer. GLsizeiptr size_; + // Usage of buffer. + GLenum usage_; + // Whether or not the data is shadowed. bool shadowed_; @@ -161,8 +168,8 @@ class BufferManager { // Gets a client id for a given service id. bool GetClientId(GLuint service_id, GLuint* client_id) const; - // Sets the size of a buffer. - void SetSize(BufferInfo* info, GLsizeiptr size); + // Sets the size and usage of a buffer. + void SetInfo(BufferInfo* info, GLsizeiptr size, GLenum usage); // Sets the target of a buffer. Returns false if the target can not be set. bool SetTarget(BufferInfo* info, GLenum target); diff --git a/gpu/command_buffer/service/buffer_manager_unittest.cc b/gpu/command_buffer/service/buffer_manager_unittest.cc index af09788..1e4258b 100644 --- a/gpu/command_buffer/service/buffer_manager_unittest.cc +++ b/gpu/command_buffer/service/buffer_manager_unittest.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 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. @@ -49,6 +49,7 @@ TEST_F(BufferManagerTest, Basic) { ASSERT_TRUE(info1 != NULL); EXPECT_EQ(0u, GetTarget(info1)); EXPECT_EQ(0, info1->size()); + EXPECT_EQ(static_cast<GLenum>(GL_STATIC_DRAW), info1->usage()); EXPECT_FALSE(info1->IsDeleted()); EXPECT_EQ(kServiceBuffer1Id, info1->service_id()); GLuint client_id = 0; @@ -57,8 +58,9 @@ TEST_F(BufferManagerTest, Basic) { manager_.SetTarget(info1, GL_ELEMENT_ARRAY_BUFFER); EXPECT_EQ(static_cast<GLenum>(GL_ELEMENT_ARRAY_BUFFER), GetTarget(info1)); // Check we and set its size. - manager_.SetSize(info1, kBuffer1Size); + manager_.SetInfo(info1, kBuffer1Size, GL_DYNAMIC_DRAW); EXPECT_EQ(kBuffer1Size, info1->size()); + EXPECT_EQ(static_cast<GLenum>(GL_DYNAMIC_DRAW), info1->usage()); // Check we get nothing for a non-existent buffer. EXPECT_TRUE(manager_.GetBufferInfo(kClientBuffer2Id) == NULL); // Check trying to a remove non-existent buffers does not crash. @@ -94,7 +96,7 @@ TEST_F(BufferManagerTest, SetRange) { BufferManager::BufferInfo* info = manager_.GetBufferInfo(kClientBufferId); ASSERT_TRUE(info != NULL); manager_.SetTarget(info, GL_ELEMENT_ARRAY_BUFFER); - manager_.SetSize(info, sizeof(data)); + manager_.SetInfo(info, sizeof(data), GL_STATIC_DRAW); EXPECT_TRUE(info->SetRange(0, sizeof(data), data)); EXPECT_TRUE(info->SetRange(sizeof(data), 0, data)); EXPECT_FALSE(info->SetRange(sizeof(data), 1, data)); @@ -111,7 +113,7 @@ TEST_F(BufferManagerTest, GetRange) { BufferManager::BufferInfo* info = manager_.GetBufferInfo(kClientBufferId); ASSERT_TRUE(info != NULL); manager_.SetTarget(info, GL_ELEMENT_ARRAY_BUFFER); - manager_.SetSize(info, sizeof(data)); + manager_.SetInfo(info, sizeof(data), GL_STATIC_DRAW); const char* buf = static_cast<const char*>(info->GetRange(0, sizeof(data))); ASSERT_TRUE(buf != NULL); const char* buf1 = @@ -132,7 +134,7 @@ TEST_F(BufferManagerTest, GetMaxValueForRangeUint8) { BufferManager::BufferInfo* info = manager_.GetBufferInfo(kClientBufferId); ASSERT_TRUE(info != NULL); manager_.SetTarget(info, GL_ELEMENT_ARRAY_BUFFER); - manager_.SetSize(info, sizeof(data)); + manager_.SetInfo(info, sizeof(data), GL_STATIC_DRAW); EXPECT_TRUE(info->SetRange(0, sizeof(data), data)); GLuint max_value; // Check entire range succeeds. @@ -162,7 +164,7 @@ TEST_F(BufferManagerTest, GetMaxValueForRangeUint16) { BufferManager::BufferInfo* info = manager_.GetBufferInfo(kClientBufferId); ASSERT_TRUE(info != NULL); manager_.SetTarget(info, GL_ELEMENT_ARRAY_BUFFER); - manager_.SetSize(info, sizeof(data)); + manager_.SetInfo(info, sizeof(data), GL_STATIC_DRAW); EXPECT_TRUE(info->SetRange(0, sizeof(data), data)); GLuint max_value; // Check entire range succeeds. @@ -194,7 +196,7 @@ TEST_F(BufferManagerTest, GetMaxValueForRangeUint32) { BufferManager::BufferInfo* info = manager_.GetBufferInfo(kClientBufferId); ASSERT_TRUE(info != NULL); manager_.SetTarget(info, GL_ELEMENT_ARRAY_BUFFER); - manager_.SetSize(info, sizeof(data)); + manager_.SetInfo(info, sizeof(data), GL_STATIC_DRAW); EXPECT_TRUE(info->SetRange(0, sizeof(data), data)); GLuint max_value; // Check entire range succeeds. diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc index 5f29545..3e0e02a 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc @@ -126,6 +126,39 @@ static bool IsAngle() { #endif } +void WrappedTexImage2D( + GLenum target, + GLint level, + GLenum internal_format, + GLsizei width, + GLsizei height, + GLint border, + GLenum format, + GLenum type, + const void* pixels) { + GLenum gl_internal_format = internal_format; + if (gfx::GetGLImplementation() != gfx::kGLImplementationEGLGLES2) { + if (format == GL_BGRA_EXT && internal_format == GL_BGRA_EXT) { + gl_internal_format = GL_RGBA; + } else if (type == GL_FLOAT) { + if (format == GL_RGBA) { + gl_internal_format = GL_RGBA32F_ARB; + } else if (format == GL_RGB) { + gl_internal_format = GL_RGB32F_ARB; + } + } else if (type == GL_HALF_FLOAT_OES) { + if (format == GL_RGBA) { + gl_internal_format = GL_RGBA16F_ARB; + } else if (format == GL_RGB) { + gl_internal_format = GL_RGB16F_ARB; + } + } + } + glTexImage2D( + target, level, gl_internal_format, width, height, border, format, type, + pixels); +} + // This class prevents any GL errors that occur when it is in scope from // being reported to the client. class ScopedGLErrorSuppressor { @@ -1469,6 +1502,9 @@ class GLES2DecoderImpl : public base::SupportsWeakPtr<GLES2DecoderImpl>, // The format of the back buffer_ GLenum back_buffer_color_format_; + bool teximage2d_faster_than_texsubimage2d_; + bool bufferdata_faster_than_buffersubdata_; + // The last error message set. std::string last_error_; @@ -1815,6 +1851,8 @@ GLES2DecoderImpl::GLES2DecoderImpl(SurfaceManager* surface_manager, copy_texture_to_parent_texture_fb_(0), offscreen_saved_color_format_(0), back_buffer_color_format_(0), + teximage2d_faster_than_texsubimage2d_(true), + bufferdata_faster_than_buffersubdata_(true), current_decoder_error_(error::kNoError), use_shader_translator_(true), validators_(group_->feature_info()->validators()), @@ -1838,6 +1876,12 @@ GLES2DecoderImpl::GLES2DecoderImpl(SurfaceManager* surface_manager, gfx::GetGLImplementation() == gfx::kGLImplementationMockGL) { use_shader_translator_ = false; } + + // TODO(gman): Consider setting these based on GPU and/or driver. + if (IsAngle()) { + teximage2d_faster_than_texsubimage2d_ = false; + bufferdata_faster_than_buffersubdata_ = false; + } } bool GLES2DecoderImpl::Initialize( @@ -5335,13 +5379,21 @@ void GLES2DecoderImpl::DoBufferData( memset(zero.get(), 0, size); data = zero.get(); } + + if (!bufferdata_faster_than_buffersubdata_ && + size == info->size() && usage == info->usage()) { + glBufferSubData(target, 0, size, data); + info->SetRange(0, size, data); + return; + } + CopyRealGLErrorsToWrapper(); glBufferData(target, size, data, usage); GLenum error = glGetError(); if (error != GL_NO_ERROR) { SetGLError(error, NULL); } else { - buffer_manager()->SetSize(info, size); + buffer_manager()->SetInfo(info, size, usage); info->SetRange(0, size, data); } } @@ -5387,9 +5439,14 @@ void GLES2DecoderImpl::DoBufferSubData( } if (!info->SetRange(offset, size, data)) { SetGLError(GL_INVALID_VALUE, "glBufferSubData: out of range"); - } else { - glBufferSubData(target, offset, size, data); + return; } + if (bufferdata_faster_than_buffersubdata_ && + offset == 0 && size == info->size()) { + glBufferData(target, size, data, info->usage()); + return; + } + glBufferSubData(target, offset, size, data); } error::Error GLES2DecoderImpl::DoCompressedTexImage2D( @@ -5591,28 +5648,24 @@ error::Error GLES2DecoderImpl::DoTexImage2D( pixels = zero.get(); } - GLenum gl_internal_format = internal_format; - if (gfx::GetGLImplementation() != gfx::kGLImplementationEGLGLES2) { - if (format == GL_BGRA_EXT && internal_format == GL_BGRA_EXT) { - gl_internal_format = GL_RGBA; - } else if (type == GL_FLOAT) { - if (format == GL_RGBA) { - gl_internal_format = GL_RGBA32F_ARB; - } else if (format == GL_RGB) { - gl_internal_format = GL_RGB32F_ARB; - } - } else if (type == GL_HALF_FLOAT_OES) { - if (format == GL_RGBA) { - gl_internal_format = GL_RGBA16F_ARB; - } else if (format == GL_RGB) { - gl_internal_format = GL_RGB16F_ARB; - } + if (!teximage2d_faster_than_texsubimage2d_) { + GLsizei tex_width = 0; + GLsizei tex_height = 0; + GLenum tex_type = 0; + GLenum tex_format = 0; + if (info->GetLevelSize(target, level, &tex_width, &tex_height) && + info->GetLevelType(target, level, &tex_type, &tex_format) && + width == tex_width && height == tex_height && + type == tex_type && format == tex_format) { + glTexSubImage2D(target, level, 0, 0, width, height, format, type, pixels); + tex_image_2d_failed_ = false; + return error::kNoError; } } CopyRealGLErrorsToWrapper(); - glTexImage2D( - target, level, gl_internal_format, width, height, border, format, type, + WrappedTexImage2D( + target, level, internal_format, width, height, border, format, type, pixels); GLenum error = glGetError(); if (error == GL_NO_ERROR) { @@ -5933,6 +5986,21 @@ void GLES2DecoderImpl::DoTexSubImage2D( "glTexSubImage2D: bad dimensions."); return; } + + // See if we can call glTexImage2D instead since it appears to be faster. + if (teximage2d_faster_than_texsubimage2d_ && xoffset == 0 && yoffset == 0) { + GLsizei tex_width = 0; + GLsizei tex_height = 0; + bool ok = info->GetLevelSize(target, level, &tex_width, &tex_height); + DCHECK(ok); + if (width == tex_width && height == tex_height) { + // NOTE: In OpenGL ES 2.0 border is always zero and format is always the + // same as internal_foramt. If that changes we'll need to look them up. + WrappedTexImage2D( + target, level, format, width, height, 0, format, type, data); + return; + } + } glTexSubImage2D( target, level, xoffset, yoffset, width, height, format, type, data); } diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc index 274d495..d50bb6d 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc @@ -2389,13 +2389,14 @@ TEST_F(GLES2DecoderTest, TexSubImage2DValidArgs) { GL_TEXTURE_2D, 1, GL_RGBA, kWidth, kHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0, 0); EXPECT_CALL(*gl_, TexSubImage2D( - GL_TEXTURE_2D, 1, 0, 0, kWidth, kHeight, GL_RGBA, GL_UNSIGNED_BYTE, + GL_TEXTURE_2D, 1, 1, 0, kWidth - 1, kHeight, GL_RGBA, GL_UNSIGNED_BYTE, shared_memory_address_)) .Times(1) .RetiresOnSaturation(); TexSubImage2D cmd; - cmd.Init(GL_TEXTURE_2D, 1, 0, 0, kWidth, kHeight, GL_RGBA, GL_UNSIGNED_BYTE, - kSharedMemoryId, kSharedMemoryOffset, GL_FALSE); + cmd.Init( + GL_TEXTURE_2D, 1, 1, 0, kWidth - 1, kHeight, GL_RGBA, GL_UNSIGNED_BYTE, + kSharedMemoryId, kSharedMemoryOffset, GL_FALSE); EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); EXPECT_EQ(GL_NO_ERROR, GetGLError()); } diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc index 7dbc98c..9470d08 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc @@ -745,7 +745,8 @@ void GLES2DecoderWithShaderTestBase::SetupIndexBuffer() { static const GLshort indices[] = {100, 1, 2, 3, 4, 5, 6, 7, 100, 9}; COMPILE_ASSERT(arraysize(indices) == kNumIndices, Indices_is_not_10); DoBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices)); - DoBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, sizeof(indices), indices); + DoBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, 2, indices); + DoBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 2, sizeof(indices) - 2, &indices[1]); } void GLES2DecoderWithShaderTestBase::SetupTexture() { |