blob: f5819696c08a14ca1ade01bb371f8a439cf36e9f [file] [log] [blame]
//
// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// IndexBuffer.cpp: Defines the abstract IndexBuffer class and IndexBufferInterface
// class with derivations, classes that perform graphics API agnostic index buffer operations.
#include "libGLESv2/renderer/IndexBuffer.h"
#include "libGLESv2/renderer/Renderer9.h"
namespace rx
{
unsigned int IndexBufferInterface::mCurrentSerial = 1;
IndexBufferInterface::IndexBufferInterface(rx::Renderer9 *renderer, UINT size, D3DFORMAT format) : mRenderer(renderer), mBufferSize(size), mIndexBuffer(NULL)
{
if (size > 0)
{
// D3D9_REPLACE
HRESULT result = mRenderer->createIndexBuffer(size, D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, format, &mIndexBuffer);
mSerial = issueSerial();
if (FAILED(result))
{
ERR("Out of memory allocating an index buffer of size %lu.", size);
}
}
}
IndexBufferInterface::~IndexBufferInterface()
{
if (mIndexBuffer)
{
mIndexBuffer->Release();
}
}
IDirect3DIndexBuffer9 *IndexBufferInterface::getBuffer() const
{
return mIndexBuffer;
}
unsigned int IndexBufferInterface::getSerial() const
{
return mSerial;
}
unsigned int IndexBufferInterface::issueSerial()
{
return mCurrentSerial++;
}
void IndexBufferInterface::unmap()
{
if (mIndexBuffer)
{
mIndexBuffer->Unlock();
}
}
StreamingIndexBufferInterface::StreamingIndexBufferInterface(rx::Renderer9 *renderer, UINT initialSize, D3DFORMAT format) : IndexBufferInterface(renderer, initialSize, format)
{
mWritePosition = 0;
}
StreamingIndexBufferInterface::~StreamingIndexBufferInterface()
{
}
void *StreamingIndexBufferInterface::map(UINT requiredSpace, UINT *offset)
{
void *mapPtr = NULL;
if (mIndexBuffer)
{
HRESULT result = mIndexBuffer->Lock(mWritePosition, requiredSpace, &mapPtr, D3DLOCK_NOOVERWRITE);
if (FAILED(result))
{
ERR(" Lock failed with error 0x%08x", result);
return NULL;
}
*offset = mWritePosition;
mWritePosition += requiredSpace;
}
return mapPtr;
}
void StreamingIndexBufferInterface::reserveSpace(UINT requiredSpace, GLenum type)
{
if (requiredSpace > mBufferSize)
{
if (mIndexBuffer)
{
mIndexBuffer->Release();
mIndexBuffer = NULL;
}
mBufferSize = std::max(requiredSpace, 2 * mBufferSize);
// D3D9_REPLACE
HRESULT result = mRenderer->createIndexBuffer(mBufferSize, D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, type == GL_UNSIGNED_INT ? D3DFMT_INDEX32 : D3DFMT_INDEX16, &mIndexBuffer);
mSerial = issueSerial();
if (FAILED(result))
{
ERR("Out of memory allocating a vertex buffer of size %lu.", mBufferSize);
}
mWritePosition = 0;
}
else if (mWritePosition + requiredSpace > mBufferSize) // Recycle
{
void *dummy;
mIndexBuffer->Lock(0, 1, &dummy, D3DLOCK_DISCARD);
mIndexBuffer->Unlock();
mWritePosition = 0;
}
}
StaticIndexBufferInterface::StaticIndexBufferInterface(rx::Renderer9 *renderer) : IndexBufferInterface(renderer, 0, D3DFMT_UNKNOWN)
{
mCacheType = GL_NONE;
}
StaticIndexBufferInterface::~StaticIndexBufferInterface()
{
}
void *StaticIndexBufferInterface::map(UINT requiredSpace, UINT *offset)
{
void *mapPtr = NULL;
if (mIndexBuffer)
{
HRESULT result = mIndexBuffer->Lock(0, requiredSpace, &mapPtr, 0);
if (FAILED(result))
{
ERR(" Lock failed with error 0x%08x", result);
return NULL;
}
*offset = 0;
}
return mapPtr;
}
void StaticIndexBufferInterface::reserveSpace(UINT requiredSpace, GLenum type)
{
if (!mIndexBuffer && mBufferSize == 0)
{
// D3D9_REPLACE
HRESULT result = mRenderer->createIndexBuffer(requiredSpace, D3DUSAGE_WRITEONLY, type == GL_UNSIGNED_INT ? D3DFMT_INDEX32 : D3DFMT_INDEX16, &mIndexBuffer);
mSerial = issueSerial();
if (FAILED(result))
{
ERR("Out of memory allocating a vertex buffer of size %lu.", mBufferSize);
}
mBufferSize = requiredSpace;
mCacheType = type;
}
else if (mIndexBuffer && mBufferSize >= requiredSpace && mCacheType == type)
{
// Already allocated
}
else UNREACHABLE(); // Static index buffers can't be resized
}
bool StaticIndexBufferInterface::lookupType(GLenum type)
{
return mCacheType == type;
}
UINT StaticIndexBufferInterface::lookupRange(intptr_t offset, GLsizei count, UINT *minIndex, UINT *maxIndex)
{
IndexRange range = {offset, count};
std::map<IndexRange, IndexResult>::iterator res = mCache.find(range);
if (res == mCache.end())
{
return -1;
}
*minIndex = res->second.minIndex;
*maxIndex = res->second.maxIndex;
return res->second.streamOffset;
}
void StaticIndexBufferInterface::addRange(intptr_t offset, GLsizei count, UINT minIndex, UINT maxIndex, UINT streamOffset)
{
IndexRange indexRange = {offset, count};
IndexResult indexResult = {minIndex, maxIndex, streamOffset};
mCache[indexRange] = indexResult;
}
}