Commit b48e8b07 by Jamie Madill

D3D11: Only rewrite for primitive restart when needed.

We would rewrite our index data every draw call. Change the index check to see if we're writing to the same sized / typed static buffer and only rewrite the data if the user re-uploaded. Also add a performance test for the primitive restart workaround. As a future improvement we could avoid creating new D3D objects every time we reinitialize static data, since BufferSubData calls don't change the size of the buffer if the index type remains the same. BUG=476658 Change-Id: I9d2540ad8b1b34fa0142ba0bf794cf572da8c61d Reviewed-on: https://chromium-review.googlesource.com/265838Tested-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org> Reviewed-by: 's avatarBrandon Jones <bajones@chromium.org>
parent 304dcde8
...@@ -114,29 +114,35 @@ gl::Error IndexDataManager::prepareIndexData(GLenum type, GLsizei count, gl::Buf ...@@ -114,29 +114,35 @@ gl::Error IndexDataManager::prepareIndexData(GLenum type, GLsizei count, gl::Buf
destinationIndexType == type; destinationIndexType == type;
unsigned int streamOffset = 0; unsigned int streamOffset = 0;
// Avoid D3D11's primitive restart index value
// see http://msdn.microsoft.com/en-us/library/windows/desktop/bb205124(v=vs.85).aspx
bool primitiveRestartWorkaround = mRendererClass == RENDERER_D3D11 &&
translated->indexRange.end == 0xFFFF &&
type == GL_UNSIGNED_SHORT;
if (primitiveRestartWorkaround)
{
destinationIndexType = GL_UNSIGNED_INT;
directStorage = false;
}
const gl::Type &destTypeInfo = gl::GetTypeInfo(destinationIndexType);
if (directStorage) if (directStorage)
{ {
streamOffset = offset; streamOffset = offset;
} }
else if (staticBuffer && staticBuffer->getBufferSize() != 0 && staticBuffer->getIndexType() == type && alignedOffset) else if (staticBuffer &&
staticBuffer->getBufferSize() != 0 &&
alignedOffset &&
staticBuffer->getIndexType() == destinationIndexType)
{ {
indexBuffer = staticBuffer; indexBuffer = staticBuffer;
// Using bit-shift here is faster than using division. // Using bit-shift here is faster than using division.
streamOffset = (offset >> typeInfo.bytesShift) << gl::GetTypeInfo(destinationIndexType).bytesShift; streamOffset = (offset >> typeInfo.bytesShift) << destTypeInfo.bytesShift;
} }
// Avoid D3D11's primitive restart index value
// see http://msdn.microsoft.com/en-us/library/windows/desktop/bb205124(v=vs.85).aspx
if (translated->indexRange.end == 0xFFFF && type == GL_UNSIGNED_SHORT && mRendererClass == RENDERER_D3D11)
{
destinationIndexType = GL_UNSIGNED_INT;
directStorage = false;
indexBuffer = NULL;
}
const gl::Type &destTypeInfo = gl::GetTypeInfo(destinationIndexType);
if (!directStorage && !indexBuffer) if (!directStorage && !indexBuffer)
{ {
gl::Error error = getStreamingIndexBuffer(destinationIndexType, &indexBuffer); gl::Error error = getStreamingIndexBuffer(destinationIndexType, &indexBuffer);
...@@ -172,7 +178,7 @@ gl::Error IndexDataManager::prepareIndexData(GLenum type, GLsizei count, gl::Buf ...@@ -172,7 +178,7 @@ gl::Error IndexDataManager::prepareIndexData(GLenum type, GLsizei count, gl::Buf
} }
unsigned int bufferSizeRequired = convertCount << destTypeInfo.bytesShift; unsigned int bufferSizeRequired = convertCount << destTypeInfo.bytesShift;
error = indexBuffer->reserveBufferSpace(bufferSizeRequired, type); error = indexBuffer->reserveBufferSpace(bufferSizeRequired, destinationIndexType);
if (error.isError()) if (error.isError())
{ {
return error; return error;
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include "common/MemoryBuffer.h" #include "common/MemoryBuffer.h"
#include "libANGLE/renderer/d3d/d3d11/Renderer11.h" #include "libANGLE/renderer/d3d/d3d11/Renderer11.h"
#include "libANGLE/renderer/d3d/d3d11/Renderer11_utils.h"
#include "libANGLE/renderer/d3d/d3d11/formatutils11.h" #include "libANGLE/renderer/d3d/d3d11/formatutils11.h"
namespace rx namespace rx
...@@ -862,6 +863,8 @@ gl::Error Buffer11::NativeStorage::resize(size_t size, bool preserveData) ...@@ -862,6 +863,8 @@ gl::Error Buffer11::NativeStorage::resize(size_t size, bool preserveData)
return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal buffer, result: 0x%X.", result); return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal buffer, result: 0x%X.", result);
} }
d3d11::SetDebugName(newBuffer, "Buffer11::NativeStorage");
if (mNativeStorage && preserveData) if (mNativeStorage && preserveData)
{ {
// We don't call resize if the buffer is big enough already. // We don't call resize if the buffer is big enough already.
......
...@@ -7,7 +7,9 @@ ...@@ -7,7 +7,9 @@
// IndexBuffer11.cpp: Defines the D3D11 IndexBuffer implementation. // IndexBuffer11.cpp: Defines the D3D11 IndexBuffer implementation.
#include "libANGLE/renderer/d3d/d3d11/IndexBuffer11.h" #include "libANGLE/renderer/d3d/d3d11/IndexBuffer11.h"
#include "libANGLE/renderer/d3d/d3d11/Renderer11.h" #include "libANGLE/renderer/d3d/d3d11/Renderer11.h"
#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h"
namespace rx namespace rx
{ {
...@@ -47,6 +49,15 @@ gl::Error IndexBuffer11::initialize(unsigned int bufferSize, GLenum indexType, b ...@@ -47,6 +49,15 @@ gl::Error IndexBuffer11::initialize(unsigned int bufferSize, GLenum indexType, b
{ {
return gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate internal index buffer of size, %lu.", bufferSize); return gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate internal index buffer of size, %lu.", bufferSize);
} }
if (dynamic)
{
d3d11::SetDebugName(mBuffer, "IndexBuffer11 (dynamic)");
}
else
{
d3d11::SetDebugName(mBuffer, "IndexBuffer11 (static)");
}
} }
mBufferSize = bufferSize; mBufferSize = bufferSize;
......
...@@ -7,11 +7,13 @@ ...@@ -7,11 +7,13 @@
// VertexBuffer11.cpp: Defines the D3D11 VertexBuffer implementation. // VertexBuffer11.cpp: Defines the D3D11 VertexBuffer implementation.
#include "libANGLE/renderer/d3d/d3d11/VertexBuffer11.h" #include "libANGLE/renderer/d3d/d3d11/VertexBuffer11.h"
#include "libANGLE/renderer/d3d/d3d11/Buffer11.h"
#include "libANGLE/renderer/d3d/d3d11/Renderer11.h"
#include "libANGLE/renderer/d3d/d3d11/formatutils11.h"
#include "libANGLE/Buffer.h" #include "libANGLE/Buffer.h"
#include "libANGLE/VertexAttribute.h" #include "libANGLE/VertexAttribute.h"
#include "libANGLE/renderer/d3d/d3d11/Buffer11.h"
#include "libANGLE/renderer/d3d/d3d11/formatutils11.h"
#include "libANGLE/renderer/d3d/d3d11/Renderer11.h"
#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h"
namespace rx namespace rx
{ {
...@@ -53,6 +55,15 @@ gl::Error VertexBuffer11::initialize(unsigned int size, bool dynamicUsage) ...@@ -53,6 +55,15 @@ gl::Error VertexBuffer11::initialize(unsigned int size, bool dynamicUsage)
{ {
return gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate internal vertex buffer of size, %lu.", size); return gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate internal vertex buffer of size, %lu.", size);
} }
if (dynamicUsage)
{
d3d11::SetDebugName(mBuffer, "VertexBuffer11 (dynamic)");
}
else
{
d3d11::SetDebugName(mBuffer, "VertexBuffer11 (static)");
}
} }
mBufferSize = size; mBufferSize = size;
......
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
'perf_tests/ANGLEPerfTest.h', 'perf_tests/ANGLEPerfTest.h',
'perf_tests/BufferSubData.cpp', 'perf_tests/BufferSubData.cpp',
'perf_tests/DrawCallPerf.cpp', 'perf_tests/DrawCallPerf.cpp',
'perf_tests/IndexConversionPerf.cpp',
'perf_tests/PointSprites.cpp', 'perf_tests/PointSprites.cpp',
'perf_tests/TexSubImage.cpp', 'perf_tests/TexSubImage.cpp',
'perf_tests/third_party/perf/perf_test.cc', 'perf_tests/third_party/perf/perf_test.cc',
......
//
// Copyright 2015 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.
//
// IndexConversionPerf:
// Performance tests for ANGLE index conversion in D3D11.
//
#include <sstream>
#include "ANGLEPerfTest.h"
#include "shader_utils.h"
namespace
{
struct IndexConversionPerfParams final : public RenderTestParams
{
std::string suffix() const override
{
std::stringstream strstr;
strstr << RenderTestParams::suffix();
return strstr.str();
}
unsigned int iterations;
unsigned int numIndexTris;
};
class IndexConversionPerfTest : public ANGLERenderTest,
public ::testing::WithParamInterface<IndexConversionPerfParams>
{
public:
IndexConversionPerfTest();
void initializeBenchmark() override;
void destroyBenchmark() override;
void beginDrawBenchmark() override;
void drawBenchmark() override;
void updateBufferData();
private:
GLuint mProgram;
GLuint mVertexBuffer;
GLuint mIndexBuffer;
std::vector<GLushort> mIndexData;
};
IndexConversionPerfTest::IndexConversionPerfTest()
: ANGLERenderTest("IndexConversionPerfTest", GetParam()),
mProgram(0),
mVertexBuffer(0),
mIndexBuffer(0)
{
mRunTimeSeconds = 3.0;
}
void IndexConversionPerfTest::initializeBenchmark()
{
const auto &params = GetParam();
ASSERT_TRUE(params.iterations > 0);
ASSERT_TRUE(params.numIndexTris > 0);
mDrawIterations = params.iterations;
const std::string vs = SHADER_SOURCE
(
attribute vec2 vPosition;
uniform float uScale;
uniform float uOffset;
void main()
{
gl_Position = vec4(vPosition * vec2(uScale) - vec2(uOffset), 0, 1);
}
);
const std::string fs = SHADER_SOURCE
(
precision mediump float;
void main()
{
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
);
mProgram = CompileProgram(vs, fs);
ASSERT_TRUE(mProgram != 0);
// Use the program object
glUseProgram(mProgram);
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
// Initialize the vertex data
std::vector<GLfloat> floatData;
size_t numTris = std::numeric_limits<GLushort>::max() / 3 + 1;
for (size_t triIndex = 0; triIndex < numTris; ++triIndex)
{
floatData.push_back(1);
floatData.push_back(2);
floatData.push_back(0);
floatData.push_back(0);
floatData.push_back(2);
floatData.push_back(0);
}
glGenBuffers(1, &mVertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
glBufferData(GL_ARRAY_BUFFER, floatData.size() * sizeof(GLfloat), &floatData[0], GL_STATIC_DRAW);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(0);
// Initialize the index buffer
for (unsigned int triIndex = 0; triIndex < params.numIndexTris; ++triIndex)
{
mIndexData.push_back(std::numeric_limits<GLushort>::max());
mIndexData.push_back(1);
mIndexData.push_back(2);
}
glGenBuffers(1, &mIndexBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer);
updateBufferData();
// Set the viewport
glViewport(0, 0, getWindow()->getWidth(), getWindow()->getHeight());
GLfloat scale = 0.5f;
GLfloat offset = 0.5f;
glUniform1f(glGetUniformLocation(mProgram, "uScale"), scale);
glUniform1f(glGetUniformLocation(mProgram, "uOffset"), offset);
ASSERT_TRUE(glGetError() == GL_NO_ERROR);
}
void IndexConversionPerfTest::updateBufferData()
{
glBufferData(GL_ELEMENT_ARRAY_BUFFER, mIndexData.size() * sizeof(mIndexData[0]), &mIndexData[0], GL_STATIC_DRAW);
}
void IndexConversionPerfTest::destroyBenchmark()
{
glDeleteProgram(mProgram);
glDeleteBuffers(1, &mVertexBuffer);
glDeleteBuffers(1, &mIndexBuffer);
}
void IndexConversionPerfTest::beginDrawBenchmark()
{
// Clear the color buffer
glClear(GL_COLOR_BUFFER_BIT);
}
void IndexConversionPerfTest::drawBenchmark()
{
const auto &params = GetParam();
// Trigger an update to ensure we convert once a frame
updateBufferData();
for (unsigned int it = 0; it < params.iterations; it++)
{
glDrawElements(GL_TRIANGLES,
static_cast<GLsizei>(params.numIndexTris * 3 - 1),
GL_UNSIGNED_SHORT,
reinterpret_cast<GLvoid*>(0));
}
EXPECT_TRUE(glGetError() == GL_NO_ERROR);
}
IndexConversionPerfParams IndexConversionPerfD3D11Params()
{
IndexConversionPerfParams params;
params.glesMajorVersion = 2;
params.widowWidth = 256;
params.windowHeight = 256;
params.requestedRenderer = EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE;
params.deviceType = EGL_PLATFORM_ANGLE_DEVICE_TYPE_NULL_ANGLE;
params.iterations = 15;
params.numIndexTris = 3000;
return params;
}
TEST_P(IndexConversionPerfTest, Run)
{
run();
}
INSTANTIATE_TEST_CASE_P(IndexConversionPerf,
IndexConversionPerfTest,
::testing::Values(IndexConversionPerfD3D11Params()));
} // namespace
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