Skip to content

Commit

Permalink
Changes the GLES2Implementation to use a RingBuffer
Browse files Browse the repository at this point in the history
to manage the transfer buffer.  This is significantly
faster than the FencedAllocator for our purposes.

TEST=some unit tests
BUG=none

Review URL: http://codereview.chromium.org/1796002

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@45844 0039d316-1c4b-4281-b951-d872f2087c98
  • Loading branch information
gman@chromium.org committed Apr 28, 2010
1 parent ec11be6 commit f6a5698
Show file tree
Hide file tree
Showing 6 changed files with 576 additions and 18 deletions.
17 changes: 10 additions & 7 deletions gpu/command_buffer/client/gles2_implementation.cc
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,11 @@ GLES2Implementation::GLES2Implementation(
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_(
kStartingOffset,
transfer_buffer_size - kStartingOffset,
helper,
static_cast<char*>(transfer_buffer) + kStartingOffset),
transfer_buffer_id_(transfer_buffer_id),
pack_alignment_(4),
unpack_alignment_(4),
Expand All @@ -344,8 +348,8 @@ GLES2Implementation::GLES2Implementation(
#endif
error_bits_(0) {
// Allocate space for simple GL results.
result_buffer_ = transfer_buffer_.Alloc(kMaxSizeOfSimpleResult);
result_shm_offset_ = transfer_buffer_.GetOffset(result_buffer_);
result_buffer_ = transfer_buffer;
result_shm_offset_ = 0;

#if defined(GLES2_SUPPORT_CLIENT_SIDE_BUFFERS)
GLint max_vertex_attribs;
Expand All @@ -366,7 +370,6 @@ GLES2Implementation::GLES2Implementation(
GLES2Implementation::~GLES2Implementation() {
GLuint buffers[] = { kClientSideArrayId, kClientSideElementArrayId, };
DeleteBuffers(arraysize(buffers), &buffers[0]);
transfer_buffer_.Free(result_buffer_);
}

void GLES2Implementation::MakeIds(
Expand Down Expand Up @@ -440,7 +443,7 @@ void GLES2Implementation::GetBucketContents(uint32 bucket_id,
transfer_buffer_id_, transfer_buffer_.GetOffset(buffer));
WaitForCmd();
memcpy(&(*data)[offset], buffer, part_size);
transfer_buffer_.Free(buffer);
transfer_buffer_.FreePendingToken(buffer, helper_->InsertToken());
offset += part_size;
size -= part_size;
}
Expand Down Expand Up @@ -1140,7 +1143,7 @@ void GLES2Implementation::ReadPixels(
dest += padded_row_size;
src += padded_row_size;
}
transfer_buffer_.Free(buffer);
transfer_buffer_.FreePendingToken(buffer, helper_->InsertToken());
yoffset += num_rows;
height -= num_rows;
}
Expand Down Expand Up @@ -1170,7 +1173,7 @@ void GLES2Implementation::ReadPixels(
return;
}
memcpy(row_dest, buffer, part_size);
transfer_buffer_.Free(buffer);
transfer_buffer_.FreePendingToken(buffer, helper_->InsertToken());
row_dest += part_size;
temp_xoffset += num_pixels;
temp_width -= num_pixels;
Expand Down
23 changes: 12 additions & 11 deletions gpu/command_buffer/client/gles2_implementation.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
#include "../common/scoped_ptr.h"
#include "../client/gles2_cmd_helper.h"
#include "../client/id_allocator.h"
#include "../client/fenced_allocator.h"
#include "../client/ring_buffer.h"

#define GLES2_SUPPORT_CLIENT_SIDE_BUFFERS 1

Expand Down Expand Up @@ -139,25 +139,26 @@ class GLES2Implementation {
}

private:
// Wraps FencedAllocatorWrapper to provide aligned allocations.
class AlignedFencedAllocator : public FencedAllocatorWrapper {
// Wraps RingBufferWrapper to provide aligned allocations.
class AlignedRingBuffer : public RingBufferWrapper {
public:
AlignedFencedAllocator(unsigned int size,
CommandBufferHelper *helper,
void *base)
: FencedAllocatorWrapper(size, helper, base) {
AlignedRingBuffer(RingBuffer::Offset base_offset,
unsigned int size,
CommandBufferHelper *helper,
void *base)
: RingBufferWrapper(base_offset, size, helper, base) {
}

static unsigned int RoundToAlignment(unsigned int size) {
return (size + kAlignment - 1) & ~(kAlignment - 1);
}

// Overrriden from FencedAllocatorWrapper
// Overrriden from RingBufferWrapper
void *Alloc(unsigned int size) {
return FencedAllocatorWrapper::Alloc(RoundToAlignment(size));
return RingBufferWrapper::Alloc(RoundToAlignment(size));
}

// Overrriden from FencedAllocatorWrapper
// Overrriden from RingBufferWrapper
template <typename T> T *AllocTyped(unsigned int count) {
return static_cast<T *>(Alloc(count * sizeof(T)));
}
Expand Down Expand Up @@ -230,7 +231,7 @@ class GLES2Implementation {
IdAllocator renderbuffer_id_allocator_;
IdAllocator program_and_shader_id_allocator_;
IdAllocator texture_id_allocator_;
AlignedFencedAllocator transfer_buffer_;
AlignedRingBuffer transfer_buffer_;
int transfer_buffer_id_;
void* result_buffer_;
uint32 result_shm_offset_;
Expand Down
103 changes: 103 additions & 0 deletions gpu/command_buffer/client/ring_buffer.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
// Copyright (c) 2010 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.

// This file contains the implementation of the RingBuffer class.

#include "../client/ring_buffer.h"
#include <algorithm>
#include "../client/cmd_buffer_helper.h"

namespace gpu {

RingBuffer::RingBuffer(
Offset base_offset, unsigned int size, CommandBufferHelper* helper)
: helper_(helper),
base_offset_(base_offset),
size_(size),
free_offset_(0),
in_use_offset_(0) {
}

RingBuffer::~RingBuffer() {
// Free blocks pending tokens.
while (!blocks_.empty()) {
FreeOldestBlock();
}
}

void RingBuffer::FreeOldestBlock() {
DCHECK(!blocks_.empty()) << "no free blocks";
Block& block = blocks_.front();
DCHECK(block.valid) << "attempt to allocate more than maximum memory";
helper_->WaitForToken(block.token);
in_use_offset_ += block.size;
if (in_use_offset_ == size_) {
in_use_offset_ = 0;
}
// If they match then the entire buffer is free.
if (in_use_offset_ == free_offset_) {
in_use_offset_ = 0;
free_offset_ = 0;
}
blocks_.pop_back();
}

RingBuffer::Offset RingBuffer::Alloc(unsigned int size) {
DCHECK_LE(size, size_) << "attempt to allocate more than maximum memory";
// Similarly to malloc, an allocation of 0 allocates at least 1 byte, to
// return different pointers every time.
if (size == 0) size = 1;

// Wait until there is enough room.
while (size > GetLargestFreeSizeNoWaiting()) {
FreeOldestBlock();
}

Offset offset = free_offset_;
blocks_.push_back(Block(offset, size));
free_offset_ += size;
if (free_offset_ == size_) {
free_offset_ = 0;
}
return offset + base_offset_;
}

void RingBuffer::FreePendingToken(RingBuffer::Offset offset,
unsigned int token) {
offset -= base_offset_;
DCHECK(!blocks_.empty()) << "no allocations to free";
for (Container::reverse_iterator it = blocks_.rbegin();
it != blocks_.rend();
++it) {
Block& block = *it;
if (block.offset == offset) {
DCHECK(!block.valid) << "block that corresponds to offset already freed";
block.token = token;
block.valid = true;
return;
}
}
NOTREACHED() << "attempt to free non-existant block";
}

unsigned int RingBuffer::GetLargestFreeSizeNoWaiting() {
if (free_offset_ == in_use_offset_) {
if (blocks_.empty()) {
// The entire buffer is free.
DCHECK_EQ(free_offset_, 0u);
return size_;
} else {
// The entire buffer is in use.
return 0;
}
} else if (free_offset_ > in_use_offset_) {
// It's free from free_offset_ to size_
return size_ - free_offset_;
} else {
// It's free from free_offset_ -> in_use_offset_;
return in_use_offset_ - free_offset_;
}
}

} // namespace gpu
Loading

0 comments on commit f6a5698

Please sign in to comment.