summaryrefslogtreecommitdiffstats
path: root/o3d/core/cross/buffer.cc
diff options
context:
space:
mode:
Diffstat (limited to 'o3d/core/cross/buffer.cc')
-rw-r--r--o3d/core/cross/buffer.cc620
1 files changed, 0 insertions, 620 deletions
diff --git a/o3d/core/cross/buffer.cc b/o3d/core/cross/buffer.cc
deleted file mode 100644
index d1d075a..0000000
--- a/o3d/core/cross/buffer.cc
+++ /dev/null
@@ -1,620 +0,0 @@
-/*
- * Copyright 2009, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-
-// This file contains the definitions of Buffer, VertexBuffer and IndexBuffer.
-
-#include "core/cross/buffer.h"
-#include "core/cross/client_info.h"
-#include "core/cross/pointer_utils.h"
-#include "core/cross/renderer.h"
-#include "core/cross/features.h"
-#include "core/cross/error.h"
-#include "import/cross/memory_stream.h"
-#include "import/cross/raw_data.h"
-
-namespace o3d {
-
-O3D_DEFN_CLASS(Buffer, NamedObject);
-O3D_DEFN_CLASS(VertexBufferBase, Buffer);
-O3D_DEFN_CLASS(VertexBuffer, VertexBufferBase);
-O3D_DEFN_CLASS(SourceBuffer, VertexBufferBase);
-O3D_DEFN_CLASS(IndexBuffer, Buffer);
-
-const char *Buffer::kSerializationID = "BUFF";
-
-namespace {
-
-// Copies a field.
-// Parameters:
-// source: address of source data.
-// source_stride: amount to step for each element in the source.
-// field_size: size of field in bytes.
-// num_elements: number of elements to copy.
-// destination: address of destination data.
-// destination_stride: amount to step for each element in the destination.
-void CopyField(const void* source,
- size_t source_stride,
- size_t field_size,
- size_t num_elements,
- void* destination,
- size_t destination_stride) {
- while (num_elements) {
- memcpy(destination, source, field_size);
- source = AddPointerOffset(source, source_stride);
- destination = AddPointerOffset(destination, destination_stride);
- --num_elements;
- }
-}
-
-typedef Field::Ref (*FieldCreatorFunc)(ServiceLocator* service_locator,
- Buffer* buffer,
- unsigned num_components,
- unsigned offset);
-
-struct FieldCreator {
- const ObjectBase::Class* field_type;
- FieldCreatorFunc create_function;
- unsigned required_component_multiple;
-};
-static FieldCreator g_creators[] = {
- { FloatField::GetApparentClass(), FloatField::Create,
- FloatField::kRequiredComponentMultiple, },
- { UInt32Field::GetApparentClass(), UInt32Field::Create,
- UInt32Field::kRequiredComponentMultiple, },
- { UByteNField::GetApparentClass(), UByteNField::Create,
- UByteNField::kRequiredComponentMultiple, },
-};
-
-} // anonymouse namespace.
-
-// Buffer ---------------
-Buffer::Buffer(ServiceLocator* service_locator)
- : NamedObject(service_locator),
- features_(service_locator->GetService<Features>()),
- field_change_count_(0),
- total_components_(0),
- stride_(0),
- num_elements_(0),
- access_mode_(NONE),
- lock_count_(0) {
-}
-
-Buffer::~Buffer() {
- AdjustBufferMemoryInfo(false);
- for (unsigned ii = 0; ii < fields_.size(); ++ii) {
- if (!fields_[ii].IsNull()) {
- fields_[ii]->ClearBuffer();
- }
- }
-}
-
-void Buffer::AdjustBufferMemoryInfo(bool add) {
- // Only count VRAM/hardware buffers.
- if (IsA(VertexBuffer::GetApparentClass()) ||
- IsA(IndexBuffer::GetApparentClass())) {
- size_t size_in_bytes = num_elements_ * stride_;
- ClientInfoManager* client_info_manager =
- service_locator()->GetService<ClientInfoManager>();
- client_info_manager->AdjustBufferMemoryUsed(
- static_cast<int>(size_in_bytes) * (add ? 1 : -1));
- }
-}
-
-bool Buffer::AllocateElements(unsigned num_elements) {
- if (access_mode_ != NONE) {
- O3D_ERROR(service_locator()) << "Attempt to allocate locked Buffer '"
- << name() << "'";
- return false;
- }
-
- if (stride_ == 0) {
- O3D_ERROR(service_locator())
- << "No fields have been set on Buffer '" << name() << "'";
- return false;
- }
-
- if (num_elements > MAX_SMALL_INDEX && !features_->large_geometry()) {
- O3D_ERROR(service_locator())
- << "You can not allocate more then " << MAX_SMALL_INDEX
- << " elements in a buffer unless "
- << "you request support for large geometry when you "
- << "initialize O3D.";
- return false;
- }
-
- if (num_elements > MAX_LARGE_INDEX) {
- O3D_ERROR(service_locator())
- << "The maximum number of elements in a buffer is " << MAX_LARGE_INDEX
- << ".";
- return false;
- }
-
- size_t size_in_bytes = num_elements * stride_;
- // Check for size_t overflow.
- if (size_in_bytes / stride_ != num_elements) {
- O3D_ERROR(service_locator())
- << "Attempt to allocate too many elements for the current set of "
- << "fields on buffer.";
- return false;
- }
-
- if (size_in_bytes == 0) {
- O3D_ERROR(service_locator())
- << "Attempt to allocate zero bytes for Buffer '" << name() << "'";
- return false;
- }
-
- bool success = true;
- if (!ConcreteAllocate(size_in_bytes)) {
- num_elements = 0;
- size_in_bytes = 0;
- success = false;
- }
-
- num_elements_ = num_elements;
-
- AdjustBufferMemoryInfo(true);
-
- return success;
-}
-
-void Buffer::Free() {
- if (num_elements_ > 0) {
- ConcreteFree();
- AdjustBufferMemoryInfo(false);
- num_elements_ = 0;
- }
-}
-
-bool Buffer::ReshuffleBuffer(unsigned int new_stride, Field* field_to_remove) {
- if (new_stride == 0) {
- AdjustBufferMemoryInfo(false);
- ConcreteFree();
- stride_ = 0;
- return true;
- }
- if (num_elements_) {
- size_t size_in_bytes = num_elements_ * new_stride;
- // Check for size_t overflow.
- if (size_in_bytes / new_stride != num_elements_) {
- O3D_ERROR(service_locator())
- << "Attempt to allocate too many elements for the current set of "
- << "fields on buffer.";
- return false;
- }
- std::vector<uint8> temp(size_in_bytes);
-
- // Copy old fields into new buffer.
- {
- BufferLockHelper helper(this);
- void* source = helper.GetData(Buffer::READ_ONLY);
- if (!source) {
- return false;
- }
- unsigned int offset = 0;
- for (unsigned ii = 0; ii < fields_.size(); ++ii) {
- Field* field = fields_[ii].Get();
- if (field != field_to_remove) {
- CopyField(PointerFromVoidPointer<void*>(source, field->offset()),
- stride_,
- field->size(),
- num_elements_,
- PointerFromVoidPointer<void*>(&temp[0], offset),
- new_stride);
- field->set_offset(offset);
- offset += field->size();
- }
- }
- }
- // Copy the reorganized data into a new buffer.
- {
- ConcreteFree();
- AdjustBufferMemoryInfo(false);
- if (!ConcreteAllocate(size_in_bytes)) {
- num_elements_ = 0;
- O3D_ERROR(service_locator())
- << "Couldn't allocate buffer of size: " << size_in_bytes
- << " for Buffer '" << name() << "'";
- return false;
- }
- // stride_ must be set before GetData is called so that the proper size
- // buffer is allocated. We also need to set it after this function is
- // is completed (see CreateField, RemoveField) for when we create a new
- // buffer with no fields yet.
- stride_ = new_stride;
- AdjustBufferMemoryInfo(true);
- BufferLockHelper helper(this);
- void* destination = helper.GetData(Buffer::WRITE_ONLY);
- if (!destination) {
- return false;
- }
- memcpy(destination, &temp[0], size_in_bytes);
- }
- }
- return true;
-}
-
-Field* Buffer::CreateFieldByClassName(const String& field_type,
- unsigned num_components) {
- for (unsigned ii = 0; ii < arraysize(g_creators); ++ii) {
- if (!field_type.compare(g_creators[ii].field_type->name()) ||
- !field_type.compare(g_creators[ii].field_type->unqualified_name())) {
- return CreateField(g_creators[ii].field_type, num_components);
- }
- }
-
- O3D_ERROR(service_locator())
- << "unrecognized field type '" << field_type << "'";
- return NULL;
-}
-
-Field* Buffer::CreateField(const ObjectBase::Class* field_type,
- unsigned num_components) {
- FieldCreator* creator = NULL;
- for (unsigned ii = 0; ii < arraysize(g_creators); ++ii) {
- if (g_creators[ii].field_type == field_type) {
- creator = &g_creators[ii];
- break;
- }
- }
-
- if (!creator) {
- O3D_ERROR(service_locator())
- << "unrecognized field type '"
- << (field_type ? field_type->name() : "NULL") << "'";
- return NULL;
- }
-
- if (num_components == 0) {
- O3D_ERROR(service_locator())
- << "num components must be > 0 for Buffer '" << name() << "'";
- return NULL;
- }
-
- if (num_components % creator->required_component_multiple != 0) {
- O3D_ERROR(service_locator())
- << "num components must be a multiple of "
- << creator->required_component_multiple
- << " for fields of type " << field_type->unqualified_name();
- return NULL;
- }
-
- Field::Ref field = creator->create_function(service_locator(), this,
- num_components, stride_);
- unsigned int new_stride = stride_ + field->size();
- ReshuffleBuffer(new_stride, NULL);
-
- fields_.push_back(field);
- stride_ = new_stride;
- total_components_ += num_components;
- ++field_change_count_;
-
- return field;
-}
-
-void Buffer::RemoveField(Field* field) {
- for (unsigned ii = 0; ii < fields_.size(); ++ii) {
- if (fields_[ii] == field) {
- unsigned int new_stride = stride_ - field->size();
- ReshuffleBuffer(new_stride, field);
- total_components_ -= field->num_components();
- stride_ = new_stride;
- field->ClearBuffer();
- // This erase may remove the last reference to the field so field may
- // be invalid after this line.
- fields_.erase(fields_.begin() + ii);
- ++field_change_count_;
- return;
- }
- }
- O3D_ERROR(service_locator())
- << "Field '" << field->name()
- << "' does not exist on Buffer '" << name() << "'";
-}
-
-bool Buffer::Lock(AccessMode access_mode, void** buffer_data) {
- if (access_mode == NONE) {
- O3D_ERROR(service_locator())
- << "attempt to lock Buffer '" << name()
- << "' with access mode NONE";
- return false;
- }
- if (access_mode_ == NONE || access_mode == access_mode_) {
- if (lock_count_ == 0) {
- if (!ConcreteLock(access_mode, &locked_data_)) {
- return false;
- }
- }
- ++lock_count_;
- *buffer_data = locked_data_;
- return true;
- } else {
- O3D_ERROR(service_locator())
- << "attempt to lock already locked Buffer '" << name()
- << "' with different access mode";
- return false;
- }
-}
-
-bool Buffer::Unlock() {
- if (lock_count_ == 0) {
- O3D_ERROR(service_locator())
- << "attempt to unlock unlocked Buffer '" << name() << "'";
- return false;
- }
- --lock_count_;
- if (lock_count_ == 0) {
- return ConcreteUnlock();
- }
- return true;
-}
-
-bool Buffer::Set(o3d::RawData *raw_data) {
- DCHECK(raw_data);
- return Set(raw_data, 0, raw_data->GetLength());
-}
-
-bool Buffer::Set(o3d::RawData *raw_data,
- size_t offset,
- size_t length) {
- DCHECK(raw_data);
-
- if (!raw_data->IsOffsetLengthValid(offset, length)) {
- O3D_ERROR(service_locator()) << "illegal buffer data offset or size";
- return false;
- }
-
- // GetData() returns NULL if it, for example, cannot open the temporary data
- // file. In that case, it invokes the error callback. We just have to be
- // careful not to dereference it.
- const uint8 *data = raw_data->GetDataAs<uint8>(offset);
- if (!data) {
- return false;
- }
-
- MemoryReadStream stream(data, length);
-
- // Verify we at least have enough data for four-char kSerializationID plus
- // version and num_fields
- if (length < 4 + 2*sizeof(int32)) {
- O3D_ERROR(service_locator())
- << "data object does not contain buffer data";
- return false;
- }
-
- // To insure data integrity we expect four characters kSerializationID
- char id[5];
- stream.Read(id, 4);
- id[4] = 0; // null-terminate
-
- if (strcmp(id, kSerializationID)) {
- O3D_ERROR(service_locator())
- << "data object does not contain buffer data";
- return false;
- }
-
- int32 version = stream.ReadLittleEndianInt32();
- if (version != 1) {
- O3D_ERROR(service_locator()) << "unknown buffer data version";
- return false;
- }
-
- // Delete existing fields.
- // TODO: Since this removes all fields, there is no need to
- // reshuffle (which can be expensive). We could provide a RemoveAllFields
- // and call it here.
- while (fields_.size() > 0) {
- RemoveField(fields_[0]);
- }
-
- // Create fields.
- int32 num_fields = stream.ReadLittleEndianInt32();
- for (int32 ff = 0; ff < num_fields; ++ff) {
- if (stream.GetRemainingByteCount() < 2*sizeof(uint8)) {
- O3D_ERROR(service_locator()) << "unexpected end of buffer data";
- return false;
- }
-
- uint8 field_id = stream.ReadByte();
- uint8 num_components = stream.ReadByte();
-
- const ObjectBase::Class *field_type;
-
- switch (field_id) {
- case Field::FIELDID_FLOAT32:
- field_type = FloatField::GetApparentClass();
- break;
- case Field::FIELDID_UINT32:
- field_type = UInt32Field::GetApparentClass();
- break;
- case Field::FIELDID_BYTE:
- field_type = UByteNField::GetApparentClass();
- break;
-
- case Field::FIELDID_UNKNOWN:
- default:
- O3D_ERROR(service_locator()) << "unknown field_type";
- return false;
- }
-
- Field* field = CreateField(field_type, num_components);
- if (!field) {
- O3D_ERROR(service_locator()) << "couldn't create field";
- return false;
- }
- }
-
- // Read the number of elements and allocate space
- if (stream.GetRemainingByteCount() < sizeof(int32)) {
- O3D_ERROR(service_locator()) << "unexpected end of buffer data";
- return false;
- }
- int32 num_elements = stream.ReadLittleEndianInt32();
- if (!AllocateElements(num_elements)) {
- O3D_ERROR(service_locator()) << "could not allocate buffer elements";
- return false;
- }
-
- {
- // Lock before reading in all the fields to avoid locking/unlocking
- // for each field which would be slower
- o3d::BufferLockHelper helper(this);
- helper.GetData(o3d::Buffer::WRITE_ONLY);
-
- // Read each field
- for (int32 ff = 0; ff < num_fields; ++ff) {
- Field *field = fields()[ff];
- if (!field->SetFromMemoryStream(&stream)) {
- O3D_ERROR(service_locator()) <<
- "unexpected end of buffer field data";
- return false;
- }
- }
- }
-
- // Final integrity check that we consumed exactly the correct amount of data
- if (stream.GetRemainingByteCount() != 0) {
- O3D_ERROR(service_locator()) << "extra buffer data remaining";
- return false;
- }
-
- return true;
-}
-
-VertexBufferBase::VertexBufferBase(ServiceLocator* service_locator)
- : Buffer(service_locator) {
-}
-
-VertexBuffer::VertexBuffer(ServiceLocator* service_locator)
- : VertexBufferBase(service_locator) {
-}
-
-ObjectBase::Ref VertexBuffer::Create(ServiceLocator* service_locator) {
- Renderer* renderer = service_locator->GetService<Renderer>();
- if (NULL == renderer) {
- O3D_ERROR(service_locator) << "No Render Device Available";
- return ObjectBase::Ref();
- }
- return ObjectBase::Ref(renderer->CreateVertexBuffer());
-}
-
-SourceBuffer::SourceBuffer(ServiceLocator* service_locator)
- : VertexBufferBase(service_locator),
- buffer_() {
-}
-
-SourceBuffer::~SourceBuffer() {
- ConcreteFree();
-}
-
-void SourceBuffer::ConcreteFree() {
- buffer_.reset();
-}
-
-bool SourceBuffer::ConcreteAllocate(size_t size_in_bytes) {
- ConcreteFree();
-
- buffer_.reset(new char[size_in_bytes]);
-
- return true;
-}
-
-bool SourceBuffer::ConcreteLock(AccessMode access_mode, void **buffer_data) {
- if (!buffer_.get()) {
- return false;
- }
-
- *buffer_data = reinterpret_cast<void*>(buffer_.get());
- return true;
-}
-
-bool SourceBuffer::ConcreteUnlock() {
- return buffer_.get() != NULL;
-}
-
-ObjectBase::Ref SourceBuffer::Create(ServiceLocator* service_locator) {
- return ObjectBase::Ref(new SourceBuffer(service_locator));
-}
-
-Field* IndexBuffer::index_field() const {
- // TODO: It does not make sense for an IndexBuffer to have more
- // than one field. For example, we do not support any way of rendering a
- // primitive using only one of the fields of an IndexBuffer. The API allows
- // you to create any number of fields for Buffers in general. That may not be
- // the best design. This code verifies that there are not multiple fields
- // on the IndexBuffer. It also checks for the case where there are no fields
- // to prevent a crash. This function can be called from JavaScript. It
- // should never crash. It is okay for an IndexBuffer to temporarily contain
- // no fields. This is is used by Buffer::Set(). I added a DCHECK for debug
- // builds.
- DCHECK(fields().size() == 1);
- return fields().size() == 1 ? fields()[0].Get() : NULL;
-}
-
-IndexBuffer::IndexBuffer(ServiceLocator* service_locator)
- : Buffer(service_locator) {
- CreateField(UInt32Field::GetApparentClass(), 1);
-}
-
-ObjectBase::Ref IndexBuffer::Create(ServiceLocator* service_locator) {
- Renderer* renderer = service_locator->GetService<Renderer>();
- if (NULL == renderer) {
- O3D_ERROR(service_locator) << "No Render Device Available";
- return ObjectBase::Ref();
- }
- return ObjectBase::Ref(renderer->CreateIndexBuffer());
-}
-
-BufferLockHelper::BufferLockHelper(Buffer* buffer)
- : buffer_(buffer),
- data_(NULL),
- locked_(false) {
-}
-
-BufferLockHelper::~BufferLockHelper() {
- if (locked_) {
- buffer_->Unlock();
- }
-}
-
-void* BufferLockHelper::GetData(Buffer::AccessMode access_mode) {
- if (!locked_) {
- locked_ = buffer_->Lock(access_mode, &data_);
- if (!locked_) {
- O3D_ERROR(buffer_->service_locator())
- << "Unable to lock buffer '" << buffer_->name() << "'";
- }
- }
- return data_;
-}
-
-} // namespace o3d