1 //
2 // Copyright 2015 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // D3D11EmulatedIndexedBufferTest:
7 // Tests to validate our D3D11 support for emulating an indexed
8 // vertex buffer.
9 //
10
11 #include "libANGLE/Context.h"
12 #include "libANGLE/Display.h"
13 #include "libANGLE/angletypes.h"
14 #include "libANGLE/renderer/d3d/IndexDataManager.h"
15 #include "libANGLE/renderer/d3d/d3d11/Buffer11.h"
16 #include "libANGLE/renderer/d3d/d3d11/Context11.h"
17 #include "libANGLE/renderer/d3d/d3d11/Renderer11.h"
18 #include "test_utils/ANGLETest.h"
19 #include "test_utils/angle_test_instantiate.h"
20 #include "util/EGLWindow.h"
21
22 using namespace angle;
23
24 namespace
25 {
26
27 class D3D11EmulatedIndexedBufferTest : public ANGLETest<>
28 {
29 protected:
testSetUp()30 void testSetUp() override
31 {
32 ASSERT_EQ(EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, GetParam().getRenderer());
33
34 egl::Display *display = static_cast<egl::Display *>(getEGLWindow()->getDisplay());
35 gl::ContextID contextID = {
36 static_cast<GLuint>(reinterpret_cast<uintptr_t>(getEGLWindow()->getContext()))};
37 mContext = display->getContext(contextID);
38 rx::Context11 *context11 = rx::GetImplAs<rx::Context11>(mContext);
39 mRenderer = context11->getRenderer();
40
41 mSourceBuffer = new rx::Buffer11(mBufferState, mRenderer);
42 GLfloat testData[] = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f};
43 angle::Result error = mSourceBuffer->setData(nullptr, gl::BufferBinding::Array, testData,
44 sizeof(testData), gl::BufferUsage::StaticDraw);
45 ASSERT_EQ(angle::Result::Continue, error);
46
47 mTranslatedAttribute.baseOffset = 0;
48 mTranslatedAttribute.usesFirstVertexOffset = false;
49 mTranslatedAttribute.stride = sizeof(GLfloat);
50
51 GLubyte indices[] = {0, 0, 3, 4, 2, 1, 1};
52
53 for (size_t i = 0; i < ArraySize(indices); i++)
54 {
55 mExpectedExpandedData.push_back(testData[indices[i]]);
56 mubyteIndices.push_back(indices[i]);
57 muintIndices.push_back(indices[i]);
58 mushortIndices.push_back(indices[i]);
59 }
60 }
61
testTearDown()62 void testTearDown() override { SafeDelete(mSourceBuffer); }
63
createMappableCompareBufferFromEmulatedBuffer(ID3D11Buffer * sourceBuffer,GLuint size,ID3D11Buffer ** mappableBuffer)64 void createMappableCompareBufferFromEmulatedBuffer(ID3D11Buffer *sourceBuffer,
65 GLuint size,
66 ID3D11Buffer **mappableBuffer)
67 {
68 *mappableBuffer = nullptr;
69
70 D3D11_BUFFER_DESC bufferDesc;
71 bufferDesc.ByteWidth = size;
72 bufferDesc.MiscFlags = 0;
73 bufferDesc.StructureByteStride = 0;
74 bufferDesc.Usage = D3D11_USAGE_STAGING;
75 bufferDesc.BindFlags = 0;
76 bufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
77
78 HRESULT hr = mRenderer->getDevice()->CreateBuffer(&bufferDesc, nullptr, mappableBuffer);
79 ASSERT_TRUE(SUCCEEDED(hr));
80
81 D3D11_BOX srcBox;
82 srcBox.left = 0;
83 srcBox.right = size;
84 srcBox.top = 0;
85 srcBox.bottom = 1;
86 srcBox.front = 0;
87 srcBox.back = 1;
88
89 mRenderer->getDeviceContext()->CopySubresourceRegion(*mappableBuffer, 0, 0, 0, 0,
90 sourceBuffer, 0, &srcBox);
91 }
92
compareContents(ID3D11Buffer * actual)93 void compareContents(ID3D11Buffer *actual)
94 {
95 ID3D11Buffer *compareBuffer = nullptr;
96 createMappableCompareBufferFromEmulatedBuffer(
97 actual, sizeof(GLfloat) * static_cast<GLuint>(mExpectedExpandedData.size()),
98 &compareBuffer);
99
100 D3D11_MAPPED_SUBRESOURCE mappedResource;
101 HRESULT hr = mRenderer->getDeviceContext()->Map(compareBuffer, 0, D3D11_MAP_READ, 0,
102 &mappedResource);
103 ASSERT_TRUE(SUCCEEDED(hr));
104
105 GLfloat *compareData = static_cast<GLfloat *>(mappedResource.pData);
106 for (size_t i = 0; i < mExpectedExpandedData.size(); i++)
107 {
108 EXPECT_EQ(mExpectedExpandedData[i], compareData[i]);
109 }
110
111 mRenderer->getDeviceContext()->Unmap(compareBuffer, 0);
112 SafeRelease(compareBuffer);
113 }
114
emulateAndCompare(rx::SourceIndexData * srcData)115 void emulateAndCompare(rx::SourceIndexData *srcData)
116 {
117 ID3D11Buffer *emulatedBuffer = nullptr;
118 angle::Result error = mSourceBuffer->getEmulatedIndexedBuffer(
119 mContext, srcData, mTranslatedAttribute, 0, &emulatedBuffer);
120 ASSERT_EQ(angle::Result::Continue, error);
121 ASSERT_TRUE(emulatedBuffer != nullptr);
122 compareContents(emulatedBuffer);
123 }
124
125 protected:
126 gl::Context *mContext;
127 rx::Buffer11 *mSourceBuffer;
128 rx::Renderer11 *mRenderer;
129 rx::TranslatedAttribute mTranslatedAttribute;
130 std::vector<GLfloat> mExpectedExpandedData;
131 std::vector<GLubyte> mubyteIndices;
132 std::vector<GLuint> muintIndices;
133 std::vector<GLushort> mushortIndices;
134 gl::BufferState mBufferState;
135 };
136
137 // This tests that a GL_UNSIGNED_BYTE indices list can be successfully expanded
138 // into a valid emulated indexed buffer.
TEST_P(D3D11EmulatedIndexedBufferTest,TestNativeToExpandedUsingGLubyteIndices)139 TEST_P(D3D11EmulatedIndexedBufferTest, TestNativeToExpandedUsingGLubyteIndices)
140 {
141 rx::SourceIndexData srcData = {nullptr, mubyteIndices.data(),
142 static_cast<unsigned int>(mubyteIndices.size()),
143 gl::DrawElementsType::UnsignedByte, false};
144 emulateAndCompare(&srcData);
145 }
146
147 // This tests that a GL_UNSIGNED_SHORT indices list can be successfully expanded
148 // into a valid emulated indexed buffer.
TEST_P(D3D11EmulatedIndexedBufferTest,TestNativeToExpandedUsingGLushortIndices)149 TEST_P(D3D11EmulatedIndexedBufferTest, TestNativeToExpandedUsingGLushortIndices)
150 {
151 rx::SourceIndexData srcData = {nullptr, mushortIndices.data(),
152 static_cast<unsigned int>(mushortIndices.size()),
153 gl::DrawElementsType::UnsignedShort, false};
154 emulateAndCompare(&srcData);
155 }
156
157 // This tests that a GL_UNSIGNED_INT indices list can be successfully expanded
158 // into a valid emulated indexed buffer.
TEST_P(D3D11EmulatedIndexedBufferTest,TestNativeToExpandedUsingGLuintIndices)159 TEST_P(D3D11EmulatedIndexedBufferTest, TestNativeToExpandedUsingGLuintIndices)
160 {
161 rx::SourceIndexData srcData = {nullptr, muintIndices.data(),
162 static_cast<unsigned int>(muintIndices.size()),
163 gl::DrawElementsType::UnsignedInt, false};
164 emulateAndCompare(&srcData);
165 }
166
167 // This tests verifies that a Buffer11 contents remain unchanged after calling
168 // getEmulatedIndexedBuffer
TEST_P(D3D11EmulatedIndexedBufferTest,TestSourceBufferRemainsUntouchedAfterExpandOperation)169 TEST_P(D3D11EmulatedIndexedBufferTest, TestSourceBufferRemainsUntouchedAfterExpandOperation)
170 {
171 // Copy the original source buffer before any expand calls have been made
172 gl::BufferState cleanSourceState;
173 rx::Buffer11 *cleanSourceBuffer = new rx::Buffer11(cleanSourceState, mRenderer);
174 ASSERT_EQ(angle::Result::Continue, cleanSourceBuffer->copySubData(nullptr, mSourceBuffer, 0, 0,
175 mSourceBuffer->getSize()));
176
177 // Do a basic exanded and compare test.
178 rx::SourceIndexData srcData = {nullptr, muintIndices.data(),
179 static_cast<unsigned int>(muintIndices.size()),
180 gl::DrawElementsType::UnsignedInt, false};
181 emulateAndCompare(&srcData);
182
183 const uint8_t *sourceBufferMem = nullptr;
184 const uint8_t *cleanBufferMem = nullptr;
185
186 ASSERT_EQ(angle::Result::Continue, mSourceBuffer->getData(mContext, &sourceBufferMem));
187 ASSERT_EQ(angle::Result::Continue, cleanSourceBuffer->getData(mContext, &cleanBufferMem));
188
189 ASSERT_EQ(0, memcmp(sourceBufferMem, cleanBufferMem, cleanSourceBuffer->getSize()));
190
191 SafeDelete(cleanSourceBuffer);
192 }
193
194 ANGLE_INSTANTIATE_TEST(D3D11EmulatedIndexedBufferTest, ES2_D3D11(), ES3_D3D11(), ES31_D3D11());
195
196 } // anonymous namespace
197