gpu: Add async pixel transfers.
This adds a generic async pixel transfer interface, a stub/fallback implementation and mocks/tests. NOTRY=true BUG=161337 Review URL: https://chromiumcodereview.appspot.com/11428140 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@173430 0039d316-1c4b-4281-b951-d872f2087c98
This commit is contained in:
@ -0,0 +1,22 @@
|
||||
// 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/async_pixel_transfer_delegate_mock.h"
|
||||
|
||||
namespace gfx {
|
||||
|
||||
MockAsyncPixelTransferState::MockAsyncPixelTransferState() {
|
||||
}
|
||||
|
||||
MockAsyncPixelTransferState::~MockAsyncPixelTransferState() {
|
||||
}
|
||||
|
||||
MockAsyncPixelTransferDelegate::MockAsyncPixelTransferDelegate() {
|
||||
}
|
||||
|
||||
MockAsyncPixelTransferDelegate::~MockAsyncPixelTransferDelegate() {
|
||||
}
|
||||
|
||||
} // namespace gfx
|
||||
|
@ -0,0 +1,53 @@
|
||||
// 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.
|
||||
|
||||
#ifndef UI_GL_ASYNC_TASK_DELEGATE_MOCK_H_
|
||||
#define UI_GL_ASYNC_TASK_DELEGATE_MOCK_H_
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "testing/gmock/include/gmock/gmock.h"
|
||||
#include "ui/gl/async_pixel_transfer_delegate.h"
|
||||
|
||||
namespace gfx {
|
||||
|
||||
class MockAsyncPixelTransferState : public gfx::AsyncPixelTransferState {
|
||||
public:
|
||||
MockAsyncPixelTransferState();
|
||||
|
||||
// Implement AsyncPixelTransferState.
|
||||
MOCK_METHOD0(TransferIsInProgress, bool());
|
||||
MOCK_METHOD1(BindTransfer, void(AsyncTexImage2DParams* level_params));
|
||||
|
||||
protected:
|
||||
virtual ~MockAsyncPixelTransferState();
|
||||
DISALLOW_COPY_AND_ASSIGN(MockAsyncPixelTransferState);
|
||||
};
|
||||
|
||||
class MockAsyncPixelTransferDelegate : public gfx::AsyncPixelTransferDelegate {
|
||||
public:
|
||||
MockAsyncPixelTransferDelegate();
|
||||
virtual ~MockAsyncPixelTransferDelegate();
|
||||
|
||||
// Implement AsyncPixelTransferDelegate.
|
||||
MOCK_METHOD1(CreateRawPixelTransferState,
|
||||
gfx::AsyncPixelTransferState*(GLuint service_id));
|
||||
MOCK_METHOD1(AsyncNotifyCompletion,
|
||||
void(const base::Closure& task));
|
||||
MOCK_METHOD3(AsyncTexImage2D,
|
||||
void(gfx::AsyncPixelTransferState*,
|
||||
const AsyncTexImage2DParams& tex_params,
|
||||
const AsyncMemoryParams& mem_params));
|
||||
MOCK_METHOD3(AsyncTexSubImage2D,
|
||||
void(gfx::AsyncPixelTransferState*,
|
||||
const AsyncTexSubImage2DParams& tex_params,
|
||||
const AsyncMemoryParams& mem_params));
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(MockAsyncPixelTransferDelegate);
|
||||
};
|
||||
|
||||
} // namespace gfx
|
||||
|
||||
#endif // UI_GL_ASYNC_TASK_DELEGATE_MOCK_H_
|
||||
|
@ -73,6 +73,10 @@ void* CommonDecoder::GetAddressAndCheckSize(unsigned int shm_id,
|
||||
return static_cast<int8*>(buffer.ptr) + offset;
|
||||
}
|
||||
|
||||
Buffer CommonDecoder::GetSharedMemoryBuffer(unsigned int shm_id) {
|
||||
return engine_->GetSharedMemoryBuffer(shm_id);
|
||||
}
|
||||
|
||||
bool CommonDecoder::PushAddress(uint32 offset) {
|
||||
if (call_stack_.size() < kMaxStackDepth) {
|
||||
CommandAddress return_address(engine_->GetGetOffset());
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include <string>
|
||||
#include "base/memory/linked_ptr.h"
|
||||
#include "base/memory/scoped_ptr.h"
|
||||
#include "gpu/command_buffer/common/buffer.h"
|
||||
#include "gpu/command_buffer/service/cmd_parser.h"
|
||||
#include "gpu/gpu_export.h"
|
||||
|
||||
@ -129,6 +130,9 @@ class GPU_EXPORT CommonDecoder : NON_EXPORTED_BASE(public AsyncAPIInterface) {
|
||||
return static_cast<T>(GetAddressAndCheckSize(shm_id, offset, size));
|
||||
}
|
||||
|
||||
// Get the actual shared memory buffer.
|
||||
Buffer GetSharedMemoryBuffer(unsigned int shm_id);
|
||||
|
||||
protected:
|
||||
// Executes a common command.
|
||||
// Parameters:
|
||||
|
@ -56,6 +56,7 @@
|
||||
#include "gpu/command_buffer/service/texture_manager.h"
|
||||
#include "gpu/command_buffer/service/vertex_attrib_manager.h"
|
||||
#include "gpu/command_buffer/service/vertex_array_manager.h"
|
||||
#include "ui/gl/async_pixel_transfer_delegate.h"
|
||||
#include "ui/gl/gl_image.h"
|
||||
#include "ui/gl/gl_implementation.h"
|
||||
#include "ui/gl/gl_surface.h"
|
||||
@ -193,6 +194,61 @@ static inline GLenum GetTexInternalFormat(GLenum internal_format) {
|
||||
return internal_format;
|
||||
}
|
||||
|
||||
// TODO(epenner): Could the above function be merged into this and removed?
|
||||
static inline GLenum GetTexInternalFormat(GLenum internal_format,
|
||||
GLenum format,
|
||||
GLenum type) {
|
||||
GLenum gl_internal_format = GetTexInternalFormat(internal_format);
|
||||
|
||||
if (gfx::GetGLImplementation() == gfx::kGLImplementationEGLGLES2)
|
||||
return gl_internal_format;
|
||||
|
||||
if (type == GL_FLOAT) {
|
||||
switch (format) {
|
||||
case GL_RGBA:
|
||||
gl_internal_format = GL_RGBA32F_ARB;
|
||||
break;
|
||||
case GL_RGB:
|
||||
gl_internal_format = GL_RGB32F_ARB;
|
||||
break;
|
||||
case GL_LUMINANCE_ALPHA:
|
||||
gl_internal_format = GL_LUMINANCE_ALPHA32F_ARB;
|
||||
break;
|
||||
case GL_LUMINANCE:
|
||||
gl_internal_format = GL_LUMINANCE32F_ARB;
|
||||
break;
|
||||
case GL_ALPHA:
|
||||
gl_internal_format = GL_ALPHA32F_ARB;
|
||||
break;
|
||||
default:
|
||||
NOTREACHED();
|
||||
break;
|
||||
}
|
||||
} else if (type == GL_HALF_FLOAT_OES) {
|
||||
switch (format) {
|
||||
case GL_RGBA:
|
||||
gl_internal_format = GL_RGBA16F_ARB;
|
||||
break;
|
||||
case GL_RGB:
|
||||
gl_internal_format = GL_RGB16F_ARB;
|
||||
break;
|
||||
case GL_LUMINANCE_ALPHA:
|
||||
gl_internal_format = GL_LUMINANCE_ALPHA16F_ARB;
|
||||
break;
|
||||
case GL_LUMINANCE:
|
||||
gl_internal_format = GL_LUMINANCE16F_ARB;
|
||||
break;
|
||||
case GL_ALPHA:
|
||||
gl_internal_format = GL_ALPHA16F_ARB;
|
||||
break;
|
||||
default:
|
||||
NOTREACHED();
|
||||
break;
|
||||
}
|
||||
}
|
||||
return gl_internal_format;
|
||||
}
|
||||
|
||||
static void WrappedTexImage2D(
|
||||
GLenum target,
|
||||
GLint level,
|
||||
@ -203,55 +259,9 @@ static void WrappedTexImage2D(
|
||||
GLenum format,
|
||||
GLenum type,
|
||||
const void* pixels) {
|
||||
GLenum gl_internal_format = GetTexInternalFormat(internal_format);
|
||||
if (gfx::GetGLImplementation() != gfx::kGLImplementationEGLGLES2) {
|
||||
if (type == GL_FLOAT) {
|
||||
switch (format) {
|
||||
case GL_RGBA:
|
||||
gl_internal_format = GL_RGBA32F_ARB;
|
||||
break;
|
||||
case GL_RGB:
|
||||
gl_internal_format = GL_RGB32F_ARB;
|
||||
break;
|
||||
case GL_LUMINANCE_ALPHA:
|
||||
gl_internal_format = GL_LUMINANCE_ALPHA32F_ARB;
|
||||
break;
|
||||
case GL_LUMINANCE:
|
||||
gl_internal_format = GL_LUMINANCE32F_ARB;
|
||||
break;
|
||||
case GL_ALPHA:
|
||||
gl_internal_format = GL_ALPHA32F_ARB;
|
||||
break;
|
||||
default:
|
||||
NOTREACHED();
|
||||
break;
|
||||
}
|
||||
} else if (type == GL_HALF_FLOAT_OES) {
|
||||
switch (format) {
|
||||
case GL_RGBA:
|
||||
gl_internal_format = GL_RGBA16F_ARB;
|
||||
break;
|
||||
case GL_RGB:
|
||||
gl_internal_format = GL_RGB16F_ARB;
|
||||
break;
|
||||
case GL_LUMINANCE_ALPHA:
|
||||
gl_internal_format = GL_LUMINANCE_ALPHA16F_ARB;
|
||||
break;
|
||||
case GL_LUMINANCE:
|
||||
gl_internal_format = GL_LUMINANCE16F_ARB;
|
||||
break;
|
||||
case GL_ALPHA:
|
||||
gl_internal_format = GL_ALPHA16F_ARB;
|
||||
break;
|
||||
default:
|
||||
NOTREACHED();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
glTexImage2D(
|
||||
target, level, gl_internal_format, width, height, border, format, type,
|
||||
pixels);
|
||||
target, level, GetTexInternalFormat(internal_format, format, type),
|
||||
width, height, border, format, type, pixels);
|
||||
}
|
||||
|
||||
// Wrapper for glEnable/glDisable that doesn't suck.
|
||||
@ -552,6 +562,12 @@ class GLES2DecoderImpl : public GLES2Decoder {
|
||||
virtual void SetMsgCallback(const MsgCallback& callback) OVERRIDE;
|
||||
|
||||
virtual void SetStreamTextureManager(StreamTextureManager* manager) OVERRIDE;
|
||||
|
||||
virtual gfx::AsyncPixelTransferDelegate*
|
||||
GetAsyncPixelTransferDelegate() OVERRIDE;
|
||||
virtual void SetAsyncPixelTransferDelegate(
|
||||
gfx::AsyncPixelTransferDelegate* delegate) OVERRIDE;
|
||||
|
||||
virtual bool GetServiceTextureId(uint32 client_texture_id,
|
||||
uint32* service_texture_id) OVERRIDE;
|
||||
|
||||
@ -774,6 +790,14 @@ class GLES2DecoderImpl : public GLES2Decoder {
|
||||
GLenum type,
|
||||
const void * data);
|
||||
|
||||
// Extra validation for async tex(Sub)Image2D.
|
||||
bool ValidateAsyncTransfer(
|
||||
const char* function_name,
|
||||
TextureManager::TextureInfo* info,
|
||||
GLenum target,
|
||||
GLint level,
|
||||
const void * data);
|
||||
|
||||
// Wrapper for TexImageIOSurface2DCHROMIUM.
|
||||
void DoTexImageIOSurface2DCHROMIUM(
|
||||
GLenum target,
|
||||
@ -1598,6 +1622,7 @@ class GLES2DecoderImpl : public GLES2Decoder {
|
||||
MsgCallback msg_callback_;
|
||||
|
||||
StreamTextureManager* stream_texture_manager_;
|
||||
scoped_ptr<gfx::AsyncPixelTransferDelegate> async_pixel_transfer_delegate_;
|
||||
|
||||
// The format of the back buffer_
|
||||
GLenum back_buffer_color_format_;
|
||||
@ -2389,6 +2414,10 @@ bool GLES2DecoderImpl::Initialize(
|
||||
glPointParameteri(GL_POINT_SPRITE_COORD_ORIGIN, GL_LOWER_LEFT);
|
||||
}
|
||||
|
||||
// Create a delegate to perform async pixel transfers.
|
||||
async_pixel_transfer_delegate_ =
|
||||
gfx::AsyncPixelTransferDelegate::Create(context.get());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -2656,6 +2685,24 @@ bool GLES2DecoderImpl::MakeCurrent() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 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)
|
||||
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();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -2886,6 +2933,16 @@ void GLES2DecoderImpl::SetStreamTextureManager(StreamTextureManager* manager) {
|
||||
stream_texture_manager_ = manager;
|
||||
}
|
||||
|
||||
gfx::AsyncPixelTransferDelegate*
|
||||
GLES2DecoderImpl::GetAsyncPixelTransferDelegate() {
|
||||
return async_pixel_transfer_delegate_.get();
|
||||
}
|
||||
|
||||
void GLES2DecoderImpl::SetAsyncPixelTransferDelegate(
|
||||
gfx::AsyncPixelTransferDelegate* delegate) {
|
||||
async_pixel_transfer_delegate_ = make_scoped_ptr(delegate);
|
||||
}
|
||||
|
||||
bool GLES2DecoderImpl::GetServiceTextureId(uint32 client_texture_id,
|
||||
uint32* service_texture_id) {
|
||||
TextureManager::TextureInfo* texture =
|
||||
@ -3628,6 +3685,7 @@ void GLES2DecoderImpl::DoBindTexture(GLenum target, GLuint client_id) {
|
||||
texture_manager()->SetInfoTarget(info, target);
|
||||
}
|
||||
glBindTexture(target, info->service_id());
|
||||
|
||||
TextureUnit& unit = state_.texture_units[state_.active_texture_unit];
|
||||
unit.bind_target = target;
|
||||
switch (target) {
|
||||
@ -7915,6 +7973,11 @@ void GLES2DecoderImpl::DoCopyTexSubImage2D(
|
||||
"glCopyTexSubImage2D", "bad dimensions.");
|
||||
return;
|
||||
}
|
||||
if (info->AsyncTransferIsInProgress()) {
|
||||
SetGLError(GL_INVALID_OPERATION,
|
||||
"glCopyTexSubImage2D", "async upload pending for texture");
|
||||
return;
|
||||
}
|
||||
|
||||
// Check we have compatible formats.
|
||||
GLenum read_format = GetBoundReadFrameBufferInternalFormat();
|
||||
@ -8040,6 +8103,11 @@ bool GLES2DecoderImpl::ValidateTexSubImage2D(
|
||||
function_name, "type does not match type of texture.");
|
||||
return false;
|
||||
}
|
||||
if (info->AsyncTransferIsInProgress()) {
|
||||
SetGLError(GL_INVALID_OPERATION,
|
||||
function_name, "async upload pending for texture");
|
||||
return false;
|
||||
}
|
||||
if (!info->ValidForTexture(
|
||||
target, level, xoffset, yoffset, width, height, format, type)) {
|
||||
SetGLError(GL_INVALID_VALUE, function_name, "bad dimensions.");
|
||||
@ -9681,13 +9749,39 @@ void GLES2DecoderImpl::DoTraceEndCHROMIUM() {
|
||||
gpu_trace_stack_.pop();
|
||||
}
|
||||
|
||||
bool GLES2DecoderImpl::ValidateAsyncTransfer(
|
||||
const char* function_name,
|
||||
TextureManager::TextureInfo* info,
|
||||
GLenum target,
|
||||
GLint level,
|
||||
const void * data) {
|
||||
// We only support async uploads to 2D textures for now.
|
||||
if (GL_TEXTURE_2D != target) {
|
||||
SetGLErrorInvalidEnum(function_name, target, "target");
|
||||
return false;
|
||||
}
|
||||
// We only support uploads to level zero for now.
|
||||
if (level != 0) {
|
||||
SetGLError(GL_INVALID_VALUE, function_name, "level != 0");
|
||||
return false;
|
||||
}
|
||||
// A transfer buffer must be bound, even for asyncTexImage2D.
|
||||
if (data == NULL) {
|
||||
SetGLError(GL_INVALID_OPERATION, function_name, "buffer == 0");
|
||||
return false;
|
||||
}
|
||||
// We only support one async transfer in progress.
|
||||
if (!info || info->AsyncTransferIsInProgress()) {
|
||||
SetGLError(GL_INVALID_OPERATION,
|
||||
function_name, "transfer already in progress");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
error::Error GLES2DecoderImpl::HandleAsyncTexImage2DCHROMIUM(
|
||||
uint32 immediate_data_size, const gles2::AsyncTexImage2DCHROMIUM& c) {
|
||||
TRACE_EVENT0("gpu", "GLES2DecoderImpl::HandleAsyncTexImage2DCHROMIUM");
|
||||
|
||||
// TODO: This is a copy of HandleTexImage2D validation. Merge
|
||||
// as much of it as possible.
|
||||
tex_image_2d_failed_ = true;
|
||||
GLenum target = static_cast<GLenum>(c.target);
|
||||
GLint level = static_cast<GLint>(c.level);
|
||||
GLint internal_format = static_cast<GLint>(c.internalformat);
|
||||
@ -9699,6 +9793,9 @@ error::Error GLES2DecoderImpl::HandleAsyncTexImage2DCHROMIUM(
|
||||
uint32 pixels_shm_id = static_cast<uint32>(c.pixels_shm_id);
|
||||
uint32 pixels_shm_offset = static_cast<uint32>(c.pixels_shm_offset);
|
||||
uint32 pixels_size;
|
||||
|
||||
// TODO(epenner): Move this and copies of this memory validation
|
||||
// into ValidateTexImage2D step.
|
||||
if (!GLES2Util::ComputeImageDataSizes(
|
||||
width, height, format, type, state_.unpack_alignment, &pixels_size, NULL,
|
||||
NULL)) {
|
||||
@ -9713,19 +9810,65 @@ error::Error GLES2DecoderImpl::HandleAsyncTexImage2DCHROMIUM(
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(epenner): Do this via an async task.
|
||||
DoTexImage2D(
|
||||
target, level, internal_format, width, height, border, format, type,
|
||||
pixels, pixels_size);
|
||||
// All the normal glTexSubImage2D validation.
|
||||
if (!ValidateTexImage2D(
|
||||
"glAsyncTexImage2DCHROMIUM", target, level, internal_format,
|
||||
width, height, border, format, type, pixels, pixels_size)) {
|
||||
return error::kNoError;
|
||||
}
|
||||
|
||||
// Extra async validation.
|
||||
TextureManager::TextureInfo* info = GetTextureInfoForTarget(target);
|
||||
if (!ValidateAsyncTransfer(
|
||||
"glAsyncTexImage2DCHROMIUM", info, target, level, pixels))
|
||||
return error::kNoError;
|
||||
|
||||
// Don't allow async redefinition of a textures.
|
||||
if (info->IsDefined()) {
|
||||
SetGLError(GL_INVALID_OPERATION,
|
||||
"glAsyncTexImage2DCHROMIUM", "already defined");
|
||||
return error::kNoError;
|
||||
}
|
||||
|
||||
// We know the memory/size is safe, so get the real shared memory since
|
||||
// it might need to be duped to prevent use-after-free of the memory.
|
||||
Buffer buffer = GetSharedMemoryBuffer(c.pixels_shm_id);
|
||||
base::SharedMemory* shared_memory = buffer.shared_memory;
|
||||
uint32 shm_size = buffer.size;
|
||||
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 info
|
||||
// is set up lazily when the transfer completes.
|
||||
DCHECK(!info->GetAsyncTransferState());
|
||||
info->SetAsyncTransferState(
|
||||
async_pixel_transfer_delegate_->
|
||||
CreatePixelTransferState(info->service_id()));
|
||||
info->SetImmutable(true);
|
||||
|
||||
// Issue the async call and set up the texture.
|
||||
GLenum gl_internal_format =
|
||||
GetTexInternalFormat(internal_format, format, type);
|
||||
gfx::AsyncTexImage2DParams tex_params = {target, level, gl_internal_format,
|
||||
width, height, border, format, type};
|
||||
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 info at the same time,
|
||||
// after the the transfer is complete.
|
||||
texture_manager()->AddPendingAsyncPixelTransfer(
|
||||
info->GetAsyncTransferState()->AsWeakPtr(), info);
|
||||
|
||||
async_pixel_transfer_delegate_->AsyncTexImage2D(
|
||||
info->GetAsyncTransferState(), tex_params, mem_params);
|
||||
return error::kNoError;
|
||||
}
|
||||
|
||||
error::Error GLES2DecoderImpl::HandleAsyncTexSubImage2DCHROMIUM(
|
||||
uint32 immediate_data_size, const gles2::AsyncTexSubImage2DCHROMIUM& c) {
|
||||
TRACE_EVENT0("gpu", "GLES2DecoderImpl::HandleAsyncTexSubImage2DCHROMIUM");
|
||||
|
||||
// TODO: This is a copy of HandleTexSubImage2D validation. Merge
|
||||
// as much of it as possible.
|
||||
GLenum target = static_cast<GLenum>(c.target);
|
||||
GLint level = static_cast<GLint>(c.level);
|
||||
GLint xoffset = static_cast<GLint>(c.xoffset);
|
||||
@ -9734,6 +9877,9 @@ error::Error GLES2DecoderImpl::HandleAsyncTexSubImage2DCHROMIUM(
|
||||
GLsizei height = static_cast<GLsizei>(c.height);
|
||||
GLenum format = static_cast<GLenum>(c.format);
|
||||
GLenum type = static_cast<GLenum>(c.type);
|
||||
|
||||
// TODO(epenner): Move this and copies of this memory validation
|
||||
// into ValidateTexSubImage2D step.
|
||||
uint32 data_size;
|
||||
if (!GLES2Util::ComputeImageDataSizes(
|
||||
width, height, format, type, state_.unpack_alignment, &data_size,
|
||||
@ -9742,13 +9888,58 @@ error::Error GLES2DecoderImpl::HandleAsyncTexSubImage2DCHROMIUM(
|
||||
}
|
||||
const void* pixels = GetSharedMemoryAs<const void*>(
|
||||
c.data_shm_id, c.data_shm_offset, data_size);
|
||||
if (pixels == NULL) {
|
||||
return error::kOutOfBounds;
|
||||
|
||||
// All the normal glTexSubImage2D validation.
|
||||
error::Error error = error::kNoError;
|
||||
if (!ValidateTexSubImage2D(&error, "glAsyncTexSubImage2DCHROMIUM",
|
||||
target, level, xoffset, yoffset, width, height, format, type, pixels)) {
|
||||
return error;
|
||||
}
|
||||
|
||||
// TODO(epenner): Do this via an async task.
|
||||
return DoTexSubImage2D(
|
||||
target, level, xoffset, yoffset, width, height, format, type, pixels);
|
||||
// Extra async validation.
|
||||
TextureManager::TextureInfo* info = GetTextureInfoForTarget(target);
|
||||
if (!ValidateAsyncTransfer(
|
||||
"glAsyncTexSubImage2DCHROMIUM", info, target, level, pixels))
|
||||
return error::kNoError;
|
||||
|
||||
// Guarantee async textures are always 'cleared' as follows:
|
||||
// - AsyncTexImage2D can not redefine an existing texture
|
||||
// - AsyncTexImage2D must initialize the entire image via non-null buffer.
|
||||
// - AsyncTexSubImage2D clears synchronously if not already cleared.
|
||||
// - Textures become immutable after an async call.
|
||||
// This way we know in all cases that an async texture is always clear.
|
||||
if (!info->SafeToRenderFrom()) {
|
||||
if (!texture_manager()->ClearTextureLevel(this, info, target, level)) {
|
||||
SetGLError(GL_OUT_OF_MEMORY,
|
||||
"glAsyncTexSubImage2DCHROMIUM","dimensions too big");
|
||||
return error::kNoError;
|
||||
}
|
||||
}
|
||||
|
||||
// We know the memory/size is safe, so get the real shared memory since
|
||||
// it might need to be duped to prevent use-after-free of the memory.
|
||||
Buffer buffer = GetSharedMemoryBuffer(c.data_shm_id);
|
||||
base::SharedMemory* shared_memory = buffer.shared_memory;
|
||||
uint32 shm_size = buffer.size;
|
||||
uint32 shm_data_offset = c.data_shm_offset;
|
||||
uint32 shm_data_size = data_size;
|
||||
|
||||
if (!info->GetAsyncTransferState()) {
|
||||
// Set up the async state if needed, and make the texture
|
||||
// immutable so the async state stays valid.
|
||||
info->SetAsyncTransferState(
|
||||
async_pixel_transfer_delegate_->
|
||||
CreatePixelTransferState(info->service_id()));
|
||||
info->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(
|
||||
info->GetAsyncTransferState(), tex_params, mem_params);
|
||||
return error::kNoError;
|
||||
}
|
||||
|
||||
// Include the auto-generated part of this file. We split this because it means
|
||||
|
@ -20,6 +20,7 @@
|
||||
namespace gfx {
|
||||
class GLContext;
|
||||
class GLSurface;
|
||||
class AsyncPixelTransferDelegate;
|
||||
}
|
||||
|
||||
namespace gpu {
|
||||
@ -157,6 +158,11 @@ class GPU_EXPORT GLES2Decoder : public base::SupportsWeakPtr<GLES2Decoder>,
|
||||
|
||||
virtual void SetStreamTextureManager(StreamTextureManager* manager) = 0;
|
||||
|
||||
// Interface to performing async pixel transfers.
|
||||
virtual gfx::AsyncPixelTransferDelegate* GetAsyncPixelTransferDelegate() = 0;
|
||||
virtual void SetAsyncPixelTransferDelegate(
|
||||
gfx::AsyncPixelTransferDelegate* delegate) = 0;
|
||||
|
||||
// Get the service texture ID corresponding to a client texture ID.
|
||||
// If no such record is found then return false.
|
||||
virtual bool GetServiceTextureId(uint32 client_texture_id,
|
||||
|
@ -57,6 +57,10 @@ class MockGLES2Decoder : public GLES2Decoder {
|
||||
MOCK_METHOD0(GetVertexArrayManager, gpu::gles2::VertexArrayManager*());
|
||||
MOCK_METHOD1(SetResizeCallback, void(const base::Callback<void(gfx::Size)>&));
|
||||
MOCK_METHOD1(SetStreamTextureManager, void(StreamTextureManager*));
|
||||
MOCK_METHOD0(GetAsyncPixelTransferDelegate,
|
||||
gfx::AsyncPixelTransferDelegate*());
|
||||
MOCK_METHOD1(SetAsyncPixelTransferDelegate,
|
||||
void(gfx::AsyncPixelTransferDelegate*));
|
||||
MOCK_METHOD3(DoCommand, error::Error(unsigned int command,
|
||||
unsigned int arg_count,
|
||||
const void* cmd_data));
|
||||
|
@ -8,6 +8,7 @@
|
||||
#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/cmd_buffer_engine.h"
|
||||
#include "gpu/command_buffer/service/context_group.h"
|
||||
#include "gpu/command_buffer/service/gl_surface_mock.h"
|
||||
@ -38,6 +39,7 @@ using ::testing::Pointee;
|
||||
using ::testing::Return;
|
||||
using ::testing::SetArrayArgument;
|
||||
using ::testing::SetArgumentPointee;
|
||||
using ::testing::SetArgPointee;
|
||||
using ::testing::StrEq;
|
||||
using ::testing::StrictMock;
|
||||
|
||||
@ -7975,6 +7977,141 @@ TEST_F(GLES2DecoderManualInitTest, GpuMemoryManagerCHROMIUM) {
|
||||
EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
|
||||
}
|
||||
|
||||
TEST_F(GLES2DecoderManualInitTest, AsyncPixelTransfers) {
|
||||
InitDecoder(
|
||||
"GL_CHROMIUM_async_pixel_transfers", // extensions
|
||||
false, false, false, // has alpha/depth/stencil
|
||||
false, false, false, // request alpha/depth/stencil
|
||||
true); // bind generates resource
|
||||
|
||||
// Set up the texture.
|
||||
DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId);
|
||||
TextureManager::TextureInfo* info = GetTextureInfo(client_texture_id_);
|
||||
|
||||
// Set a mock Async delegate
|
||||
// Async state is returned as a scoped_ptr, but we keep a raw copy.
|
||||
StrictMock<gfx::MockAsyncPixelTransferDelegate>* delegate =
|
||||
new StrictMock<gfx::MockAsyncPixelTransferDelegate>;
|
||||
decoder_->SetAsyncPixelTransferDelegate(delegate);
|
||||
StrictMock<gfx::MockAsyncPixelTransferState>* state = 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);
|
||||
AsyncTexSubImage2DCHROMIUM texsubimage_cmd;
|
||||
texsubimage_cmd.Init(GL_TEXTURE_2D, 0, 0, 0, 8, 8, GL_RGBA,
|
||||
GL_UNSIGNED_BYTE, kSharedMemoryId, kSharedMemoryOffset);
|
||||
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(info->GetAsyncTransferState());
|
||||
|
||||
// AsyncTexImage2D
|
||||
{
|
||||
// Create transfer state since it doesn't exist.
|
||||
EXPECT_CALL(*delegate, CreateRawPixelTransferState(kServiceTextureId))
|
||||
.WillOnce(Return(
|
||||
state = new StrictMock<gfx::MockAsyncPixelTransferState>))
|
||||
.RetiresOnSaturation();
|
||||
EXPECT_CALL(*delegate, AsyncTexImage2D(state, _, _))
|
||||
.RetiresOnSaturation();
|
||||
// Command succeeds.
|
||||
EXPECT_EQ(error::kNoError, ExecuteCmd(teximage_cmd));
|
||||
EXPECT_EQ(GL_NO_ERROR, GetGLError());
|
||||
EXPECT_TRUE(info->GetAsyncTransferState());
|
||||
EXPECT_TRUE(info->IsImmutable());
|
||||
// The texture is safe but the level has not been defined yet.
|
||||
EXPECT_TRUE(info->SafeToRenderFrom());
|
||||
GLsizei width, height;
|
||||
EXPECT_FALSE(info->GetLevelSize(GL_TEXTURE_2D, 0, &width, &height));
|
||||
}
|
||||
{
|
||||
// Async redefinitions are not allowed!
|
||||
// Command fails.
|
||||
EXPECT_EQ(error::kNoError, ExecuteCmd(teximage_cmd));
|
||||
EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
|
||||
EXPECT_TRUE(info->GetAsyncTransferState());
|
||||
EXPECT_TRUE(info->IsImmutable());
|
||||
EXPECT_TRUE(info->SafeToRenderFrom());
|
||||
}
|
||||
|
||||
// Lazy 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 info.
|
||||
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.
|
||||
EXPECT_TRUE(info->SafeToRenderFrom());
|
||||
GLsizei width, height;
|
||||
EXPECT_TRUE(info->GetLevelSize(GL_TEXTURE_2D, 0, &width, &height));
|
||||
EXPECT_EQ(width, 8);
|
||||
EXPECT_EQ(height, 8);
|
||||
}
|
||||
|
||||
// AsyncTexSubImage2D
|
||||
info->SetAsyncTransferState(scoped_ptr<gfx::AsyncPixelTransferState>());
|
||||
info->SetImmutable(false);
|
||||
{
|
||||
// Create transfer state since it doesn't exist.
|
||||
EXPECT_CALL(*delegate, CreateRawPixelTransferState(kServiceTextureId))
|
||||
.WillOnce(Return(
|
||||
state = new StrictMock<gfx::MockAsyncPixelTransferState>))
|
||||
.RetiresOnSaturation();
|
||||
EXPECT_CALL(*delegate, AsyncTexSubImage2D(state, _, _))
|
||||
.RetiresOnSaturation();
|
||||
// Command succeeds.
|
||||
EXPECT_EQ(error::kNoError, ExecuteCmd(texsubimage_cmd));
|
||||
EXPECT_EQ(GL_NO_ERROR, GetGLError());
|
||||
EXPECT_TRUE(info->GetAsyncTransferState());
|
||||
EXPECT_TRUE(info->IsImmutable());
|
||||
EXPECT_TRUE(info->SafeToRenderFrom());
|
||||
}
|
||||
{
|
||||
// No transfer is in progress.
|
||||
EXPECT_CALL(*state, TransferIsInProgress())
|
||||
.WillOnce(Return(false)) // texSubImage validation
|
||||
.WillOnce(Return(false)) // async validation
|
||||
.RetiresOnSaturation();
|
||||
EXPECT_CALL(*delegate, AsyncTexSubImage2D(state, _, _))
|
||||
.RetiresOnSaturation();
|
||||
// Command succeeds.
|
||||
EXPECT_EQ(error::kNoError, ExecuteCmd(texsubimage_cmd));
|
||||
EXPECT_EQ(GL_NO_ERROR, GetGLError());
|
||||
EXPECT_TRUE(info->GetAsyncTransferState());
|
||||
EXPECT_TRUE(info->IsImmutable());
|
||||
EXPECT_TRUE(info->SafeToRenderFrom());
|
||||
}
|
||||
{
|
||||
// A transfer is still in progress!
|
||||
EXPECT_CALL(*state, TransferIsInProgress())
|
||||
.WillOnce(Return(true))
|
||||
.RetiresOnSaturation();
|
||||
// No async call, command fails.
|
||||
EXPECT_EQ(error::kNoError, ExecuteCmd(texsubimage_cmd));
|
||||
EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
|
||||
EXPECT_TRUE(info->GetAsyncTransferState());
|
||||
EXPECT_TRUE(info->IsImmutable());
|
||||
EXPECT_TRUE(info->SafeToRenderFrom());
|
||||
}
|
||||
|
||||
decoder_->SetAsyncPixelTransferDelegate(NULL);
|
||||
info->SetAsyncTransferState(scoped_ptr<gfx::AsyncPixelTransferState>());
|
||||
}
|
||||
|
||||
// TODO(gman): Complete this test.
|
||||
// TEST_F(GLES2DecoderTest, CompressedTexImage2DGLError) {
|
||||
// }
|
||||
|
@ -4,11 +4,13 @@
|
||||
|
||||
#include "gpu/command_buffer/service/query_manager.h"
|
||||
#include "base/atomicops.h"
|
||||
#include "base/bind.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/time.h"
|
||||
#include "gpu/command_buffer/common/gles2_cmd_format.h"
|
||||
#include "gpu/command_buffer/service/gles2_cmd_decoder.h"
|
||||
#include "gpu/command_buffer/service/feature_info.h"
|
||||
#include "ui/gl/async_pixel_transfer_delegate.h"
|
||||
|
||||
namespace gpu {
|
||||
namespace gles2 {
|
||||
@ -162,7 +164,9 @@ void CommandLatencyQuery::Destroy(bool /* have_context */) {
|
||||
CommandLatencyQuery::~CommandLatencyQuery() {
|
||||
}
|
||||
|
||||
class AsyncPixelTransfersCompletedQuery : public QueryManager::Query {
|
||||
class AsyncPixelTransfersCompletedQuery
|
||||
: public QueryManager::Query
|
||||
, public base::SupportsWeakPtr<AsyncPixelTransfersCompletedQuery> {
|
||||
public:
|
||||
AsyncPixelTransfersCompletedQuery(
|
||||
QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset);
|
||||
@ -172,6 +176,8 @@ class AsyncPixelTransfersCompletedQuery : public QueryManager::Query {
|
||||
virtual bool Process() OVERRIDE;
|
||||
virtual void Destroy(bool have_context) OVERRIDE;
|
||||
|
||||
void MarkAsCompletedCallback() { MarkAsCompleted(1); }
|
||||
|
||||
protected:
|
||||
virtual ~AsyncPixelTransfersCompletedQuery();
|
||||
};
|
||||
@ -186,12 +192,24 @@ bool AsyncPixelTransfersCompletedQuery::Begin() {
|
||||
}
|
||||
|
||||
bool AsyncPixelTransfersCompletedQuery::End(uint32 submit_count) {
|
||||
// TODO(epenner): Mark completion via an async task.
|
||||
// TODO(epenner): This will be a boolean to start, indicating
|
||||
// completion of all tasks in the query. We could change this
|
||||
// to return a count of tasks completed instead.
|
||||
MarkAsPending(submit_count);
|
||||
return MarkAsCompleted(1);
|
||||
|
||||
// This will call MarkAsCompleted(1) as a reply to a task on
|
||||
// the async upload thread, such that it occurs after all previous
|
||||
// async transfers have completed.
|
||||
manager()->decoder()->GetAsyncPixelTransferDelegate()->AsyncNotifyCompletion(
|
||||
base::Bind(
|
||||
&AsyncPixelTransfersCompletedQuery::MarkAsCompletedCallback,
|
||||
AsWeakPtr()));
|
||||
|
||||
// TODO(epenner): The async task occurs outside the normal
|
||||
// flow, via a callback on this thread. Is there anything
|
||||
// missing or wrong with that?
|
||||
|
||||
// TODO(epenner): Could we possibly trigger the completion on
|
||||
// the upload thread by writing to the query shared memory
|
||||
// directly?
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AsyncPixelTransfersCompletedQuery::Process() {
|
||||
|
@ -1210,5 +1210,53 @@ void TextureManager::AddToSignature(
|
||||
info->AddToSignature(feature_info_.get(), target, level, signature);
|
||||
}
|
||||
|
||||
void TextureManager::AddPendingAsyncPixelTransfer(
|
||||
base::WeakPtr<gfx::AsyncPixelTransferState> state, TextureInfo* info) {
|
||||
pending_async_transfers_.push_back(PendingAsyncTransfer(state,info));
|
||||
}
|
||||
|
||||
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 TextureInfo. So if the
|
||||
// async state is deleted, so is the TextureInfo.
|
||||
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 TextureInfo, 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
|
||||
|
@ -5,6 +5,7 @@
|
||||
#ifndef GPU_COMMAND_BUFFER_SERVICE_TEXTURE_MANAGER_H_
|
||||
#define GPU_COMMAND_BUFFER_SERVICE_TEXTURE_MANAGER_H_
|
||||
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "base/basictypes.h"
|
||||
@ -15,6 +16,7 @@
|
||||
#include "gpu/command_buffer/service/gl_utils.h"
|
||||
#include "gpu/command_buffer/service/memory_tracking.h"
|
||||
#include "gpu/gpu_export.h"
|
||||
#include "ui/gl/async_pixel_transfer_delegate.h"
|
||||
#include "ui/gl/gl_image.h"
|
||||
|
||||
namespace gpu {
|
||||
@ -178,6 +180,17 @@ class GPU_EXPORT TextureManager {
|
||||
return stream_texture_;
|
||||
}
|
||||
|
||||
gfx::AsyncPixelTransferState* GetAsyncTransferState() const {
|
||||
return async_transfer_state_.get();
|
||||
}
|
||||
void SetAsyncTransferState(scoped_ptr<gfx::AsyncPixelTransferState> state) {
|
||||
async_transfer_state_ = state.Pass();
|
||||
}
|
||||
bool AsyncTransferIsInProgress() {
|
||||
return async_transfer_state_ &&
|
||||
async_transfer_state_->TransferIsInProgress();
|
||||
}
|
||||
|
||||
void SetImmutable(bool immutable) {
|
||||
immutable_ = immutable;
|
||||
}
|
||||
@ -189,6 +202,11 @@ class GPU_EXPORT TextureManager {
|
||||
// Whether a particular level/face is cleared.
|
||||
bool IsLevelCleared(GLenum target, GLint level);
|
||||
|
||||
// Whether the texture has been defined
|
||||
bool IsDefined() {
|
||||
return estimated_size() > 0;
|
||||
}
|
||||
|
||||
private:
|
||||
friend class TextureManager;
|
||||
friend class base::RefCounted<TextureInfo>;
|
||||
@ -341,6 +359,9 @@ class GPU_EXPORT TextureManager {
|
||||
// Whether this is a special streaming texture.
|
||||
bool stream_texture_;
|
||||
|
||||
// State to facilitate async transfers on this texture.
|
||||
scoped_ptr<gfx::AsyncPixelTransferState> async_transfer_state_;
|
||||
|
||||
// Whether the texture is immutable and no further changes to the format
|
||||
// or dimensions of the texture object can be made.
|
||||
bool immutable_;
|
||||
@ -530,6 +551,13 @@ class GPU_EXPORT TextureManager {
|
||||
GLint level,
|
||||
std::string* signature) const;
|
||||
|
||||
// Transfers added will get their TextureInfo updated at the same time
|
||||
// the async transfer is bound to the real texture.
|
||||
void AddPendingAsyncPixelTransfer(
|
||||
base::WeakPtr<gfx::AsyncPixelTransferState> state, TextureInfo* info);
|
||||
void BindFinishedAsyncPixelTransfers(bool* texture_dirty,
|
||||
bool* framebuffer_dirty);
|
||||
|
||||
private:
|
||||
// Helper for Initialize().
|
||||
TextureInfo::Ref CreateDefaultAndBlackTextures(
|
||||
@ -572,6 +600,14 @@ class GPU_EXPORT TextureManager {
|
||||
// The default textures for each target (texture name = 0)
|
||||
TextureInfo::Ref default_textures_[kNumDefaultTextures];
|
||||
|
||||
// Async texture allocations which haven't been bound to their textures
|
||||
// yet. This facilitates updating the TextureInfo at the same time the
|
||||
// real texture data is bound.
|
||||
typedef std::pair<base::WeakPtr<gfx::AsyncPixelTransferState>,
|
||||
TextureInfo*> PendingAsyncTransfer;
|
||||
typedef std::list<PendingAsyncTransfer> PendingAsyncTransferList;
|
||||
PendingAsyncTransferList pending_async_transfers_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(TextureManager);
|
||||
};
|
||||
|
||||
|
@ -155,6 +155,8 @@
|
||||
'command_buffer/common/id_allocator_test.cc',
|
||||
'command_buffer/common/trace_event.h',
|
||||
'command_buffer/common/unittest_main.cc',
|
||||
'command_buffer/service/async_pixel_transfer_delegate_mock.h',
|
||||
'command_buffer/service/async_pixel_transfer_delegate_mock.cc',
|
||||
'command_buffer/service/buffer_manager_unittest.cc',
|
||||
'command_buffer/service/cmd_parser_test.cc',
|
||||
'command_buffer/service/command_buffer_service_unittest.cc',
|
||||
|
117
ui/gl/async_pixel_transfer_delegate.h
Normal file
117
ui/gl/async_pixel_transfer_delegate.h
Normal file
@ -0,0 +1,117 @@
|
||||
// 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.
|
||||
|
||||
#ifndef UI_GL_ASYNC_TASK_DELEGATE_H_
|
||||
#define UI_GL_ASYNC_TASK_DELEGATE_H_
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "base/bind.h"
|
||||
#include "base/memory/scoped_ptr.h"
|
||||
#include "base/memory/weak_ptr.h"
|
||||
#include "build/build_config.h"
|
||||
#include "ui/gl/gl_bindings.h"
|
||||
#include "ui/gl/gl_export.h"
|
||||
|
||||
namespace base {
|
||||
class SharedMemory;
|
||||
}
|
||||
|
||||
namespace gfx {
|
||||
|
||||
struct AsyncTexImage2DParams {
|
||||
GLenum target;
|
||||
GLint level;
|
||||
GLenum internal_format;
|
||||
GLsizei width;
|
||||
GLsizei height;
|
||||
GLint border;
|
||||
GLenum format;
|
||||
GLenum type;
|
||||
};
|
||||
|
||||
struct AsyncTexSubImage2DParams {
|
||||
GLenum target;
|
||||
GLint level;
|
||||
GLint xoffset;
|
||||
GLint yoffset;
|
||||
GLsizei width;
|
||||
GLsizei height;
|
||||
GLenum format;
|
||||
GLenum type;
|
||||
};
|
||||
|
||||
struct AsyncMemoryParams {
|
||||
base::SharedMemory* shared_memory;
|
||||
uint32 shm_size;
|
||||
uint32 shm_data_offset;
|
||||
uint32 shm_data_size;
|
||||
};
|
||||
|
||||
// AsyncPixelTransferState holds the resources required to do async
|
||||
// transfers on one texture. It should stay alive for the lifetime
|
||||
// of the texture to allow multiple transfers.
|
||||
class GL_EXPORT AsyncPixelTransferState :
|
||||
public base::SupportsWeakPtr<AsyncPixelTransferState> {
|
||||
public:
|
||||
virtual ~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);
|
||||
};
|
||||
|
||||
class GL_EXPORT AsyncPixelTransferDelegate {
|
||||
public:
|
||||
static scoped_ptr<AsyncPixelTransferDelegate>
|
||||
Create(gfx::GLContext* context);
|
||||
virtual ~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));
|
||||
}
|
||||
|
||||
virtual void AsyncNotifyCompletion(
|
||||
const base::Closure& notify_task) = 0;
|
||||
|
||||
virtual void AsyncTexImage2D(
|
||||
AsyncPixelTransferState* state,
|
||||
const AsyncTexImage2DParams& tex_params,
|
||||
const AsyncMemoryParams& mem_params) = 0;
|
||||
|
||||
virtual void AsyncTexSubImage2D(
|
||||
AsyncPixelTransferState* state,
|
||||
const AsyncTexSubImage2DParams& tex_params,
|
||||
const AsyncMemoryParams& mem_params) = 0;
|
||||
|
||||
protected:
|
||||
AsyncPixelTransferDelegate() {}
|
||||
// For testing, as returning scoped_ptr wouldn't work with MOCK_METHOD.
|
||||
virtual AsyncPixelTransferState*
|
||||
CreateRawPixelTransferState(GLuint texture_id) = 0;
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(AsyncPixelTransferDelegate);
|
||||
};
|
||||
|
||||
} // namespace gfx
|
||||
|
||||
#endif // UI_GL_ASYNC_TASK_DELEGATE_H_
|
||||
|
135
ui/gl/async_pixel_transfer_delegate_stub.cc
Normal file
135
ui/gl/async_pixel_transfer_delegate_stub.cc
Normal file
@ -0,0 +1,135 @@
|
||||
// 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 "ui/gl/async_pixel_transfer_delegate_stub.h"
|
||||
|
||||
#include "base/shared_memory.h"
|
||||
#include "build/build_config.h"
|
||||
#include "ui/gl/gl_bindings.h"
|
||||
|
||||
using base::SharedMemory;
|
||||
using base::SharedMemoryHandle;
|
||||
|
||||
namespace {
|
||||
// Gets the address of the data from shared memory.
|
||||
void* GetAddress(SharedMemory* shared_memory,
|
||||
uint32 shm_size,
|
||||
uint32 shm_data_offset,
|
||||
uint32 shm_data_size) {
|
||||
// Memory bounds have already been validated, so there
|
||||
// is just DCHECKS here.
|
||||
DCHECK(shared_memory);
|
||||
DCHECK(shared_memory->memory());
|
||||
DCHECK_LE(shm_data_offset + shm_data_size, shm_size);
|
||||
return static_cast<int8*>(shared_memory->memory()) + shm_data_offset;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace gfx {
|
||||
|
||||
scoped_ptr<AsyncPixelTransferDelegate>
|
||||
AsyncPixelTransferDelegate::Create(gfx::GLContext* context) {
|
||||
return AsyncPixelTransferDelegateStub::Create(context);
|
||||
}
|
||||
|
||||
scoped_ptr<AsyncPixelTransferDelegate>
|
||||
AsyncPixelTransferDelegateStub::Create(gfx::GLContext* context) {
|
||||
return make_scoped_ptr(
|
||||
static_cast<AsyncPixelTransferDelegate*>(
|
||||
new AsyncPixelTransferDelegateStub()));
|
||||
}
|
||||
|
||||
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() {
|
||||
}
|
||||
|
||||
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() {
|
||||
}
|
||||
|
||||
AsyncPixelTransferDelegateStub::~AsyncPixelTransferDelegateStub() {
|
||||
}
|
||||
|
||||
AsyncPixelTransferState*
|
||||
AsyncPixelTransferDelegateStub::CreateRawPixelTransferState(
|
||||
GLuint texture_id) {
|
||||
return static_cast<AsyncPixelTransferState*>(
|
||||
new AsyncTransferStateStub(texture_id));
|
||||
}
|
||||
|
||||
void AsyncPixelTransferDelegateStub::AsyncNotifyCompletion(
|
||||
const base::Closure& task) {
|
||||
task.Run();
|
||||
}
|
||||
|
||||
void AsyncPixelTransferDelegateStub::AsyncTexImage2D(
|
||||
AsyncPixelTransferState* transfer_state,
|
||||
const AsyncTexImage2DParams& tex_params,
|
||||
const AsyncMemoryParams& mem_params) {
|
||||
// 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,
|
||||
mem_params.shm_data_size);
|
||||
glTexImage2D(
|
||||
tex_params.target,
|
||||
tex_params.level,
|
||||
tex_params.internal_format,
|
||||
tex_params.width,
|
||||
tex_params.height,
|
||||
tex_params.border,
|
||||
tex_params.format,
|
||||
tex_params.type,
|
||||
data);
|
||||
}
|
||||
|
||||
void AsyncPixelTransferDelegateStub::AsyncTexSubImage2D(
|
||||
AsyncPixelTransferState* transfer_state,
|
||||
const AsyncTexSubImage2DParams& tex_params,
|
||||
const AsyncMemoryParams& mem_params) {
|
||||
void* data = GetAddress(mem_params.shared_memory,
|
||||
mem_params.shm_size,
|
||||
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_);
|
||||
glTexSubImage2D(
|
||||
tex_params.target,
|
||||
tex_params.level,
|
||||
tex_params.xoffset,
|
||||
tex_params.yoffset,
|
||||
tex_params.width,
|
||||
tex_params.height,
|
||||
tex_params.format,
|
||||
tex_params.type,
|
||||
data);
|
||||
}
|
||||
} // namespace gfx
|
||||
|
59
ui/gl/async_pixel_transfer_delegate_stub.h
Normal file
59
ui/gl/async_pixel_transfer_delegate_stub.h
Normal file
@ -0,0 +1,59 @@
|
||||
// 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.
|
||||
|
||||
#ifndef UI_GL_ASYNC_TASK_DELEGATE_STUB_H_
|
||||
#define UI_GL_ASYNC_TASK_DELEGATE_STUB_H_
|
||||
|
||||
#include "ui/gl/async_pixel_transfer_delegate.h"
|
||||
|
||||
namespace gfx {
|
||||
|
||||
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();
|
||||
DISALLOW_COPY_AND_ASSIGN(AsyncTransferStateStub);
|
||||
};
|
||||
|
||||
// Class which handles async pixel transfers (as a fallback).
|
||||
// This class just does the uploads synchronously.
|
||||
class AsyncPixelTransferDelegateStub : public AsyncPixelTransferDelegate {
|
||||
public:
|
||||
static scoped_ptr<AsyncPixelTransferDelegate>
|
||||
Create(gfx::GLContext* context);
|
||||
|
||||
AsyncPixelTransferDelegateStub();
|
||||
virtual ~AsyncPixelTransferDelegateStub();
|
||||
|
||||
// implement AsyncPixelTransferDelegate:
|
||||
virtual void AsyncNotifyCompletion(const base::Closure& task) OVERRIDE;
|
||||
virtual void AsyncTexImage2D(
|
||||
AsyncPixelTransferState* transfer_state,
|
||||
const AsyncTexImage2DParams& tex_params,
|
||||
const AsyncMemoryParams& mem_params) OVERRIDE;
|
||||
virtual void AsyncTexSubImage2D(
|
||||
AsyncPixelTransferState* transfer_state,
|
||||
const AsyncTexSubImage2DParams& tex_params,
|
||||
const AsyncMemoryParams& mem_params) OVERRIDE;
|
||||
private:
|
||||
// implement AsyncPixelTransferDelegate:
|
||||
virtual AsyncPixelTransferState*
|
||||
CreateRawPixelTransferState(GLuint texture_id) OVERRIDE;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(AsyncPixelTransferDelegateStub);
|
||||
};
|
||||
|
||||
} // namespace gfx
|
||||
|
||||
#endif // UI_GL_ASYNC_TASK_DELEGATE_ANDROID_H_
|
||||
|
@ -902,6 +902,19 @@ EGL_FUNCTIONS = [
|
||||
'names': ['eglQuerySurfacePointerANGLE'],
|
||||
'arguments':
|
||||
'EGLDisplay dpy, EGLSurface surface, EGLint attribute, void** value', },
|
||||
{ 'return_type': 'EGLSyncKHR',
|
||||
'names': ['eglCreateSyncKHR'],
|
||||
'arguments': 'EGLDisplay dpy, EGLenum type, const EGLint* attrib_list',
|
||||
'other_extensions': ['EGL_KHR_fence_sync'] },
|
||||
{ 'return_type': 'EGLint',
|
||||
'names': ['eglClientWaitSyncKHR'],
|
||||
'arguments': 'EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, '
|
||||
'EGLTimeKHR timeout',
|
||||
'other_extensions': ['EGL_KHR_fence_sync'] },
|
||||
{ 'return_type': 'EGLBoolean',
|
||||
'names': ['eglDestroySyncKHR'],
|
||||
'arguments': 'EGLDisplay dpy, EGLSyncKHR sync',
|
||||
'other_extensions': ['EGL_KHR_fence_sync'] },
|
||||
]
|
||||
|
||||
WGL_FUNCTIONS = [
|
||||
|
@ -40,6 +40,9 @@
|
||||
'<(DEPTH)/third_party/mesa/mesa.gyp:mesa_headers',
|
||||
],
|
||||
'sources': [
|
||||
'async_pixel_transfer_delegate.h',
|
||||
'async_pixel_transfer_delegate_stub.cc',
|
||||
'async_pixel_transfer_delegate_stub.h',
|
||||
'gl_bindings.h',
|
||||
'gl_bindings_skia_in_process.cc',
|
||||
'gl_bindings_skia_in_process.h',
|
||||
|
@ -53,6 +53,7 @@ typedef void (*OSMESAproc)();
|
||||
#if !defined(OS_MACOSX)
|
||||
|
||||
// Forward declare EGL types.
|
||||
typedef uint64 EGLTimeKHR;
|
||||
typedef unsigned int EGLBoolean;
|
||||
typedef unsigned int EGLenum;
|
||||
typedef int EGLint;
|
||||
@ -62,6 +63,7 @@ typedef void *EGLDisplay;
|
||||
typedef void *EGLImageKHR;
|
||||
typedef void *EGLSurface;
|
||||
typedef void *EGLClientBuffer;
|
||||
typedef void *EGLSyncKHR;
|
||||
typedef void (*__eglMustCastToProperFunctionPointerType)(void);
|
||||
typedef void* GLeglImageOES;
|
||||
|
||||
|
Reference in New Issue
Block a user