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