rewrite buffers implementation to support static buffers more efficiently

Bug=89 Trac #13565 Signed-off-by: Daniel Koch Author: Nicolas Capens git-svn-id: https://angleproject.googlecode.com/svn/trunk@526 736b8ea6-26fd-11df-bfd4-992fa37f6226
parent d2fed1c7
......@@ -144,10 +144,6 @@
'common/angleutils.h',
'common/debug.cpp',
'common/debug.h',
'libGLESv2/geometry/backend.cpp',
'libGLESv2/geometry/backend.h',
'libGLESv2/geometry/dx9.cpp',
'libGLESv2/geometry/dx9.h',
'libGLESv2/geometry/IndexDataManager.cpp',
'libGLESv2/geometry/IndexDataManager.h',
'libGLESv2/geometry/vertexconversion.h',
......
......@@ -187,4 +187,3 @@ void TCompiler::collectAttribsUniforms(TIntermNode* root)
CollectAttribsUniforms collect(attribs, uniforms);
root->traverse(&collect);
}
......@@ -299,4 +299,4 @@ void TAllocation::checkAllocList() const
{
for (const TAllocation* alloc = this; alloc != 0; alloc = alloc->prevAlloc)
alloc->check();
}
}
\ No newline at end of file
......@@ -297,4 +297,4 @@ protected:
TPoolAllocator& allocator;
};
#endif // _POOLALLOC_INCLUDED_
#endif // _POOLALLOC_INCLUDED_
\ No newline at end of file
......@@ -101,4 +101,4 @@ private:
TCompiler* ConstructCompiler(ShShaderType type, ShShaderSpec spec);
void DeleteCompiler(TCompiler*);
#endif // _SHHANDLE_INCLUDED_
#endif // _SHHANDLE_INCLUDED_
\ No newline at end of file
......@@ -252,4 +252,3 @@ void ShGetActiveUniform(const ShHandle handle,
getVariableInfo(SH_ACTIVE_UNIFORMS,
handle, index, length, size, type, name);
}
......@@ -213,8 +213,6 @@ void Surface::writeRecordableFlipState(IDirect3DDevice9 *device)
device->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
device->SetFVF(D3DFVF_XYZRHW | D3DFVF_TEX1);
device->SetStreamSourceFreq(0, 1); // DrawPrimitiveUP only cares about stream 0, not the rest.
RECT scissorRect = {0}; // Scissoring is disabled for flipping, but we need this to capture and restore the old rectangle
device->SetScissorRect(&scissorRect);
D3DVIEWPORT9 viewport = {0, 0, mWidth, mHeight, 0.0f, 1.0f};
......
......@@ -466,11 +466,6 @@ void Blit::setCommonBlitState()
device->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
device->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
for (int i = 0; i < MAX_VERTEX_ATTRIBS+1; i++)
{
device->SetStreamSourceFreq(i, 1);
}
RECT scissorRect = {0}; // Scissoring is disabled for flipping, but we need this to capture and restore the old rectangle
device->SetScissorRect(&scissorRect);
}
......
......@@ -10,6 +10,10 @@
#include "libGLESv2/Buffer.h"
#include "libGLESv2/main.h"
#include "libGLESv2/geometry/VertexDataManager.h"
#include "libGLESv2/geometry/IndexDataManager.h"
namespace gl
{
......@@ -18,11 +22,16 @@ Buffer::Buffer(GLuint id) : RefCountObject(id)
mContents = NULL;
mSize = 0;
mUsage = GL_DYNAMIC_DRAW;
mVertexBuffer = NULL;
mIndexBuffer = NULL;
}
Buffer::~Buffer()
{
delete[] mContents;
delete mVertexBuffer;
delete mIndexBuffer;
}
void Buffer::bufferData(const void *data, GLsizeiptr size, GLenum usage)
......@@ -46,11 +55,49 @@ void Buffer::bufferData(const void *data, GLsizeiptr size, GLenum usage)
mSize = size;
mUsage = usage;
invalidateStaticData();
if (usage == GL_STATIC_DRAW)
{
mVertexBuffer = new StaticVertexBuffer(getDevice());
mIndexBuffer = new StaticIndexBuffer(getDevice());
}
}
void Buffer::bufferSubData(const void *data, GLsizeiptr size, GLintptr offset)
{
memcpy(mContents + offset, data, size);
if ((mVertexBuffer && mVertexBuffer->size() != 0) || (mIndexBuffer && mIndexBuffer->size() != 0))
{
invalidateStaticData();
if (mUsage == GL_STATIC_DRAW)
{
mVertexBuffer = new StaticVertexBuffer(getDevice());
mIndexBuffer = new StaticIndexBuffer(getDevice());
}
}
}
StaticVertexBuffer *Buffer::getVertexBuffer()
{
return mVertexBuffer;
}
StaticIndexBuffer *Buffer::getIndexBuffer()
{
return mIndexBuffer;
}
void Buffer::invalidateStaticData()
{
delete mVertexBuffer;
mVertexBuffer = NULL;
delete mIndexBuffer;
mIndexBuffer = NULL;
}
}
......@@ -22,6 +22,8 @@
namespace gl
{
class StaticVertexBuffer;
class StaticIndexBuffer;
class Buffer : public RefCountObject
{
......@@ -37,12 +39,19 @@ class Buffer : public RefCountObject
size_t size() const { return mSize; }
GLenum usage() const { return mUsage; }
StaticVertexBuffer *getVertexBuffer();
StaticIndexBuffer *getIndexBuffer();
void invalidateStaticData();
private:
DISALLOW_COPY_AND_ASSIGN(Buffer);
GLubyte *mContents;
size_t mSize;
GLenum mUsage;
StaticVertexBuffer *mVertexBuffer;
StaticIndexBuffer *mIndexBuffer;
};
}
......
......@@ -25,10 +25,8 @@
#include "libGLESv2/RenderBuffer.h"
#include "libGLESv2/Shader.h"
#include "libGLESv2/Texture.h"
#include "libGLESv2/geometry/backend.h"
#include "libGLESv2/geometry/VertexDataManager.h"
#include "libGLESv2/geometry/IndexDataManager.h"
#include "libGLESv2/geometry/dx9.h"
#undef near
#undef far
......@@ -139,7 +137,6 @@ Context::Context(const egl::Config *config, const gl::Context *shareContext)
mState.packAlignment = 4;
mState.unpackAlignment = 4;
mBufferBackEnd = NULL;
mVertexDataManager = NULL;
mIndexDataManager = NULL;
mBlit = NULL;
......@@ -212,7 +209,6 @@ Context::~Context()
mTexture2DZero.set(NULL);
mTextureCubeMapZero.set(NULL);
delete mBufferBackEnd;
delete mVertexDataManager;
delete mIndexDataManager;
delete mBlit;
......@@ -233,9 +229,8 @@ void Context::makeCurrent(egl::Display *display, egl::Surface *surface)
{
mDeviceCaps = display->getDeviceCaps();
mBufferBackEnd = new Dx9BackEnd(this, device);
mVertexDataManager = new VertexDataManager(this, mBufferBackEnd);
mIndexDataManager = new IndexDataManager(this, mBufferBackEnd);
mVertexDataManager = new VertexDataManager(this, device);
mIndexDataManager = new IndexDataManager(this, device);
mBlit = new Blit(this);
mSupportsShaderModel3 = mDeviceCaps.PixelShaderVersion == D3DPS_VERSION(3, 0);
......@@ -281,6 +276,8 @@ void Context::makeCurrent(egl::Display *display, egl::Surface *surface)
mSupportsLuminanceTextures = display->getLuminanceTextureSupport();
mSupportsLuminanceAlphaTextures = display->getLuminanceAlphaTextureSupport();
mSupports32bitIndices = mDeviceCaps.MaxVertexIndex >= (1 << 16);
initExtensionString();
mState.viewportX = 0;
......@@ -339,11 +336,6 @@ void Context::markAllStateDirty()
mSampleStateDirty = true;
mDitherStateDirty = true;
mFrontFaceDirty = true;
if (mBufferBackEnd != NULL)
{
mBufferBackEnd->invalidate();
}
}
void Context::setClearColor(float red, float green, float blue, float alpha)
......@@ -743,12 +735,12 @@ GLuint Context::getArrayBufferHandle() const
return mState.arrayBuffer.id();
}
void Context::setVertexAttribEnabled(unsigned int attribNum, bool enabled)
void Context::setEnableVertexAttribArray(unsigned int attribNum, bool enabled)
{
mState.vertexAttribute[attribNum].mEnabled = enabled;
mState.vertexAttribute[attribNum].mArrayEnabled = enabled;
}
const AttributeState &Context::getVertexAttribState(unsigned int attribNum)
const VertexAttribute &Context::getVertexAttribState(unsigned int attribNum)
{
return mState.vertexAttribute[attribNum];
}
......@@ -769,8 +761,7 @@ const void *Context::getVertexAttribPointer(unsigned int attribNum) const
return mState.vertexAttribute[attribNum].mPointer;
}
// returns entire set of attributes as a block
const AttributeState *Context::getVertexAttribBlock()
const VertexAttributeArray &Context::getVertexAttributes()
{
return mState.vertexAttribute;
}
......@@ -1963,18 +1954,18 @@ void Context::lookupAttributeMapping(TranslatedAttribute *attributes)
{
for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
{
if (attributes[i].enabled)
if (attributes[i].active)
{
attributes[i].semanticIndex = getCurrentProgram()->getSemanticIndex(i);
}
}
}
GLenum Context::applyVertexBuffer(GLenum mode, GLint first, GLsizei count, bool *useIndexing, TranslatedIndexData *indexInfo)
GLenum Context::applyVertexBuffer(GLint first, GLsizei count)
{
TranslatedAttribute translated[MAX_VERTEX_ATTRIBS];
GLenum err = mVertexDataManager->preRenderValidate(first, count, translated);
GLenum err = mVertexDataManager->prepareVertexData(first, count, translated);
if (err != GL_NO_ERROR)
{
return err;
......@@ -1982,53 +1973,20 @@ GLenum Context::applyVertexBuffer(GLenum mode, GLint first, GLsizei count, bool
lookupAttributeMapping(translated);
mBufferBackEnd->setupAttributesPreDraw(translated);
for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
{
if (translated[i].enabled && translated[i].nonArray)
{
err = mIndexDataManager->preRenderValidateUnindexed(mode, count, indexInfo);
if (err != GL_NO_ERROR)
{
return err;
}
mVertexDataManager->setupAttributes(translated);
mBufferBackEnd->setupIndicesPreDraw(*indexInfo);
*useIndexing = true;
return GL_NO_ERROR;
}
}
*useIndexing = false;
return GL_NO_ERROR;
}
GLenum Context::applyVertexBuffer(const TranslatedIndexData &indexInfo)
{
TranslatedAttribute translated[MAX_VERTEX_ATTRIBS];
GLenum err = mVertexDataManager->preRenderValidate(indexInfo.minIndex, indexInfo.maxIndex-indexInfo.minIndex+1, translated);
if (err == GL_NO_ERROR)
{
lookupAttributeMapping(translated);
mBufferBackEnd->setupAttributesPreDraw(translated);
}
return err;
}
// Applies the indices and element array bindings to the Direct3D 9 device
GLenum Context::applyIndexBuffer(const void *indices, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo)
{
GLenum err = mIndexDataManager->preRenderValidate(mode, type, count, mState.elementArrayBuffer.get(), indices, indexInfo);
IDirect3DDevice9 *device = getDevice();
GLenum err = mIndexDataManager->prepareIndexData(type, count, mState.elementArrayBuffer.get(), indices, indexInfo);
if (err == GL_NO_ERROR)
{
mBufferBackEnd->setupIndicesPreDraw(*indexInfo);
device->SetIndices(indexInfo->indexBuffer);
}
return err;
......@@ -2486,7 +2444,6 @@ void Context::clear(GLbitfield mask)
device->SetPixelShader(NULL);
device->SetVertexShader(NULL);
device->SetFVF(D3DFVF_XYZRHW | D3DFVF_DIFFUSE);
device->SetStreamSourceFreq(0, 1);
device->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_DISABLE);
hr = device->EndStateBlock(&mMaskedClearSavedState);
......@@ -2542,7 +2499,6 @@ void Context::clear(GLbitfield mask)
device->SetPixelShader(NULL);
device->SetVertexShader(NULL);
device->SetFVF(D3DFVF_XYZRHW | D3DFVF_DIFFUSE);
device->SetStreamSourceFreq(0, 1);
device->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_DISABLE);
struct Vertex
......@@ -2624,9 +2580,7 @@ void Context::drawArrays(GLenum mode, GLint first, GLsizei count)
applyState(mode);
TranslatedIndexData indexInfo;
bool useIndexing;
GLenum err = applyVertexBuffer(mode, first, count, &useIndexing, &indexInfo);
GLenum err = applyVertexBuffer(first, count);
if (err != GL_NO_ERROR)
{
return error(err);
......@@ -2643,14 +2597,8 @@ void Context::drawArrays(GLenum mode, GLint first, GLsizei count)
if (!cullSkipsDraw(mode))
{
display->startScene();
if (useIndexing)
{
device->DrawIndexedPrimitive(primitiveType, -(INT)indexInfo.minIndex, indexInfo.minIndex, indexInfo.maxIndex-indexInfo.minIndex+1, indexInfo.offset/indexInfo.indexSize, primitiveCount);
}
else
{
device->DrawPrimitive(primitiveType, 0, primitiveCount);
}
device->DrawPrimitive(primitiveType, 0, primitiveCount);
}
}
......@@ -2693,7 +2641,8 @@ void Context::drawElements(GLenum mode, GLsizei count, GLenum type, const void*
return error(err);
}
err = applyVertexBuffer(indexInfo);
GLsizei vertexCount = indexInfo.maxIndex - indexInfo.minIndex + 1;
err = applyVertexBuffer(indexInfo.minIndex, vertexCount);
if (err != GL_NO_ERROR)
{
return error(err);
......@@ -2710,7 +2659,7 @@ void Context::drawElements(GLenum mode, GLsizei count, GLenum type, const void*
if (!cullSkipsDraw(mode))
{
display->startScene();
device->DrawIndexedPrimitive(primitiveType, -(INT)indexInfo.minIndex, indexInfo.minIndex, indexInfo.maxIndex-indexInfo.minIndex+1, indexInfo.offset/indexInfo.indexSize, primitiveCount);
device->DrawIndexedPrimitive(primitiveType, -(INT)indexInfo.minIndex, indexInfo.minIndex, vertexCount, indexInfo.startIndex, primitiveCount);
}
}
......@@ -2738,7 +2687,6 @@ void Context::finish()
ASSERT(SUCCEEDED(result));
// Render something outside the render target
device->SetStreamSourceFreq(0, 1);
device->SetPixelShader(NULL);
device->SetVertexShader(NULL);
device->SetFVF(D3DFVF_XYZRHW);
......@@ -2975,6 +2923,11 @@ bool Context::supportsLuminanceAlphaTextures() const
return mSupportsLuminanceAlphaTextures;
}
bool Context::supports32bitIndices() const
{
return mSupports32bitIndices;
}
void Context::detachBuffer(GLuint buffer)
{
// [OpenGL ES 2.0.24] section 2.9 page 22:
......@@ -3160,7 +3113,7 @@ void Context::setVertexAttrib(GLuint index, const GLfloat *values)
mState.vertexAttribute[index].mCurrentValue[2] = values[2];
mState.vertexAttribute[index].mCurrentValue[3] = values[3];
mVertexDataManager->dirtyCurrentValues();
mVertexDataManager->dirtyCurrentValue(index);
}
void Context::initExtensionString()
......@@ -3207,7 +3160,7 @@ void Context::initExtensionString()
mExtensionString += "GL_ANGLE_framebuffer_multisample ";
}
if (mBufferBackEnd->supportIntIndices())
if (supports32bitIndices())
{
mExtensionString += "GL_OES_element_index_uint ";
}
......
......@@ -50,13 +50,12 @@ class Stencilbuffer;
class DepthStencilbuffer;
class VertexDataManager;
class IndexDataManager;
class BufferBackEnd;
class Blit;
class Fence;
enum
{
MAX_VERTEX_ATTRIBS = 16 - 1, // Stream 0 reserved to enable instancing for non-array attributes
MAX_VERTEX_ATTRIBS = 16,
MAX_VERTEX_UNIFORM_VECTORS = 256 - 2, // 256 is the minimum for SM2, and in practice the maximum for DX9. Reserve space for dx_HalfPixelSize and dx_DepthRange.
MAX_VARYING_VECTORS_SM2 = 8,
MAX_VARYING_VECTORS_SM3 = 10,
......@@ -86,32 +85,56 @@ struct Color
};
// Helper structure describing a single vertex attribute
class AttributeState
class VertexAttribute
{
public:
AttributeState()
: mType(GL_FLOAT), mSize(0), mNormalized(false), mStride(0), mPointer(NULL), mEnabled(false)
VertexAttribute() : mType(GL_FLOAT), mSize(0), mNormalized(false), mStride(0), mPointer(NULL), mArrayEnabled(false)
{
mCurrentValue[0] = 0;
mCurrentValue[1] = 0;
mCurrentValue[2] = 0;
mCurrentValue[3] = 1;
mCurrentValue[0] = 0.0f;
mCurrentValue[1] = 0.0f;
mCurrentValue[2] = 0.0f;
mCurrentValue[3] = 1.0f;
}
// From VertexArrayPointer
int typeSize() const
{
switch (mType)
{
case GL_BYTE: return mSize * sizeof(GLbyte);
case GL_UNSIGNED_BYTE: return mSize * sizeof(GLubyte);
case GL_SHORT: return mSize * sizeof(GLshort);
case GL_UNSIGNED_SHORT: return mSize * sizeof(GLushort);
case GL_FIXED: return mSize * sizeof(GLfixed);
case GL_FLOAT: return mSize * sizeof(GLfloat);
default: UNREACHABLE(); return mSize * sizeof(GLfloat);
}
}
GLsizei stride() const
{
return mStride ? mStride : typeSize();
}
// From glVertexAttribPointer
GLenum mType;
GLint mSize;
bool mNormalized;
GLsizei mStride; // 0 means natural stride
const void *mPointer;
GLsizei mStride; // 0 means natural stride
BindingPointer<Buffer> mBoundBuffer; // Captured when VertexArrayPointer is called.
union
{
const void *mPointer;
intptr_t mOffset;
};
bool mEnabled; // From Enable/DisableVertexAttribArray
BindingPointer<Buffer> mBoundBuffer; // Captured when glVertexAttribPointer is called.
float mCurrentValue[4]; // From VertexAttrib4f
bool mArrayEnabled; // From glEnable/DisableVertexAttribArray
float mCurrentValue[4]; // From glVertexAttrib
};
typedef VertexAttribute VertexAttributeArray[MAX_VERTEX_ATTRIBS];
// Helper structure to store all raw state
struct State
{
......@@ -188,7 +211,7 @@ struct State
BindingPointer<Renderbuffer> renderbuffer;
GLuint currentProgram;
AttributeState vertexAttribute[MAX_VERTEX_ATTRIBS];
VertexAttribute vertexAttribute[MAX_VERTEX_ATTRIBS];
BindingPointer<Texture> samplerTexture[SAMPLER_TYPE_COUNT][MAX_TEXTURE_IMAGE_UNITS];
GLint unpackAlignment;
......@@ -283,13 +306,13 @@ class Context
GLuint getArrayBufferHandle() const;
void setVertexAttribEnabled(unsigned int attribNum, bool enabled);
const AttributeState &getVertexAttribState(unsigned int attribNum);
void setEnableVertexAttribArray(unsigned int attribNum, bool enabled);
const VertexAttribute &getVertexAttribState(unsigned int attribNum);
void setVertexAttribState(unsigned int attribNum, Buffer *boundBuffer, GLint size, GLenum type,
bool normalized, GLsizei stride, const void *pointer);
const void *getVertexAttribPointer(unsigned int attribNum) const;
const AttributeState *getVertexAttribBlock();
const VertexAttributeArray &getVertexAttributes();
void setUnpackAlignment(GLint alignment);
GLint getUnpackAlignment() const;
......@@ -359,10 +382,8 @@ class Context
bool applyRenderTarget(bool ignoreViewport);
void applyState(GLenum drawMode);
GLenum applyVertexBuffer(GLenum mode, GLint first, GLsizei count, bool *useIndexing, TranslatedIndexData *indexInfo);
GLenum applyVertexBuffer(const TranslatedIndexData &indexInfo);
GLenum applyVertexBuffer(GLint first, GLsizei count);
GLenum applyIndexBuffer(const void *indices, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo);
GLenum applyCountingIndexBuffer(GLenum mode, GLenum count, TranslatedIndexData *indexInfo);
void applyShaders();
void applyTextures();
......@@ -401,6 +422,7 @@ class Context
bool supportsHalfFloatRenderableTextures() const;
bool supportsLuminanceTextures() const;
bool supportsLuminanceAlphaTextures() const;
bool supports32bitIndices() const;
void blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
......@@ -432,7 +454,6 @@ class Context
BindingPointer<Texture2D> mTexture2DZero;
BindingPointer<TextureCubeMap> mTextureCubeMapZero;
typedef std::map<GLuint, Framebuffer*> FramebufferMap;
FramebufferMap mFramebufferMap;
......@@ -442,7 +463,6 @@ class Context
void initExtensionString();
std::string mExtensionString;
BufferBackEnd *mBufferBackEnd;
VertexDataManager *mVertexDataManager;
IndexDataManager *mIndexDataManager;
......@@ -482,6 +502,7 @@ class Context
bool mSupportsHalfFloatRenderableTextures;
bool mSupportsLuminanceTextures;
bool mSupportsLuminanceAlphaTextures;
bool mSupports32bitIndices;
// state caching flags
bool mClearStateDirty;
......
......@@ -13,7 +13,6 @@
#include "libGLESv2/Buffer.h"
#include "libGLESv2/mathutil.h"
#include "libGLESv2/geometry/backend.h"
namespace
{
......@@ -23,254 +22,352 @@ namespace
namespace gl
{
IndexDataManager::IndexDataManager(Context *context, BufferBackEnd *backend)
: mContext(context), mBackend(backend), mIntIndicesSupported(backend->supportIntIndices())
IndexDataManager::IndexDataManager(Context *context, IDirect3DDevice9 *device) : mDevice(device)
{
mCountingBuffer = NULL;
mCountingBufferSize = 0;
mStreamingBufferShort = new StreamingIndexBuffer(mDevice, INITIAL_INDEX_BUFFER_SIZE, D3DFMT_INDEX16);
mLineLoopBuffer = NULL;
mStreamBufferShort = mBackend->createIndexBuffer(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_SHORT);
if (mIntIndicesSupported)
if (context->supports32bitIndices())
{
mStreamBufferInt = mBackend->createIndexBuffer(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_INT);
mStreamingBufferInt = new StreamingIndexBuffer(mDevice, INITIAL_INDEX_BUFFER_SIZE, D3DFMT_INDEX32);
}
else
{
mStreamBufferInt = NULL;
mStreamingBufferInt = NULL;
}
}
IndexDataManager::~IndexDataManager()
{
delete mStreamBufferShort;
delete mStreamBufferInt;
delete mCountingBuffer;
delete mLineLoopBuffer;
delete mStreamingBufferShort;
delete mStreamingBufferInt;
}
namespace
void convertIndices(GLenum type, const void *input, GLsizei count, void *output)
{
if (type == GL_UNSIGNED_BYTE)
{
const GLubyte *in = static_cast<const GLubyte*>(input);
GLushort *out = static_cast<GLushort*>(output);
template <class InputIndexType, class OutputIndexType>
void copyIndices(const InputIndexType *in, GLsizei count, OutputIndexType *out, GLuint *minIndex, GLuint *maxIndex)
for (GLsizei i = 0; i < count; i++)
{
out[i] = in[i];
}
}
else if (type == GL_UNSIGNED_INT)
{
memcpy(output, input, count * sizeof(GLuint));
}
else if (type == GL_UNSIGNED_SHORT)
{
memcpy(output, input, count * sizeof(GLushort));
}
else UNREACHABLE();
}
template <class IndexType>
void computeRange(const IndexType *indices, GLsizei count, GLuint *minIndex, GLuint *maxIndex)
{
InputIndexType first = *in;
GLuint minIndexSoFar = first;
GLuint maxIndexSoFar = first;
*minIndex = indices[0];
*maxIndex = indices[0];
for (GLsizei i = 0; i < count; i++)
{
if (minIndexSoFar > *in) minIndexSoFar = *in;
if (maxIndexSoFar < *in) maxIndexSoFar = *in;
*out++ = *in++;
if (*minIndex > indices[i]) *minIndex = indices[i];
if (*maxIndex < indices[i]) *maxIndex = indices[i];
}
// It might be a line loop, so copy the loop index.
*out = first;
*minIndex = minIndexSoFar;
*maxIndex = maxIndexSoFar;
}
void computeRange(GLenum type, const void *indices, GLsizei count, GLuint *minIndex, GLuint *maxIndex)
{
if (type == GL_UNSIGNED_BYTE)
{
computeRange(static_cast<const GLubyte*>(indices), count, minIndex, maxIndex);
}
else if (type == GL_UNSIGNED_INT)
{
computeRange(static_cast<const GLuint*>(indices), count, minIndex, maxIndex);
}
else if (type == GL_UNSIGNED_SHORT)
{
computeRange(static_cast<const GLushort*>(indices), count, minIndex, maxIndex);
}
else UNREACHABLE();
}
GLenum IndexDataManager::preRenderValidate(GLenum mode, GLenum type, GLsizei count, Buffer *arrayElementBuffer, const void *indices, TranslatedIndexData *translated)
GLenum IndexDataManager::prepareIndexData(GLenum type, GLsizei count, Buffer *buffer, const void *indices, TranslatedIndexData *translated)
{
ASSERT(type == GL_UNSIGNED_SHORT || type == GL_UNSIGNED_BYTE || type == GL_UNSIGNED_INT);
ASSERT(count > 0);
D3DFORMAT format = (type == GL_UNSIGNED_INT) ? D3DFMT_INDEX32 : D3DFMT_INDEX16;
intptr_t offset = reinterpret_cast<intptr_t>(indices);
bool alignedOffset = false;
if (arrayElementBuffer != NULL)
if (buffer != NULL)
{
GLsizei offset = reinterpret_cast<GLsizei>(indices);
switch (type)
{
case GL_UNSIGNED_BYTE: alignedOffset = (offset % sizeof(GLubyte) == 0); break;
case GL_UNSIGNED_SHORT: alignedOffset = (offset % sizeof(GLushort) == 0); break;
case GL_UNSIGNED_INT: alignedOffset = (offset % sizeof(GLuint) == 0); break;
default: UNREACHABLE(); alignedOffset = false;
}
if (typeSize(type) * count + offset > static_cast<std::size_t>(arrayElementBuffer->size()))
if (typeSize(type) * count + offset > static_cast<std::size_t>(buffer->size()))
{
return GL_INVALID_OPERATION;
}
indices = static_cast<const GLubyte*>(arrayElementBuffer->data()) + offset;
indices = static_cast<const GLubyte*>(buffer->data()) + offset;
}
translated->count = count;
std::size_t requiredSpace = spaceRequired(type, count);
TranslatedIndexBuffer *streamIb = prepareIndexBuffer(type, requiredSpace);
size_t offset;
void *output = streamIb->map(requiredSpace, &offset);
if (output == NULL)
{
ERR(" failed to map index buffer.");
return GL_OUT_OF_MEMORY;
}
StreamingIndexBuffer *streamingBuffer = (type == GL_UNSIGNED_INT) ? mStreamingBufferInt : mStreamingBufferShort;
translated->buffer = streamIb;
translated->offset = offset;
translated->indexSize = indexSize(type);
StaticIndexBuffer *staticBuffer = buffer ? buffer->getIndexBuffer() : NULL;
IndexBuffer *indexBuffer = streamingBuffer;
UINT streamOffset = 0;
if (type == GL_UNSIGNED_BYTE)
if (staticBuffer && staticBuffer->lookupType(type) && alignedOffset)
{
const GLubyte *in = static_cast<const GLubyte*>(indices);
GLushort *out = static_cast<GLushort*>(output);
indexBuffer = staticBuffer;
streamOffset = staticBuffer->lookupRange(offset, count, &translated->minIndex, &translated->maxIndex);
copyIndices(in, count, out, &translated->minIndex, &translated->maxIndex);
if (streamOffset == -1)
{
streamOffset = (offset / typeSize(type)) * indexSize(format);
computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex);
staticBuffer->addRange(offset, count, translated->minIndex, translated->maxIndex, streamOffset);
}
}
else if (type == GL_UNSIGNED_INT)
else
{
const GLuint *in = static_cast<const GLuint*>(indices);
int convertCount = count;
if (mIntIndicesSupported)
if (staticBuffer)
{
GLuint *out = static_cast<GLuint*>(output);
copyIndices(in, count, out, &translated->minIndex, &translated->maxIndex);
if (staticBuffer->size() == 0 && alignedOffset)
{
indexBuffer = staticBuffer;
convertCount = buffer->size() / typeSize(type);
}
else
{
buffer->invalidateStaticData();
staticBuffer = NULL;
}
}
else
{
// When 32-bit indices are unsupported, fake them by truncating to 16-bit.
GLushort *out = static_cast<GLushort*>(output);
indexBuffer->reserveSpace(convertCount * indexSize(format), type);
copyIndices(in, count, out, &translated->minIndex, &translated->maxIndex);
void *output = indexBuffer->map(indexSize(format) * convertCount, &streamOffset);
if (output == NULL)
{
ERR("Failed to map index buffer.");
return GL_OUT_OF_MEMORY;
}
}
else
{
const GLushort *in = static_cast<const GLushort*>(indices);
GLushort *out = static_cast<GLushort*>(output);
copyIndices(in, count, out, &translated->minIndex, &translated->maxIndex);
convertIndices(type, staticBuffer ? buffer->data() : indices, convertCount, output);
indexBuffer->unmap();
computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex);
if (staticBuffer)
{
streamOffset = (offset / typeSize(type)) * indexSize(format);
staticBuffer->addRange(offset, count, translated->minIndex, translated->maxIndex, streamOffset);
}
}
streamIb->unmap();
translated->indexBuffer = indexBuffer->getBuffer();
translated->startIndex = streamOffset / indexSize(format);
return GL_NO_ERROR;
}
std::size_t IndexDataManager::indexSize(GLenum type) const
std::size_t IndexDataManager::indexSize(D3DFORMAT format) const
{
return (type == GL_UNSIGNED_INT && mIntIndicesSupported) ? sizeof(GLuint) : sizeof(GLushort);
return (format == D3DFMT_INDEX32) ? sizeof(unsigned int) : sizeof(unsigned short);
}
std::size_t IndexDataManager::typeSize(GLenum type) const
{
switch (type)
{
case GL_UNSIGNED_INT: return sizeof(GLuint);
case GL_UNSIGNED_INT: return sizeof(GLuint);
case GL_UNSIGNED_SHORT: return sizeof(GLushort);
default: UNREACHABLE();
case GL_UNSIGNED_BYTE: return sizeof(GLubyte);
case GL_UNSIGNED_BYTE: return sizeof(GLubyte);
default: UNREACHABLE(); return sizeof(GLushort);
}
}
std::size_t IndexDataManager::spaceRequired(GLenum type, GLsizei count) const
IndexBuffer::IndexBuffer(IDirect3DDevice9 *device, UINT size, D3DFORMAT format) : mDevice(device), mBufferSize(size), mIndexBuffer(NULL)
{
return (count + 1) * indexSize(type); // +1 because we always leave an extra for line loops
if (size > 0)
{
HRESULT result = device->CreateIndexBuffer(size, D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, format, D3DPOOL_DEFAULT, &mIndexBuffer, NULL);
if (FAILED(result))
{
ERR("Out of memory allocating an index buffer of size %lu.", size);
}
}
}
TranslatedIndexBuffer *IndexDataManager::prepareIndexBuffer(GLenum type, std::size_t requiredSpace)
IndexBuffer::~IndexBuffer()
{
bool use32 = (type == GL_UNSIGNED_INT && mIntIndicesSupported);
if (mIndexBuffer)
{
mIndexBuffer->Release();
}
}
TranslatedIndexBuffer *streamIb = use32 ? mStreamBufferInt : mStreamBufferShort;
IDirect3DIndexBuffer9 *IndexBuffer::getBuffer() const
{
return mIndexBuffer;
}
if (requiredSpace > streamIb->size())
void IndexBuffer::unmap()
{
if (mIndexBuffer)
{
std::size_t newSize = std::max(requiredSpace, 2 * streamIb->size());
mIndexBuffer->Unlock();
}
}
TranslatedIndexBuffer *newStreamBuffer = mBackend->createIndexBuffer(newSize, use32 ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT);
StreamingIndexBuffer::StreamingIndexBuffer(IDirect3DDevice9 *device, UINT initialSize, D3DFORMAT format) : IndexBuffer(device, initialSize, format)
{
mWritePosition = 0;
}
delete streamIb;
StreamingIndexBuffer::~StreamingIndexBuffer()
{
}
streamIb = newStreamBuffer;
void *StreamingIndexBuffer::map(UINT requiredSpace, UINT *offset)
{
void *mapPtr = NULL;
if (use32)
{
mStreamBufferInt = streamIb;
}
else
if (mIndexBuffer)
{
HRESULT result = mIndexBuffer->Lock(mWritePosition, requiredSpace, &mapPtr, D3DLOCK_NOOVERWRITE);
if (FAILED(result))
{
mStreamBufferShort = streamIb;
ERR(" Lock failed with error 0x%08x", result);
return NULL;
}
}
streamIb->reserveSpace(requiredSpace);
*offset = mWritePosition;
mWritePosition += requiredSpace;
}
return streamIb;
return mapPtr;
}
GLenum IndexDataManager::preRenderValidateUnindexed(GLenum mode, GLsizei count, TranslatedIndexData *indexInfo)
void StreamingIndexBuffer::reserveSpace(UINT requiredSpace, GLenum type)
{
if (count >= 65535) return GL_OUT_OF_MEMORY;
if (mode == GL_LINE_LOOP)
if (requiredSpace > mBufferSize)
{
// For line loops, create a single-use buffer that runs 0 - count-1, 0.
delete mLineLoopBuffer;
mLineLoopBuffer = mBackend->createIndexBuffer((count+1) * sizeof(unsigned short), GL_UNSIGNED_SHORT);
unsigned short *indices = static_cast<unsigned short *>(mLineLoopBuffer->map());
if (indices == NULL)
if (mIndexBuffer)
{
ERR(" failed to map index buffer.");
return GL_OUT_OF_MEMORY;
mIndexBuffer->Release();
mIndexBuffer = NULL;
}
for (int i = 0; i < count; i++)
mBufferSize = std::max(requiredSpace, 2 * mBufferSize);
HRESULT result = mDevice->CreateIndexBuffer(mBufferSize, D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, type == GL_UNSIGNED_INT ? D3DFMT_INDEX32 : D3DFMT_INDEX16, D3DPOOL_DEFAULT, &mIndexBuffer, NULL);
if (FAILED(result))
{
indices[i] = i;
ERR("Out of memory allocating a vertex buffer of size %lu.", mBufferSize);
}
indices[count] = 0;
mLineLoopBuffer->unmap();
indexInfo->buffer = mLineLoopBuffer;
indexInfo->count = count + 1;
indexInfo->maxIndex = count - 1;
mWritePosition = 0;
}
else if (mCountingBufferSize < count)
else if (mWritePosition + requiredSpace > mBufferSize) // Recycle
{
mCountingBufferSize = std::max(static_cast<GLsizei>(ceilPow2(count)), mCountingBufferSize*2);
void *dummy;
mIndexBuffer->Lock(0, 1, &dummy, D3DLOCK_DISCARD);
mIndexBuffer->Unlock();
mWritePosition = 0;
}
}
StaticIndexBuffer::StaticIndexBuffer(IDirect3DDevice9 *device) : IndexBuffer(device, 0, D3DFMT_UNKNOWN)
{
mCacheType = GL_NONE;
}
StaticIndexBuffer::~StaticIndexBuffer()
{
}
delete mCountingBuffer;
mCountingBuffer = mBackend->createIndexBuffer(count * sizeof(unsigned short), GL_UNSIGNED_SHORT);
void *StaticIndexBuffer::map(UINT requiredSpace, UINT *offset)
{
void *mapPtr = NULL;
unsigned short *indices = static_cast<unsigned short *>(mCountingBuffer->map());
if (indices == NULL)
if (mIndexBuffer)
{
HRESULT result = mIndexBuffer->Lock(0, requiredSpace, &mapPtr, 0);
if (FAILED(result))
{
ERR(" failed to map index buffer.");
return GL_OUT_OF_MEMORY;
ERR(" Lock failed with error 0x%08x", result);
return NULL;
}
for (int i = 0; i < count; i++)
*offset = 0;
}
return mapPtr;
}
void StaticIndexBuffer::reserveSpace(UINT requiredSpace, GLenum type)
{
if (!mIndexBuffer && mBufferSize == 0)
{
HRESULT result = mDevice->CreateIndexBuffer(requiredSpace, D3DUSAGE_WRITEONLY, type == GL_UNSIGNED_INT ? D3DFMT_INDEX32 : D3DFMT_INDEX16, D3DPOOL_DEFAULT, &mIndexBuffer, NULL);
if (FAILED(result))
{
indices[i] = i;
ERR("Out of memory allocating a vertex buffer of size %lu.", mBufferSize);
}
mCountingBuffer->unmap();
indexInfo->buffer = mCountingBuffer;
indexInfo->count = count;
indexInfo->maxIndex = count - 1;
mBufferSize = requiredSpace;
mCacheType = type;
}
else
else if (mIndexBuffer && mBufferSize >= requiredSpace && mCacheType == type)
{
indexInfo->buffer = mCountingBuffer;
indexInfo->count = count;
indexInfo->maxIndex = count - 1;
// Already allocated
}
else UNREACHABLE(); // Static index buffers can't be resized
}
indexInfo->indexSize = sizeof(unsigned short);
indexInfo->minIndex = 0;
indexInfo->offset = 0;
bool StaticIndexBuffer::lookupType(GLenum type)
{
return mCacheType == type;
}
return GL_NO_ERROR;
UINT StaticIndexBuffer::lookupRange(intptr_t offset, GLsizei count, UINT *minIndex, UINT *maxIndex)
{
for (unsigned int range = 0; range < mCache.size(); range++)
{
if (mCache[range].offset == offset && mCache[range].count == count)
{
*minIndex = mCache[range].minIndex;
*maxIndex = mCache[range].maxIndex;
return mCache[range].streamOffset;
}
}
return -1;
}
void StaticIndexBuffer::addRange(intptr_t offset, GLsizei count, UINT minIndex, UINT maxIndex, UINT streamOffset)
{
IndexRange indexRange = {offset, count, minIndex, maxIndex, streamOffset};
mCache.push_back(indexRange);
}
}
......@@ -10,7 +10,7 @@
#ifndef LIBGLESV2_GEOMETRY_INDEXDATAMANAGER_H_
#define LIBGLESV2_GEOMETRY_INDEXDATAMANAGER_H_
#include <bitset>
#include <vector>
#include <cstddef>
#define GL_APICALL
......@@ -21,49 +21,98 @@
namespace gl
{
class Buffer;
class BufferBackEnd;
class TranslatedIndexBuffer;
struct FormatConverter;
struct TranslatedIndexData
{
GLuint minIndex;
GLuint maxIndex;
GLuint count;
GLuint indexSize;
UINT minIndex;
UINT maxIndex;
UINT startIndex;
TranslatedIndexBuffer *buffer;
GLsizei offset;
IDirect3DIndexBuffer9 *indexBuffer;
};
class IndexDataManager
class IndexBuffer
{
public:
IndexBuffer(IDirect3DDevice9 *device, UINT size, D3DFORMAT format);
virtual ~IndexBuffer();
UINT size() const { return mBufferSize; }
virtual void *map(UINT requiredSpace, UINT *offset) = 0;
void unmap();
virtual void reserveSpace(UINT requiredSpace, GLenum type) = 0;
IDirect3DIndexBuffer9 *getBuffer() const;
protected:
IDirect3DDevice9 *const mDevice;
IDirect3DIndexBuffer9 *mIndexBuffer;
UINT mBufferSize;
private:
DISALLOW_COPY_AND_ASSIGN(IndexBuffer);
};
class StreamingIndexBuffer : public IndexBuffer
{
public:
StreamingIndexBuffer(IDirect3DDevice9 *device, UINT initialSize, D3DFORMAT format);
~StreamingIndexBuffer();
void *map(UINT requiredSpace, UINT *offset);
void reserveSpace(UINT requiredSpace, GLenum type);
private:
UINT mWritePosition;
};
class StaticIndexBuffer : public IndexBuffer
{
public:
IndexDataManager(Context *context, BufferBackEnd *backend);
~IndexDataManager();
explicit StaticIndexBuffer(IDirect3DDevice9 *device);
~StaticIndexBuffer();
void *map(UINT requiredSpace, UINT *offset);
void reserveSpace(UINT requiredSpace, GLenum type);
GLenum preRenderValidate(GLenum mode, GLenum type, GLsizei count, Buffer *arrayElementBuffer, const void *indices, TranslatedIndexData *translated);
GLenum preRenderValidateUnindexed(GLenum mode, GLsizei count, TranslatedIndexData *indexInfo);
bool lookupType(GLenum type);
UINT lookupRange(intptr_t offset, GLsizei count, UINT *minIndex, UINT *maxIndex); // Returns the offset into the index buffer, or -1 if not found
void addRange(intptr_t offset, GLsizei count, UINT minIndex, UINT maxIndex, UINT streamOffset);
private:
std::size_t IndexDataManager::typeSize(GLenum type) const;
std::size_t IndexDataManager::indexSize(GLenum type) const;
std::size_t spaceRequired(GLenum type, GLsizei count) const;
TranslatedIndexBuffer *prepareIndexBuffer(GLenum type, std::size_t requiredSpace);
GLenum mCacheType;
struct IndexRange
{
intptr_t offset;
GLsizei count;
UINT minIndex;
UINT maxIndex;
UINT streamOffset;
};
std::vector<IndexRange> mCache;
};
class IndexDataManager
{
public:
IndexDataManager(Context *context, IDirect3DDevice9 *evice);
virtual ~IndexDataManager();
Context *mContext;
BufferBackEnd *mBackend;
GLenum prepareIndexData(GLenum type, GLsizei count, Buffer *arrayElementBuffer, const void *indices, TranslatedIndexData *translated);
bool mIntIndicesSupported;
private:
DISALLOW_COPY_AND_ASSIGN(IndexDataManager);
TranslatedIndexBuffer *mStreamBufferShort;
TranslatedIndexBuffer *mStreamBufferInt;
std::size_t typeSize(GLenum type) const;
std::size_t indexSize(D3DFORMAT format) const;
TranslatedIndexBuffer *mCountingBuffer;
GLsizei mCountingBufferSize;
IDirect3DDevice9 *const mDevice;
TranslatedIndexBuffer *mLineLoopBuffer;
StreamingIndexBuffer *mStreamingBufferShort;
StreamingIndexBuffer *mStreamingBufferInt;
};
}
......
......@@ -9,14 +9,12 @@
#include "libGLESv2/geometry/VertexDataManager.h"
#include <limits>
#include "common/debug.h"
#include "libGLESv2/Buffer.h"
#include "libGLESv2/Program.h"
#include "libGLESv2/geometry/backend.h"
#include "libGLESv2/geometry/vertexconversion.h"
#include "libGLESv2/geometry/IndexDataManager.h"
namespace
......@@ -27,252 +25,729 @@ namespace
namespace gl
{
VertexDataManager::VertexDataManager(Context *context, BufferBackEnd *backend)
: mContext(context), mBackend(backend), mDirtyCurrentValues(true), mCurrentValueOffset(0)
VertexDataManager::VertexDataManager(Context *context, IDirect3DDevice9 *device) : mContext(context), mDevice(device)
{
mStreamBuffer = mBackend->createVertexBuffer(INITIAL_STREAM_BUFFER_SIZE);
try
{
mCurrentValueBuffer = mBackend->createVertexBufferForStrideZero(4 * sizeof(float) * MAX_VERTEX_ATTRIBS);
}
catch (...)
for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
{
delete mStreamBuffer;
throw;
mDirtyCurrentValue[i] = true;
mCurrentValueBuffer[i] = NULL;
}
const D3DCAPS9 &caps = context->getDeviceCaps();
checkVertexCaps(caps.DeclTypes);
mStreamingBuffer = new StreamingVertexBuffer(mDevice, INITIAL_STREAM_BUFFER_SIZE);
}
VertexDataManager::~VertexDataManager()
{
delete mStreamBuffer;
delete mCurrentValueBuffer;
delete mStreamingBuffer;
for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
{
delete mCurrentValueBuffer[i];
}
}
std::bitset<MAX_VERTEX_ATTRIBS> VertexDataManager::getActiveAttribs() const
UINT VertexDataManager::writeAttributeData(ArrayVertexBuffer *vertexBuffer, GLint start, GLsizei count, const VertexAttribute &attribute)
{
std::bitset<MAX_VERTEX_ATTRIBS> active;
Buffer *buffer = attribute.mBoundBuffer.get();
Program *program = mContext->getCurrentProgram();
int inputStride = attribute.stride();
int elementSize = attribute.typeSize();
const FormatConverter &converter = formatConverter(attribute);
UINT streamOffset = 0;
for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
void *output = vertexBuffer->map(attribute, spaceRequired(attribute, count), &streamOffset);
if (output == NULL)
{
active[attributeIndex] = (program->getSemanticIndex(attributeIndex) != -1);
ERR("Failed to map vertex buffer.");
return -1;
}
return active;
const char *input = NULL;
if (buffer)
{
int offset = attribute.mOffset;
input = static_cast<const char*>(buffer->data()) + offset;
}
else
{
input = static_cast<const char*>(attribute.mPointer);
}
input += inputStride * start;
if (converter.identity && inputStride == elementSize)
{
memcpy(output, input, count * inputStride);
}
else
{
converter.convertArray(input, inputStride, count, output);
}
vertexBuffer->unmap();
return streamOffset;
}
GLenum VertexDataManager::preRenderValidate(GLint start, GLsizei count,
TranslatedAttribute *translated)
GLenum VertexDataManager::prepareVertexData(GLint start, GLsizei count, TranslatedAttribute *translated)
{
GLenum error = GL_NO_ERROR;
const AttributeState *attribs = mContext->getVertexAttribBlock();
const std::bitset<MAX_VERTEX_ATTRIBS> activeAttribs = getActiveAttribs();
const VertexAttributeArray &attribs = mContext->getVertexAttributes();
Program *program = mContext->getCurrentProgram();
for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
{
translated[i].enabled = activeAttribs[i];
translated[attributeIndex].active = (program->getSemanticIndex(attributeIndex) != -1);
}
bool usesCurrentValues = false;
// Determine the required storage size per used buffer
for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
{
if (activeAttribs[i] && !attribs[i].mEnabled)
Buffer *buffer = attribs[i].mBoundBuffer.get();
if (translated[i].active && attribs[i].mArrayEnabled && (buffer || attribs[i].mPointer))
{
usesCurrentValues = true;
break;
StaticVertexBuffer *staticBuffer = buffer ? buffer->getVertexBuffer() : NULL;
if (staticBuffer && staticBuffer->size() == 0)
{
int totalCount = buffer->size() / attribs[i].stride();
staticBuffer->addRequiredSpace(spaceRequired(attribs[i], totalCount));
}
else if (!staticBuffer || staticBuffer->lookupAttribute(attribs[i]) == -1)
{
mStreamingBuffer->addRequiredSpace(spaceRequired(attribs[i], count));
}
}
}
// Handle the identity-mapped attributes.
// Process array attributes.
std::size_t requiredSpace = 0;
// Invalidate static buffers if the attribute formats no longer match
for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
{
if (activeAttribs[i] && attribs[i].mEnabled)
Buffer *buffer = attribs[i].mBoundBuffer.get();
if (translated[i].active && attribs[i].mArrayEnabled && buffer)
{
requiredSpace += spaceRequired(attribs[i], count);
StaticVertexBuffer *staticBuffer = buffer->getVertexBuffer();
if (staticBuffer && staticBuffer->size() != 0)
{
bool matchingAttributes = true;
for (int j = 0; j < MAX_VERTEX_ATTRIBS; j++)
{
if (translated[j].active && attribs[j].mArrayEnabled && attribs[j].mBoundBuffer.get() == buffer)
{
if (staticBuffer->lookupAttribute(attribs[j]) == -1)
{
matchingAttributes = false;
break;
}
}
}
if (!matchingAttributes)
{
mStreamingBuffer->addRequiredSpaceFor(staticBuffer);
buffer->invalidateStaticData();
}
}
}
}
if (requiredSpace > mStreamBuffer->size())
// Reserve the required space per used buffer
for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
{
std::size_t newSize = std::max(requiredSpace, 3 * mStreamBuffer->size() / 2); // 1.5 x mStreamBuffer->size() is arbitrary and should be checked to see we don't have too many reallocations.
Buffer *buffer = attribs[i].mBoundBuffer.get();
TranslatedVertexBuffer *newStreamBuffer = mBackend->createVertexBuffer(newSize);
if (translated[i].active && attribs[i].mArrayEnabled && (buffer || attribs[i].mPointer))
{
ArrayVertexBuffer *staticBuffer = buffer ? buffer->getVertexBuffer() : NULL;
ArrayVertexBuffer *vertexBuffer = staticBuffer ? staticBuffer : mStreamingBuffer;
delete mStreamBuffer;
mStreamBuffer = newStreamBuffer;
vertexBuffer->reserveRequiredSpace();
}
}
mStreamBuffer->reserveSpace(requiredSpace);
for (size_t i = 0; i < MAX_VERTEX_ATTRIBS; i++)
// Perform the vertex data translations
for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
{
if (activeAttribs[i] && attribs[i].mEnabled)
if (translated[i].active)
{
FormatConverter formatConverter = mBackend->getFormatConverter(attribs[i].mType, attribs[i].mSize, attribs[i].mNormalized);
Buffer *buffer = attribs[i].mBoundBuffer.get();
translated[i].nonArray = false;
translated[i].type = attribs[i].mType;
translated[i].size = attribs[i].mSize;
translated[i].normalized = attribs[i].mNormalized;
translated[i].stride = formatConverter.outputVertexSize;
translated[i].buffer = mStreamBuffer;
if (attribs[i].mArrayEnabled)
{
if (!buffer && attribs[i].mPointer == NULL)
{
// This is an application error that would normally result in a crash, but we catch it and return an error
ERR("An enabled vertex array has no buffer and no pointer.");
return GL_INVALID_OPERATION;
}
size_t inputStride = interpretGlStride(attribs[i]);
size_t elementSize = typeSize(attribs[i].mType) * attribs[i].mSize;
const FormatConverter &converter = formatConverter(attribs[i]);
void *output = mStreamBuffer->map(spaceRequired(attribs[i], count), &translated[i].offset);
if (output == NULL)
{
ERR(" failed to map vertex buffer.");
return GL_OUT_OF_MEMORY;
}
StaticVertexBuffer *staticBuffer = buffer ? buffer->getVertexBuffer() : NULL;
ArrayVertexBuffer *vertexBuffer = staticBuffer ? staticBuffer : static_cast<ArrayVertexBuffer*>(mStreamingBuffer);
const void *input;
if (attribs[i].mBoundBuffer.get())
{
Buffer *buffer = attribs[i].mBoundBuffer.get();
UINT streamOffset = -1;
if (staticBuffer)
{
streamOffset = staticBuffer->lookupAttribute(attribs[i]);
if (streamOffset == -1)
{
// Convert the entire buffer
int totalCount = buffer->size() / attribs[i].stride();
int startIndex = attribs[i].mOffset / attribs[i].stride();
size_t offset = reinterpret_cast<size_t>(attribs[i].mPointer);
streamOffset = writeAttributeData(staticBuffer, -startIndex, totalCount, attribs[i]);
}
// Before we calculate the required size below, make sure it can be computed without integer overflow.
if (std::numeric_limits<std::size_t>::max() - start < static_cast<std::size_t>(count)
|| std::numeric_limits<std::size_t>::max() / inputStride < static_cast<std::size_t>(start + count - 1) // it's a prerequisite that count >= 1, so start+count-1 >= 0.
|| std::numeric_limits<std::size_t>::max() - offset < inputStride * (start + count - 1)
|| std::numeric_limits<std::size_t>::max() - elementSize < offset + inputStride * (start + count - 1) + elementSize)
if (streamOffset != -1)
{
streamOffset += (start + attribs[i].mOffset / attribs[i].stride()) * converter.outputElementSize;
}
}
else
{
mStreamBuffer->unmap();
return GL_INVALID_OPERATION;
streamOffset = writeAttributeData(mStreamingBuffer, start, count, attribs[i]);
}
if (offset + inputStride * (start + count - 1) + elementSize > buffer->size())
if (streamOffset == -1)
{
mStreamBuffer->unmap();
return GL_INVALID_OPERATION;
return GL_OUT_OF_MEMORY;
}
input = static_cast<const char*>(buffer->data()) + offset;
translated[i].vertexBuffer = vertexBuffer->getBuffer();
translated[i].type = converter.d3dDeclType;
translated[i].stride = converter.outputElementSize;
translated[i].offset = streamOffset;
}
else
{
input = attribs[i].mPointer;
}
if (mDirtyCurrentValue[i])
{
delete mCurrentValueBuffer[i];
mCurrentValueBuffer[i] = new ConstantVertexBuffer(mDevice, attribs[i].mCurrentValue[0], attribs[i].mCurrentValue[1], attribs[i].mCurrentValue[2], attribs[i].mCurrentValue[3]);
mDirtyCurrentValue[i] = false;
}
input = static_cast<const char*>(input) + inputStride * start;
translated[i].vertexBuffer = mCurrentValueBuffer[i]->getBuffer();
if (formatConverter.identity && inputStride == elementSize)
{
memcpy(output, input, count * inputStride);
translated[i].type = D3DDECLTYPE_FLOAT4;
translated[i].stride = 0;
translated[i].offset = 0;
}
else
}
}
return GL_NO_ERROR;
}
std::size_t VertexDataManager::spaceRequired(const VertexAttribute &attrib, std::size_t count) const
{
return formatConverter(attrib).outputElementSize * count;
}
// Mapping from OpenGL-ES vertex attrib type to D3D decl type:
//
// BYTE SHORT (Cast)
// BYTE-norm FLOAT (Normalize) (can't be exactly represented as SHORT-norm)
// UNSIGNED_BYTE UBYTE4 (Identity) or SHORT (Cast)
// UNSIGNED_BYTE-norm UBYTE4N (Identity) or FLOAT (Normalize)
// SHORT SHORT (Identity)
// SHORT-norm SHORT-norm (Identity) or FLOAT (Normalize)
// UNSIGNED_SHORT FLOAT (Cast)
// UNSIGNED_SHORT-norm USHORT-norm (Identity) or FLOAT (Normalize)
// FIXED (not in WebGL) FLOAT (FixedToFloat)
// FLOAT FLOAT (Identity)
// GLToCType maps from GL type (as GLenum) to the C typedef.
template <GLenum GLType> struct GLToCType { };
template <> struct GLToCType<GL_BYTE> { typedef GLbyte type; };
template <> struct GLToCType<GL_UNSIGNED_BYTE> { typedef GLubyte type; };
template <> struct GLToCType<GL_SHORT> { typedef GLshort type; };
template <> struct GLToCType<GL_UNSIGNED_SHORT> { typedef GLushort type; };
template <> struct GLToCType<GL_FIXED> { typedef GLuint type; };
template <> struct GLToCType<GL_FLOAT> { typedef GLfloat type; };
// This differs from D3DDECLTYPE in that it is unsized. (Size expansion is applied last.)
enum D3DVertexType
{
D3DVT_FLOAT,
D3DVT_SHORT,
D3DVT_SHORT_NORM,
D3DVT_UBYTE,
D3DVT_UBYTE_NORM,
D3DVT_USHORT_NORM
};
// D3DToCType maps from D3D vertex type (as enum D3DVertexType) to the corresponding C type.
template <unsigned int D3DType> struct D3DToCType { };
template <> struct D3DToCType<D3DVT_FLOAT> { typedef float type; };
template <> struct D3DToCType<D3DVT_SHORT> { typedef short type; };
template <> struct D3DToCType<D3DVT_SHORT_NORM> { typedef short type; };
template <> struct D3DToCType<D3DVT_UBYTE> { typedef unsigned char type; };
template <> struct D3DToCType<D3DVT_UBYTE_NORM> { typedef unsigned char type; };
template <> struct D3DToCType<D3DVT_USHORT_NORM> { typedef unsigned short type; };
// Encode the type/size combinations that D3D permits. For each type/size it expands to a widener that will provide the appropriate final size.
template <unsigned int type, int size>
struct WidenRule
{
};
template <int size> struct WidenRule<D3DVT_FLOAT, size> : gl::NoWiden<size> { };
template <int size> struct WidenRule<D3DVT_SHORT, size> : gl::WidenToEven<size> { };
template <int size> struct WidenRule<D3DVT_SHORT_NORM, size> : gl::WidenToEven<size> { };
template <int size> struct WidenRule<D3DVT_UBYTE, size> : gl::WidenToFour<size> { };
template <int size> struct WidenRule<D3DVT_UBYTE_NORM, size> : gl::WidenToFour<size> { };
template <int size> struct WidenRule<D3DVT_USHORT_NORM, size> : gl::WidenToEven<size> { };
// VertexTypeFlags encodes the D3DCAPS9::DeclType flag and vertex declaration flag for each D3D vertex type & size combination.
template <unsigned int d3dtype, int size>
struct VertexTypeFlags
{
};
template <unsigned int capflag, unsigned int declflag>
struct VertexTypeFlagsHelper
{
enum { capflag = capflag };
enum { declflag = declflag };
};
template <> struct VertexTypeFlags<D3DVT_FLOAT, 1> : VertexTypeFlagsHelper<0, D3DDECLTYPE_FLOAT1> { };
template <> struct VertexTypeFlags<D3DVT_FLOAT, 2> : VertexTypeFlagsHelper<0, D3DDECLTYPE_FLOAT2> { };
template <> struct VertexTypeFlags<D3DVT_FLOAT, 3> : VertexTypeFlagsHelper<0, D3DDECLTYPE_FLOAT3> { };
template <> struct VertexTypeFlags<D3DVT_FLOAT, 4> : VertexTypeFlagsHelper<0, D3DDECLTYPE_FLOAT4> { };
template <> struct VertexTypeFlags<D3DVT_SHORT, 2> : VertexTypeFlagsHelper<0, D3DDECLTYPE_SHORT2> { };
template <> struct VertexTypeFlags<D3DVT_SHORT, 4> : VertexTypeFlagsHelper<0, D3DDECLTYPE_SHORT4> { };
template <> struct VertexTypeFlags<D3DVT_SHORT_NORM, 2> : VertexTypeFlagsHelper<D3DDTCAPS_SHORT2N, D3DDECLTYPE_SHORT2N> { };
template <> struct VertexTypeFlags<D3DVT_SHORT_NORM, 4> : VertexTypeFlagsHelper<D3DDTCAPS_SHORT4N, D3DDECLTYPE_SHORT4N> { };
template <> struct VertexTypeFlags<D3DVT_UBYTE, 4> : VertexTypeFlagsHelper<D3DDTCAPS_UBYTE4, D3DDECLTYPE_UBYTE4> { };
template <> struct VertexTypeFlags<D3DVT_UBYTE_NORM, 4> : VertexTypeFlagsHelper<D3DDTCAPS_UBYTE4N, D3DDECLTYPE_UBYTE4N> { };
template <> struct VertexTypeFlags<D3DVT_USHORT_NORM, 2> : VertexTypeFlagsHelper<D3DDTCAPS_USHORT2N, D3DDECLTYPE_USHORT2N> { };
template <> struct VertexTypeFlags<D3DVT_USHORT_NORM, 4> : VertexTypeFlagsHelper<D3DDTCAPS_USHORT4N, D3DDECLTYPE_USHORT4N> { };
// VertexTypeMapping maps GL type & normalized flag to preferred and fallback D3D vertex types (as D3DVertexType enums).
template <GLenum GLtype, bool normalized>
struct VertexTypeMapping
{
};
template <D3DVertexType Preferred, D3DVertexType Fallback = Preferred>
struct VertexTypeMappingBase
{
enum { preferred = Preferred };
enum { fallback = Fallback };
};
template <> struct VertexTypeMapping<GL_BYTE, false> : VertexTypeMappingBase<D3DVT_SHORT> { }; // Cast
template <> struct VertexTypeMapping<GL_BYTE, true> : VertexTypeMappingBase<D3DVT_FLOAT> { }; // Normalize
template <> struct VertexTypeMapping<GL_UNSIGNED_BYTE, false> : VertexTypeMappingBase<D3DVT_UBYTE, D3DVT_FLOAT> { }; // Identity, Cast
template <> struct VertexTypeMapping<GL_UNSIGNED_BYTE, true> : VertexTypeMappingBase<D3DVT_UBYTE_NORM, D3DVT_FLOAT> { }; // Identity, Normalize
template <> struct VertexTypeMapping<GL_SHORT, false> : VertexTypeMappingBase<D3DVT_SHORT> { }; // Identity
template <> struct VertexTypeMapping<GL_SHORT, true> : VertexTypeMappingBase<D3DVT_SHORT_NORM, D3DVT_FLOAT> { }; // Cast, Normalize
template <> struct VertexTypeMapping<GL_UNSIGNED_SHORT, false> : VertexTypeMappingBase<D3DVT_FLOAT> { }; // Cast
template <> struct VertexTypeMapping<GL_UNSIGNED_SHORT, true> : VertexTypeMappingBase<D3DVT_USHORT_NORM, D3DVT_FLOAT> { }; // Cast, Normalize
template <bool normalized> struct VertexTypeMapping<GL_FIXED, normalized> : VertexTypeMappingBase<D3DVT_FLOAT> { }; // FixedToFloat
template <bool normalized> struct VertexTypeMapping<GL_FLOAT, normalized> : VertexTypeMappingBase<D3DVT_FLOAT> { }; // Identity
// Given a GL type & norm flag and a D3D type, ConversionRule provides the type conversion rule (Cast, Normalize, Identity, FixedToFloat).
// The conversion rules themselves are defined in vertexconversion.h.
// Almost all cases are covered by Cast (including those that are actually Identity since Cast<T,T> knows it's an identity mapping).
template <GLenum fromType, bool normalized, unsigned int toType>
struct ConversionRule : gl::Cast<typename GLToCType<fromType>::type, typename D3DToCType<toType>::type>
{
};
// All conversions from normalized types to float use the Normalize operator.
template <GLenum fromType> struct ConversionRule<fromType, true, D3DVT_FLOAT> : gl::Normalize<typename GLToCType<fromType>::type> { };
// Use a full specialisation for this so that it preferentially matches ahead of the generic normalize-to-float rules.
template <> struct ConversionRule<GL_FIXED, true, D3DVT_FLOAT> : gl::FixedToFloat<GLuint, 16> { };
template <> struct ConversionRule<GL_FIXED, false, D3DVT_FLOAT> : gl::FixedToFloat<GLuint, 16> { };
// A 2-stage construction is used for DefaultVertexValues because float must use SimpleDefaultValues (i.e. 0/1)
// whether it is normalized or not.
template <class T, bool normalized>
struct DefaultVertexValuesStage2
{
};
template <class T> struct DefaultVertexValuesStage2<T, true> : gl::NormalizedDefaultValues<T> { };
template <class T> struct DefaultVertexValuesStage2<T, false> : gl::SimpleDefaultValues<T> { };
// Work out the default value rule for a D3D type (expressed as the C type) and
template <class T, bool normalized>
struct DefaultVertexValues : DefaultVertexValuesStage2<T, normalized>
{
};
template <bool normalized> struct DefaultVertexValues<float, normalized> : gl::SimpleDefaultValues<float> { };
// Policy rules for use with Converter, to choose whether to use the preferred or fallback conversion.
// The fallback conversion produces an output that all D3D9 devices must support.
template <class T> struct UsePreferred { enum { type = T::preferred }; };
template <class T> struct UseFallback { enum { type = T::fallback }; };
// Converter ties it all together. Given an OpenGL type/norm/size and choice of preferred/fallback conversion,
// it provides all the members of the appropriate VertexDataConverter, the D3DCAPS9::DeclTypes flag in cap flag
// and the D3DDECLTYPE member needed for the vertex declaration in declflag.
template <GLenum fromType, bool normalized, int size, template <class T> class PreferenceRule>
struct Converter
: gl::VertexDataConverter<typename GLToCType<fromType>::type,
WidenRule<PreferenceRule< VertexTypeMapping<fromType, normalized> >::type, size>,
ConversionRule<fromType,
normalized,
PreferenceRule< VertexTypeMapping<fromType, normalized> >::type>,
DefaultVertexValues<typename D3DToCType<PreferenceRule< VertexTypeMapping<fromType, normalized> >::type>::type, normalized > >
{
private:
enum { d3dtype = PreferenceRule< VertexTypeMapping<fromType, normalized> >::type };
enum { d3dsize = WidenRule<d3dtype, size>::finalWidth };
public:
enum { capflag = VertexTypeFlags<d3dtype, d3dsize>::capflag };
enum { declflag = VertexTypeFlags<d3dtype, d3dsize>::declflag };
};
// Initialise a TranslationInfo
#define TRANSLATION(type, norm, size, preferred) \
{ \
Converter<type, norm, size, preferred>::identity, \
Converter<type, norm, size, preferred>::finalSize, \
Converter<type, norm, size, preferred>::convertArray, \
static_cast<D3DDECLTYPE>(Converter<type, norm, size, preferred>::declflag) \
}
#define TRANSLATION_FOR_TYPE_NORM_SIZE(type, norm, size) \
{ \
Converter<type, norm, size, UsePreferred>::capflag, \
TRANSLATION(type, norm, size, UsePreferred), \
TRANSLATION(type, norm, size, UseFallback) \
}
#define TRANSLATIONS_FOR_TYPE(type) \
{ \
{ TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 1), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 2), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 3), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 4) }, \
{ TRANSLATION_FOR_TYPE_NORM_SIZE(type, true, 1), TRANSLATION_FOR_TYPE_NORM_SIZE(type, true, 2), TRANSLATION_FOR_TYPE_NORM_SIZE(type, true, 3), TRANSLATION_FOR_TYPE_NORM_SIZE(type, true, 4) }, \
}
const VertexDataManager::TranslationDescription VertexDataManager::mPossibleTranslations[NUM_GL_VERTEX_ATTRIB_TYPES][2][4] = // [GL types as enumerated by typeIndex()][normalized][size-1]
{
TRANSLATIONS_FOR_TYPE(GL_BYTE),
TRANSLATIONS_FOR_TYPE(GL_UNSIGNED_BYTE),
TRANSLATIONS_FOR_TYPE(GL_SHORT),
TRANSLATIONS_FOR_TYPE(GL_UNSIGNED_SHORT),
TRANSLATIONS_FOR_TYPE(GL_FIXED),
TRANSLATIONS_FOR_TYPE(GL_FLOAT)
};
void VertexDataManager::checkVertexCaps(DWORD declTypes)
{
for (unsigned int i = 0; i < NUM_GL_VERTEX_ATTRIB_TYPES; i++)
{
for (unsigned int j = 0; j < 2; j++)
{
for (unsigned int k = 0; k < 4; k++)
{
formatConverter.convertArray(input, inputStride, count, output);
if (mPossibleTranslations[i][j][k].capsFlag == 0 || (declTypes & mPossibleTranslations[i][j][k].capsFlag) != 0)
{
mAttributeTypes[i][j][k] = mPossibleTranslations[i][j][k].preferredConversion;
}
else
{
mAttributeTypes[i][j][k] = mPossibleTranslations[i][j][k].fallbackConversion;
}
}
}
}
}
mStreamBuffer->unmap();
// This is used to index mAttributeTypes and mPossibleTranslations.
unsigned int VertexDataManager::typeIndex(GLenum type) const
{
switch (type)
{
case GL_BYTE: return 0;
case GL_UNSIGNED_BYTE: return 1;
case GL_SHORT: return 2;
case GL_UNSIGNED_SHORT: return 3;
case GL_FIXED: return 4;
case GL_FLOAT: return 5;
default: UNREACHABLE(); return 5;
}
}
void VertexDataManager::setupAttributes(const TranslatedAttribute *attributes)
{
D3DVERTEXELEMENT9 elements[MAX_VERTEX_ATTRIBS];
D3DVERTEXELEMENT9 *element = &elements[0];
for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
{
if (attributes[i].active)
{
mDevice->SetStreamSource(i, attributes[i].vertexBuffer, attributes[i].offset, attributes[i].stride);
element->Stream = i;
element->Offset = 0;
element->Type = attributes[i].type;
element->Method = D3DDECLMETHOD_DEFAULT;
element->Usage = D3DDECLUSAGE_TEXCOORD;
element->UsageIndex = attributes[i].semanticIndex;
element++;
}
}
if (usesCurrentValues)
static const D3DVERTEXELEMENT9 end = D3DDECL_END();
*element = end;
IDirect3DVertexDeclaration9 *vertexDeclaration;
mDevice->CreateVertexDeclaration(elements, &vertexDeclaration);
mDevice->SetVertexDeclaration(vertexDeclaration);
vertexDeclaration->Release();
}
VertexBuffer::VertexBuffer(IDirect3DDevice9 *device, std::size_t size, DWORD usageFlags) : mDevice(device), mVertexBuffer(NULL)
{
if (size > 0)
{
error = processNonArrayAttributes(attribs, activeAttribs, translated, count);
HRESULT result = device->CreateVertexBuffer(size, usageFlags, 0, D3DPOOL_DEFAULT, &mVertexBuffer, NULL);
if (FAILED(result))
{
ERR("Out of memory allocating a vertex buffer of size %lu.", size);
}
}
}
return error;
VertexBuffer::~VertexBuffer()
{
if (mVertexBuffer)
{
mVertexBuffer->Release();
}
}
std::size_t VertexDataManager::typeSize(GLenum type) const
void VertexBuffer::unmap()
{
switch (type)
if (mVertexBuffer)
{
case GL_BYTE: case GL_UNSIGNED_BYTE: return sizeof(GLbyte);
case GL_SHORT: case GL_UNSIGNED_SHORT: return sizeof(GLshort);
case GL_FIXED: return sizeof(GLfixed);
case GL_FLOAT: return sizeof(GLfloat);
default: UNREACHABLE(); return sizeof(GLfloat);
mVertexBuffer->Unlock();
}
}
std::size_t VertexDataManager::interpretGlStride(const AttributeState &attrib) const
IDirect3DVertexBuffer9 *VertexBuffer::getBuffer() const
{
return attrib.mStride ? attrib.mStride : typeSize(attrib.mType) * attrib.mSize;
return mVertexBuffer;
}
// Round up x (>=0) to the next multiple of multiple (>0).
// 0 rounds up to 0.
std::size_t VertexDataManager::roundUp(std::size_t x, std::size_t multiple) const
ConstantVertexBuffer::ConstantVertexBuffer(IDirect3DDevice9 *device, float x, float y, float z, float w) : VertexBuffer(device, 4 * sizeof(float), D3DUSAGE_WRITEONLY)
{
ASSERT(x >= 0);
ASSERT(multiple > 0);
void *buffer = NULL;
std::size_t remainder = x % multiple;
if (remainder != 0)
if (mVertexBuffer)
{
return x + multiple - remainder;
HRESULT result = mVertexBuffer->Lock(0, 0, &buffer, 0);
if (FAILED(result))
{
ERR("Lock failed with error 0x%08x", result);
}
}
else
if (buffer)
{
return x;
float *vector = (float*)buffer;
vector[0] = x;
vector[1] = y;
vector[2] = z;
vector[3] = w;
mVertexBuffer->Unlock();
}
}
std::size_t VertexDataManager::spaceRequired(const AttributeState &attrib, std::size_t maxVertex) const
ConstantVertexBuffer::~ConstantVertexBuffer()
{
std::size_t size = mBackend->getFormatConverter(attrib.mType, attrib.mSize, attrib.mNormalized).outputVertexSize;
size *= maxVertex;
}
return roundUp(size, 4 * sizeof(GLfloat));
ArrayVertexBuffer::ArrayVertexBuffer(IDirect3DDevice9 *device, std::size_t size, DWORD usageFlags) : VertexBuffer(device, size, usageFlags)
{
mBufferSize = size;
mWritePosition = 0;
mRequiredSpace = 0;
}
GLenum VertexDataManager::processNonArrayAttributes(const AttributeState *attribs, const std::bitset<MAX_VERTEX_ATTRIBS> &activeAttribs, TranslatedAttribute *translated, std::size_t count)
ArrayVertexBuffer::~ArrayVertexBuffer()
{
if (mDirtyCurrentValues)
}
void ArrayVertexBuffer::addRequiredSpace(UINT requiredSpace)
{
mRequiredSpace += requiredSpace;
}
void ArrayVertexBuffer::addRequiredSpaceFor(ArrayVertexBuffer *buffer)
{
mRequiredSpace += buffer->mRequiredSpace;
}
StreamingVertexBuffer::StreamingVertexBuffer(IDirect3DDevice9 *device, std::size_t initialSize) : ArrayVertexBuffer(device, initialSize, D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY)
{
}
StreamingVertexBuffer::~StreamingVertexBuffer()
{
}
void *StreamingVertexBuffer::map(const VertexAttribute &attribute, std::size_t requiredSpace, std::size_t *offset)
{
void *mapPtr = NULL;
if (mVertexBuffer)
{
HRESULT result = mVertexBuffer->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 StreamingVertexBuffer::reserveRequiredSpace()
{
if (mRequiredSpace > mBufferSize)
{
std::size_t totalSize = 4 * sizeof(float) * MAX_VERTEX_ATTRIBS;
if (mVertexBuffer)
{
mVertexBuffer->Release();
mVertexBuffer = NULL;
}
mCurrentValueBuffer->reserveSpace(totalSize);
mBufferSize = std::max(mRequiredSpace, 3 * mBufferSize / 2); // 1.5 x mBufferSize is arbitrary and should be checked to see we don't have too many reallocations.
HRESULT result = mDevice->CreateVertexBuffer(mBufferSize, D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, 0, D3DPOOL_DEFAULT, &mVertexBuffer, NULL);
if (FAILED(result))
{
ERR("Out of memory allocating a vertex buffer of size %lu.", mBufferSize);
}
float* currentValues = static_cast<float*>(mCurrentValueBuffer->map(totalSize, &mCurrentValueOffset));
if (currentValues == NULL)
mWritePosition = 0;
}
else if (mWritePosition + mRequiredSpace > mBufferSize) // Recycle
{
if (mVertexBuffer)
{
ERR(" failed to map vertex buffer.");
return GL_OUT_OF_MEMORY;
void *dummy;
mVertexBuffer->Lock(0, 1, &dummy, D3DLOCK_DISCARD);
mVertexBuffer->Unlock();
}
for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
mWritePosition = 0;
}
mRequiredSpace = 0;
}
StaticVertexBuffer::StaticVertexBuffer(IDirect3DDevice9 *device) : ArrayVertexBuffer(device, 0, D3DUSAGE_WRITEONLY)
{
}
StaticVertexBuffer::~StaticVertexBuffer()
{
}
void *StaticVertexBuffer::map(const VertexAttribute &attribute, std::size_t requiredSpace, UINT *streamOffset)
{
void *mapPtr = NULL;
if (mVertexBuffer)
{
HRESULT result = mVertexBuffer->Lock(mWritePosition, requiredSpace, &mapPtr, 0);
if (FAILED(result))
{
// This assumes that the GL_FLOATx4 is supported by the back-end. (For D3D9, it is a mandatory format.)
currentValues[i*4+0] = attribs[i].mCurrentValue[0];
currentValues[i*4+1] = attribs[i].mCurrentValue[1];
currentValues[i*4+2] = attribs[i].mCurrentValue[2];
currentValues[i*4+3] = attribs[i].mCurrentValue[3];
ERR("Lock failed with error 0x%08x", result);
return NULL;
}
mCurrentValueBuffer->unmap();
int attributeOffset = attribute.mOffset % attribute.stride();
VertexElement element = {attribute.mType, attribute.mSize, attribute.mNormalized, attributeOffset, mWritePosition};
mCache.push_back(element);
*streamOffset = mWritePosition;
mWritePosition += requiredSpace;
}
for (std::size_t i = 0; i < MAX_VERTEX_ATTRIBS; i++)
return mapPtr;
}
void StaticVertexBuffer::reserveRequiredSpace()
{
if (!mVertexBuffer && mBufferSize == 0)
{
if (activeAttribs[i] && !attribs[i].mEnabled)
HRESULT result = mDevice->CreateVertexBuffer(mRequiredSpace, D3DUSAGE_WRITEONLY, 0, D3DPOOL_DEFAULT, &mVertexBuffer, NULL);
if (FAILED(result))
{
translated[i].nonArray = true;
ERR("Out of memory allocating a vertex buffer of size %lu.", mRequiredSpace);
}
translated[i].buffer = mCurrentValueBuffer;
mBufferSize = mRequiredSpace;
}
else if (mVertexBuffer && mBufferSize >= mRequiredSpace)
{
// Already allocated
}
else UNREACHABLE(); // Static vertex buffers can't be resized
translated[i].type = GL_FLOAT;
translated[i].size = 4;
translated[i].normalized = false;
translated[i].stride = 0;
translated[i].offset = mCurrentValueOffset + 4 * sizeof(float) * i;
mRequiredSpace = 0;
}
UINT StaticVertexBuffer::lookupAttribute(const VertexAttribute &attribute)
{
for (unsigned int element = 0; element < mCache.size(); element++)
{
if (mCache[element].type == attribute.mType && mCache[element].size == attribute.mSize && mCache[element].normalized == attribute.mNormalized)
{
if (mCache[element].attributeOffset == attribute.mOffset % attribute.stride())
{
return mCache[element].streamOffset;
}
}
}
return GL_NO_ERROR;
return -1;
}
const VertexDataManager::FormatConverter &VertexDataManager::formatConverter(const VertexAttribute &attribute) const
{
return mAttributeTypes[typeIndex(attribute.mType)][attribute.mNormalized][attribute.mSize - 1];
}
}
......@@ -10,7 +10,7 @@
#ifndef LIBGLESV2_GEOMETRY_VERTEXDATAMANAGER_H_
#define LIBGLESV2_GEOMETRY_VERTEXDATAMANAGER_H_
#include <bitset>
#include <vector>
#include <cstddef>
#define GL_APICALL
......@@ -21,44 +21,148 @@
namespace gl
{
class Buffer;
class BufferBackEnd;
class TranslatedVertexBuffer;
struct TranslatedAttribute;
struct FormatConverter;
struct TranslatedIndexData;
struct TranslatedAttribute
{
bool active;
D3DDECLTYPE type;
UINT offset;
UINT stride; // 0 means not to advance the read pointer at all
UINT semanticIndex;
IDirect3DVertexBuffer9 *vertexBuffer;
};
class VertexBuffer
{
public:
VertexBuffer(IDirect3DDevice9 *device, UINT size, DWORD usageFlags);
virtual ~VertexBuffer();
void unmap();
IDirect3DVertexBuffer9 *getBuffer() const;
protected:
IDirect3DDevice9 *const mDevice;
IDirect3DVertexBuffer9 *mVertexBuffer;
private:
DISALLOW_COPY_AND_ASSIGN(VertexBuffer);
};
class ConstantVertexBuffer : public VertexBuffer
{
public:
ConstantVertexBuffer(IDirect3DDevice9 *device, float x, float y, float z, float w);
~ConstantVertexBuffer();
};
class ArrayVertexBuffer : public VertexBuffer
{
public:
ArrayVertexBuffer(IDirect3DDevice9 *device, UINT size, DWORD usageFlags);
~ArrayVertexBuffer();
UINT size() const { return mBufferSize; }
virtual void *map(const VertexAttribute &attribute, UINT requiredSpace, UINT *streamOffset) = 0;
virtual void reserveRequiredSpace() = 0;
void addRequiredSpace(UINT requiredSpace);
void addRequiredSpaceFor(ArrayVertexBuffer *buffer);
protected:
UINT mBufferSize;
UINT mWritePosition;
UINT mRequiredSpace;
};
class StreamingVertexBuffer : public ArrayVertexBuffer
{
public:
StreamingVertexBuffer(IDirect3DDevice9 *device, UINT initialSize);
~StreamingVertexBuffer();
void *map(const VertexAttribute &attribute, UINT requiredSpace, UINT *streamOffset);
void reserveRequiredSpace();
};
class StaticVertexBuffer : public ArrayVertexBuffer
{
public:
explicit StaticVertexBuffer(IDirect3DDevice9 *device);
~StaticVertexBuffer();
void *map(const VertexAttribute &attribute, UINT requiredSpace, UINT *streamOffset);
void reserveRequiredSpace();
UINT lookupAttribute(const VertexAttribute &attribute); // Returns the offset into the vertex buffer, or -1 if not found
private:
struct VertexElement
{
GLenum type;
GLint size;
bool normalized;
int attributeOffset;
UINT streamOffset;
};
std::vector<VertexElement> mCache;
};
class VertexDataManager
{
public:
VertexDataManager(Context *context, BufferBackEnd *backend);
~VertexDataManager();
VertexDataManager(Context *context, IDirect3DDevice9 *backend);
virtual ~VertexDataManager();
void dirtyCurrentValues() { mDirtyCurrentValues = true; }
void dirtyCurrentValue(int index) { mDirtyCurrentValue[index] = true; }
GLenum preRenderValidate(GLint start,
GLsizei count,
TranslatedAttribute *outAttribs);
void setupAttributes(const TranslatedAttribute *attributes);
GLenum prepareVertexData(GLint start, GLsizei count, TranslatedAttribute *outAttribs);
private:
std::bitset<MAX_VERTEX_ATTRIBS> getActiveAttribs() const;
DISALLOW_COPY_AND_ASSIGN(VertexDataManager);
UINT spaceRequired(const VertexAttribute &attrib, std::size_t count) const;
UINT writeAttributeData(ArrayVertexBuffer *vertexBuffer, GLint start, GLsizei count, const VertexAttribute &attribute);
Context *const mContext;
IDirect3DDevice9 *const mDevice;
StreamingVertexBuffer *mStreamingBuffer;
bool mDirtyCurrentValue[MAX_VERTEX_ATTRIBS];
ConstantVertexBuffer *mCurrentValueBuffer[MAX_VERTEX_ATTRIBS];
// Attribute format conversion
struct FormatConverter
{
bool identity;
std::size_t outputElementSize;
void (*convertArray)(const void *in, std::size_t stride, std::size_t n, void *out);
D3DDECLTYPE d3dDeclType;
};
GLenum processNonArrayAttributes(const AttributeState *attribs, const std::bitset<MAX_VERTEX_ATTRIBS> &activeAttribs, TranslatedAttribute *translated, std::size_t count);
enum { NUM_GL_VERTEX_ATTRIB_TYPES = 6 };
std::size_t typeSize(GLenum type) const;
std::size_t interpretGlStride(const AttributeState &attrib) const;
FormatConverter mAttributeTypes[NUM_GL_VERTEX_ATTRIB_TYPES][2][4]; // [GL types as enumerated by typeIndex()][normalized][size - 1]
std::size_t roundUp(std::size_t x, std::size_t multiple) const;
std::size_t spaceRequired(const AttributeState &attrib, std::size_t maxVertex) const;
struct TranslationDescription
{
DWORD capsFlag;
FormatConverter preferredConversion;
FormatConverter fallbackConversion;
};
Context *mContext;
BufferBackEnd *mBackend;
// This table is used to generate mAttributeTypes.
static const TranslationDescription mPossibleTranslations[NUM_GL_VERTEX_ATTRIB_TYPES][2][4]; // [GL types as enumerated by typeIndex()][normalized][size - 1]
TranslatedVertexBuffer *mStreamBuffer;
void checkVertexCaps(DWORD declTypes);
bool mDirtyCurrentValues;
std::size_t mCurrentValueOffset; // Offset within mCurrentValueBuffer that the current attribute values were last loaded at.
TranslatedVertexBuffer *mCurrentValueBuffer;
unsigned int typeIndex(GLenum type) const;
const FormatConverter &formatConverter(const VertexAttribute &attribute) const;
};
}
......
//
// Copyright (c) 2002-2010 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.
//
// geometry/backend.h: Abstract classes BufferBackEnd, TranslatedVertexBuffer and TranslatedIndexBuffer
// that must be implemented by any API-specific implementation of ANGLE.
#include "libGLESv2/geometry/backend.h"
#include "common/debug.h"
namespace gl
{
void *TranslatedBuffer::map(std::size_t requiredSpace, std::size_t *offset)
{
ASSERT(requiredSpace <= mBufferSize);
reserveSpace(requiredSpace);
*offset = mCurrentPoint;
mCurrentPoint += requiredSpace;
return streamingMap(*offset, requiredSpace);
}
void TranslatedBuffer::reserveSpace(std::size_t requiredSpace)
{
if (mCurrentPoint + requiredSpace > mBufferSize)
{
recycle();
mCurrentPoint = 0;
}
}
}
//
// Copyright (c) 2002-2010 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.
//
// geometry/backend.h: Abstract classes BufferBackEnd, TranslatedVertexBuffer and TranslatedIndexBuffer
// that must be implemented by any API-specific implementation of ANGLE.
#ifndef LIBGLESV2_GEOMETRY_BACKEND_H_
#define LIBGLESV2_GEOMETRY_BACKEND_H_
#include <cstddef>
#define GL_APICALL
#include <GLES2/gl2.h>
#include "libGLESv2/Context.h"
namespace gl
{
class TranslatedVertexBuffer;
class TranslatedIndexBuffer;
struct FormatConverter
{
bool identity;
std::size_t outputVertexSize;
void (*convertArray)(const void *in, std::size_t stride, std::size_t n, void *out);
};
struct TranslatedAttribute
{
bool enabled;
bool nonArray;
// These are the original untranslated values. (Or just have some sort of BufferBackEnd::TranslatedTypeKey.)
GLenum type;
std::size_t size;
bool normalized;
std::size_t offset;
std::size_t stride; // 0 means not to advance the read pointer at all
std::size_t semanticIndex;
TranslatedVertexBuffer *buffer;
};
class BufferBackEnd
{
public:
virtual ~BufferBackEnd() { }
virtual bool supportIntIndices() = 0;
virtual TranslatedVertexBuffer *createVertexBuffer(std::size_t size) = 0;
virtual TranslatedVertexBuffer *createVertexBufferForStrideZero(std::size_t size) = 0;
virtual TranslatedIndexBuffer *createIndexBuffer(std::size_t size, GLenum type) = 0;
virtual FormatConverter getFormatConverter(GLenum type, std::size_t size, bool normalize) = 0;
// For an identity-mappable stream, verify that the stride and offset are okay.
virtual bool validateStream(GLenum type, std::size_t size, std::size_t stride, std::size_t offset) const = 0;
virtual GLenum setupIndicesPreDraw(const TranslatedIndexData &indexInfo) = 0;
virtual GLenum setupAttributesPreDraw(const TranslatedAttribute *attributes) = 0;
virtual void invalidate() = 0;
};
class TranslatedBuffer
{
public:
explicit TranslatedBuffer(std::size_t size) : mBufferSize(size), mCurrentPoint(0) { }
virtual ~TranslatedBuffer() { }
std::size_t size() const { return mBufferSize; }
virtual void *map() = 0;
virtual void unmap() = 0;
void reserveSpace(std::size_t requiredSpace);
void *map(std::size_t requiredSpace, std::size_t *offset);
protected:
virtual void recycle() = 0;
virtual void *streamingMap(std::size_t offset, std::size_t size) = 0;
private:
std::size_t mBufferSize;
std::size_t mCurrentPoint;
DISALLOW_COPY_AND_ASSIGN(TranslatedBuffer);
};
class TranslatedVertexBuffer : public TranslatedBuffer
{
public:
explicit TranslatedVertexBuffer(std::size_t size) : TranslatedBuffer(size) { }
};
class TranslatedIndexBuffer : public TranslatedBuffer
{
public:
explicit TranslatedIndexBuffer(std::size_t size) : TranslatedBuffer(size) { }
};
}
#endif // LIBGLESV2_GEOMETRY_BACKEND_H_
//
// Copyright (c) 2002-2010 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.
//
// geometry/dx9.h: Direct3D 9-based implementation of BufferBackEnd, TranslatedVertexBuffer and TranslatedIndexBuffer.
#include "libGLESv2/geometry/dx9.h"
#include <cstddef>
#define GL_APICALL
#include <GLES2/gl2.h>
#include "common/debug.h"
#include "libGLESv2/Context.h"
#include "libGLESv2/main.h"
#include "libGLESv2/geometry/vertexconversion.h"
#include "libGLESv2/geometry/IndexDataManager.h"
namespace
{
// Mapping from OpenGL-ES vertex attrib type to D3D decl type:
//
// BYTE SHORT (Cast)
// BYTE-norm FLOAT (Normalize) (can't be exactly represented as SHORT-norm)
// UNSIGNED_BYTE UBYTE4 (Identity) or SHORT (Cast)
// UNSIGNED_BYTE-norm UBYTE4N (Identity) or FLOAT (Normalize)
// SHORT SHORT (Identity)
// SHORT-norm SHORT-norm (Identity) or FLOAT (Normalize)
// UNSIGNED_SHORT FLOAT (Cast)
// UNSIGNED_SHORT-norm USHORT-norm (Identity) or FLOAT (Normalize)
// FIXED (not in WebGL) FLOAT (FixedToFloat)
// FLOAT FLOAT (Identity)
// GLToCType maps from GL type (as GLenum) to the C typedef.
template <GLenum GLType> struct GLToCType { };
template <> struct GLToCType<GL_BYTE> { typedef GLbyte type; };
template <> struct GLToCType<GL_UNSIGNED_BYTE> { typedef GLubyte type; };
template <> struct GLToCType<GL_SHORT> { typedef GLshort type; };
template <> struct GLToCType<GL_UNSIGNED_SHORT> { typedef GLushort type; };
template <> struct GLToCType<GL_FIXED> { typedef GLuint type; };
template <> struct GLToCType<GL_FLOAT> { typedef GLfloat type; };
// This differs from D3DDECLTYPE in that it is unsized. (Size expansion is applied last.)
enum D3DVertexType
{
D3DVT_FLOAT,
D3DVT_SHORT,
D3DVT_SHORT_NORM,
D3DVT_UBYTE,
D3DVT_UBYTE_NORM,
D3DVT_USHORT_NORM
};
// D3DToCType maps from D3D vertex type (as enum D3DVertexType) to the corresponding C type.
template <unsigned int D3DType> struct D3DToCType { };
template <> struct D3DToCType<D3DVT_FLOAT> { typedef float type; };
template <> struct D3DToCType<D3DVT_SHORT> { typedef short type; };
template <> struct D3DToCType<D3DVT_SHORT_NORM> { typedef short type; };
template <> struct D3DToCType<D3DVT_UBYTE> { typedef unsigned char type; };
template <> struct D3DToCType<D3DVT_UBYTE_NORM> { typedef unsigned char type; };
template <> struct D3DToCType<D3DVT_USHORT_NORM> { typedef unsigned short type; };
// Encode the type/size combinations that D3D permits. For each type/size it expands to a widener that will provide the appropriate final size.
template <unsigned int type, int size>
struct WidenRule
{
};
template <int size> struct WidenRule<D3DVT_FLOAT, size> : gl::NoWiden<size> { };
template <int size> struct WidenRule<D3DVT_SHORT, size> : gl::WidenToEven<size> { };
template <int size> struct WidenRule<D3DVT_SHORT_NORM, size> : gl::WidenToEven<size> { };
template <int size> struct WidenRule<D3DVT_UBYTE, size> : gl::WidenToFour<size> { };
template <int size> struct WidenRule<D3DVT_UBYTE_NORM, size> : gl::WidenToFour<size> { };
template <int size> struct WidenRule<D3DVT_USHORT_NORM, size> : gl::WidenToEven<size> { };
// VertexTypeFlags encodes the D3DCAPS9::DeclType flag and vertex declaration flag for each D3D vertex type & size combination.
template <unsigned int d3dtype, int size>
struct VertexTypeFlags
{
};
template <unsigned int capflag, unsigned int declflag>
struct VertexTypeFlagsHelper
{
enum { capflag = capflag };
enum { declflag = declflag };
};
template <> struct VertexTypeFlags<D3DVT_FLOAT, 1> : VertexTypeFlagsHelper<0, D3DDECLTYPE_FLOAT1> { };
template <> struct VertexTypeFlags<D3DVT_FLOAT, 2> : VertexTypeFlagsHelper<0, D3DDECLTYPE_FLOAT2> { };
template <> struct VertexTypeFlags<D3DVT_FLOAT, 3> : VertexTypeFlagsHelper<0, D3DDECLTYPE_FLOAT3> { };
template <> struct VertexTypeFlags<D3DVT_FLOAT, 4> : VertexTypeFlagsHelper<0, D3DDECLTYPE_FLOAT4> { };
template <> struct VertexTypeFlags<D3DVT_SHORT, 2> : VertexTypeFlagsHelper<0, D3DDECLTYPE_SHORT2> { };
template <> struct VertexTypeFlags<D3DVT_SHORT, 4> : VertexTypeFlagsHelper<0, D3DDECLTYPE_SHORT4> { };
template <> struct VertexTypeFlags<D3DVT_SHORT_NORM, 2> : VertexTypeFlagsHelper<D3DDTCAPS_SHORT2N, D3DDECLTYPE_SHORT2N> { };
template <> struct VertexTypeFlags<D3DVT_SHORT_NORM, 4> : VertexTypeFlagsHelper<D3DDTCAPS_SHORT4N, D3DDECLTYPE_SHORT4N> { };
template <> struct VertexTypeFlags<D3DVT_UBYTE, 4> : VertexTypeFlagsHelper<D3DDTCAPS_UBYTE4, D3DDECLTYPE_UBYTE4> { };
template <> struct VertexTypeFlags<D3DVT_UBYTE_NORM, 4> : VertexTypeFlagsHelper<D3DDTCAPS_UBYTE4N, D3DDECLTYPE_UBYTE4N> { };
template <> struct VertexTypeFlags<D3DVT_USHORT_NORM, 2> : VertexTypeFlagsHelper<D3DDTCAPS_USHORT2N, D3DDECLTYPE_USHORT2N> { };
template <> struct VertexTypeFlags<D3DVT_USHORT_NORM, 4> : VertexTypeFlagsHelper<D3DDTCAPS_USHORT4N, D3DDECLTYPE_USHORT4N> { };
// VertexTypeMapping maps GL type & normalized flag to preferred and fallback D3D vertex types (as D3DVertexType enums).
template <GLenum GLtype, bool normalized>
struct VertexTypeMapping
{
};
template <D3DVertexType Preferred, D3DVertexType Fallback = Preferred>
struct VertexTypeMappingBase
{
enum { preferred = Preferred };
enum { fallback = Fallback };
};
template <> struct VertexTypeMapping<GL_BYTE, false> : VertexTypeMappingBase<D3DVT_SHORT> { }; // Cast
template <> struct VertexTypeMapping<GL_BYTE, true> : VertexTypeMappingBase<D3DVT_FLOAT> { }; // Normalize
template <> struct VertexTypeMapping<GL_UNSIGNED_BYTE, false> : VertexTypeMappingBase<D3DVT_UBYTE, D3DVT_FLOAT> { }; // Identity, Cast
template <> struct VertexTypeMapping<GL_UNSIGNED_BYTE, true> : VertexTypeMappingBase<D3DVT_UBYTE_NORM, D3DVT_FLOAT> { }; // Identity, Normalize
template <> struct VertexTypeMapping<GL_SHORT, false> : VertexTypeMappingBase<D3DVT_SHORT> { }; // Identity
template <> struct VertexTypeMapping<GL_SHORT, true> : VertexTypeMappingBase<D3DVT_SHORT_NORM, D3DVT_FLOAT> { }; // Cast, Normalize
template <> struct VertexTypeMapping<GL_UNSIGNED_SHORT, false> : VertexTypeMappingBase<D3DVT_FLOAT> { }; // Cast
template <> struct VertexTypeMapping<GL_UNSIGNED_SHORT, true> : VertexTypeMappingBase<D3DVT_USHORT_NORM, D3DVT_FLOAT> { }; // Cast, Normalize
template <bool normalized> struct VertexTypeMapping<GL_FIXED, normalized> : VertexTypeMappingBase<D3DVT_FLOAT> { }; // FixedToFloat
template <bool normalized> struct VertexTypeMapping<GL_FLOAT, normalized> : VertexTypeMappingBase<D3DVT_FLOAT> { }; // Identity
// Given a GL type & norm flag and a D3D type, ConversionRule provides the type conversion rule (Cast, Normalize, Identity, FixedToFloat).
// The conversion rules themselves are defined in vertexconversion.h.
// Almost all cases are covered by Cast (including those that are actually Identity since Cast<T,T> knows it's an identity mapping).
template <GLenum fromType, bool normalized, unsigned int toType>
struct ConversionRule : gl::Cast<typename GLToCType<fromType>::type, typename D3DToCType<toType>::type>
{
};
// All conversions from normalized types to float use the Normalize operator.
template <GLenum fromType> struct ConversionRule<fromType, true, D3DVT_FLOAT> : gl::Normalize<typename GLToCType<fromType>::type> { };
// Use a full specialisation for this so that it preferentially matches ahead of the generic normalize-to-float rules.
template <> struct ConversionRule<GL_FIXED, true, D3DVT_FLOAT> : gl::FixedToFloat<GLuint, 16> { };
template <> struct ConversionRule<GL_FIXED, false, D3DVT_FLOAT> : gl::FixedToFloat<GLuint, 16> { };
// A 2-stage construction is used for DefaultVertexValues because float must use SimpleDefaultValues (i.e. 0/1)
// whether it is normalized or not.
template <class T, bool normalized>
struct DefaultVertexValuesStage2
{
};
template <class T> struct DefaultVertexValuesStage2<T, true> : gl::NormalizedDefaultValues<T> { };
template <class T> struct DefaultVertexValuesStage2<T, false> : gl::SimpleDefaultValues<T> { };
// Work out the default value rule for a D3D type (expressed as the C type) and
template <class T, bool normalized>
struct DefaultVertexValues : DefaultVertexValuesStage2<T, normalized>
{
};
template <bool normalized> struct DefaultVertexValues<float, normalized> : gl::SimpleDefaultValues<float> { };
// Policy rules for use with Converter, to choose whether to use the preferred or fallback conversion.
// The fallback conversion produces an output that all D3D9 devices must support.
template <class T> struct UsePreferred { enum { type = T::preferred }; };
template <class T> struct UseFallback { enum { type = T::fallback }; };
// Converter ties it all together. Given an OpenGL type/norm/size and choice of preferred/fallback conversion,
// it provides all the members of the appropriate VertexDataConverter, the D3DCAPS9::DeclTypes flag in cap flag
// and the D3DDECLTYPE member needed for the vertex declaration in declflag.
template <GLenum fromType, bool normalized, int size, template <class T> class PreferenceRule>
struct Converter
: gl::VertexDataConverter<typename GLToCType<fromType>::type,
WidenRule<PreferenceRule< VertexTypeMapping<fromType, normalized> >::type, size>,
ConversionRule<fromType,
normalized,
PreferenceRule< VertexTypeMapping<fromType, normalized> >::type>,
DefaultVertexValues<typename D3DToCType<PreferenceRule< VertexTypeMapping<fromType, normalized> >::type>::type, normalized > >
{
private:
enum { d3dtype = PreferenceRule< VertexTypeMapping<fromType, normalized> >::type };
enum { d3dsize = WidenRule<d3dtype, size>::finalWidth };
public:
enum { capflag = VertexTypeFlags<d3dtype, d3dsize>::capflag };
enum { declflag = VertexTypeFlags<d3dtype, d3dsize>::declflag };
};
}
namespace gl
{
Dx9BackEnd::Dx9BackEnd(Context *context, IDirect3DDevice9 *d3ddevice)
: mDevice(d3ddevice)
{
mDevice->AddRef();
for (int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
{
mAppliedAttribEnabled[i] = true;
mStreamFrequency[i] = STREAM_FREQUENCY_UNINSTANCED;
}
mStreamFrequency[MAX_VERTEX_ATTRIBS] = STREAM_FREQUENCY_UNINSTANCED;
D3DCAPS9 caps = context->getDeviceCaps();
IDirect3D9 *d3dObject;
mDevice->GetDirect3D(&d3dObject);
D3DADAPTER_IDENTIFIER9 ident;
d3dObject->GetAdapterIdentifier(caps.AdapterOrdinal, 0, &ident);
d3dObject->Release();
// Instancing is mandatory for all HW with SM3 vertex shaders, but avoid hardware where it does not work.
mUseInstancingForStrideZero = (caps.VertexShaderVersion >= D3DVS_VERSION(3, 0) && ident.VendorId != 0x8086);
mSupportIntIndices = (caps.MaxVertexIndex >= (1 << 16));
checkVertexCaps(caps.DeclTypes);
}
Dx9BackEnd::~Dx9BackEnd()
{
mDevice->Release();
}
bool Dx9BackEnd::supportIntIndices()
{
return mSupportIntIndices;
}
// Initialise a TranslationInfo
#define TRANSLATION(type, norm, size, preferred) \
{ \
{ \
Converter<type, norm, size, preferred>::identity, \
Converter<type, norm, size, preferred>::finalSize, \
Converter<type, norm, size, preferred>::convertArray, \
}, \
static_cast<D3DDECLTYPE>(Converter<type, norm, size, preferred>::declflag) \
}
#define TRANSLATION_FOR_TYPE_NORM_SIZE(type, norm, size) \
{ \
Converter<type, norm, size, UsePreferred>::capflag, \
TRANSLATION(type, norm, size, UsePreferred), \
TRANSLATION(type, norm, size, UseFallback) \
}
#define TRANSLATIONS_FOR_TYPE(type) \
{ \
{ TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 1), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 2), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 3), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 4) }, \
{ TRANSLATION_FOR_TYPE_NORM_SIZE(type, true, 1), TRANSLATION_FOR_TYPE_NORM_SIZE(type, true, 2), TRANSLATION_FOR_TYPE_NORM_SIZE(type, true, 3), TRANSLATION_FOR_TYPE_NORM_SIZE(type, true, 4) }, \
}
const Dx9BackEnd::TranslationDescription Dx9BackEnd::mPossibleTranslations[NUM_GL_VERTEX_ATTRIB_TYPES][2][4] = // [GL types as enumerated by typeIndex()][normalized][size-1]
{
TRANSLATIONS_FOR_TYPE(GL_BYTE),
TRANSLATIONS_FOR_TYPE(GL_UNSIGNED_BYTE),
TRANSLATIONS_FOR_TYPE(GL_SHORT),
TRANSLATIONS_FOR_TYPE(GL_UNSIGNED_SHORT),
TRANSLATIONS_FOR_TYPE(GL_FIXED),
TRANSLATIONS_FOR_TYPE(GL_FLOAT)
};
void Dx9BackEnd::checkVertexCaps(DWORD declTypes)
{
for (unsigned int i = 0; i < NUM_GL_VERTEX_ATTRIB_TYPES; i++)
{
for (unsigned int j = 0; j < 2; j++)
{
for (unsigned int k = 0; k < 4; k++)
{
if (mPossibleTranslations[i][j][k].capsFlag == 0 || (declTypes & mPossibleTranslations[i][j][k].capsFlag) != 0)
{
mAttributeTypes[i][j][k] = mPossibleTranslations[i][j][k].preferredConversion;
}
else
{
mAttributeTypes[i][j][k] = mPossibleTranslations[i][j][k].fallbackConversion;
}
}
}
}
}
TranslatedVertexBuffer *Dx9BackEnd::createVertexBuffer(std::size_t size)
{
return new Dx9VertexBuffer(mDevice, size);
}
TranslatedVertexBuffer *Dx9BackEnd::createVertexBufferForStrideZero(std::size_t size)
{
if (mUseInstancingForStrideZero)
{
return new Dx9VertexBuffer(mDevice, size);
}
else
{
return new Dx9VertexBufferZeroStrideWorkaround(mDevice, size);
}
}
TranslatedIndexBuffer *Dx9BackEnd::createIndexBuffer(std::size_t size, GLenum type)
{
return new Dx9IndexBuffer(mDevice, size, type);
}
// This is used to index mAttributeTypes and mPossibleTranslations.
unsigned int Dx9BackEnd::typeIndex(GLenum type) const
{
switch (type)
{
case GL_BYTE: return 0;
case GL_UNSIGNED_BYTE: return 1;
case GL_SHORT: return 2;
case GL_UNSIGNED_SHORT: return 3;
case GL_FIXED: return 4;
case GL_FLOAT: return 5;
default: UNREACHABLE(); return 5;
}
}
FormatConverter Dx9BackEnd::getFormatConverter(GLenum type, std::size_t size, bool normalize)
{
return mAttributeTypes[typeIndex(type)][normalize][size-1].formatConverter;
}
D3DDECLTYPE Dx9BackEnd::mapAttributeType(GLenum type, std::size_t size, bool normalize) const
{
return mAttributeTypes[typeIndex(type)][normalize][size-1].d3dDeclType;
}
bool Dx9BackEnd::validateStream(GLenum type, std::size_t size, std::size_t stride, std::size_t offset) const
{
// D3D9 requires the stream offset and stride to be a multiple of DWORD.
return (stride % sizeof(DWORD) == 0 && offset % sizeof(DWORD) == 0);
}
IDirect3DVertexBuffer9 *Dx9BackEnd::getDxBuffer(TranslatedVertexBuffer *vb) const
{
return vb ? static_cast<Dx9VertexBuffer*>(vb)->getBuffer() : NULL;
}
IDirect3DIndexBuffer9 *Dx9BackEnd::getDxBuffer(TranslatedIndexBuffer *ib) const
{
return ib ? static_cast<Dx9IndexBuffer*>(ib)->getBuffer() : NULL;
}
GLenum Dx9BackEnd::setupIndicesPreDraw(const TranslatedIndexData &indexInfo)
{
mDevice->SetIndices(getDxBuffer(indexInfo.buffer));
return GL_NO_ERROR;
}
GLenum Dx9BackEnd::setupAttributesPreDraw(const TranslatedAttribute *attributes)
{
HRESULT hr;
D3DVERTEXELEMENT9 elements[MAX_VERTEX_ATTRIBS+1];
D3DVERTEXELEMENT9 *nextElement = &elements[0];
for (BYTE i = 0; i < MAX_VERTEX_ATTRIBS; i++)
{
if (attributes[i].enabled)
{
nextElement->Stream = i + 1; // Stream 0 is skipped because D3D does not permit it to be an instanced stream.
nextElement->Offset = 0;
nextElement->Type = static_cast<BYTE>(mapAttributeType(attributes[i].type, attributes[i].size, attributes[i].normalized));
nextElement->Method = D3DDECLMETHOD_DEFAULT;
nextElement->Usage = D3DDECLUSAGE_TEXCOORD;
nextElement->UsageIndex = attributes[i].semanticIndex;
nextElement++;
}
}
static const D3DVERTEXELEMENT9 end = D3DDECL_END();
*nextElement = end;
IDirect3DVertexDeclaration9* vertexDeclaration;
hr = mDevice->CreateVertexDeclaration(elements, &vertexDeclaration);
mDevice->SetVertexDeclaration(vertexDeclaration);
vertexDeclaration->Release();
mDevice->SetStreamSource(0, NULL, 0, 0);
bool nonArrayAttributes = false;
for (size_t i = 0; i < MAX_VERTEX_ATTRIBS; i++)
{
if (attributes[i].enabled)
{
if (attributes[i].nonArray) nonArrayAttributes = true;
mDevice->SetStreamSource(i + 1, getDxBuffer(attributes[i].buffer), attributes[i].offset, attributes[i].stride);
if (!mAppliedAttribEnabled[i])
{
mAppliedAttribEnabled[i] = true;
}
}
else
{
if (mAppliedAttribEnabled[i])
{
mDevice->SetStreamSource(i + 1, 0, 0, 0);
mAppliedAttribEnabled[i] = false;
}
}
}
if (mUseInstancingForStrideZero)
{
// When there are no stride zero attributes, we disable instancing so that DrawPrimitive can be used.
if (nonArrayAttributes)
{
if (mStreamFrequency[0] != STREAM_FREQUENCY_INDEXED)
{
mStreamFrequency[0] = STREAM_FREQUENCY_INDEXED;
mDevice->SetStreamSourceFreq(0, D3DSTREAMSOURCE_INDEXEDDATA | 1);
}
for (size_t i = 0; i < MAX_VERTEX_ATTRIBS; i++)
{
if (attributes[i].enabled)
{
if (attributes[i].nonArray)
{
if (mStreamFrequency[i+1] != STREAM_FREQUENCY_INSTANCED)
{
mStreamFrequency[i+1] = STREAM_FREQUENCY_INSTANCED;
mDevice->SetStreamSourceFreq(i + 1, D3DSTREAMSOURCE_INSTANCEDATA | 1);
}
}
else
{
if (mStreamFrequency[i+1] != STREAM_FREQUENCY_INDEXED)
{
mStreamFrequency[i+1] = STREAM_FREQUENCY_INDEXED;
mDevice->SetStreamSourceFreq(i + 1, D3DSTREAMSOURCE_INDEXEDDATA | 1);
}
}
}
}
}
else
{
for (size_t i = 0; i < MAX_VERTEX_ATTRIBS + 1; i++)
{
if (mStreamFrequency[i] != STREAM_FREQUENCY_UNINSTANCED)
{
mStreamFrequency[i] = STREAM_FREQUENCY_UNINSTANCED;
// This should not be needed, but otherwise there is a buggy driver that will leave instancing
// enabled for the first draw after it has been turned off.
mDevice->SetStreamSourceFreq(i, D3DSTREAMSOURCE_INDEXEDDATA | 1);
mDevice->SetStreamSourceFreq(i, 1);
}
}
}
}
return GL_NO_ERROR;
}
void Dx9BackEnd::invalidate()
{
for (int i = 0; i < MAX_VERTEX_ATTRIBS + 1; i++)
{
mStreamFrequency[i] = STREAM_FREQUENCY_DIRTY;
}
}
Dx9BackEnd::Dx9VertexBuffer::Dx9VertexBuffer(IDirect3DDevice9 *device, std::size_t size)
: TranslatedVertexBuffer(size)
{
HRESULT hr = device->CreateVertexBuffer(size, D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, 0, D3DPOOL_DEFAULT, &mVertexBuffer, NULL);
if (hr != S_OK)
{
ERR("Out of memory allocating a vertex buffer of size %lu.", size);
throw std::bad_alloc();
}
}
Dx9BackEnd::Dx9VertexBuffer::Dx9VertexBuffer(IDirect3DDevice9 *device, std::size_t size, DWORD usageFlags)
: TranslatedVertexBuffer(size)
{
HRESULT hr = device->CreateVertexBuffer(size, usageFlags, 0, D3DPOOL_DEFAULT, &mVertexBuffer, NULL);
if (hr != S_OK)
{
ERR("Out of memory allocating a vertex buffer of size %lu.", size);
throw std::bad_alloc();
}
}
Dx9BackEnd::Dx9VertexBuffer::~Dx9VertexBuffer()
{
mVertexBuffer->Release();
}
IDirect3DVertexBuffer9 *Dx9BackEnd::Dx9VertexBuffer::getBuffer() const
{
return mVertexBuffer;
}
void *Dx9BackEnd::Dx9VertexBuffer::map()
{
void *mapPtr;
HRESULT hr = mVertexBuffer->Lock(0, 0, &mapPtr, 0);
if (FAILED(hr))
{
ERR(" Lock failed with error 0x%08x", hr);
return NULL;
}
return mapPtr;
}
void Dx9BackEnd::Dx9VertexBuffer::unmap()
{
mVertexBuffer->Unlock();
}
void Dx9BackEnd::Dx9VertexBuffer::recycle()
{
void *dummy;
mVertexBuffer->Lock(0, 1, &dummy, D3DLOCK_DISCARD);
mVertexBuffer->Unlock();
}
void *Dx9BackEnd::Dx9VertexBuffer::streamingMap(std::size_t offset, std::size_t size)
{
void *mapPtr;
HRESULT hr = mVertexBuffer->Lock(offset, size, &mapPtr, D3DLOCK_NOOVERWRITE);
if (FAILED(hr))
{
ERR(" Lock failed with error 0x%08x", hr);
return NULL;
}
return mapPtr;
}
// Normally VBs are created with D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC, but some hardware & drivers won't render
// if any stride-zero streams are in D3DUSAGE_DYNAMIC VBs, so this provides a way to create such VBs with only D3DUSAGE_WRITEONLY set.
// D3DLOCK_DISCARD and D3DLOCK_NOOVERWRITE are only available on D3DUSAGE_DYNAMIC VBs, so we override methods to avoid using these flags.
Dx9BackEnd::Dx9VertexBufferZeroStrideWorkaround::Dx9VertexBufferZeroStrideWorkaround(IDirect3DDevice9 *device, std::size_t size)
: Dx9VertexBuffer(device, size, D3DUSAGE_WRITEONLY)
{
}
void Dx9BackEnd::Dx9VertexBufferZeroStrideWorkaround::recycle()
{
}
void *Dx9BackEnd::Dx9VertexBufferZeroStrideWorkaround::streamingMap(std::size_t offset, std::size_t size)
{
void *mapPtr;
HRESULT hr = getBuffer()->Lock(offset, size, &mapPtr, 0);
if (FAILED(hr))
{
ERR(" Lock failed with error 0x%08x", hr);
return NULL;
}
return mapPtr;
}
Dx9BackEnd::Dx9IndexBuffer::Dx9IndexBuffer(IDirect3DDevice9 *device, std::size_t size, GLenum type)
: TranslatedIndexBuffer(size)
{
ASSERT(type == GL_UNSIGNED_SHORT || type == GL_UNSIGNED_INT);
D3DFORMAT format = (type == GL_UNSIGNED_SHORT) ? D3DFMT_INDEX16 : D3DFMT_INDEX32;
HRESULT hr = device->CreateIndexBuffer(size, D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, format, D3DPOOL_DEFAULT, &mIndexBuffer, NULL);
if (hr != S_OK)
{
ERR("Out of memory allocating an index buffer of size %lu.", size);
throw std::bad_alloc();
}
}
Dx9BackEnd::Dx9IndexBuffer::~Dx9IndexBuffer()
{
mIndexBuffer->Release();
}
IDirect3DIndexBuffer9*Dx9BackEnd::Dx9IndexBuffer::getBuffer() const
{
return mIndexBuffer;
}
void *Dx9BackEnd::Dx9IndexBuffer::map()
{
void *mapPtr;
HRESULT hr = mIndexBuffer->Lock(0, 0, &mapPtr, 0);
if (FAILED(hr))
{
ERR(" Lock failed with error 0x%08x", hr);
return NULL;
}
return mapPtr;
}
void Dx9BackEnd::Dx9IndexBuffer::unmap()
{
mIndexBuffer->Unlock();
}
void Dx9BackEnd::Dx9IndexBuffer::recycle()
{
void *dummy;
mIndexBuffer->Lock(0, 1, &dummy, D3DLOCK_DISCARD);
mIndexBuffer->Unlock();
}
void *Dx9BackEnd::Dx9IndexBuffer::streamingMap(std::size_t offset, std::size_t size)
{
void *mapPtr;
HRESULT hr = mIndexBuffer->Lock(offset, size, &mapPtr, D3DLOCK_NOOVERWRITE);
if (FAILED(hr))
{
ERR(" Lock failed with error 0x%08x", hr);
return NULL;
}
return mapPtr;
}
}
//
// Copyright (c) 2002-2010 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.
//
// geometry/dx9.h: Direct3D 9-based implementation of BufferBackEnd, TranslatedVertexBuffer and TranslatedIndexBuffer.
#ifndef LIBGLESV2_GEOMETRY_DX9_H_
#define LIBGLESV2_GEOMETRY_DX9_H_
#include <d3d9.h>
#include "libGLESv2/Buffer.h"
#include "libGLESv2/geometry/backend.h"
namespace gl
{
class Dx9BackEnd : public BufferBackEnd
{
public:
explicit Dx9BackEnd(Context *context, IDirect3DDevice9 *d3ddevice);
~Dx9BackEnd();
virtual bool supportIntIndices();
virtual TranslatedVertexBuffer *createVertexBuffer(std::size_t size);
virtual TranslatedVertexBuffer *createVertexBufferForStrideZero(std::size_t size);
virtual TranslatedIndexBuffer *createIndexBuffer(std::size_t size, GLenum type);
virtual FormatConverter getFormatConverter(GLenum type, std::size_t size, bool normalize);
virtual bool validateStream(GLenum type, std::size_t size, std::size_t stride, std::size_t offset) const;
virtual GLenum setupIndicesPreDraw(const TranslatedIndexData &indexInfo);
virtual GLenum setupAttributesPreDraw(const TranslatedAttribute *attributes);
void invalidate();
private:
IDirect3DDevice9 *mDevice;
bool mUseInstancingForStrideZero;
bool mSupportIntIndices;
bool mAppliedAttribEnabled[MAX_VERTEX_ATTRIBS];
enum StreamFrequency
{
STREAM_FREQUENCY_UNINSTANCED = 0,
STREAM_FREQUENCY_INDEXED,
STREAM_FREQUENCY_INSTANCED,
STREAM_FREQUENCY_DIRTY
};
StreamFrequency mStreamFrequency[MAX_VERTEX_ATTRIBS+1]; // Stream frequencies as last set.
struct TranslationInfo
{
FormatConverter formatConverter;
D3DDECLTYPE d3dDeclType;
};
enum { NUM_GL_VERTEX_ATTRIB_TYPES = 6 };
TranslationInfo mAttributeTypes[NUM_GL_VERTEX_ATTRIB_TYPES][2][4]; // [GL types as enumerated by typeIndex()][normalized][size-1]
struct TranslationDescription
{
DWORD capsFlag;
TranslationInfo preferredConversion;
TranslationInfo fallbackConversion;
};
// This table is used to generate mAttributeTypes.
static const TranslationDescription mPossibleTranslations[NUM_GL_VERTEX_ATTRIB_TYPES][2][4]; // [GL types as enumerated by typeIndex()][normalized][size-1]
void checkVertexCaps(DWORD declTypes);
unsigned int typeIndex(GLenum type) const;
class Dx9VertexBuffer : public TranslatedVertexBuffer
{
public:
Dx9VertexBuffer(IDirect3DDevice9 *device, std::size_t size);
virtual ~Dx9VertexBuffer();
IDirect3DVertexBuffer9 *getBuffer() const;
protected:
Dx9VertexBuffer(IDirect3DDevice9 *device, std::size_t size, DWORD usageFlags);
virtual void *map();
virtual void unmap();
virtual void recycle();
virtual void *streamingMap(std::size_t offset, std::size_t size);
private:
IDirect3DVertexBuffer9 *mVertexBuffer;
};
class Dx9VertexBufferZeroStrideWorkaround : public Dx9VertexBuffer
{
public:
Dx9VertexBufferZeroStrideWorkaround(IDirect3DDevice9 *device, std::size_t size);
protected:
virtual void recycle();
virtual void *streamingMap(std::size_t offset, std::size_t size);
};
class Dx9IndexBuffer : public TranslatedIndexBuffer
{
public:
Dx9IndexBuffer(IDirect3DDevice9 *device, std::size_t size, GLenum type);
virtual ~Dx9IndexBuffer();
IDirect3DIndexBuffer9 *getBuffer() const;
protected:
virtual void *map();
virtual void unmap();
virtual void recycle();
virtual void *streamingMap(std::size_t offset, std::size_t size);
private:
IDirect3DIndexBuffer9 *mIndexBuffer;
};
IDirect3DVertexBuffer9 *getDxBuffer(TranslatedVertexBuffer *vb) const;
IDirect3DIndexBuffer9 *getDxBuffer(TranslatedIndexBuffer *ib) const;
D3DDECLTYPE mapAttributeType(GLenum type, std::size_t size, bool normalized) const;
};
}
#endif // LIBGLESV2_GEOMETRY_DX9_H_
......@@ -1714,7 +1714,7 @@ void __stdcall glDisableVertexAttribArray(GLuint index)
if (context)
{
context->setVertexAttribEnabled(index, false);
context->setEnableVertexAttribArray(index, false);
}
}
catch(std::bad_alloc&)
......@@ -1759,20 +1759,25 @@ void __stdcall glDrawElements(GLenum mode, GLsizei count, GLenum type, const GLv
return error(GL_INVALID_VALUE);
}
switch (type)
{
case GL_UNSIGNED_BYTE:
case GL_UNSIGNED_SHORT:
case GL_UNSIGNED_INT:
break;
default:
return error(GL_INVALID_ENUM);
}
gl::Context *context = gl::getContext();
if (context)
{
switch (type)
{
case GL_UNSIGNED_BYTE:
case GL_UNSIGNED_SHORT:
break;
case GL_UNSIGNED_INT:
if (!context->supports32bitIndices())
{
return error(GL_INVALID_ENUM);
}
break;
default:
return error(GL_INVALID_ENUM);
}
context->drawElements(mode, count, type, indices);
}
}
......@@ -1829,7 +1834,7 @@ void __stdcall glEnableVertexAttribArray(GLuint index)
if (context)
{
context->setVertexAttribEnabled(index, true);
context->setEnableVertexAttribArray(index, true);
}
}
catch(std::bad_alloc&)
......@@ -3457,12 +3462,12 @@ void __stdcall glGetVertexAttribfv(GLuint index, GLenum pname, GLfloat* params)
return error(GL_INVALID_VALUE);
}
const gl::AttributeState &attribState = context->getVertexAttribState(index);
const gl::VertexAttribute &attribState = context->getVertexAttribState(index);
switch (pname)
{
case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
*params = (GLfloat)(attribState.mEnabled ? GL_TRUE : GL_FALSE);
*params = (GLfloat)(attribState.mArrayEnabled ? GL_TRUE : GL_FALSE);
break;
case GL_VERTEX_ATTRIB_ARRAY_SIZE:
*params = (GLfloat)attribState.mSize;
......@@ -3510,12 +3515,12 @@ void __stdcall glGetVertexAttribiv(GLuint index, GLenum pname, GLint* params)
return error(GL_INVALID_VALUE);
}
const gl::AttributeState &attribState = context->getVertexAttribState(index);
const gl::VertexAttribute &attribState = context->getVertexAttribState(index);
switch (pname)
{
case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
*params = (attribState.mEnabled ? GL_TRUE : GL_FALSE);
*params = (attribState.mArrayEnabled ? GL_TRUE : GL_FALSE);
break;
case GL_VERTEX_ATTRIB_ARRAY_SIZE:
*params = attribState.mSize;
......
......@@ -248,14 +248,6 @@
Name="Geometry"
>
<File
RelativePath=".\geometry\backend.cpp"
>
</File>
<File
RelativePath=".\geometry\dx9.cpp"
>
</File>
<File
RelativePath=".\geometry\IndexDataManager.cpp"
>
</File>
......@@ -342,14 +334,6 @@
Name="Geometry"
>
<File
RelativePath=".\geometry\backend.h"
>
</File>
<File
RelativePath=".\geometry\dx9.h"
>
</File>
<File
RelativePath=".\geometry\IndexDataManager.h"
>
</File>
......
......@@ -707,46 +707,46 @@ unsigned int GetDepthSize(D3DFORMAT depthFormat)
case D3DFMT_D16: return 16;
case D3DFMT_D32F_LOCKABLE: return 32;
case D3DFMT_D24FS8: return 24;
// case D3DFMT_D32_LOCKABLE: return 32; // D3D9Ex only
// case D3DFMT_S8_LOCKABLE: return 0; // D3D9Ex only
//case D3DFMT_D32_LOCKABLE: return 32; // D3D9Ex only
//case D3DFMT_S8_LOCKABLE: return 0; // D3D9Ex only
default:
UNREACHABLE();
}
return 0;
}
bool ConvertPrimitiveType(GLenum primitiveType, GLsizei primitiveCount,
bool ConvertPrimitiveType(GLenum primitiveType, GLsizei elementCount,
D3DPRIMITIVETYPE *d3dPrimitiveType, int *d3dPrimitiveCount)
{
switch (primitiveType)
{
case GL_POINTS:
*d3dPrimitiveType = D3DPT_POINTLIST;
*d3dPrimitiveCount = primitiveCount;
*d3dPrimitiveCount = elementCount;
break;
case GL_LINES:
*d3dPrimitiveType = D3DPT_LINELIST;
*d3dPrimitiveCount = primitiveCount / 2;
*d3dPrimitiveCount = elementCount / 2;
break;
case GL_LINE_LOOP:
*d3dPrimitiveType = D3DPT_LINESTRIP;
*d3dPrimitiveCount = primitiveCount;
*d3dPrimitiveCount = elementCount - 1; // D3D doesn't support line loops, so we draw the last line separately
break;
case GL_LINE_STRIP:
*d3dPrimitiveType = D3DPT_LINESTRIP;
*d3dPrimitiveCount = primitiveCount - 1;
*d3dPrimitiveCount = elementCount - 1;
break;
case GL_TRIANGLES:
*d3dPrimitiveType = D3DPT_TRIANGLELIST;
*d3dPrimitiveCount = primitiveCount / 3;
*d3dPrimitiveCount = elementCount / 3;
break;
case GL_TRIANGLE_STRIP:
*d3dPrimitiveType = D3DPT_TRIANGLESTRIP;
*d3dPrimitiveCount = primitiveCount - 2;
*d3dPrimitiveCount = elementCount - 2;
break;
case GL_TRIANGLE_FAN:
*d3dPrimitiveType = D3DPT_TRIANGLEFAN;
*d3dPrimitiveCount = primitiveCount - 2;
*d3dPrimitiveCount = elementCount - 2;
break;
default:
return false;
......
......@@ -61,7 +61,7 @@ unsigned int GetGreenSize(D3DFORMAT colorFormat);
unsigned int GetBlueSize(D3DFORMAT colorFormat);
unsigned int GetDepthSize(D3DFORMAT depthFormat);
unsigned int GetStencilSize(D3DFORMAT stencilFormat);
bool ConvertPrimitiveType(GLenum primitiveType, GLsizei primitiveCount,
bool ConvertPrimitiveType(GLenum primitiveType, GLsizei elementCount,
D3DPRIMITIVETYPE *d3dPrimitiveType, int *d3dPrimitiveCount);
D3DFORMAT ConvertRenderbufferFormat(GLenum format);
D3DMULTISAMPLE_TYPE GetMultisampleTypeFromSamples(GLsizei samples);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment