| Index: gpu/command_buffer/client/gles2_implementation.cc
|
| ===================================================================
|
| --- gpu/command_buffer/client/gles2_implementation.cc (revision 33021)
|
| +++ gpu/command_buffer/client/gles2_implementation.cc (working copy)
|
| @@ -14,13 +14,21 @@
|
|
|
| GLES2Implementation::GLES2Implementation(
|
| GLES2CmdHelper* helper,
|
| + size_t transfer_buffer_size,
|
| void* transfer_buffer,
|
| - int transfer_buffer_id)
|
| + int32 transfer_buffer_id)
|
| : util_(0), // TODO(gman): Get real number of compressed texture formats.
|
| helper_(helper),
|
| - shared_memory_(transfer_buffer, transfer_buffer_id),
|
| + transfer_buffer_(transfer_buffer_size, helper, transfer_buffer),
|
| + transfer_buffer_id_(transfer_buffer_id),
|
| pack_alignment_(4),
|
| unpack_alignment_(4) {
|
| + // Eat 1 id so we start at 1 instead of 0.
|
| + GLuint eat;
|
| + MakeIds(1, &eat);
|
| + // Allocate space for simple GL results.
|
| + result_buffer_ = transfer_buffer_.Alloc(kMaxSizeOfSimpleResult);
|
| + result_shm_offset_ = transfer_buffer_.GetOffset(result_buffer_);
|
| }
|
|
|
| void GLES2Implementation::MakeIds(GLsizei n, GLuint* ids) {
|
| @@ -35,11 +43,47 @@
|
| }
|
| }
|
|
|
| +void GLES2Implementation::WaitForCmd() {
|
| + int32 token = helper_->InsertToken();
|
| + helper_->WaitForToken(token);
|
| +}
|
| +
|
| void GLES2Implementation::DrawElements(
|
| GLenum mode, GLsizei count, GLenum type, const void* indices) {
|
| helper_->DrawElements(mode, count, type, reinterpret_cast<GLuint>(indices));
|
| }
|
|
|
| +GLint GLES2Implementation::GetAttribLocation(
|
| + GLuint program, const char* name) {
|
| + helper_->GetAttribLocationImmediate(
|
| + program, name, result_shm_id(), result_shm_offset());
|
| + WaitForCmd();
|
| + return GetResultAs<GLint>();
|
| +}
|
| +
|
| +GLint GLES2Implementation::GetUniformLocation(
|
| + GLuint program, const char* name) {
|
| + helper_->GetUniformLocationImmediate(
|
| + program, name, result_shm_id(), result_shm_offset());
|
| + WaitForCmd();
|
| + return GetResultAs<GLint>();
|
| +}
|
| +
|
| +void GLES2Implementation::PixelStorei(GLenum pname, GLint param) {
|
| + switch (pname) {
|
| + case GL_PACK_ALIGNMENT:
|
| + pack_alignment_ = param;
|
| + break;
|
| + case GL_UNPACK_ALIGNMENT:
|
| + unpack_alignment_ = param;
|
| + break;
|
| + default:
|
| + break;
|
| + }
|
| + helper_->PixelStorei(pname, param);
|
| +}
|
| +
|
| +
|
| void GLES2Implementation::VertexAttribPointer(
|
| GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride,
|
| const void* ptr) {
|
| @@ -48,103 +92,158 @@
|
| }
|
|
|
| void GLES2Implementation::ShaderSource(
|
| - GLuint shader, GLsizei count, const char** string, const GLint* length) {
|
| + GLuint shader, GLsizei count, const char** source, const GLint* length) {
|
| // TODO(gman): change to use buckets and check that there is enough room.
|
| - uint32* offsets = shared_memory_.GetAddressAs<uint32*>(0);
|
| - char* strings = reinterpret_cast<char*>(offsets + count);
|
|
|
| + // Compute the total size.
|
| + uint32 total_size = count * sizeof(total_size);
|
| + for (GLsizei ii = 0; ii < count; ++ii) {
|
| + total_size += length ? length[ii] : strlen(source[ii]);
|
| + }
|
| +
|
| + // Create string table in transfer buffer.
|
| + char* strings = transfer_buffer_.AllocTyped<char>(total_size);
|
| + uint32* offsets = reinterpret_cast<uint32*>(strings);
|
| uint32 offset = count * sizeof(*offsets);
|
| for (GLsizei ii = 0; ii < count; ++ii) {
|
| - uint32 len = length ? length[ii] : strlen(string[ii]);
|
| - memcpy(strings + offset, string[ii], len);
|
| + uint32 len = length ? length[ii] : strlen(source[ii]);
|
| + memcpy(strings + offset, source[ii], len);
|
| offset += len;
|
| offsets[ii] = offset;
|
| }
|
|
|
| - helper_->ShaderSource(shader, count, shared_memory_.GetId(), 0, offset);
|
| - // TODO(gman): Should insert token but not wait until we need shared memory
|
| - // again. Really, I should implement a shared memory manager that puts
|
| - // things in the next unused part of shared memory and only blocks
|
| - // when it needs more memory.
|
| - int32 token = helper_->InsertToken();
|
| - helper_->WaitForToken(token);
|
| + helper_->ShaderSource(shader, count,
|
| + transfer_buffer_id_,
|
| + transfer_buffer_.GetOffset(strings), offset);
|
| + transfer_buffer_.FreePendingToken(strings, helper_->InsertToken());
|
| }
|
|
|
| void GLES2Implementation::BufferData(
|
| GLenum target, GLsizeiptr size, const void* data, GLenum usage) {
|
| - // TODO(gman): Switch to use buckets alwayst or at least if no room in shared
|
| - // memory.
|
| - memcpy(shared_memory_.GetAddress(0), data, size);
|
| - helper_->BufferData(target, size, shared_memory_.GetId(), 0, usage);
|
| - int32 token = helper_->InsertToken();
|
| - helper_->WaitForToken(token);
|
| + // NOTE: Should this be optimized for the case where we can call BufferData
|
| + // with the actual data in the case of our transfer buffer being big
|
| + // enough?
|
| + helper_->BufferData(target, size, 0, 0, usage);
|
| + if (data != NULL) {
|
| + BufferSubData(target, 0, size, data);
|
| + }
|
| }
|
|
|
| void GLES2Implementation::BufferSubData(
|
| GLenum target, GLintptr offset, GLsizeiptr size, const void* data) {
|
| - // TODO(gman): Switch to use buckets alwayst or at least if no room in shared
|
| - // memory.
|
| - memcpy(shared_memory_.GetAddress(0), data, size);
|
| - helper_->BufferSubData(target, offset, size, shared_memory_.GetId(), 0);
|
| - int32 token = helper_->InsertToken();
|
| - helper_->WaitForToken(token);
|
| + const int8* source = static_cast<const int8*>(data);
|
| + GLsizeiptr max_size = transfer_buffer_.GetLargestFreeOrPendingSize();
|
| + while (size) {
|
| + GLsizeiptr part_size = std::min(size, max_size);
|
| + void* buffer = transfer_buffer_.Alloc(part_size);
|
| + memcpy(buffer, source, part_size);
|
| + helper_->BufferSubData(target, offset, part_size,
|
| + transfer_buffer_id_,
|
| + transfer_buffer_.GetOffset(buffer));
|
| + transfer_buffer_.FreePendingToken(buffer, helper_->InsertToken());
|
| + offset += part_size;
|
| + source += part_size;
|
| + size -= part_size;
|
| + }
|
| }
|
|
|
| void GLES2Implementation::CompressedTexImage2D(
|
| GLenum target, GLint level, GLenum internalformat, GLsizei width,
|
| - GLsizei height, GLint border, GLsizei imageSize, const void* data) {
|
| + GLsizei height, GLint border, GLsizei image_size, const void* data) {
|
| // TODO(gman): Switch to use buckets alwayst or at least if no room in shared
|
| // memory.
|
| - memcpy(shared_memory_.GetAddress(0), data, imageSize);
|
| + DCHECK_LE(image_size,
|
| + static_cast<GLsizei>(
|
| + transfer_buffer_.GetLargestFreeOrPendingSize()));
|
| + void* buffer = transfer_buffer_.Alloc(image_size);
|
| + memcpy(buffer, data, image_size);
|
| helper_->CompressedTexImage2D(
|
| - target, level, internalformat, width, height, border, imageSize,
|
| - shared_memory_.GetId(), 0);
|
| - int32 token = helper_->InsertToken();
|
| - helper_->WaitForToken(token);
|
| + target, level, internalformat, width, height, border, image_size,
|
| + transfer_buffer_id_, transfer_buffer_.GetOffset(buffer));
|
| + transfer_buffer_.FreePendingToken(buffer, helper_->InsertToken());
|
| }
|
|
|
| void GLES2Implementation::CompressedTexSubImage2D(
|
| GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
|
| - GLsizei height, GLenum format, GLsizei imageSize, const void* data) {
|
| + GLsizei height, GLenum format, GLsizei image_size, const void* data) {
|
| // TODO(gman): Switch to use buckets alwayst or at least if no room in shared
|
| // memory.
|
| - memcpy(shared_memory_.GetAddress(0), data, imageSize);
|
| + DCHECK_LE(image_size,
|
| + static_cast<GLsizei>(
|
| + transfer_buffer_.GetLargestFreeOrPendingSize()));
|
| + void* buffer = transfer_buffer_.Alloc(image_size);
|
| + memcpy(buffer, data, image_size);
|
| helper_->CompressedTexSubImage2D(
|
| - target, level, xoffset, yoffset, width, height, format, imageSize,
|
| - shared_memory_.GetId(), 0);
|
| - int32 token = helper_->InsertToken();
|
| - helper_->WaitForToken(token);
|
| + target, level, xoffset, yoffset, width, height, format, image_size,
|
| + transfer_buffer_id_, transfer_buffer_.GetOffset(buffer));
|
| + transfer_buffer_.FreePendingToken(buffer, helper_->InsertToken());
|
| }
|
|
|
| void GLES2Implementation::TexImage2D(
|
| GLenum target, GLint level, GLint internalformat, GLsizei width,
|
| GLsizei height, GLint border, GLenum format, GLenum type,
|
| const void* pixels) {
|
| - // TODO(gman): Switch to use buckets alwayst or at least if no room in shared
|
| - // memory.
|
| - uint32 pixels_size = GLES2Util::ComputeImageDataSize(
|
| - width, height, format, type, unpack_alignment_);
|
| - memcpy(shared_memory_.GetAddress(0), pixels, pixels_size);
|
| helper_->TexImage2D(
|
| - target, level, internalformat, width, height, border, format, type,
|
| - shared_memory_.GetId(), 0);
|
| - int32 token = helper_->InsertToken();
|
| - helper_->WaitForToken(token);
|
| + target, level, internalformat, width, height, border, format, type, 0, 0);
|
| + if (pixels) {
|
| + TexSubImage2D(target, level, 0, 0, width, height, format, type, pixels);
|
| + }
|
| }
|
|
|
| void GLES2Implementation::TexSubImage2D(
|
| GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
|
| GLsizei height, GLenum format, GLenum type, const void* pixels) {
|
| - // TODO(gman): Switch to use buckets alwayst or at least if no room in shared
|
| - // memory.
|
| - uint32 pixels_size = GLES2Util::ComputeImageDataSize(
|
| - width, height, format, type, unpack_alignment_);
|
| - memcpy(shared_memory_.GetAddress(0), pixels, pixels_size);
|
| - helper_->TexSubImage2D(
|
| - target, level, xoffset, yoffset, width, height, format, type,
|
| - shared_memory_.GetId(), 0);
|
| - int32 token = helper_->InsertToken();
|
| - helper_->WaitForToken(token);
|
| + const int8* source = static_cast<const int8*>(pixels);
|
| + GLsizeiptr max_size = transfer_buffer_.GetLargestFreeOrPendingSize();
|
| +
|
| + GLsizeiptr unpadded_row_size = GLES2Util::ComputeImageDataSize(
|
| + width, 1, format, type, unpack_alignment_);
|
| + GLsizeiptr padded_row_size = GLES2Util::ComputeImageDataSize(
|
| + width, 2, format, type, unpack_alignment_) - unpadded_row_size;
|
| +
|
| + if (padded_row_size <= max_size) {
|
| + // Transfer by rows.
|
| + GLint max_rows = max_size / padded_row_size;
|
| + while (height) {
|
| + GLint num_rows = std::min(height, max_rows);
|
| + GLsizeiptr part_size = num_rows * padded_row_size;
|
| + void* buffer = transfer_buffer_.Alloc(part_size);
|
| + memcpy(buffer, source, part_size);
|
| + helper_->TexSubImage2D(
|
| + target, level, xoffset, yoffset, width, num_rows, format, type,
|
| + transfer_buffer_id_, transfer_buffer_.GetOffset(buffer));
|
| + transfer_buffer_.FreePendingToken(buffer, helper_->InsertToken());
|
| + yoffset += num_rows;
|
| + source += part_size;
|
| + height -= num_rows;
|
| + }
|
| + } else {
|
| + // Transfer by sub rows. Beacuse GL has no maximum texture dimensions.
|
| + GLsizeiptr element_size = GLES2Util::ComputeImageDataSize(
|
| + 1, 1, format, type, unpack_alignment_);
|
| + max_size -= max_size % element_size;
|
| + GLint max_sub_row_pixels = max_size / element_size;
|
| + for (; height; --height) {
|
| + GLint temp_width = width;
|
| + GLint temp_xoffset = xoffset;
|
| + const int8* row_source = source;
|
| + while (temp_width) {
|
| + GLint num_pixels = std::min(width, max_sub_row_pixels);
|
| + GLsizeiptr part_size = num_pixels * element_size;
|
| + void* buffer = transfer_buffer_.Alloc(part_size);
|
| + memcpy(buffer, row_source, part_size);
|
| + helper_->TexSubImage2D(
|
| + target, level, temp_xoffset, yoffset, temp_width, 1, format, type,
|
| + transfer_buffer_id_, transfer_buffer_.GetOffset(buffer));
|
| + transfer_buffer_.FreePendingToken(buffer, helper_->InsertToken());
|
| + row_source += part_size;
|
| + temp_xoffset += num_pixels;
|
| + temp_width -= num_pixels;
|
| + }
|
| + ++yoffset;
|
| + source += padded_row_size;
|
| + }
|
| + }
|
| }
|
|
|
|
|
|
|