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 @@ ...@@ -144,10 +144,6 @@
'common/angleutils.h', 'common/angleutils.h',
'common/debug.cpp', 'common/debug.cpp',
'common/debug.h', '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.cpp',
'libGLESv2/geometry/IndexDataManager.h', 'libGLESv2/geometry/IndexDataManager.h',
'libGLESv2/geometry/vertexconversion.h', 'libGLESv2/geometry/vertexconversion.h',
......
...@@ -187,4 +187,3 @@ void TCompiler::collectAttribsUniforms(TIntermNode* root) ...@@ -187,4 +187,3 @@ void TCompiler::collectAttribsUniforms(TIntermNode* root)
CollectAttribsUniforms collect(attribs, uniforms); CollectAttribsUniforms collect(attribs, uniforms);
root->traverse(&collect); root->traverse(&collect);
} }
...@@ -299,4 +299,4 @@ void TAllocation::checkAllocList() const ...@@ -299,4 +299,4 @@ void TAllocation::checkAllocList() const
{ {
for (const TAllocation* alloc = this; alloc != 0; alloc = alloc->prevAlloc) for (const TAllocation* alloc = this; alloc != 0; alloc = alloc->prevAlloc)
alloc->check(); alloc->check();
} }
\ No newline at end of file
...@@ -297,4 +297,4 @@ protected: ...@@ -297,4 +297,4 @@ protected:
TPoolAllocator& allocator; TPoolAllocator& allocator;
}; };
#endif // _POOLALLOC_INCLUDED_ #endif // _POOLALLOC_INCLUDED_
\ No newline at end of file
...@@ -101,4 +101,4 @@ private: ...@@ -101,4 +101,4 @@ private:
TCompiler* ConstructCompiler(ShShaderType type, ShShaderSpec spec); TCompiler* ConstructCompiler(ShShaderType type, ShShaderSpec spec);
void DeleteCompiler(TCompiler*); void DeleteCompiler(TCompiler*);
#endif // _SHHANDLE_INCLUDED_ #endif // _SHHANDLE_INCLUDED_
\ No newline at end of file
...@@ -252,4 +252,3 @@ void ShGetActiveUniform(const ShHandle handle, ...@@ -252,4 +252,3 @@ void ShGetActiveUniform(const ShHandle handle,
getVariableInfo(SH_ACTIVE_UNIFORMS, getVariableInfo(SH_ACTIVE_UNIFORMS,
handle, index, length, size, type, name); handle, index, length, size, type, name);
} }
...@@ -213,8 +213,6 @@ void Surface::writeRecordableFlipState(IDirect3DDevice9 *device) ...@@ -213,8 +213,6 @@ void Surface::writeRecordableFlipState(IDirect3DDevice9 *device)
device->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); device->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
device->SetFVF(D3DFVF_XYZRHW | D3DFVF_TEX1); 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 RECT scissorRect = {0}; // Scissoring is disabled for flipping, but we need this to capture and restore the old rectangle
device->SetScissorRect(&scissorRect); device->SetScissorRect(&scissorRect);
D3DVIEWPORT9 viewport = {0, 0, mWidth, mHeight, 0.0f, 1.0f}; D3DVIEWPORT9 viewport = {0, 0, mWidth, mHeight, 0.0f, 1.0f};
......
...@@ -466,11 +466,6 @@ void Blit::setCommonBlitState() ...@@ -466,11 +466,6 @@ void Blit::setCommonBlitState()
device->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); device->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
device->SetSamplerState(0, D3DSAMP_ADDRESSV, 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 RECT scissorRect = {0}; // Scissoring is disabled for flipping, but we need this to capture and restore the old rectangle
device->SetScissorRect(&scissorRect); device->SetScissorRect(&scissorRect);
} }
......
...@@ -10,6 +10,10 @@ ...@@ -10,6 +10,10 @@
#include "libGLESv2/Buffer.h" #include "libGLESv2/Buffer.h"
#include "libGLESv2/main.h"
#include "libGLESv2/geometry/VertexDataManager.h"
#include "libGLESv2/geometry/IndexDataManager.h"
namespace gl namespace gl
{ {
...@@ -18,11 +22,16 @@ Buffer::Buffer(GLuint id) : RefCountObject(id) ...@@ -18,11 +22,16 @@ Buffer::Buffer(GLuint id) : RefCountObject(id)
mContents = NULL; mContents = NULL;
mSize = 0; mSize = 0;
mUsage = GL_DYNAMIC_DRAW; mUsage = GL_DYNAMIC_DRAW;
mVertexBuffer = NULL;
mIndexBuffer = NULL;
} }
Buffer::~Buffer() Buffer::~Buffer()
{ {
delete[] mContents; delete[] mContents;
delete mVertexBuffer;
delete mIndexBuffer;
} }
void Buffer::bufferData(const void *data, GLsizeiptr size, GLenum usage) void Buffer::bufferData(const void *data, GLsizeiptr size, GLenum usage)
...@@ -46,11 +55,49 @@ 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; mSize = size;
mUsage = usage; 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) void Buffer::bufferSubData(const void *data, GLsizeiptr size, GLintptr offset)
{ {
memcpy(mContents + offset, data, size); 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 @@ ...@@ -22,6 +22,8 @@
namespace gl namespace gl
{ {
class StaticVertexBuffer;
class StaticIndexBuffer;
class Buffer : public RefCountObject class Buffer : public RefCountObject
{ {
...@@ -37,12 +39,19 @@ class Buffer : public RefCountObject ...@@ -37,12 +39,19 @@ class Buffer : public RefCountObject
size_t size() const { return mSize; } size_t size() const { return mSize; }
GLenum usage() const { return mUsage; } GLenum usage() const { return mUsage; }
StaticVertexBuffer *getVertexBuffer();
StaticIndexBuffer *getIndexBuffer();
void invalidateStaticData();
private: private:
DISALLOW_COPY_AND_ASSIGN(Buffer); DISALLOW_COPY_AND_ASSIGN(Buffer);
GLubyte *mContents; GLubyte *mContents;
size_t mSize; size_t mSize;
GLenum mUsage; GLenum mUsage;
StaticVertexBuffer *mVertexBuffer;
StaticIndexBuffer *mIndexBuffer;
}; };
} }
......
...@@ -25,10 +25,8 @@ ...@@ -25,10 +25,8 @@
#include "libGLESv2/RenderBuffer.h" #include "libGLESv2/RenderBuffer.h"
#include "libGLESv2/Shader.h" #include "libGLESv2/Shader.h"
#include "libGLESv2/Texture.h" #include "libGLESv2/Texture.h"
#include "libGLESv2/geometry/backend.h"
#include "libGLESv2/geometry/VertexDataManager.h" #include "libGLESv2/geometry/VertexDataManager.h"
#include "libGLESv2/geometry/IndexDataManager.h" #include "libGLESv2/geometry/IndexDataManager.h"
#include "libGLESv2/geometry/dx9.h"
#undef near #undef near
#undef far #undef far
...@@ -139,7 +137,6 @@ Context::Context(const egl::Config *config, const gl::Context *shareContext) ...@@ -139,7 +137,6 @@ Context::Context(const egl::Config *config, const gl::Context *shareContext)
mState.packAlignment = 4; mState.packAlignment = 4;
mState.unpackAlignment = 4; mState.unpackAlignment = 4;
mBufferBackEnd = NULL;
mVertexDataManager = NULL; mVertexDataManager = NULL;
mIndexDataManager = NULL; mIndexDataManager = NULL;
mBlit = NULL; mBlit = NULL;
...@@ -212,7 +209,6 @@ Context::~Context() ...@@ -212,7 +209,6 @@ Context::~Context()
mTexture2DZero.set(NULL); mTexture2DZero.set(NULL);
mTextureCubeMapZero.set(NULL); mTextureCubeMapZero.set(NULL);
delete mBufferBackEnd;
delete mVertexDataManager; delete mVertexDataManager;
delete mIndexDataManager; delete mIndexDataManager;
delete mBlit; delete mBlit;
...@@ -233,9 +229,8 @@ void Context::makeCurrent(egl::Display *display, egl::Surface *surface) ...@@ -233,9 +229,8 @@ void Context::makeCurrent(egl::Display *display, egl::Surface *surface)
{ {
mDeviceCaps = display->getDeviceCaps(); mDeviceCaps = display->getDeviceCaps();
mBufferBackEnd = new Dx9BackEnd(this, device); mVertexDataManager = new VertexDataManager(this, device);
mVertexDataManager = new VertexDataManager(this, mBufferBackEnd); mIndexDataManager = new IndexDataManager(this, device);
mIndexDataManager = new IndexDataManager(this, mBufferBackEnd);
mBlit = new Blit(this); mBlit = new Blit(this);
mSupportsShaderModel3 = mDeviceCaps.PixelShaderVersion == D3DPS_VERSION(3, 0); mSupportsShaderModel3 = mDeviceCaps.PixelShaderVersion == D3DPS_VERSION(3, 0);
...@@ -281,6 +276,8 @@ void Context::makeCurrent(egl::Display *display, egl::Surface *surface) ...@@ -281,6 +276,8 @@ void Context::makeCurrent(egl::Display *display, egl::Surface *surface)
mSupportsLuminanceTextures = display->getLuminanceTextureSupport(); mSupportsLuminanceTextures = display->getLuminanceTextureSupport();
mSupportsLuminanceAlphaTextures = display->getLuminanceAlphaTextureSupport(); mSupportsLuminanceAlphaTextures = display->getLuminanceAlphaTextureSupport();
mSupports32bitIndices = mDeviceCaps.MaxVertexIndex >= (1 << 16);
initExtensionString(); initExtensionString();
mState.viewportX = 0; mState.viewportX = 0;
...@@ -339,11 +336,6 @@ void Context::markAllStateDirty() ...@@ -339,11 +336,6 @@ void Context::markAllStateDirty()
mSampleStateDirty = true; mSampleStateDirty = true;
mDitherStateDirty = true; mDitherStateDirty = true;
mFrontFaceDirty = true; mFrontFaceDirty = true;
if (mBufferBackEnd != NULL)
{
mBufferBackEnd->invalidate();
}
} }
void Context::setClearColor(float red, float green, float blue, float alpha) void Context::setClearColor(float red, float green, float blue, float alpha)
...@@ -743,12 +735,12 @@ GLuint Context::getArrayBufferHandle() const ...@@ -743,12 +735,12 @@ GLuint Context::getArrayBufferHandle() const
return mState.arrayBuffer.id(); 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]; return mState.vertexAttribute[attribNum];
} }
...@@ -769,8 +761,7 @@ const void *Context::getVertexAttribPointer(unsigned int attribNum) const ...@@ -769,8 +761,7 @@ const void *Context::getVertexAttribPointer(unsigned int attribNum) const
return mState.vertexAttribute[attribNum].mPointer; return mState.vertexAttribute[attribNum].mPointer;
} }
// returns entire set of attributes as a block const VertexAttributeArray &Context::getVertexAttributes()
const AttributeState *Context::getVertexAttribBlock()
{ {
return mState.vertexAttribute; return mState.vertexAttribute;
} }
...@@ -1963,18 +1954,18 @@ void Context::lookupAttributeMapping(TranslatedAttribute *attributes) ...@@ -1963,18 +1954,18 @@ void Context::lookupAttributeMapping(TranslatedAttribute *attributes)
{ {
for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++) for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
{ {
if (attributes[i].enabled) if (attributes[i].active)
{ {
attributes[i].semanticIndex = getCurrentProgram()->getSemanticIndex(i); 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]; TranslatedAttribute translated[MAX_VERTEX_ATTRIBS];
GLenum err = mVertexDataManager->preRenderValidate(first, count, translated); GLenum err = mVertexDataManager->prepareVertexData(first, count, translated);
if (err != GL_NO_ERROR) if (err != GL_NO_ERROR)
{ {
return err; return err;
...@@ -1982,53 +1973,20 @@ GLenum Context::applyVertexBuffer(GLenum mode, GLint first, GLsizei count, bool ...@@ -1982,53 +1973,20 @@ GLenum Context::applyVertexBuffer(GLenum mode, GLint first, GLsizei count, bool
lookupAttributeMapping(translated); lookupAttributeMapping(translated);
mBufferBackEnd->setupAttributesPreDraw(translated); mVertexDataManager->setupAttributes(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;
}
mBufferBackEnd->setupIndicesPreDraw(*indexInfo);
*useIndexing = true;
return GL_NO_ERROR;
}
}
*useIndexing = false;
return GL_NO_ERROR; 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 // 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 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) if (err == GL_NO_ERROR)
{ {
mBufferBackEnd->setupIndicesPreDraw(*indexInfo); device->SetIndices(indexInfo->indexBuffer);
} }
return err; return err;
...@@ -2486,7 +2444,6 @@ void Context::clear(GLbitfield mask) ...@@ -2486,7 +2444,6 @@ void Context::clear(GLbitfield mask)
device->SetPixelShader(NULL); device->SetPixelShader(NULL);
device->SetVertexShader(NULL); device->SetVertexShader(NULL);
device->SetFVF(D3DFVF_XYZRHW | D3DFVF_DIFFUSE); device->SetFVF(D3DFVF_XYZRHW | D3DFVF_DIFFUSE);
device->SetStreamSourceFreq(0, 1);
device->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_DISABLE); device->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_DISABLE);
hr = device->EndStateBlock(&mMaskedClearSavedState); hr = device->EndStateBlock(&mMaskedClearSavedState);
...@@ -2542,7 +2499,6 @@ void Context::clear(GLbitfield mask) ...@@ -2542,7 +2499,6 @@ void Context::clear(GLbitfield mask)
device->SetPixelShader(NULL); device->SetPixelShader(NULL);
device->SetVertexShader(NULL); device->SetVertexShader(NULL);
device->SetFVF(D3DFVF_XYZRHW | D3DFVF_DIFFUSE); device->SetFVF(D3DFVF_XYZRHW | D3DFVF_DIFFUSE);
device->SetStreamSourceFreq(0, 1);
device->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_DISABLE); device->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_DISABLE);
struct Vertex struct Vertex
...@@ -2624,9 +2580,7 @@ void Context::drawArrays(GLenum mode, GLint first, GLsizei count) ...@@ -2624,9 +2580,7 @@ void Context::drawArrays(GLenum mode, GLint first, GLsizei count)
applyState(mode); applyState(mode);
TranslatedIndexData indexInfo; GLenum err = applyVertexBuffer(first, count);
bool useIndexing;
GLenum err = applyVertexBuffer(mode, first, count, &useIndexing, &indexInfo);
if (err != GL_NO_ERROR) if (err != GL_NO_ERROR)
{ {
return error(err); return error(err);
...@@ -2643,14 +2597,8 @@ void Context::drawArrays(GLenum mode, GLint first, GLsizei count) ...@@ -2643,14 +2597,8 @@ void Context::drawArrays(GLenum mode, GLint first, GLsizei count)
if (!cullSkipsDraw(mode)) if (!cullSkipsDraw(mode))
{ {
display->startScene(); display->startScene();
if (useIndexing)
{ device->DrawPrimitive(primitiveType, 0, primitiveCount);
device->DrawIndexedPrimitive(primitiveType, -(INT)indexInfo.minIndex, indexInfo.minIndex, indexInfo.maxIndex-indexInfo.minIndex+1, indexInfo.offset/indexInfo.indexSize, primitiveCount);
}
else
{
device->DrawPrimitive(primitiveType, 0, primitiveCount);
}
} }
} }
...@@ -2693,7 +2641,8 @@ void Context::drawElements(GLenum mode, GLsizei count, GLenum type, const void* ...@@ -2693,7 +2641,8 @@ void Context::drawElements(GLenum mode, GLsizei count, GLenum type, const void*
return error(err); return error(err);
} }
err = applyVertexBuffer(indexInfo); GLsizei vertexCount = indexInfo.maxIndex - indexInfo.minIndex + 1;
err = applyVertexBuffer(indexInfo.minIndex, vertexCount);
if (err != GL_NO_ERROR) if (err != GL_NO_ERROR)
{ {
return error(err); return error(err);
...@@ -2710,7 +2659,7 @@ void Context::drawElements(GLenum mode, GLsizei count, GLenum type, const void* ...@@ -2710,7 +2659,7 @@ void Context::drawElements(GLenum mode, GLsizei count, GLenum type, const void*
if (!cullSkipsDraw(mode)) if (!cullSkipsDraw(mode))
{ {
display->startScene(); 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() ...@@ -2738,7 +2687,6 @@ void Context::finish()
ASSERT(SUCCEEDED(result)); ASSERT(SUCCEEDED(result));
// Render something outside the render target // Render something outside the render target
device->SetStreamSourceFreq(0, 1);
device->SetPixelShader(NULL); device->SetPixelShader(NULL);
device->SetVertexShader(NULL); device->SetVertexShader(NULL);
device->SetFVF(D3DFVF_XYZRHW); device->SetFVF(D3DFVF_XYZRHW);
...@@ -2975,6 +2923,11 @@ bool Context::supportsLuminanceAlphaTextures() const ...@@ -2975,6 +2923,11 @@ bool Context::supportsLuminanceAlphaTextures() const
return mSupportsLuminanceAlphaTextures; return mSupportsLuminanceAlphaTextures;
} }
bool Context::supports32bitIndices() const
{
return mSupports32bitIndices;
}
void Context::detachBuffer(GLuint buffer) void Context::detachBuffer(GLuint buffer)
{ {
// [OpenGL ES 2.0.24] section 2.9 page 22: // [OpenGL ES 2.0.24] section 2.9 page 22:
...@@ -3160,7 +3113,7 @@ void Context::setVertexAttrib(GLuint index, const GLfloat *values) ...@@ -3160,7 +3113,7 @@ void Context::setVertexAttrib(GLuint index, const GLfloat *values)
mState.vertexAttribute[index].mCurrentValue[2] = values[2]; mState.vertexAttribute[index].mCurrentValue[2] = values[2];
mState.vertexAttribute[index].mCurrentValue[3] = values[3]; mState.vertexAttribute[index].mCurrentValue[3] = values[3];
mVertexDataManager->dirtyCurrentValues(); mVertexDataManager->dirtyCurrentValue(index);
} }
void Context::initExtensionString() void Context::initExtensionString()
...@@ -3207,7 +3160,7 @@ void Context::initExtensionString() ...@@ -3207,7 +3160,7 @@ void Context::initExtensionString()
mExtensionString += "GL_ANGLE_framebuffer_multisample "; mExtensionString += "GL_ANGLE_framebuffer_multisample ";
} }
if (mBufferBackEnd->supportIntIndices()) if (supports32bitIndices())
{ {
mExtensionString += "GL_OES_element_index_uint "; mExtensionString += "GL_OES_element_index_uint ";
} }
......
...@@ -50,13 +50,12 @@ class Stencilbuffer; ...@@ -50,13 +50,12 @@ class Stencilbuffer;
class DepthStencilbuffer; class DepthStencilbuffer;
class VertexDataManager; class VertexDataManager;
class IndexDataManager; class IndexDataManager;
class BufferBackEnd;
class Blit; class Blit;
class Fence; class Fence;
enum 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_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_SM2 = 8,
MAX_VARYING_VECTORS_SM3 = 10, MAX_VARYING_VECTORS_SM3 = 10,
...@@ -86,32 +85,56 @@ struct Color ...@@ -86,32 +85,56 @@ struct Color
}; };
// Helper structure describing a single vertex attribute // Helper structure describing a single vertex attribute
class AttributeState class VertexAttribute
{ {
public: public:
AttributeState() VertexAttribute() : mType(GL_FLOAT), mSize(0), mNormalized(false), mStride(0), mPointer(NULL), mArrayEnabled(false)
: mType(GL_FLOAT), mSize(0), mNormalized(false), mStride(0), mPointer(NULL), mEnabled(false)
{ {
mCurrentValue[0] = 0; mCurrentValue[0] = 0.0f;
mCurrentValue[1] = 0; mCurrentValue[1] = 0.0f;
mCurrentValue[2] = 0; mCurrentValue[2] = 0.0f;
mCurrentValue[3] = 1; 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; GLenum mType;
GLint mSize; GLint mSize;
bool mNormalized; bool mNormalized;
GLsizei mStride; // 0 means natural stride GLsizei mStride; // 0 means natural stride
const void *mPointer;
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 // Helper structure to store all raw state
struct State struct State
{ {
...@@ -188,7 +211,7 @@ struct State ...@@ -188,7 +211,7 @@ struct State
BindingPointer<Renderbuffer> renderbuffer; BindingPointer<Renderbuffer> renderbuffer;
GLuint currentProgram; GLuint currentProgram;
AttributeState vertexAttribute[MAX_VERTEX_ATTRIBS]; VertexAttribute vertexAttribute[MAX_VERTEX_ATTRIBS];
BindingPointer<Texture> samplerTexture[SAMPLER_TYPE_COUNT][MAX_TEXTURE_IMAGE_UNITS]; BindingPointer<Texture> samplerTexture[SAMPLER_TYPE_COUNT][MAX_TEXTURE_IMAGE_UNITS];
GLint unpackAlignment; GLint unpackAlignment;
...@@ -283,13 +306,13 @@ class Context ...@@ -283,13 +306,13 @@ class Context
GLuint getArrayBufferHandle() const; GLuint getArrayBufferHandle() const;
void setVertexAttribEnabled(unsigned int attribNum, bool enabled); void setEnableVertexAttribArray(unsigned int attribNum, bool enabled);
const AttributeState &getVertexAttribState(unsigned int attribNum); const VertexAttribute &getVertexAttribState(unsigned int attribNum);
void setVertexAttribState(unsigned int attribNum, Buffer *boundBuffer, GLint size, GLenum type, void setVertexAttribState(unsigned int attribNum, Buffer *boundBuffer, GLint size, GLenum type,
bool normalized, GLsizei stride, const void *pointer); bool normalized, GLsizei stride, const void *pointer);
const void *getVertexAttribPointer(unsigned int attribNum) const; const void *getVertexAttribPointer(unsigned int attribNum) const;
const AttributeState *getVertexAttribBlock(); const VertexAttributeArray &getVertexAttributes();
void setUnpackAlignment(GLint alignment); void setUnpackAlignment(GLint alignment);
GLint getUnpackAlignment() const; GLint getUnpackAlignment() const;
...@@ -359,10 +382,8 @@ class Context ...@@ -359,10 +382,8 @@ class Context
bool applyRenderTarget(bool ignoreViewport); bool applyRenderTarget(bool ignoreViewport);
void applyState(GLenum drawMode); void applyState(GLenum drawMode);
GLenum applyVertexBuffer(GLenum mode, GLint first, GLsizei count, bool *useIndexing, TranslatedIndexData *indexInfo); GLenum applyVertexBuffer(GLint first, GLsizei count);
GLenum applyVertexBuffer(const TranslatedIndexData &indexInfo);
GLenum applyIndexBuffer(const void *indices, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo); GLenum applyIndexBuffer(const void *indices, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo);
GLenum applyCountingIndexBuffer(GLenum mode, GLenum count, TranslatedIndexData *indexInfo);
void applyShaders(); void applyShaders();
void applyTextures(); void applyTextures();
...@@ -401,6 +422,7 @@ class Context ...@@ -401,6 +422,7 @@ class Context
bool supportsHalfFloatRenderableTextures() const; bool supportsHalfFloatRenderableTextures() const;
bool supportsLuminanceTextures() const; bool supportsLuminanceTextures() const;
bool supportsLuminanceAlphaTextures() const; bool supportsLuminanceAlphaTextures() const;
bool supports32bitIndices() const;
void blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, void blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
...@@ -432,7 +454,6 @@ class Context ...@@ -432,7 +454,6 @@ class Context
BindingPointer<Texture2D> mTexture2DZero; BindingPointer<Texture2D> mTexture2DZero;
BindingPointer<TextureCubeMap> mTextureCubeMapZero; BindingPointer<TextureCubeMap> mTextureCubeMapZero;
typedef std::map<GLuint, Framebuffer*> FramebufferMap; typedef std::map<GLuint, Framebuffer*> FramebufferMap;
FramebufferMap mFramebufferMap; FramebufferMap mFramebufferMap;
...@@ -442,7 +463,6 @@ class Context ...@@ -442,7 +463,6 @@ class Context
void initExtensionString(); void initExtensionString();
std::string mExtensionString; std::string mExtensionString;
BufferBackEnd *mBufferBackEnd;
VertexDataManager *mVertexDataManager; VertexDataManager *mVertexDataManager;
IndexDataManager *mIndexDataManager; IndexDataManager *mIndexDataManager;
...@@ -482,6 +502,7 @@ class Context ...@@ -482,6 +502,7 @@ class Context
bool mSupportsHalfFloatRenderableTextures; bool mSupportsHalfFloatRenderableTextures;
bool mSupportsLuminanceTextures; bool mSupportsLuminanceTextures;
bool mSupportsLuminanceAlphaTextures; bool mSupportsLuminanceAlphaTextures;
bool mSupports32bitIndices;
// state caching flags // state caching flags
bool mClearStateDirty; bool mClearStateDirty;
......
...@@ -13,7 +13,6 @@ ...@@ -13,7 +13,6 @@
#include "libGLESv2/Buffer.h" #include "libGLESv2/Buffer.h"
#include "libGLESv2/mathutil.h" #include "libGLESv2/mathutil.h"
#include "libGLESv2/geometry/backend.h"
namespace namespace
{ {
...@@ -23,254 +22,352 @@ namespace ...@@ -23,254 +22,352 @@ namespace
namespace gl namespace gl
{ {
IndexDataManager::IndexDataManager(Context *context, BufferBackEnd *backend) IndexDataManager::IndexDataManager(Context *context, IDirect3DDevice9 *device) : mDevice(device)
: mContext(context), mBackend(backend), mIntIndicesSupported(backend->supportIntIndices())
{ {
mCountingBuffer = NULL; mStreamingBufferShort = new StreamingIndexBuffer(mDevice, INITIAL_INDEX_BUFFER_SIZE, D3DFMT_INDEX16);
mCountingBufferSize = 0;
mLineLoopBuffer = NULL; if (context->supports32bitIndices())
mStreamBufferShort = mBackend->createIndexBuffer(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_SHORT);
if (mIntIndicesSupported)
{ {
mStreamBufferInt = mBackend->createIndexBuffer(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_INT); mStreamingBufferInt = new StreamingIndexBuffer(mDevice, INITIAL_INDEX_BUFFER_SIZE, D3DFMT_INDEX32);
} }
else else
{ {
mStreamBufferInt = NULL; mStreamingBufferInt = NULL;
} }
} }
IndexDataManager::~IndexDataManager() IndexDataManager::~IndexDataManager()
{ {
delete mStreamBufferShort; delete mStreamingBufferShort;
delete mStreamBufferInt; delete mStreamingBufferInt;
delete mCountingBuffer;
delete mLineLoopBuffer;
} }
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> for (GLsizei i = 0; i < count; i++)
void copyIndices(const InputIndexType *in, GLsizei count, OutputIndexType *out, GLuint *minIndex, GLuint *maxIndex) {
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; *minIndex = indices[0];
GLuint minIndexSoFar = first; *maxIndex = indices[0];
GLuint maxIndexSoFar = first;
for (GLsizei i = 0; i < count; i++) for (GLsizei i = 0; i < count; i++)
{ {
if (minIndexSoFar > *in) minIndexSoFar = *in; if (*minIndex > indices[i]) *minIndex = indices[i];
if (maxIndexSoFar < *in) maxIndexSoFar = *in; if (*maxIndex < indices[i]) *maxIndex = indices[i];
*out++ = *in++;
} }
// 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); D3DFORMAT format = (type == GL_UNSIGNED_INT) ? D3DFMT_INDEX32 : D3DFMT_INDEX16;
ASSERT(count > 0); 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; return GL_INVALID_OPERATION;
} }
indices = static_cast<const GLubyte*>(arrayElementBuffer->data()) + offset; indices = static_cast<const GLubyte*>(buffer->data()) + offset;
} }
translated->count = count; StreamingIndexBuffer *streamingBuffer = (type == GL_UNSIGNED_INT) ? mStreamingBufferInt : mStreamingBufferShort;
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;
}
translated->buffer = streamIb; StaticIndexBuffer *staticBuffer = buffer ? buffer->getIndexBuffer() : NULL;
translated->offset = offset; IndexBuffer *indexBuffer = streamingBuffer;
translated->indexSize = indexSize(type); UINT streamOffset = 0;
if (type == GL_UNSIGNED_BYTE) if (staticBuffer && staticBuffer->lookupType(type) && alignedOffset)
{ {
const GLubyte *in = static_cast<const GLubyte*>(indices); indexBuffer = staticBuffer;
GLushort *out = static_cast<GLushort*>(output); 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); if (staticBuffer->size() == 0 && alignedOffset)
{
copyIndices(in, count, out, &translated->minIndex, &translated->maxIndex); 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; 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 std::size_t IndexDataManager::typeSize(GLenum type) const
{ {
switch (type) switch (type)
{ {
case GL_UNSIGNED_INT: return sizeof(GLuint); case GL_UNSIGNED_INT: return sizeof(GLuint);
case GL_UNSIGNED_SHORT: return sizeof(GLushort); 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) if (mIndexBuffer)
{ {
mStreamBufferInt = streamIb; HRESULT result = mIndexBuffer->Lock(mWritePosition, requiredSpace, &mapPtr, D3DLOCK_NOOVERWRITE);
}
else 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 (requiredSpace > mBufferSize)
if (mode == GL_LINE_LOOP)
{ {
// For line loops, create a single-use buffer that runs 0 - count-1, 0. if (mIndexBuffer)
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)
{ {
ERR(" failed to map index buffer."); mIndexBuffer->Release();
return GL_OUT_OF_MEMORY; 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; mWritePosition = 0;
mLineLoopBuffer->unmap();
indexInfo->buffer = mLineLoopBuffer;
indexInfo->count = count + 1;
indexInfo->maxIndex = count - 1;
} }
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; void *StaticIndexBuffer::map(UINT requiredSpace, UINT *offset)
mCountingBuffer = mBackend->createIndexBuffer(count * sizeof(unsigned short), GL_UNSIGNED_SHORT); {
void *mapPtr = NULL;
unsigned short *indices = static_cast<unsigned short *>(mCountingBuffer->map()); if (mIndexBuffer)
if (indices == NULL) {
HRESULT result = mIndexBuffer->Lock(0, requiredSpace, &mapPtr, 0);
if (FAILED(result))
{ {
ERR(" failed to map index buffer."); ERR(" Lock failed with error 0x%08x", result);
return GL_OUT_OF_MEMORY; 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(); mBufferSize = requiredSpace;
mCacheType = type;
indexInfo->buffer = mCountingBuffer;
indexInfo->count = count;
indexInfo->maxIndex = count - 1;
} }
else else if (mIndexBuffer && mBufferSize >= requiredSpace && mCacheType == type)
{ {
indexInfo->buffer = mCountingBuffer; // Already allocated
indexInfo->count = count;
indexInfo->maxIndex = count - 1;
} }
else UNREACHABLE(); // Static index buffers can't be resized
}
indexInfo->indexSize = sizeof(unsigned short); bool StaticIndexBuffer::lookupType(GLenum type)
indexInfo->minIndex = 0; {
indexInfo->offset = 0; 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 @@ ...@@ -10,7 +10,7 @@
#ifndef LIBGLESV2_GEOMETRY_INDEXDATAMANAGER_H_ #ifndef LIBGLESV2_GEOMETRY_INDEXDATAMANAGER_H_
#define LIBGLESV2_GEOMETRY_INDEXDATAMANAGER_H_ #define LIBGLESV2_GEOMETRY_INDEXDATAMANAGER_H_
#include <bitset> #include <vector>
#include <cstddef> #include <cstddef>
#define GL_APICALL #define GL_APICALL
...@@ -21,49 +21,98 @@ ...@@ -21,49 +21,98 @@
namespace gl namespace gl
{ {
class Buffer;
class BufferBackEnd;
class TranslatedIndexBuffer;
struct FormatConverter;
struct TranslatedIndexData struct TranslatedIndexData
{ {
GLuint minIndex; UINT minIndex;
GLuint maxIndex; UINT maxIndex;
GLuint count; UINT startIndex;
GLuint indexSize;
TranslatedIndexBuffer *buffer; IDirect3DIndexBuffer9 *indexBuffer;
GLsizei offset;
}; };
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: public:
IndexDataManager(Context *context, BufferBackEnd *backend); explicit StaticIndexBuffer(IDirect3DDevice9 *device);
~IndexDataManager(); ~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); bool lookupType(GLenum type);
GLenum preRenderValidateUnindexed(GLenum mode, GLsizei count, TranslatedIndexData *indexInfo); 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: private:
std::size_t IndexDataManager::typeSize(GLenum type) const; GLenum mCacheType;
std::size_t IndexDataManager::indexSize(GLenum type) const;
std::size_t spaceRequired(GLenum type, GLsizei count) const; struct IndexRange
TranslatedIndexBuffer *prepareIndexBuffer(GLenum type, std::size_t requiredSpace); {
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; GLenum prepareIndexData(GLenum type, GLsizei count, Buffer *arrayElementBuffer, const void *indices, TranslatedIndexData *translated);
BufferBackEnd *mBackend;
bool mIntIndicesSupported; private:
DISALLOW_COPY_AND_ASSIGN(IndexDataManager);
TranslatedIndexBuffer *mStreamBufferShort; std::size_t typeSize(GLenum type) const;
TranslatedIndexBuffer *mStreamBufferInt; std::size_t indexSize(D3DFORMAT format) const;
TranslatedIndexBuffer *mCountingBuffer; IDirect3DDevice9 *const mDevice;
GLsizei mCountingBufferSize;
TranslatedIndexBuffer *mLineLoopBuffer; StreamingIndexBuffer *mStreamingBufferShort;
StreamingIndexBuffer *mStreamingBufferInt;
}; };
} }
......
...@@ -9,14 +9,12 @@ ...@@ -9,14 +9,12 @@
#include "libGLESv2/geometry/VertexDataManager.h" #include "libGLESv2/geometry/VertexDataManager.h"
#include <limits>
#include "common/debug.h" #include "common/debug.h"
#include "libGLESv2/Buffer.h" #include "libGLESv2/Buffer.h"
#include "libGLESv2/Program.h" #include "libGLESv2/Program.h"
#include "libGLESv2/geometry/backend.h" #include "libGLESv2/geometry/vertexconversion.h"
#include "libGLESv2/geometry/IndexDataManager.h" #include "libGLESv2/geometry/IndexDataManager.h"
namespace namespace
...@@ -27,252 +25,729 @@ namespace ...@@ -27,252 +25,729 @@ namespace
namespace gl namespace gl
{ {
VertexDataManager::VertexDataManager(Context *context, BufferBackEnd *backend) VertexDataManager::VertexDataManager(Context *context, IDirect3DDevice9 *device) : mContext(context), mDevice(device)
: mContext(context), mBackend(backend), mDirtyCurrentValues(true), mCurrentValueOffset(0)
{ {
mStreamBuffer = mBackend->createVertexBuffer(INITIAL_STREAM_BUFFER_SIZE); for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
try
{
mCurrentValueBuffer = mBackend->createVertexBufferForStrideZero(4 * sizeof(float) * MAX_VERTEX_ATTRIBS);
}
catch (...)
{ {
delete mStreamBuffer; mDirtyCurrentValue[i] = true;
throw; mCurrentValueBuffer[i] = NULL;
} }
const D3DCAPS9 &caps = context->getDeviceCaps();
checkVertexCaps(caps.DeclTypes);
mStreamingBuffer = new StreamingVertexBuffer(mDevice, INITIAL_STREAM_BUFFER_SIZE);
} }
VertexDataManager::~VertexDataManager() VertexDataManager::~VertexDataManager()
{ {
delete mStreamBuffer; delete mStreamingBuffer;
delete mCurrentValueBuffer;
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, GLenum VertexDataManager::prepareVertexData(GLint start, GLsizei count, TranslatedAttribute *translated)
TranslatedAttribute *translated)
{ {
GLenum error = GL_NO_ERROR; GLenum error = GL_NO_ERROR;
const AttributeState *attribs = mContext->getVertexAttribBlock(); const VertexAttributeArray &attribs = mContext->getVertexAttributes();
const std::bitset<MAX_VERTEX_ATTRIBS> activeAttribs = getActiveAttribs(); 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++) 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; StaticVertexBuffer *staticBuffer = buffer ? buffer->getVertexBuffer() : NULL;
break;
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. // Invalidate static buffers if the attribute formats no longer match
// Process array attributes.
std::size_t requiredSpace = 0;
for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++) 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; vertexBuffer->reserveRequiredSpace();
mStreamBuffer = newStreamBuffer; }
} }
mStreamBuffer->reserveSpace(requiredSpace); // Perform the vertex data translations
for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
for (size_t 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; if (attribs[i].mArrayEnabled)
translated[i].type = attribs[i].mType; {
translated[i].size = attribs[i].mSize; if (!buffer && attribs[i].mPointer == NULL)
translated[i].normalized = attribs[i].mNormalized; {
translated[i].stride = formatConverter.outputVertexSize; // This is an application error that would normally result in a crash, but we catch it and return an error
translated[i].buffer = mStreamBuffer; ERR("An enabled vertex array has no buffer and no pointer.");
return GL_INVALID_OPERATION;
}
size_t inputStride = interpretGlStride(attribs[i]); const FormatConverter &converter = formatConverter(attribs[i]);
size_t elementSize = typeSize(attribs[i].mType) * attribs[i].mSize;
void *output = mStreamBuffer->map(spaceRequired(attribs[i], count), &translated[i].offset); StaticVertexBuffer *staticBuffer = buffer ? buffer->getVertexBuffer() : NULL;
if (output == NULL) ArrayVertexBuffer *vertexBuffer = staticBuffer ? staticBuffer : static_cast<ArrayVertexBuffer*>(mStreamingBuffer);
{
ERR(" failed to map vertex buffer.");
return GL_OUT_OF_MEMORY;
}
const void *input; UINT streamOffset = -1;
if (attribs[i].mBoundBuffer.get())
{ if (staticBuffer)
Buffer *buffer = attribs[i].mBoundBuffer.get(); {
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 (streamOffset != -1)
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. streamOffset += (start + attribs[i].mOffset / attribs[i].stride()) * converter.outputElementSize;
|| 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) }
else
{ {
mStreamBuffer->unmap(); streamOffset = writeAttributeData(mStreamingBuffer, start, count, attribs[i]);
return GL_INVALID_OPERATION;
} }
if (offset + inputStride * (start + count - 1) + elementSize > buffer->size()) if (streamOffset == -1)
{ {
mStreamBuffer->unmap(); return GL_OUT_OF_MEMORY;
return GL_INVALID_OPERATION;
} }
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 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) translated[i].type = D3DDECLTYPE_FLOAT4;
{ translated[i].stride = 0;
memcpy(output, input, count * inputStride); 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); mVertexBuffer->Unlock();
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);
} }
} }
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). ConstantVertexBuffer::ConstantVertexBuffer(IDirect3DDevice9 *device, float x, float y, float z, float w) : VertexBuffer(device, 4 * sizeof(float), D3DUSAGE_WRITEONLY)
// 0 rounds up to 0.
std::size_t VertexDataManager::roundUp(std::size_t x, std::size_t multiple) const
{ {
ASSERT(x >= 0); void *buffer = NULL;
ASSERT(multiple > 0);
std::size_t remainder = x % multiple; if (mVertexBuffer)
if (remainder != 0)
{ {
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)); mWritePosition = 0;
if (currentValues == NULL) }
else if (mWritePosition + mRequiredSpace > mBufferSize) // Recycle
{
if (mVertexBuffer)
{ {
ERR(" failed to map vertex buffer."); void *dummy;
return GL_OUT_OF_MEMORY; 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.) ERR("Lock failed with error 0x%08x", result);
currentValues[i*4+0] = attribs[i].mCurrentValue[0]; return NULL;
currentValues[i*4+1] = attribs[i].mCurrentValue[1];
currentValues[i*4+2] = attribs[i].mCurrentValue[2];
currentValues[i*4+3] = attribs[i].mCurrentValue[3];
} }
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; mRequiredSpace = 0;
translated[i].size = 4; }
translated[i].normalized = false;
translated[i].stride = 0; UINT StaticVertexBuffer::lookupAttribute(const VertexAttribute &attribute)
translated[i].offset = mCurrentValueOffset + 4 * sizeof(float) * i; {
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 @@ ...@@ -10,7 +10,7 @@
#ifndef LIBGLESV2_GEOMETRY_VERTEXDATAMANAGER_H_ #ifndef LIBGLESV2_GEOMETRY_VERTEXDATAMANAGER_H_
#define LIBGLESV2_GEOMETRY_VERTEXDATAMANAGER_H_ #define LIBGLESV2_GEOMETRY_VERTEXDATAMANAGER_H_
#include <bitset> #include <vector>
#include <cstddef> #include <cstddef>
#define GL_APICALL #define GL_APICALL
...@@ -21,44 +21,148 @@ ...@@ -21,44 +21,148 @@
namespace gl namespace gl
{ {
class Buffer; struct TranslatedAttribute
class BufferBackEnd; {
class TranslatedVertexBuffer; bool active;
struct TranslatedAttribute;
struct FormatConverter; D3DDECLTYPE type;
struct TranslatedIndexData; 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 class VertexDataManager
{ {
public: public:
VertexDataManager(Context *context, BufferBackEnd *backend); VertexDataManager(Context *context, IDirect3DDevice9 *backend);
~VertexDataManager(); virtual ~VertexDataManager();
void dirtyCurrentValues() { mDirtyCurrentValues = true; } void dirtyCurrentValue(int index) { mDirtyCurrentValue[index] = true; }
GLenum preRenderValidate(GLint start, void setupAttributes(const TranslatedAttribute *attributes);
GLsizei count, GLenum prepareVertexData(GLint start, GLsizei count, TranslatedAttribute *outAttribs);
TranslatedAttribute *outAttribs);
private: 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; FormatConverter mAttributeTypes[NUM_GL_VERTEX_ATTRIB_TYPES][2][4]; // [GL types as enumerated by typeIndex()][normalized][size - 1]
std::size_t interpretGlStride(const AttributeState &attrib) const;
std::size_t roundUp(std::size_t x, std::size_t multiple) const; struct TranslationDescription
std::size_t spaceRequired(const AttributeState &attrib, std::size_t maxVertex) const; {
DWORD capsFlag;
FormatConverter preferredConversion;
FormatConverter fallbackConversion;
};
Context *mContext; // This table is used to generate mAttributeTypes.
BufferBackEnd *mBackend; 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; unsigned int typeIndex(GLenum type) const;
std::size_t mCurrentValueOffset; // Offset within mCurrentValueBuffer that the current attribute values were last loaded at. const FormatConverter &formatConverter(const VertexAttribute &attribute) const;
TranslatedVertexBuffer *mCurrentValueBuffer;
}; };
} }
......
//
// 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) ...@@ -1714,7 +1714,7 @@ void __stdcall glDisableVertexAttribArray(GLuint index)
if (context) if (context)
{ {
context->setVertexAttribEnabled(index, false); context->setEnableVertexAttribArray(index, false);
} }
} }
catch(std::bad_alloc&) catch(std::bad_alloc&)
...@@ -1759,20 +1759,25 @@ void __stdcall glDrawElements(GLenum mode, GLsizei count, GLenum type, const GLv ...@@ -1759,20 +1759,25 @@ void __stdcall glDrawElements(GLenum mode, GLsizei count, GLenum type, const GLv
return error(GL_INVALID_VALUE); 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(); gl::Context *context = gl::getContext();
if (context) 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); context->drawElements(mode, count, type, indices);
} }
} }
...@@ -1829,7 +1834,7 @@ void __stdcall glEnableVertexAttribArray(GLuint index) ...@@ -1829,7 +1834,7 @@ void __stdcall glEnableVertexAttribArray(GLuint index)
if (context) if (context)
{ {
context->setVertexAttribEnabled(index, true); context->setEnableVertexAttribArray(index, true);
} }
} }
catch(std::bad_alloc&) catch(std::bad_alloc&)
...@@ -3457,12 +3462,12 @@ void __stdcall glGetVertexAttribfv(GLuint index, GLenum pname, GLfloat* params) ...@@ -3457,12 +3462,12 @@ void __stdcall glGetVertexAttribfv(GLuint index, GLenum pname, GLfloat* params)
return error(GL_INVALID_VALUE); return error(GL_INVALID_VALUE);
} }
const gl::AttributeState &attribState = context->getVertexAttribState(index); const gl::VertexAttribute &attribState = context->getVertexAttribState(index);
switch (pname) switch (pname)
{ {
case GL_VERTEX_ATTRIB_ARRAY_ENABLED: case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
*params = (GLfloat)(attribState.mEnabled ? GL_TRUE : GL_FALSE); *params = (GLfloat)(attribState.mArrayEnabled ? GL_TRUE : GL_FALSE);
break; break;
case GL_VERTEX_ATTRIB_ARRAY_SIZE: case GL_VERTEX_ATTRIB_ARRAY_SIZE:
*params = (GLfloat)attribState.mSize; *params = (GLfloat)attribState.mSize;
...@@ -3510,12 +3515,12 @@ void __stdcall glGetVertexAttribiv(GLuint index, GLenum pname, GLint* params) ...@@ -3510,12 +3515,12 @@ void __stdcall glGetVertexAttribiv(GLuint index, GLenum pname, GLint* params)
return error(GL_INVALID_VALUE); return error(GL_INVALID_VALUE);
} }
const gl::AttributeState &attribState = context->getVertexAttribState(index); const gl::VertexAttribute &attribState = context->getVertexAttribState(index);
switch (pname) switch (pname)
{ {
case GL_VERTEX_ATTRIB_ARRAY_ENABLED: case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
*params = (attribState.mEnabled ? GL_TRUE : GL_FALSE); *params = (attribState.mArrayEnabled ? GL_TRUE : GL_FALSE);
break; break;
case GL_VERTEX_ATTRIB_ARRAY_SIZE: case GL_VERTEX_ATTRIB_ARRAY_SIZE:
*params = attribState.mSize; *params = attribState.mSize;
......
...@@ -248,14 +248,6 @@ ...@@ -248,14 +248,6 @@
Name="Geometry" Name="Geometry"
> >
<File <File
RelativePath=".\geometry\backend.cpp"
>
</File>
<File
RelativePath=".\geometry\dx9.cpp"
>
</File>
<File
RelativePath=".\geometry\IndexDataManager.cpp" RelativePath=".\geometry\IndexDataManager.cpp"
> >
</File> </File>
...@@ -342,14 +334,6 @@ ...@@ -342,14 +334,6 @@
Name="Geometry" Name="Geometry"
> >
<File <File
RelativePath=".\geometry\backend.h"
>
</File>
<File
RelativePath=".\geometry\dx9.h"
>
</File>
<File
RelativePath=".\geometry\IndexDataManager.h" RelativePath=".\geometry\IndexDataManager.h"
> >
</File> </File>
......
...@@ -707,46 +707,46 @@ unsigned int GetDepthSize(D3DFORMAT depthFormat) ...@@ -707,46 +707,46 @@ unsigned int GetDepthSize(D3DFORMAT depthFormat)
case D3DFMT_D16: return 16; case D3DFMT_D16: return 16;
case D3DFMT_D32F_LOCKABLE: return 32; case D3DFMT_D32F_LOCKABLE: return 32;
case D3DFMT_D24FS8: return 24; case D3DFMT_D24FS8: return 24;
// case D3DFMT_D32_LOCKABLE: return 32; // D3D9Ex only //case D3DFMT_D32_LOCKABLE: return 32; // D3D9Ex only
// case D3DFMT_S8_LOCKABLE: return 0; // D3D9Ex only //case D3DFMT_S8_LOCKABLE: return 0; // D3D9Ex only
default: default:
UNREACHABLE(); UNREACHABLE();
} }
return 0; return 0;
} }
bool ConvertPrimitiveType(GLenum primitiveType, GLsizei primitiveCount, bool ConvertPrimitiveType(GLenum primitiveType, GLsizei elementCount,
D3DPRIMITIVETYPE *d3dPrimitiveType, int *d3dPrimitiveCount) D3DPRIMITIVETYPE *d3dPrimitiveType, int *d3dPrimitiveCount)
{ {
switch (primitiveType) switch (primitiveType)
{ {
case GL_POINTS: case GL_POINTS:
*d3dPrimitiveType = D3DPT_POINTLIST; *d3dPrimitiveType = D3DPT_POINTLIST;
*d3dPrimitiveCount = primitiveCount; *d3dPrimitiveCount = elementCount;
break; break;
case GL_LINES: case GL_LINES:
*d3dPrimitiveType = D3DPT_LINELIST; *d3dPrimitiveType = D3DPT_LINELIST;
*d3dPrimitiveCount = primitiveCount / 2; *d3dPrimitiveCount = elementCount / 2;
break; break;
case GL_LINE_LOOP: case GL_LINE_LOOP:
*d3dPrimitiveType = D3DPT_LINESTRIP; *d3dPrimitiveType = D3DPT_LINESTRIP;
*d3dPrimitiveCount = primitiveCount; *d3dPrimitiveCount = elementCount - 1; // D3D doesn't support line loops, so we draw the last line separately
break; break;
case GL_LINE_STRIP: case GL_LINE_STRIP:
*d3dPrimitiveType = D3DPT_LINESTRIP; *d3dPrimitiveType = D3DPT_LINESTRIP;
*d3dPrimitiveCount = primitiveCount - 1; *d3dPrimitiveCount = elementCount - 1;
break; break;
case GL_TRIANGLES: case GL_TRIANGLES:
*d3dPrimitiveType = D3DPT_TRIANGLELIST; *d3dPrimitiveType = D3DPT_TRIANGLELIST;
*d3dPrimitiveCount = primitiveCount / 3; *d3dPrimitiveCount = elementCount / 3;
break; break;
case GL_TRIANGLE_STRIP: case GL_TRIANGLE_STRIP:
*d3dPrimitiveType = D3DPT_TRIANGLESTRIP; *d3dPrimitiveType = D3DPT_TRIANGLESTRIP;
*d3dPrimitiveCount = primitiveCount - 2; *d3dPrimitiveCount = elementCount - 2;
break; break;
case GL_TRIANGLE_FAN: case GL_TRIANGLE_FAN:
*d3dPrimitiveType = D3DPT_TRIANGLEFAN; *d3dPrimitiveType = D3DPT_TRIANGLEFAN;
*d3dPrimitiveCount = primitiveCount - 2; *d3dPrimitiveCount = elementCount - 2;
break; break;
default: default:
return false; return false;
......
...@@ -61,7 +61,7 @@ unsigned int GetGreenSize(D3DFORMAT colorFormat); ...@@ -61,7 +61,7 @@ unsigned int GetGreenSize(D3DFORMAT colorFormat);
unsigned int GetBlueSize(D3DFORMAT colorFormat); unsigned int GetBlueSize(D3DFORMAT colorFormat);
unsigned int GetDepthSize(D3DFORMAT depthFormat); unsigned int GetDepthSize(D3DFORMAT depthFormat);
unsigned int GetStencilSize(D3DFORMAT stencilFormat); unsigned int GetStencilSize(D3DFORMAT stencilFormat);
bool ConvertPrimitiveType(GLenum primitiveType, GLsizei primitiveCount, bool ConvertPrimitiveType(GLenum primitiveType, GLsizei elementCount,
D3DPRIMITIVETYPE *d3dPrimitiveType, int *d3dPrimitiveCount); D3DPRIMITIVETYPE *d3dPrimitiveType, int *d3dPrimitiveCount);
D3DFORMAT ConvertRenderbufferFormat(GLenum format); D3DFORMAT ConvertRenderbufferFormat(GLenum format);
D3DMULTISAMPLE_TYPE GetMultisampleTypeFromSamples(GLsizei samples); 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