Commit 84b0c3b7 by Austin Kinross Committed by Jamie Madill

Re-land "In D3D, cache static vertex buffers to prevent wasteful recreation"

BUG=angleproject:197 Changes since first failed patch: - Optimized BufferD3D::getStaticVertexBuffer() - Removed loop to commit static buffers - Out-of-date static buffers (which are much rarer anyway after this patch) are marked for deletion at the *next* draw call, rather than searched for before each draw call. That search was expensive. The change should see a net improvement to DrawCallPerfBenchmark for D3D null. Change-Id: If4942e0afd9e8fefadce8820a1305e13636547ef Reviewed-on: https://chromium-review.googlesource.com/311115Tested-by: 's avatarAustin Kinross <aukinros@microsoft.com> Tryjob-Request: Jamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org>
parent e8e4debc
......@@ -8,6 +8,7 @@
#include "libANGLE/renderer/d3d/BufferD3D.h"
#include "common/mathutil.h"
#include "common/utilities.h"
#include "libANGLE/renderer/d3d/IndexBuffer.h"
#include "libANGLE/renderer/d3d/VertexBuffer.h"
......@@ -22,6 +23,9 @@ BufferD3D::BufferD3D(BufferFactoryD3D *factory)
mFactory(factory),
mStaticVertexBuffer(nullptr),
mStaticIndexBuffer(nullptr),
mStaticBufferCache(nullptr),
mStaticBufferCacheTotalSize(0),
mStaticVertexBufferOutOfDate(false),
mUnmodifiedDataUse(0),
mUsage(D3D_BUFFER_USAGE_STATIC)
{
......@@ -32,6 +36,14 @@ BufferD3D::~BufferD3D()
{
SafeDelete(mStaticVertexBuffer);
SafeDelete(mStaticIndexBuffer);
// Empty the cache of static vertex buffers too
if (mStaticBufferCache != nullptr)
{
SafeDeleteContainer(*mStaticBufferCache);
}
mStaticBufferCacheTotalSize = 0;
}
void BufferD3D::updateSerial()
......@@ -75,8 +87,130 @@ void BufferD3D::initializeStaticData()
}
}
void BufferD3D::invalidateStaticData()
StaticIndexBufferInterface *BufferD3D::getStaticIndexBuffer()
{
return mStaticIndexBuffer;
}
StaticVertexBufferInterface *BufferD3D::getStaticVertexBuffer(
const gl::VertexAttribute &attribute,
D3DStaticBufferCreationType creationType)
{
if (!mStaticVertexBuffer)
{
// Early out if there aren't any static buffers at all
ASSERT(mStaticBufferCache == nullptr);
return nullptr;
}
if (mStaticBufferCache == nullptr && !mStaticVertexBuffer->isCommitted())
{
// Early out, the attribute can be added to mStaticVertexBuffer or is already in there
return mStaticVertexBuffer;
}
// At this point, see if any of the existing static buffers contains the attribute data
// If the default static vertex buffer contains the attribute, then return it
if (mStaticVertexBuffer->lookupAttribute(attribute, nullptr))
{
return mStaticVertexBuffer;
}
if (mStaticBufferCache != nullptr)
{
// If there is a cached static buffer that already contains the attribute, then return it
for (StaticVertexBufferInterface *staticBuffer : *mStaticBufferCache)
{
if (staticBuffer->lookupAttribute(attribute, nullptr))
{
return staticBuffer;
}
}
}
if (!mStaticVertexBuffer->isCommitted())
{
// None of the existing static buffers contain the attribute data and we are able to add
// the data to mStaticVertexBuffer, so we should just do so
return mStaticVertexBuffer;
}
// At this point, we must create a new static buffer for the attribute data
if (creationType != D3D_BUFFER_CREATE_IF_NECESSARY)
{
return nullptr;
}
ASSERT(mStaticVertexBuffer);
ASSERT(mStaticVertexBuffer->isCommitted());
unsigned int staticVertexBufferSize = mStaticVertexBuffer->getBufferSize();
if (IsUnsignedAdditionSafe(staticVertexBufferSize, mStaticBufferCacheTotalSize))
{
// Ensure that the total size of the static buffer cache remains less than 4x the
// size of the original buffer
unsigned int maxStaticCacheSize =
IsUnsignedMultiplicationSafe(static_cast<unsigned int>(getSize()), 4u)
? 4u * static_cast<unsigned int>(getSize())
: std::numeric_limits<unsigned int>::max();
// We can't reuse the default static vertex buffer, so we add it to the cache
if (staticVertexBufferSize + mStaticBufferCacheTotalSize <= maxStaticCacheSize)
{
if (mStaticBufferCache == nullptr)
{
mStaticBufferCache = new std::vector<StaticVertexBufferInterface *>();
}
mStaticBufferCacheTotalSize += staticVertexBufferSize;
(*mStaticBufferCache).push_back(mStaticVertexBuffer);
mStaticVertexBuffer = nullptr;
// Then reinitialize the static buffers to create a new static vertex buffer
initializeStaticData();
// Return the default static vertex buffer
return mStaticVertexBuffer;
}
}
// At this point:
// - mStaticVertexBuffer is committed and can't be altered
// - mStaticBufferCache is full (or nearly overflowing)
// The inputted attribute should be put in some static buffer at some point, but it can't
// go in one right now, since mStaticBufferCache is full and we can't delete mStaticVertexBuffer
// in case another attribute is relying upon it for the current draw.
// We therefore mark mStaticVertexBuffer for deletion at the next possible time.
mStaticVertexBufferOutOfDate = true;
return nullptr;
}
void BufferD3D::reinitOutOfDateStaticData()
{
if (mStaticVertexBufferOutOfDate)
{
// During the last draw the caller tried to use some attribute with static data, but neither
// the static buffer cache nor mStaticVertexBuffer contained that data.
// Therefore, invalidate mStaticVertexBuffer so that if the caller tries to use that
// attribute in the next draw, it'll successfully get put into mStaticVertexBuffer.
invalidateStaticData(D3D_BUFFER_INVALIDATE_DEFAULT_BUFFER_ONLY);
mStaticVertexBufferOutOfDate = false;
}
}
void BufferD3D::invalidateStaticData(D3DBufferInvalidationType invalidationType)
{
if (invalidationType == D3D_BUFFER_INVALIDATE_WHOLE_CACHE && mStaticBufferCache != nullptr)
{
// Empty the cache of static vertex buffers too
for (StaticVertexBufferInterface *staticBuffer : *mStaticBufferCache)
{
SafeDelete(staticBuffer);
}
mStaticBufferCache->clear();
mStaticBufferCacheTotalSize = 0;
}
if ((mStaticVertexBuffer && mStaticVertexBuffer->getBufferSize() != 0) || (mStaticIndexBuffer && mStaticIndexBuffer->getBufferSize() != 0))
{
SafeDelete(mStaticVertexBuffer);
......@@ -98,6 +232,10 @@ void BufferD3D::promoteStaticUsage(int dataSize)
{
if (!mStaticVertexBuffer && !mStaticIndexBuffer)
{
// There isn't any scenario that involves promoting static usage and the static buffer cache
// being non-empty
ASSERT(mStaticBufferCache == nullptr);
mUnmodifiedDataUse += dataSize;
if (mUnmodifiedDataUse > 3 * getSize())
......
......@@ -13,6 +13,7 @@
#include "libANGLE/renderer/BufferImpl.h"
#include <stdint.h>
#include <vector>
namespace rx
{
......@@ -26,6 +27,18 @@ enum D3DBufferUsage
D3D_BUFFER_USAGE_DYNAMIC,
};
enum D3DBufferInvalidationType
{
D3D_BUFFER_INVALIDATE_WHOLE_CACHE,
D3D_BUFFER_INVALIDATE_DEFAULT_BUFFER_ONLY,
};
enum D3DStaticBufferCreationType
{
D3D_BUFFER_CREATE_IF_NECESSARY,
D3D_BUFFER_DO_NOT_CREATE,
};
class BufferD3D : public BufferImpl
{
public:
......@@ -39,11 +52,14 @@ class BufferD3D : public BufferImpl
virtual void markTransformFeedbackUsage() = 0;
virtual gl::Error getData(const uint8_t **outData) = 0;
StaticVertexBufferInterface *getStaticVertexBuffer() { return mStaticVertexBuffer; }
StaticIndexBufferInterface *getStaticIndexBuffer() { return mStaticIndexBuffer; }
StaticVertexBufferInterface *getStaticVertexBuffer(const gl::VertexAttribute &attribute,
D3DStaticBufferCreationType creationType);
StaticIndexBufferInterface *getStaticIndexBuffer();
void initializeStaticData();
void invalidateStaticData();
void invalidateStaticData(D3DBufferInvalidationType invalidationType);
void reinitOutOfDateStaticData();
void promoteStaticUsage(int dataSize);
gl::Error getIndexRange(GLenum type,
......@@ -62,6 +78,9 @@ class BufferD3D : public BufferImpl
StaticVertexBufferInterface *mStaticVertexBuffer;
StaticIndexBufferInterface *mStaticIndexBuffer;
std::vector<StaticVertexBufferInterface *> *mStaticBufferCache;
unsigned int mStaticBufferCacheTotalSize;
unsigned int mStaticVertexBufferOutOfDate;
unsigned int mUnmodifiedDataUse;
D3DBufferUsage mUsage;
};
......
......@@ -231,7 +231,7 @@ gl::Error IndexDataManager::prepareIndexData(GLenum srcType,
if (staticBufferInitialized && !staticBufferUsable)
{
buffer->invalidateStaticData();
buffer->invalidateStaticData(D3D_BUFFER_INVALIDATE_WHOLE_CACHE);
staticBuffer = nullptr;
}
......
......@@ -243,7 +243,7 @@ gl::Error StreamingVertexBufferInterface::reserveSpace(unsigned int size)
}
StaticVertexBufferInterface::StaticVertexBufferInterface(BufferFactoryD3D *factory)
: VertexBufferInterface(factory, false)
: VertexBufferInterface(factory, false), mIsCommitted(false)
{
}
......@@ -255,13 +255,14 @@ bool StaticVertexBufferInterface::lookupAttribute(const gl::VertexAttribute &att
{
for (unsigned int element = 0; element < mCache.size(); element++)
{
if (mCache[element].type == attrib.type &&
mCache[element].size == attrib.size &&
mCache[element].stride == ComputeVertexAttributeStride(attrib) &&
size_t attribStride = ComputeVertexAttributeStride(attrib);
if (mCache[element].type == attrib.type && mCache[element].size == attrib.size &&
mCache[element].stride == attribStride &&
mCache[element].normalized == attrib.normalized &&
mCache[element].pureInteger == attrib.pureInteger)
{
size_t offset = (static_cast<size_t>(attrib.offset) % ComputeVertexAttributeStride(attrib));
size_t offset = (static_cast<size_t>(attrib.offset) % attribStride);
if (mCache[element].attributeOffset == offset)
{
if (outStreamOffset)
......@@ -321,4 +322,11 @@ gl::Error StaticVertexBufferInterface::storeVertexAttributes(const gl::VertexAtt
return gl::Error(GL_NO_ERROR);
}
void StaticVertexBufferInterface::commit()
{
if (getBufferSize() > 0)
{
mIsCommitted = true;
}
}
}
......@@ -135,6 +135,11 @@ class StaticVertexBufferInterface : public VertexBufferInterface
bool lookupAttribute(const gl::VertexAttribute &attribute, unsigned int* outStreamFffset);
// If a static vertex buffer is committed then no more attribute data can be added to it
// A new static vertex buffer should be created instead
void commit();
bool isCommitted() { return mIsCommitted; }
protected:
gl::Error reserveSpace(unsigned int size);
......@@ -151,6 +156,7 @@ class StaticVertexBufferInterface : public VertexBufferInterface
unsigned int streamOffset;
};
bool mIsCommitted;
std::vector<VertexElement> mCache;
};
......
......@@ -88,10 +88,17 @@ void VertexDataManager::hintUnmapAllResources(const std::vector<gl::VertexAttrib
{
gl::Buffer *buffer = translated->attribute->buffer.get();
BufferD3D *storage = buffer ? GetImplAs<BufferD3D>(buffer) : nullptr;
StaticVertexBufferInterface *staticBuffer = storage ? storage->getStaticVertexBuffer() : nullptr;
StaticVertexBufferInterface *staticBuffer =
storage
? storage->getStaticVertexBuffer(*translated->attribute, D3D_BUFFER_DO_NOT_CREATE)
: nullptr;
if (staticBuffer)
{
// Commit all the static vertex buffers. This fixes them in size/contents, and forces
// ANGLE to use a new static buffer (or recreate the static buffers) next time
staticBuffer->commit();
staticBuffer->getVertexBuffer()->hintUnmapResource();
}
}
......@@ -146,10 +153,14 @@ gl::Error VertexDataManager::prepareVertexData(const gl::State &state,
{
mActiveEnabledAttributes.push_back(translated);
// Also invalidate static buffers that don't contain matching attributes
invalidateMatchingStaticData(
vertexAttributes[attribIndex],
state.getVertexAttribCurrentValue(static_cast<unsigned int>(attribIndex)));
gl::Buffer *buffer = vertexAttributes[attribIndex].buffer.get();
if (buffer)
{
// Also reinitialize static buffers which didn't contain matching data
// last time they were used
BufferD3D *bufferImpl = GetImplAs<BufferD3D>(buffer);
bufferImpl->reinitOutOfDateStaticData();
}
}
else
{
......@@ -215,26 +226,6 @@ gl::Error VertexDataManager::prepareVertexData(const gl::State &state,
return gl::Error(GL_NO_ERROR);
}
void VertexDataManager::invalidateMatchingStaticData(const gl::VertexAttribute &attrib,
const gl::VertexAttribCurrentValueData &currentValue) const
{
gl::Buffer *buffer = attrib.buffer.get();
if (buffer)
{
BufferD3D *bufferImpl = GetImplAs<BufferD3D>(buffer);
StaticVertexBufferInterface *staticBuffer = bufferImpl->getStaticVertexBuffer();
if (staticBuffer &&
staticBuffer->getBufferSize() > 0 &&
!staticBuffer->lookupAttribute(attrib, NULL) &&
!staticBuffer->directStoragePossible(attrib, currentValue.Type))
{
bufferImpl->invalidateStaticData();
}
}
}
gl::Error VertexDataManager::reserveSpaceForAttrib(const TranslatedAttribute &translatedAttrib,
GLsizei count,
GLsizei instances) const
......@@ -242,7 +233,9 @@ gl::Error VertexDataManager::reserveSpaceForAttrib(const TranslatedAttribute &tr
const gl::VertexAttribute &attrib = *translatedAttrib.attribute;
gl::Buffer *buffer = attrib.buffer.get();
BufferD3D *bufferImpl = buffer ? GetImplAs<BufferD3D>(buffer) : NULL;
StaticVertexBufferInterface *staticBuffer = bufferImpl ? bufferImpl->getStaticVertexBuffer() : NULL;
StaticVertexBufferInterface *staticBuffer =
bufferImpl ? bufferImpl->getStaticVertexBuffer(attrib, D3D_BUFFER_CREATE_IF_NECESSARY)
: NULL;
VertexBufferInterface *vertexBuffer = staticBuffer ? staticBuffer : static_cast<VertexBufferInterface*>(mStreamingBuffer);
if (!vertexBuffer->directStoragePossible(attrib, translatedAttrib.currentValueType))
......@@ -291,7 +284,8 @@ gl::Error VertexDataManager::storeAttribute(TranslatedAttribute *translated,
ASSERT(attrib.enabled);
BufferD3D *storage = buffer ? GetImplAs<BufferD3D>(buffer) : NULL;
StaticVertexBufferInterface *staticBuffer = storage ? storage->getStaticVertexBuffer() : NULL;
StaticVertexBufferInterface *staticBuffer =
storage ? storage->getStaticVertexBuffer(attrib, D3D_BUFFER_DO_NOT_CREATE) : NULL;
VertexBufferInterface *vertexBuffer = staticBuffer ? staticBuffer : static_cast<VertexBufferInterface*>(mStreamingBuffer);
bool directStorage = vertexBuffer->directStoragePossible(attrib, translated->currentValueType);
......
......@@ -82,9 +82,6 @@ class VertexDataManager : angle::NonCopyable
GLsizei count,
GLsizei instances) const;
void invalidateMatchingStaticData(const gl::VertexAttribute &attrib,
const gl::VertexAttribCurrentValueData &currentValue) const;
gl::Error storeAttribute(TranslatedAttribute *translated,
GLint start,
GLsizei count,
......
......@@ -361,7 +361,7 @@ gl::Error Buffer11::setSubData(const void *data, size_t size, size_t offset)
}
mSize = std::max(mSize, requiredSize);
invalidateStaticData();
invalidateStaticData(D3D_BUFFER_INVALIDATE_WHOLE_CACHE);
return gl::Error(GL_NO_ERROR);
}
......@@ -417,7 +417,7 @@ gl::Error Buffer11::copySubData(BufferImpl *source,
copyDest->setDataRevision(copyDest->getDataRevision() + 1);
mSize = std::max<size_t>(mSize, destOffset + size);
invalidateStaticData();
invalidateStaticData(D3D_BUFFER_INVALIDATE_WHOLE_CACHE);
return gl::Error(GL_NO_ERROR);
}
......@@ -457,7 +457,7 @@ gl::Error Buffer11::mapRange(size_t offset, size_t length, GLbitfield access, GL
{
// Update the data revision immediately, since the data might be changed at any time
mMappedStorage->setDataRevision(mMappedStorage->getDataRevision() + 1);
invalidateStaticData();
invalidateStaticData(D3D_BUFFER_INVALIDATE_WHOLE_CACHE);
}
uint8_t *mappedBuffer = mMappedStorage->map(offset, length, access);
......@@ -492,7 +492,7 @@ void Buffer11::markTransformFeedbackUsage()
transformFeedbackStorage->setDataRevision(transformFeedbackStorage->getDataRevision() + 1);
}
invalidateStaticData();
invalidateStaticData(D3D_BUFFER_INVALIDATE_WHOLE_CACHE);
}
void Buffer11::markBufferUsage()
......
......@@ -38,7 +38,7 @@ gl::Error Buffer9::setData(const void* data, size_t size, GLenum usage)
memcpy(mMemory.data(), data, size);
}
invalidateStaticData();
invalidateStaticData(D3D_BUFFER_INVALIDATE_WHOLE_CACHE);
updateD3DBufferUsage(usage);
return gl::Error(GL_NO_ERROR);
......@@ -66,7 +66,7 @@ gl::Error Buffer9::setSubData(const void* data, size_t size, size_t offset)
memcpy(mMemory.data() + offset, data, size);
}
invalidateStaticData();
invalidateStaticData(D3D_BUFFER_INVALIDATE_WHOLE_CACHE);
return gl::Error(GL_NO_ERROR);
}
......@@ -79,7 +79,7 @@ gl::Error Buffer9::copySubData(BufferImpl* source, GLintptr sourceOffset, GLintp
memcpy(mMemory.data() + destOffset, sourceBuffer->mMemory.data() + sourceOffset, size);
invalidateStaticData();
invalidateStaticData(D3D_BUFFER_INVALIDATE_WHOLE_CACHE);
return gl::Error(GL_NO_ERROR);
}
......
......@@ -21,6 +21,7 @@
'<(angle_path)/src/tests/perf_tests/DrawCallPerf.cpp',
'<(angle_path)/src/tests/perf_tests/EGLInitializePerf.cpp',
'<(angle_path)/src/tests/perf_tests/IndexConversionPerf.cpp',
'<(angle_path)/src/tests/perf_tests/InterleavedAttributeData.cpp',
'<(angle_path)/src/tests/perf_tests/PointSprites.cpp',
'<(angle_path)/src/tests/perf_tests/TexSubImage.cpp',
'<(angle_path)/src/tests/perf_tests/third_party/perf/perf_test.cc',
......
......@@ -45,7 +45,7 @@ struct BufferSubDataParams final : public RenderTestParams
unsigned int iterations;
};
inline std::ostream &operator<<(std::ostream &os, const BufferSubDataParams &params)
std::ostream &operator<<(std::ostream &os, const BufferSubDataParams &params)
{
os << params.suffix().substr(1);
return os;
......
......@@ -55,7 +55,7 @@ struct DrawCallPerfParams final : public RenderTestParams
int numTris;
};
inline std::ostream &operator<<(std::ostream &os, const DrawCallPerfParams &params)
std::ostream &operator<<(std::ostream &os, const DrawCallPerfParams &params)
{
os << params.suffix().substr(1);
return os;
......
//
// Copyright (c) 2014 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.
//
// InterleavedAttributeData:
// Performance test for draws using interleaved attribute data in vertex buffers.
//
#include <sstream>
#include "ANGLEPerfTest.h"
#include "shader_utils.h"
using namespace angle;
namespace
{
struct InterleavedAttributeDataParams final : public RenderTestParams
{
InterleavedAttributeDataParams()
{
// Common default values
majorVersion = 2;
minorVersion = 0;
windowWidth = 512;
windowHeight = 512;
numSprites = 3000;
}
// static parameters
unsigned int numSprites;
};
std::ostream &operator<<(std::ostream &os, const InterleavedAttributeDataParams &params)
{
os << params.suffix().substr(1);
if (params.eglParameters.majorVersion != EGL_DONT_CARE)
{
os << "_" << params.eglParameters.majorVersion << "_" << params.eglParameters.minorVersion;
}
return os;
}
class InterleavedAttributeDataBenchmark
: public ANGLERenderTest,
public ::testing::WithParamInterface<InterleavedAttributeDataParams>
{
public:
InterleavedAttributeDataBenchmark();
void initializeBenchmark() override;
void destroyBenchmark() override;
void beginDrawBenchmark() override;
void drawBenchmark() override;
private:
GLuint mPointSpriteProgram;
GLuint mPositionColorBuffer[2];
// The buffers contain two floats and 3 unsigned bytes per point sprite
const size_t mBytesPerSprite = 2 * sizeof(float) + 3;
};
InterleavedAttributeDataBenchmark::InterleavedAttributeDataBenchmark()
: ANGLERenderTest("InterleavedAttributeData", GetParam()), mPointSpriteProgram(0)
{
}
void InterleavedAttributeDataBenchmark::initializeBenchmark()
{
const auto &params = GetParam();
// Compile point sprite shaders
const std::string vs =
"attribute vec4 aPosition;"
"attribute vec4 aColor;"
"varying vec4 vColor;"
"void main()"
"{"
" gl_PointSize = 25.0;"
" gl_Position = aPosition;"
" vColor = aColor;"
"}";
const std::string fs =
"precision mediump float;"
"varying vec4 vColor;"
"void main()"
"{"
" gl_FragColor = vColor;"
"}";
mPointSpriteProgram = CompileProgram(vs, fs);
ASSERT_TRUE(mPointSpriteProgram != 0);
glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
for (size_t i = 0; i < ArraySize(mPositionColorBuffer); i++)
{
// Set up initial data for pointsprite positions and colors
std::vector<uint8_t> positionColorData(mBytesPerSprite * params.numSprites);
for (unsigned int j = 0; j < params.numSprites; j++)
{
float pointSpriteX =
(static_cast<float>(rand() % getWindow()->getWidth()) / getWindow()->getWidth()) *
2.0f - 1.0f;
float pointSpriteY =
(static_cast<float>(rand() % getWindow()->getHeight()) / getWindow()->getHeight()) *
2.0f - 1.0f;
GLubyte pointSpriteRed = static_cast<GLubyte>(rand() % 255);
GLubyte pointSpriteGreen = static_cast<GLubyte>(rand() % 255);
GLubyte pointSpriteBlue = static_cast<GLubyte>(rand() % 255);
// Add position data for the pointsprite
*reinterpret_cast<float *>(
&(positionColorData[j * mBytesPerSprite + 0 * sizeof(float) + 0])) =
pointSpriteX; // X
*reinterpret_cast<float *>(
&(positionColorData[j * mBytesPerSprite + 1 * sizeof(float) + 0])) =
pointSpriteY; // Y
// Add color data for the pointsprite
positionColorData[j * mBytesPerSprite + 2 * sizeof(float) + 0] = pointSpriteRed; // R
positionColorData[j * mBytesPerSprite + 2 * sizeof(float) + 1] = pointSpriteGreen; // G
positionColorData[j * mBytesPerSprite + 2 * sizeof(float) + 2] = pointSpriteBlue; // B
}
// Generate the GL buffer with the position/color data
glGenBuffers(1, &mPositionColorBuffer[i]);
glBindBuffer(GL_ARRAY_BUFFER, mPositionColorBuffer[i]);
glBufferData(GL_ARRAY_BUFFER, params.numSprites * mBytesPerSprite, &(positionColorData[0]),
GL_STATIC_DRAW);
}
ASSERT_GL_NO_ERROR();
}
void InterleavedAttributeDataBenchmark::destroyBenchmark()
{
glDeleteProgram(mPointSpriteProgram);
for (size_t i = 0; i < ArraySize(mPositionColorBuffer); i++)
{
glDeleteBuffers(1, &mPositionColorBuffer[i]);
}
}
void InterleavedAttributeDataBenchmark::beginDrawBenchmark()
{
// Clear the color buffer
glClear(GL_COLOR_BUFFER_BIT);
}
void InterleavedAttributeDataBenchmark::drawBenchmark()
{
for (size_t k = 0; k < 4; k++)
{
for (size_t i = 0; i < ArraySize(mPositionColorBuffer); i++)
{
// Firstly get the attribute locations for the program
glUseProgram(mPointSpriteProgram);
GLint positionLocation = glGetAttribLocation(mPointSpriteProgram, "aPosition");
ASSERT_NE(positionLocation, -1);
GLint colorLocation = glGetAttribLocation(mPointSpriteProgram, "aColor");
ASSERT_NE(colorLocation, -1);
// Bind the position data from one buffer
glBindBuffer(GL_ARRAY_BUFFER, mPositionColorBuffer[i]);
glEnableVertexAttribArray(positionLocation);
glVertexAttribPointer(positionLocation, 2, GL_FLOAT, GL_FALSE,
static_cast<GLsizei>(mBytesPerSprite), 0);
// But bind the color data from the other buffer.
glBindBuffer(GL_ARRAY_BUFFER,
mPositionColorBuffer[(i + 1) % ArraySize(mPositionColorBuffer)]);
glEnableVertexAttribArray(colorLocation);
glVertexAttribPointer(colorLocation, 3, GL_UNSIGNED_BYTE, GL_TRUE,
static_cast<GLsizei>(mBytesPerSprite),
reinterpret_cast<void *>(2 * sizeof(float)));
// Then draw the colored pointsprites
glDrawArrays(GL_POINTS, 0, GetParam().numSprites);
glFlush();
glDisableVertexAttribArray(positionLocation);
glDisableVertexAttribArray(colorLocation);
}
}
ASSERT_GL_NO_ERROR();
}
TEST_P(InterleavedAttributeDataBenchmark, Run)
{
run();
}
InterleavedAttributeDataParams D3D11Params()
{
InterleavedAttributeDataParams params;
params.eglParameters = egl_platform::D3D11();
return params;
}
InterleavedAttributeDataParams D3D11_9_3Params()
{
InterleavedAttributeDataParams params;
params.eglParameters = egl_platform::D3D11_FL9_3();
return params;
}
InterleavedAttributeDataParams D3D9Params()
{
InterleavedAttributeDataParams params;
params.eglParameters = egl_platform::D3D9();
return params;
}
InterleavedAttributeDataParams OpenGLParams()
{
InterleavedAttributeDataParams params;
params.eglParameters = egl_platform::OPENGL();
return params;
}
ANGLE_INSTANTIATE_TEST(InterleavedAttributeDataBenchmark,
D3D11Params(),
D3D11_9_3Params(),
D3D9Params(),
OpenGLParams());
} // anonymous namespace
......@@ -45,7 +45,7 @@ struct PointSpritesParams final : public RenderTestParams
unsigned int iterations;
};
inline std::ostream &operator<<(std::ostream &os, const PointSpritesParams &params)
std::ostream &operator<<(std::ostream &os, const PointSpritesParams &params)
{
os << params.suffix().substr(1);
return os;
......
......@@ -44,7 +44,7 @@ struct TexSubImageParams final : public RenderTestParams
unsigned int iterations;
};
inline std::ostream &operator<<(std::ostream &os, const TexSubImageParams &params)
std::ostream &operator<<(std::ostream &os, const TexSubImageParams &params)
{
os << params.suffix().substr(1);
return os;
......
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