Index: gpu/command_buffer/service/gles2_cmd_decoder_unittest_async_pixel.cc |
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_async_pixel.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_async_pixel.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..3df70011470595353badba29497b736dad565842 |
--- /dev/null |
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_async_pixel.cc |
@@ -0,0 +1,390 @@ |
+// Copyright (c) 2012 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. |
+ |
+#include "gpu/command_buffer/service/gles2_cmd_decoder.h" |
+ |
+#include "base/command_line.h" |
+#include "base/strings/string_number_conversions.h" |
+#include "gpu/command_buffer/common/gles2_cmd_format.h" |
+#include "gpu/command_buffer/common/gles2_cmd_utils.h" |
+#include "gpu/command_buffer/common/id_allocator.h" |
+#include "gpu/command_buffer/service/async_pixel_transfer_delegate_mock.h" |
+#include "gpu/command_buffer/service/async_pixel_transfer_manager.h" |
+#include "gpu/command_buffer/service/async_pixel_transfer_manager_mock.h" |
+#include "gpu/command_buffer/service/cmd_buffer_engine.h" |
+#include "gpu/command_buffer/service/context_group.h" |
+#include "gpu/command_buffer/service/context_state.h" |
+#include "gpu/command_buffer/service/gl_surface_mock.h" |
+#include "gpu/command_buffer/service/gles2_cmd_decoder_unittest.h" |
+ |
+#include "gpu/command_buffer/service/gpu_switches.h" |
+#include "gpu/command_buffer/service/image_manager.h" |
+#include "gpu/command_buffer/service/mailbox_manager.h" |
+#include "gpu/command_buffer/service/mocks.h" |
+#include "gpu/command_buffer/service/program_manager.h" |
+#include "gpu/command_buffer/service/test_helper.h" |
+#include "testing/gtest/include/gtest/gtest.h" |
+#include "ui/gl/gl_implementation.h" |
+#include "ui/gl/gl_mock.h" |
+#include "ui/gl/gl_surface_stub.h" |
+ |
+#if !defined(GL_DEPTH24_STENCIL8) |
+#define GL_DEPTH24_STENCIL8 0x88F0 |
+#endif |
+ |
+using ::gfx::MockGLInterface; |
+using ::testing::_; |
+using ::testing::DoAll; |
+using ::testing::InSequence; |
+using ::testing::Invoke; |
+using ::testing::MatcherCast; |
+using ::testing::Mock; |
+using ::testing::Pointee; |
+using ::testing::Return; |
+using ::testing::SaveArg; |
+using ::testing::SetArrayArgument; |
+using ::testing::SetArgumentPointee; |
+using ::testing::SetArgPointee; |
+using ::testing::StrEq; |
+using ::testing::StrictMock; |
+ |
+namespace gpu { |
+namespace gles2 { |
+ |
+using namespace cmds; |
+ |
+TEST_F(GLES2DecoderManualInitTest, AsyncPixelTransfers) { |
+ InitState init; |
+ init.extensions = "GL_CHROMIUM_async_pixel_transfers"; |
+ init.gl_version = "3.0"; |
+ init.bind_generates_resource = true; |
+ InitDecoder(init); |
+ |
+ // Set up the texture. |
+ DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId); |
+ TextureRef* texture_ref = GetTexture(client_texture_id_); |
+ Texture* texture = texture_ref->texture(); |
+ |
+ // Set a mock Async delegate |
+ StrictMock<gpu::MockAsyncPixelTransferManager>* manager = |
+ new StrictMock<gpu::MockAsyncPixelTransferManager>; |
+ manager->Initialize(group().texture_manager()); |
+ decoder_->SetAsyncPixelTransferManagerForTest(manager); |
+ StrictMock<gpu::MockAsyncPixelTransferDelegate>* delegate = NULL; |
+ |
+ // Tex(Sub)Image2D upload commands. |
+ AsyncTexImage2DCHROMIUM teximage_cmd; |
+ teximage_cmd.Init(GL_TEXTURE_2D, |
+ 0, |
+ GL_RGBA, |
+ 8, |
+ 8, |
+ 0, |
+ GL_RGBA, |
+ GL_UNSIGNED_BYTE, |
+ kSharedMemoryId, |
+ kSharedMemoryOffset, |
+ 0, |
+ 0, |
+ 0); |
+ AsyncTexSubImage2DCHROMIUM texsubimage_cmd; |
+ texsubimage_cmd.Init(GL_TEXTURE_2D, |
+ 0, |
+ 0, |
+ 0, |
+ 8, |
+ 8, |
+ GL_RGBA, |
+ GL_UNSIGNED_BYTE, |
+ kSharedMemoryId, |
+ kSharedMemoryOffset, |
+ 0, |
+ 0, |
+ 0); |
+ WaitAsyncTexImage2DCHROMIUM wait_cmd; |
+ wait_cmd.Init(GL_TEXTURE_2D); |
+ WaitAllAsyncTexImage2DCHROMIUM wait_all_cmd; |
+ wait_all_cmd.Init(); |
+ |
+ // No transfer state exists initially. |
+ EXPECT_FALSE( |
+ decoder_->GetAsyncPixelTransferManager()->GetPixelTransferDelegate( |
+ texture_ref)); |
+ |
+ base::Closure bind_callback; |
+ |
+ // AsyncTexImage2D |
+ { |
+ // Create transfer state since it doesn't exist. |
+ EXPECT_EQ(texture_ref->num_observers(), 0); |
+ EXPECT_CALL(*manager, CreatePixelTransferDelegateImpl(texture_ref, _)) |
+ .WillOnce(Return( |
+ delegate = new StrictMock<gpu::MockAsyncPixelTransferDelegate>)) |
+ .RetiresOnSaturation(); |
+ EXPECT_CALL(*delegate, AsyncTexImage2D(_, _, _)) |
+ .WillOnce(SaveArg<2>(&bind_callback)) |
+ .RetiresOnSaturation(); |
+ // Command succeeds. |
+ EXPECT_EQ(error::kNoError, ExecuteCmd(teximage_cmd)); |
+ EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
+ EXPECT_EQ( |
+ delegate, |
+ decoder_->GetAsyncPixelTransferManager()->GetPixelTransferDelegate( |
+ texture_ref)); |
+ EXPECT_TRUE(texture->IsImmutable()); |
+ // The texture is safe but the level has not been defined yet. |
+ EXPECT_TRUE(texture->SafeToRenderFrom()); |
+ GLsizei width, height; |
+ EXPECT_FALSE(texture->GetLevelSize(GL_TEXTURE_2D, 0, &width, &height)); |
+ EXPECT_EQ(texture_ref->num_observers(), 1); |
+ } |
+ { |
+ // Async redefinitions are not allowed! |
+ // Command fails. |
+ EXPECT_EQ(error::kNoError, ExecuteCmd(teximage_cmd)); |
+ EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
+ EXPECT_EQ( |
+ delegate, |
+ decoder_->GetAsyncPixelTransferManager()->GetPixelTransferDelegate( |
+ texture_ref)); |
+ EXPECT_TRUE(texture->IsImmutable()); |
+ EXPECT_TRUE(texture->SafeToRenderFrom()); |
+ } |
+ |
+ // Binding/defining of the async transfer |
+ { |
+ // TODO(epenner): We should check that the manager 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)); |
+ EXPECT_EQ(width, 8); |
+ EXPECT_EQ(height, 8); |
+ } |
+ |
+ // AsyncTexSubImage2D |
+ EXPECT_CALL(*delegate, Destroy()).RetiresOnSaturation(); |
+ decoder_->GetAsyncPixelTransferManager()->ClearPixelTransferDelegateForTest( |
+ texture_ref); |
+ EXPECT_EQ(texture_ref->num_observers(), 0); |
+ texture->SetImmutable(false); |
+ { |
+ // Create transfer state since it doesn't exist. |
+ EXPECT_CALL(*manager, CreatePixelTransferDelegateImpl(texture_ref, _)) |
+ .WillOnce(Return( |
+ delegate = new StrictMock<gpu::MockAsyncPixelTransferDelegate>)) |
+ .RetiresOnSaturation(); |
+ EXPECT_CALL(*delegate, AsyncTexSubImage2D(_, _)).RetiresOnSaturation(); |
+ // Command succeeds. |
+ EXPECT_EQ(error::kNoError, ExecuteCmd(texsubimage_cmd)); |
+ EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
+ EXPECT_EQ( |
+ delegate, |
+ decoder_->GetAsyncPixelTransferManager()->GetPixelTransferDelegate( |
+ texture_ref)); |
+ EXPECT_TRUE(texture->IsImmutable()); |
+ EXPECT_TRUE(texture->SafeToRenderFrom()); |
+ } |
+ { |
+ // No transfer is in progress. |
+ EXPECT_CALL(*delegate, TransferIsInProgress()) |
+ .WillOnce(Return(false)) // texSubImage validation |
+ .WillOnce(Return(false)) // async validation |
+ .RetiresOnSaturation(); |
+ EXPECT_CALL(*delegate, AsyncTexSubImage2D(_, _)).RetiresOnSaturation(); |
+ // Command succeeds. |
+ EXPECT_EQ(error::kNoError, ExecuteCmd(texsubimage_cmd)); |
+ EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
+ EXPECT_EQ( |
+ delegate, |
+ decoder_->GetAsyncPixelTransferManager()->GetPixelTransferDelegate( |
+ texture_ref)); |
+ EXPECT_TRUE(texture->IsImmutable()); |
+ EXPECT_TRUE(texture->SafeToRenderFrom()); |
+ } |
+ { |
+ // A transfer is still in progress! |
+ EXPECT_CALL(*delegate, TransferIsInProgress()) |
+ .WillOnce(Return(true)) |
+ .RetiresOnSaturation(); |
+ // No async call, command fails. |
+ EXPECT_EQ(error::kNoError, ExecuteCmd(texsubimage_cmd)); |
+ EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
+ EXPECT_EQ( |
+ delegate, |
+ decoder_->GetAsyncPixelTransferManager()->GetPixelTransferDelegate( |
+ texture_ref)); |
+ EXPECT_TRUE(texture->IsImmutable()); |
+ EXPECT_TRUE(texture->SafeToRenderFrom()); |
+ } |
+ |
+ // Delete delegate on DeleteTexture. |
+ { |
+ EXPECT_EQ(texture_ref->num_observers(), 1); |
+ EXPECT_CALL(*delegate, Destroy()).RetiresOnSaturation(); |
+ DoDeleteTexture(client_texture_id_, kServiceTextureId); |
+ EXPECT_FALSE( |
+ decoder_->GetAsyncPixelTransferManager()->GetPixelTransferDelegate( |
+ texture_ref)); |
+ texture = NULL; |
+ texture_ref = NULL; |
+ delegate = NULL; |
+ } |
+ |
+ // WaitAsyncTexImage2D |
+ { |
+ // Get a fresh texture since the existing texture cannot be respecified |
+ // asynchronously and AsyncTexSubImage2D does not involve binding. |
+ EXPECT_CALL(*gl_, GenTextures(1, _)) |
+ .WillOnce(SetArgumentPointee<1>(kServiceTextureId)); |
+ DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId); |
+ texture_ref = GetTexture(client_texture_id_); |
+ texture = texture_ref->texture(); |
+ texture->SetImmutable(false); |
+ // Create transfer state since it doesn't exist. |
+ EXPECT_CALL(*manager, CreatePixelTransferDelegateImpl(texture_ref, _)) |
+ .WillOnce(Return( |
+ delegate = new StrictMock<gpu::MockAsyncPixelTransferDelegate>)) |
+ .RetiresOnSaturation(); |
+ EXPECT_CALL(*delegate, AsyncTexImage2D(_, _, _)).RetiresOnSaturation(); |
+ // Start async transfer. |
+ EXPECT_EQ(error::kNoError, ExecuteCmd(teximage_cmd)); |
+ EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
+ EXPECT_EQ( |
+ delegate, |
+ decoder_->GetAsyncPixelTransferManager()->GetPixelTransferDelegate( |
+ texture_ref)); |
+ |
+ EXPECT_TRUE(texture->IsImmutable()); |
+ // Wait for completion. |
+ EXPECT_CALL(*delegate, WaitForTransferCompletion()); |
+ EXPECT_CALL(*manager, BindCompletedAsyncTransfers()); |
+ EXPECT_EQ(error::kNoError, ExecuteCmd(wait_cmd)); |
+ EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
+ } |
+ |
+ // WaitAllAsyncTexImage2D |
+ EXPECT_CALL(*delegate, Destroy()).RetiresOnSaturation(); |
+ DoDeleteTexture(client_texture_id_, kServiceTextureId); |
+ EXPECT_FALSE( |
+ decoder_->GetAsyncPixelTransferManager()->GetPixelTransferDelegate( |
+ texture_ref)); |
+ texture = NULL; |
+ texture_ref = NULL; |
+ delegate = NULL; |
+ { |
+ // Get a fresh texture since the existing texture cannot be respecified |
+ // asynchronously and AsyncTexSubImage2D does not involve binding. |
+ EXPECT_CALL(*gl_, GenTextures(1, _)) |
+ .WillOnce(SetArgumentPointee<1>(kServiceTextureId)); |
+ DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId); |
+ texture_ref = GetTexture(client_texture_id_); |
+ texture = texture_ref->texture(); |
+ texture->SetImmutable(false); |
+ // Create transfer state since it doesn't exist. |
+ EXPECT_CALL(*manager, CreatePixelTransferDelegateImpl(texture_ref, _)) |
+ .WillOnce(Return( |
+ delegate = new StrictMock<gpu::MockAsyncPixelTransferDelegate>)) |
+ .RetiresOnSaturation(); |
+ EXPECT_CALL(*delegate, AsyncTexImage2D(_, _, _)).RetiresOnSaturation(); |
+ // Start async transfer. |
+ EXPECT_EQ(error::kNoError, ExecuteCmd(teximage_cmd)); |
+ EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
+ EXPECT_EQ( |
+ delegate, |
+ decoder_->GetAsyncPixelTransferManager()->GetPixelTransferDelegate( |
+ texture_ref)); |
+ |
+ EXPECT_TRUE(texture->IsImmutable()); |
+ // Wait for completion of all uploads. |
+ EXPECT_CALL(*manager, WaitAllAsyncTexImage2D()).RetiresOnSaturation(); |
+ EXPECT_CALL(*manager, BindCompletedAsyncTransfers()); |
+ EXPECT_EQ(error::kNoError, ExecuteCmd(wait_all_cmd)); |
+ EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
+ } |
+ |
+ // Remove PixelTransferManager before the decoder destroys. |
+ EXPECT_CALL(*delegate, Destroy()).RetiresOnSaturation(); |
+ decoder_->ResetAsyncPixelTransferManagerForTest(); |
+ manager = NULL; |
+} |
+ |
+TEST_F(GLES2DecoderManualInitTest, AsyncPixelTransferManager) { |
+ InitState init; |
+ init.extensions = "GL_CHROMIUM_async_pixel_transfers"; |
+ init.gl_version = "3.0"; |
+ init.bind_generates_resource = true; |
+ InitDecoder(init); |
+ |
+ // Set up the texture. |
+ DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId); |
+ TextureRef* texture_ref = GetTexture(client_texture_id_); |
+ |
+ // Set a mock Async delegate. |
+ StrictMock<gpu::MockAsyncPixelTransferManager>* manager = |
+ new StrictMock<gpu::MockAsyncPixelTransferManager>; |
+ manager->Initialize(group().texture_manager()); |
+ decoder_->SetAsyncPixelTransferManagerForTest(manager); |
+ StrictMock<gpu::MockAsyncPixelTransferDelegate>* delegate = NULL; |
+ |
+ AsyncTexImage2DCHROMIUM teximage_cmd; |
+ teximage_cmd.Init(GL_TEXTURE_2D, |
+ 0, |
+ GL_RGBA, |
+ 8, |
+ 8, |
+ 0, |
+ GL_RGBA, |
+ GL_UNSIGNED_BYTE, |
+ kSharedMemoryId, |
+ kSharedMemoryOffset, |
+ 0, |
+ 0, |
+ 0); |
+ |
+ // No transfer delegate exists initially. |
+ EXPECT_FALSE( |
+ decoder_->GetAsyncPixelTransferManager()->GetPixelTransferDelegate( |
+ texture_ref)); |
+ |
+ // Create delegate on AsyncTexImage2D. |
+ { |
+ EXPECT_CALL(*manager, CreatePixelTransferDelegateImpl(texture_ref, _)) |
+ .WillOnce(Return( |
+ delegate = new StrictMock<gpu::MockAsyncPixelTransferDelegate>)) |
+ .RetiresOnSaturation(); |
+ EXPECT_CALL(*delegate, AsyncTexImage2D(_, _, _)).RetiresOnSaturation(); |
+ |
+ // Command succeeds. |
+ EXPECT_EQ(error::kNoError, ExecuteCmd(teximage_cmd)); |
+ EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
+ } |
+ |
+ // Delegate is cached. |
+ EXPECT_EQ(delegate, |
+ decoder_->GetAsyncPixelTransferManager()->GetPixelTransferDelegate( |
+ texture_ref)); |
+ |
+ // Delete delegate on manager teardown. |
+ { |
+ EXPECT_EQ(texture_ref->num_observers(), 1); |
+ EXPECT_CALL(*delegate, Destroy()).RetiresOnSaturation(); |
+ decoder_->ResetAsyncPixelTransferManagerForTest(); |
+ manager = NULL; |
+ |
+ // Texture ref still valid. |
+ EXPECT_EQ(texture_ref, GetTexture(client_texture_id_)); |
+ EXPECT_EQ(texture_ref->num_observers(), 0); |
+ } |
+} |
+ |
+} // namespace gles2 |
+} // namespace gpu |