diff options
Diffstat (limited to 'src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp')
-rw-r--r-- | src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp | 3096 |
1 files changed, 1818 insertions, 1278 deletions
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp index 223e2b019b..62badccefc 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp @@ -8,47 +8,63 @@ #include "libANGLE/renderer/d3d/d3d11/Renderer11.h" -#include "common/utilities.h" +#include <EGL/eglext.h> +#include <sstream> +#if !defined(ANGLE_MINGW32_COMPAT) && WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP +#include <VersionHelpers.h> +#endif + #include "common/tls.h" +#include "common/utilities.h" #include "libANGLE/Buffer.h" #include "libANGLE/Display.h" +#include "libANGLE/formatutils.h" #include "libANGLE/Framebuffer.h" #include "libANGLE/FramebufferAttachment.h" +#include "libANGLE/histogram_macros.h" #include "libANGLE/Program.h" -#include "libANGLE/State.h" -#include "libANGLE/Surface.h" -#include "libANGLE/formatutils.h" #include "libANGLE/renderer/d3d/CompilerD3D.h" -#include "libANGLE/renderer/d3d/FramebufferD3D.h" -#include "libANGLE/renderer/d3d/IndexDataManager.h" -#include "libANGLE/renderer/d3d/ProgramD3D.h" -#include "libANGLE/renderer/d3d/RenderbufferD3D.h" -#include "libANGLE/renderer/d3d/ShaderD3D.h" -#include "libANGLE/renderer/d3d/SurfaceD3D.h" -#include "libANGLE/renderer/d3d/TextureD3D.h" -#include "libANGLE/renderer/d3d/TransformFeedbackD3D.h" -#include "libANGLE/renderer/d3d/VertexDataManager.h" #include "libANGLE/renderer/d3d/d3d11/Blit11.h" #include "libANGLE/renderer/d3d/d3d11/Buffer11.h" #include "libANGLE/renderer/d3d/d3d11/Clear11.h" +#include "libANGLE/renderer/d3d/d3d11/dxgi_support_table.h" #include "libANGLE/renderer/d3d/d3d11/Fence11.h" +#include "libANGLE/renderer/d3d/d3d11/formatutils11.h" #include "libANGLE/renderer/d3d/d3d11/Framebuffer11.h" #include "libANGLE/renderer/d3d/d3d11/Image11.h" #include "libANGLE/renderer/d3d/d3d11/IndexBuffer11.h" #include "libANGLE/renderer/d3d/d3d11/PixelTransfer11.h" #include "libANGLE/renderer/d3d/d3d11/Query11.h" +#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h" #include "libANGLE/renderer/d3d/d3d11/RenderTarget11.h" #include "libANGLE/renderer/d3d/d3d11/ShaderExecutable11.h" #include "libANGLE/renderer/d3d/d3d11/SwapChain11.h" +#include "libANGLE/renderer/d3d/d3d11/texture_format_table.h" #include "libANGLE/renderer/d3d/d3d11/TextureStorage11.h" #include "libANGLE/renderer/d3d/d3d11/Trim11.h" #include "libANGLE/renderer/d3d/d3d11/VertexArray11.h" #include "libANGLE/renderer/d3d/d3d11/VertexBuffer11.h" -#include "libANGLE/renderer/d3d/d3d11/formatutils11.h" -#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h" +#include "libANGLE/renderer/d3d/CompilerD3D.h" +#include "libANGLE/renderer/d3d/DeviceD3D.h" +#include "libANGLE/renderer/d3d/FramebufferD3D.h" +#include "libANGLE/renderer/d3d/IndexDataManager.h" +#include "libANGLE/renderer/d3d/ProgramD3D.h" +#include "libANGLE/renderer/d3d/RenderbufferD3D.h" +#include "libANGLE/renderer/d3d/ShaderD3D.h" +#include "libANGLE/renderer/d3d/SurfaceD3D.h" +#include "libANGLE/renderer/d3d/TextureD3D.h" +#include "libANGLE/renderer/d3d/TransformFeedbackD3D.h" +#include "libANGLE/renderer/d3d/VertexDataManager.h" +#include "libANGLE/State.h" +#include "libANGLE/Surface.h" +#include "third_party/trace_event/trace_event.h" -#include <sstream> -#include <EGL/eglext.h> +// Include the D3D9 debug annotator header for use by the desktop D3D11 renderer +// because the D3D11 interface method ID3DUserDefinedAnnotation::GetStatus +// doesn't work with the Graphics Diagnostics tools in Visual Studio 2013. +#ifdef ANGLE_ENABLE_D3D9 +#include "libANGLE/renderer/d3d/d3d9/DebugAnnotator9.h" +#endif // Enable ANGLE_SKIP_DXGI_1_2_CHECK if there is not a possibility of using cross-process // HWNDs or the Windows 7 Platform Update (KB2670838) is expected to be installed. @@ -62,67 +78,6 @@ #define ANGLE_SUPPRESS_D3D11_HAZARD_WARNINGS 1 #endif -#ifndef __d3d11sdklayers_h__ -#define D3D11_MESSAGE_CATEGORY UINT -#define D3D11_MESSAGE_SEVERITY UINT -#define D3D11_MESSAGE_ID UINT -struct D3D11_MESSAGE; -typedef struct D3D11_INFO_QUEUE_FILTER_DESC -{ - UINT NumCategories; - D3D11_MESSAGE_CATEGORY *pCategoryList; - UINT NumSeverities; - D3D11_MESSAGE_SEVERITY *pSeverityList; - UINT NumIDs; - D3D11_MESSAGE_ID *pIDList; -} D3D11_INFO_QUEUE_FILTER_DESC; -typedef struct D3D11_INFO_QUEUE_FILTER -{ - D3D11_INFO_QUEUE_FILTER_DESC AllowList; - D3D11_INFO_QUEUE_FILTER_DESC DenyList; -} D3D11_INFO_QUEUE_FILTER; -static const IID IID_ID3D11InfoQueue = { 0x6543dbb6, 0x1b48, 0x42f5, 0xab, 0x82, 0xe9, 0x7e, 0xc7, 0x43, 0x26, 0xf6 }; -MIDL_INTERFACE("6543dbb6-1b48-42f5-ab82-e97ec74326f6") ID3D11InfoQueue : public IUnknown -{ -public: - virtual HRESULT __stdcall SetMessageCountLimit(UINT64) = 0; - virtual void __stdcall ClearStoredMessages() = 0; - virtual HRESULT __stdcall GetMessage(UINT64, D3D11_MESSAGE *, SIZE_T *) = 0; - virtual UINT64 __stdcall GetNumMessagesAllowedByStorageFilter() = 0; - virtual UINT64 __stdcall GetNumMessagesDeniedByStorageFilter() = 0; - virtual UINT64 __stdcall GetNumStoredMessages() = 0; - virtual UINT64 __stdcall GetNumStoredMessagesAllowedByRetrievalFilter() = 0; - virtual UINT64 __stdcall GetNumMessagesDiscardedByMessageCountLimit() = 0; - virtual UINT64 __stdcall GetMessageCountLimit() = 0; - virtual HRESULT __stdcall AddStorageFilterEntries(D3D11_INFO_QUEUE_FILTER *) = 0; - virtual HRESULT __stdcall GetStorageFilter(D3D11_INFO_QUEUE_FILTER *, SIZE_T *) = 0; - virtual void __stdcall ClearStorageFilter() = 0; - virtual HRESULT __stdcall PushEmptyStorageFilter() = 0; - virtual HRESULT __stdcall PushCopyOfStorageFilter() = 0; - virtual HRESULT __stdcall PushStorageFilter(D3D11_INFO_QUEUE_FILTER *) = 0; - virtual void __stdcall PopStorageFilter() = 0; - virtual UINT __stdcall GetStorageFilterStackSize() = 0; - virtual HRESULT __stdcall AddRetrievalFilterEntries(D3D11_INFO_QUEUE_FILTER *) = 0; - virtual HRESULT __stdcall GetRetrievalFilter(D3D11_INFO_QUEUE_FILTER *, SIZE_T *) = 0; - virtual void __stdcall ClearRetrievalFilter() = 0; - virtual HRESULT __stdcall PushEmptyRetrievalFilter() = 0; - virtual HRESULT __stdcall PushCopyOfRetrievalFilter() = 0; - virtual HRESULT __stdcall PushRetrievalFilter(D3D11_INFO_QUEUE_FILTER *) = 0; - virtual void __stdcall PopRetrievalFilter() = 0; - virtual UINT __stdcall GetRetrievalFilterStackSize() = 0; - virtual HRESULT __stdcall AddMessage(D3D11_MESSAGE_CATEGORY, D3D11_MESSAGE_SEVERITY, D3D11_MESSAGE_ID, LPCSTR) = 0; - virtual HRESULT __stdcall AddApplicationMessage(D3D11_MESSAGE_SEVERITY, LPCSTR) = 0; - virtual HRESULT __stdcall SetBreakOnCategory(D3D11_MESSAGE_CATEGORY, BOOL) = 0; - virtual HRESULT __stdcall SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY, BOOL) = 0; - virtual HRESULT __stdcall SetBreakOnID(D3D11_MESSAGE_ID, BOOL) = 0; - virtual BOOL __stdcall GetBreakOnCategory(D3D11_MESSAGE_CATEGORY) = 0; - virtual BOOL __stdcall GetBreakOnSeverity(D3D11_MESSAGE_SEVERITY) = 0; - virtual BOOL __stdcall GetBreakOnID(D3D11_MESSAGE_ID) = 0; - virtual void __stdcall SetMuteDebugOutput(BOOL) = 0; - virtual BOOL __stdcall GetMuteDebugOutput() = 0; -}; -#endif - namespace rx { @@ -134,107 +89,299 @@ enum MAX_TEXTURE_IMAGE_UNITS_VTF_SM4 = 16 }; -// dirtyPointer is a special value that will make the comparison with any valid pointer fail and force the renderer to re-apply the state. -static const uintptr_t DirtyPointer = static_cast<uintptr_t>(-1); +#if defined(ANGLE_ENABLE_D3D11_1) +void CalculateConstantBufferParams(GLintptr offset, GLsizeiptr size, UINT *outFirstConstant, UINT *outNumConstants) +{ + // The offset must be aligned to 256 bytes (should have been enforced by glBindBufferRange). + ASSERT(offset % 256 == 0); + + // firstConstant and numConstants are expressed in constants of 16-bytes. Furthermore they must be a multiple of 16 constants. + *outFirstConstant = static_cast<UINT>(offset / 16); + + // The GL size is not required to be aligned to a 256 bytes boundary. + // Round the size up to a 256 bytes boundary then express the results in constants of 16-bytes. + *outNumConstants = static_cast<UINT>(rx::roundUp(size, static_cast<GLsizeiptr>(256)) / 16); -static bool ImageIndexConflictsWithSRV(const gl::ImageIndex *index, D3D11_SHADER_RESOURCE_VIEW_DESC desc) + // Since the size is rounded up, firstConstant + numConstants may be bigger than the actual size of the buffer. + // This behaviour is explictly allowed according to the documentation on ID3D11DeviceContext1::PSSetConstantBuffers1 + // https://msdn.microsoft.com/en-us/library/windows/desktop/hh404649%28v=vs.85%29.aspx +} +#endif + +enum ANGLEFeatureLevel { - unsigned mipLevel = index->mipIndex; - unsigned layerIndex = index->layerIndex; - GLenum type = index->type; + ANGLE_FEATURE_LEVEL_INVALID, + ANGLE_FEATURE_LEVEL_9_3, + ANGLE_FEATURE_LEVEL_10_0, + ANGLE_FEATURE_LEVEL_10_1, + ANGLE_FEATURE_LEVEL_11_0, + ANGLE_FEATURE_LEVEL_11_1, + NUM_ANGLE_FEATURE_LEVELS +}; - switch (desc.ViewDimension) +ANGLEFeatureLevel GetANGLEFeatureLevel(D3D_FEATURE_LEVEL d3dFeatureLevel) +{ + switch (d3dFeatureLevel) { - case D3D11_SRV_DIMENSION_TEXTURE2D: - { - unsigned maxSrvMip = desc.Texture2D.MipLevels + desc.Texture2D.MostDetailedMip; - maxSrvMip = (desc.Texture2D.MipLevels == -1) ? INT_MAX : maxSrvMip; + case D3D_FEATURE_LEVEL_9_3: return ANGLE_FEATURE_LEVEL_9_3; + case D3D_FEATURE_LEVEL_10_0: return ANGLE_FEATURE_LEVEL_10_0; + case D3D_FEATURE_LEVEL_10_1: return ANGLE_FEATURE_LEVEL_10_1; + case D3D_FEATURE_LEVEL_11_0: return ANGLE_FEATURE_LEVEL_11_0; + // Note: we don't ever request a 11_1 device, because this gives + // an E_INVALIDARG error on systems that don't have the platform update. + case D3D_FEATURE_LEVEL_11_1: return ANGLE_FEATURE_LEVEL_11_1; + default: return ANGLE_FEATURE_LEVEL_INVALID; + } +} - unsigned mipMin = index->mipIndex; - unsigned mipMax = (layerIndex == -1) ? INT_MAX : layerIndex; +void SetLineLoopIndices(GLuint *dest, size_t count) +{ + for (size_t i = 0; i < count; i++) + { + dest[i] = static_cast<GLuint>(i); + } + dest[count] = 0; +} - return type == GL_TEXTURE_2D && RangeUI(mipMin, mipMax).intersects(RangeUI(desc.Texture2D.MostDetailedMip, maxSrvMip)); - } +template <typename T> +void CopyLineLoopIndices(const GLvoid *indices, GLuint *dest, size_t count) +{ + const T *srcPtr = static_cast<const T *>(indices); + for (size_t i = 0; i < count; ++i) + { + dest[i] = static_cast<GLuint>(srcPtr[i]); + } + dest[count] = static_cast<GLuint>(srcPtr[0]); +} - case D3D11_SRV_DIMENSION_TEXTURE2DARRAY: - { - unsigned maxSrvMip = desc.Texture2DArray.MipLevels + desc.Texture2DArray.MostDetailedMip; - maxSrvMip = (desc.Texture2DArray.MipLevels == -1) ? INT_MAX : maxSrvMip; +void SetTriangleFanIndices(GLuint *destPtr, size_t numTris) +{ + for (size_t i = 0; i < numTris; i++) + { + destPtr[i * 3 + 0] = 0; + destPtr[i * 3 + 1] = static_cast<GLuint>(i) + 1; + destPtr[i * 3 + 2] = static_cast<GLuint>(i) + 2; + } +} + +template <typename T> +void CopyLineLoopIndicesWithRestart(const GLvoid *indices, + size_t count, + GLenum indexType, + std::vector<GLuint> *bufferOut) +{ + GLuint restartIndex = gl::GetPrimitiveRestartIndex(indexType); + GLuint d3dRestartIndex = static_cast<GLuint>(d3d11::GetPrimitiveRestartIndex()); + const T *srcPtr = static_cast<const T *>(indices); + Optional<GLuint> currentLoopStart; - unsigned maxSlice = desc.Texture2DArray.FirstArraySlice + desc.Texture2DArray.ArraySize; + bufferOut->clear(); - // Cube maps can be mapped to Texture2DArray SRVs - return (type == GL_TEXTURE_2D_ARRAY || gl::IsCubeMapTextureTarget(type)) && - desc.Texture2DArray.MostDetailedMip <= mipLevel && mipLevel < maxSrvMip && - desc.Texture2DArray.FirstArraySlice <= layerIndex && layerIndex < maxSlice; - } + for (size_t indexIdx = 0; indexIdx < count; ++indexIdx) + { + GLuint value = static_cast<GLuint>(srcPtr[indexIdx]); - case D3D11_SRV_DIMENSION_TEXTURECUBE: + if (value == restartIndex) { - unsigned maxSrvMip = desc.TextureCube.MipLevels + desc.TextureCube.MostDetailedMip; - maxSrvMip = (desc.TextureCube.MipLevels == -1) ? INT_MAX : maxSrvMip; - - return gl::IsCubeMapTextureTarget(type) && - desc.TextureCube.MostDetailedMip <= mipLevel && mipLevel < maxSrvMip; + if (currentLoopStart.valid()) + { + bufferOut->push_back(currentLoopStart.value()); + bufferOut->push_back(d3dRestartIndex); + currentLoopStart.reset(); + } } - - case D3D11_SRV_DIMENSION_TEXTURE3D: + else { - unsigned maxSrvMip = desc.Texture3D.MipLevels + desc.Texture3D.MostDetailedMip; - maxSrvMip = (desc.Texture3D.MipLevels == -1) ? INT_MAX : maxSrvMip; - - return type == GL_TEXTURE_3D && - desc.Texture3D.MostDetailedMip <= mipLevel && mipLevel < maxSrvMip; + bufferOut->push_back(value); + if (!currentLoopStart.valid()) + { + currentLoopStart = value; + } } - default: - // We only handle the cases corresponding to valid image indexes - UNIMPLEMENTED(); } - return false; + if (currentLoopStart.valid()) + { + bufferOut->push_back(currentLoopStart.value()); + } } -// Does *not* increment the resource ref count!! -ID3D11Resource *GetViewResource(ID3D11View *view) +void GetLineLoopIndices(const GLvoid *indices, + GLenum indexType, + GLuint count, + bool usePrimitiveRestartFixedIndex, + std::vector<GLuint> *bufferOut) { - ID3D11Resource *resource = NULL; - ASSERT(view); - view->GetResource(&resource); - resource->Release(); - return resource; + if (indexType != GL_NONE && usePrimitiveRestartFixedIndex) + { + switch (indexType) + { + case GL_UNSIGNED_BYTE: + CopyLineLoopIndicesWithRestart<GLubyte>(indices, count, indexType, bufferOut); + break; + case GL_UNSIGNED_SHORT: + CopyLineLoopIndicesWithRestart<GLushort>(indices, count, indexType, bufferOut); + break; + case GL_UNSIGNED_INT: + CopyLineLoopIndicesWithRestart<GLuint>(indices, count, indexType, bufferOut); + break; + default: + UNREACHABLE(); + break; + } + return; + } + + // For non-primitive-restart draws, the index count is static. + bufferOut->resize(static_cast<size_t>(count) + 1); + + switch (indexType) + { + // Non-indexed draw + case GL_NONE: + SetLineLoopIndices(&(*bufferOut)[0], count); + break; + case GL_UNSIGNED_BYTE: + CopyLineLoopIndices<GLubyte>(indices, &(*bufferOut)[0], count); + break; + case GL_UNSIGNED_SHORT: + CopyLineLoopIndices<GLushort>(indices, &(*bufferOut)[0], count); + break; + case GL_UNSIGNED_INT: + CopyLineLoopIndices<GLuint>(indices, &(*bufferOut)[0], count); + break; + default: + UNREACHABLE(); + break; + } } -void CalculateConstantBufferParams(GLintptr offset, GLsizeiptr size, UINT *outFirstConstant, UINT *outNumConstants) +template <typename T> +void CopyTriangleFanIndices(const GLvoid *indices, GLuint *destPtr, size_t numTris) { - // The offset must be aligned to 256 bytes (should have been enforced by glBindBufferRange). - ASSERT(offset % 256 == 0); + const T *srcPtr = static_cast<const T *>(indices); - // firstConstant and numConstants are expressed in constants of 16-bytes. Furthermore they must be a multiple of 16 constants. - *outFirstConstant = offset / 16; + for (size_t i = 0; i < numTris; i++) + { + destPtr[i * 3 + 0] = static_cast<GLuint>(srcPtr[0]); + destPtr[i * 3 + 1] = static_cast<GLuint>(srcPtr[i + 1]); + destPtr[i * 3 + 2] = static_cast<GLuint>(srcPtr[i + 2]); + } +} - // The GL size is not required to be aligned to a 256 bytes boundary. - // Round the size up to a 256 bytes boundary then express the results in constants of 16-bytes. - *outNumConstants = rx::roundUp(size, static_cast<GLsizeiptr>(256)) / 16; +template <typename T> +void CopyTriangleFanIndicesWithRestart(const GLvoid *indices, + GLuint indexCount, + GLenum indexType, + std::vector<GLuint> *bufferOut) +{ + GLuint restartIndex = gl::GetPrimitiveRestartIndex(indexType); + GLuint d3dRestartIndex = gl::GetPrimitiveRestartIndex(GL_UNSIGNED_INT); + const T *srcPtr = static_cast<const T *>(indices); + Optional<GLuint> vertexA; + Optional<GLuint> vertexB; - // Since the size is rounded up, firstConstant + numConstants may be bigger than the actual size of the buffer. - // This behaviour is explictly allowed according to the documentation on ID3D11DeviceContext1::PSSetConstantBuffers1 - // https://msdn.microsoft.com/en-us/library/windows/desktop/hh404649%28v=vs.85%29.aspx + bufferOut->clear(); + + for (size_t indexIdx = 0; indexIdx < indexCount; ++indexIdx) + { + GLuint value = static_cast<GLuint>(srcPtr[indexIdx]); + + if (value == restartIndex) + { + bufferOut->push_back(d3dRestartIndex); + vertexA.reset(); + vertexB.reset(); + } + else + { + if (!vertexA.valid()) + { + vertexA = value; + } + else if (!vertexB.valid()) + { + vertexB = value; + } + else + { + bufferOut->push_back(vertexA.value()); + bufferOut->push_back(vertexB.value()); + bufferOut->push_back(value); + vertexB = value; + } + } + } } +void GetTriFanIndices(const GLvoid *indices, + GLenum indexType, + GLuint count, + bool usePrimitiveRestartFixedIndex, + std::vector<GLuint> *bufferOut) +{ + if (indexType != GL_NONE && usePrimitiveRestartFixedIndex) + { + switch (indexType) + { + case GL_UNSIGNED_BYTE: + CopyTriangleFanIndicesWithRestart<GLubyte>(indices, count, indexType, bufferOut); + break; + case GL_UNSIGNED_SHORT: + CopyTriangleFanIndicesWithRestart<GLushort>(indices, count, indexType, bufferOut); + break; + case GL_UNSIGNED_INT: + CopyTriangleFanIndicesWithRestart<GLuint>(indices, count, indexType, bufferOut); + break; + default: + UNREACHABLE(); + break; + } + return; + } + + // For non-primitive-restart draws, the index count is static. + GLuint numTris = count - 2; + bufferOut->resize(numTris * 3); + + switch (indexType) + { + // Non-indexed draw + case GL_NONE: + SetTriangleFanIndices(&(*bufferOut)[0], numTris); + break; + case GL_UNSIGNED_BYTE: + CopyTriangleFanIndices<GLubyte>(indices, &(*bufferOut)[0], numTris); + break; + case GL_UNSIGNED_SHORT: + CopyTriangleFanIndices<GLushort>(indices, &(*bufferOut)[0], numTris); + break; + case GL_UNSIGNED_INT: + CopyTriangleFanIndices<GLuint>(indices, &(*bufferOut)[0], numTris); + break; + default: + UNREACHABLE(); + break; + } } +} // anonymous namespace + Renderer11::Renderer11(egl::Display *display) : RendererD3D(display), - mStateCache(this) + mStateCache(this), + mStateManager(this), + mLastHistogramUpdateTime(ANGLEPlatformCurrent()->monotonicallyIncreasingTime()) +#if !defined(ANGLE_MINGW32_COMPAT) + ,mDebug(nullptr) +#endif { - // Initialize global annotator - gl::InitializeDebugAnnotations(&mAnnotator); - mVertexDataManager = NULL; mIndexDataManager = NULL; mLineLoopIB = NULL; mTriangleFanIB = NULL; + mAppliedIBChanged = false; mBlit = NULL; mPixelTransfer = NULL; @@ -245,10 +392,18 @@ Renderer11::Renderer11(egl::Display *display) mSyncQuery = NULL; - mSupportsConstantBufferOffsets = false; + mRenderer11DeviceCaps.supportsClearView = false; + mRenderer11DeviceCaps.supportsConstantBufferOffsets = false; + mRenderer11DeviceCaps.supportsDXGI1_2 = false; + mRenderer11DeviceCaps.B5G6R5support = 0; + mRenderer11DeviceCaps.B4G4R4A4support = 0; + mRenderer11DeviceCaps.B5G5R5A1support = 0; mD3d11Module = NULL; mDxgiModule = NULL; + mDCompModule = NULL; + mCreatedWithDeviceEXT = false; + mEGLDevice = nullptr; mDevice = NULL; mDeviceContext = NULL; @@ -265,89 +420,105 @@ Renderer11::Renderer11(egl::Display *display) mAppliedNumXFBBindings = static_cast<size_t>(-1); - const auto &attributes = mDisplay->getAttributeMap(); - - EGLint requestedMajorVersion = attributes.get(EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE, EGL_DONT_CARE); - EGLint requestedMinorVersion = attributes.get(EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE, EGL_DONT_CARE); + ZeroMemory(&mAdapterDescription, sizeof(mAdapterDescription)); - if (requestedMajorVersion == EGL_DONT_CARE || requestedMajorVersion >= 11) + if (mDisplay->getPlatform() == EGL_PLATFORM_ANGLE_ANGLE) { - if (requestedMinorVersion == EGL_DONT_CARE || requestedMinorVersion >= 0) - { - mAvailableFeatureLevels.push_back(D3D_FEATURE_LEVEL_11_0); - } - } + const auto &attributes = mDisplay->getAttributeMap(); - if (requestedMajorVersion == EGL_DONT_CARE || requestedMajorVersion >= 10) - { - if (requestedMinorVersion == EGL_DONT_CARE || requestedMinorVersion >= 1) + EGLint requestedMajorVersion = + attributes.get(EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE, EGL_DONT_CARE); + EGLint requestedMinorVersion = + attributes.get(EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE, EGL_DONT_CARE); + + if (requestedMajorVersion == EGL_DONT_CARE || requestedMajorVersion >= 11) { - mAvailableFeatureLevels.push_back(D3D_FEATURE_LEVEL_10_1); + if (requestedMinorVersion == EGL_DONT_CARE || requestedMinorVersion >= 0) + { + mAvailableFeatureLevels.push_back(D3D_FEATURE_LEVEL_11_0); + } } - if (requestedMinorVersion == EGL_DONT_CARE || requestedMinorVersion >= 0) + + if (requestedMajorVersion == EGL_DONT_CARE || requestedMajorVersion >= 10) { - mAvailableFeatureLevels.push_back(D3D_FEATURE_LEVEL_10_0); + if (requestedMinorVersion == EGL_DONT_CARE || requestedMinorVersion >= 1) + { + mAvailableFeatureLevels.push_back(D3D_FEATURE_LEVEL_10_1); + } + if (requestedMinorVersion == EGL_DONT_CARE || requestedMinorVersion >= 0) + { + mAvailableFeatureLevels.push_back(D3D_FEATURE_LEVEL_10_0); + } } - } #if defined(ANGLE_ENABLE_WINDOWS_STORE) - if (requestedMajorVersion == EGL_DONT_CARE || requestedMajorVersion >= 9) + if (requestedMajorVersion == EGL_DONT_CARE || requestedMajorVersion >= 9) #else - if (requestedMajorVersion == 9 && requestedMinorVersion == 3) + if (requestedMajorVersion == 9 && requestedMinorVersion == 3) #endif - { - if (requestedMinorVersion == EGL_DONT_CARE || requestedMinorVersion >= 3) { - mAvailableFeatureLevels.push_back(D3D_FEATURE_LEVEL_9_3); - } + if (requestedMinorVersion == EGL_DONT_CARE || requestedMinorVersion >= 3) + { + mAvailableFeatureLevels.push_back(D3D_FEATURE_LEVEL_9_3); + } #if defined(ANGLE_ENABLE_WINDOWS_STORE) - if (requestedMinorVersion == EGL_DONT_CARE || requestedMinorVersion >= 2) - { - mAvailableFeatureLevels.push_back(D3D_FEATURE_LEVEL_9_2); + if (requestedMinorVersion == EGL_DONT_CARE || requestedMinorVersion >= 2) + { + mAvailableFeatureLevels.push_back(D3D_FEATURE_LEVEL_9_2); + } + if (requestedMinorVersion == EGL_DONT_CARE || requestedMinorVersion >= 1) + { + mAvailableFeatureLevels.push_back(D3D_FEATURE_LEVEL_9_1); + } +#endif } - if (requestedMinorVersion == EGL_DONT_CARE || requestedMinorVersion >= 1) + + EGLint requestedDeviceType = attributes.get(EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE, + EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE); + switch (requestedDeviceType) { - mAvailableFeatureLevels.push_back(D3D_FEATURE_LEVEL_9_1); - } -#endif - } + case EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE: + mRequestedDriverType = D3D_DRIVER_TYPE_HARDWARE; + break; - EGLint requestedDeviceType = attributes.get(EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE, - EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE); - switch (requestedDeviceType) - { - case EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE: - mDriverType = D3D_DRIVER_TYPE_HARDWARE; - break; + case EGL_PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE: + mRequestedDriverType = D3D_DRIVER_TYPE_WARP; + break; - case EGL_PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE: - mDriverType = D3D_DRIVER_TYPE_WARP; - break; + case EGL_PLATFORM_ANGLE_DEVICE_TYPE_REFERENCE_ANGLE: + mRequestedDriverType = D3D_DRIVER_TYPE_REFERENCE; + break; - case EGL_PLATFORM_ANGLE_DEVICE_TYPE_REFERENCE_ANGLE: - mDriverType = D3D_DRIVER_TYPE_REFERENCE; - break; + case EGL_PLATFORM_ANGLE_DEVICE_TYPE_NULL_ANGLE: + mRequestedDriverType = D3D_DRIVER_TYPE_NULL; + break; - case EGL_PLATFORM_ANGLE_DEVICE_TYPE_NULL_ANGLE: - mDriverType = D3D_DRIVER_TYPE_NULL; - break; + default: + UNREACHABLE(); + } - default: - UNREACHABLE(); + const EGLenum presentPath = attributes.get(EGL_EXPERIMENTAL_PRESENT_PATH_ANGLE, + EGL_EXPERIMENTAL_PRESENT_PATH_COPY_ANGLE); + mPresentPathFastEnabled = (presentPath == EGL_EXPERIMENTAL_PRESENT_PATH_FAST_ANGLE); } -} + else if (display->getPlatform() == EGL_PLATFORM_DEVICE_EXT) + { + mEGLDevice = GetImplAs<DeviceD3D>(display->getDevice()); + ASSERT(mEGLDevice != nullptr); + mCreatedWithDeviceEXT = true; -Renderer11::~Renderer11() -{ - release(); + // Also set EGL_PLATFORM_ANGLE_ANGLE variables, in case they're used elsewhere in ANGLE + // mAvailableFeatureLevels defaults to empty + mRequestedDriverType = D3D_DRIVER_TYPE_UNKNOWN; + mPresentPathFastEnabled = false; + } - gl::UninitializeDebugAnnotations(); + initializeDebugAnnotator(); } -Renderer11 *Renderer11::makeRenderer11(Renderer *renderer) +Renderer11::~Renderer11() { - ASSERT(HAS_DYNAMIC_TYPE(Renderer11*, renderer)); - return static_cast<Renderer11*>(renderer); + release(); } #ifndef __d3d11_1_h__ @@ -356,209 +527,268 @@ Renderer11 *Renderer11::makeRenderer11(Renderer *renderer) egl::Error Renderer11::initialize() { - if (!mCompiler.initialize()) + HRESULT result = S_OK; + + egl::Error error = initializeD3DDevice(); + if (error.isError()) { - return egl::Error(EGL_NOT_INITIALIZED, - D3D11_INIT_COMPILER_ERROR, - "Failed to initialize compiler."); + return error; } #if !defined(ANGLE_ENABLE_WINDOWS_STORE) - mDxgiModule = LoadLibrary(TEXT("dxgi.dll")); - mD3d11Module = LoadLibrary(TEXT("d3d11.dll")); - - if (mD3d11Module == NULL || mDxgiModule == NULL) +#if !ANGLE_SKIP_DXGI_1_2_CHECK { - return egl::Error(EGL_NOT_INITIALIZED, - D3D11_INIT_MISSING_DEP, - "Could not load D3D11 or DXGI library."); - } - - // create the D3D11 device - ASSERT(mDevice == NULL); - PFN_D3D11_CREATE_DEVICE D3D11CreateDevice = (PFN_D3D11_CREATE_DEVICE)GetProcAddress(mD3d11Module, "D3D11CreateDevice"); + TRACE_EVENT0("gpu.angle", "Renderer11::initialize (DXGICheck)"); + // In order to create a swap chain for an HWND owned by another process, DXGI 1.2 is required. + // The easiest way to check is to query for a IDXGIDevice2. + bool requireDXGI1_2 = false; + HWND hwnd = WindowFromDC(mDisplay->getNativeDisplayId()); + if (hwnd) + { + DWORD currentProcessId = GetCurrentProcessId(); + DWORD wndProcessId; + GetWindowThreadProcessId(hwnd, &wndProcessId); + requireDXGI1_2 = (currentProcessId != wndProcessId); + } + else + { + requireDXGI1_2 = true; + } - if (D3D11CreateDevice == NULL) - { - return egl::Error(EGL_NOT_INITIALIZED, - D3D11_INIT_MISSING_DEP, - "Could not retrieve D3D11CreateDevice address."); + if (requireDXGI1_2) + { + IDXGIDevice2 *dxgiDevice2 = NULL; + result = mDevice->QueryInterface(__uuidof(IDXGIDevice2), (void**)&dxgiDevice2); + if (FAILED(result)) + { + return egl::Error(EGL_NOT_INITIALIZED, + D3D11_INIT_INCOMPATIBLE_DXGI, + "DXGI 1.2 required to present to HWNDs owned by another process."); + } + SafeRelease(dxgiDevice2); + } } #endif +#endif - HRESULT result = S_OK; -#ifdef _DEBUG - result = D3D11CreateDevice(NULL, - mDriverType, - NULL, - D3D11_CREATE_DEVICE_DEBUG, - mAvailableFeatureLevels.data(), - mAvailableFeatureLevels.size(), - D3D11_SDK_VERSION, - &mDevice, - &mFeatureLevel, - &mDeviceContext); - - if (!mDevice || FAILED(result)) { - ERR("Failed creating Debug D3D11 device - falling back to release runtime.\n"); - } - - if (!mDevice || FAILED(result)) + TRACE_EVENT0("gpu.angle", "Renderer11::initialize (ComQueries)"); + // Cast the DeviceContext to a DeviceContext1. + // This could fail on Windows 7 without the Platform Update. + // Don't error in this case- just don't use mDeviceContext1. +#if defined(ANGLE_ENABLE_D3D11_1) + mDeviceContext1 = d3d11::DynamicCastComObject<ID3D11DeviceContext1>(mDeviceContext); #endif - { - result = D3D11CreateDevice(NULL, - mDriverType, - NULL, - 0, - mAvailableFeatureLevels.data(), - mAvailableFeatureLevels.size(), - D3D11_SDK_VERSION, - &mDevice, - &mFeatureLevel, - &mDeviceContext); - if (result == E_INVALIDARG) + IDXGIDevice *dxgiDevice = NULL; + result = mDevice->QueryInterface(__uuidof(IDXGIDevice), (void**)&dxgiDevice); + + if (FAILED(result)) { - // Cleanup done by destructor through glDestroyRenderer return egl::Error(EGL_NOT_INITIALIZED, - D3D11_INIT_CREATEDEVICE_INVALIDARG, - "Could not create D3D11 device."); + D3D11_INIT_OTHER_ERROR, + "Could not query DXGI device."); } - if (!mDevice || FAILED(result)) + result = dxgiDevice->GetParent(__uuidof(IDXGIAdapter), (void**)&mDxgiAdapter); + + if (FAILED(result)) { - // Cleanup done by destructor through glDestroyRenderer return egl::Error(EGL_NOT_INITIALIZED, - D3D11_INIT_CREATEDEVICE_ERROR, - "Could not create D3D11 device."); + D3D11_INIT_OTHER_ERROR, + "Could not retrieve DXGI adapter"); } - } -#if !defined(ANGLE_ENABLE_WINDOWS_STORE) -#if !ANGLE_SKIP_DXGI_1_2_CHECK - // In order to create a swap chain for an HWND owned by another process, DXGI 1.2 is required. - // The easiest way to check is to query for a IDXGIDevice2. - bool requireDXGI1_2 = false; - HWND hwnd = WindowFromDC(mDisplay->getNativeDisplayId()); - if (hwnd) - { - DWORD currentProcessId = GetCurrentProcessId(); - DWORD wndProcessId; - GetWindowThreadProcessId(hwnd, &wndProcessId); - requireDXGI1_2 = (currentProcessId != wndProcessId); - } - else - { - requireDXGI1_2 = true; - } + SafeRelease(dxgiDevice); - if (requireDXGI1_2) - { - IDXGIDevice2 *dxgiDevice2 = NULL; - result = mDevice->QueryInterface(__uuidof(IDXGIDevice2), (void**)&dxgiDevice2); - if (FAILED(result)) +#if defined(ANGLE_ENABLE_D3D11_1) + IDXGIAdapter2 *dxgiAdapter2 = d3d11::DynamicCastComObject<IDXGIAdapter2>(mDxgiAdapter); + + // On D3D_FEATURE_LEVEL_9_*, IDXGIAdapter::GetDesc returns "Software Adapter" for the description string. + // If DXGI1.2 is available then IDXGIAdapter2::GetDesc2 can be used to get the actual hardware values. + if (mRenderer11DeviceCaps.featureLevel <= D3D_FEATURE_LEVEL_9_3 && dxgiAdapter2 != NULL) { - return egl::Error(EGL_NOT_INITIALIZED, - D3D11_INIT_INCOMPATIBLE_DXGI, - "DXGI 1.2 required to present to HWNDs owned by another process."); + DXGI_ADAPTER_DESC2 adapterDesc2 = {}; + result = dxgiAdapter2->GetDesc2(&adapterDesc2); + if (SUCCEEDED(result)) + { + // Copy the contents of the DXGI_ADAPTER_DESC2 into mAdapterDescription (a DXGI_ADAPTER_DESC). + memcpy(mAdapterDescription.Description, adapterDesc2.Description, sizeof(mAdapterDescription.Description)); + mAdapterDescription.VendorId = adapterDesc2.VendorId; + mAdapterDescription.DeviceId = adapterDesc2.DeviceId; + mAdapterDescription.SubSysId = adapterDesc2.SubSysId; + mAdapterDescription.Revision = adapterDesc2.Revision; + mAdapterDescription.DedicatedVideoMemory = adapterDesc2.DedicatedVideoMemory; + mAdapterDescription.DedicatedSystemMemory = adapterDesc2.DedicatedSystemMemory; + mAdapterDescription.SharedSystemMemory = adapterDesc2.SharedSystemMemory; + mAdapterDescription.AdapterLuid = adapterDesc2.AdapterLuid; + } } - SafeRelease(dxgiDevice2); - } -#endif + else #endif + { + result = mDxgiAdapter->GetDesc(&mAdapterDescription); + } - // Cast the DeviceContext to a DeviceContext1. - // This could fail on Windows 7 without the Platform Update. - // Don't error in this case- just don't use mDeviceContext1. #if defined(ANGLE_ENABLE_D3D11_1) - mDeviceContext1 = d3d11::DynamicCastComObject<ID3D11DeviceContext1>(mDeviceContext); + SafeRelease(dxgiAdapter2); #endif - IDXGIDevice *dxgiDevice = NULL; - result = mDevice->QueryInterface(__uuidof(IDXGIDevice), (void**)&dxgiDevice); + if (FAILED(result)) + { + return egl::Error(EGL_NOT_INITIALIZED, + D3D11_INIT_OTHER_ERROR, + "Could not read DXGI adaptor description."); + } - if (FAILED(result)) - { - return egl::Error(EGL_NOT_INITIALIZED, - D3D11_INIT_OTHER_ERROR, - "Could not query DXGI device."); - } + memset(mDescription, 0, sizeof(mDescription)); + wcstombs(mDescription, mAdapterDescription.Description, sizeof(mDescription) - 1); - result = dxgiDevice->GetParent(__uuidof(IDXGIAdapter), (void**)&mDxgiAdapter); + result = mDxgiAdapter->GetParent(__uuidof(IDXGIFactory), (void**)&mDxgiFactory); - if (FAILED(result)) - { - return egl::Error(EGL_NOT_INITIALIZED, - D3D11_INIT_OTHER_ERROR, - "Could not retrieve DXGI adapter"); + if (!mDxgiFactory || FAILED(result)) + { + return egl::Error(EGL_NOT_INITIALIZED, + D3D11_INIT_OTHER_ERROR, + "Could not create DXGI factory."); + } } - SafeRelease(dxgiDevice); +#if !defined(ANGLE_MINGW32_COMPAT) + // Disable some spurious D3D11 debug warnings to prevent them from flooding the output log +#if defined(ANGLE_SUPPRESS_D3D11_HAZARD_WARNINGS) && defined(_DEBUG) + { + TRACE_EVENT0("gpu.angle", "Renderer11::initialize (HideWarnings)"); + ID3D11InfoQueue *infoQueue; + result = mDevice->QueryInterface(__uuidof(ID3D11InfoQueue), (void **)&infoQueue); -#if defined(ANGLE_ENABLE_D3D11_1) - IDXGIAdapter2 *dxgiAdapter2 = d3d11::DynamicCastComObject<IDXGIAdapter2>(mDxgiAdapter); + if (SUCCEEDED(result)) + { + D3D11_MESSAGE_ID hideMessages[] = + { + D3D11_MESSAGE_ID_DEVICE_DRAW_RENDERTARGETVIEW_NOT_SET + }; - // On D3D_FEATURE_LEVEL_9_*, IDXGIAdapter::GetDesc returns "Software Adapter" for the description string. - // If DXGI1.2 is available then IDXGIAdapter2::GetDesc2 can be used to get the actual hardware values. - if (mFeatureLevel <= D3D_FEATURE_LEVEL_9_3 && dxgiAdapter2 != NULL) - { - DXGI_ADAPTER_DESC2 adapterDesc2 = {0}; - dxgiAdapter2->GetDesc2(&adapterDesc2); + D3D11_INFO_QUEUE_FILTER filter = {}; + filter.DenyList.NumIDs = static_cast<unsigned int>(ArraySize(hideMessages)); + filter.DenyList.pIDList = hideMessages; - // Copy the contents of the DXGI_ADAPTER_DESC2 into mAdapterDescription (a DXGI_ADAPTER_DESC). - memcpy(mAdapterDescription.Description, adapterDesc2.Description, sizeof(mAdapterDescription.Description)); - mAdapterDescription.VendorId = adapterDesc2.VendorId; - mAdapterDescription.DeviceId = adapterDesc2.DeviceId; - mAdapterDescription.SubSysId = adapterDesc2.SubSysId; - mAdapterDescription.Revision = adapterDesc2.Revision; - mAdapterDescription.DedicatedVideoMemory = adapterDesc2.DedicatedVideoMemory; - mAdapterDescription.DedicatedSystemMemory = adapterDesc2.DedicatedSystemMemory; - mAdapterDescription.SharedSystemMemory = adapterDesc2.SharedSystemMemory; - mAdapterDescription.AdapterLuid = adapterDesc2.AdapterLuid; - } - else - { - mDxgiAdapter->GetDesc(&mAdapterDescription); + infoQueue->AddStorageFilterEntries(&filter); + SafeRelease(infoQueue); + } } +#endif - SafeRelease(dxgiAdapter2); +#if !defined(NDEBUG) + mDebug = d3d11::DynamicCastComObject<ID3D11Debug>(mDevice); #endif +#endif // !ANGLE_MINGW32_COMPAT - memset(mDescription, 0, sizeof(mDescription)); - wcstombs(mDescription, mAdapterDescription.Description, sizeof(mDescription) - 1); + initializeDevice(); + + return egl::Error(EGL_SUCCESS); +} - result = mDxgiAdapter->GetParent(__uuidof(IDXGIFactory), (void**)&mDxgiFactory); +egl::Error Renderer11::initializeD3DDevice() +{ + HRESULT result = S_OK; - if (!mDxgiFactory || FAILED(result)) + if (!mCreatedWithDeviceEXT) { - return egl::Error(EGL_NOT_INITIALIZED, - D3D11_INIT_OTHER_ERROR, - "Could not create DXGI factory."); - } +#if !defined(ANGLE_ENABLE_WINDOWS_STORE) + PFN_D3D11_CREATE_DEVICE D3D11CreateDevice = nullptr; + { + SCOPED_ANGLE_HISTOGRAM_TIMER("GPU.ANGLE.Renderer11InitializeDLLsMS"); + TRACE_EVENT0("gpu.angle", "Renderer11::initialize (Load DLLs)"); + mDxgiModule = LoadLibrary(TEXT("dxgi.dll")); + mD3d11Module = LoadLibrary(TEXT("d3d11.dll")); + mDCompModule = LoadLibrary(TEXT("dcomp.dll")); - // Disable some spurious D3D11 debug warnings to prevent them from flooding the output log -#if defined(ANGLE_SUPPRESS_D3D11_HAZARD_WARNINGS) && defined(_DEBUG) - ID3D11InfoQueue *infoQueue; - result = mDevice->QueryInterface(IID_ID3D11InfoQueue, (void **)&infoQueue); + if (mD3d11Module == nullptr || mDxgiModule == nullptr) + { + return egl::Error(EGL_NOT_INITIALIZED, D3D11_INIT_MISSING_DEP, + "Could not load D3D11 or DXGI library."); + } - if (SUCCEEDED(result)) + // create the D3D11 device + ASSERT(mDevice == nullptr); + D3D11CreateDevice = reinterpret_cast<PFN_D3D11_CREATE_DEVICE>( + GetProcAddress(mD3d11Module, "D3D11CreateDevice")); + + if (D3D11CreateDevice == nullptr) + { + return egl::Error(EGL_NOT_INITIALIZED, D3D11_INIT_MISSING_DEP, + "Could not retrieve D3D11CreateDevice address."); + } + } +#endif + +#ifdef _DEBUG + { + TRACE_EVENT0("gpu.angle", "D3D11CreateDevice (Debug)"); + result = D3D11CreateDevice(nullptr, mRequestedDriverType, nullptr, + D3D11_CREATE_DEVICE_DEBUG, mAvailableFeatureLevels.data(), + static_cast<unsigned int>(mAvailableFeatureLevels.size()), + D3D11_SDK_VERSION, &mDevice, + &(mRenderer11DeviceCaps.featureLevel), &mDeviceContext); + } + + if (!mDevice || FAILED(result)) + { + ERR("Failed creating Debug D3D11 device - falling back to release runtime.\n"); + } + + if (!mDevice || FAILED(result)) +#endif + { + SCOPED_ANGLE_HISTOGRAM_TIMER("GPU.ANGLE.D3D11CreateDeviceMS"); + TRACE_EVENT0("gpu.angle", "D3D11CreateDevice"); + + result = D3D11CreateDevice( + nullptr, mRequestedDriverType, nullptr, 0, mAvailableFeatureLevels.data(), + static_cast<unsigned int>(mAvailableFeatureLevels.size()), D3D11_SDK_VERSION, + &mDevice, &(mRenderer11DeviceCaps.featureLevel), &mDeviceContext); + + // Cleanup done by destructor + if (!mDevice || FAILED(result)) + { + ANGLE_HISTOGRAM_SPARSE_SLOWLY("GPU.ANGLE.D3D11CreateDeviceError", + static_cast<int>(result)); + return egl::Error(EGL_NOT_INITIALIZED, D3D11_INIT_CREATEDEVICE_ERROR, + "Could not create D3D11 device."); + } + } + } + else { - D3D11_MESSAGE_ID hideMessages[] = + // We should use the inputted D3D11 device instead + void *device = nullptr; + egl::Error error = mEGLDevice->getDevice(&device); + if (error.isError()) + { + return error; + } + + ID3D11Device *d3dDevice = reinterpret_cast<ID3D11Device *>(device); + if (FAILED(d3dDevice->GetDeviceRemovedReason())) { - D3D11_MESSAGE_ID_DEVICE_DRAW_RENDERTARGETVIEW_NOT_SET - }; + return egl::Error(EGL_NOT_INITIALIZED, "Inputted D3D11 device has been lost."); + } - D3D11_INFO_QUEUE_FILTER filter = {0}; - filter.DenyList.NumIDs = ArraySize(hideMessages); - filter.DenyList.pIDList = hideMessages; + if (d3dDevice->GetFeatureLevel() < D3D_FEATURE_LEVEL_9_3) + { + return egl::Error(EGL_NOT_INITIALIZED, + "Inputted D3D11 device must be Feature Level 9_3 or greater."); + } - infoQueue->AddStorageFilterEntries(&filter); - SafeRelease(infoQueue); + // The Renderer11 adds a ref to the inputted D3D11 device, like D3D11CreateDevice does. + mDevice = d3dDevice; + mDevice->AddRef(); + mDevice->GetImmediateContext(&mDeviceContext); + mRenderer11DeviceCaps.featureLevel = mDevice->GetFeatureLevel(); } -#endif - initializeDevice(); + d3d11::SetDebugName(mDeviceContext, "DeviceContext"); return egl::Error(EGL_SUCCESS); } @@ -568,6 +798,11 @@ egl::Error Renderer11::initialize() // to reset the scene status and ensure the default states are reset. void Renderer11::initializeDevice() { + SCOPED_ANGLE_HISTOGRAM_TIMER("GPU.ANGLE.Renderer11InitializeDeviceMS"); + TRACE_EVENT0("gpu.angle", "Renderer11::initializeDevice"); + + populateRenderer11DeviceCaps(); + mStateCache.initialize(mDevice); mInputLayoutCache.initialize(mDevice, mDeviceContext); @@ -598,14 +833,7 @@ void Renderer11::initializeDevice() const gl::Caps &rendererCaps = getRendererCaps(); -#if defined(ANGLE_ENABLE_D3D11_1) - if (getDeviceContext1IfSupported()) - { - D3D11_FEATURE_DATA_D3D11_OPTIONS d3d11Options; - mDevice->CheckFeatureSupport(D3D11_FEATURE_D3D11_OPTIONS, &d3d11Options, sizeof(D3D11_FEATURE_DATA_D3D11_OPTIONS)); - mSupportsConstantBufferOffsets = (d3d11Options.ConstantBufferOffsetting != FALSE); - } -#endif + mStateManager.initialize(rendererCaps); mForceSetVertexSamplerStates.resize(rendererCaps.maxVertexTextureImageUnits); mCurVertexSamplerStates.resize(rendererCaps.maxVertexTextureImageUnits); @@ -613,19 +841,94 @@ void Renderer11::initializeDevice() mForceSetPixelSamplerStates.resize(rendererCaps.maxTextureImageUnits); mCurPixelSamplerStates.resize(rendererCaps.maxTextureImageUnits); - mCurVertexSRVs.resize(rendererCaps.maxVertexTextureImageUnits); - mCurPixelSRVs.resize(rendererCaps.maxTextureImageUnits); + mStateManager.initialize(rendererCaps); markAllStateDirty(); + + // Gather stats on DXGI and D3D feature level + ANGLE_HISTOGRAM_BOOLEAN("GPU.ANGLE.SupportsDXGI1_2", mRenderer11DeviceCaps.supportsDXGI1_2); + + ANGLEFeatureLevel angleFeatureLevel = GetANGLEFeatureLevel(mRenderer11DeviceCaps.featureLevel); + + // We don't actually request a 11_1 device, because of complications with the platform + // update. Instead we check if the mDeviceContext1 pointer cast succeeded. + // Note: we should support D3D11_0 always, but we aren't guaranteed to be at FL11_0 + // because the app can specify a lower version (such as 9_3) on Display creation. + if (mDeviceContext1 != nullptr) + { + angleFeatureLevel = ANGLE_FEATURE_LEVEL_11_1; + } + + ANGLE_HISTOGRAM_ENUMERATION("GPU.ANGLE.D3D11FeatureLevel", + angleFeatureLevel, + NUM_ANGLE_FEATURE_LEVELS); + + // TODO(jmadill): use context caps, and place in common D3D location + mTranslatedAttribCache.resize(getRendererCaps().maxVertexAttributes); +} + +void Renderer11::populateRenderer11DeviceCaps() +{ + HRESULT hr = S_OK; + +#if defined(ANGLE_ENABLE_D3D11_1) + if (mDeviceContext1) + { + D3D11_FEATURE_DATA_D3D11_OPTIONS d3d11Options; + HRESULT result = mDevice->CheckFeatureSupport(D3D11_FEATURE_D3D11_OPTIONS, &d3d11Options, sizeof(D3D11_FEATURE_DATA_D3D11_OPTIONS)); + if (SUCCEEDED(result)) + { + mRenderer11DeviceCaps.supportsClearView = (d3d11Options.ClearView != FALSE); + mRenderer11DeviceCaps.supportsConstantBufferOffsets = (d3d11Options.ConstantBufferOffsetting != FALSE); + } + } +#endif + + hr = mDevice->CheckFormatSupport(DXGI_FORMAT_B5G6R5_UNORM, &(mRenderer11DeviceCaps.B5G6R5support)); + if (FAILED(hr)) + { + mRenderer11DeviceCaps.B5G6R5support = 0; + } + + hr = mDevice->CheckFormatSupport(DXGI_FORMAT_B4G4R4A4_UNORM, &(mRenderer11DeviceCaps.B4G4R4A4support)); + if (FAILED(hr)) + { + mRenderer11DeviceCaps.B4G4R4A4support = 0; + } + + hr = mDevice->CheckFormatSupport(DXGI_FORMAT_B5G5R5A1_UNORM, &(mRenderer11DeviceCaps.B5G5R5A1support)); + if (FAILED(hr)) + { + mRenderer11DeviceCaps.B5G5R5A1support = 0; + } + +#if defined(ANGLE_ENABLE_D3D11_1) + IDXGIAdapter2 *dxgiAdapter2 = d3d11::DynamicCastComObject<IDXGIAdapter2>(mDxgiAdapter); + mRenderer11DeviceCaps.supportsDXGI1_2 = (dxgiAdapter2 != nullptr); + SafeRelease(dxgiAdapter2); +#endif } egl::ConfigSet Renderer11::generateConfigs() const { - static const GLenum colorBufferFormats[] = + std::vector<GLenum> colorBufferFormats; + + // 32-bit supported formats + colorBufferFormats.push_back(GL_BGRA8_EXT); + colorBufferFormats.push_back(GL_RGBA8_OES); + + // 24-bit supported formats + colorBufferFormats.push_back(GL_RGB8_OES); + + if (!mPresentPathFastEnabled) { - GL_BGRA8_EXT, - GL_RGBA8_OES, - }; + // 16-bit supported formats + // These aren't valid D3D11 swapchain formats, so don't expose them as configs + // if present path fast is active + colorBufferFormats.push_back(GL_RGBA4); + colorBufferFormats.push_back(GL_RGB5_A1); + colorBufferFormats.push_back(GL_RGB565); + } static const GLenum depthStencilBufferFormats[] = { @@ -637,64 +940,87 @@ egl::ConfigSet Renderer11::generateConfigs() const const gl::Caps &rendererCaps = getRendererCaps(); const gl::TextureCapsMap &rendererTextureCaps = getRendererTextureCaps(); + const EGLint optimalSurfaceOrientation = + mPresentPathFastEnabled ? 0 : EGL_SURFACE_ORIENTATION_INVERT_Y_ANGLE; + egl::ConfigSet configs; - for (size_t formatIndex = 0; formatIndex < ArraySize(colorBufferFormats); formatIndex++) + for (GLenum colorBufferInternalFormat : colorBufferFormats) { - GLenum colorBufferInternalFormat = colorBufferFormats[formatIndex]; const gl::TextureCaps &colorBufferFormatCaps = rendererTextureCaps.get(colorBufferInternalFormat); - if (colorBufferFormatCaps.renderable) + if (!colorBufferFormatCaps.renderable) { - for (size_t depthStencilIndex = 0; depthStencilIndex < ArraySize(depthStencilBufferFormats); depthStencilIndex++) + continue; + } + + for (GLenum depthStencilBufferInternalFormat : depthStencilBufferFormats) + { + const gl::TextureCaps &depthStencilBufferFormatCaps = + rendererTextureCaps.get(depthStencilBufferInternalFormat); + if (!depthStencilBufferFormatCaps.renderable && + depthStencilBufferInternalFormat != GL_NONE) { - GLenum depthStencilBufferInternalFormat = depthStencilBufferFormats[depthStencilIndex]; - const gl::TextureCaps &depthStencilBufferFormatCaps = rendererTextureCaps.get(depthStencilBufferInternalFormat); - if (depthStencilBufferFormatCaps.renderable || depthStencilBufferInternalFormat == GL_NONE) - { - const gl::InternalFormat &colorBufferFormatInfo = gl::GetInternalFormatInfo(colorBufferInternalFormat); - const gl::InternalFormat &depthStencilBufferFormatInfo = gl::GetInternalFormatInfo(depthStencilBufferInternalFormat); - - egl::Config config; - config.renderTargetFormat = colorBufferInternalFormat; - config.depthStencilFormat = depthStencilBufferInternalFormat; - config.bufferSize = colorBufferFormatInfo.pixelBytes * 8; - config.redSize = colorBufferFormatInfo.redBits; - config.greenSize = colorBufferFormatInfo.greenBits; - config.blueSize = colorBufferFormatInfo.blueBits; - config.luminanceSize = colorBufferFormatInfo.luminanceBits; - config.alphaSize = colorBufferFormatInfo.alphaBits; - config.alphaMaskSize = 0; - config.bindToTextureRGB = (colorBufferFormatInfo.format == GL_RGB); - config.bindToTextureRGBA = (colorBufferFormatInfo.format == GL_RGBA || colorBufferFormatInfo.format == GL_BGRA_EXT); - config.colorBufferType = EGL_RGB_BUFFER; - config.configID = static_cast<EGLint>(configs.size() + 1); - // Can only support a conformant ES2 with feature level greater than 10.0. - config.conformant = (mFeatureLevel >= D3D_FEATURE_LEVEL_10_0) ? (EGL_OPENGL_ES2_BIT | EGL_OPENGL_ES3_BIT_KHR) : EGL_NONE; - config.configCaveat = config.conformant == EGL_NONE ? EGL_NON_CONFORMANT_CONFIG : EGL_NONE; - config.depthSize = depthStencilBufferFormatInfo.depthBits; - config.level = 0; - config.matchNativePixmap = EGL_NONE; - config.maxPBufferWidth = rendererCaps.max2DTextureSize; - config.maxPBufferHeight = rendererCaps.max2DTextureSize; - config.maxPBufferPixels = rendererCaps.max2DTextureSize * rendererCaps.max2DTextureSize; - config.maxSwapInterval = 4; - config.minSwapInterval = 0; - config.nativeRenderable = EGL_FALSE; - config.nativeVisualID = 0; - config.nativeVisualType = EGL_NONE; - // Can't support ES3 at all without feature level 10.0 - config.renderableType = EGL_OPENGL_ES2_BIT | ((mFeatureLevel >= D3D_FEATURE_LEVEL_10_0) ? EGL_OPENGL_ES3_BIT_KHR : 0); - config.sampleBuffers = 0; // FIXME: enumerate multi-sampling - config.samples = 0; - config.stencilSize = depthStencilBufferFormatInfo.stencilBits; - config.surfaceType = EGL_PBUFFER_BIT | EGL_WINDOW_BIT | EGL_SWAP_BEHAVIOR_PRESERVED_BIT; - config.transparentType = EGL_NONE; - config.transparentRedValue = 0; - config.transparentGreenValue = 0; - config.transparentBlueValue = 0; - - configs.add(config); - } + continue; + } + + const gl::InternalFormat &colorBufferFormatInfo = + gl::GetInternalFormatInfo(colorBufferInternalFormat); + const gl::InternalFormat &depthStencilBufferFormatInfo = + gl::GetInternalFormatInfo(depthStencilBufferInternalFormat); + + egl::Config config; + config.renderTargetFormat = colorBufferInternalFormat; + config.depthStencilFormat = depthStencilBufferInternalFormat; + config.bufferSize = colorBufferFormatInfo.pixelBytes * 8; + config.redSize = colorBufferFormatInfo.redBits; + config.greenSize = colorBufferFormatInfo.greenBits; + config.blueSize = colorBufferFormatInfo.blueBits; + config.luminanceSize = colorBufferFormatInfo.luminanceBits; + config.alphaSize = colorBufferFormatInfo.alphaBits; + config.alphaMaskSize = 0; + config.bindToTextureRGB = (colorBufferFormatInfo.format == GL_RGB); + config.bindToTextureRGBA = (colorBufferFormatInfo.format == GL_RGBA || + colorBufferFormatInfo.format == GL_BGRA_EXT); + config.colorBufferType = EGL_RGB_BUFFER; + config.configID = static_cast<EGLint>(configs.size() + 1); + // Can only support a conformant ES2 with feature level greater than 10.0. + config.conformant = (mRenderer11DeviceCaps.featureLevel >= D3D_FEATURE_LEVEL_10_0) + ? (EGL_OPENGL_ES2_BIT | EGL_OPENGL_ES3_BIT_KHR) + : 0; + config.configCaveat = config.conformant == EGL_NONE ? EGL_NON_CONFORMANT_CONFIG : EGL_NONE; + + // PresentPathFast may not be conformant + if (mPresentPathFastEnabled) + { + config.conformant = 0; } + + config.depthSize = depthStencilBufferFormatInfo.depthBits; + config.level = 0; + config.matchNativePixmap = EGL_NONE; + config.maxPBufferWidth = rendererCaps.max2DTextureSize; + config.maxPBufferHeight = rendererCaps.max2DTextureSize; + config.maxPBufferPixels = rendererCaps.max2DTextureSize * rendererCaps.max2DTextureSize; + config.maxSwapInterval = 4; + config.minSwapInterval = 0; + config.nativeRenderable = EGL_FALSE; + config.nativeVisualID = 0; + config.nativeVisualType = EGL_NONE; + // Can't support ES3 at all without feature level 10.0 + config.renderableType = + EGL_OPENGL_ES2_BIT | ((mRenderer11DeviceCaps.featureLevel >= D3D_FEATURE_LEVEL_10_0) + ? EGL_OPENGL_ES3_BIT_KHR + : 0); + config.sampleBuffers = 0; // FIXME: enumerate multi-sampling + config.samples = 0; + config.stencilSize = depthStencilBufferFormatInfo.stencilBits; + config.surfaceType = EGL_PBUFFER_BIT | EGL_WINDOW_BIT | EGL_SWAP_BEHAVIOR_PRESERVED_BIT; + config.transparentType = EGL_NONE; + config.transparentRedValue = 0; + config.transparentGreenValue = 0; + config.transparentBlueValue = 0; + config.optimalOrientation = optimalSurfaceOrientation; + + configs.add(config); } } @@ -702,6 +1028,42 @@ egl::ConfigSet Renderer11::generateConfigs() const return configs; } +void Renderer11::generateDisplayExtensions(egl::DisplayExtensions *outExtensions) const +{ + outExtensions->createContextRobustness = true; + + if (getShareHandleSupport()) + { + outExtensions->d3dShareHandleClientBuffer = true; + outExtensions->surfaceD3DTexture2DShareHandle = true; + } + + outExtensions->keyedMutex = true; + outExtensions->querySurfacePointer = true; + outExtensions->windowFixedSize = true; + + // If present path fast is active then the surface orientation extension isn't supported + outExtensions->surfaceOrientation = !mPresentPathFastEnabled; + + // D3D11 does not support present with dirty rectangles until DXGI 1.2. + outExtensions->postSubBuffer = mRenderer11DeviceCaps.supportsDXGI1_2; + + outExtensions->createContext = true; + + outExtensions->deviceQuery = true; + + outExtensions->createContextNoError = true; + + outExtensions->image = true; + outExtensions->imageBase = true; + outExtensions->glTexture2DImage = true; + outExtensions->glTextureCubemapImage = true; + outExtensions->glRenderbufferImage = true; + + outExtensions->flexibleSurfaceCompatibility = true; + outExtensions->directComposition = !!mDCompModule; +} + gl::Error Renderer11::flush() { mDeviceContext->Flush(); @@ -751,9 +1113,31 @@ gl::Error Renderer11::finish() return gl::Error(GL_NO_ERROR); } -SwapChainD3D *Renderer11::createSwapChain(NativeWindow nativeWindow, HANDLE shareHandle, GLenum backBufferFormat, GLenum depthBufferFormat) +SwapChainD3D *Renderer11::createSwapChain(NativeWindow nativeWindow, + HANDLE shareHandle, + GLenum backBufferFormat, + GLenum depthBufferFormat, + EGLint orientation) +{ + return new SwapChain11(this, nativeWindow, shareHandle, backBufferFormat, depthBufferFormat, + orientation); +} + +CompilerImpl *Renderer11::createCompiler() +{ + if (mRenderer11DeviceCaps.featureLevel <= D3D_FEATURE_LEVEL_9_3) + { + return new CompilerD3D(SH_HLSL_4_0_FL9_3_OUTPUT); + } + else + { + return new CompilerD3D(SH_HLSL_4_1_OUTPUT); + } +} + +void *Renderer11::getD3DDevice() { - return new SwapChain11(this, nativeWindow, shareHandle, backBufferFormat, depthBufferFormat); + return reinterpret_cast<void*>(mDevice); } gl::Error Renderer11::generateSwizzle(gl::Texture *texture) @@ -772,11 +1156,11 @@ gl::Error Renderer11::generateSwizzle(gl::Texture *texture) if (texStorage) { - TextureStorage11 *storage11 = TextureStorage11::makeTextureStorage11(texStorage); - error = storage11->generateSwizzles(texture->getSamplerState().swizzleRed, - texture->getSamplerState().swizzleGreen, - texture->getSamplerState().swizzleBlue, - texture->getSamplerState().swizzleAlpha); + TextureStorage11 *storage11 = GetAs<TextureStorage11>(texStorage); + const gl::TextureState &textureState = texture->getTextureState(); + error = + storage11->generateSwizzles(textureState.swizzleRed, textureState.swizzleGreen, + textureState.swizzleBlue, textureState.swizzleAlpha); if (error.isError()) { return error; @@ -787,11 +1171,13 @@ gl::Error Renderer11::generateSwizzle(gl::Texture *texture) return gl::Error(GL_NO_ERROR); } -gl::Error Renderer11::setSamplerState(gl::SamplerType type, int index, gl::Texture *texture, const gl::SamplerState &samplerStateParam) +gl::Error Renderer11::setSamplerState(gl::SamplerType type, + int index, + gl::Texture *texture, + const gl::SamplerState &samplerState) { // Make sure to add the level offset for our tiny compressed texture workaround TextureD3D *textureD3D = GetImplAs<TextureD3D>(texture); - gl::SamplerState samplerStateInternal = samplerStateParam; TextureStorage *storage = nullptr; gl::Error error = textureD3D->getNativeTexture(&storage); @@ -803,16 +1189,15 @@ gl::Error Renderer11::setSamplerState(gl::SamplerType type, int index, gl::Textu // Storage should exist, texture should be complete ASSERT(storage); - samplerStateInternal.baseLevel += storage->getTopLevel(); - if (type == gl::SAMPLER_PIXEL) { ASSERT(static_cast<unsigned int>(index) < getRendererCaps().maxTextureImageUnits); - if (mForceSetPixelSamplerStates[index] || memcmp(&samplerStateInternal, &mCurPixelSamplerStates[index], sizeof(gl::SamplerState)) != 0) + if (mForceSetPixelSamplerStates[index] || + memcmp(&samplerState, &mCurPixelSamplerStates[index], sizeof(gl::SamplerState)) != 0) { ID3D11SamplerState *dxSamplerState = NULL; - error = mStateCache.getSamplerState(samplerStateInternal, &dxSamplerState); + error = mStateCache.getSamplerState(samplerState, &dxSamplerState); if (error.isError()) { return error; @@ -821,7 +1206,7 @@ gl::Error Renderer11::setSamplerState(gl::SamplerType type, int index, gl::Textu ASSERT(dxSamplerState != NULL); mDeviceContext->PSSetSamplers(index, 1, &dxSamplerState); - mCurPixelSamplerStates[index] = samplerStateInternal; + mCurPixelSamplerStates[index] = samplerState; } mForceSetPixelSamplerStates[index] = false; @@ -830,10 +1215,11 @@ gl::Error Renderer11::setSamplerState(gl::SamplerType type, int index, gl::Textu { ASSERT(static_cast<unsigned int>(index) < getRendererCaps().maxVertexTextureImageUnits); - if (mForceSetVertexSamplerStates[index] || memcmp(&samplerStateInternal, &mCurVertexSamplerStates[index], sizeof(gl::SamplerState)) != 0) + if (mForceSetVertexSamplerStates[index] || + memcmp(&samplerState, &mCurVertexSamplerStates[index], sizeof(gl::SamplerState)) != 0) { ID3D11SamplerState *dxSamplerState = NULL; - error = mStateCache.getSamplerState(samplerStateInternal, &dxSamplerState); + error = mStateCache.getSamplerState(samplerState, &dxSamplerState); if (error.isError()) { return error; @@ -842,7 +1228,7 @@ gl::Error Renderer11::setSamplerState(gl::SamplerType type, int index, gl::Textu ASSERT(dxSamplerState != NULL); mDeviceContext->VSSetSamplers(index, 1, &dxSamplerState); - mCurVertexSamplerStates[index] = samplerStateInternal; + mCurVertexSamplerStates[index] = samplerState; } mForceSetVertexSamplerStates[index] = false; @@ -870,13 +1256,13 @@ gl::Error Renderer11::setTexture(gl::SamplerType type, int index, gl::Texture *t // Texture should be complete and have a storage ASSERT(texStorage); - TextureStorage11 *storage11 = TextureStorage11::makeTextureStorage11(texStorage); + TextureStorage11 *storage11 = GetAs<TextureStorage11>(texStorage); // Make sure to add the level offset for our tiny compressed texture workaround - gl::SamplerState samplerState = texture->getSamplerState(); - samplerState.baseLevel += storage11->getTopLevel(); + gl::TextureState textureState = texture->getTextureState(); + textureState.baseLevel += storage11->getTopLevel(); - error = storage11->getSRV(samplerState, &textureSRV); + error = storage11->getSRV(textureState, &textureSRV); if (error.isError()) { return error; @@ -892,16 +1278,16 @@ gl::Error Renderer11::setTexture(gl::SamplerType type, int index, gl::Texture *t ASSERT((type == gl::SAMPLER_PIXEL && static_cast<unsigned int>(index) < getRendererCaps().maxTextureImageUnits) || (type == gl::SAMPLER_VERTEX && static_cast<unsigned int>(index) < getRendererCaps().maxVertexTextureImageUnits)); - setShaderResource(type, index, textureSRV); + mStateManager.setShaderResource(type, index, textureSRV); return gl::Error(GL_NO_ERROR); } gl::Error Renderer11::setUniformBuffers(const gl::Data &data, - const GLint vertexUniformBuffers[], - const GLint fragmentUniformBuffers[]) + const std::vector<GLint> &vertexUniformBuffers, + const std::vector<GLint> &fragmentUniformBuffers) { - for (unsigned int uniformBufferIndex = 0; uniformBufferIndex < data.caps->maxVertexUniformBlocks; uniformBufferIndex++) + for (size_t uniformBufferIndex = 0; uniformBufferIndex < vertexUniformBuffers.size(); uniformBufferIndex++) { GLint binding = vertexUniformBuffers[uniformBufferIndex]; @@ -910,14 +1296,24 @@ gl::Error Renderer11::setUniformBuffers(const gl::Data &data, continue; } - gl::Buffer *uniformBuffer = data.state->getIndexedUniformBuffer(binding); - GLintptr uniformBufferOffset = data.state->getIndexedUniformBufferOffset(binding); - GLsizeiptr uniformBufferSize = data.state->getIndexedUniformBufferSize(binding); + const OffsetBindingPointer<gl::Buffer> &uniformBuffer = + data.state->getIndexedUniformBuffer(binding); + GLintptr uniformBufferOffset = uniformBuffer.getOffset(); + GLsizeiptr uniformBufferSize = uniformBuffer.getSize(); - if (uniformBuffer) + if (uniformBuffer.get() != nullptr) { - Buffer11 *bufferStorage = Buffer11::makeBuffer11(uniformBuffer->getImplementation()); - ID3D11Buffer *constantBuffer = bufferStorage->getBuffer(BUFFER_USAGE_UNIFORM); + Buffer11 *bufferStorage = GetImplAs<Buffer11>(uniformBuffer.get()); + ID3D11Buffer *constantBuffer; + + if (mRenderer11DeviceCaps.supportsConstantBufferOffsets) + { + constantBuffer = bufferStorage->getBuffer(BUFFER_USAGE_UNIFORM); + } + else + { + constantBuffer = bufferStorage->getConstantBufferRange(uniformBufferOffset, uniformBufferSize); + } if (!constantBuffer) { @@ -929,19 +1325,22 @@ gl::Error Renderer11::setUniformBuffers(const gl::Data &data, mCurrentConstantBufferVSSize[uniformBufferIndex] != uniformBufferSize) { #if defined(ANGLE_ENABLE_D3D11_1) - if (mSupportsConstantBufferOffsets && uniformBufferSize != 0) + if (mRenderer11DeviceCaps.supportsConstantBufferOffsets && uniformBufferSize != 0) { UINT firstConstant = 0, numConstants = 0; CalculateConstantBufferParams(uniformBufferOffset, uniformBufferSize, &firstConstant, &numConstants); - mDeviceContext1->VSSetConstantBuffers1(getReservedVertexUniformBuffers() + uniformBufferIndex, - 1, &constantBuffer, &firstConstant, &numConstants); + mDeviceContext1->VSSetConstantBuffers1( + getReservedVertexUniformBuffers() + + static_cast<unsigned int>(uniformBufferIndex), + 1, &constantBuffer, &firstConstant, &numConstants); } else #endif { - ASSERT(uniformBufferOffset == 0); - mDeviceContext->VSSetConstantBuffers(getReservedVertexUniformBuffers() + uniformBufferIndex, - 1, &constantBuffer); + mDeviceContext->VSSetConstantBuffers( + getReservedVertexUniformBuffers() + + static_cast<unsigned int>(uniformBufferIndex), + 1, &constantBuffer); } mCurrentConstantBufferVS[uniformBufferIndex] = bufferStorage->getSerial(); @@ -951,7 +1350,7 @@ gl::Error Renderer11::setUniformBuffers(const gl::Data &data, } } - for (unsigned int uniformBufferIndex = 0; uniformBufferIndex < data.caps->maxFragmentUniformBlocks; uniformBufferIndex++) + for (size_t uniformBufferIndex = 0; uniformBufferIndex < fragmentUniformBuffers.size(); uniformBufferIndex++) { GLint binding = fragmentUniformBuffers[uniformBufferIndex]; @@ -960,14 +1359,24 @@ gl::Error Renderer11::setUniformBuffers(const gl::Data &data, continue; } - gl::Buffer *uniformBuffer = data.state->getIndexedUniformBuffer(binding); - GLintptr uniformBufferOffset = data.state->getIndexedUniformBufferOffset(binding); - GLsizeiptr uniformBufferSize = data.state->getIndexedUniformBufferSize(binding); + const OffsetBindingPointer<gl::Buffer> &uniformBuffer = + data.state->getIndexedUniformBuffer(binding); + GLintptr uniformBufferOffset = uniformBuffer.getOffset(); + GLsizeiptr uniformBufferSize = uniformBuffer.getSize(); - if (uniformBuffer) + if (uniformBuffer.get() != nullptr) { - Buffer11 *bufferStorage = Buffer11::makeBuffer11(uniformBuffer->getImplementation()); - ID3D11Buffer *constantBuffer = bufferStorage->getBuffer(BUFFER_USAGE_UNIFORM); + Buffer11 *bufferStorage = GetImplAs<Buffer11>(uniformBuffer.get()); + ID3D11Buffer *constantBuffer; + + if (mRenderer11DeviceCaps.supportsConstantBufferOffsets) + { + constantBuffer = bufferStorage->getBuffer(BUFFER_USAGE_UNIFORM); + } + else + { + constantBuffer = bufferStorage->getConstantBufferRange(uniformBufferOffset, uniformBufferSize); + } if (!constantBuffer) { @@ -979,19 +1388,22 @@ gl::Error Renderer11::setUniformBuffers(const gl::Data &data, mCurrentConstantBufferPSSize[uniformBufferIndex] != uniformBufferSize) { #if defined(ANGLE_ENABLE_D3D11_1) - if (mSupportsConstantBufferOffsets && uniformBufferSize != 0) + if (mRenderer11DeviceCaps.supportsConstantBufferOffsets && uniformBufferSize != 0) { UINT firstConstant = 0, numConstants = 0; CalculateConstantBufferParams(uniformBufferOffset, uniformBufferSize, &firstConstant, &numConstants); - mDeviceContext1->PSSetConstantBuffers1(getReservedFragmentUniformBuffers() + uniformBufferIndex, - 1, &constantBuffer, &firstConstant, &numConstants); + mDeviceContext1->PSSetConstantBuffers1( + getReservedFragmentUniformBuffers() + + static_cast<unsigned int>(uniformBufferIndex), + 1, &constantBuffer, &firstConstant, &numConstants); } else #endif { - ASSERT(uniformBufferOffset == 0); - mDeviceContext->PSSetConstantBuffers(getReservedFragmentUniformBuffers() + uniformBufferIndex, - 1, &constantBuffer); + mDeviceContext->PSSetConstantBuffers( + getReservedFragmentUniformBuffers() + + static_cast<unsigned int>(uniformBufferIndex), + 1, &constantBuffer); } mCurrentConstantBufferPS[uniformBufferIndex] = bufferStorage->getSerial(); @@ -1004,229 +1416,60 @@ gl::Error Renderer11::setUniformBuffers(const gl::Data &data, return gl::Error(GL_NO_ERROR); } -gl::Error Renderer11::setRasterizerState(const gl::RasterizerState &rasterState) +gl::Error Renderer11::updateState(const gl::Data &data, GLenum drawMode) { - if (mForceSetRasterState || memcmp(&rasterState, &mCurRasterState, sizeof(gl::RasterizerState)) != 0) + // Applies the render target surface, depth stencil surface, viewport rectangle and + // scissor rectangle to the renderer + const gl::Framebuffer *framebufferObject = data.state->getDrawFramebuffer(); + ASSERT(framebufferObject && framebufferObject->checkStatus(data) == GL_FRAMEBUFFER_COMPLETE); + gl::Error error = applyRenderTarget(framebufferObject); + if (error.isError()) { - ID3D11RasterizerState *dxRasterState = NULL; - gl::Error error = mStateCache.getRasterizerState(rasterState, mScissorEnabled, &dxRasterState); - if (error.isError()) - { - return error; - } - - mDeviceContext->RSSetState(dxRasterState); - - mCurRasterState = rasterState; + return error; } - mForceSetRasterState = false; + // Set the present path state + const bool presentPathFastActive = + UsePresentPathFast(this, framebufferObject->getFirstColorbuffer()); + mStateManager.updatePresentPath(presentPathFastActive, + framebufferObject->getFirstColorbuffer()); - return gl::Error(GL_NO_ERROR); -} + // Setting viewport state + mStateManager.setViewport(data.caps, data.state->getViewport(), data.state->getNearPlane(), + data.state->getFarPlane()); -gl::Error Renderer11::setBlendState(const gl::Framebuffer *framebuffer, const gl::BlendState &blendState, const gl::ColorF &blendColor, - unsigned int sampleMask) -{ - if (mForceSetBlendState || - memcmp(&blendState, &mCurBlendState, sizeof(gl::BlendState)) != 0 || - memcmp(&blendColor, &mCurBlendColor, sizeof(gl::ColorF)) != 0 || - sampleMask != mCurSampleMask) - { - ID3D11BlendState *dxBlendState = NULL; - gl::Error error = mStateCache.getBlendState(framebuffer, blendState, &dxBlendState); - if (error.isError()) - { - return error; - } - - ASSERT(dxBlendState != NULL); - - float blendColors[4] = {0.0f}; - if (blendState.sourceBlendRGB != GL_CONSTANT_ALPHA && blendState.sourceBlendRGB != GL_ONE_MINUS_CONSTANT_ALPHA && - blendState.destBlendRGB != GL_CONSTANT_ALPHA && blendState.destBlendRGB != GL_ONE_MINUS_CONSTANT_ALPHA) - { - blendColors[0] = blendColor.red; - blendColors[1] = blendColor.green; - blendColors[2] = blendColor.blue; - blendColors[3] = blendColor.alpha; - } - else - { - blendColors[0] = blendColor.alpha; - blendColors[1] = blendColor.alpha; - blendColors[2] = blendColor.alpha; - blendColors[3] = blendColor.alpha; - } - - mDeviceContext->OMSetBlendState(dxBlendState, blendColors, sampleMask); - - mCurBlendState = blendState; - mCurBlendColor = blendColor; - mCurSampleMask = sampleMask; - } + // Setting scissor state + mStateManager.setScissorRectangle(data.state->getScissor(), data.state->isScissorTestEnabled()); - mForceSetBlendState = false; + // Applying rasterizer state to D3D11 device + int samples = framebufferObject->getSamples(data); + gl::RasterizerState rasterizer = data.state->getRasterizerState(); + rasterizer.pointDrawMode = (drawMode == GL_POINTS); + rasterizer.multiSample = (samples != 0); - return gl::Error(GL_NO_ERROR); -} - -gl::Error Renderer11::setDepthStencilState(const gl::DepthStencilState &depthStencilState, int stencilRef, - int stencilBackRef, bool frontFaceCCW) -{ - if (mForceSetDepthStencilState || - memcmp(&depthStencilState, &mCurDepthStencilState, sizeof(gl::DepthStencilState)) != 0 || - stencilRef != mCurStencilRef || stencilBackRef != mCurStencilBackRef) + error = mStateManager.setRasterizerState(rasterizer); + if (error.isError()) { - ASSERT(depthStencilState.stencilWritemask == depthStencilState.stencilBackWritemask); - ASSERT(stencilRef == stencilBackRef); - ASSERT(depthStencilState.stencilMask == depthStencilState.stencilBackMask); - - ID3D11DepthStencilState *dxDepthStencilState = NULL; - gl::Error error = mStateCache.getDepthStencilState(depthStencilState, &dxDepthStencilState); - if (error.isError()) - { - return error; - } - - ASSERT(dxDepthStencilState); - - // Max D3D11 stencil reference value is 0xFF, corresponding to the max 8 bits in a stencil buffer - // GL specifies we should clamp the ref value to the nearest bit depth when doing stencil ops - static_assert(D3D11_DEFAULT_STENCIL_READ_MASK == 0xFF, "Unexpected value of D3D11_DEFAULT_STENCIL_READ_MASK"); - static_assert(D3D11_DEFAULT_STENCIL_WRITE_MASK == 0xFF, "Unexpected value of D3D11_DEFAULT_STENCIL_WRITE_MASK"); - UINT dxStencilRef = std::min<UINT>(stencilRef, 0xFFu); - - mDeviceContext->OMSetDepthStencilState(dxDepthStencilState, dxStencilRef); - - mCurDepthStencilState = depthStencilState; - mCurStencilRef = stencilRef; - mCurStencilBackRef = stencilBackRef; + return error; } - mForceSetDepthStencilState = false; - - return gl::Error(GL_NO_ERROR); -} - -void Renderer11::setScissorRectangle(const gl::Rectangle &scissor, bool enabled) -{ - if (mForceSetScissor || memcmp(&scissor, &mCurScissor, sizeof(gl::Rectangle)) != 0 || - enabled != mScissorEnabled) + // Setting blend state + unsigned int mask = GetBlendSampleMask(data, samples); + error = mStateManager.setBlendState(framebufferObject, data.state->getBlendState(), + data.state->getBlendColor(), mask); + if (error.isError()) { - if (enabled) - { - D3D11_RECT rect; - rect.left = std::max(0, scissor.x); - rect.top = std::max(0, scissor.y); - rect.right = scissor.x + std::max(0, scissor.width); - rect.bottom = scissor.y + std::max(0, scissor.height); - - mDeviceContext->RSSetScissorRects(1, &rect); - } - - if (enabled != mScissorEnabled) - { - mForceSetRasterState = true; - } - - mCurScissor = scissor; - mScissorEnabled = enabled; + return error; } - mForceSetScissor = false; + // Setting depth stencil state + error = mStateManager.setDepthStencilState(*data.state); + return error; } -void Renderer11::setViewport(const gl::Rectangle &viewport, float zNear, float zFar, GLenum drawMode, GLenum frontFace, - bool ignoreViewport) +void Renderer11::syncState(const gl::State &state, const gl::State::DirtyBits &bitmask) { - gl::Rectangle actualViewport = viewport; - float actualZNear = gl::clamp01(zNear); - float actualZFar = gl::clamp01(zFar); - if (ignoreViewport) - { - actualViewport.x = 0; - actualViewport.y = 0; - actualViewport.width = mRenderTargetDesc.width; - actualViewport.height = mRenderTargetDesc.height; - actualZNear = 0.0f; - actualZFar = 1.0f; - } - - bool viewportChanged = mForceSetViewport || memcmp(&actualViewport, &mCurViewport, sizeof(gl::Rectangle)) != 0 || - actualZNear != mCurNear || actualZFar != mCurFar; - - if (viewportChanged) - { - const gl::Caps& caps = getRendererCaps(); - - int dxMaxViewportBoundsX = static_cast<int>(caps.maxViewportWidth); - int dxMaxViewportBoundsY = static_cast<int>(caps.maxViewportHeight); - int dxMinViewportBoundsX = -dxMaxViewportBoundsX; - int dxMinViewportBoundsY = -dxMaxViewportBoundsY; - - if (mFeatureLevel <= D3D_FEATURE_LEVEL_9_3) - { - // Feature Level 9 viewports shouldn't exceed the dimensions of the rendertarget. - dxMaxViewportBoundsX = mRenderTargetDesc.width; - dxMaxViewportBoundsY = mRenderTargetDesc.height; - dxMinViewportBoundsX = 0; - dxMinViewportBoundsY = 0; - } - - int dxViewportTopLeftX = gl::clamp(actualViewport.x, dxMinViewportBoundsX, dxMaxViewportBoundsX); - int dxViewportTopLeftY = gl::clamp(actualViewport.y, dxMinViewportBoundsY, dxMaxViewportBoundsY); - int dxViewportWidth = gl::clamp(actualViewport.width, 0, dxMaxViewportBoundsX - dxViewportTopLeftX); - int dxViewportHeight = gl::clamp(actualViewport.height, 0, dxMaxViewportBoundsY - dxViewportTopLeftY); - - D3D11_VIEWPORT dxViewport; - dxViewport.TopLeftX = static_cast<float>(dxViewportTopLeftX); - dxViewport.TopLeftY = static_cast<float>(dxViewportTopLeftY); - dxViewport.Width = static_cast<float>(dxViewportWidth); - dxViewport.Height = static_cast<float>(dxViewportHeight); - dxViewport.MinDepth = actualZNear; - dxViewport.MaxDepth = actualZFar; - - mDeviceContext->RSSetViewports(1, &dxViewport); - - mCurViewport = actualViewport; - mCurNear = actualZNear; - mCurFar = actualZFar; - - // On Feature Level 9_*, we must emulate large and/or negative viewports in the shaders using viewAdjust (like the D3D9 renderer). - if (mFeatureLevel <= D3D_FEATURE_LEVEL_9_3) - { - mVertexConstants.viewAdjust[0] = static_cast<float>((actualViewport.width - dxViewportWidth) + 2 * (actualViewport.x - dxViewportTopLeftX)) / dxViewport.Width; - mVertexConstants.viewAdjust[1] = static_cast<float>((actualViewport.height - dxViewportHeight) + 2 * (actualViewport.y - dxViewportTopLeftY)) / dxViewport.Height; - mVertexConstants.viewAdjust[2] = static_cast<float>(actualViewport.width) / dxViewport.Width; - mVertexConstants.viewAdjust[3] = static_cast<float>(actualViewport.height) / dxViewport.Height; - } - - mPixelConstants.viewCoords[0] = actualViewport.width * 0.5f; - mPixelConstants.viewCoords[1] = actualViewport.height * 0.5f; - mPixelConstants.viewCoords[2] = actualViewport.x + (actualViewport.width * 0.5f); - mPixelConstants.viewCoords[3] = actualViewport.y + (actualViewport.height * 0.5f); - - // Instanced pointsprite emulation requires ViewCoords to be defined in the - // the vertex shader. - mVertexConstants.viewCoords[0] = mPixelConstants.viewCoords[0]; - mVertexConstants.viewCoords[1] = mPixelConstants.viewCoords[1]; - mVertexConstants.viewCoords[2] = mPixelConstants.viewCoords[2]; - mVertexConstants.viewCoords[3] = mPixelConstants.viewCoords[3]; - - mPixelConstants.depthFront[0] = (actualZFar - actualZNear) * 0.5f; - mPixelConstants.depthFront[1] = (actualZNear + actualZFar) * 0.5f; - - mVertexConstants.depthRange[0] = actualZNear; - mVertexConstants.depthRange[1] = actualZFar; - mVertexConstants.depthRange[2] = actualZFar - actualZNear; - - mPixelConstants.depthRange[0] = actualZNear; - mPixelConstants.depthRange[1] = actualZFar; - mPixelConstants.depthRange[2] = actualZFar - actualZNear; - } - - mForceSetViewport = false; + mStateManager.syncState(state, bitmask); } bool Renderer11::applyPrimitiveType(GLenum mode, GLsizei count, bool usesPointSize) @@ -1267,176 +1510,51 @@ bool Renderer11::applyPrimitiveType(GLenum mode, GLsizei count, bool usesPointSi return count >= minCount; } -void Renderer11::unsetConflictingSRVs(gl::SamplerType samplerType, uintptr_t resource, const gl::ImageIndex *index) +gl::Error Renderer11::applyRenderTarget(const gl::Framebuffer *framebuffer) { - auto ¤tSRVs = (samplerType == gl::SAMPLER_VERTEX ? mCurVertexSRVs : mCurPixelSRVs); - - for (size_t resourceIndex = 0; resourceIndex < currentSRVs.size(); ++resourceIndex) - { - auto &record = currentSRVs[resourceIndex]; - - if (record.srv && record.resource == resource && ImageIndexConflictsWithSRV(index, record.desc)) - { - setShaderResource(samplerType, static_cast<UINT>(resourceIndex), NULL); - } - } + return mStateManager.syncFramebuffer(framebuffer); } -gl::Error Renderer11::applyRenderTarget(const gl::Framebuffer *framebuffer) +gl::Error Renderer11::applyVertexBuffer(const gl::State &state, + GLenum mode, + GLint first, + GLsizei count, + GLsizei instances, + TranslatedIndexData *indexInfo) { - // Get the color render buffer and serial - // Also extract the render target dimensions and view - unsigned int renderTargetWidth = 0; - unsigned int renderTargetHeight = 0; - DXGI_FORMAT renderTargetFormat = DXGI_FORMAT_UNKNOWN; - ID3D11RenderTargetView* framebufferRTVs[gl::IMPLEMENTATION_MAX_DRAW_BUFFERS] = {NULL}; - bool missingColorRenderTarget = true; - - const FramebufferD3D *framebufferD3D = GetImplAs<FramebufferD3D>(framebuffer); - const gl::AttachmentList &colorbuffers = framebufferD3D->getColorAttachmentsForRender(getWorkarounds()); - - for (size_t colorAttachment = 0; colorAttachment < colorbuffers.size(); ++colorAttachment) - { - gl::FramebufferAttachment *colorbuffer = colorbuffers[colorAttachment]; - - if (colorbuffer) - { - // the draw buffer must be either "none", "back" for the default buffer or the same index as this color (in order) - - // check for zero-sized default framebuffer, which is a special case. - // in this case we do not wish to modify any state and just silently return false. - // this will not report any gl error but will cause the calling method to return. - if (colorbuffer->getWidth() == 0 || colorbuffer->getHeight() == 0) - { - return gl::Error(GL_NO_ERROR); - } - - // Extract the render target dimensions and view - RenderTarget11 *renderTarget = NULL; - gl::Error error = d3d11::GetAttachmentRenderTarget(colorbuffer, &renderTarget); - if (error.isError()) - { - return error; - } - ASSERT(renderTarget); - - framebufferRTVs[colorAttachment] = renderTarget->getRenderTargetView(); - ASSERT(framebufferRTVs[colorAttachment]); - - if (missingColorRenderTarget) - { - renderTargetWidth = renderTarget->getWidth(); - renderTargetHeight = renderTarget->getHeight(); - renderTargetFormat = renderTarget->getDXGIFormat(); - missingColorRenderTarget = false; - } - - // Unbind render target SRVs from the shader here to prevent D3D11 warnings. - if (colorbuffer->type() == GL_TEXTURE) - { - uintptr_t rtResource = reinterpret_cast<uintptr_t>(GetViewResource(framebufferRTVs[colorAttachment])); - const gl::ImageIndex *index = colorbuffer->getTextureImageIndex(); - ASSERT(index); - // The index doesn't need to be corrected for the small compressed texture workaround - // because a rendertarget is never compressed. - unsetConflictingSRVs(gl::SAMPLER_VERTEX, rtResource, index); - unsetConflictingSRVs(gl::SAMPLER_PIXEL, rtResource, index); - } - } - } - - // Get the depth stencil buffers - ID3D11DepthStencilView* framebufferDSV = NULL; - gl::FramebufferAttachment *depthStencil = framebuffer->getDepthOrStencilbuffer(); - if (depthStencil) - { - RenderTarget11 *depthStencilRenderTarget = NULL; - gl::Error error = d3d11::GetAttachmentRenderTarget(depthStencil, &depthStencilRenderTarget); - if (error.isError()) - { - SafeRelease(framebufferRTVs); - return error; - } - ASSERT(depthStencilRenderTarget); - - framebufferDSV = depthStencilRenderTarget->getDepthStencilView(); - ASSERT(framebufferDSV); - - // If there is no render buffer, the width, height and format values come from - // the depth stencil - if (missingColorRenderTarget) - { - renderTargetWidth = depthStencilRenderTarget->getWidth(); - renderTargetHeight = depthStencilRenderTarget->getHeight(); - renderTargetFormat = depthStencilRenderTarget->getDXGIFormat(); - } - - // Unbind render target SRVs from the shader here to prevent D3D11 warnings. - if (depthStencil->type() == GL_TEXTURE) - { - uintptr_t depthStencilResource = reinterpret_cast<uintptr_t>(GetViewResource(framebufferDSV)); - const gl::ImageIndex *index = depthStencil->getTextureImageIndex(); - ASSERT(index); - // The index doesn't need to be corrected for the small compressed texture workaround - // because a rendertarget is never compressed. - unsetConflictingSRVs(gl::SAMPLER_VERTEX, depthStencilResource, index); - unsetConflictingSRVs(gl::SAMPLER_PIXEL, depthStencilResource, index); - } - } - - // Apply the render target and depth stencil - if (!mRenderTargetDescInitialized || !mDepthStencilInitialized || - memcmp(framebufferRTVs, mAppliedRTVs, sizeof(framebufferRTVs)) != 0 || - reinterpret_cast<uintptr_t>(framebufferDSV) != mAppliedDSV) - { - mDeviceContext->OMSetRenderTargets(getRendererCaps().maxDrawBuffers, framebufferRTVs, framebufferDSV); - - mRenderTargetDesc.width = renderTargetWidth; - mRenderTargetDesc.height = renderTargetHeight; - mRenderTargetDesc.format = renderTargetFormat; - mForceSetViewport = true; - mForceSetScissor = true; - mForceSetBlendState = true; - - if (!mDepthStencilInitialized) - { - mForceSetRasterState = true; - } - - for (size_t rtIndex = 0; rtIndex < ArraySize(framebufferRTVs); rtIndex++) - { - mAppliedRTVs[rtIndex] = reinterpret_cast<uintptr_t>(framebufferRTVs[rtIndex]); - } - mAppliedDSV = reinterpret_cast<uintptr_t>(framebufferDSV); - mRenderTargetDescInitialized = true; - mDepthStencilInitialized = true; - } - - const Framebuffer11 *framebuffer11 = GetImplAs<Framebuffer11>(framebuffer); - gl::Error error = framebuffer11->invalidateSwizzles(); + gl::Error error = mVertexDataManager->prepareVertexData(state, first, count, &mTranslatedAttribCache, instances); if (error.isError()) { return error; } - return gl::Error(GL_NO_ERROR); -} - -gl::Error Renderer11::applyVertexBuffer(const gl::State &state, GLenum mode, GLint first, GLsizei count, GLsizei instances) -{ - TranslatedAttribute attributes[gl::MAX_VERTEX_ATTRIBS]; - gl::Error error = mVertexDataManager->prepareVertexData(state, first, count, attributes, instances); - if (error.isError()) + // If index information is passed, mark it with the current changed status. + if (indexInfo) { - return error; + indexInfo->srcIndexData.srcIndicesChanged = mAppliedIBChanged; } - return mInputLayoutCache.applyVertexBuffers(attributes, mode, state.getProgram()); + GLsizei numIndicesPerInstance = 0; + if (instances > 0) + { + numIndicesPerInstance = count; + } + return mInputLayoutCache.applyVertexBuffers(mTranslatedAttribCache, mode, state.getProgram(), + indexInfo, numIndicesPerInstance); } -gl::Error Renderer11::applyIndexBuffer(const GLvoid *indices, gl::Buffer *elementArrayBuffer, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo) +gl::Error Renderer11::applyIndexBuffer(const gl::Data &data, + const GLvoid *indices, + GLsizei count, + GLenum mode, + GLenum type, + TranslatedIndexData *indexInfo) { - gl::Error error = mIndexDataManager->prepareIndexData(type, count, elementArrayBuffer, indices, indexInfo); + gl::VertexArray *vao = data.state->getVertexArray(); + gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get(); + gl::Error error = + mIndexDataManager->prepareIndexData(type, count, elementArrayBuffer, indices, indexInfo, + data.state->isPrimitiveRestartEnabled()); if (error.isError()) { return error; @@ -1447,15 +1565,16 @@ gl::Error Renderer11::applyIndexBuffer(const GLvoid *indices, gl::Buffer *elemen if (indexInfo->storage) { - Buffer11 *storage = Buffer11::makeBuffer11(indexInfo->storage); + Buffer11 *storage = GetAs<Buffer11>(indexInfo->storage); buffer = storage->getBuffer(BUFFER_USAGE_INDEX); } else { - IndexBuffer11* indexBuffer = IndexBuffer11::makeIndexBuffer11(indexInfo->indexBuffer); + IndexBuffer11* indexBuffer = GetAs<IndexBuffer11>(indexInfo->indexBuffer); buffer = indexBuffer->getBuffer(); } + mAppliedIBChanged = false; if (buffer != mAppliedIB || bufferFormat != mAppliedIBFormat || indexInfo->startOffset != mAppliedIBOffset) { mDeviceContext->IASetIndexBuffer(buffer, bufferFormat, indexInfo->startOffset); @@ -1463,6 +1582,7 @@ gl::Error Renderer11::applyIndexBuffer(const GLvoid *indices, gl::Buffer *elemen mAppliedIB = buffer; mAppliedIBFormat = bufferFormat; mAppliedIBOffset = indexInfo->startOffset; + mAppliedIBChanged = true; } return gl::Error(GL_NO_ERROR); @@ -1475,22 +1595,23 @@ void Renderer11::applyTransformFeedbackBuffers(const gl::State &state) if (state.isTransformFeedbackActiveUnpaused()) { - numXFBBindings = state.getTransformFeedbackBufferIndexRange(); + const gl::TransformFeedback *transformFeedback = state.getCurrentTransformFeedback(); + numXFBBindings = transformFeedback->getIndexedBufferCount(); ASSERT(numXFBBindings <= gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS); for (size_t i = 0; i < numXFBBindings; i++) { - gl::Buffer *curXFBBuffer = state.getIndexedTransformFeedbackBuffer(i); - GLintptr curXFBOffset = state.getIndexedTransformFeedbackBufferOffset(i); + const OffsetBindingPointer<gl::Buffer> &binding = transformFeedback->getIndexedBuffer(i); + ID3D11Buffer *d3dBuffer = NULL; - if (curXFBBuffer) + if (binding.get() != nullptr) { - Buffer11 *storage = Buffer11::makeBuffer11(curXFBBuffer->getImplementation()); + Buffer11 *storage = GetImplAs<Buffer11>(binding.get()); d3dBuffer = storage->getBuffer(BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK); } // TODO: mAppliedTFBuffers and friends should also be kept in a vector. - if (d3dBuffer != mAppliedTFBuffers[i] || curXFBOffset != mAppliedTFOffsets[i]) + if (d3dBuffer != mAppliedTFBuffers[i] || binding.getOffset() != mAppliedTFOffsets[i]) { requiresUpdate = true; } @@ -1499,18 +1620,17 @@ void Renderer11::applyTransformFeedbackBuffers(const gl::State &state) if (requiresUpdate || numXFBBindings != mAppliedNumXFBBindings) { + const gl::TransformFeedback *transformFeedback = state.getCurrentTransformFeedback(); for (size_t i = 0; i < numXFBBindings; ++i) { - gl::Buffer *curXFBBuffer = state.getIndexedTransformFeedbackBuffer(i); - GLintptr curXFBOffset = state.getIndexedTransformFeedbackBufferOffset(i); - - if (curXFBBuffer) + const OffsetBindingPointer<gl::Buffer> &binding = transformFeedback->getIndexedBuffer(i); + if (binding.get() != nullptr) { - Buffer11 *storage = Buffer11::makeBuffer11(curXFBBuffer->getImplementation()); + Buffer11 *storage = GetImplAs<Buffer11>(binding.get()); ID3D11Buffer *d3dBuffer = storage->getBuffer(BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK); - mCurrentD3DOffsets[i] = (mAppliedTFBuffers[i] != d3dBuffer || mAppliedTFOffsets[i] != curXFBOffset) ? - static_cast<UINT>(curXFBOffset) : -1; + mCurrentD3DOffsets[i] = (mAppliedTFBuffers[i] != d3dBuffer || mAppliedTFOffsets[i] != binding.getOffset()) ? + static_cast<UINT>(binding.getOffset()) : -1; mAppliedTFBuffers[i] = d3dBuffer; } else @@ -1518,26 +1638,30 @@ void Renderer11::applyTransformFeedbackBuffers(const gl::State &state) mAppliedTFBuffers[i] = NULL; mCurrentD3DOffsets[i] = 0; } - mAppliedTFOffsets[i] = curXFBOffset; + mAppliedTFOffsets[i] = binding.getOffset(); } mAppliedNumXFBBindings = numXFBBindings; - mDeviceContext->SOSetTargets(numXFBBindings, mAppliedTFBuffers, mCurrentD3DOffsets); + mDeviceContext->SOSetTargets(static_cast<unsigned int>(numXFBBindings), mAppliedTFBuffers, + mCurrentD3DOffsets); } } -gl::Error Renderer11::drawArrays(const gl::Data &data, GLenum mode, GLsizei count, GLsizei instances, bool usesPointSize) +gl::Error Renderer11::drawArraysImpl(const gl::Data &data, + GLenum mode, + GLsizei count, + GLsizei instances) { - bool useInstancedPointSpriteEmulation = usesPointSize && getWorkarounds().useInstancedPointSpriteEmulation; - if (mode == GL_POINTS && data.state->isTransformFeedbackActiveUnpaused()) - { - // Since point sprites are generated with a geometry shader, too many vertices will - // be written if transform feedback is active. To work around this, draw only the points - // with the stream out shader and no pixel shader to feed the stream out buffers and then - // draw again with the point sprite geometry shader to rasterize the point sprites. + ProgramD3D *programD3D = GetImplAs<ProgramD3D>(data.state->getProgram()); - mDeviceContext->PSSetShader(NULL, NULL, 0); + if (programD3D->usesGeometryShader(mode) && data.state->isTransformFeedbackActiveUnpaused()) + { + // Since we use a geometry if-and-only-if we rewrite vertex streams, transform feedback + // won't get the correct output. To work around this, draw with *only* the stream out + // first (no pixel shader) to feed the stream out buffers and then draw again with the + // geometry shader + pixel shader to rasterize the primitives. + mDeviceContext->PSSetShader(nullptr, nullptr, 0); if (instances > 0) { @@ -1548,98 +1672,192 @@ gl::Error Renderer11::drawArrays(const gl::Data &data, GLenum mode, GLsizei coun mDeviceContext->Draw(count, 0); } - ProgramD3D *programD3D = GetImplAs<ProgramD3D>(data.state->getProgram()); - - rx::ShaderExecutableD3D *pixelExe = NULL; + rx::ShaderExecutableD3D *pixelExe = nullptr; gl::Error error = programD3D->getPixelExecutableForFramebuffer(data.state->getDrawFramebuffer(), &pixelExe); if (error.isError()) { return error; } - // Skip this step if we're doing rasterizer discard. - if (pixelExe && !data.state->getRasterizerState().rasterizerDiscard && usesPointSize) + // Skip the draw call if rasterizer discard is enabled (or no fragment shader). + if (!pixelExe || data.state->getRasterizerState().rasterizerDiscard) { - ID3D11PixelShader *pixelShader = ShaderExecutable11::makeShaderExecutable11(pixelExe)->getPixelShader(); - ASSERT(reinterpret_cast<uintptr_t>(pixelShader) == mAppliedPixelShader); - mDeviceContext->PSSetShader(pixelShader, NULL, 0); + return gl::Error(GL_NO_ERROR); + } - // Retrieve the point sprite geometry shader - rx::ShaderExecutableD3D *geometryExe = programD3D->getGeometryExecutable(); - ID3D11GeometryShader *geometryShader = (geometryExe ? ShaderExecutable11::makeShaderExecutable11(geometryExe)->getGeometryShader() : NULL); - mAppliedGeometryShader = reinterpret_cast<uintptr_t>(geometryShader); - ASSERT(geometryShader); - mDeviceContext->GSSetShader(geometryShader, NULL, 0); + ID3D11PixelShader *pixelShader = GetAs<ShaderExecutable11>(pixelExe)->getPixelShader(); + ASSERT(reinterpret_cast<uintptr_t>(pixelShader) == mAppliedPixelShader); + mDeviceContext->PSSetShader(pixelShader, NULL, 0); - if (instances > 0) - { - mDeviceContext->DrawInstanced(count, instances, 0, 0); - } - else - { - mDeviceContext->Draw(count, 0); - } + // Retrieve the geometry shader. + rx::ShaderExecutableD3D *geometryExe = nullptr; + error = + programD3D->getGeometryExecutableForPrimitiveType(data, mode, &geometryExe, nullptr); + if (error.isError()) + { + return error; } + ID3D11GeometryShader *geometryShader = + (geometryExe ? GetAs<ShaderExecutable11>(geometryExe)->getGeometryShader() : NULL); + mAppliedGeometryShader = reinterpret_cast<uintptr_t>(geometryShader); + ASSERT(geometryShader); + mDeviceContext->GSSetShader(geometryShader, NULL, 0); + + if (instances > 0) + { + mDeviceContext->DrawInstanced(count, instances, 0, 0); + } + else + { + mDeviceContext->Draw(count, 0); + } return gl::Error(GL_NO_ERROR); } - else if (mode == GL_LINE_LOOP) - { - return drawLineLoop(count, GL_NONE, NULL, 0, NULL); - } - else if (mode == GL_TRIANGLE_FAN) + + if (mode == GL_LINE_LOOP) { - return drawTriangleFan(count, GL_NONE, NULL, 0, NULL, instances); + return drawLineLoop(data, count, GL_NONE, nullptr, nullptr, instances); } - else if (instances > 0) + + if (mode == GL_TRIANGLE_FAN) { - mDeviceContext->DrawInstanced(count, instances, 0, 0); - return gl::Error(GL_NO_ERROR); + return drawTriangleFan(data, count, GL_NONE, nullptr, 0, instances); } - else + + bool useInstancedPointSpriteEmulation = + programD3D->usesPointSize() && getWorkarounds().useInstancedPointSpriteEmulation; + + if (instances > 0) { - // If gl_PointSize is used and GL_POINTS is specified, then it is expected to render pointsprites. - // If instanced pointsprite emulation is being used the topology is expexted to be - // D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST and DrawIndexedInstanced must be used. if (mode == GL_POINTS && useInstancedPointSpriteEmulation) { - mDeviceContext->DrawIndexedInstanced(6, count, 0, 0, 0); + // If pointsprite emulation is used with glDrawArraysInstanced then we need to take a + // less efficent code path. + // Instanced rendering of emulated pointsprites requires a loop to draw each batch of + // points. An offset into the instanced data buffer is calculated and applied on each + // iteration to ensure all instances are rendered correctly. + + // Each instance being rendered requires the inputlayout cache to reapply buffers and + // offsets. + for (GLsizei i = 0; i < instances; i++) + { + gl::Error error = mInputLayoutCache.updateVertexOffsetsForPointSpritesEmulation(i); + if (error.isError()) + { + return error; + } + + mDeviceContext->DrawIndexedInstanced(6, count, 0, 0, 0); + } } else { - mDeviceContext->Draw(count, 0); + mDeviceContext->DrawInstanced(count, instances, 0, 0); } return gl::Error(GL_NO_ERROR); } + + // If the shader is writing to gl_PointSize, then pointsprites are being rendered. + // Emulating instanced point sprites for FL9_3 requires the topology to be + // D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST and DrawIndexedInstanced is called instead. + if (mode == GL_POINTS && useInstancedPointSpriteEmulation) + { + mDeviceContext->DrawIndexedInstanced(6, count, 0, 0, 0); + } + else + { + mDeviceContext->Draw(count, 0); + } + return gl::Error(GL_NO_ERROR); } -gl::Error Renderer11::drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, - gl::Buffer *elementArrayBuffer, const TranslatedIndexData &indexInfo, GLsizei instances) +gl::Error Renderer11::drawElementsImpl(const gl::Data &data, + const TranslatedIndexData &indexInfo, + GLenum mode, + GLsizei count, + GLenum type, + const GLvoid *indices, + GLsizei instances) { int minIndex = static_cast<int>(indexInfo.indexRange.start); if (mode == GL_LINE_LOOP) { - return drawLineLoop(count, type, indices, minIndex, elementArrayBuffer); + return drawLineLoop(data, count, type, indices, &indexInfo, instances); } - else if (mode == GL_TRIANGLE_FAN) + + if (mode == GL_TRIANGLE_FAN) { - return drawTriangleFan(count, type, indices, minIndex, elementArrayBuffer, instances); + return drawTriangleFan(data, count, type, indices, minIndex, instances); } - else if (instances > 0) + + const ProgramD3D *programD3D = GetImplAs<ProgramD3D>(data.state->getProgram()); + if (instances > 0) { - mDeviceContext->DrawIndexedInstanced(count, instances, 0, -minIndex, 0); + if (mode == GL_POINTS && programD3D->usesInstancedPointSpriteEmulation()) + { + // If pointsprite emulation is used with glDrawElementsInstanced then we need to take a + // less efficent code path. + // Instanced rendering of emulated pointsprites requires a loop to draw each batch of + // points. An offset into the instanced data buffer is calculated and applied on each + // iteration to ensure all instances are rendered correctly. + GLsizei elementsToRender = static_cast<GLsizei>(indexInfo.indexRange.vertexCount()); + + // Each instance being rendered requires the inputlayout cache to reapply buffers and + // offsets. + for (GLsizei i = 0; i < instances; i++) + { + gl::Error error = mInputLayoutCache.updateVertexOffsetsForPointSpritesEmulation(i); + if (error.isError()) + { + return error; + } + + mDeviceContext->DrawIndexedInstanced(6, elementsToRender, 0, 0, 0); + } + } + else + { + mDeviceContext->DrawIndexedInstanced(count, instances, 0, -minIndex, 0); + } return gl::Error(GL_NO_ERROR); } + + // If the shader is writing to gl_PointSize, then pointsprites are being rendered. + // Emulating instanced point sprites for FL9_3 requires the topology to be + // D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST and DrawIndexedInstanced is called instead. + if (mode == GL_POINTS && programD3D->usesInstancedPointSpriteEmulation()) + { + // The count parameter passed to drawElements represents the total number of instances + // to be rendered. Each instance is referenced by the bound index buffer from the + // the caller. + // + // Indexed pointsprite emulation replicates data for duplicate entries found + // in the index buffer. + // This is not an efficent rendering mechanism and is only used on downlevel renderers + // that do not support geometry shaders. + mDeviceContext->DrawIndexedInstanced(6, count, 0, 0, 0); + } else { mDeviceContext->DrawIndexed(count, 0, -minIndex); - return gl::Error(GL_NO_ERROR); } + return gl::Error(GL_NO_ERROR); } -gl::Error Renderer11::drawLineLoop(GLsizei count, GLenum type, const GLvoid *indices, int minIndex, gl::Buffer *elementArrayBuffer) +gl::Error Renderer11::drawLineLoop(const gl::Data &data, + GLsizei count, + GLenum type, + const GLvoid *indexPointer, + const TranslatedIndexData *indexInfo, + int instances) { + gl::VertexArray *vao = data.state->getVertexArray(); + gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get(); + + const GLvoid *indices = indexPointer; + // Get the raw indices for an indexed draw if (type != GL_NONE && elementArrayBuffer) { @@ -1675,7 +1893,11 @@ gl::Error Renderer11::drawLineLoop(GLsizei count, GLenum type, const GLvoid *ind return gl::Error(GL_OUT_OF_MEMORY, "Failed to create a 32-bit looping index buffer for GL_LINE_LOOP, too many indices required."); } - const unsigned int spaceNeeded = (static_cast<unsigned int>(count) + 1) * sizeof(unsigned int); + GetLineLoopIndices(indices, type, static_cast<GLuint>(count), + data.state->isPrimitiveRestartEnabled(), &mScratchIndexDataBuffer); + + unsigned int spaceNeeded = + static_cast<unsigned int>(sizeof(GLuint) * mScratchIndexDataBuffer.size()); gl::Error error = mLineLoopIB->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_INT); if (error.isError()) { @@ -1690,41 +1912,9 @@ gl::Error Renderer11::drawLineLoop(GLsizei count, GLenum type, const GLvoid *ind return error; } - unsigned int *data = reinterpret_cast<unsigned int*>(mappedMemory); - unsigned int indexBufferOffset = offset; - - switch (type) - { - case GL_NONE: // Non-indexed draw - for (int i = 0; i < count; i++) - { - data[i] = i; - } - data[count] = 0; - break; - case GL_UNSIGNED_BYTE: - for (int i = 0; i < count; i++) - { - data[i] = static_cast<const GLubyte*>(indices)[i]; - } - data[count] = static_cast<const GLubyte*>(indices)[0]; - break; - case GL_UNSIGNED_SHORT: - for (int i = 0; i < count; i++) - { - data[i] = static_cast<const GLushort*>(indices)[i]; - } - data[count] = static_cast<const GLushort*>(indices)[0]; - break; - case GL_UNSIGNED_INT: - for (int i = 0; i < count; i++) - { - data[i] = static_cast<const GLuint*>(indices)[i]; - } - data[count] = static_cast<const GLuint*>(indices)[0]; - break; - default: UNREACHABLE(); - } + // Copy over the converted index data. + memcpy(mappedMemory, &mScratchIndexDataBuffer[0], + sizeof(GLuint) * mScratchIndexDataBuffer.size()); error = mLineLoopIB->unmapBuffer(); if (error.isError()) @@ -1732,25 +1922,46 @@ gl::Error Renderer11::drawLineLoop(GLsizei count, GLenum type, const GLvoid *ind return error; } - IndexBuffer11 *indexBuffer = IndexBuffer11::makeIndexBuffer11(mLineLoopIB->getIndexBuffer()); + IndexBuffer11 *indexBuffer = GetAs<IndexBuffer11>(mLineLoopIB->getIndexBuffer()); ID3D11Buffer *d3dIndexBuffer = indexBuffer->getBuffer(); DXGI_FORMAT indexFormat = indexBuffer->getIndexFormat(); - if (mAppliedIB != d3dIndexBuffer || mAppliedIBFormat != indexFormat || mAppliedIBOffset != indexBufferOffset) + if (mAppliedIB != d3dIndexBuffer || mAppliedIBFormat != indexFormat || + mAppliedIBOffset != offset) { - mDeviceContext->IASetIndexBuffer(d3dIndexBuffer, indexFormat, indexBufferOffset); + mDeviceContext->IASetIndexBuffer(d3dIndexBuffer, indexFormat, offset); mAppliedIB = d3dIndexBuffer; mAppliedIBFormat = indexFormat; - mAppliedIBOffset = indexBufferOffset; + mAppliedIBOffset = offset; } - mDeviceContext->DrawIndexed(count + 1, 0, -minIndex); + INT baseVertexLocation = (indexInfo ? -static_cast<int>(indexInfo->indexRange.start) : 0); + UINT indexCount = static_cast<UINT>(mScratchIndexDataBuffer.size()); + + if (instances > 0) + { + mDeviceContext->DrawIndexedInstanced(indexCount, instances, 0, baseVertexLocation, 0); + } + else + { + mDeviceContext->DrawIndexed(indexCount, 0, baseVertexLocation); + } return gl::Error(GL_NO_ERROR); } -gl::Error Renderer11::drawTriangleFan(GLsizei count, GLenum type, const GLvoid *indices, int minIndex, gl::Buffer *elementArrayBuffer, int instances) +gl::Error Renderer11::drawTriangleFan(const gl::Data &data, + GLsizei count, + GLenum type, + const GLvoid *indices, + int minIndex, + int instances) { + gl::VertexArray *vao = data.state->getVertexArray(); + gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get(); + + const GLvoid *indexPointer = indices; + // Get the raw indices for an indexed draw if (type != GL_NONE && elementArrayBuffer) { @@ -1764,7 +1975,7 @@ gl::Error Renderer11::drawTriangleFan(GLsizei count, GLenum type, const GLvoid * return error; } - indices = bufferData + offset; + indexPointer = bufferData + offset; } if (!mTriangleFanIB) @@ -1781,21 +1992,25 @@ gl::Error Renderer11::drawTriangleFan(GLsizei count, GLenum type, const GLvoid * // Checked by Renderer11::applyPrimitiveType ASSERT(count >= 3); - const unsigned int numTris = count - 2; + const GLuint numTris = count - 2; if (numTris > (std::numeric_limits<unsigned int>::max() / (sizeof(unsigned int) * 3))) { return gl::Error(GL_OUT_OF_MEMORY, "Failed to create a scratch index buffer for GL_TRIANGLE_FAN, too many indices required."); } - const unsigned int spaceNeeded = (numTris * 3) * sizeof(unsigned int); + GetTriFanIndices(indexPointer, type, count, data.state->isPrimitiveRestartEnabled(), + &mScratchIndexDataBuffer); + + const unsigned int spaceNeeded = + static_cast<unsigned int>(mScratchIndexDataBuffer.size() * sizeof(unsigned int)); gl::Error error = mTriangleFanIB->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_INT); if (error.isError()) { return error; } - void* mappedMemory = NULL; + void *mappedMemory = nullptr; unsigned int offset; error = mTriangleFanIB->mapBuffer(spaceNeeded, &mappedMemory, &offset); if (error.isError()) @@ -1803,45 +2018,7 @@ gl::Error Renderer11::drawTriangleFan(GLsizei count, GLenum type, const GLvoid * return error; } - unsigned int *data = reinterpret_cast<unsigned int*>(mappedMemory); - unsigned int indexBufferOffset = offset; - - switch (type) - { - case GL_NONE: // Non-indexed draw - for (unsigned int i = 0; i < numTris; i++) - { - data[i*3 + 0] = 0; - data[i*3 + 1] = i + 1; - data[i*3 + 2] = i + 2; - } - break; - case GL_UNSIGNED_BYTE: - for (unsigned int i = 0; i < numTris; i++) - { - data[i*3 + 0] = static_cast<const GLubyte*>(indices)[0]; - data[i*3 + 1] = static_cast<const GLubyte*>(indices)[i + 1]; - data[i*3 + 2] = static_cast<const GLubyte*>(indices)[i + 2]; - } - break; - case GL_UNSIGNED_SHORT: - for (unsigned int i = 0; i < numTris; i++) - { - data[i*3 + 0] = static_cast<const GLushort*>(indices)[0]; - data[i*3 + 1] = static_cast<const GLushort*>(indices)[i + 1]; - data[i*3 + 2] = static_cast<const GLushort*>(indices)[i + 2]; - } - break; - case GL_UNSIGNED_INT: - for (unsigned int i = 0; i < numTris; i++) - { - data[i*3 + 0] = static_cast<const GLuint*>(indices)[0]; - data[i*3 + 1] = static_cast<const GLuint*>(indices)[i + 1]; - data[i*3 + 2] = static_cast<const GLuint*>(indices)[i + 2]; - } - break; - default: UNREACHABLE(); - } + memcpy(mappedMemory, &mScratchIndexDataBuffer[0], spaceNeeded); error = mTriangleFanIB->unmapBuffer(); if (error.isError()) @@ -1849,34 +2026,37 @@ gl::Error Renderer11::drawTriangleFan(GLsizei count, GLenum type, const GLvoid * return error; } - IndexBuffer11 *indexBuffer = IndexBuffer11::makeIndexBuffer11(mTriangleFanIB->getIndexBuffer()); + IndexBuffer11 *indexBuffer = GetAs<IndexBuffer11>(mTriangleFanIB->getIndexBuffer()); ID3D11Buffer *d3dIndexBuffer = indexBuffer->getBuffer(); DXGI_FORMAT indexFormat = indexBuffer->getIndexFormat(); - if (mAppliedIB != d3dIndexBuffer || mAppliedIBFormat != indexFormat || mAppliedIBOffset != indexBufferOffset) + if (mAppliedIB != d3dIndexBuffer || mAppliedIBFormat != indexFormat || + mAppliedIBOffset != offset) { - mDeviceContext->IASetIndexBuffer(d3dIndexBuffer, indexFormat, indexBufferOffset); + mDeviceContext->IASetIndexBuffer(d3dIndexBuffer, indexFormat, offset); mAppliedIB = d3dIndexBuffer; mAppliedIBFormat = indexFormat; - mAppliedIBOffset = indexBufferOffset; + mAppliedIBOffset = offset; } + UINT indexCount = static_cast<UINT>(mScratchIndexDataBuffer.size()); + if (instances > 0) { - mDeviceContext->DrawIndexedInstanced(numTris * 3, instances, 0, -minIndex, 0); + mDeviceContext->DrawIndexedInstanced(indexCount, instances, 0, -minIndex, 0); } else { - mDeviceContext->DrawIndexed(numTris * 3, 0, -minIndex); + mDeviceContext->DrawIndexed(indexCount, 0, -minIndex); } return gl::Error(GL_NO_ERROR); } -gl::Error Renderer11::applyShaders(gl::Program *program, const gl::VertexFormat inputLayout[], const gl::Framebuffer *framebuffer, - bool rasterizerDiscard, bool transformFeedbackActive) +gl::Error Renderer11::applyShadersImpl(const gl::Data &data, GLenum drawMode) { - ProgramD3D *programD3D = GetImplAs<ProgramD3D>(program); + ProgramD3D *programD3D = GetImplAs<ProgramD3D>(data.state->getProgram()); + const auto &inputLayout = programD3D->getCachedInputLayout(); ShaderExecutableD3D *vertexExe = NULL; gl::Error error = programD3D->getVertexExecutableForInputLayout(inputLayout, &vertexExe, nullptr); @@ -1885,32 +2065,41 @@ gl::Error Renderer11::applyShaders(gl::Program *program, const gl::VertexFormat return error; } + const gl::Framebuffer *drawFramebuffer = data.state->getDrawFramebuffer(); ShaderExecutableD3D *pixelExe = NULL; - error = programD3D->getPixelExecutableForFramebuffer(framebuffer, &pixelExe); + error = programD3D->getPixelExecutableForFramebuffer(drawFramebuffer, &pixelExe); if (error.isError()) { return error; } - ShaderExecutableD3D *geometryExe = programD3D->getGeometryExecutable(); + ShaderExecutableD3D *geometryExe = nullptr; + error = + programD3D->getGeometryExecutableForPrimitiveType(data, drawMode, &geometryExe, nullptr); + if (error.isError()) + { + return error; + } - ID3D11VertexShader *vertexShader = (vertexExe ? ShaderExecutable11::makeShaderExecutable11(vertexExe)->getVertexShader() : NULL); + ID3D11VertexShader *vertexShader = (vertexExe ? GetAs<ShaderExecutable11>(vertexExe)->getVertexShader() : NULL); ID3D11PixelShader *pixelShader = NULL; // Skip pixel shader if we're doing rasterizer discard. + bool rasterizerDiscard = data.state->getRasterizerState().rasterizerDiscard; if (!rasterizerDiscard) { - pixelShader = (pixelExe ? ShaderExecutable11::makeShaderExecutable11(pixelExe)->getPixelShader() : NULL); + pixelShader = (pixelExe ? GetAs<ShaderExecutable11>(pixelExe)->getPixelShader() : NULL); } ID3D11GeometryShader *geometryShader = NULL; + bool transformFeedbackActive = data.state->isTransformFeedbackActiveUnpaused(); if (transformFeedbackActive) { - geometryShader = (vertexExe ? ShaderExecutable11::makeShaderExecutable11(vertexExe)->getStreamOutShader() : NULL); + geometryShader = (vertexExe ? GetAs<ShaderExecutable11>(vertexExe)->getStreamOutShader() : NULL); } - else if (mCurRasterState.pointDrawMode) + else { - geometryShader = (geometryExe ? ShaderExecutable11::makeShaderExecutable11(geometryExe)->getGeometryShader() : NULL); + geometryShader = (geometryExe ? GetAs<ShaderExecutable11>(geometryExe)->getGeometryShader() : NULL); } bool dirtyUniforms = false; @@ -1944,7 +2133,9 @@ gl::Error Renderer11::applyShaders(gl::Program *program, const gl::VertexFormat return gl::Error(GL_NO_ERROR); } -gl::Error Renderer11::applyUniforms(const ProgramImpl &program, const std::vector<gl::LinkedUniform*> &uniformArray) +gl::Error Renderer11::applyUniforms(const ProgramD3D &programD3D, + GLenum drawMode, + const std::vector<D3DUniform *> &uniformArray) { unsigned int totalRegisterCountVS = 0; unsigned int totalRegisterCountPS = 0; @@ -1952,26 +2143,25 @@ gl::Error Renderer11::applyUniforms(const ProgramImpl &program, const std::vecto bool vertexUniformsDirty = false; bool pixelUniformsDirty = false; - for (size_t uniformIndex = 0; uniformIndex < uniformArray.size(); uniformIndex++) + for (const D3DUniform *uniform : uniformArray) { - const gl::LinkedUniform &uniform = *uniformArray[uniformIndex]; - - if (uniform.isReferencedByVertexShader() && !uniform.isSampler()) + if (uniform->isReferencedByVertexShader() && !uniform->isSampler()) { - totalRegisterCountVS += uniform.registerCount; - vertexUniformsDirty = (vertexUniformsDirty || uniform.dirty); + totalRegisterCountVS += uniform->registerCount; + vertexUniformsDirty = (vertexUniformsDirty || uniform->dirty); } - if (uniform.isReferencedByFragmentShader() && !uniform.isSampler()) + if (uniform->isReferencedByFragmentShader() && !uniform->isSampler()) { - totalRegisterCountPS += uniform.registerCount; - pixelUniformsDirty = (pixelUniformsDirty || uniform.dirty); + totalRegisterCountPS += uniform->registerCount; + pixelUniformsDirty = (pixelUniformsDirty || uniform->dirty); } } - const ProgramD3D *programD3D = GetAs<ProgramD3D>(&program); - const UniformStorage11 *vertexUniformStorage = UniformStorage11::makeUniformStorage11(&programD3D->getVertexUniformStorage()); - const UniformStorage11 *fragmentUniformStorage = UniformStorage11::makeUniformStorage11(&programD3D->getFragmentUniformStorage()); + const UniformStorage11 *vertexUniformStorage = + GetAs<UniformStorage11>(&programD3D.getVertexUniformStorage()); + const UniformStorage11 *fragmentUniformStorage = + GetAs<UniformStorage11>(&programD3D.getFragmentUniformStorage()); ASSERT(vertexUniformStorage); ASSERT(fragmentUniformStorage); @@ -1999,26 +2189,26 @@ gl::Error Renderer11::applyUniforms(const ProgramImpl &program, const std::vecto mapPS = (float(*)[4])map.pData; } - for (size_t uniformIndex = 0; uniformIndex < uniformArray.size(); uniformIndex++) + for (const D3DUniform *uniform : uniformArray) { - gl::LinkedUniform *uniform = uniformArray[uniformIndex]; + if (uniform->isSampler()) + continue; - if (!uniform->isSampler()) - { - unsigned int componentCount = (4 - uniform->registerElement); + unsigned int componentCount = (4 - uniform->registerElement); - // we assume that uniforms from structs are arranged in struct order in our uniforms list. otherwise we would - // overwrite previously written regions of memory. + // we assume that uniforms from structs are arranged in struct order in our uniforms list. + // otherwise we would overwrite previously written regions of memory. - if (uniform->isReferencedByVertexShader() && mapVS) - { - memcpy(&mapVS[uniform->vsRegisterIndex][uniform->registerElement], uniform->data, uniform->registerCount * sizeof(float) * componentCount); - } + if (uniform->isReferencedByVertexShader() && mapVS) + { + memcpy(&mapVS[uniform->vsRegisterIndex][uniform->registerElement], uniform->data, + uniform->registerCount * sizeof(float) * componentCount); + } - if (uniform->isReferencedByFragmentShader() && mapPS) - { - memcpy(&mapPS[uniform->psRegisterIndex][uniform->registerElement], uniform->data, uniform->registerCount * sizeof(float) * componentCount); - } + if (uniform->isReferencedByFragmentShader() && mapPS) + { + memcpy(&mapPS[uniform->psRegisterIndex][uniform->registerElement], uniform->data, + uniform->registerCount * sizeof(float) * componentCount); } } @@ -2048,7 +2238,7 @@ gl::Error Renderer11::applyUniforms(const ProgramImpl &program, const std::vecto if (!mDriverConstantBufferVS) { D3D11_BUFFER_DESC constantBufferDescription = {0}; - constantBufferDescription.ByteWidth = sizeof(dx_VertexConstants); + constantBufferDescription.ByteWidth = sizeof(dx_VertexConstants11); constantBufferDescription.Usage = D3D11_USAGE_DEFAULT; constantBufferDescription.BindFlags = D3D11_BIND_CONSTANT_BUFFER; constantBufferDescription.CPUAccessFlags = 0; @@ -2056,16 +2246,18 @@ gl::Error Renderer11::applyUniforms(const ProgramImpl &program, const std::vecto constantBufferDescription.StructureByteStride = 0; HRESULT result = mDevice->CreateBuffer(&constantBufferDescription, NULL, &mDriverConstantBufferVS); - UNUSED_ASSERTION_VARIABLE(result); ASSERT(SUCCEEDED(result)); - + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create vertex shader constant buffer, result: 0x%X.", result); + } mDeviceContext->VSSetConstantBuffers(1, 1, &mDriverConstantBufferVS); } if (!mDriverConstantBufferPS) { D3D11_BUFFER_DESC constantBufferDescription = {0}; - constantBufferDescription.ByteWidth = sizeof(dx_PixelConstants); + constantBufferDescription.ByteWidth = sizeof(dx_PixelConstants11); constantBufferDescription.Usage = D3D11_USAGE_DEFAULT; constantBufferDescription.BindFlags = D3D11_BIND_CONSTANT_BUFFER; constantBufferDescription.CPUAccessFlags = 0; @@ -2073,32 +2265,50 @@ gl::Error Renderer11::applyUniforms(const ProgramImpl &program, const std::vecto constantBufferDescription.StructureByteStride = 0; HRESULT result = mDevice->CreateBuffer(&constantBufferDescription, NULL, &mDriverConstantBufferPS); - UNUSED_ASSERTION_VARIABLE(result); ASSERT(SUCCEEDED(result)); - + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create pixel shader constant buffer, result: 0x%X.", result); + } mDeviceContext->PSSetConstantBuffers(1, 1, &mDriverConstantBufferPS); } - if (memcmp(&mVertexConstants, &mAppliedVertexConstants, sizeof(dx_VertexConstants)) != 0) + const dx_VertexConstants11 &vertexConstants = mStateManager.getVertexConstants(); + if (memcmp(&vertexConstants, &mAppliedVertexConstants, sizeof(dx_VertexConstants11)) != 0) { - mDeviceContext->UpdateSubresource(mDriverConstantBufferVS, 0, NULL, &mVertexConstants, 16, 0); - memcpy(&mAppliedVertexConstants, &mVertexConstants, sizeof(dx_VertexConstants)); + ASSERT(mDriverConstantBufferVS != nullptr); + if (mDriverConstantBufferVS) + { + mDeviceContext->UpdateSubresource(mDriverConstantBufferVS, 0, NULL, &vertexConstants, + 16, 0); + memcpy(&mAppliedVertexConstants, &vertexConstants, sizeof(dx_VertexConstants11)); + } } - if (memcmp(&mPixelConstants, &mAppliedPixelConstants, sizeof(dx_PixelConstants)) != 0) + const dx_PixelConstants11 &pixelConstants = mStateManager.getPixelConstants(); + if (memcmp(&pixelConstants, &mAppliedPixelConstants, sizeof(dx_PixelConstants11)) != 0) { - mDeviceContext->UpdateSubresource(mDriverConstantBufferPS, 0, NULL, &mPixelConstants, 16, 0); - memcpy(&mAppliedPixelConstants, &mPixelConstants, sizeof(dx_PixelConstants)); + ASSERT(mDriverConstantBufferPS != nullptr); + if (mDriverConstantBufferPS) + { + mDeviceContext->UpdateSubresource(mDriverConstantBufferPS, 0, NULL, &pixelConstants, 16, + 0); + memcpy(&mAppliedPixelConstants, &pixelConstants, sizeof(dx_PixelConstants11)); + } } // GSSetConstantBuffers triggers device removal on 9_3, so we should only call it if necessary - if (programD3D->usesGeometryShader()) + if (programD3D.usesGeometryShader(drawMode)) { // needed for the point sprite geometry shader if (mCurrentGeometryConstantBuffer != mDriverConstantBufferPS) { - mDeviceContext->GSSetConstantBuffers(0, 1, &mDriverConstantBufferPS); - mCurrentGeometryConstantBuffer = mDriverConstantBufferPS; + ASSERT(mDriverConstantBufferPS != nullptr); + if (mDriverConstantBufferPS) + { + mDeviceContext->GSSetConstantBuffers(0, 1, &mDriverConstantBufferPS); + mCurrentGeometryConstantBuffer = mDriverConstantBufferPS; + } } } @@ -2107,45 +2317,27 @@ gl::Error Renderer11::applyUniforms(const ProgramImpl &program, const std::vecto void Renderer11::markAllStateDirty() { - for (size_t rtIndex = 0; rtIndex < ArraySize(mAppliedRTVs); rtIndex++) - { - mAppliedRTVs[rtIndex] = DirtyPointer; - } - mAppliedDSV = DirtyPointer; - mDepthStencilInitialized = false; - mRenderTargetDescInitialized = false; - - // We reset the current SRV data because it might not be in sync with D3D's state - // anymore. For example when a currently used SRV is used as an RTV, D3D silently - // remove it from its state. - memset(mCurVertexSRVs.data(), 0, sizeof(SRVRecord) * mCurVertexSRVs.size()); - memset(mCurPixelSRVs.data(), 0, sizeof(SRVRecord) * mCurPixelSRVs.size()); + TRACE_EVENT0("gpu.angle", "Renderer11::markAllStateDirty"); - ASSERT(mForceSetVertexSamplerStates.size() == mCurVertexSRVs.size()); for (size_t vsamplerId = 0; vsamplerId < mForceSetVertexSamplerStates.size(); ++vsamplerId) { mForceSetVertexSamplerStates[vsamplerId] = true; } - ASSERT(mForceSetPixelSamplerStates.size() == mCurPixelSRVs.size()); for (size_t fsamplerId = 0; fsamplerId < mForceSetPixelSamplerStates.size(); ++fsamplerId) { mForceSetPixelSamplerStates[fsamplerId] = true; } - mForceSetBlendState = true; - mForceSetRasterState = true; - mForceSetDepthStencilState = true; - mForceSetScissor = true; - mForceSetViewport = true; + mStateManager.invalidateEverything(); mAppliedIB = NULL; mAppliedIBFormat = DXGI_FORMAT_UNKNOWN; mAppliedIBOffset = 0; - mAppliedVertexShader = DirtyPointer; - mAppliedGeometryShader = DirtyPointer; - mAppliedPixelShader = DirtyPointer; + mAppliedVertexShader = angle::DirtyPointer; + mAppliedGeometryShader = angle::DirtyPointer; + mAppliedPixelShader = angle::DirtyPointer; mAppliedNumXFBBindings = static_cast<size_t>(-1); @@ -2155,8 +2347,8 @@ void Renderer11::markAllStateDirty() mAppliedTFOffsets[i] = 0; } - memset(&mAppliedVertexConstants, 0, sizeof(dx_VertexConstants)); - memset(&mAppliedPixelConstants, 0, sizeof(dx_PixelConstants)); + memset(&mAppliedVertexConstants, 0, sizeof(dx_VertexConstants11)); + memset(&mAppliedPixelConstants, 0, sizeof(dx_PixelConstants11)); mInputLayoutCache.markDirty(); @@ -2238,20 +2430,16 @@ bool Renderer11::testDeviceResettable() D3D_FEATURE_LEVEL dummyFeatureLevel; ID3D11DeviceContext* dummyContext; - HRESULT result = D3D11CreateDevice(NULL, - mDriverType, - NULL, + ASSERT(mRequestedDriverType != D3D_DRIVER_TYPE_UNKNOWN); + HRESULT result = D3D11CreateDevice( + NULL, mRequestedDriverType, NULL, #if defined(_DEBUG) - D3D11_CREATE_DEVICE_DEBUG, + D3D11_CREATE_DEVICE_DEBUG, #else - 0, + 0, #endif - mAvailableFeatureLevels.data(), - mAvailableFeatureLevels.size(), - D3D11_SDK_VERSION, - &dummyDevice, - &dummyFeatureLevel, - &dummyContext); + mAvailableFeatureLevels.data(), static_cast<unsigned int>(mAvailableFeatureLevels.size()), + D3D11_SDK_VERSION, &dummyDevice, &dummyFeatureLevel, &dummyContext); if (!mDevice || FAILED(result)) { @@ -2270,6 +2458,13 @@ void Renderer11::release() releaseDeviceResources(); + if (!mCreatedWithDeviceEXT) + { + // Only delete the device if the Renderer11 owns it + // Otherwise we should keep it around in case we try to reinitialize the renderer later + SafeDelete(mEGLDevice); + } + SafeRelease(mDxgiFactory); SafeRelease(mDxgiAdapter); @@ -2285,6 +2480,9 @@ void Renderer11::release() } SafeRelease(mDevice); +#if !defined(ANGLE_MINGW32_COMPAT) + SafeRelease(mDebug); +#endif if (mD3d11Module) { @@ -2298,7 +2496,15 @@ void Renderer11::release() mDxgiModule = NULL; } + if (mDCompModule) + { + FreeLibrary(mDCompModule); + mDCompModule = NULL; + } + mCompiler.release(); + + mSupportsShareHandles.reset(); } bool Renderer11::resetDevice() @@ -2318,11 +2524,6 @@ bool Renderer11::resetDevice() return true; } -VendorID Renderer11::getVendorId() const -{ - return static_cast<VendorID>(mAdapterDescription.VendorId); -} - std::string Renderer11::getRendererDescription() const { std::ostringstream rendererString; @@ -2336,24 +2537,29 @@ std::string Renderer11::getRendererDescription() const return rendererString.str(); } -GUID Renderer11::getAdapterIdentifier() const +DeviceIdentifier Renderer11::getAdapterIdentifier() const { - // Use the adapter LUID as our adapter ID - // This number is local to a machine is only guaranteed to be unique between restarts - static_assert(sizeof(LUID) <= sizeof(GUID), "Size of GUID must be at least as large as LUID."); - GUID adapterId = {0}; - memcpy(&adapterId, &mAdapterDescription.AdapterLuid, sizeof(LUID)); - return adapterId; + // Don't use the AdapterLuid here, since that doesn't persist across reboot. + DeviceIdentifier deviceIdentifier = { 0 }; + deviceIdentifier.VendorId = mAdapterDescription.VendorId; + deviceIdentifier.DeviceId = mAdapterDescription.DeviceId; + deviceIdentifier.SubSysId = mAdapterDescription.SubSysId; + deviceIdentifier.Revision = mAdapterDescription.Revision; + deviceIdentifier.FeatureLevel = static_cast<UINT>(mRenderer11DeviceCaps.featureLevel); + + return deviceIdentifier; } unsigned int Renderer11::getReservedVertexUniformVectors() const { - return 0; // Driver uniforms are stored in a separate constant buffer + // Driver uniforms are stored in a separate constant buffer + return d3d11_gl::GetReservedVertexUniformVectors(mRenderer11DeviceCaps.featureLevel); } unsigned int Renderer11::getReservedFragmentUniformVectors() const { - return 0; // Driver uniforms are stored in a separate constant buffer + // Driver uniforms are stored in a separate constant buffer + return d3d11_gl::GetReservedFragmentUniformVectors(mRenderer11DeviceCaps.featureLevel); } unsigned int Renderer11::getReservedVertexUniformBuffers() const @@ -2368,24 +2574,100 @@ unsigned int Renderer11::getReservedFragmentUniformBuffers() const return 2; } +d3d11::ANGLED3D11DeviceType Renderer11::getDeviceType() const +{ + if (mCreatedWithDeviceEXT) + { + return d3d11::GetDeviceType(mDevice); + } + + if ((mRequestedDriverType == D3D_DRIVER_TYPE_SOFTWARE) || + (mRequestedDriverType == D3D_DRIVER_TYPE_REFERENCE) || + (mRequestedDriverType == D3D_DRIVER_TYPE_NULL)) + { + return d3d11::ANGLE_D3D11_DEVICE_TYPE_SOFTWARE_REF_OR_NULL; + } + + if (mRequestedDriverType == D3D_DRIVER_TYPE_WARP) + { + return d3d11::ANGLE_D3D11_DEVICE_TYPE_WARP; + } + + return d3d11::ANGLE_D3D11_DEVICE_TYPE_HARDWARE; +} + bool Renderer11::getShareHandleSupport() const { + if (mSupportsShareHandles.valid()) + { + return mSupportsShareHandles.value(); + } + // We only currently support share handles with BGRA surfaces, because // chrome needs BGRA. Once chrome fixes this, we should always support them. + if (!getRendererExtensions().textureFormatBGRA8888) + { + mSupportsShareHandles = false; + return false; + } + // PIX doesn't seem to support using share handles, so disable them. + if (gl::DebugAnnotationsActive()) + { + mSupportsShareHandles = false; + return false; + } + // Also disable share handles on Feature Level 9_3, since it doesn't support share handles on RGBA8 textures/swapchains. - return getRendererExtensions().textureFormatBGRA8888 && !gl::DebugAnnotationsActive();// && !(mFeatureLevel <= D3D_FEATURE_LEVEL_9_3); Qt: we don't care about the 9_3 limitation -} + if (mRenderer11DeviceCaps.featureLevel <= D3D_FEATURE_LEVEL_9_3) + { + mSupportsShareHandles = false; + return false; + } -bool Renderer11::getPostSubBufferSupport() const -{ - // D3D11 does not support present with dirty rectangles until D3D11.1 and DXGI 1.2. - return false; + // Find out which type of D3D11 device the Renderer11 is using + d3d11::ANGLED3D11DeviceType deviceType = getDeviceType(); + if (deviceType == d3d11::ANGLE_D3D11_DEVICE_TYPE_UNKNOWN) + { + mSupportsShareHandles = false; + return false; + } + + if (deviceType == d3d11::ANGLE_D3D11_DEVICE_TYPE_SOFTWARE_REF_OR_NULL) + { + // Software/Reference/NULL devices don't support share handles + mSupportsShareHandles = false; + return false; + } + + if (deviceType == d3d11::ANGLE_D3D11_DEVICE_TYPE_WARP) + { +#if !defined(ANGLE_ENABLE_WINDOWS_STORE) && !defined(__GNUC__) + if (!IsWindows8OrGreater()) + { + // WARP on Windows 7 doesn't support shared handles + mSupportsShareHandles = false; + return false; + } +#endif // ANGLE_ENABLE_WINDOWS_STORE + + // WARP on Windows 8.0+ supports shared handles when shared with another WARP device + // TODO: allow applications to query for HARDWARE or WARP-specific share handles, + // to prevent them trying to use a WARP share handle with an a HW device (or + // vice-versa) + // e.g. by creating EGL_D3D11_[HARDWARE/WARP]_DEVICE_SHARE_HANDLE_ANGLE + mSupportsShareHandles = true; + return true; + } + + ASSERT(mCreatedWithDeviceEXT || mRequestedDriverType == D3D_DRIVER_TYPE_HARDWARE); + mSupportsShareHandles = true; + return true; } int Renderer11::getMajorShaderModel() const { - switch (mFeatureLevel) + switch (mRenderer11DeviceCaps.featureLevel) { case D3D_FEATURE_LEVEL_11_0: return D3D11_SHADER_MAJOR_VERSION; // 5 case D3D_FEATURE_LEVEL_10_1: return D3D10_1_SHADER_MAJOR_VERSION; // 4 @@ -2397,7 +2679,7 @@ int Renderer11::getMajorShaderModel() const int Renderer11::getMinorShaderModel() const { - switch (mFeatureLevel) + switch (mRenderer11DeviceCaps.featureLevel) { case D3D_FEATURE_LEVEL_11_0: return D3D11_SHADER_MINOR_VERSION; // 0 case D3D_FEATURE_LEVEL_10_1: return D3D10_1_SHADER_MINOR_VERSION; // 1 @@ -2409,7 +2691,7 @@ int Renderer11::getMinorShaderModel() const std::string Renderer11::getShaderModelSuffix() const { - switch (mFeatureLevel) + switch (mRenderer11DeviceCaps.featureLevel) { case D3D_FEATURE_LEVEL_11_0: return ""; case D3D_FEATURE_LEVEL_10_1: return ""; @@ -2419,14 +2701,25 @@ std::string Renderer11::getShaderModelSuffix() const } } +const WorkaroundsD3D &RendererD3D::getWorkarounds() const +{ + if (!mWorkaroundsInitialized) + { + mWorkarounds = generateWorkarounds(); + mWorkaroundsInitialized = true; + } + + return mWorkarounds; +} + gl::Error Renderer11::copyImage2D(const gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, const gl::Offset &destOffset, TextureStorage *storage, GLint level) { - gl::FramebufferAttachment *colorbuffer = framebuffer->getReadColorbuffer(); + const gl::FramebufferAttachment *colorbuffer = framebuffer->getReadColorbuffer(); ASSERT(colorbuffer); RenderTarget11 *sourceRenderTarget = NULL; - gl::Error error = d3d11::GetAttachmentRenderTarget(colorbuffer, &sourceRenderTarget); + gl::Error error = colorbuffer->getRenderTarget(&sourceRenderTarget); if (error.isError()) { return error; @@ -2436,7 +2729,7 @@ gl::Error Renderer11::copyImage2D(const gl::Framebuffer *framebuffer, const gl:: ID3D11ShaderResourceView *source = sourceRenderTarget->getShaderResourceView(); ASSERT(source); - TextureStorage11_2D *storage11 = TextureStorage11_2D::makeTextureStorage11_2D(storage); + TextureStorage11_2D *storage11 = GetAs<TextureStorage11_2D>(storage); ASSERT(storage11); gl::ImageIndex index = gl::ImageIndex::Make2D(level); @@ -2448,18 +2741,26 @@ gl::Error Renderer11::copyImage2D(const gl::Framebuffer *framebuffer, const gl:: } ASSERT(destRenderTarget); - ID3D11RenderTargetView *dest = RenderTarget11::makeRenderTarget11(destRenderTarget)->getRenderTargetView(); + ID3D11RenderTargetView *dest = GetAs<RenderTarget11>(destRenderTarget)->getRenderTargetView(); ASSERT(dest); gl::Box sourceArea(sourceRect.x, sourceRect.y, 0, sourceRect.width, sourceRect.height, 1); gl::Extents sourceSize(sourceRenderTarget->getWidth(), sourceRenderTarget->getHeight(), 1); + const bool invertSource = UsePresentPathFast(this, colorbuffer); + if (invertSource) + { + sourceArea.y = sourceSize.height - sourceRect.y; + sourceArea.height = -sourceArea.height; + } + gl::Box destArea(destOffset.x, destOffset.y, 0, sourceRect.width, sourceRect.height, 1); gl::Extents destSize(destRenderTarget->getWidth(), destRenderTarget->getHeight(), 1); // Use nearest filtering because source and destination are the same size for the direct // copy - mBlit->copyTexture(source, sourceArea, sourceSize, dest, destArea, destSize, NULL, destFormat, GL_NEAREST); + error = mBlit->copyTexture(source, sourceArea, sourceSize, dest, destArea, destSize, NULL, + destFormat, GL_NEAREST, false); if (error.isError()) { return error; @@ -2473,11 +2774,11 @@ gl::Error Renderer11::copyImage2D(const gl::Framebuffer *framebuffer, const gl:: gl::Error Renderer11::copyImageCube(const gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, const gl::Offset &destOffset, TextureStorage *storage, GLenum target, GLint level) { - gl::FramebufferAttachment *colorbuffer = framebuffer->getReadColorbuffer(); + const gl::FramebufferAttachment *colorbuffer = framebuffer->getReadColorbuffer(); ASSERT(colorbuffer); RenderTarget11 *sourceRenderTarget = NULL; - gl::Error error = d3d11::GetAttachmentRenderTarget(colorbuffer, &sourceRenderTarget); + gl::Error error = colorbuffer->getRenderTarget(&sourceRenderTarget); if (error.isError()) { return error; @@ -2487,7 +2788,7 @@ gl::Error Renderer11::copyImageCube(const gl::Framebuffer *framebuffer, const gl ID3D11ShaderResourceView *source = sourceRenderTarget->getShaderResourceView(); ASSERT(source); - TextureStorage11_Cube *storage11 = TextureStorage11_Cube::makeTextureStorage11_Cube(storage); + TextureStorage11_Cube *storage11 = GetAs<TextureStorage11_Cube>(storage); ASSERT(storage11); gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level); @@ -2499,18 +2800,26 @@ gl::Error Renderer11::copyImageCube(const gl::Framebuffer *framebuffer, const gl } ASSERT(destRenderTarget); - ID3D11RenderTargetView *dest = RenderTarget11::makeRenderTarget11(destRenderTarget)->getRenderTargetView(); + ID3D11RenderTargetView *dest = GetAs<RenderTarget11>(destRenderTarget)->getRenderTargetView(); ASSERT(dest); gl::Box sourceArea(sourceRect.x, sourceRect.y, 0, sourceRect.width, sourceRect.height, 1); gl::Extents sourceSize(sourceRenderTarget->getWidth(), sourceRenderTarget->getHeight(), 1); + const bool invertSource = UsePresentPathFast(this, colorbuffer); + if (invertSource) + { + sourceArea.y = sourceSize.height - sourceRect.y; + sourceArea.height = -sourceArea.height; + } + gl::Box destArea(destOffset.x, destOffset.y, 0, sourceRect.width, sourceRect.height, 1); gl::Extents destSize(destRenderTarget->getWidth(), destRenderTarget->getHeight(), 1); // Use nearest filtering because source and destination are the same size for the direct // copy - error = mBlit->copyTexture(source, sourceArea, sourceSize, dest, destArea, destSize, NULL, destFormat, GL_NEAREST); + error = mBlit->copyTexture(source, sourceArea, sourceSize, dest, destArea, destSize, NULL, + destFormat, GL_NEAREST, false); if (error.isError()) { return error; @@ -2524,11 +2833,11 @@ gl::Error Renderer11::copyImageCube(const gl::Framebuffer *framebuffer, const gl gl::Error Renderer11::copyImage3D(const gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, const gl::Offset &destOffset, TextureStorage *storage, GLint level) { - gl::FramebufferAttachment *colorbuffer = framebuffer->getReadColorbuffer(); + const gl::FramebufferAttachment *colorbuffer = framebuffer->getReadColorbuffer(); ASSERT(colorbuffer); RenderTarget11 *sourceRenderTarget = NULL; - gl::Error error = d3d11::GetAttachmentRenderTarget(colorbuffer, &sourceRenderTarget); + gl::Error error = colorbuffer->getRenderTarget(&sourceRenderTarget); if (error.isError()) { return error; @@ -2538,7 +2847,7 @@ gl::Error Renderer11::copyImage3D(const gl::Framebuffer *framebuffer, const gl:: ID3D11ShaderResourceView *source = sourceRenderTarget->getShaderResourceView(); ASSERT(source); - TextureStorage11_3D *storage11 = TextureStorage11_3D::makeTextureStorage11_3D(storage); + TextureStorage11_3D *storage11 = GetAs<TextureStorage11_3D>(storage); ASSERT(storage11); gl::ImageIndex index = gl::ImageIndex::Make3D(level, destOffset.z); @@ -2550,7 +2859,7 @@ gl::Error Renderer11::copyImage3D(const gl::Framebuffer *framebuffer, const gl:: } ASSERT(destRenderTarget); - ID3D11RenderTargetView *dest = RenderTarget11::makeRenderTarget11(destRenderTarget)->getRenderTargetView(); + ID3D11RenderTargetView *dest = GetAs<RenderTarget11>(destRenderTarget)->getRenderTargetView(); ASSERT(dest); gl::Box sourceArea(sourceRect.x, sourceRect.y, 0, sourceRect.width, sourceRect.height, 1); @@ -2561,7 +2870,8 @@ gl::Error Renderer11::copyImage3D(const gl::Framebuffer *framebuffer, const gl:: // Use nearest filtering because source and destination are the same size for the direct // copy - error = mBlit->copyTexture(source, sourceArea, sourceSize, dest, destArea, destSize, NULL, destFormat, GL_NEAREST); + error = mBlit->copyTexture(source, sourceArea, sourceSize, dest, destArea, destSize, NULL, + destFormat, GL_NEAREST, false); if (error.isError()) { return error; @@ -2575,11 +2885,11 @@ gl::Error Renderer11::copyImage3D(const gl::Framebuffer *framebuffer, const gl:: gl::Error Renderer11::copyImage2DArray(const gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, const gl::Offset &destOffset, TextureStorage *storage, GLint level) { - gl::FramebufferAttachment *colorbuffer = framebuffer->getReadColorbuffer(); + const gl::FramebufferAttachment *colorbuffer = framebuffer->getReadColorbuffer(); ASSERT(colorbuffer); RenderTarget11 *sourceRenderTarget = NULL; - gl::Error error = d3d11::GetAttachmentRenderTarget(colorbuffer, &sourceRenderTarget); + gl::Error error = colorbuffer->getRenderTarget(&sourceRenderTarget); if (error.isError()) { return error; @@ -2589,7 +2899,7 @@ gl::Error Renderer11::copyImage2DArray(const gl::Framebuffer *framebuffer, const ID3D11ShaderResourceView *source = sourceRenderTarget->getShaderResourceView(); ASSERT(source); - TextureStorage11_2DArray *storage11 = TextureStorage11_2DArray::makeTextureStorage11_2DArray(storage); + TextureStorage11_2DArray *storage11 = GetAs<TextureStorage11_2DArray>(storage); ASSERT(storage11); gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, destOffset.z); @@ -2601,7 +2911,7 @@ gl::Error Renderer11::copyImage2DArray(const gl::Framebuffer *framebuffer, const } ASSERT(destRenderTarget); - ID3D11RenderTargetView *dest = RenderTarget11::makeRenderTarget11(destRenderTarget)->getRenderTargetView(); + ID3D11RenderTargetView *dest = GetAs<RenderTarget11>(destRenderTarget)->getRenderTargetView(); ASSERT(dest); gl::Box sourceArea(sourceRect.x, sourceRect.y, 0, sourceRect.width, sourceRect.height, 1); @@ -2612,7 +2922,8 @@ gl::Error Renderer11::copyImage2DArray(const gl::Framebuffer *framebuffer, const // Use nearest filtering because source and destination are the same size for the direct // copy - error = mBlit->copyTexture(source, sourceArea, sourceSize, dest, destArea, destSize, NULL, destFormat, GL_NEAREST); + error = mBlit->copyTexture(source, sourceArea, sourceSize, dest, destArea, destSize, NULL, + destFormat, GL_NEAREST, false); if (error.isError()) { return error; @@ -2640,14 +2951,14 @@ void Renderer11::setOneTimeRenderTarget(ID3D11RenderTargetView *renderTargetView // Do not preserve the serial for this one-time-use render target for (size_t rtIndex = 0; rtIndex < ArraySize(mAppliedRTVs); rtIndex++) { - mAppliedRTVs[rtIndex] = DirtyPointer; + mAppliedRTVs[rtIndex] = angle::DirtyPointer; } - mAppliedDSV = DirtyPointer; + mAppliedDSV = angle::DirtyPointer; } gl::Error Renderer11::createRenderTarget(int width, int height, GLenum format, GLsizei samples, RenderTargetD3D **outRT) { - const d3d11::TextureFormat &formatInfo = d3d11::GetTextureFormatInfo(format, mFeatureLevel); + const d3d11::TextureFormat &formatInfo = d3d11::GetTextureFormatInfo(format, mRenderer11DeviceCaps); const gl::TextureCaps &textureCaps = getRendererTextureCaps().get(format); GLuint supportedSamples = textureCaps.getNearestSamples(samples); @@ -2779,9 +3090,26 @@ gl::Error Renderer11::createRenderTarget(int width, int height, GLenum format, G return gl::Error(GL_NO_ERROR); } -FramebufferImpl *Renderer11::createDefaultFramebuffer(const gl::Framebuffer::Data &data) +gl::Error Renderer11::createRenderTargetCopy(RenderTargetD3D *source, RenderTargetD3D **outRT) { - return createFramebuffer(data); + ASSERT(source != nullptr); + + RenderTargetD3D *newRT = nullptr; + gl::Error error = createRenderTarget(source->getWidth(), source->getHeight(), + source->getInternalFormat(), source->getSamples(), &newRT); + if (error.isError()) + { + return error; + } + + RenderTarget11 *source11 = GetAs<RenderTarget11>(source); + RenderTarget11 *dest11 = GetAs<RenderTarget11>(newRT); + + mDeviceContext->CopySubresourceRegion(dest11->getTexture(), dest11->getSubresourceIndex(), 0, 0, + 0, source11->getTexture(), + source11->getSubresourceIndex(), nullptr); + *outRT = newRT; + return gl::Error(GL_NO_ERROR); } FramebufferImpl *Renderer11::createFramebuffer(const gl::Framebuffer::Data &data) @@ -2789,24 +3117,22 @@ FramebufferImpl *Renderer11::createFramebuffer(const gl::Framebuffer::Data &data return new Framebuffer11(data, this); } -CompilerImpl *Renderer11::createCompiler(const gl::Data &data) +ShaderImpl *Renderer11::createShader(const gl::Shader::Data &data) { - return new CompilerD3D(data, SH_HLSL11_OUTPUT); + return new ShaderD3D(data); } -ShaderImpl *Renderer11::createShader(GLenum type) +ProgramImpl *Renderer11::createProgram(const gl::Program::Data &data) { - return new ShaderD3D(type); + return new ProgramD3D(data, this); } -ProgramImpl *Renderer11::createProgram() -{ - return new ProgramD3D(this); -} - -gl::Error Renderer11::loadExecutable(const void *function, size_t length, ShaderType type, - const std::vector<gl::LinkedVarying> &transformFeedbackVaryings, - bool separatedOutputBuffers, ShaderExecutableD3D **outExecutable) +gl::Error Renderer11::loadExecutable(const void *function, + size_t length, + ShaderType type, + const std::vector<D3DVarying> &streamOutVaryings, + bool separatedOutputBuffers, + ShaderExecutableD3D **outExecutable) { switch (type) { @@ -2822,29 +3148,28 @@ gl::Error Renderer11::loadExecutable(const void *function, size_t length, Shader return gl::Error(GL_OUT_OF_MEMORY, "Failed to create vertex shader, result: 0x%X.", result); } - if (transformFeedbackVaryings.size() > 0) + if (!streamOutVaryings.empty()) { std::vector<D3D11_SO_DECLARATION_ENTRY> soDeclaration; - for (size_t i = 0; i < transformFeedbackVaryings.size(); i++) + soDeclaration.reserve(streamOutVaryings.size()); + + for (const auto &streamOutVarying : streamOutVaryings) { - const gl::LinkedVarying &varying = transformFeedbackVaryings[i]; - GLenum transposedType = gl::TransposeMatrixType(varying.type); - - for (size_t j = 0; j < varying.semanticIndexCount; j++) - { - D3D11_SO_DECLARATION_ENTRY entry = { 0 }; - entry.Stream = 0; - entry.SemanticName = varying.semanticName.c_str(); - entry.SemanticIndex = varying.semanticIndex + j; - entry.StartComponent = 0; - entry.ComponentCount = gl::VariableColumnCount(transposedType); - entry.OutputSlot = (separatedOutputBuffers ? i : 0); - soDeclaration.push_back(entry); - } + D3D11_SO_DECLARATION_ENTRY entry = {0}; + entry.Stream = 0; + entry.SemanticName = streamOutVarying.semanticName.c_str(); + entry.SemanticIndex = streamOutVarying.semanticIndex; + entry.StartComponent = 0; + entry.ComponentCount = static_cast<BYTE>(streamOutVarying.componentCount); + entry.OutputSlot = static_cast<BYTE>( + (separatedOutputBuffers ? streamOutVarying.outputSlot : 0)); + soDeclaration.push_back(entry); } - result = mDevice->CreateGeometryShaderWithStreamOutput(function, length, soDeclaration.data(), soDeclaration.size(), - NULL, 0, 0, NULL, &streamOutShader); + result = mDevice->CreateGeometryShaderWithStreamOutput( + function, static_cast<unsigned int>(length), soDeclaration.data(), + static_cast<unsigned int>(soDeclaration.size()), NULL, 0, 0, NULL, + &streamOutShader); ASSERT(SUCCEEDED(result)); if (FAILED(result)) { @@ -2891,9 +3216,12 @@ gl::Error Renderer11::loadExecutable(const void *function, size_t length, Shader return gl::Error(GL_NO_ERROR); } -gl::Error Renderer11::compileToExecutable(gl::InfoLog &infoLog, const std::string &shaderHLSL, ShaderType type, - const std::vector<gl::LinkedVarying> &transformFeedbackVaryings, - bool separatedOutputBuffers, const D3DCompilerWorkarounds &workarounds, +gl::Error Renderer11::compileToExecutable(gl::InfoLog &infoLog, + const std::string &shaderHLSL, + ShaderType type, + const std::vector<D3DVarying> &streamOutVaryings, + bool separatedOutputBuffers, + const D3DCompilerWorkarounds &workarounds, ShaderExecutableD3D **outExectuable) { const char *profileType = NULL; @@ -2936,6 +3264,15 @@ gl::Error Renderer11::compileToExecutable(gl::InfoLog &infoLog, const std::strin configs.push_back(CompileConfig(flags | D3DCOMPILE_SKIP_VALIDATION, "skip validation" )); configs.push_back(CompileConfig(flags | D3DCOMPILE_SKIP_OPTIMIZATION, "skip optimization")); + if (getMajorShaderModel() == 4 && getShaderModelSuffix() != "") + { + // Some shaders might cause a "blob content mismatch between level9 and d3d10 shader". + // e.g. dEQP-GLES2.functional.shaders.struct.local.loop_nested_struct_array_*. + // Using the [unroll] directive works around this, as does this D3DCompile flag. + configs.push_back( + CompileConfig(flags | D3DCOMPILE_AVOID_FLOW_CONTROL, "avoid flow control")); + } + D3D_SHADER_MACRO loopMacros[] = { {"ANGLE_ENABLE_LOOP_FLATTEN", "1"}, {0, 0} }; ID3DBlob *binary = NULL; @@ -2955,7 +3292,7 @@ gl::Error Renderer11::compileToExecutable(gl::InfoLog &infoLog, const std::strin } error = loadExecutable(binary->GetBufferPointer(), binary->GetBufferSize(), type, - transformFeedbackVaryings, separatedOutputBuffers, outExectuable); + streamOutVaryings, separatedOutputBuffers, outExectuable); SafeRelease(binary); if (error.isError()) @@ -2988,12 +3325,14 @@ IndexBuffer *Renderer11::createIndexBuffer() BufferImpl *Renderer11::createBuffer() { - return new Buffer11(this); + Buffer11 *buffer = new Buffer11(this); + mAliveBuffers.insert(buffer); + return buffer; } -VertexArrayImpl *Renderer11::createVertexArray() +VertexArrayImpl *Renderer11::createVertexArray(const gl::VertexArray::Data &data) { - return new VertexArray11(this); + return new VertexArray11(data); } QueryImpl *Renderer11::createQuery(GLenum type) @@ -3021,7 +3360,7 @@ bool Renderer11::supportsFastCopyBufferToTexture(GLenum internalFormat) const ASSERT(getRendererExtensions().pixelBufferObject); const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(internalFormat); - const d3d11::TextureFormat &d3d11FormatInfo = d3d11::GetTextureFormatInfo(internalFormat, mFeatureLevel); + const d3d11::TextureFormat &d3d11FormatInfo = d3d11::GetTextureFormatInfo(internalFormat, mRenderer11DeviceCaps); const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(d3d11FormatInfo.texFormat); // sRGB formats do not work with D3D11 buffer SRVs @@ -3065,17 +3404,42 @@ ImageD3D *Renderer11::createImage() gl::Error Renderer11::generateMipmap(ImageD3D *dest, ImageD3D *src) { - Image11 *dest11 = Image11::makeImage11(dest); - Image11 *src11 = Image11::makeImage11(src); + Image11 *dest11 = GetAs<Image11>(dest); + Image11 *src11 = GetAs<Image11>(src); return Image11::generateMipmap(dest11, src11); } +gl::Error Renderer11::generateMipmapsUsingD3D(TextureStorage *storage, + const gl::TextureState &textureState) +{ + TextureStorage11 *storage11 = GetAs<TextureStorage11>(storage); + + ASSERT(storage11->isRenderTarget()); + ASSERT(storage11->supportsNativeMipmapFunction()); + + ID3D11ShaderResourceView *srv; + gl::Error error = storage11->getSRVLevels(textureState.baseLevel, textureState.maxLevel, &srv); + if (error.isError()) + { + return error; + } + + mDeviceContext->GenerateMips(srv); + + return gl::Error(GL_NO_ERROR); +} + TextureStorage *Renderer11::createTextureStorage2D(SwapChainD3D *swapChain) { - SwapChain11 *swapChain11 = SwapChain11::makeSwapChain11(swapChain); + SwapChain11 *swapChain11 = GetAs<SwapChain11>(swapChain); return new TextureStorage11_2D(this, swapChain11); } +TextureStorage *Renderer11::createTextureStorageEGLImage(EGLImageD3D *eglImage) +{ + return new TextureStorage11_EGLImage(this, eglImage); +} + TextureStorage *Renderer11::createTextureStorage2D(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels, bool hintLevelZeroOnly) { return new TextureStorage11_2D(this, internalformat, renderTarget, width, height, levels, hintLevelZeroOnly); @@ -3117,28 +3481,53 @@ RenderbufferImpl *Renderer11::createRenderbuffer() return renderbuffer; } -gl::Error Renderer11::readTextureData(ID3D11Texture2D *texture, unsigned int subResource, const gl::Rectangle &area, GLenum format, - GLenum type, GLuint outputPitch, const gl::PixelPackState &pack, uint8_t *pixels) +gl::Error Renderer11::readFromAttachment(const gl::FramebufferAttachment &srcAttachment, + const gl::Rectangle &sourceArea, + GLenum format, + GLenum type, + GLuint outputPitch, + const gl::PixelPackState &pack, + uint8_t *pixelsOut) { - ASSERT(area.width >= 0); - ASSERT(area.height >= 0); + ASSERT(sourceArea.width >= 0); + ASSERT(sourceArea.height >= 0); - D3D11_TEXTURE2D_DESC textureDesc; - texture->GetDesc(&textureDesc); + const bool invertTexture = UsePresentPathFast(this, &srcAttachment); + + RenderTargetD3D *renderTarget = nullptr; + gl::Error error = srcAttachment.getRenderTarget(&renderTarget); + if (error.isError()) + { + return error; + } + + RenderTarget11 *rt11 = GetAs<RenderTarget11>(renderTarget); + ASSERT(rt11->getTexture()); + + TextureHelper11 textureHelper = TextureHelper11::MakeAndReference(rt11->getTexture()); + unsigned int sourceSubResource = rt11->getSubresourceIndex(); + + const gl::Extents &texSize = textureHelper.getExtents(); + + gl::Rectangle actualArea = sourceArea; + if (invertTexture) + { + actualArea.y = texSize.height - actualArea.y - actualArea.height; + } // Clamp read region to the defined texture boundaries, preventing out of bounds reads // and reads of uninitialized data. gl::Rectangle safeArea; - safeArea.x = gl::clamp(area.x, 0, static_cast<int>(textureDesc.Width)); - safeArea.y = gl::clamp(area.y, 0, static_cast<int>(textureDesc.Height)); - safeArea.width = gl::clamp(area.width + std::min(area.x, 0), 0, - static_cast<int>(textureDesc.Width) - safeArea.x); - safeArea.height = gl::clamp(area.height + std::min(area.y, 0), 0, - static_cast<int>(textureDesc.Height) - safeArea.y); + safeArea.x = gl::clamp(actualArea.x, 0, texSize.width); + safeArea.y = gl::clamp(actualArea.y, 0, texSize.height); + safeArea.width = + gl::clamp(actualArea.width + std::min(actualArea.x, 0), 0, texSize.width - safeArea.x); + safeArea.height = + gl::clamp(actualArea.height + std::min(actualArea.y, 0), 0, texSize.height - safeArea.y); ASSERT(safeArea.x >= 0 && safeArea.y >= 0); - ASSERT(safeArea.x + safeArea.width <= static_cast<int>(textureDesc.Width)); - ASSERT(safeArea.y + safeArea.height <= static_cast<int>(textureDesc.Height)); + ASSERT(safeArea.x + safeArea.width <= texSize.width); + ASSERT(safeArea.y + safeArea.height <= texSize.height); if (safeArea.width == 0 || safeArea.height == 0) { @@ -3146,35 +3535,29 @@ gl::Error Renderer11::readTextureData(ID3D11Texture2D *texture, unsigned int sub return gl::Error(GL_NO_ERROR); } - D3D11_TEXTURE2D_DESC stagingDesc; - stagingDesc.Width = safeArea.width; - stagingDesc.Height = safeArea.height; - stagingDesc.MipLevels = 1; - stagingDesc.ArraySize = 1; - stagingDesc.Format = textureDesc.Format; - stagingDesc.SampleDesc.Count = 1; - stagingDesc.SampleDesc.Quality = 0; - stagingDesc.Usage = D3D11_USAGE_STAGING; - stagingDesc.BindFlags = 0; - stagingDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; - stagingDesc.MiscFlags = 0; - - ID3D11Texture2D* stagingTex = NULL; - HRESULT result = mDevice->CreateTexture2D(&stagingDesc, NULL, &stagingTex); - if (FAILED(result)) + gl::Extents safeSize(safeArea.width, safeArea.height, 1); + auto errorOrResult = CreateStagingTexture(textureHelper.getTextureType(), + textureHelper.getFormat(), safeSize, mDevice); + if (errorOrResult.isError()) { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal staging texture for ReadPixels, HRESULT: 0x%X.", result); + return errorOrResult.getError(); } - ID3D11Texture2D* srcTex = NULL; - if (textureDesc.SampleDesc.Count > 1) + TextureHelper11 stagingHelper(errorOrResult.getResult()); + TextureHelper11 resolvedTextureHelper; + + // "srcTexture" usually points to the source texture. + // For 2D multisampled textures, it points to the multisampled resolve texture. + const TextureHelper11 *srcTexture = &textureHelper; + + if (textureHelper.getTextureType() == GL_TEXTURE_2D && textureHelper.getSampleCount() > 1) { D3D11_TEXTURE2D_DESC resolveDesc; - resolveDesc.Width = textureDesc.Width; - resolveDesc.Height = textureDesc.Height; + resolveDesc.Width = static_cast<UINT>(texSize.width); + resolveDesc.Height = static_cast<UINT>(texSize.height); resolveDesc.MipLevels = 1; resolveDesc.ArraySize = 1; - resolveDesc.Format = textureDesc.Format; + resolveDesc.Format = textureHelper.getFormat(); resolveDesc.SampleDesc.Count = 1; resolveDesc.SampleDesc.Quality = 0; resolveDesc.Usage = D3D11_USAGE_DEFAULT; @@ -3182,20 +3565,22 @@ gl::Error Renderer11::readTextureData(ID3D11Texture2D *texture, unsigned int sub resolveDesc.CPUAccessFlags = 0; resolveDesc.MiscFlags = 0; - result = mDevice->CreateTexture2D(&resolveDesc, NULL, &srcTex); + ID3D11Texture2D *resolveTex2D = nullptr; + HRESULT result = mDevice->CreateTexture2D(&resolveDesc, nullptr, &resolveTex2D); if (FAILED(result)) { - SafeRelease(stagingTex); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal resolve texture for ReadPixels, HRESULT: 0x%X.", result); + return gl::Error(GL_OUT_OF_MEMORY, + "Renderer11::readTextureData failed to create internal resolve " + "texture for ReadPixels, HRESULT: 0x%X.", + result); } - mDeviceContext->ResolveSubresource(srcTex, 0, texture, subResource, textureDesc.Format); - subResource = 0; - } - else - { - srcTex = texture; - srcTex->AddRef(); + mDeviceContext->ResolveSubresource(resolveTex2D, 0, textureHelper.getTexture2D(), + sourceSubResource, textureHelper.getFormat()); + resolvedTextureHelper = TextureHelper11::MakeAndReference(resolveTex2D); + + sourceSubResource = 0; + srcTexture = &resolvedTextureHelper; } D3D11_BOX srcBox; @@ -3203,28 +3588,52 @@ gl::Error Renderer11::readTextureData(ID3D11Texture2D *texture, unsigned int sub srcBox.right = static_cast<UINT>(safeArea.x + safeArea.width); srcBox.top = static_cast<UINT>(safeArea.y); srcBox.bottom = static_cast<UINT>(safeArea.y + safeArea.height); - srcBox.front = 0; - srcBox.back = 1; - mDeviceContext->CopySubresourceRegion(stagingTex, 0, 0, 0, 0, srcTex, subResource, &srcBox); + // Select the correct layer from a 3D attachment + srcBox.front = 0; + if (textureHelper.getTextureType() == GL_TEXTURE_3D) + { + srcBox.front = static_cast<UINT>(srcAttachment.layer()); + } + srcBox.back = srcBox.front + 1; - SafeRelease(srcTex); + mDeviceContext->CopySubresourceRegion(stagingHelper.getResource(), 0, 0, 0, 0, + srcTexture->getResource(), sourceSubResource, &srcBox); - PackPixelsParams packParams(safeArea, format, type, outputPitch, pack, 0); - gl::Error error = packPixels(stagingTex, packParams, pixels); + if (invertTexture) + { + gl::PixelPackState invertTexturePack; - SafeRelease(stagingTex); + // Create a new PixelPackState with reversed row order. Note that we can't just assign + // 'invertTexturePack' to be 'pack' (or memcpy) since that breaks the ref counting/object + // tracking in the 'pixelBuffer' members, causing leaks. Instead we must use + // pixelBuffer.set() twice, which performs the addRef/release correctly + invertTexturePack.alignment = pack.alignment; + invertTexturePack.pixelBuffer.set(pack.pixelBuffer.get()); + invertTexturePack.reverseRowOrder = !pack.reverseRowOrder; - return error; + PackPixelsParams packParams(safeArea, format, type, outputPitch, invertTexturePack, 0); + error = packPixels(stagingHelper, packParams, pixelsOut); + + invertTexturePack.pixelBuffer.set(nullptr); + + return error; + } + else + { + PackPixelsParams packParams(safeArea, format, type, outputPitch, pack, 0); + return packPixels(stagingHelper, packParams, pixelsOut); + } } -gl::Error Renderer11::packPixels(ID3D11Texture2D *readTexture, const PackPixelsParams ¶ms, uint8_t *pixelsOut) +gl::Error Renderer11::packPixels(const TextureHelper11 &textureHelper, + const PackPixelsParams ¶ms, + uint8_t *pixelsOut) { - D3D11_TEXTURE2D_DESC textureDesc; - readTexture->GetDesc(&textureDesc); + ID3D11Resource *readResource = textureHelper.getResource(); D3D11_MAPPED_SUBRESOURCE mapping; - HRESULT hr = mDeviceContext->Map(readTexture, 0, D3D11_MAP_READ, 0, &mapping); + HRESULT hr = mDeviceContext->Map(readResource, 0, D3D11_MAP_READ, 0, &mapping); if (FAILED(hr)) { ASSERT(hr == E_OUTOFMEMORY); @@ -3244,7 +3653,7 @@ gl::Error Renderer11::packPixels(ID3D11Texture2D *readTexture, const PackPixelsP inputPitch = static_cast<int>(mapping.RowPitch); } - const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(textureDesc.Format); + const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(textureHelper.getFormat()); const gl::InternalFormat &sourceFormatInfo = gl::GetInternalFormatInfo(dxgiFormatInfo.internalFormat); if (sourceFormatInfo.format == params.format && sourceFormatInfo.type == params.type) { @@ -3256,9 +3665,8 @@ gl::Error Renderer11::packPixels(ID3D11Texture2D *readTexture, const PackPixelsP } else { - const d3d11::DXGIFormat &sourceDXGIFormatInfo = d3d11::GetDXGIFormatInfo(textureDesc.Format); - ColorCopyFunction fastCopyFunc = sourceDXGIFormatInfo.getFastCopyFunction(params.format, params.type); - + ColorCopyFunction fastCopyFunc = + dxgiFormatInfo.getFastCopyFunction(params.format, params.type); GLenum sizedDestInternalFormat = gl::GetSizedInternalFormat(params.format, params.type); const gl::InternalFormat &destFormatInfo = gl::GetInternalFormatInfo(sizedDestInternalFormat); @@ -3278,7 +3686,7 @@ gl::Error Renderer11::packPixels(ID3D11Texture2D *readTexture, const PackPixelsP } else { - ColorReadFunction colorReadFunction = sourceDXGIFormatInfo.colorReadFunction; + ColorReadFunction colorReadFunction = dxgiFormatInfo.colorReadFunction; ColorWriteFunction colorWriteFunction = GetColorWriteFunction(params.format, params.type); uint8_t temp[16]; // Maximum size of any Color<T> type used. @@ -3303,21 +3711,27 @@ gl::Error Renderer11::packPixels(ID3D11Texture2D *readTexture, const PackPixelsP } } - mDeviceContext->Unmap(readTexture, 0); + mDeviceContext->Unmap(readResource, 0); return gl::Error(GL_NO_ERROR); } -gl::Error Renderer11::blitRenderbufferRect(const gl::Rectangle &readRect, const gl::Rectangle &drawRect, RenderTargetD3D *readRenderTarget, - RenderTargetD3D *drawRenderTarget, GLenum filter, const gl::Rectangle *scissor, - bool colorBlit, bool depthBlit, bool stencilBlit) +gl::Error Renderer11::blitRenderbufferRect(const gl::Rectangle &readRectIn, + const gl::Rectangle &drawRectIn, + RenderTargetD3D *readRenderTarget, + RenderTargetD3D *drawRenderTarget, + GLenum filter, + const gl::Rectangle *scissor, + bool colorBlit, + bool depthBlit, + bool stencilBlit) { // Since blitRenderbufferRect is called for each render buffer that needs to be blitted, // it should never be the case that both color and depth/stencil need to be blitted at // at the same time. ASSERT(colorBlit != (depthBlit || stencilBlit)); - RenderTarget11 *drawRenderTarget11 = RenderTarget11::makeRenderTarget11(drawRenderTarget); + RenderTarget11 *drawRenderTarget11 = GetAs<RenderTarget11>(drawRenderTarget); if (!drawRenderTarget) { return gl::Error(GL_OUT_OF_MEMORY, "Failed to retrieve the internal draw render target from the draw framebuffer."); @@ -3328,7 +3742,7 @@ gl::Error Renderer11::blitRenderbufferRect(const gl::Rectangle &readRect, const ID3D11RenderTargetView *drawRTV = drawRenderTarget11->getRenderTargetView(); ID3D11DepthStencilView *drawDSV = drawRenderTarget11->getDepthStencilView(); - RenderTarget11 *readRenderTarget11 = RenderTarget11::makeRenderTarget11(readRenderTarget); + RenderTarget11 *readRenderTarget11 = GetAs<RenderTarget11>(readRenderTarget); if (!readRenderTarget) { return gl::Error(GL_OUT_OF_MEMORY, "Failed to retrieve the internal read render target from the read framebuffer."); @@ -3376,13 +3790,94 @@ gl::Error Renderer11::blitRenderbufferRect(const gl::Rectangle &readRect, const gl::Extents readSize(readRenderTarget->getWidth(), readRenderTarget->getHeight(), 1); gl::Extents drawSize(drawRenderTarget->getWidth(), drawRenderTarget->getHeight(), 1); + // From the spec: + // "The actual region taken from the read framebuffer is limited to the intersection of the + // source buffers being transferred, which may include the color buffer selected by the read + // buffer, the depth buffer, and / or the stencil buffer depending on mask." + // This means negative x and y are out of bounds, and not to be read from. We handle this here + // by internally scaling the read and draw rectangles. + gl::Rectangle readRect = readRectIn; + gl::Rectangle drawRect = drawRectIn; + auto readToDrawX = [&drawRectIn, &readRectIn](int readOffset) + { + double readToDrawScale = + static_cast<double>(drawRectIn.width) / static_cast<double>(readRectIn.width); + return static_cast<int>(round(static_cast<double>(readOffset) * readToDrawScale)); + }; + if (readRect.x < 0) + { + int readOffset = -readRect.x; + readRect.x += readOffset; + readRect.width -= readOffset; + + int drawOffset = readToDrawX(readOffset); + drawRect.x += drawOffset; + drawRect.width -= drawOffset; + } + + auto readToDrawY = [&drawRectIn, &readRectIn](int readOffset) + { + double readToDrawScale = + static_cast<double>(drawRectIn.height) / static_cast<double>(readRectIn.height); + return static_cast<int>(round(static_cast<double>(readOffset) * readToDrawScale)); + }; + if (readRect.y < 0) + { + int readOffset = -readRect.y; + readRect.y += readOffset; + readRect.height -= readOffset; + + int drawOffset = readToDrawY(readOffset); + drawRect.y += drawOffset; + drawRect.height -= drawOffset; + } + + if (readRect.x1() < 0) + { + int readOffset = -readRect.x1(); + readRect.width += readOffset; + + int drawOffset = readToDrawX(readOffset); + drawRect.width += drawOffset; + } + + if (readRect.y1() < 0) + { + int readOffset = -readRect.y1(); + readRect.height += readOffset; + + int drawOffset = readToDrawY(readOffset); + drawRect.height += drawOffset; + } + bool scissorNeeded = scissor && gl::ClipRectangle(drawRect, *scissor, NULL); - bool wholeBufferCopy = !scissorNeeded && - readRect.x == 0 && readRect.width == readSize.width && - readRect.y == 0 && readRect.height == readSize.height && - drawRect.x == 0 && drawRect.width == drawSize.width && - drawRect.y == 0 && drawRect.height == drawSize.height; + const auto &destFormatInfo = gl::GetInternalFormatInfo(drawRenderTarget->getInternalFormat()); + const auto &srcFormatInfo = gl::GetInternalFormatInfo(readRenderTarget->getInternalFormat()); + const auto &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(drawRenderTarget11->getDXGIFormat()); + + // Some blits require masking off emulated texture channels. eg: from RGBA8 to RGB8, we + // emulate RGB8 with RGBA8, so we need to mask off the alpha channel when we copy. + + gl::Color<bool> colorMask; + colorMask.red = (srcFormatInfo.redBits > 0) && (destFormatInfo.redBits == 0) && + (dxgiFormatInfo.redBits > 0); + colorMask.green = (srcFormatInfo.greenBits > 0) && (destFormatInfo.greenBits == 0) && + (dxgiFormatInfo.greenBits > 0); + colorMask.blue = (srcFormatInfo.blueBits > 0) && (destFormatInfo.blueBits == 0) && + (dxgiFormatInfo.blueBits > 0); + colorMask.alpha = (srcFormatInfo.alphaBits > 0) && (destFormatInfo.alphaBits == 0) && + (dxgiFormatInfo.alphaBits > 0); + + // We only currently support masking off the alpha channel. + bool colorMaskingNeeded = colorMask.alpha; + ASSERT(!colorMask.red && !colorMask.green && !colorMask.blue); + + bool wholeBufferCopy = !scissorNeeded && !colorMaskingNeeded && readRect.x == 0 && + readRect.width == readSize.width && readRect.y == 0 && + readRect.height == readSize.height && drawRect.x == 0 && + drawRect.width == drawSize.width && drawRect.y == 0 && + drawRect.height == drawSize.height; bool stretchRequired = readRect.width != drawRect.width || readRect.height != drawRect.height; @@ -3393,14 +3888,13 @@ gl::Error Renderer11::blitRenderbufferRect(const gl::Rectangle &readRect, const drawRect.x < 0 || drawRect.x + drawRect.width > drawSize.width || drawRect.y < 0 || drawRect.y + drawRect.height > drawSize.height; - const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(drawRenderTarget11->getDXGIFormat()); bool partialDSBlit = (dxgiFormatInfo.depthBits > 0 && depthBlit) != (dxgiFormatInfo.stencilBits > 0 && stencilBlit); gl::Error result(GL_NO_ERROR); if (readRenderTarget11->getDXGIFormat() == drawRenderTarget11->getDXGIFormat() && !stretchRequired && !outOfBounds && !flipRequired && !partialDSBlit && - (!(depthBlit || stencilBlit) || wholeBufferCopy)) + !colorMaskingNeeded && (!(depthBlit || stencilBlit) || wholeBufferCopy)) { UINT dstX = drawRect.x; UINT dstY = drawRect.y; @@ -3470,9 +3964,10 @@ gl::Error Renderer11::blitRenderbufferRect(const gl::Rectangle &readRect, const } else { - GLenum format = gl::GetInternalFormatInfo(drawRenderTarget->getInternalFormat()).format; + // We don't currently support masking off any other channel than alpha + bool maskOffAlpha = colorMaskingNeeded && colorMask.alpha; result = mBlit->copyTexture(readSRV, readArea, readSize, drawRTV, drawArea, drawSize, - scissor, format, filter); + scissor, destFormatInfo.format, filter, maskOffAlpha); } } @@ -3484,9 +3979,44 @@ gl::Error Renderer11::blitRenderbufferRect(const gl::Rectangle &readRect, const bool Renderer11::isES3Capable() const { - return (d3d11_gl::GetMaximumClientVersion(mFeatureLevel) > 2); + return (d3d11_gl::GetMaximumClientVersion(mRenderer11DeviceCaps.featureLevel) > 2); }; +void Renderer11::onSwap() +{ + // Send histogram updates every half hour + const double kHistogramUpdateInterval = 30 * 60; + + const double currentTime = ANGLEPlatformCurrent()->monotonicallyIncreasingTime(); + const double timeSinceLastUpdate = currentTime - mLastHistogramUpdateTime; + + if (timeSinceLastUpdate > kHistogramUpdateInterval) + { + updateHistograms(); + mLastHistogramUpdateTime = currentTime; + } +} + +void Renderer11::updateHistograms() +{ + // Update the buffer CPU memory histogram + { + size_t sizeSum = 0; + for (auto &buffer : mAliveBuffers) + { + sizeSum += buffer->getTotalCPUBufferMemoryBytes(); + } + const int kOneMegaByte = 1024 * 1024; + ANGLE_HISTOGRAM_MEMORY_MB("GPU.ANGLE.Buffer11CPUMemoryMB", + static_cast<int>(sizeSum) / kOneMegaByte); + } +} + +void Renderer11::onBufferDelete(const Buffer11 *deleted) +{ + mAliveBuffers.erase(deleted); +} + ID3D11Texture2D *Renderer11::resolveMultisampledTexture(ID3D11Texture2D *source, unsigned int subresource) { D3D11_TEXTURE2D_DESC textureDesc; @@ -3545,54 +4075,64 @@ bool Renderer11::getLUID(LUID *adapterLuid) const return true; } -VertexConversionType Renderer11::getVertexConversionType(const gl::VertexFormat &vertexFormat) const +VertexConversionType Renderer11::getVertexConversionType(gl::VertexFormatType vertexFormatType) const { - return d3d11::GetVertexFormatInfo(vertexFormat, mFeatureLevel).conversionType; + return d3d11::GetVertexFormatInfo(vertexFormatType, mRenderer11DeviceCaps.featureLevel).conversionType; } -GLenum Renderer11::getVertexComponentType(const gl::VertexFormat &vertexFormat) const +GLenum Renderer11::getVertexComponentType(gl::VertexFormatType vertexFormatType) const { - return d3d11::GetDXGIFormatInfo(d3d11::GetVertexFormatInfo(vertexFormat, mFeatureLevel).nativeFormat).componentType; + return d3d11::GetDXGIFormatInfo(d3d11::GetVertexFormatInfo(vertexFormatType, mRenderer11DeviceCaps.featureLevel).nativeFormat).componentType; } -void Renderer11::generateCaps(gl::Caps *outCaps, gl::TextureCapsMap *outTextureCaps, gl::Extensions *outExtensions) const +void Renderer11::generateCaps(gl::Caps *outCaps, gl::TextureCapsMap *outTextureCaps, + gl::Extensions *outExtensions, gl::Limitations *outLimitations) const { - d3d11_gl::GenerateCaps(mDevice, mDeviceContext, outCaps, outTextureCaps, outExtensions); + d3d11_gl::GenerateCaps(mDevice, mDeviceContext, mRenderer11DeviceCaps, outCaps, outTextureCaps, + outExtensions, outLimitations); } -Workarounds Renderer11::generateWorkarounds() const +WorkaroundsD3D Renderer11::generateWorkarounds() const { - return d3d11::GenerateWorkarounds(mFeatureLevel); + return d3d11::GenerateWorkarounds(mRenderer11DeviceCaps.featureLevel); } -void Renderer11::setShaderResource(gl::SamplerType shaderType, UINT resourceSlot, ID3D11ShaderResourceView *srv) +void Renderer11::createAnnotator() { - auto ¤tSRVs = (shaderType == gl::SAMPLER_VERTEX ? mCurVertexSRVs : mCurPixelSRVs); + // The D3D11 renderer must choose the D3D9 debug annotator because the D3D11 interface + // method ID3DUserDefinedAnnotation::GetStatus on desktop builds doesn't work with the Graphics + // Diagnostics tools in Visual Studio 2013. + // The D3D9 annotator works properly for both D3D11 and D3D9. + // Incorrect status reporting can cause ANGLE to log unnecessary debug events. +#ifdef ANGLE_ENABLE_D3D9 + mAnnotator = new DebugAnnotator9(); +#else + mAnnotator = new DebugAnnotator11(); +#endif +} - ASSERT(static_cast<size_t>(resourceSlot) < currentSRVs.size()); - auto &record = currentSRVs[resourceSlot]; +gl::Error Renderer11::clearTextures(gl::SamplerType samplerType, size_t rangeStart, size_t rangeEnd) +{ + return mStateManager.clearTextures(samplerType, rangeStart, rangeEnd); +} - if (record.srv != reinterpret_cast<uintptr_t>(srv)) +egl::Error Renderer11::getEGLDevice(DeviceImpl **device) +{ + if (mEGLDevice == nullptr) { - if (shaderType == gl::SAMPLER_VERTEX) - { - mDeviceContext->VSSetShaderResources(resourceSlot, 1, &srv); - } - else - { - mDeviceContext->PSSetShaderResources(resourceSlot, 1, &srv); - } + ASSERT(mDevice != nullptr); + mEGLDevice = new DeviceD3D(); + egl::Error error = mEGLDevice->initialize(reinterpret_cast<void *>(mDevice), + EGL_D3D11_DEVICE_ANGLE, EGL_FALSE); - record.srv = reinterpret_cast<uintptr_t>(srv); - if (srv) - { - record.resource = reinterpret_cast<uintptr_t>(GetViewResource(srv)); - srv->GetDesc(&record.desc); - } - else + if (error.isError()) { - record.resource = 0; + SafeDelete(mEGLDevice); + return error; } } + + *device = static_cast<DeviceImpl *>(mEGLDevice); + return egl::Error(EGL_SUCCESS); } } |