blob: 1208a574eba885b98b909e83aec194924edad029 [file] [log] [blame]
// Copyright (c) 2006-2009 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.
// A class to emluate GLES2 over command buffers.
#include "gpu/command_buffer/client/gles2_implementation.h"
// TODO(gman): remove when all functions have been implemented.
#include "gpu/command_buffer/client/gles2_implementation_gen.h"
#include "gpu/command_buffer/common/gles2_cmd_utils.h"
namespace command_buffer {
namespace gles2 {
GLES2Implementation::GLES2Implementation(
GLES2CmdHelper* helper,
size_t transfer_buffer_size,
void* transfer_buffer,
int32 transfer_buffer_id)
: util_(0), // TODO(gman): Get real number of compressed texture formats.
helper_(helper),
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) {
for (GLsizei ii = 0; ii < n; ++ii) {
ids[ii] = id_allocator_.AllocateID();
}
}
void GLES2Implementation::FreeIds(GLsizei n, const GLuint* ids) {
for (GLsizei ii = 0; ii < n; ++ii) {
id_allocator_.FreeID(ids[ii]);
}
}
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) {
helper_->VertexAttribPointer(index, size, type, normalized, stride,
reinterpret_cast<GLuint>(ptr));
}
void GLES2Implementation::ShaderSource(
GLuint shader, GLsizei count, const char** source, const GLint* length) {
// TODO(gman): change to use buckets and check that there is enough room.
// 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(source[ii]);
memcpy(strings + offset, source[ii], len);
offset += len;
offsets[ii] = offset;
}
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) {
// 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) {
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 image_size, const void* data) {
// TODO(gman): Switch to use buckets alwayst or at least if no room in shared
// memory.
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, 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 image_size, const void* data) {
// TODO(gman): Switch to use buckets alwayst or at least if no room in shared
// memory.
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, 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) {
helper_->TexImage2D(
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) {
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;
}
}
}
} // namespace gles2
} // namespace command_buffer