You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
604 lines
19 KiB
604 lines
19 KiB
/*-------------------------------------------------------------------------
|
|
* drawElements Quality Program OpenGL Utilities
|
|
* ---------------------------------------------
|
|
*
|
|
* Copyright 2014 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*
|
|
*//*!
|
|
* \file
|
|
* \brief Draw call utilities.
|
|
*//*--------------------------------------------------------------------*/
|
|
|
|
#include "gluDrawUtil.hpp"
|
|
#include "gluRenderContext.hpp"
|
|
#include "gluObjectWrapper.hpp"
|
|
#include "glwFunctions.hpp"
|
|
#include "glwEnums.hpp"
|
|
#include "deInt32.h"
|
|
#include "deMemory.h"
|
|
|
|
#include <vector>
|
|
#include <set>
|
|
#include <iterator>
|
|
|
|
namespace glu
|
|
{
|
|
namespace
|
|
{
|
|
|
|
struct VertexAttributeDescriptor
|
|
{
|
|
int location;
|
|
VertexComponentType componentType;
|
|
VertexComponentConversion convert;
|
|
int numComponents;
|
|
int numElements;
|
|
int stride; //!< Stride or 0 if using default stride.
|
|
const void* pointer; //!< Pointer or offset.
|
|
|
|
VertexAttributeDescriptor (int location_,
|
|
VertexComponentType componentType_,
|
|
VertexComponentConversion convert_,
|
|
int numComponents_,
|
|
int numElements_,
|
|
int stride_,
|
|
const void* pointer_)
|
|
: location (location_)
|
|
, componentType (componentType_)
|
|
, convert (convert_)
|
|
, numComponents (numComponents_)
|
|
, numElements (numElements_)
|
|
, stride (stride_)
|
|
, pointer (pointer_)
|
|
{
|
|
}
|
|
|
|
VertexAttributeDescriptor (void)
|
|
: location (0)
|
|
, componentType (VTX_COMP_TYPE_LAST)
|
|
, convert (VTX_COMP_CONVERT_LAST)
|
|
, numComponents (0)
|
|
, numElements (0)
|
|
, stride (0)
|
|
, pointer (0)
|
|
{
|
|
}
|
|
};
|
|
|
|
struct VertexBufferLayout
|
|
{
|
|
int size;
|
|
std::vector<VertexAttributeDescriptor> attributes;
|
|
|
|
VertexBufferLayout (int size_ = 0)
|
|
: size(size_)
|
|
{
|
|
}
|
|
};
|
|
|
|
struct VertexBufferDescriptor
|
|
{
|
|
deUint32 buffer;
|
|
std::vector<VertexAttributeDescriptor> attributes;
|
|
|
|
VertexBufferDescriptor (deUint32 buffer_ = 0)
|
|
: buffer(buffer_)
|
|
{
|
|
}
|
|
};
|
|
|
|
class VertexBuffer : public Buffer
|
|
{
|
|
public:
|
|
enum Type
|
|
{
|
|
TYPE_PLANAR = 0, //!< Data for each vertex array resides in a separate contiguous block in buffer.
|
|
TYPE_STRIDED, //!< Vertex arrays are interleaved.
|
|
|
|
TYPE_LAST
|
|
};
|
|
|
|
VertexBuffer (const RenderContext& context, int numBindings, const VertexArrayBinding* bindings, Type type = TYPE_PLANAR);
|
|
~VertexBuffer (void);
|
|
|
|
const VertexBufferDescriptor& getDescriptor (void) const { return m_layout; }
|
|
|
|
private:
|
|
VertexBuffer (const VertexBuffer& other);
|
|
VertexBuffer& operator= (const VertexBuffer& other);
|
|
|
|
VertexBufferDescriptor m_layout;
|
|
};
|
|
|
|
class IndexBuffer : public Buffer
|
|
{
|
|
public:
|
|
IndexBuffer (const RenderContext& context, IndexType indexType, int numIndices, const void* indices);
|
|
~IndexBuffer (void);
|
|
|
|
private:
|
|
IndexBuffer (const IndexBuffer& other);
|
|
IndexBuffer& operator= (const IndexBuffer& other);
|
|
};
|
|
|
|
static deUint32 getVtxCompGLType (VertexComponentType type)
|
|
{
|
|
switch (type)
|
|
{
|
|
case VTX_COMP_UNSIGNED_INT8: return GL_UNSIGNED_BYTE;
|
|
case VTX_COMP_UNSIGNED_INT16: return GL_UNSIGNED_SHORT;
|
|
case VTX_COMP_UNSIGNED_INT32: return GL_UNSIGNED_INT;
|
|
case VTX_COMP_SIGNED_INT8: return GL_BYTE;
|
|
case VTX_COMP_SIGNED_INT16: return GL_SHORT;
|
|
case VTX_COMP_SIGNED_INT32: return GL_INT;
|
|
case VTX_COMP_FIXED: return GL_FIXED;
|
|
case VTX_COMP_HALF_FLOAT: return GL_HALF_FLOAT;
|
|
case VTX_COMP_FLOAT: return GL_FLOAT;
|
|
default:
|
|
DE_ASSERT(false);
|
|
return GL_NONE;
|
|
}
|
|
}
|
|
|
|
static int getVtxCompSize (VertexComponentType type)
|
|
{
|
|
switch (type)
|
|
{
|
|
case VTX_COMP_UNSIGNED_INT8: return 1;
|
|
case VTX_COMP_UNSIGNED_INT16: return 2;
|
|
case VTX_COMP_UNSIGNED_INT32: return 4;
|
|
case VTX_COMP_SIGNED_INT8: return 1;
|
|
case VTX_COMP_SIGNED_INT16: return 2;
|
|
case VTX_COMP_SIGNED_INT32: return 4;
|
|
case VTX_COMP_FIXED: return 4;
|
|
case VTX_COMP_HALF_FLOAT: return 2;
|
|
case VTX_COMP_FLOAT: return 4;
|
|
default:
|
|
DE_ASSERT(false);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static deUint32 getIndexGLType (IndexType type)
|
|
{
|
|
switch (type)
|
|
{
|
|
case INDEXTYPE_UINT8: return GL_UNSIGNED_BYTE;
|
|
case INDEXTYPE_UINT16: return GL_UNSIGNED_SHORT;
|
|
case INDEXTYPE_UINT32: return GL_UNSIGNED_INT;
|
|
default:
|
|
DE_ASSERT(false);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static int getIndexSize (IndexType type)
|
|
{
|
|
switch (type)
|
|
{
|
|
case INDEXTYPE_UINT8: return 1;
|
|
case INDEXTYPE_UINT16: return 2;
|
|
case INDEXTYPE_UINT32: return 4;
|
|
default:
|
|
DE_ASSERT(false);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static deUint32 getPrimitiveGLType (PrimitiveType type)
|
|
{
|
|
switch (type)
|
|
{
|
|
case PRIMITIVETYPE_TRIANGLES: return GL_TRIANGLES;
|
|
case PRIMITIVETYPE_TRIANGLE_STRIP: return GL_TRIANGLE_STRIP;
|
|
case PRIMITIVETYPE_TRIANGLE_FAN: return GL_TRIANGLE_FAN;
|
|
case PRIMITIVETYPE_LINES: return GL_LINES;
|
|
case PRIMITIVETYPE_LINE_STRIP: return GL_LINE_STRIP;
|
|
case PRIMITIVETYPE_LINE_LOOP: return GL_LINE_LOOP;
|
|
case PRIMITIVETYPE_POINTS: return GL_POINTS;
|
|
case PRIMITIVETYPE_PATCHES: return GL_PATCHES;
|
|
default:
|
|
DE_ASSERT(false);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
//! Lower named bindings to locations and eliminate bindings that are not used by program.
|
|
template<typename InputIter, typename OutputIter>
|
|
static OutputIter namedBindingsToProgramLocations (const glw::Functions& gl, deUint32 program, InputIter first, InputIter end, OutputIter out)
|
|
{
|
|
for (InputIter cur = first; cur != end; ++cur)
|
|
{
|
|
const BindingPoint& binding = cur->binding;
|
|
if (binding.type == BindingPoint::BPTYPE_NAME)
|
|
{
|
|
DE_ASSERT(binding.location >= 0);
|
|
int location = gl.getAttribLocation(program, binding.name.c_str());
|
|
if (location >= 0)
|
|
{
|
|
// Add binding.location as an offset to accommodate matrices.
|
|
*out = VertexArrayBinding(BindingPoint(location + binding.location), cur->pointer);
|
|
++out;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
*out = *cur;
|
|
++out;
|
|
}
|
|
}
|
|
|
|
return out;
|
|
}
|
|
|
|
static deUint32 getMinimumAlignment (const VertexArrayPointer& pointer)
|
|
{
|
|
// \todo [2013-05-07 pyry] What is the actual min?
|
|
DE_UNREF(pointer);
|
|
return (deUint32)sizeof(float);
|
|
}
|
|
|
|
template<typename BindingIter>
|
|
static bool areVertexArrayLocationsValid (BindingIter first, BindingIter end)
|
|
{
|
|
std::set<int> usedLocations;
|
|
for (BindingIter cur = first; cur != end; ++cur)
|
|
{
|
|
const BindingPoint& binding = cur->binding;
|
|
|
|
if (binding.type != BindingPoint::BPTYPE_LOCATION)
|
|
return false;
|
|
|
|
if (usedLocations.find(binding.location) != usedLocations.end())
|
|
return false;
|
|
|
|
usedLocations.insert(binding.location);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// \todo [2013-05-08 pyry] Buffer upload should try to match pointers to reduce dataset size.
|
|
|
|
static void appendAttributeNonStrided (VertexBufferLayout& layout, const VertexArrayBinding& va)
|
|
{
|
|
const int offset = deAlign32(layout.size, getMinimumAlignment(va.pointer));
|
|
const int elementSize = getVtxCompSize(va.pointer.componentType)*va.pointer.numComponents;
|
|
const int size = elementSize*va.pointer.numElements;
|
|
|
|
// Must be assigned to location at this point.
|
|
DE_ASSERT(va.binding.type == BindingPoint::BPTYPE_LOCATION);
|
|
|
|
layout.attributes.push_back(VertexAttributeDescriptor(va.binding.location,
|
|
va.pointer.componentType,
|
|
va.pointer.convert,
|
|
va.pointer.numComponents,
|
|
va.pointer.numElements,
|
|
0, // default stride
|
|
(const void*)(deUintptr)offset));
|
|
layout.size = offset+size;
|
|
}
|
|
|
|
template<typename BindingIter>
|
|
static void computeNonStridedBufferLayout (VertexBufferLayout& layout, BindingIter first, BindingIter end)
|
|
{
|
|
for (BindingIter iter = first; iter != end; ++iter)
|
|
appendAttributeNonStrided(layout, *iter);
|
|
}
|
|
|
|
static void copyToLayout (void* dstBasePtr, const VertexAttributeDescriptor& dstVA, const VertexArrayPointer& srcPtr)
|
|
{
|
|
DE_ASSERT(dstVA.componentType == srcPtr.componentType &&
|
|
dstVA.numComponents == srcPtr.numComponents &&
|
|
dstVA.numElements == srcPtr.numElements);
|
|
|
|
const int elementSize = getVtxCompSize(dstVA.componentType)*dstVA.numComponents;
|
|
const bool srcHasCustomStride = srcPtr.stride != 0 && srcPtr.stride != elementSize;
|
|
const bool dstHasCustomStride = dstVA.stride != 0 && dstVA.stride != elementSize;
|
|
|
|
if (srcHasCustomStride || dstHasCustomStride)
|
|
{
|
|
const int dstStride = dstVA.stride != 0 ? dstVA.stride : elementSize;
|
|
const int srcStride = srcPtr.stride != 0 ? srcPtr.stride : elementSize;
|
|
|
|
for (int ndx = 0; ndx < dstVA.numElements; ndx++)
|
|
deMemcpy((deUint8*)dstBasePtr + (deUintptr)dstVA.pointer + ndx*dstStride, (const deUint8*)srcPtr.data + ndx*srcStride, elementSize);
|
|
}
|
|
else
|
|
deMemcpy((deUint8*)dstBasePtr + (deUintptr)dstVA.pointer, srcPtr.data, elementSize*dstVA.numElements);
|
|
}
|
|
|
|
void uploadBufferData (const glw::Functions& gl, deUint32 buffer, deUint32 usage, const VertexBufferLayout& layout, const VertexArrayPointer* srcArrays)
|
|
{
|
|
// Create temporary data buffer for upload.
|
|
std::vector<deUint8> localBuf(layout.size);
|
|
|
|
for (int attrNdx = 0; attrNdx < (int)layout.attributes.size(); ++attrNdx)
|
|
copyToLayout(&localBuf[0], layout.attributes[attrNdx], srcArrays[attrNdx]);
|
|
|
|
gl.bindBuffer(GL_ARRAY_BUFFER, buffer);
|
|
gl.bufferData(GL_ARRAY_BUFFER, (int)localBuf.size(), &localBuf[0], usage);
|
|
gl.bindBuffer(GL_ARRAY_BUFFER, 0);
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "Uploading buffer data failed");
|
|
}
|
|
|
|
// VertexBuffer
|
|
|
|
VertexBuffer::VertexBuffer (const RenderContext& context, int numBindings, const VertexArrayBinding* bindings, Type type)
|
|
: Buffer(context)
|
|
{
|
|
const glw::Functions& gl = context.getFunctions();
|
|
const deUint32 usage = GL_STATIC_DRAW;
|
|
VertexBufferLayout layout;
|
|
|
|
if (!areVertexArrayLocationsValid(bindings, bindings+numBindings))
|
|
throw tcu::TestError("Invalid vertex array locations");
|
|
|
|
if (type == TYPE_PLANAR)
|
|
computeNonStridedBufferLayout(layout, bindings, bindings+numBindings);
|
|
else
|
|
throw tcu::InternalError("Strided layout is not yet supported");
|
|
|
|
std::vector<VertexArrayPointer> srcPtrs(numBindings);
|
|
for (int ndx = 0; ndx < numBindings; ndx++)
|
|
srcPtrs[ndx] = bindings[ndx].pointer;
|
|
|
|
DE_ASSERT(srcPtrs.size() == layout.attributes.size());
|
|
if (!srcPtrs.empty())
|
|
uploadBufferData(gl, m_object, usage, layout, &srcPtrs[0]);
|
|
|
|
// Construct descriptor.
|
|
m_layout.buffer = m_object;
|
|
m_layout.attributes = layout.attributes;
|
|
}
|
|
|
|
VertexBuffer::~VertexBuffer (void)
|
|
{
|
|
}
|
|
|
|
// IndexBuffer
|
|
|
|
IndexBuffer::IndexBuffer (const RenderContext& context, IndexType indexType, int numIndices, const void* indices)
|
|
: Buffer(context)
|
|
{
|
|
const glw::Functions& gl = context.getFunctions();
|
|
const deUint32 usage = GL_STATIC_DRAW;
|
|
|
|
gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_object);
|
|
gl.bufferData(GL_ELEMENT_ARRAY_BUFFER, numIndices*getIndexSize(indexType), indices, usage);
|
|
gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "Uploading index data failed");
|
|
}
|
|
|
|
IndexBuffer::~IndexBuffer (void)
|
|
{
|
|
}
|
|
|
|
static inline VertexAttributeDescriptor getUserPointerDescriptor (const VertexArrayBinding& vertexArray)
|
|
{
|
|
DE_ASSERT(vertexArray.binding.type == BindingPoint::BPTYPE_LOCATION);
|
|
|
|
return VertexAttributeDescriptor(vertexArray.binding.location,
|
|
vertexArray.pointer.componentType,
|
|
vertexArray.pointer.convert,
|
|
vertexArray.pointer.numComponents,
|
|
vertexArray.pointer.numElements,
|
|
vertexArray.pointer.stride,
|
|
vertexArray.pointer.data);
|
|
}
|
|
|
|
//! Setup VA according to allocation spec. Assumes that other state (VAO binding, buffer) is set already.
|
|
static void setVertexAttribPointer (const glw::Functions& gl, const VertexAttributeDescriptor& va)
|
|
{
|
|
const bool isIntType = de::inRange<int>(va.componentType, VTX_COMP_UNSIGNED_INT8, VTX_COMP_SIGNED_INT32);
|
|
const bool isSpecialType = de::inRange<int>(va.componentType, VTX_COMP_FIXED, VTX_COMP_FLOAT);
|
|
const deUint32 compTypeGL = getVtxCompGLType(va.componentType);
|
|
|
|
DE_ASSERT(isIntType != isSpecialType); // Must be either int or special type.
|
|
DE_ASSERT(isIntType || va.convert == VTX_COMP_CONVERT_NONE); // Conversion allowed only for special types.
|
|
DE_UNREF(isSpecialType);
|
|
|
|
gl.enableVertexAttribArray(va.location);
|
|
|
|
if (isIntType && va.convert == VTX_COMP_CONVERT_NONE)
|
|
gl.vertexAttribIPointer(va.location, va.numComponents, compTypeGL, va.stride, va.pointer);
|
|
else
|
|
gl.vertexAttribPointer(va.location, va.numComponents, compTypeGL, va.convert == VTX_COMP_CONVERT_NORMALIZE_TO_FLOAT ? GL_TRUE : GL_FALSE, va.stride, va.pointer);
|
|
}
|
|
|
|
//! Setup vertex buffer and attributes.
|
|
static void setVertexBufferAttributes (const glw::Functions& gl, const VertexBufferDescriptor& buffer)
|
|
{
|
|
gl.bindBuffer(GL_ARRAY_BUFFER, buffer.buffer);
|
|
|
|
for (std::vector<VertexAttributeDescriptor>::const_iterator vaIter = buffer.attributes.begin(); vaIter != buffer.attributes.end(); ++vaIter)
|
|
setVertexAttribPointer(gl, *vaIter);
|
|
|
|
gl.bindBuffer(GL_ARRAY_BUFFER, 0);
|
|
}
|
|
|
|
static void disableVertexArrays (const glw::Functions& gl, const std::vector<VertexArrayBinding>& bindings)
|
|
{
|
|
for (std::vector<VertexArrayBinding>::const_iterator vaIter = bindings.begin(); vaIter != bindings.end(); ++vaIter)
|
|
{
|
|
DE_ASSERT(vaIter->binding.type == BindingPoint::BPTYPE_LOCATION);
|
|
gl.disableVertexAttribArray(vaIter->binding.location);
|
|
}
|
|
}
|
|
|
|
#if defined(DE_DEBUG)
|
|
static bool isProgramActive (const RenderContext& context, deUint32 program)
|
|
{
|
|
// \todo [2013-05-08 pyry] Is this query broken?
|
|
/* deUint32 activeProgram = 0;
|
|
context.getFunctions().getIntegerv(GL_ACTIVE_PROGRAM, (int*)&activeProgram);
|
|
GLU_EXPECT_NO_ERROR(context.getFunctions().getError(), "oh");
|
|
return activeProgram == program;*/
|
|
DE_UNREF(context);
|
|
DE_UNREF(program);
|
|
return true;
|
|
}
|
|
|
|
static bool isDrawCallValid (int numVertexArrays, const VertexArrayBinding* vertexArrays, const PrimitiveList& primitives)
|
|
{
|
|
if (numVertexArrays < 0)
|
|
return false;
|
|
|
|
if ((primitives.indexType == INDEXTYPE_LAST) != (primitives.indices == 0))
|
|
return false;
|
|
|
|
if (primitives.numElements < 0)
|
|
return false;
|
|
|
|
if (!primitives.indices)
|
|
{
|
|
for (int ndx = 0; ndx < numVertexArrays; ndx++)
|
|
{
|
|
if (primitives.numElements > vertexArrays[ndx].pointer.numElements)
|
|
return false;
|
|
}
|
|
}
|
|
// \todo [2013-05-08 pyry] We could walk whole index array and determine index range
|
|
|
|
return true;
|
|
}
|
|
#endif // DE_DEBUG
|
|
|
|
static inline void drawNonIndexed (const glw::Functions& gl, PrimitiveType type, int numElements)
|
|
{
|
|
deUint32 mode = getPrimitiveGLType(type);
|
|
gl.drawArrays(mode, 0, numElements);
|
|
}
|
|
|
|
static inline void drawIndexed (const glw::Functions& gl, PrimitiveType type, int numElements, IndexType indexType, const void* indexPtr)
|
|
{
|
|
deUint32 mode = getPrimitiveGLType(type);
|
|
deUint32 indexGLType = getIndexGLType(indexType);
|
|
|
|
gl.drawElements(mode, numElements, indexGLType, indexPtr);
|
|
}
|
|
|
|
} // anonymous
|
|
|
|
void drawFromUserPointers (const RenderContext& context, deUint32 program, int numVertexArrays, const VertexArrayBinding* vertexArrays, const PrimitiveList& primitives, DrawUtilCallback* callback)
|
|
{
|
|
const glw::Functions& gl = context.getFunctions();
|
|
std::vector<VertexArrayBinding> bindingsWithLocations;
|
|
|
|
DE_ASSERT(isDrawCallValid(numVertexArrays, vertexArrays, primitives));
|
|
DE_ASSERT(isProgramActive(context, program));
|
|
|
|
// Lower bindings to locations.
|
|
namedBindingsToProgramLocations(gl, program, vertexArrays, vertexArrays+numVertexArrays, std::inserter(bindingsWithLocations, bindingsWithLocations.begin()));
|
|
|
|
TCU_CHECK(areVertexArrayLocationsValid(bindingsWithLocations.begin(), bindingsWithLocations.end()));
|
|
|
|
// Set VA state.
|
|
for (std::vector<VertexArrayBinding>::const_iterator vaIter = bindingsWithLocations.begin(); vaIter != bindingsWithLocations.end(); ++vaIter)
|
|
setVertexAttribPointer(gl, getUserPointerDescriptor(*vaIter));
|
|
|
|
if (callback)
|
|
callback->beforeDrawCall();
|
|
|
|
if (primitives.indices)
|
|
drawIndexed(gl, primitives.type, primitives.numElements, primitives.indexType, primitives.indices);
|
|
else
|
|
drawNonIndexed(gl, primitives.type, primitives.numElements);
|
|
|
|
if (callback)
|
|
callback->afterDrawCall();
|
|
|
|
// Disable attribute arrays or otherwise someone later on might get crash thanks to invalid pointers.
|
|
disableVertexArrays(gl, bindingsWithLocations);
|
|
}
|
|
|
|
void drawFromBuffers (const RenderContext& context, deUint32 program, int numVertexArrays, const VertexArrayBinding* vertexArrays, const PrimitiveList& primitives, DrawUtilCallback* callback)
|
|
{
|
|
const glw::Functions& gl = context.getFunctions();
|
|
std::vector<VertexArrayBinding> bindingsWithLocations;
|
|
|
|
DE_ASSERT(isDrawCallValid(numVertexArrays, vertexArrays, primitives));
|
|
DE_ASSERT(isProgramActive(context, program));
|
|
|
|
// Lower bindings to locations.
|
|
namedBindingsToProgramLocations(gl, program, vertexArrays, vertexArrays+numVertexArrays, std::inserter(bindingsWithLocations, bindingsWithLocations.begin()));
|
|
|
|
TCU_CHECK(areVertexArrayLocationsValid(bindingsWithLocations.begin(), bindingsWithLocations.end()));
|
|
|
|
// Create buffers for duration of draw call.
|
|
{
|
|
VertexBuffer vertexBuffer (context, (int)bindingsWithLocations.size(), (bindingsWithLocations.empty()) ? (DE_NULL) : (&bindingsWithLocations[0]));
|
|
|
|
// Set state.
|
|
setVertexBufferAttributes(gl, vertexBuffer.getDescriptor());
|
|
|
|
if (primitives.indices)
|
|
{
|
|
IndexBuffer indexBuffer(context, primitives.indexType, primitives.numElements, primitives.indices);
|
|
|
|
gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, *indexBuffer);
|
|
|
|
if (callback)
|
|
callback->beforeDrawCall();
|
|
|
|
drawIndexed(gl, primitives.type, primitives.numElements, primitives.indexType, 0);
|
|
|
|
if (callback)
|
|
callback->afterDrawCall();
|
|
|
|
gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
|
}
|
|
else
|
|
{
|
|
if (callback)
|
|
callback->beforeDrawCall();
|
|
|
|
drawNonIndexed(gl, primitives.type, primitives.numElements);
|
|
|
|
if (callback)
|
|
callback->afterDrawCall();
|
|
}
|
|
}
|
|
|
|
// Disable attribute arrays or otherwise someone later on might get crash thanks to invalid pointers.
|
|
for (std::vector<VertexArrayBinding>::const_iterator vaIter = bindingsWithLocations.begin(); vaIter != bindingsWithLocations.end(); ++vaIter)
|
|
gl.disableVertexAttribArray(vaIter->binding.location);
|
|
}
|
|
|
|
void drawFromVAOBuffers (const RenderContext& context, deUint32 program, int numVertexArrays, const VertexArrayBinding* vertexArrays, const PrimitiveList& primitives, DrawUtilCallback* callback)
|
|
{
|
|
const glw::Functions& gl = context.getFunctions();
|
|
VertexArray vao (context);
|
|
|
|
gl.bindVertexArray(*vao);
|
|
drawFromBuffers(context, program, numVertexArrays, vertexArrays, primitives, callback);
|
|
gl.bindVertexArray(0);
|
|
}
|
|
|
|
void draw (const RenderContext& context, deUint32 program, int numVertexArrays, const VertexArrayBinding* vertexArrays, const PrimitiveList& primitives, DrawUtilCallback* callback)
|
|
{
|
|
const glu::ContextType ctxType = context.getType();
|
|
|
|
if (isContextTypeGLCore(ctxType) || contextSupports(ctxType, ApiType::es(3,1)))
|
|
drawFromVAOBuffers(context, program, numVertexArrays, vertexArrays, primitives, callback);
|
|
else
|
|
{
|
|
DE_ASSERT(isContextTypeES(ctxType));
|
|
drawFromUserPointers(context, program, numVertexArrays, vertexArrays, primitives, callback);
|
|
}
|
|
}
|
|
|
|
} // glu
|