| // | |
| // 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. | |
| // | |
| // D3D11EmulatedIndexedBufferTest: | |
| // Tests to validate our D3D11 support for emulating an indexed | |
| // vertex buffer. | |
| // | |
| #include "libANGLE/Context.h" | |
| #include "libANGLE/angletypes.h" | |
| #include "libANGLE/renderer/d3d/IndexDataManager.h" | |
| #include "libANGLE/renderer/d3d/d3d11/Buffer11.h" | |
| #include "libANGLE/renderer/d3d/d3d11/Context11.h" | |
| #include "libANGLE/renderer/d3d/d3d11/Renderer11.h" | |
| #include "test_utils/ANGLETest.h" | |
| #include "test_utils/angle_test_instantiate.h" | |
| #include "util/EGLWindow.h" | |
| using namespace angle; | |
| namespace | |
| { | |
| class D3D11EmulatedIndexedBufferTest : public ANGLETest | |
| { | |
| protected: | |
| void testSetUp() override | |
| { | |
| ASSERT_EQ(EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, GetParam().getRenderer()); | |
| mContext = static_cast<gl::Context *>(getEGLWindow()->getContext()); | |
| rx::Context11 *context11 = rx::GetImplAs<rx::Context11>(mContext); | |
| mRenderer = context11->getRenderer(); | |
| mSourceBuffer = new rx::Buffer11(mBufferState, mRenderer); | |
| GLfloat testData[] = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f}; | |
| angle::Result error = mSourceBuffer->setData(nullptr, gl::BufferBinding::Array, testData, | |
| sizeof(testData), gl::BufferUsage::StaticDraw); | |
| ASSERT_EQ(angle::Result::Continue, error); | |
| mTranslatedAttribute.baseOffset = 0; | |
| mTranslatedAttribute.usesFirstVertexOffset = false; | |
| mTranslatedAttribute.stride = sizeof(GLfloat); | |
| GLubyte indices[] = {0, 0, 3, 4, 2, 1, 1}; | |
| for (size_t i = 0; i < ArraySize(indices); i++) | |
| { | |
| mExpectedExpandedData.push_back(testData[indices[i]]); | |
| mubyteIndices.push_back(indices[i]); | |
| muintIndices.push_back(indices[i]); | |
| mushortIndices.push_back(indices[i]); | |
| } | |
| } | |
| void testTearDown() override { SafeDelete(mSourceBuffer); } | |
| void createMappableCompareBufferFromEmulatedBuffer(ID3D11Buffer *sourceBuffer, | |
| GLuint size, | |
| ID3D11Buffer **mappableBuffer) | |
| { | |
| *mappableBuffer = nullptr; | |
| D3D11_BUFFER_DESC bufferDesc; | |
| bufferDesc.ByteWidth = size; | |
| bufferDesc.MiscFlags = 0; | |
| bufferDesc.StructureByteStride = 0; | |
| bufferDesc.Usage = D3D11_USAGE_STAGING; | |
| bufferDesc.BindFlags = 0; | |
| bufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE; | |
| HRESULT hr = mRenderer->getDevice()->CreateBuffer(&bufferDesc, nullptr, mappableBuffer); | |
| ASSERT_TRUE(SUCCEEDED(hr)); | |
| D3D11_BOX srcBox; | |
| srcBox.left = 0; | |
| srcBox.right = size; | |
| srcBox.top = 0; | |
| srcBox.bottom = 1; | |
| srcBox.front = 0; | |
| srcBox.back = 1; | |
| mRenderer->getDeviceContext()->CopySubresourceRegion(*mappableBuffer, 0, 0, 0, 0, | |
| sourceBuffer, 0, &srcBox); | |
| } | |
| void compareContents(ID3D11Buffer *actual) | |
| { | |
| ID3D11Buffer *compareBuffer = nullptr; | |
| createMappableCompareBufferFromEmulatedBuffer( | |
| actual, sizeof(GLfloat) * static_cast<GLuint>(mExpectedExpandedData.size()), | |
| &compareBuffer); | |
| D3D11_MAPPED_SUBRESOURCE mappedResource; | |
| HRESULT hr = mRenderer->getDeviceContext()->Map(compareBuffer, 0, D3D11_MAP_READ, 0, | |
| &mappedResource); | |
| ASSERT_TRUE(SUCCEEDED(hr)); | |
| GLfloat *compareData = static_cast<GLfloat *>(mappedResource.pData); | |
| for (size_t i = 0; i < mExpectedExpandedData.size(); i++) | |
| { | |
| EXPECT_EQ(mExpectedExpandedData[i], compareData[i]); | |
| } | |
| mRenderer->getDeviceContext()->Unmap(compareBuffer, 0); | |
| SafeRelease(compareBuffer); | |
| } | |
| void emulateAndCompare(rx::SourceIndexData *srcData) | |
| { | |
| ID3D11Buffer *emulatedBuffer = nullptr; | |
| angle::Result error = mSourceBuffer->getEmulatedIndexedBuffer( | |
| mContext, srcData, mTranslatedAttribute, 0, &emulatedBuffer); | |
| ASSERT_EQ(angle::Result::Continue, error); | |
| ASSERT_TRUE(emulatedBuffer != nullptr); | |
| compareContents(emulatedBuffer); | |
| } | |
| protected: | |
| gl::Context *mContext; | |
| rx::Buffer11 *mSourceBuffer; | |
| rx::Renderer11 *mRenderer; | |
| rx::TranslatedAttribute mTranslatedAttribute; | |
| std::vector<GLfloat> mExpectedExpandedData; | |
| std::vector<GLubyte> mubyteIndices; | |
| std::vector<GLuint> muintIndices; | |
| std::vector<GLushort> mushortIndices; | |
| gl::BufferState mBufferState; | |
| }; | |
| // This tests that a GL_UNSIGNED_BYTE indices list can be successfully expanded | |
| // into a valid emulated indexed buffer. | |
| TEST_P(D3D11EmulatedIndexedBufferTest, TestNativeToExpandedUsingGLubyteIndices) | |
| { | |
| rx::SourceIndexData srcData = {nullptr, mubyteIndices.data(), | |
| static_cast<unsigned int>(mubyteIndices.size()), | |
| gl::DrawElementsType::UnsignedByte, false}; | |
| emulateAndCompare(&srcData); | |
| } | |
| // This tests that a GL_UNSIGNED_SHORT indices list can be successfully expanded | |
| // into a valid emulated indexed buffer. | |
| TEST_P(D3D11EmulatedIndexedBufferTest, TestNativeToExpandedUsingGLushortIndices) | |
| { | |
| rx::SourceIndexData srcData = {nullptr, mushortIndices.data(), | |
| static_cast<unsigned int>(mushortIndices.size()), | |
| gl::DrawElementsType::UnsignedShort, false}; | |
| emulateAndCompare(&srcData); | |
| } | |
| // This tests that a GL_UNSIGNED_INT indices list can be successfully expanded | |
| // into a valid emulated indexed buffer. | |
| TEST_P(D3D11EmulatedIndexedBufferTest, TestNativeToExpandedUsingGLuintIndices) | |
| { | |
| rx::SourceIndexData srcData = {nullptr, muintIndices.data(), | |
| static_cast<unsigned int>(muintIndices.size()), | |
| gl::DrawElementsType::UnsignedInt, false}; | |
| emulateAndCompare(&srcData); | |
| } | |
| // This tests verifies that a Buffer11 contents remain unchanged after calling | |
| // getEmulatedIndexedBuffer | |
| TEST_P(D3D11EmulatedIndexedBufferTest, TestSourceBufferRemainsUntouchedAfterExpandOperation) | |
| { | |
| // Copy the original source buffer before any expand calls have been made | |
| gl::BufferState cleanSourceState; | |
| rx::Buffer11 *cleanSourceBuffer = new rx::Buffer11(cleanSourceState, mRenderer); | |
| ASSERT_EQ(angle::Result::Continue, cleanSourceBuffer->copySubData(nullptr, mSourceBuffer, 0, 0, | |
| mSourceBuffer->getSize())); | |
| // Do a basic exanded and compare test. | |
| rx::SourceIndexData srcData = {nullptr, muintIndices.data(), | |
| static_cast<unsigned int>(muintIndices.size()), | |
| gl::DrawElementsType::UnsignedInt, false}; | |
| emulateAndCompare(&srcData); | |
| const uint8_t *sourceBufferMem = nullptr; | |
| const uint8_t *cleanBufferMem = nullptr; | |
| ASSERT_EQ(angle::Result::Continue, mSourceBuffer->getData(mContext, &sourceBufferMem)); | |
| ASSERT_EQ(angle::Result::Continue, cleanSourceBuffer->getData(mContext, &cleanBufferMem)); | |
| ASSERT_EQ(0, memcmp(sourceBufferMem, cleanBufferMem, cleanSourceBuffer->getSize())); | |
| SafeDelete(cleanSourceBuffer); | |
| } | |
| ANGLE_INSTANTIATE_TEST(D3D11EmulatedIndexedBufferTest, ES2_D3D11(), ES3_D3D11(), ES31_D3D11()); | |
| } // anonymous namespace |