summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorepenner@chromium.org <epenner@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-03-13 05:36:44 +0000
committerepenner@chromium.org <epenner@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-03-13 05:36:44 +0000
commit5b3a8e0d883a0fb89faa1b23992c9dcaea9ea44d (patch)
treec52809345af859a1fbe097e635e9f551712cca70
parente97f23a7335324fba0cc44a27c5af9e0569d0822 (diff)
downloadchromium_src-5b3a8e0d883a0fb89faa1b23992c9dcaea9ea44d.zip
chromium_src-5b3a8e0d883a0fb89faa1b23992c9dcaea9ea44d.tar.gz
chromium_src-5b3a8e0d883a0fb89faa1b23992c9dcaea9ea44d.tar.bz2
gpu: Clean up pending async transfers.
Async transfers are currently tracked in the texture manager. This gives less flexibility to the async implementation, and has much higher coupling between the decoder/async-delegate. This patch moves everything into the delegate. BUG=161337 Review URL: https://chromiumcodereview.appspot.com/12330118 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@187790 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--gpu/command_buffer/service/async_pixel_transfer_delegate_mock.h11
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder.cc88
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc50
-rw-r--r--gpu/command_buffer/service/texture_manager.cc48
-rw-r--r--gpu/command_buffer/service/texture_manager.h25
-rw-r--r--ui/gl/async_pixel_transfer_delegate.h24
-rw-r--r--ui/gl/async_pixel_transfer_delegate_android.cc146
-rw-r--r--ui/gl/async_pixel_transfer_delegate_stub.cc33
-rw-r--r--ui/gl/async_pixel_transfer_delegate_stub.h12
9 files changed, 210 insertions, 227 deletions
diff --git a/gpu/command_buffer/service/async_pixel_transfer_delegate_mock.h b/gpu/command_buffer/service/async_pixel_transfer_delegate_mock.h
index 7432737..bc72269 100644
--- a/gpu/command_buffer/service/async_pixel_transfer_delegate_mock.h
+++ b/gpu/command_buffer/service/async_pixel_transfer_delegate_mock.h
@@ -30,15 +30,18 @@ class MockAsyncPixelTransferDelegate : public gfx::AsyncPixelTransferDelegate {
virtual ~MockAsyncPixelTransferDelegate();
// Implement AsyncPixelTransferDelegate.
- MOCK_METHOD1(CreateRawPixelTransferState,
- gfx::AsyncPixelTransferState*(GLuint service_id));
+ MOCK_METHOD2(CreateRawPixelTransferState,
+ gfx::AsyncPixelTransferState*(
+ GLuint service_id, const AsyncTexImage2DParams& define_params));
+ MOCK_METHOD0(BindCompletedAsyncTransfers, bool());
MOCK_METHOD2(AsyncNotifyCompletion,
void(const AsyncMemoryParams& mem_params,
const CompletionCallback& callback));
- MOCK_METHOD3(AsyncTexImage2D,
+ MOCK_METHOD4(AsyncTexImage2D,
void(gfx::AsyncPixelTransferState*,
const AsyncTexImage2DParams& tex_params,
- const AsyncMemoryParams& mem_params));
+ const AsyncMemoryParams& mem_params,
+ const base::Closure& bind_callback));
MOCK_METHOD3(AsyncTexSubImage2D,
void(gfx::AsyncPixelTransferState*,
const AsyncTexSubImage2DParams& tex_params,
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
index 94de0f5..1d642fd 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -2857,23 +2857,13 @@ void GLES2DecoderImpl::ProcessFinishedAsyncTransfers() {
if (engine() && query_manager_.get())
query_manager_->ProcessPendingTransferQueries();
- // TODO(epenner): Is there a better place to do this? Transfers
- // can complete any time we yield the main thread. So we *must*
- // process transfers after any such yield, before resuming.
- bool frame_buffer_dirty = false;
- bool texture_dirty = false;
- texture_manager()->BindFinishedAsyncPixelTransfers(
- &texture_dirty, &frame_buffer_dirty);
- // Texture unit zero might be stomped.
- if (texture_dirty)
+ // TODO(epenner): Is there a better place to do this?
+ // This needs to occur before we execute any batch of commands
+ // from the client, as the client may have recieved an async
+ // completion while issuing those commands.
+ // "DidFlushStart" would be ideal if we had such a callback.
+ if (async_pixel_transfer_delegate_->BindCompletedAsyncTransfers())
RestoreCurrentTexture2DBindings();
- // A texture attached to frame-buffer might have changed size.
- if (frame_buffer_dirty) {
- clear_state_dirty_ = true;
- // TODO(gman): If textures tracked which framebuffers they were attached to
- // we could just mark those framebuffers as not complete.
- framebuffer_manager()->IncFramebufferStateChangeCount();
- }
}
void GLES2DecoderImpl::ReleaseCurrent() {
@@ -10197,6 +10187,15 @@ error::Error GLES2DecoderImpl::HandleAsyncTexImage2DCHROMIUM(
return error::kNoError;
}
+ // Since we don't allow async redefinition, this is the only
+ // time the size of this texture can change while bound
+ // as a frame-buffer.
+ if (texture->IsAttachedToFramebuffer()) {
+ // TODO(gman): If textures tracked which framebuffers they were attached to
+ // we could just mark those framebuffers as not complete.
+ framebuffer_manager()->IncFramebufferStateChangeCount();
+ }
+
if (!EnsureGPUMemoryAvailable(pixels_size)) {
LOCAL_SET_GL_ERROR(
GL_OUT_OF_MEMORY, "glAsyncTexImage2DCHROMIUM", "out of memory");
@@ -10211,16 +10210,7 @@ error::Error GLES2DecoderImpl::HandleAsyncTexImage2DCHROMIUM(
uint32 shm_data_offset = c.pixels_shm_offset;
uint32 shm_data_size = pixels_size;
- // Set up the async state if needed, and make the texture
- // immutable so the async state stays valid. The level texture
- // is set up lazily when the transfer completes.
- DCHECK(!texture->GetAsyncTransferState());
- texture->SetAsyncTransferState(
- async_pixel_transfer_delegate_->
- CreatePixelTransferState(texture->service_id()));
- texture->SetImmutable(true);
-
- // Issue the async call and set up the texture.
+ // Setup the parameters.
GLenum gl_internal_format =
GetTexInternalFormat(internal_format, format, type);
gfx::AsyncTexImage2DParams tex_params = {target, level, gl_internal_format,
@@ -10228,14 +10218,27 @@ error::Error GLES2DecoderImpl::HandleAsyncTexImage2DCHROMIUM(
gfx::AsyncMemoryParams mem_params = {shared_memory, shm_size,
shm_data_offset, shm_data_size};
- // Add a pending transfer to the texture manager, which will bind the
- // transfer data to the texture and set the level texture at the same time,
- // after the the transfer is complete.
- texture_manager()->AddPendingAsyncPixelTransfer(
- texture->GetAsyncTransferState()->AsWeakPtr(), texture);
+ // Set up the async state if needed, and make the texture
+ // immutable so the async state stays valid. The level info
+ // is set up lazily when the transfer completes.
+ DCHECK(!texture->GetAsyncTransferState());
+ texture->SetAsyncTransferState(
+ async_pixel_transfer_delegate_->
+ CreatePixelTransferState(texture->service_id(),
+ tex_params));
+ texture->SetImmutable(true);
async_pixel_transfer_delegate_->AsyncTexImage2D(
- texture->GetAsyncTransferState(), tex_params, mem_params);
+ texture->GetAsyncTransferState(),
+ tex_params,
+ mem_params,
+ base::Bind(&TextureManager::SetLevelInfoFromParams,
+ // The callback is only invoked if the transfer state
+ // still exists, which implies through manager->info->state
+ // ownership that both of these pointers are valid.
+ base::Unretained(texture_manager()),
+ base::Unretained(texture),
+ tex_params));
return error::kNoError;
}
@@ -10298,19 +10301,30 @@ error::Error GLES2DecoderImpl::HandleAsyncTexSubImage2DCHROMIUM(
uint32 shm_data_offset = c.data_shm_offset;
uint32 shm_data_size = data_size;
+ // Setup the parameters.
+ gfx::AsyncTexSubImage2DParams tex_params = {target, level, xoffset, yoffset,
+ width, height, format, type};
+ gfx::AsyncMemoryParams mem_params = {shared_memory, shm_size,
+ shm_data_offset, shm_data_size};
if (!texture->GetAsyncTransferState()) {
+ // TODO(epenner): We may want to enforce exclusive use
+ // of async APIs in which case this should become an error,
+ // (the texture should have been async defined).
+ gfx::AsyncTexImage2DParams define_params = {target, level,
+ 0, 0, 0, 0, 0, 0};
+ texture->GetLevelSize(target, level, &define_params.width,
+ &define_params.height);
+ texture->GetLevelType(target, level, &define_params.type,
+ &define_params.internal_format);
// Set up the async state if needed, and make the texture
// immutable so the async state stays valid.
texture->SetAsyncTransferState(
async_pixel_transfer_delegate_->
- CreatePixelTransferState(texture->service_id()));
+ CreatePixelTransferState(texture->service_id(),
+ define_params));
texture->SetImmutable(true);
}
- gfx::AsyncTexSubImage2DParams tex_params = {target, level, xoffset, yoffset,
- width, height, format, type};
- gfx::AsyncMemoryParams mem_params = {shared_memory, shm_size,
- shm_data_offset, shm_data_size};
async_pixel_transfer_delegate_->AsyncTexSubImage2D(
texture->GetAsyncTransferState(), tex_params, mem_params);
return error::kNoError;
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc
index e4dd9cb..a385f81 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc
@@ -38,6 +38,7 @@ using ::testing::Invoke;
using ::testing::MatcherCast;
using ::testing::Pointee;
using ::testing::Return;
+using ::testing::SaveArg;
using ::testing::SetArrayArgument;
using ::testing::SetArgumentPointee;
using ::testing::SetArgPointee;
@@ -8000,20 +8001,21 @@ TEST_F(GLES2DecoderManualInitTest, AsyncPixelTransfers) {
GL_UNSIGNED_BYTE, kSharedMemoryId, kSharedMemoryOffset);
WaitAsyncTexImage2DCHROMIUM wait_cmd;
wait_cmd.Init(GL_TEXTURE_2D);
- gfx::AsyncTexImage2DParams teximage_params =
- {GL_TEXTURE_2D, 0, GL_RGBA, 8, 8, 0, GL_RGBA, GL_UNSIGNED_BYTE};
// No transfer state exists initially.
EXPECT_FALSE(texture->GetAsyncTransferState());
+ base::Closure bind_callback;
+
// AsyncTexImage2D
{
// Create transfer state since it doesn't exist.
- EXPECT_CALL(*delegate, CreateRawPixelTransferState(kServiceTextureId))
+ EXPECT_CALL(*delegate, CreateRawPixelTransferState(kServiceTextureId, _))
.WillOnce(Return(
state = new StrictMock<gfx::MockAsyncPixelTransferState>))
.RetiresOnSaturation();
- EXPECT_CALL(*delegate, AsyncTexImage2D(state, _, _))
+ EXPECT_CALL(*delegate, AsyncTexImage2D(state, _, _, _))
+ .WillOnce(SaveArg<3>(&bind_callback))
.RetiresOnSaturation();
// Command succeeds.
EXPECT_EQ(error::kNoError, ExecuteCmd(teximage_cmd));
@@ -8035,24 +8037,17 @@ TEST_F(GLES2DecoderManualInitTest, AsyncPixelTransfers) {
EXPECT_TRUE(texture->SafeToRenderFrom());
}
- // Lazy binding/defining of the async transfer
+ // Binding/defining of the async transfer
{
- // We the code should check that the transfer is done,
- // call bind transfer on it, and update the texture texture.
- InSequence scoped_in_sequence;
- EXPECT_CALL(*state, TransferIsInProgress())
- .WillOnce(Return(false))
- .RetiresOnSaturation();
- EXPECT_CALL(*state, BindTransfer(_))
- .WillOnce(SetArgPointee<0>(teximage_params))
- .RetiresOnSaturation();
- TextureManager* manager = decoder_->GetContextGroup()->texture_manager();
- bool texture_dirty, framebuffer_dirty;
- manager->BindFinishedAsyncPixelTransfers(&texture_dirty,
- &framebuffer_dirty);
- EXPECT_TRUE(texture_dirty);
- EXPECT_FALSE(framebuffer_dirty);
- // Texture is safe, and has the right size etc.
+ // TODO(epenner): We should check that the delegate gets the
+ // BindCompletedAsyncTransfers() call, which is required to
+ // guarantee the delegate calls the bind callback.
+
+ // Simulate the bind callback from the delegate.
+ bind_callback.Run();
+
+ // After the bind callback is run, the texture is safe,
+ // and has the right size etc.
EXPECT_TRUE(texture->SafeToRenderFrom());
GLsizei width, height;
EXPECT_TRUE(texture->GetLevelSize(GL_TEXTURE_2D, 0, &width, &height));
@@ -8065,7 +8060,7 @@ TEST_F(GLES2DecoderManualInitTest, AsyncPixelTransfers) {
texture->SetImmutable(false);
{
// Create transfer state since it doesn't exist.
- EXPECT_CALL(*delegate, CreateRawPixelTransferState(kServiceTextureId))
+ EXPECT_CALL(*delegate, CreateRawPixelTransferState(kServiceTextureId, _))
.WillOnce(Return(
state = new StrictMock<gfx::MockAsyncPixelTransferState>))
.RetiresOnSaturation();
@@ -8119,11 +8114,11 @@ TEST_F(GLES2DecoderManualInitTest, AsyncPixelTransfers) {
texture->SetAsyncTransferState(scoped_ptr<gfx::AsyncPixelTransferState>());
texture->SetImmutable(false);
// Create transfer state since it doesn't exist.
- EXPECT_CALL(*delegate, CreateRawPixelTransferState(kServiceTextureId))
+ EXPECT_CALL(*delegate, CreateRawPixelTransferState(kServiceTextureId, _))
.WillOnce(Return(
state = new StrictMock<gfx::MockAsyncPixelTransferState>))
.RetiresOnSaturation();
- EXPECT_CALL(*delegate, AsyncTexImage2D(state, _, _))
+ EXPECT_CALL(*delegate, AsyncTexImage2D(state, _, _, _))
.RetiresOnSaturation();
// Start async transfer.
EXPECT_EQ(error::kNoError, ExecuteCmd(teximage_cmd));
@@ -8132,11 +8127,8 @@ TEST_F(GLES2DecoderManualInitTest, AsyncPixelTransfers) {
EXPECT_TRUE(texture->IsImmutable());
// Wait for completion.
EXPECT_CALL(*delegate, WaitForTransferCompletion(state));
- EXPECT_CALL(*state, TransferIsInProgress())
- .WillOnce(Return(false))
- .RetiresOnSaturation();
- EXPECT_CALL(*state, BindTransfer(_))
- .WillOnce(SetArgPointee<0>(teximage_params))
+ EXPECT_CALL(*delegate, BindCompletedAsyncTransfers())
+ .WillOnce(Return(true))
.RetiresOnSaturation();
// State restoration after binding.
EXPECT_CALL(*gl_, ActiveTexture(_));
diff --git a/gpu/command_buffer/service/texture_manager.cc b/gpu/command_buffer/service/texture_manager.cc
index 4b6fe58..8f72cf4 100644
--- a/gpu/command_buffer/service/texture_manager.cc
+++ b/gpu/command_buffer/service/texture_manager.cc
@@ -1230,53 +1230,5 @@ void TextureManager::AddToSignature(
texture->AddToSignature(feature_info_.get(), target, level, signature);
}
-void TextureManager::AddPendingAsyncPixelTransfer(
- base::WeakPtr<gfx::AsyncPixelTransferState> state, Texture* texture) {
- pending_async_transfers_.push_back(PendingAsyncTransfer(state, texture));
-}
-
-void TextureManager::BindFinishedAsyncPixelTransfers(
- bool* texture_dirty, bool* framebuffer_dirty) {
- DCHECK(texture_dirty);
- DCHECK(framebuffer_dirty);
- *texture_dirty = false;
- *framebuffer_dirty = false;
-
- // Remove finished transfers from the list, while
- // marking whether texture unit 0 or frame_buffer status is dirty.
- while(!pending_async_transfers_.empty()) {
- PendingAsyncTransfer state_info = pending_async_transfers_.front();
- if (!state_info.first.get()) {
- // The AsyncState is owned by the Texture. So if the
- // async state is deleted, so is the Texture.
- pending_async_transfers_.pop_front();
- continue;
- }
- // Terminate early, as all transfers finish in order.
- if (state_info.first->TransferIsInProgress())
- break;
- // If the transfer is finished, bind it to the texture,
- // update the Texture, and remove it from pending list.
- *texture_dirty = true;
- *framebuffer_dirty |= state_info.second->IsAttachedToFramebuffer();
- gfx::AsyncTexImage2DParams tex_define_params;
- state_info.second->
- GetAsyncTransferState()->BindTransfer(&tex_define_params);
- SetLevelInfo(
- state_info.second,
- tex_define_params.target,
- tex_define_params.level,
- tex_define_params.internal_format,
- tex_define_params.width,
- tex_define_params.height,
- 1, // depth
- tex_define_params.border,
- tex_define_params.format,
- tex_define_params.type,
- true); // cleared
- pending_async_transfers_.pop_front();
- }
-}
-
} // namespace gles2
} // namespace gpu
diff --git a/gpu/command_buffer/service/texture_manager.h b/gpu/command_buffer/service/texture_manager.h
index 18dda7a..f1d1fea 100644
--- a/gpu/command_buffer/service/texture_manager.h
+++ b/gpu/command_buffer/service/texture_manager.h
@@ -448,6 +448,16 @@ class GPU_EXPORT TextureManager {
GLenum type,
bool cleared);
+ // Adapter to call above function.
+ void SetLevelInfoFromParams(Texture* texture,
+ const gfx::AsyncTexImage2DParams& params) {
+ SetLevelInfo(
+ texture, params.target, params.level, params.internal_format,
+ params.width, params.height, 1 /* depth */,
+ params.border, params.format,
+ params.type, true /* cleared */ );
+ }
+
// Save the texture definition and leave it undefined.
TextureDefinition* Save(Texture* texture);
@@ -554,13 +564,6 @@ class GPU_EXPORT TextureManager {
GLint level,
std::string* signature) const;
- // Transfers added will get their Texture updated at the same time
- // the async transfer is bound to the real texture.
- void AddPendingAsyncPixelTransfer(
- base::WeakPtr<gfx::AsyncPixelTransferState> state, Texture* texture);
- void BindFinishedAsyncPixelTransfers(bool* texture_dirty,
- bool* framebuffer_dirty);
-
private:
friend class Texture;
@@ -605,14 +608,6 @@ class GPU_EXPORT TextureManager {
// The default textures for each target (texture name = 0)
scoped_refptr<Texture> default_textures_[kNumDefaultTextures];
- // Async texture allocations which haven't been bound to their textures
- // yet. This facilitates updating the Texture at the same time the
- // real texture data is bound.
- typedef std::pair<base::WeakPtr<gfx::AsyncPixelTransferState>,
- Texture*> PendingAsyncTransfer;
- typedef std::list<PendingAsyncTransfer> PendingAsyncTransferList;
- PendingAsyncTransferList pending_async_transfers_;
-
DISALLOW_COPY_AND_ASSIGN(TextureManager);
};
diff --git a/ui/gl/async_pixel_transfer_delegate.h b/ui/gl/async_pixel_transfer_delegate.h
index e2d1d6c..44bcbcb 100644
--- a/ui/gl/async_pixel_transfer_delegate.h
+++ b/ui/gl/async_pixel_transfer_delegate.h
@@ -60,18 +60,10 @@ class GL_EXPORT AsyncPixelTransferState :
// Returns true if there is a transfer in progress.
virtual bool TransferIsInProgress() = 0;
- // Perform any custom binding of the transfer (currently only
- // needed for AsyncTexImage2D). The params used to define the texture
- // are returned in level_params.
- //
- // The transfer must be complete to call this (!TransferIsInProgress).
- virtual void BindTransfer(AsyncTexImage2DParams* level_params) = 0;
-
protected:
friend class base::RefCounted<AsyncPixelTransferState>;
AsyncPixelTransferState() {}
-
private:
DISALLOW_COPY_AND_ASSIGN(AsyncPixelTransferState);
};
@@ -87,19 +79,26 @@ class GL_EXPORT AsyncPixelTransferDelegate {
// This wouldn't work with MOCK_METHOD, so it routes through
// a virtual protected version which returns a raw pointer.
scoped_ptr<AsyncPixelTransferState>
- CreatePixelTransferState(GLuint texture_id) {
- return make_scoped_ptr(CreateRawPixelTransferState(texture_id));
+ CreatePixelTransferState(GLuint tex_id,
+ const AsyncTexImage2DParams& define_params) {
+ return make_scoped_ptr(CreateRawPixelTransferState(tex_id, define_params));
}
+ // Returns true iff a texture was bound to texture-unit zero.
+ virtual bool BindCompletedAsyncTransfers() = 0;
+
// There's no guarantee that callback will run on the caller thread.
virtual void AsyncNotifyCompletion(
const AsyncMemoryParams& mem_params,
const CompletionCallback& callback) = 0;
+ // The callback occurs on the caller thread, once the texture is
+ // safe/ready to be used.
virtual void AsyncTexImage2D(
AsyncPixelTransferState* state,
const AsyncTexImage2DParams& tex_params,
- const AsyncMemoryParams& mem_params) = 0;
+ const AsyncMemoryParams& mem_params,
+ const base::Closure& bind_callback) = 0;
virtual void AsyncTexSubImage2D(
AsyncPixelTransferState* state,
@@ -117,7 +116,8 @@ class GL_EXPORT AsyncPixelTransferDelegate {
AsyncPixelTransferDelegate() {}
// For testing, as returning scoped_ptr wouldn't work with MOCK_METHOD.
virtual AsyncPixelTransferState*
- CreateRawPixelTransferState(GLuint texture_id) = 0;
+ CreateRawPixelTransferState(GLuint tex_id,
+ const AsyncTexImage2DParams& define_params) = 0;
private:
DISALLOW_COPY_AND_ASSIGN(AsyncPixelTransferDelegate);
diff --git a/ui/gl/async_pixel_transfer_delegate_android.cc b/ui/gl/async_pixel_transfer_delegate_android.cc
index 85a4374..6a34639 100644
--- a/ui/gl/async_pixel_transfer_delegate_android.cc
+++ b/ui/gl/async_pixel_transfer_delegate_android.cc
@@ -4,6 +4,7 @@
#include "ui/gl/async_pixel_transfer_delegate_android.h"
+#include <list>
#include <string>
#include "base/bind.h"
@@ -183,19 +184,18 @@ class TransferStateInternal
: public base::RefCountedThreadSafe<TransferStateInternal> {
public:
explicit TransferStateInternal(GLuint texture_id,
+ const AsyncTexImage2DParams& define_params,
bool wait_for_uploads,
bool wait_for_creation,
bool use_image_preserved)
: texture_id_(texture_id),
thread_texture_id_(0),
- needs_late_bind_(false),
transfer_completion_(true, true),
egl_image_(EGL_NO_IMAGE_KHR),
wait_for_uploads_(wait_for_uploads),
wait_for_creation_(wait_for_creation),
use_image_preserved_(use_image_preserved) {
- static const AsyncTexImage2DParams zero_params = {0, 0, 0, 0, 0, 0, 0, 0};
- late_bind_define_params_ = zero_params;
+ define_params_ = define_params;
}
// Implement AsyncPixelTransferState:
@@ -203,15 +203,11 @@ class TransferStateInternal
return !transfer_completion_.IsSignaled();
}
- void BindTransfer(AsyncTexImage2DParams* bound_params) {
+ void BindTransfer() {
TRACE_EVENT2("gpu", "BindAsyncTransfer glEGLImageTargetTexture2DOES",
- "width", late_bind_define_params_.width,
- "height", late_bind_define_params_.height);
- DCHECK(bound_params);
+ "width", define_params_.width,
+ "height", define_params_.height);
DCHECK(texture_id_);
- *bound_params = late_bind_define_params_;
- if (!needs_late_bind_)
- return;
DCHECK_NE(EGL_NO_IMAGE_KHR, egl_image_);
// We can only change the active texture and unit 0,
@@ -219,7 +215,7 @@ class TransferStateInternal
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture_id_);
glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, egl_image_);
- needs_late_bind_ = false;
+ bind_callback_.Run();
DCHECK(CHECK_GL());
}
@@ -313,12 +309,8 @@ class TransferStateInternal
// The EGLImage sibling on the upload thread.
GLuint thread_texture_id_;
- // Indicates there is a new EGLImage and the 'real'
- // texture needs to be bound to it as an EGLImage target.
- bool needs_late_bind_;
-
// Definition params for texture that needs binding.
- AsyncTexImage2DParams late_bind_define_params_;
+ AsyncTexImage2DParams define_params_;
// Indicates that an async transfer is in progress.
base::WaitableEvent transfer_completion_;
@@ -328,6 +320,11 @@ class TransferStateInternal
// one for the lifetime of the texture.
EGLImageKHR egl_image_;
+ // Callback to invoke when AsyncTexImage2D is complete
+ // and the client can safely use the texture. This occurs
+ // during BindCompletedAsyncTransfers().
+ base::Closure bind_callback_;
+
// Customize when we block on fences (these are work-arounds).
bool wait_for_uploads_;
bool wait_for_creation_;
@@ -338,11 +335,14 @@ class TransferStateInternal
// an internal thread-safe ref-counted state object.
class AsyncTransferStateAndroid : public AsyncPixelTransferState {
public:
- explicit AsyncTransferStateAndroid(GLuint texture_id,
- bool wait_for_uploads,
- bool wait_for_creation,
- bool use_image_preserved)
+ explicit AsyncTransferStateAndroid(
+ GLuint texture_id,
+ const AsyncTexImage2DParams& define_params,
+ bool wait_for_uploads,
+ bool wait_for_creation,
+ bool use_image_preserved)
: internal_(new TransferStateInternal(texture_id,
+ define_params,
wait_for_uploads,
wait_for_creation,
use_image_preserved)) {
@@ -351,8 +351,8 @@ class AsyncTransferStateAndroid : public AsyncPixelTransferState {
virtual bool TransferIsInProgress() OVERRIDE {
return internal_->TransferIsInProgress();
}
- virtual void BindTransfer(AsyncTexImage2DParams* bound_params) OVERRIDE {
- internal_->BindTransfer(bound_params);
+ void BindTransfer() {
+ internal_->BindTransfer();
}
scoped_refptr<TransferStateInternal> internal_;
};
@@ -367,13 +367,15 @@ class AsyncPixelTransferDelegateAndroid
virtual ~AsyncPixelTransferDelegateAndroid();
// implement AsyncPixelTransferDelegate:
+ virtual bool BindCompletedAsyncTransfers() OVERRIDE;
virtual void AsyncNotifyCompletion(
const AsyncMemoryParams& mem_params,
const CompletionCallback& callback) OVERRIDE;
virtual void AsyncTexImage2D(
AsyncPixelTransferState* state,
const AsyncTexImage2DParams& tex_params,
- const AsyncMemoryParams& mem_params) OVERRIDE;
+ const AsyncMemoryParams& mem_params,
+ const base::Closure& bind_callback) OVERRIDE;
virtual void AsyncTexSubImage2D(
AsyncPixelTransferState* state,
const AsyncTexSubImage2DParams& tex_params,
@@ -386,7 +388,8 @@ class AsyncPixelTransferDelegateAndroid
private:
// implement AsyncPixelTransferDelegate:
virtual AsyncPixelTransferState*
- CreateRawPixelTransferState(GLuint texture_id) OVERRIDE;
+ CreateRawPixelTransferState(GLuint texture_id,
+ const AsyncTexImage2DParams& define_params) OVERRIDE;
static void PerformNotifyCompletion(
AsyncMemoryParams mem_params,
@@ -406,14 +409,18 @@ class AsyncPixelTransferDelegateAndroid
// Returns true if a work-around was used.
bool WorkAroundAsyncTexImage2D(
- TransferStateInternal* state,
+ AsyncPixelTransferState* state,
const AsyncTexImage2DParams& tex_params,
- const AsyncMemoryParams& mem_params);
+ const AsyncMemoryParams& mem_params,
+ const base::Closure& bind_callback);
bool WorkAroundAsyncTexSubImage2D(
- TransferStateInternal* state,
+ AsyncPixelTransferState* state,
const AsyncTexSubImage2DParams& tex_params,
const AsyncMemoryParams& mem_params);
+ typedef std::list<base::WeakPtr<AsyncPixelTransferState> > TransferQueue;
+ TransferQueue pending_allocations_;
+
scoped_refptr<TextureUploadStats> texture_upload_stats_;
bool is_imagination_;
bool is_qualcomm_;
@@ -458,8 +465,8 @@ AsyncPixelTransferDelegateAndroid::~AsyncPixelTransferDelegateAndroid() {
AsyncPixelTransferState*
AsyncPixelTransferDelegateAndroid::
- CreateRawPixelTransferState(GLuint texture_id) {
-
+ CreateRawPixelTransferState(GLuint texture_id,
+ const AsyncTexImage2DParams& define_params) {
// We can't wait on uploads on imagination (it can take 200ms+).
// In practice, they are complete when the CPU glTexSubImage2D completes.
bool wait_for_uploads = !is_imagination_;
@@ -478,11 +485,34 @@ AsyncPixelTransferState*
return static_cast<AsyncPixelTransferState*>(
new AsyncTransferStateAndroid(texture_id,
+ define_params,
wait_for_uploads,
wait_for_creation,
use_image_preserved));
}
+bool AsyncPixelTransferDelegateAndroid::BindCompletedAsyncTransfers() {
+ bool texture_dirty = false;
+ while(!pending_allocations_.empty()) {
+ if (!pending_allocations_.front().get()) {
+ pending_allocations_.pop_front();
+ continue;
+ }
+ scoped_refptr<TransferStateInternal> state =
+ static_cast<AsyncTransferStateAndroid*>
+ (pending_allocations_.front().get())->internal_.get();
+ // Terminate early, as all transfers finish in order, currently.
+ if (state->TransferIsInProgress())
+ break;
+ // If the transfer is finished, bind it to the texture
+ // and remove it from pending list.
+ texture_dirty = true;
+ state->BindTransfer();
+ pending_allocations_.pop_front();
+ }
+ return texture_dirty;
+}
+
void AsyncPixelTransferDelegateAndroid::AsyncNotifyCompletion(
const AsyncMemoryParams& mem_params,
const CompletionCallback& callback) {
@@ -531,7 +561,12 @@ void AsyncPixelTransferDelegateAndroid::WaitForTransferCompletion(
void AsyncPixelTransferDelegateAndroid::AsyncTexImage2D(
AsyncPixelTransferState* transfer_state,
const AsyncTexImage2DParams& tex_params,
- const AsyncMemoryParams& mem_params) {
+ const AsyncMemoryParams& mem_params,
+ const base::Closure& bind_callback) {
+ if (WorkAroundAsyncTexImage2D(transfer_state, tex_params,
+ mem_params, bind_callback))
+ return;
+
scoped_refptr<TransferStateInternal> state =
static_cast<AsyncTransferStateAndroid*>(transfer_state)->internal_.get();
DCHECK(mem_params.shared_memory);
@@ -539,23 +574,20 @@ void AsyncPixelTransferDelegateAndroid::AsyncTexImage2D(
mem_params.shm_size);
DCHECK(state);
DCHECK(state->texture_id_);
- DCHECK(!state->needs_late_bind_);
DCHECK(!state->TransferIsInProgress());
DCHECK_EQ(state->egl_image_, EGL_NO_IMAGE_KHR);
DCHECK_EQ(static_cast<GLenum>(GL_TEXTURE_2D), tex_params.target);
DCHECK_EQ(tex_params.level, 0);
- if (WorkAroundAsyncTexImage2D(state, tex_params, mem_params))
- return;
-
- // Mark the transfer in progress and save define params for lazy binding.
- state->needs_late_bind_ = true;
- state->late_bind_define_params_ = tex_params;
+ // Mark the transfer in progress and save the late bind
+ // callback, so we can notify the client when it is bound.
+ pending_allocations_.push_back(transfer_state->AsWeakPtr());
+ state->bind_callback_ = bind_callback;
// Mark the transfer in progress.
state->MarkAsTransferIsInProgress();
- // Duplicate the shared memory so there are no way we can get
+ // Duplicate the shared memory so there is no way we can get
// a use-after-free of the raw pixels.
transfer_message_loop_proxy()->PostTask(FROM_HERE,
base::Bind(
@@ -567,6 +599,7 @@ void AsyncPixelTransferDelegateAndroid::AsyncTexImage2D(
mem_params.shared_memory,
mem_params.shm_size))));
+
DCHECK(CHECK_GL());
}
@@ -577,8 +610,11 @@ void AsyncPixelTransferDelegateAndroid::AsyncTexSubImage2D(
TRACE_EVENT2("gpu", "AsyncTexSubImage2D",
"width", tex_params.width,
"height", tex_params.height);
+ if (WorkAroundAsyncTexSubImage2D(transfer_state, tex_params, mem_params))
+ return;
scoped_refptr<TransferStateInternal> state =
static_cast<AsyncTransferStateAndroid*>(transfer_state)->internal_.get();
+
DCHECK(state->texture_id_);
DCHECK(!state->TransferIsInProgress());
DCHECK(mem_params.shared_memory);
@@ -587,9 +623,6 @@ void AsyncPixelTransferDelegateAndroid::AsyncTexSubImage2D(
DCHECK_EQ(static_cast<GLenum>(GL_TEXTURE_2D), tex_params.target);
DCHECK_EQ(tex_params.level, 0);
- if (WorkAroundAsyncTexSubImage2D(state, tex_params, mem_params))
- return;
-
// Mark the transfer in progress.
state->MarkAsTransferIsInProgress();
@@ -773,11 +806,14 @@ bool DimensionsSupportImgFastPath(int width, int height) {
// on purely synchronous allocation/upload on the main thread.
bool AsyncPixelTransferDelegateAndroid::WorkAroundAsyncTexImage2D(
- TransferStateInternal* state,
+ AsyncPixelTransferState* transfer_state,
const AsyncTexImage2DParams& tex_params,
- const AsyncMemoryParams& mem_params) {
+ const AsyncMemoryParams& mem_params,
+ const base::Closure& bind_callback) {
if (!is_imagination_)
return false;
+ scoped_refptr<TransferStateInternal> state =
+ static_cast<AsyncTransferStateAndroid*>(transfer_state)->internal_.get();
// On imagination we allocate synchronously all the time, even
// if the dimensions support fast uploads. This is for part a.)
@@ -793,8 +829,6 @@ bool AsyncPixelTransferDelegateAndroid::WorkAroundAsyncTexImage2D(
// The allocation has already occured, so mark it as finished
// and ready for binding.
- state->needs_late_bind_ = false;
- state->late_bind_define_params_ = tex_params;
CHECK(!state->TransferIsInProgress());
// If the dimensions support fast async uploads, create the
@@ -803,7 +837,8 @@ bool AsyncPixelTransferDelegateAndroid::WorkAroundAsyncTexImage2D(
// texture, but this is required to prevent an imagination driver crash.
if (DimensionsSupportImgFastPath(tex_params.width, tex_params.height)) {
state->CreateEglImageOnMainThreadIfNeeded();
- state->needs_late_bind_ = true;
+ pending_allocations_.push_back(transfer_state->AsWeakPtr());
+ state->bind_callback_ = bind_callback;
}
DCHECK(CHECK_GL());
@@ -811,7 +846,7 @@ bool AsyncPixelTransferDelegateAndroid::WorkAroundAsyncTexImage2D(
}
bool AsyncPixelTransferDelegateAndroid::WorkAroundAsyncTexSubImage2D(
- TransferStateInternal* state,
+ AsyncPixelTransferState* transfer_state,
const AsyncTexSubImage2DParams& tex_params,
const AsyncMemoryParams& mem_params) {
if (!is_imagination_)
@@ -822,6 +857,9 @@ bool AsyncPixelTransferDelegateAndroid::WorkAroundAsyncTexSubImage2D(
if (DimensionsSupportImgFastPath(tex_params.width, tex_params.height))
return false;
+ scoped_refptr<TransferStateInternal> state =
+ static_cast<AsyncTransferStateAndroid*>(transfer_state)->internal_.get();
+
// Fall back on a synchronous stub as we don't have a known fast path.
// Also, older ICS drivers crash when we do any glTexSubImage2D on the
// same thread. To work around this we do glTexImage2D instead. Since
@@ -830,11 +868,11 @@ bool AsyncPixelTransferDelegateAndroid::WorkAroundAsyncTexSubImage2D(
DCHECK(!state->egl_image_);
DCHECK_EQ(tex_params.xoffset, 0);
DCHECK_EQ(tex_params.yoffset, 0);
- DCHECK_EQ(state->late_bind_define_params_.width, tex_params.width);
- DCHECK_EQ(state->late_bind_define_params_.height, tex_params.height);
- DCHECK_EQ(state->late_bind_define_params_.level, tex_params.level);
- DCHECK_EQ(state->late_bind_define_params_.format, tex_params.format);
- DCHECK_EQ(state->late_bind_define_params_.type, tex_params.type);
+ DCHECK_EQ(state->define_params_.width, tex_params.width);
+ DCHECK_EQ(state->define_params_.height, tex_params.height);
+ DCHECK_EQ(state->define_params_.level, tex_params.level);
+ DCHECK_EQ(state->define_params_.format, tex_params.format);
+ DCHECK_EQ(state->define_params_.type, tex_params.type);
void* data = GetAddress(mem_params.shared_memory,
mem_params.shm_data_offset);
@@ -843,9 +881,9 @@ bool AsyncPixelTransferDelegateAndroid::WorkAroundAsyncTexSubImage2D(
begin_time = base::TimeTicks::HighResNow();
{
TRACE_EVENT0("gpu", "glTexSubImage2D");
- // Note we use late_bind_define_params_ instead of tex_params.
+ // Note we use define_params_ instead of tex_params.
// The DCHECKs above verify this is always the same.
- DoTexImage2D(state->late_bind_define_params_, data);
+ DoTexImage2D(state->define_params_, data);
}
if (texture_upload_stats_) {
texture_upload_stats_->AddUpload(
diff --git a/ui/gl/async_pixel_transfer_delegate_stub.cc b/ui/gl/async_pixel_transfer_delegate_stub.cc
index 093cb11..2ec16bb 100644
--- a/ui/gl/async_pixel_transfer_delegate_stub.cc
+++ b/ui/gl/async_pixel_transfer_delegate_stub.cc
@@ -43,9 +43,6 @@ scoped_ptr<AsyncPixelTransferDelegate>
}
AsyncTransferStateStub::AsyncTransferStateStub(GLuint texture_id) {
- static const AsyncTexImage2DParams zero_params = {0, 0, 0, 0, 0, 0, 0, 0};
- late_bind_define_params_ = zero_params;
- needs_late_bind_ = false;
}
AsyncTransferStateStub::~AsyncTransferStateStub() {
@@ -55,13 +52,6 @@ bool AsyncTransferStateStub::TransferIsInProgress() {
return false;
}
-void AsyncTransferStateStub::BindTransfer(AsyncTexImage2DParams* out_params) {
- DCHECK(out_params);
- DCHECK(needs_late_bind_);
- *out_params = late_bind_define_params_;
- needs_late_bind_ = false;
-}
-
AsyncPixelTransferDelegateStub::AsyncPixelTransferDelegateStub()
: texture_upload_count_(0) {
}
@@ -71,11 +61,17 @@ AsyncPixelTransferDelegateStub::~AsyncPixelTransferDelegateStub() {
AsyncPixelTransferState*
AsyncPixelTransferDelegateStub::CreateRawPixelTransferState(
- GLuint texture_id) {
+ GLuint texture_id,
+ const AsyncTexImage2DParams& define_params) {
return static_cast<AsyncPixelTransferState*>(
new AsyncTransferStateStub(texture_id));
}
+bool AsyncPixelTransferDelegateStub::BindCompletedAsyncTransfers() {
+ // Everything is already bound.
+ return false;
+}
+
void AsyncPixelTransferDelegateStub::AsyncNotifyCompletion(
const AsyncMemoryParams& mem_params,
const CompletionCallback& callback) {
@@ -85,17 +81,11 @@ void AsyncPixelTransferDelegateStub::AsyncNotifyCompletion(
void AsyncPixelTransferDelegateStub::AsyncTexImage2D(
AsyncPixelTransferState* transfer_state,
const AsyncTexImage2DParams& tex_params,
- const AsyncMemoryParams& mem_params) {
+ const AsyncMemoryParams& mem_params,
+ const base::Closure& bind_callback) {
// Save the define params to return later during deferred
// binding of the transfer texture.
DCHECK(transfer_state);
- AsyncTransferStateStub* state =
- static_cast<AsyncTransferStateStub*>(transfer_state);
- // We don't actually need a late bind since this stub does
- // everything synchronously, but this tries to be similar
- // as an async implementation.
- state->needs_late_bind_ = true;
- state->late_bind_define_params_ = tex_params;
void* data = GetAddress(mem_params.shared_memory,
mem_params.shm_size,
mem_params.shm_data_offset,
@@ -110,6 +100,8 @@ void AsyncPixelTransferDelegateStub::AsyncTexImage2D(
tex_params.format,
tex_params.type,
data);
+ // The texture is already fully bound so just call it now.
+ bind_callback.Run();
}
void AsyncPixelTransferDelegateStub::AsyncTexSubImage2D(
@@ -121,9 +113,6 @@ void AsyncPixelTransferDelegateStub::AsyncTexSubImage2D(
mem_params.shm_data_offset,
mem_params.shm_data_size);
DCHECK(transfer_state);
- AsyncTransferStateStub* state =
- static_cast<AsyncTransferStateStub*>(transfer_state);
- DCHECK(!state->needs_late_bind_);
base::TimeTicks begin_time(base::TimeTicks::HighResNow());
glTexSubImage2D(
tex_params.target,
diff --git a/ui/gl/async_pixel_transfer_delegate_stub.h b/ui/gl/async_pixel_transfer_delegate_stub.h
index cb21d8c..ae90342 100644
--- a/ui/gl/async_pixel_transfer_delegate_stub.h
+++ b/ui/gl/async_pixel_transfer_delegate_stub.h
@@ -13,12 +13,9 @@ class AsyncTransferStateStub : public AsyncPixelTransferState {
public:
// implement AsyncPixelTransferState:
virtual bool TransferIsInProgress() OVERRIDE;
- virtual void BindTransfer(AsyncTexImage2DParams* bound_params) OVERRIDE;
private:
friend class AsyncPixelTransferDelegateStub;
- bool needs_late_bind_;
- AsyncTexImage2DParams late_bind_define_params_ ;
explicit AsyncTransferStateStub(GLuint texture_id);
virtual ~AsyncTransferStateStub();
@@ -36,13 +33,15 @@ class AsyncPixelTransferDelegateStub : public AsyncPixelTransferDelegate {
virtual ~AsyncPixelTransferDelegateStub();
// implement AsyncPixelTransferDelegate:
+ virtual bool BindCompletedAsyncTransfers() OVERRIDE;
virtual void AsyncNotifyCompletion(
const AsyncMemoryParams& mem_params,
const CompletionCallback& callback) OVERRIDE;
virtual void AsyncTexImage2D(
- AsyncPixelTransferState* transfer_state,
+ AsyncPixelTransferState* state,
const AsyncTexImage2DParams& tex_params,
- const AsyncMemoryParams& mem_params) OVERRIDE;
+ const AsyncMemoryParams& mem_params,
+ const base::Closure& bind_callback) OVERRIDE;
virtual void AsyncTexSubImage2D(
AsyncPixelTransferState* transfer_state,
const AsyncTexSubImage2DParams& tex_params,
@@ -54,7 +53,8 @@ class AsyncPixelTransferDelegateStub : public AsyncPixelTransferDelegate {
private:
// implement AsyncPixelTransferDelegate:
virtual AsyncPixelTransferState*
- CreateRawPixelTransferState(GLuint texture_id) OVERRIDE;
+ CreateRawPixelTransferState(GLuint texture_id,
+ const AsyncTexImage2DParams& define_params) OVERRIDE;
int texture_upload_count_;
base::TimeDelta total_texture_upload_time_;