From a218a252c4200cfe7048de81a46f7e48349084d5 Mon Sep 17 00:00:00 2001 From: Andrew Knight Date: Wed, 8 Apr 2015 17:04:36 +0300 Subject: Upgrade ANGLE to 2.1~99f075dade7c This aligns with Chromium branch 2356. This version brings more complete OpenGL ES 3 support as well as various bug fixes and performance improvements. The following changes were made to earlier patches: -0000-General-fixes-for-ANGLE-2.1 Removed. All changes are now handled elsewhere. +0001-ANGLE-Improve-Windows-Phone-support Consolidated remaining parts from 0009/0010. +0002-ANGLE-Fix-compilation-with-MinGW Remaining issues from patch 0016. +0003-ANGLE-Fix-compilation-with-MSVC2010 Remaining issues from patch 0015. +0004-ANGLE-Dynamically-load-D3D-compiler-from-list Renamed from patch 0008. +0005-ANGLE-Add-support-for-querying-platform-device Renamed from patch 0013. -0004-Make-it-possible-to-link-ANGLE-statically-for-single Removed. Fixed by adding defines to project files. -0008-ANGLE-Dynamically-load-D3D-compiler-from-a-list-or-t Renamed to patch 0005. -0009-ANGLE-Support-WinRT Removed. Mostly fixed upstream; remaining parts in patch 0001. -0010-ANGLE-Enable-D3D11-for-feature-level-9-cards Removed. Mostly fixed upstream; remaining parts in patch 0001. -0012-ANGLE-fix-semantic-index-lookup Removed. Fixed upstream. -0013-ANGLE-Add-support-for-querying-platform-device Renamed to patch 0005. -0014-Let-ANGLE-use-multithreaded-devices-if-necessary Removed. No longer needed. -0015-ANGLE-Fix-angle-d3d11-on-MSVC2010 Moved remaining parts to patch 0003. -0016-ANGLE-Fix-compilation-with-MinGW-D3D11 Moved remaining parts to patch 0002. -0017-ANGLE-Fix-compilation-with-D3D9 Removed. Fixed upstream. -0018-ANGLE-Fix-releasing-textures-after-we-kill-D3D11 Removed. Fixed upstream. -0019-ANGLE-Fix-handling-of-shader-source-with-fixed-lengt Removed. Fixed upstream. -0020-ANGLE-Do-not-use-std-strlen Removed. Fixed upstream. -0020-ANGLE-Fix-compilation-with-MSVC2013-Update4 Removed. Fixed upstream. [ChangeLog][Third-party libraries] ANGLE was updated to Chromium branch 2356 (2.1~99f075dade7c). Change-Id: I32ccbfe95e10986bd94be7191dfd53445ea09158 Task-number: QTBUG-44815 Task-number: QTBUG-37660 Task-number: QTBUG-44694 Task-number: QTBUG-42443 Reviewed-by: Andrew Knight Reviewed-by: Friedemann Kleint --- src/3rdparty/angle/src/libANGLE/AttributeMap.cpp | 53 + src/3rdparty/angle/src/libANGLE/AttributeMap.h | 39 + src/3rdparty/angle/src/libANGLE/BinaryStream.h | 218 ++ src/3rdparty/angle/src/libANGLE/Buffer.cpp | 121 + src/3rdparty/angle/src/libANGLE/Buffer.h | 70 + src/3rdparty/angle/src/libANGLE/Caps.cpp | 527 +++ src/3rdparty/angle/src/libANGLE/Caps.h | 374 ++ src/3rdparty/angle/src/libANGLE/Compiler.cpp | 38 + src/3rdparty/angle/src/libANGLE/Compiler.h | 39 + src/3rdparty/angle/src/libANGLE/Config.cpp | 275 ++ src/3rdparty/angle/src/libANGLE/Config.h | 91 + src/3rdparty/angle/src/libANGLE/Constants.h | 44 + src/3rdparty/angle/src/libANGLE/Context.cpp | 1587 +++++++++ src/3rdparty/angle/src/libANGLE/Context.h | 277 ++ src/3rdparty/angle/src/libANGLE/Data.cpp | 51 + src/3rdparty/angle/src/libANGLE/Data.h | 38 + src/3rdparty/angle/src/libANGLE/Display.cpp | 675 ++++ src/3rdparty/angle/src/libANGLE/Display.h | 124 + src/3rdparty/angle/src/libANGLE/Error.cpp | 86 + src/3rdparty/angle/src/libANGLE/Error.h | 83 + src/3rdparty/angle/src/libANGLE/Error.inl | 163 + src/3rdparty/angle/src/libANGLE/Fence.cpp | 117 + src/3rdparty/angle/src/libANGLE/Fence.h | 71 + .../angle/src/libANGLE/Float16ToFloat32.cpp | 2203 ++++++++++++ src/3rdparty/angle/src/libANGLE/Framebuffer.cpp | 658 ++++ src/3rdparty/angle/src/libANGLE/Framebuffer.h | 144 + .../angle/src/libANGLE/FramebufferAttachment.cpp | 302 ++ .../angle/src/libANGLE/FramebufferAttachment.h | 154 + .../angle/src/libANGLE/HandleAllocator.cpp | 133 + src/3rdparty/angle/src/libANGLE/HandleAllocator.h | 63 + src/3rdparty/angle/src/libANGLE/ImageIndex.cpp | 170 + src/3rdparty/angle/src/libANGLE/ImageIndex.h | 79 + src/3rdparty/angle/src/libANGLE/Platform.cpp | 35 + src/3rdparty/angle/src/libANGLE/Program.cpp | 1617 +++++++++ src/3rdparty/angle/src/libANGLE/Program.h | 276 ++ src/3rdparty/angle/src/libANGLE/Query.cpp | 50 + src/3rdparty/angle/src/libANGLE/Query.h | 47 + src/3rdparty/angle/src/libANGLE/RefCountObject.cpp | 39 + src/3rdparty/angle/src/libANGLE/RefCountObject.h | 110 + src/3rdparty/angle/src/libANGLE/Renderbuffer.cpp | 130 + src/3rdparty/angle/src/libANGLE/Renderbuffer.h | 69 + .../angle/src/libANGLE/ResourceManager.cpp | 456 +++ src/3rdparty/angle/src/libANGLE/ResourceManager.h | 114 + src/3rdparty/angle/src/libANGLE/Sampler.cpp | 43 + src/3rdparty/angle/src/libANGLE/Sampler.h | 60 + src/3rdparty/angle/src/libANGLE/Shader.cpp | 243 ++ src/3rdparty/angle/src/libANGLE/Shader.h | 118 + src/3rdparty/angle/src/libANGLE/State.cpp | 1470 ++++++++ src/3rdparty/angle/src/libANGLE/State.h | 335 ++ src/3rdparty/angle/src/libANGLE/Surface.cpp | 166 + src/3rdparty/angle/src/libANGLE/Surface.h | 98 + src/3rdparty/angle/src/libANGLE/Texture.cpp | 573 ++++ src/3rdparty/angle/src/libANGLE/Texture.h | 156 + .../angle/src/libANGLE/TransformFeedback.cpp | 71 + .../angle/src/libANGLE/TransformFeedback.h | 50 + src/3rdparty/angle/src/libANGLE/Uniform.cpp | 107 + src/3rdparty/angle/src/libANGLE/Uniform.h | 77 + src/3rdparty/angle/src/libANGLE/VertexArray.cpp | 101 + src/3rdparty/angle/src/libANGLE/VertexArray.h | 66 + .../angle/src/libANGLE/VertexAttribute.cpp | 73 + src/3rdparty/angle/src/libANGLE/VertexAttribute.h | 122 + src/3rdparty/angle/src/libANGLE/angletypes.cpp | 246 ++ src/3rdparty/angle/src/libANGLE/angletypes.h | 323 ++ src/3rdparty/angle/src/libANGLE/features.h | 40 + src/3rdparty/angle/src/libANGLE/formatutils.cpp | 650 ++++ src/3rdparty/angle/src/libANGLE/formatutils.h | 81 + .../angle/src/libANGLE/queryconversions.cpp | 147 + src/3rdparty/angle/src/libANGLE/queryconversions.h | 17 + .../angle/src/libANGLE/renderer/BufferImpl.h | 38 + .../angle/src/libANGLE/renderer/CompilerImpl.h | 30 + .../angle/src/libANGLE/renderer/DisplayImpl.cpp | 58 + .../angle/src/libANGLE/renderer/DisplayImpl.h | 99 + .../angle/src/libANGLE/renderer/FenceNVImpl.h | 34 + .../angle/src/libANGLE/renderer/FenceSyncImpl.h | 35 + .../angle/src/libANGLE/renderer/FramebufferImpl.h | 68 + src/3rdparty/angle/src/libANGLE/renderer/Image.h | 77 + .../angle/src/libANGLE/renderer/ImplFactory.h | 68 + .../src/libANGLE/renderer/IndexRangeCache.cpp | 114 + .../angle/src/libANGLE/renderer/IndexRangeCache.h | 53 + .../angle/src/libANGLE/renderer/ProgramImpl.cpp | 152 + .../angle/src/libANGLE/renderer/ProgramImpl.h | 137 + .../angle/src/libANGLE/renderer/QueryImpl.h | 40 + .../src/libANGLE/renderer/RenderbufferImpl.cpp | 21 + .../angle/src/libANGLE/renderer/RenderbufferImpl.h | 33 + .../angle/src/libANGLE/renderer/Renderer.cpp | 72 + .../angle/src/libANGLE/renderer/Renderer.h | 91 + .../angle/src/libANGLE/renderer/ShaderImpl.h | 57 + .../angle/src/libANGLE/renderer/SurfaceImpl.cpp | 22 + .../angle/src/libANGLE/renderer/SurfaceImpl.h | 48 + .../angle/src/libANGLE/renderer/TextureImpl.h | 72 + .../src/libANGLE/renderer/TransformFeedbackImpl.h | 31 + .../angle/src/libANGLE/renderer/VertexArrayImpl.h | 32 + .../angle/src/libANGLE/renderer/Workarounds.h | 74 + .../angle/src/libANGLE/renderer/d3d/BufferD3D.cpp | 80 + .../angle/src/libANGLE/renderer/d3d/BufferD3D.h | 56 + .../src/libANGLE/renderer/d3d/CompilerD3D.cpp | 128 + .../angle/src/libANGLE/renderer/d3d/CompilerD3D.h | 48 + .../angle/src/libANGLE/renderer/d3d/DisplayD3D.cpp | 357 ++ .../angle/src/libANGLE/renderer/d3d/DisplayD3D.h | 61 + .../src/libANGLE/renderer/d3d/DynamicHLSL.cpp | 1265 +++++++ .../angle/src/libANGLE/renderer/d3d/DynamicHLSL.h | 99 + .../src/libANGLE/renderer/d3d/FramebufferD3D.cpp | 463 +++ .../src/libANGLE/renderer/d3d/FramebufferD3D.h | 111 + .../src/libANGLE/renderer/d3d/HLSLCompiler.cpp | 340 ++ .../angle/src/libANGLE/renderer/d3d/HLSLCompiler.h | 54 + .../angle/src/libANGLE/renderer/d3d/ImageD3D.cpp | 47 + .../angle/src/libANGLE/renderer/d3d/ImageD3D.h | 84 + .../src/libANGLE/renderer/d3d/IndexBuffer.cpp | 196 ++ .../angle/src/libANGLE/renderer/d3d/IndexBuffer.h | 101 + .../src/libANGLE/renderer/d3d/IndexDataManager.cpp | 267 ++ .../src/libANGLE/renderer/d3d/IndexDataManager.h | 70 + .../angle/src/libANGLE/renderer/d3d/ProgramD3D.cpp | 2005 +++++++++++ .../angle/src/libANGLE/renderer/d3d/ProgramD3D.h | 244 ++ .../src/libANGLE/renderer/d3d/RenderTargetD3D.cpp | 36 + .../src/libANGLE/renderer/d3d/RenderTargetD3D.h | 42 + .../src/libANGLE/renderer/d3d/RenderbufferD3D.cpp | 73 + .../src/libANGLE/renderer/d3d/RenderbufferD3D.h | 43 + .../src/libANGLE/renderer/d3d/RendererD3D.cpp | 628 ++++ .../angle/src/libANGLE/renderer/d3d/RendererD3D.h | 241 ++ .../angle/src/libANGLE/renderer/d3d/ShaderD3D.cpp | 388 +++ .../angle/src/libANGLE/renderer/d3d/ShaderD3D.h | 89 + .../libANGLE/renderer/d3d/ShaderExecutableD3D.cpp | 61 + .../libANGLE/renderer/d3d/ShaderExecutableD3D.h | 54 + .../angle/src/libANGLE/renderer/d3d/SurfaceD3D.cpp | 396 +++ .../angle/src/libANGLE/renderer/d3d/SurfaceD3D.h | 92 + .../angle/src/libANGLE/renderer/d3d/SwapChainD3D.h | 63 + .../angle/src/libANGLE/renderer/d3d/TextureD3D.cpp | 2916 ++++++++++++++++ .../angle/src/libANGLE/renderer/d3d/TextureD3D.h | 364 ++ .../src/libANGLE/renderer/d3d/TextureStorage.cpp | 39 + .../src/libANGLE/renderer/d3d/TextureStorage.h | 67 + .../libANGLE/renderer/d3d/TransformFeedbackD3D.cpp | 38 + .../libANGLE/renderer/d3d/TransformFeedbackD3D.h | 32 + .../src/libANGLE/renderer/d3d/VertexBuffer.cpp | 311 ++ .../angle/src/libANGLE/renderer/d3d/VertexBuffer.h | 143 + .../libANGLE/renderer/d3d/VertexDataManager.cpp | 396 +++ .../src/libANGLE/renderer/d3d/VertexDataManager.h | 95 + .../angle/src/libANGLE/renderer/d3d/copyimage.cpp | 22 + .../angle/src/libANGLE/renderer/d3d/copyimage.h | 35 + .../angle/src/libANGLE/renderer/d3d/copyimage.inl | 32 + .../src/libANGLE/renderer/d3d/d3d11/Blit11.cpp | 1059 ++++++ .../angle/src/libANGLE/renderer/d3d/d3d11/Blit11.h | 121 + .../src/libANGLE/renderer/d3d/d3d11/Buffer11.cpp | 1070 ++++++ .../src/libANGLE/renderer/d3d/d3d11/Buffer11.h | 103 + .../src/libANGLE/renderer/d3d/d3d11/Clear11.cpp | 614 ++++ .../src/libANGLE/renderer/d3d/d3d11/Clear11.h | 86 + .../renderer/d3d/d3d11/DebugAnnotator11.cpp | 119 + .../libANGLE/renderer/d3d/d3d11/DebugAnnotator11.h | 39 + .../src/libANGLE/renderer/d3d/d3d11/Fence11.cpp | 231 ++ .../src/libANGLE/renderer/d3d/d3d11/Fence11.h | 59 + .../libANGLE/renderer/d3d/d3d11/Framebuffer11.cpp | 270 ++ .../libANGLE/renderer/d3d/d3d11/Framebuffer11.h | 45 + .../src/libANGLE/renderer/d3d/d3d11/Image11.cpp | 664 ++++ .../src/libANGLE/renderer/d3d/d3d11/Image11.h | 84 + .../libANGLE/renderer/d3d/d3d11/IndexBuffer11.cpp | 162 + .../libANGLE/renderer/d3d/d3d11/IndexBuffer11.h | 51 + .../renderer/d3d/d3d11/InputLayoutCache.cpp | 430 +++ .../libANGLE/renderer/d3d/d3d11/InputLayoutCache.h | 103 + .../src/libANGLE/renderer/d3d/d3d11/NativeWindow.h | 80 + .../renderer/d3d/d3d11/PixelTransfer11.cpp | 302 ++ .../libANGLE/renderer/d3d/d3d11/PixelTransfer11.h | 89 + .../src/libANGLE/renderer/d3d/d3d11/Query11.cpp | 164 + .../src/libANGLE/renderer/d3d/d3d11/Query11.h | 42 + .../renderer/d3d/d3d11/RenderStateCache.cpp | 452 +++ .../libANGLE/renderer/d3d/d3d11/RenderStateCache.h | 111 + .../libANGLE/renderer/d3d/d3d11/RenderTarget11.cpp | 394 +++ .../libANGLE/renderer/d3d/d3d11/RenderTarget11.h | 110 + .../src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp | 3585 ++++++++++++++++++++ .../src/libANGLE/renderer/d3d/d3d11/Renderer11.h | 400 +++ .../renderer/d3d/d3d11/ShaderExecutable11.cpp | 110 + .../renderer/d3d/d3d11/ShaderExecutable11.h | 59 + .../libANGLE/renderer/d3d/d3d11/SwapChain11.cpp | 711 ++++ .../src/libANGLE/renderer/d3d/d3d11/SwapChain11.h | 87 + .../renderer/d3d/d3d11/TextureStorage11.cpp | 2676 +++++++++++++++ .../libANGLE/renderer/d3d/d3d11/TextureStorage11.h | 326 ++ .../src/libANGLE/renderer/d3d/d3d11/Trim11.cpp | 95 + .../angle/src/libANGLE/renderer/d3d/d3d11/Trim11.h | 43 + .../libANGLE/renderer/d3d/d3d11/VertexArray11.h | 40 + .../libANGLE/renderer/d3d/d3d11/VertexBuffer11.cpp | 244 ++ .../libANGLE/renderer/d3d/d3d11/VertexBuffer11.h | 58 + .../src/libANGLE/renderer/d3d/d3d11/copyvertex.h | 40 + .../src/libANGLE/renderer/d3d/d3d11/copyvertex.inl | 377 ++ .../libANGLE/renderer/d3d/d3d11/formatutils11.cpp | 1328 ++++++++ .../libANGLE/renderer/d3d/d3d11/formatutils11.h | 93 + .../renderer/d3d/d3d11/renderer11_utils.cpp | 1378 ++++++++ .../libANGLE/renderer/d3d/d3d11/renderer11_utils.h | 190 ++ .../d3d/d3d11/shaders/BufferToTexture11.hlsl | 77 + .../renderer/d3d/d3d11/shaders/Clear11.hlsl | 119 + .../d3d/d3d11/shaders/Passthrough2D11.hlsl | 111 + .../d3d/d3d11/shaders/Passthrough3D11.hlsl | 146 + .../renderer/d3d/d3d11/shaders/Swizzle11.hlsl | 99 + .../renderer/d3d/d3d11/win32/NativeWindow.cpp | 68 + .../d3d/d3d11/winrt/CoreWindowNativeWindow.cpp | 214 ++ .../d3d/d3d11/winrt/CoreWindowNativeWindow.h | 110 + .../d3d/d3d11/winrt/InspectableNativeWindow.cpp | 291 ++ .../d3d/d3d11/winrt/InspectableNativeWindow.h | 105 + .../d3d/d3d11/winrt/SwapChainPanelNativeWindow.cpp | 228 ++ .../d3d/d3d11/winrt/SwapChainPanelNativeWindow.h | 79 + .../angle/src/libANGLE/renderer/d3d/d3d9/Blit9.cpp | 679 ++++ .../angle/src/libANGLE/renderer/d3d/d3d9/Blit9.h | 97 + .../src/libANGLE/renderer/d3d/d3d9/Buffer9.cpp | 116 + .../angle/src/libANGLE/renderer/d3d/d3d9/Buffer9.h | 49 + .../libANGLE/renderer/d3d/d3d9/DebugAnnotator9.cpp | 36 + .../libANGLE/renderer/d3d/d3d9/DebugAnnotator9.h | 29 + .../src/libANGLE/renderer/d3d/d3d9/Fence9.cpp | 90 + .../angle/src/libANGLE/renderer/d3d/d3d9/Fence9.h | 36 + .../libANGLE/renderer/d3d/d3d9/Framebuffer9.cpp | 422 +++ .../src/libANGLE/renderer/d3d/d3d9/Framebuffer9.h | 41 + .../src/libANGLE/renderer/d3d/d3d9/Image9.cpp | 788 +++++ .../angle/src/libANGLE/renderer/d3d/d3d9/Image9.h | 73 + .../libANGLE/renderer/d3d/d3d9/IndexBuffer9.cpp | 173 + .../src/libANGLE/renderer/d3d/d3d9/IndexBuffer9.h | 51 + .../src/libANGLE/renderer/d3d/d3d9/Query9.cpp | 144 + .../angle/src/libANGLE/renderer/d3d/d3d9/Query9.h | 41 + .../libANGLE/renderer/d3d/d3d9/RenderTarget9.cpp | 139 + .../src/libANGLE/renderer/d3d/d3d9/RenderTarget9.h | 84 + .../src/libANGLE/renderer/d3d/d3d9/Renderer9.cpp | 2933 ++++++++++++++++ .../src/libANGLE/renderer/d3d/d3d9/Renderer9.h | 377 ++ .../src/libANGLE/renderer/d3d/d3d9/ShaderCache.h | 108 + .../renderer/d3d/d3d9/ShaderExecutable9.cpp | 53 + .../libANGLE/renderer/d3d/d3d9/ShaderExecutable9.h | 37 + .../src/libANGLE/renderer/d3d/d3d9/SwapChain9.cpp | 425 +++ .../src/libANGLE/renderer/d3d/d3d9/SwapChain9.h | 63 + .../libANGLE/renderer/d3d/d3d9/TextureStorage9.cpp | 472 +++ .../libANGLE/renderer/d3d/d3d9/TextureStorage9.h | 108 + .../src/libANGLE/renderer/d3d/d3d9/VertexArray9.h | 41 + .../libANGLE/renderer/d3d/d3d9/VertexBuffer9.cpp | 239 ++ .../src/libANGLE/renderer/d3d/d3d9/VertexBuffer9.h | 52 + .../renderer/d3d/d3d9/VertexDeclarationCache.cpp | 237 ++ .../renderer/d3d/d3d9/VertexDeclarationCache.h | 60 + .../libANGLE/renderer/d3d/d3d9/formatutils9.cpp | 602 ++++ .../src/libANGLE/renderer/d3d/d3d9/formatutils9.h | 86 + .../libANGLE/renderer/d3d/d3d9/renderer9_utils.cpp | 597 ++++ .../libANGLE/renderer/d3d/d3d9/renderer9_utils.h | 86 + .../src/libANGLE/renderer/d3d/d3d9/shaders/Blit.ps | 33 + .../src/libANGLE/renderer/d3d/d3d9/shaders/Blit.vs | 43 + .../libANGLE/renderer/d3d/d3d9/vertexconversion.h | 197 ++ .../src/libANGLE/renderer/d3d/formatutilsD3D.cpp | 147 + .../src/libANGLE/renderer/d3d/formatutilsD3D.h | 50 + .../angle/src/libANGLE/renderer/d3d/generatemip.h | 28 + .../src/libANGLE/renderer/d3d/generatemip.inl | 266 ++ .../angle/src/libANGLE/renderer/d3d/imageformats.h | 2031 +++++++++++ .../angle/src/libANGLE/renderer/d3d/loadimage.cpp | 662 ++++ .../angle/src/libANGLE/renderer/d3d/loadimage.h | 193 ++ .../angle/src/libANGLE/renderer/d3d/loadimage.inl | 156 + .../src/libANGLE/renderer/d3d/loadimageSSE2.cpp | 125 + src/3rdparty/angle/src/libANGLE/validationEGL.cpp | 503 +++ src/3rdparty/angle/src/libANGLE/validationEGL.h | 49 + src/3rdparty/angle/src/libANGLE/validationES.cpp | 1882 ++++++++++ src/3rdparty/angle/src/libANGLE/validationES.h | 94 + src/3rdparty/angle/src/libANGLE/validationES2.cpp | 882 +++++ src/3rdparty/angle/src/libANGLE/validationES2.h | 34 + src/3rdparty/angle/src/libANGLE/validationES3.cpp | 1282 +++++++ src/3rdparty/angle/src/libANGLE/validationES3.h | 49 + 253 files changed, 70682 insertions(+) create mode 100644 src/3rdparty/angle/src/libANGLE/AttributeMap.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/AttributeMap.h create mode 100644 src/3rdparty/angle/src/libANGLE/BinaryStream.h create mode 100644 src/3rdparty/angle/src/libANGLE/Buffer.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/Buffer.h create mode 100644 src/3rdparty/angle/src/libANGLE/Caps.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/Caps.h create mode 100644 src/3rdparty/angle/src/libANGLE/Compiler.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/Compiler.h create mode 100644 src/3rdparty/angle/src/libANGLE/Config.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/Config.h create mode 100644 src/3rdparty/angle/src/libANGLE/Constants.h create mode 100644 src/3rdparty/angle/src/libANGLE/Context.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/Context.h create mode 100644 src/3rdparty/angle/src/libANGLE/Data.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/Data.h create mode 100644 src/3rdparty/angle/src/libANGLE/Display.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/Display.h create mode 100644 src/3rdparty/angle/src/libANGLE/Error.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/Error.h create mode 100644 src/3rdparty/angle/src/libANGLE/Error.inl create mode 100644 src/3rdparty/angle/src/libANGLE/Fence.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/Fence.h create mode 100644 src/3rdparty/angle/src/libANGLE/Float16ToFloat32.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/Framebuffer.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/Framebuffer.h create mode 100644 src/3rdparty/angle/src/libANGLE/FramebufferAttachment.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/FramebufferAttachment.h create mode 100644 src/3rdparty/angle/src/libANGLE/HandleAllocator.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/HandleAllocator.h create mode 100644 src/3rdparty/angle/src/libANGLE/ImageIndex.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/ImageIndex.h create mode 100644 src/3rdparty/angle/src/libANGLE/Platform.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/Program.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/Program.h create mode 100644 src/3rdparty/angle/src/libANGLE/Query.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/Query.h create mode 100644 src/3rdparty/angle/src/libANGLE/RefCountObject.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/RefCountObject.h create mode 100644 src/3rdparty/angle/src/libANGLE/Renderbuffer.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/Renderbuffer.h create mode 100644 src/3rdparty/angle/src/libANGLE/ResourceManager.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/ResourceManager.h create mode 100644 src/3rdparty/angle/src/libANGLE/Sampler.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/Sampler.h create mode 100644 src/3rdparty/angle/src/libANGLE/Shader.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/Shader.h create mode 100644 src/3rdparty/angle/src/libANGLE/State.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/State.h create mode 100644 src/3rdparty/angle/src/libANGLE/Surface.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/Surface.h create mode 100644 src/3rdparty/angle/src/libANGLE/Texture.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/Texture.h create mode 100644 src/3rdparty/angle/src/libANGLE/TransformFeedback.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/TransformFeedback.h create mode 100644 src/3rdparty/angle/src/libANGLE/Uniform.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/Uniform.h create mode 100644 src/3rdparty/angle/src/libANGLE/VertexArray.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/VertexArray.h create mode 100644 src/3rdparty/angle/src/libANGLE/VertexAttribute.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/VertexAttribute.h create mode 100644 src/3rdparty/angle/src/libANGLE/angletypes.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/angletypes.h create mode 100644 src/3rdparty/angle/src/libANGLE/features.h create mode 100644 src/3rdparty/angle/src/libANGLE/formatutils.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/formatutils.h create mode 100644 src/3rdparty/angle/src/libANGLE/queryconversions.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/queryconversions.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/BufferImpl.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/CompilerImpl.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/DisplayImpl.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/DisplayImpl.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/FenceNVImpl.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/FenceSyncImpl.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/FramebufferImpl.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/Image.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/ImplFactory.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/IndexRangeCache.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/IndexRangeCache.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/ProgramImpl.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/ProgramImpl.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/QueryImpl.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/RenderbufferImpl.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/RenderbufferImpl.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/Renderer.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/Renderer.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/ShaderImpl.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/SurfaceImpl.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/SurfaceImpl.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/TextureImpl.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/TransformFeedbackImpl.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/VertexArrayImpl.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/Workarounds.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/BufferD3D.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/BufferD3D.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/CompilerD3D.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/CompilerD3D.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/DisplayD3D.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/DisplayD3D.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/DynamicHLSL.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/DynamicHLSL.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/FramebufferD3D.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/FramebufferD3D.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/HLSLCompiler.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/HLSLCompiler.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/ImageD3D.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/ImageD3D.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/IndexBuffer.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/IndexBuffer.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/IndexDataManager.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/IndexDataManager.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/ProgramD3D.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/ProgramD3D.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/RenderTargetD3D.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/RenderTargetD3D.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/RenderbufferD3D.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/RenderbufferD3D.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/RendererD3D.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/RendererD3D.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/ShaderD3D.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/ShaderD3D.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/ShaderExecutableD3D.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/ShaderExecutableD3D.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/SurfaceD3D.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/SurfaceD3D.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/SwapChainD3D.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/TextureD3D.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/TextureD3D.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/TextureStorage.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/TextureStorage.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/TransformFeedbackD3D.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/TransformFeedbackD3D.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/VertexBuffer.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/VertexBuffer.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/VertexDataManager.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/VertexDataManager.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/copyimage.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/copyimage.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/copyimage.inl create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Blit11.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Blit11.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Buffer11.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Buffer11.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Clear11.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Clear11.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/DebugAnnotator11.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/DebugAnnotator11.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Fence11.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Fence11.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Framebuffer11.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Framebuffer11.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Image11.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Image11.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/IndexBuffer11.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/IndexBuffer11.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/InputLayoutCache.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/InputLayoutCache.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/NativeWindow.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/PixelTransfer11.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/PixelTransfer11.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Query11.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Query11.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/RenderStateCache.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/RenderStateCache.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/RenderTarget11.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/RenderTarget11.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Renderer11.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/ShaderExecutable11.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/ShaderExecutable11.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/SwapChain11.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/SwapChain11.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/TextureStorage11.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/TextureStorage11.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Trim11.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Trim11.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/VertexArray11.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/VertexBuffer11.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/VertexBuffer11.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/copyvertex.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/copyvertex.inl create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/formatutils11.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/formatutils11.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/shaders/BufferToTexture11.hlsl create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/shaders/Clear11.hlsl create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/shaders/Passthrough2D11.hlsl create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/shaders/Passthrough3D11.hlsl create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/shaders/Swizzle11.hlsl create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/win32/NativeWindow.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/InspectableNativeWindow.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/InspectableNativeWindow.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/SwapChainPanelNativeWindow.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/SwapChainPanelNativeWindow.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Blit9.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Blit9.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Buffer9.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Buffer9.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/DebugAnnotator9.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/DebugAnnotator9.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Fence9.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Fence9.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Framebuffer9.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Framebuffer9.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Image9.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Image9.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/IndexBuffer9.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/IndexBuffer9.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Query9.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Query9.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/RenderTarget9.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/RenderTarget9.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Renderer9.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Renderer9.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/ShaderCache.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/ShaderExecutable9.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/ShaderExecutable9.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/SwapChain9.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/SwapChain9.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/TextureStorage9.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/TextureStorage9.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/VertexArray9.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/VertexBuffer9.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/VertexBuffer9.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/VertexDeclarationCache.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/VertexDeclarationCache.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/formatutils9.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/formatutils9.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/renderer9_utils.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/renderer9_utils.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/shaders/Blit.ps create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/shaders/Blit.vs create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/vertexconversion.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/formatutilsD3D.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/formatutilsD3D.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/generatemip.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/generatemip.inl create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/imageformats.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/loadimage.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/loadimage.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/loadimage.inl create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/loadimageSSE2.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/validationEGL.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/validationEGL.h create mode 100644 src/3rdparty/angle/src/libANGLE/validationES.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/validationES.h create mode 100644 src/3rdparty/angle/src/libANGLE/validationES2.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/validationES2.h create mode 100644 src/3rdparty/angle/src/libANGLE/validationES3.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/validationES3.h (limited to 'src/3rdparty/angle/src/libANGLE') diff --git a/src/3rdparty/angle/src/libANGLE/AttributeMap.cpp b/src/3rdparty/angle/src/libANGLE/AttributeMap.cpp new file mode 100644 index 0000000000..651a012037 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/AttributeMap.cpp @@ -0,0 +1,53 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "libANGLE/AttributeMap.h" + +namespace egl +{ + +AttributeMap::AttributeMap() +{ +} + +AttributeMap::AttributeMap(const EGLint *attributes) +{ + if (attributes) + { + for (const EGLint *curAttrib = attributes; curAttrib[0] != EGL_NONE; curAttrib += 2) + { + insert(curAttrib[0], curAttrib[1]); + } + } +} + +void AttributeMap::insert(EGLint key, EGLint value) +{ + mAttributes[key] = value; +} + +bool AttributeMap::contains(EGLint key) const +{ + return (mAttributes.find(key) != mAttributes.end()); +} + +EGLint AttributeMap::get(EGLint key, EGLint defaultValue) const +{ + std::map::const_iterator iter = mAttributes.find(key); + return (mAttributes.find(key) != mAttributes.end()) ? iter->second : defaultValue; +} + +AttributeMap::const_iterator AttributeMap::begin() const +{ + return mAttributes.begin(); +} + +AttributeMap::const_iterator AttributeMap::end() const +{ + return mAttributes.end(); +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/AttributeMap.h b/src/3rdparty/angle/src/libANGLE/AttributeMap.h new file mode 100644 index 0000000000..72b6edc3c7 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/AttributeMap.h @@ -0,0 +1,39 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef LIBANGLE_ATTRIBUTEMAP_H_ +#define LIBANGLE_ATTRIBUTEMAP_H_ + + +#include + +#include + +namespace egl +{ + +class AttributeMap +{ + public: + AttributeMap(); + explicit AttributeMap(const EGLint *attributes); + + virtual void insert(EGLint key, EGLint value); + virtual bool contains(EGLint key) const; + virtual EGLint get(EGLint key, EGLint defaultValue) const; + + typedef std::map::const_iterator const_iterator; + + const_iterator begin() const; + const_iterator end() const; + + private: + std::map mAttributes; +}; + +} + +#endif // LIBANGLE_ATTRIBUTEMAP_H_ diff --git a/src/3rdparty/angle/src/libANGLE/BinaryStream.h b/src/3rdparty/angle/src/libANGLE/BinaryStream.h new file mode 100644 index 0000000000..50392e1d3f --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/BinaryStream.h @@ -0,0 +1,218 @@ +// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// BinaryStream.h: Provides binary serialization of simple types. + +#ifndef LIBANGLE_BINARYSTREAM_H_ +#define LIBANGLE_BINARYSTREAM_H_ + +#include "common/angleutils.h" +#include "common/mathutil.h" + +#include +#include +#include +#include + +template +void StaticAssertIsFundamental() +{ + // c++11 STL is not available on OSX or Android +#if !defined(ANGLE_PLATFORM_APPLE) && !defined(ANGLE_PLATFORM_ANDROID) + static_assert(std::is_fundamental::value, "T must be a fundamental type."); +#else + union { T dummy; } dummy; + static_cast(dummy); +#endif +} + +namespace gl +{ + +class BinaryInputStream : angle::NonCopyable +{ + public: + BinaryInputStream(const void *data, size_t length) + { + mError = false; + mOffset = 0; + mData = static_cast(data); + mLength = length; + } + + // readInt will generate an error for bool types + template + IntT readInt() + { + int value; + read(&value); + return static_cast(value); + } + + template + void readInt(IntT *outValue) + { + *outValue = readInt(); + } + + bool readBool() + { + int value; + read(&value); + return (value > 0); + } + + void readBool(bool *outValue) + { + *outValue = readBool(); + } + + void readBytes(unsigned char outArray[], size_t count) + { + read(outArray, count); + } + + std::string readString() + { + std::string outString; + readString(&outString); + return outString; + } + + void readString(std::string *v) + { + size_t length; + readInt(&length); + + if (mError) + { + return; + } + + if (mOffset + length > mLength) + { + mError = true; + return; + } + + v->assign(reinterpret_cast(mData) + mOffset, length); + mOffset += length; + } + + void skip(size_t length) + { + if (mOffset + length > mLength) + { + mError = true; + return; + } + + mOffset += length; + } + + size_t offset() const + { + return mOffset; + } + + bool error() const + { + return mError; + } + + bool endOfStream() const + { + return mOffset == mLength; + } + + const uint8_t *data() + { + return mData; + } + + private: + bool mError; + size_t mOffset; + const uint8_t *mData; + size_t mLength; + + template + void read(T *v, size_t num) + { + StaticAssertIsFundamental(); + + size_t length = num * sizeof(T); + + if (mOffset + length > mLength) + { + mError = true; + return; + } + + memcpy(v, mData + mOffset, length); + mOffset += length; + } + + template + void read(T *v) + { + read(v, 1); + } + +}; + +class BinaryOutputStream : angle::NonCopyable +{ + public: + BinaryOutputStream() + { + } + + // writeInt also handles bool types + template + void writeInt(IntT param) + { + ASSERT(rx::IsIntegerCastSafe(param)); + int intValue = static_cast(param); + write(&intValue, 1); + } + + void writeString(const std::string &v) + { + writeInt(v.length()); + write(v.c_str(), v.length()); + } + + void writeBytes(const unsigned char *bytes, size_t count) + { + write(bytes, count); + } + + size_t length() const + { + return mData.size(); + } + + const void* data() const + { + return mData.size() ? &mData[0] : NULL; + } + + private: + std::vector mData; + + template + void write(const T *v, size_t num) + { + StaticAssertIsFundamental(); + const char *asBytes = reinterpret_cast(v); + mData.insert(mData.end(), asBytes, asBytes + num * sizeof(T)); + } + +}; +} + +#endif // LIBANGLE_BINARYSTREAM_H_ diff --git a/src/3rdparty/angle/src/libANGLE/Buffer.cpp b/src/3rdparty/angle/src/libANGLE/Buffer.cpp new file mode 100644 index 0000000000..f394a6b1d1 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/Buffer.cpp @@ -0,0 +1,121 @@ +// +// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Buffer.cpp: Implements the gl::Buffer class, representing storage of vertex and/or +// index data. Implements GL buffer objects and related functionality. +// [OpenGL ES 2.0.24] section 2.9 page 21. + +#include "libANGLE/Buffer.h" +#include "libANGLE/renderer/BufferImpl.h" +#include "libANGLE/renderer/Renderer.h" + +namespace gl +{ + +Buffer::Buffer(rx::BufferImpl *impl, GLuint id) + : RefCountObject(id), + mBuffer(impl), + mUsage(GL_DYNAMIC_DRAW), + mSize(0), + mAccessFlags(0), + mMapped(GL_FALSE), + mMapPointer(NULL), + mMapOffset(0), + mMapLength(0) +{ +} + +Buffer::~Buffer() +{ + SafeDelete(mBuffer); +} + +Error Buffer::bufferData(const void *data, GLsizeiptr size, GLenum usage) +{ + gl::Error error = mBuffer->setData(data, size, usage); + if (error.isError()) + { + return error; + } + + mIndexRangeCache.clear(); + mUsage = usage; + mSize = size; + + return error; +} + +Error Buffer::bufferSubData(const void *data, GLsizeiptr size, GLintptr offset) +{ + gl::Error error = mBuffer->setSubData(data, size, offset); + if (error.isError()) + { + return error; + } + + mIndexRangeCache.invalidateRange(offset, size); + + return error; +} + +Error Buffer::copyBufferSubData(Buffer* source, GLintptr sourceOffset, GLintptr destOffset, GLsizeiptr size) +{ + gl::Error error = mBuffer->copySubData(source->getImplementation(), sourceOffset, destOffset, size); + if (error.isError()) + { + return error; + } + + mIndexRangeCache.invalidateRange(destOffset, size); + + return error; +} + +Error Buffer::mapRange(GLintptr offset, GLsizeiptr length, GLbitfield access) +{ + ASSERT(!mMapped); + ASSERT(offset + length <= mSize); + + Error error = mBuffer->map(offset, length, access, &mMapPointer); + if (error.isError()) + { + mMapPointer = NULL; + return error; + } + + mMapped = GL_TRUE; + mMapOffset = static_cast(offset); + mMapLength = static_cast(length); + mAccessFlags = static_cast(access); + + if ((access & GL_MAP_WRITE_BIT) > 0) + { + mIndexRangeCache.invalidateRange(offset, length); + } + + return error; +} + +Error Buffer::unmap() +{ + ASSERT(mMapped); + + Error error = mBuffer->unmap(); + if (error.isError()) + { + return error; + } + + mMapped = GL_FALSE; + mMapPointer = NULL; + mMapOffset = 0; + mMapLength = 0; + mAccessFlags = 0; + + return error; +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/Buffer.h b/src/3rdparty/angle/src/libANGLE/Buffer.h new file mode 100644 index 0000000000..6793028e3b --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/Buffer.h @@ -0,0 +1,70 @@ +// +// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Buffer.h: Defines the gl::Buffer class, representing storage of vertex and/or +// index data. Implements GL buffer objects and related functionality. +// [OpenGL ES 2.0.24] section 2.9 page 21. + +#ifndef LIBANGLE_BUFFER_H_ +#define LIBANGLE_BUFFER_H_ + +#include "libANGLE/Error.h" +#include "libANGLE/RefCountObject.h" +#include "libANGLE/renderer/IndexRangeCache.h" + +#include "common/angleutils.h" + +namespace rx +{ +class BufferImpl; +}; + +namespace gl +{ + +class Buffer : public RefCountObject +{ + public: + Buffer(rx::BufferImpl *impl, GLuint id); + + virtual ~Buffer(); + + Error bufferData(const void *data, GLsizeiptr size, GLenum usage); + Error bufferSubData(const void *data, GLsizeiptr size, GLintptr offset); + Error copyBufferSubData(Buffer* source, GLintptr sourceOffset, GLintptr destOffset, GLsizeiptr size); + Error mapRange(GLintptr offset, GLsizeiptr length, GLbitfield access); + Error unmap(); + + GLenum getUsage() const { return mUsage; } + GLint getAccessFlags() const { return mAccessFlags; } + GLboolean isMapped() const { return mMapped; } + GLvoid *getMapPointer() const { return mMapPointer; } + GLint64 getMapOffset() const { return mMapOffset; } + GLint64 getMapLength() const { return mMapLength; } + GLint64 getSize() const { return mSize; } + + rx::BufferImpl *getImplementation() const { return mBuffer; } + + rx::IndexRangeCache *getIndexRangeCache() { return &mIndexRangeCache; } + const rx::IndexRangeCache *getIndexRangeCache() const { return &mIndexRangeCache; } + + private: + rx::BufferImpl *mBuffer; + + GLenum mUsage; + GLint64 mSize; + GLint mAccessFlags; + GLboolean mMapped; + GLvoid *mMapPointer; + GLint64 mMapOffset; + GLint64 mMapLength; + + rx::IndexRangeCache mIndexRangeCache; +}; + +} + +#endif // LIBANGLE_BUFFER_H_ diff --git a/src/3rdparty/angle/src/libANGLE/Caps.cpp b/src/3rdparty/angle/src/libANGLE/Caps.cpp new file mode 100644 index 0000000000..086d0a02a2 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/Caps.cpp @@ -0,0 +1,527 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "libANGLE/Caps.h" +#include "common/debug.h" +#include "common/angleutils.h" + +#include "angle_gl.h" + +#include +#include + +static void InsertExtensionString(const std::string &extension, bool supported, std::vector *extensionVector) +{ + if (supported) + { + extensionVector->push_back(extension); + } +} + +namespace gl +{ + +TextureCaps::TextureCaps() + : texturable(false), + filterable(false), + renderable(false), + sampleCounts() +{ +} + +GLuint TextureCaps::getMaxSamples() const +{ + return !sampleCounts.empty() ? *sampleCounts.rbegin() : 0; +} + +GLuint TextureCaps::getNearestSamples(GLuint requestedSamples) const +{ + if (requestedSamples == 0) + { + return 0; + } + + for (SupportedSampleSet::const_iterator i = sampleCounts.begin(); i != sampleCounts.end(); i++) + { + GLuint samples = *i; + if (samples >= requestedSamples) + { + return samples; + } + } + + return 0; +} + +void TextureCapsMap::insert(GLenum internalFormat, const TextureCaps &caps) +{ + mCapsMap.insert(std::make_pair(internalFormat, caps)); +} + +void TextureCapsMap::remove(GLenum internalFormat) +{ + InternalFormatToCapsMap::iterator i = mCapsMap.find(internalFormat); + if (i != mCapsMap.end()) + { + mCapsMap.erase(i); + } +} + +const TextureCaps &TextureCapsMap::get(GLenum internalFormat) const +{ + static TextureCaps defaultUnsupportedTexture; + InternalFormatToCapsMap::const_iterator iter = mCapsMap.find(internalFormat); + return (iter != mCapsMap.end()) ? iter->second : defaultUnsupportedTexture; +} + +TextureCapsMap::const_iterator TextureCapsMap::begin() const +{ + return mCapsMap.begin(); +} + +TextureCapsMap::const_iterator TextureCapsMap::end() const +{ + return mCapsMap.end(); +} + +size_t TextureCapsMap::size() const +{ + return mCapsMap.size(); +} + +Extensions::Extensions() + : elementIndexUint(false), + packedDepthStencil(false), + getProgramBinary(false), + rgb8rgba8(false), + textureFormatBGRA8888(false), + readFormatBGRA(false), + pixelBufferObject(false), + mapBuffer(false), + mapBufferRange(false), + textureHalfFloat(false), + textureHalfFloatLinear(false), + textureFloat(false), + textureFloatLinear(false), + textureRG(false), + textureCompressionDXT1(false), + textureCompressionDXT3(false), + textureCompressionDXT5(false), + depthTextures(false), + textureNPOT(false), + drawBuffers(false), + textureStorage(false), + textureFilterAnisotropic(false), + maxTextureAnisotropy(false), + occlusionQueryBoolean(false), + fence(false), + timerQuery(false), + robustness(false), + blendMinMax(false), + framebufferBlit(false), + framebufferMultisample(false), + instancedArrays(false), + packReverseRowOrder(false), + standardDerivatives(false), + shaderTextureLOD(false), + shaderFramebufferFetch(false), + ARMshaderFramebufferFetch(false), + NVshaderFramebufferFetch(false), + fragDepth(false), + textureUsage(false), + translatedShaderSource(false), + colorBufferFloat(false) +{ +} + +std::vector Extensions::getStrings() const +{ + std::vector extensionStrings; + + // | Extension name | Supported flag | Output vector | + InsertExtensionString("GL_OES_element_index_uint", elementIndexUint, &extensionStrings); + InsertExtensionString("GL_OES_packed_depth_stencil", packedDepthStencil, &extensionStrings); + InsertExtensionString("GL_OES_get_program_binary", getProgramBinary, &extensionStrings); + InsertExtensionString("GL_OES_rgb8_rgba8", rgb8rgba8, &extensionStrings); + InsertExtensionString("GL_EXT_texture_format_BGRA8888", textureFormatBGRA8888, &extensionStrings); + InsertExtensionString("GL_EXT_read_format_bgra", readFormatBGRA, &extensionStrings); + InsertExtensionString("GL_NV_pixel_buffer_object", pixelBufferObject, &extensionStrings); + InsertExtensionString("GL_OES_mapbuffer", mapBuffer, &extensionStrings); + InsertExtensionString("GL_EXT_map_buffer_range", mapBufferRange, &extensionStrings); + InsertExtensionString("GL_OES_texture_half_float", textureHalfFloat, &extensionStrings); + InsertExtensionString("GL_OES_texture_half_float_linear", textureHalfFloatLinear, &extensionStrings); + InsertExtensionString("GL_OES_texture_float", textureFloat, &extensionStrings); + InsertExtensionString("GL_OES_texture_float_linear", textureFloatLinear, &extensionStrings); + InsertExtensionString("GL_EXT_texture_rg", textureRG, &extensionStrings); + InsertExtensionString("GL_EXT_texture_compression_dxt1", textureCompressionDXT1, &extensionStrings); + InsertExtensionString("GL_ANGLE_texture_compression_dxt3", textureCompressionDXT3, &extensionStrings); + InsertExtensionString("GL_ANGLE_texture_compression_dxt5", textureCompressionDXT5, &extensionStrings); + InsertExtensionString("GL_EXT_sRGB", sRGB, &extensionStrings); + InsertExtensionString("GL_ANGLE_depth_texture", depthTextures, &extensionStrings); + InsertExtensionString("GL_EXT_texture_storage", textureStorage, &extensionStrings); + InsertExtensionString("GL_OES_texture_npot", textureNPOT, &extensionStrings); + InsertExtensionString("GL_EXT_draw_buffers", drawBuffers, &extensionStrings); + InsertExtensionString("GL_EXT_texture_filter_anisotropic", textureFilterAnisotropic, &extensionStrings); + InsertExtensionString("GL_EXT_occlusion_query_boolean", occlusionQueryBoolean, &extensionStrings); + InsertExtensionString("GL_NV_fence", fence, &extensionStrings); + InsertExtensionString("GL_ANGLE_timer_query", timerQuery, &extensionStrings); + InsertExtensionString("GL_EXT_robustness", robustness, &extensionStrings); + InsertExtensionString("GL_EXT_blend_minmax", blendMinMax, &extensionStrings); + InsertExtensionString("GL_ANGLE_framebuffer_blit", framebufferBlit, &extensionStrings); + InsertExtensionString("GL_ANGLE_framebuffer_multisample", framebufferMultisample, &extensionStrings); + InsertExtensionString("GL_ANGLE_instanced_arrays", instancedArrays, &extensionStrings); + InsertExtensionString("GL_ANGLE_pack_reverse_row_order", packReverseRowOrder, &extensionStrings); + InsertExtensionString("GL_OES_standard_derivatives", standardDerivatives, &extensionStrings); + InsertExtensionString("GL_EXT_shader_texture_lod", shaderTextureLOD, &extensionStrings); + InsertExtensionString("GL_NV_shader_framebuffer_fetch", NVshaderFramebufferFetch, &extensionStrings); + InsertExtensionString("GL_ARM_shader_framebuffer_fetch", ARMshaderFramebufferFetch,&extensionStrings); + InsertExtensionString("GL_EXT_shader_framebuffer_fetch", shaderFramebufferFetch, &extensionStrings); + InsertExtensionString("GL_EXT_frag_depth", fragDepth, &extensionStrings); + InsertExtensionString("GL_ANGLE_texture_usage", textureUsage, &extensionStrings); + InsertExtensionString("GL_ANGLE_translated_shader_source", translatedShaderSource, &extensionStrings); + InsertExtensionString("GL_EXT_color_buffer_float", colorBufferFloat, &extensionStrings); + + return extensionStrings; +} + +static bool GetFormatSupport(const TextureCapsMap &textureCaps, const std::vector &requiredFormats, + bool requiresTexturing, bool requiresFiltering, bool requiresRendering) +{ + for (size_t i = 0; i < requiredFormats.size(); i++) + { + const TextureCaps &cap = textureCaps.get(requiredFormats[i]); + + if (requiresTexturing && !cap.texturable) + { + return false; + } + + if (requiresFiltering && !cap.filterable) + { + return false; + } + + if (requiresRendering && !cap.renderable) + { + return false; + } + } + + return true; +} + +// Checks for GL_OES_rgb8_rgba8 support +static bool DetermineRGB8AndRGBA8TextureSupport(const TextureCapsMap &textureCaps) +{ + std::vector requiredFormats; + requiredFormats.push_back(GL_RGB8); + requiredFormats.push_back(GL_RGBA8); + + return GetFormatSupport(textureCaps, requiredFormats, true, true, true); +} + +// Checks for GL_EXT_texture_format_BGRA8888 support +static bool DetermineBGRA8TextureSupport(const TextureCapsMap &textureCaps) +{ + std::vector requiredFormats; + requiredFormats.push_back(GL_BGRA8_EXT); + + return GetFormatSupport(textureCaps, requiredFormats, true, true, true); +} + +// Checks for GL_OES_texture_half_float support +static bool DetermineHalfFloatTextureSupport(const TextureCapsMap &textureCaps) +{ + std::vector requiredFormats; + requiredFormats.push_back(GL_RGB16F); + requiredFormats.push_back(GL_RGBA16F); + + return GetFormatSupport(textureCaps, requiredFormats, true, false, true); +} + +// Checks for GL_OES_texture_half_float_linear support +static bool DetermineHalfFloatTextureFilteringSupport(const TextureCapsMap &textureCaps) +{ + std::vector requiredFormats; + requiredFormats.push_back(GL_RGB16F); + requiredFormats.push_back(GL_RGBA16F); + + return GetFormatSupport(textureCaps, requiredFormats, true, true, false); +} + +// Checks for GL_OES_texture_float support +static bool DetermineFloatTextureSupport(const TextureCapsMap &textureCaps) +{ + std::vector requiredFormats; + requiredFormats.push_back(GL_RGB32F); + requiredFormats.push_back(GL_RGBA32F); + + return GetFormatSupport(textureCaps, requiredFormats, true, false, true); +} + +// Checks for GL_OES_texture_float_linear support +static bool DetermineFloatTextureFilteringSupport(const TextureCapsMap &textureCaps) +{ + std::vector requiredFormats; + requiredFormats.push_back(GL_RGB32F); + requiredFormats.push_back(GL_RGBA32F); + + return GetFormatSupport(textureCaps, requiredFormats, true, true, false); +} + +// Checks for GL_EXT_texture_rg support +static bool DetermineRGTextureSupport(const TextureCapsMap &textureCaps, bool checkHalfFloatFormats, bool checkFloatFormats) +{ + std::vector requiredFormats; + requiredFormats.push_back(GL_R8); + requiredFormats.push_back(GL_RG8); + if (checkHalfFloatFormats) + { + requiredFormats.push_back(GL_R16F); + requiredFormats.push_back(GL_RG16F); + } + if (checkFloatFormats) + { + requiredFormats.push_back(GL_R32F); + requiredFormats.push_back(GL_RG32F); + } + + return GetFormatSupport(textureCaps, requiredFormats, true, true, false); +} + +// Check for GL_EXT_texture_compression_dxt1 +static bool DetermineDXT1TextureSupport(const TextureCapsMap &textureCaps) +{ + std::vector requiredFormats; + requiredFormats.push_back(GL_COMPRESSED_RGB_S3TC_DXT1_EXT); + requiredFormats.push_back(GL_COMPRESSED_RGBA_S3TC_DXT1_EXT); + + return GetFormatSupport(textureCaps, requiredFormats, true, true, false); +} + +// Check for GL_ANGLE_texture_compression_dxt3 +static bool DetermineDXT3TextureSupport(const TextureCapsMap &textureCaps) +{ + std::vector requiredFormats; + requiredFormats.push_back(GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE); + + return GetFormatSupport(textureCaps, requiredFormats, true, true, false); +} + +// Check for GL_ANGLE_texture_compression_dxt5 +static bool DetermineDXT5TextureSupport(const TextureCapsMap &textureCaps) +{ + std::vector requiredFormats; + requiredFormats.push_back(GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE); + + return GetFormatSupport(textureCaps, requiredFormats, true, true, false); +} + +// Check for GL_ANGLE_texture_compression_dxt5 +static bool DetermineSRGBTextureSupport(const TextureCapsMap &textureCaps) +{ + std::vector requiredFilterFormats; + requiredFilterFormats.push_back(GL_SRGB8); + requiredFilterFormats.push_back(GL_SRGB8_ALPHA8); + + std::vector requiredRenderFormats; + requiredRenderFormats.push_back(GL_SRGB8_ALPHA8); + + return GetFormatSupport(textureCaps, requiredFilterFormats, true, true, false) && + GetFormatSupport(textureCaps, requiredRenderFormats, true, false, true); +} + +// Check for GL_ANGLE_depth_texture +static bool DetermineDepthTextureSupport(const TextureCapsMap &textureCaps) +{ + std::vector requiredFormats; + requiredFormats.push_back(GL_DEPTH_COMPONENT16); + requiredFormats.push_back(GL_DEPTH_COMPONENT32_OES); + requiredFormats.push_back(GL_DEPTH24_STENCIL8_OES); + + return GetFormatSupport(textureCaps, requiredFormats, true, true, true); +} + +// Check for GL_EXT_color_buffer_float +static bool DetermineColorBufferFloatSupport(const TextureCapsMap &textureCaps) +{ + std::vector requiredFormats; + requiredFormats.push_back(GL_R16F); + requiredFormats.push_back(GL_RG16F); + requiredFormats.push_back(GL_RGBA16F); + requiredFormats.push_back(GL_R32F); + requiredFormats.push_back(GL_RG32F); + requiredFormats.push_back(GL_RGBA32F); + requiredFormats.push_back(GL_R11F_G11F_B10F); + + return GetFormatSupport(textureCaps, requiredFormats, true, false, true); +} + +void Extensions::setTextureExtensionSupport(const TextureCapsMap &textureCaps) +{ + rgb8rgba8 = DetermineRGB8AndRGBA8TextureSupport(textureCaps); + textureFormatBGRA8888 = DetermineBGRA8TextureSupport(textureCaps); + textureHalfFloat = DetermineHalfFloatTextureSupport(textureCaps); + textureHalfFloatLinear = DetermineHalfFloatTextureFilteringSupport(textureCaps); + textureFloat = DetermineFloatTextureSupport(textureCaps); + textureFloatLinear = DetermineFloatTextureFilteringSupport(textureCaps); + textureRG = DetermineRGTextureSupport(textureCaps, textureHalfFloat, textureFloat); + textureCompressionDXT1 = DetermineDXT1TextureSupport(textureCaps); + textureCompressionDXT3 = DetermineDXT3TextureSupport(textureCaps); + textureCompressionDXT5 = DetermineDXT5TextureSupport(textureCaps); + sRGB = DetermineSRGBTextureSupport(textureCaps); + depthTextures = DetermineDepthTextureSupport(textureCaps); + colorBufferFloat = DetermineColorBufferFloatSupport(textureCaps); +} + +TypePrecision::TypePrecision() +{ + range[0] = 0; + range[1] = 0; + precision = 0; +} + +void TypePrecision::setIEEEFloat() +{ + range[0] = 127; + range[1] = 127; + precision = 23; +} + +void TypePrecision::setTwosComplementInt(unsigned int bits) +{ + range[0] = GLint(bits) - 1; + range[1] = GLint(bits) - 2; + precision = 0; +} + +void TypePrecision::setSimulatedInt(unsigned int r) +{ + range[0] = GLint(r); + range[1] = GLint(r); + precision = 0; +} + +void TypePrecision::get(GLint *returnRange, GLint *returnPrecision) const +{ + returnRange[0] = range[0]; + returnRange[1] = range[1]; + *returnPrecision = precision; +} + +Caps::Caps() + : maxElementIndex(0), + max3DTextureSize(0), + max2DTextureSize(0), + maxArrayTextureLayers(0), + maxLODBias(0), + maxCubeMapTextureSize(0), + maxRenderbufferSize(0), + maxDrawBuffers(0), + maxColorAttachments(0), + maxViewportWidth(0), + maxViewportHeight(0), + minAliasedPointSize(0), + maxAliasedPointSize(0), + minAliasedLineWidth(0), + // Table 6.29 + maxElementsIndices(0), + maxElementsVertices(0), + maxServerWaitTimeout(0), + // Table 6.31 + maxVertexAttributes(0), + maxVertexUniformComponents(0), + maxVertexUniformVectors(0), + maxVertexUniformBlocks(0), + maxVertexOutputComponents(0), + maxVertexTextureImageUnits(0), + // Table 6.32 + maxFragmentUniformComponents(0), + maxFragmentUniformVectors(0), + maxFragmentUniformBlocks(0), + maxFragmentInputComponents(0), + maxTextureImageUnits(0), + minProgramTexelOffset(0), + maxProgramTexelOffset(0), + + maxUniformBufferBindings(0), + maxUniformBlockSize(0), + uniformBufferOffsetAlignment(0), + maxCombinedUniformBlocks(0), + maxCombinedVertexUniformComponents(0), + maxCombinedFragmentUniformComponents(0), + maxVaryingComponents(0), + maxVaryingVectors(0), + maxCombinedTextureImageUnits(0), + + maxTransformFeedbackInterleavedComponents(0), + maxTransformFeedbackSeparateAttributes(0), + maxTransformFeedbackSeparateComponents(0) +{ +} + +} + +namespace egl +{ + +Caps::Caps() + : textureNPOT(false) +{ +} + +DisplayExtensions::DisplayExtensions() + : createContextRobustness(false), + d3dShareHandleClientBuffer(false), + surfaceD3DTexture2DShareHandle(false), + querySurfacePointer(false), + windowFixedSize(false), + postSubBuffer(false), + createContext(false) +{ +} + +std::vector DisplayExtensions::getStrings() const +{ + std::vector extensionStrings; + + // | Extension name | Supported flag | Output vector | + InsertExtensionString("EGL_EXT_create_context_robustness", createContextRobustness, &extensionStrings); + InsertExtensionString("EGL_ANGLE_d3d_share_handle_client_buffer", d3dShareHandleClientBuffer, &extensionStrings); + InsertExtensionString("EGL_ANGLE_surface_d3d_texture_2d_share_handle", surfaceD3DTexture2DShareHandle, &extensionStrings); + InsertExtensionString("EGL_ANGLE_query_surface_pointer", querySurfacePointer, &extensionStrings); + InsertExtensionString("EGL_ANGLE_window_fixed_size", windowFixedSize, &extensionStrings); + InsertExtensionString("EGL_NV_post_sub_buffer", postSubBuffer, &extensionStrings); + InsertExtensionString("EGL_KHR_create_context", createContext, &extensionStrings); + + return extensionStrings; +} + + +ClientExtensions::ClientExtensions() + : clientExtensions(false), + platformBase(false), + platformANGLE(false), + platformANGLED3D(false), + platformANGLEOpenGL(false) +{ +} + +std::vector ClientExtensions::getStrings() const +{ + std::vector extensionStrings; + + // | Extension name | Supported flag | Output vector | + InsertExtensionString("EGL_EXT_client_extensions", clientExtensions, &extensionStrings); + InsertExtensionString("EGL_EXT_platform_base", platformBase, &extensionStrings); + InsertExtensionString("EGL_ANGLE_platform_angle", platformANGLE, &extensionStrings); + InsertExtensionString("EGL_ANGLE_platform_angle_d3d", platformANGLED3D, &extensionStrings); + InsertExtensionString("EGL_ANGLE_platform_angle_opengl", platformANGLEOpenGL, &extensionStrings); + + return extensionStrings; +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/Caps.h b/src/3rdparty/angle/src/libANGLE/Caps.h new file mode 100644 index 0000000000..37a634226a --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/Caps.h @@ -0,0 +1,374 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef LIBANGLE_CAPS_H_ +#define LIBANGLE_CAPS_H_ + +#include "angle_gl.h" +#include "libANGLE/angletypes.h" + +#include +#include +#include +#include + +namespace gl +{ + +typedef std::set SupportedSampleSet; + +struct TextureCaps +{ + TextureCaps(); + + // Supports for basic texturing: glTexImage, glTexSubImage, etc + bool texturable; + + // Support for linear or anisotropic filtering + bool filterable; + + // Support for being used as a framebuffer attachment or renderbuffer format + bool renderable; + + SupportedSampleSet sampleCounts; + + // Get the maximum number of samples supported + GLuint getMaxSamples() const; + + // Get the number of supported samples that is at least as many as requested. Returns 0 if + // there are no sample counts available + GLuint getNearestSamples(GLuint requestedSamples) const; +}; + +class TextureCapsMap +{ + public: + typedef std::map::const_iterator const_iterator; + + void insert(GLenum internalFormat, const TextureCaps &caps); + void remove(GLenum internalFormat); + + const TextureCaps &get(GLenum internalFormat) const; + + const_iterator begin() const; + const_iterator end() const; + + size_t size() const; + + private: + typedef std::map InternalFormatToCapsMap; + InternalFormatToCapsMap mCapsMap; +}; + +struct Extensions +{ + Extensions(); + + // Generate a vector of supported extension strings + std::vector getStrings() const; + + // Set all texture related extension support based on the supported textures. + // Determines support for: + // GL_OES_rgb8_rgba8 + // GL_EXT_texture_format_BGRA8888 + // GL_OES_texture_half_float, GL_OES_texture_half_float_linear + // GL_OES_texture_float, GL_OES_texture_float_linear + // GL_EXT_texture_rg + // GL_EXT_texture_compression_dxt1, GL_ANGLE_texture_compression_dxt3, GL_ANGLE_texture_compression_dxt5 + // GL_EXT_sRGB + // GL_ANGLE_depth_texture + // GL_EXT_color_buffer_float + void setTextureExtensionSupport(const TextureCapsMap &textureCaps); + + // ES2 Extension support + + // GL_OES_element_index_uint + bool elementIndexUint; + + // GL_OES_packed_depth_stencil + bool packedDepthStencil; + + // GL_OES_get_program_binary + bool getProgramBinary; + + // GL_OES_rgb8_rgba8 + // Implies that TextureCaps for GL_RGB8 and GL_RGBA8 exist + bool rgb8rgba8; + + // GL_EXT_texture_format_BGRA8888 + // Implies that TextureCaps for GL_BGRA8 exist + bool textureFormatBGRA8888; + + // GL_EXT_read_format_bgra + bool readFormatBGRA; + + // GL_NV_pixel_buffer_object + bool pixelBufferObject; + + // GL_OES_mapbuffer and GL_EXT_map_buffer_range + bool mapBuffer; + bool mapBufferRange; + + // GL_OES_texture_half_float and GL_OES_texture_half_float_linear + // Implies that TextureCaps for GL_RGB16F, GL_RGBA16F, GL_ALPHA32F_EXT, GL_LUMINANCE32F_EXT and + // GL_LUMINANCE_ALPHA32F_EXT exist + bool textureHalfFloat; + bool textureHalfFloatLinear; + + // GL_OES_texture_float and GL_OES_texture_float_linear + // Implies that TextureCaps for GL_RGB32F, GL_RGBA32F, GL_ALPHA16F_EXT, GL_LUMINANCE16F_EXT and + // GL_LUMINANCE_ALPHA16F_EXT exist + bool textureFloat; + bool textureFloatLinear; + + // GL_EXT_texture_rg + // Implies that TextureCaps for GL_R8, GL_RG8 (and floating point R/RG texture formats if floating point extensions + // are also present) exist + bool textureRG; + + // GL_EXT_texture_compression_dxt1, GL_ANGLE_texture_compression_dxt3 and GL_ANGLE_texture_compression_dxt5 + // Implies that TextureCaps for GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT + // GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE and GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE + bool textureCompressionDXT1; + bool textureCompressionDXT3; + bool textureCompressionDXT5; + + // GL_EXT_sRGB + // Implies that TextureCaps for GL_SRGB8_ALPHA8 and GL_SRGB8 exist + // TODO: Don't advertise this extension in ES3 + bool sRGB; + + // GL_ANGLE_depth_texture + bool depthTextures; + + // GL_EXT_texture_storage + bool textureStorage; + + // GL_OES_texture_npot + bool textureNPOT; + + // GL_EXT_draw_buffers + bool drawBuffers; + + // GL_EXT_texture_filter_anisotropic + bool textureFilterAnisotropic; + GLfloat maxTextureAnisotropy; + + // GL_EXT_occlusion_query_boolean + bool occlusionQueryBoolean; + + // GL_NV_fence + bool fence; + + // GL_ANGLE_timer_query + bool timerQuery; + + // GL_EXT_robustness + bool robustness; + + // GL_EXT_blend_minmax + bool blendMinMax; + + // GL_ANGLE_framebuffer_blit + bool framebufferBlit; + + // GL_ANGLE_framebuffer_multisample + bool framebufferMultisample; + GLuint maxSamples; + + // GL_ANGLE_instanced_arrays + bool instancedArrays; + + // GL_ANGLE_pack_reverse_row_order + bool packReverseRowOrder; + + // GL_OES_standard_derivatives + bool standardDerivatives; + + // GL_EXT_shader_texture_lod + bool shaderTextureLOD; + + // GL_EXT_shader_framebuffer_fetch + bool shaderFramebufferFetch; + + // GL_ARM_shader_framebuffer_fetch + bool ARMshaderFramebufferFetch; + + // GL_NV_shader_framebuffer_fetch + bool NVshaderFramebufferFetch; + + // GL_EXT_frag_depth + bool fragDepth; + + // GL_ANGLE_texture_usage + bool textureUsage; + + // GL_ANGLE_translated_shader_source + bool translatedShaderSource; + + // ES3 Extension support + + // GL_EXT_color_buffer_float + bool colorBufferFloat; +}; + +struct TypePrecision +{ + TypePrecision(); + + void setIEEEFloat(); + void setTwosComplementInt(unsigned int bits); + void setSimulatedInt(unsigned int range); + + void get(GLint *returnRange, GLint *returnPrecision) const; + + GLint range[2]; + GLint precision; +}; + +struct Caps +{ + Caps(); + + // Table 6.28, implementation dependent values + GLuint64 maxElementIndex; + GLuint max3DTextureSize; + GLuint max2DTextureSize; + GLuint maxArrayTextureLayers; + GLfloat maxLODBias; + GLuint maxCubeMapTextureSize; + GLuint maxRenderbufferSize; + GLuint maxDrawBuffers; + GLuint maxColorAttachments; + GLuint maxViewportWidth; + GLuint maxViewportHeight; + GLfloat minAliasedPointSize; + GLfloat maxAliasedPointSize; + GLfloat minAliasedLineWidth; + GLfloat maxAliasedLineWidth; + + // Table 6.29, implementation dependent values (cont.) + GLuint maxElementsIndices; + GLuint maxElementsVertices; + std::vector compressedTextureFormats; + std::vector programBinaryFormats; + std::vector shaderBinaryFormats; + TypePrecision vertexHighpFloat; + TypePrecision vertexMediumpFloat; + TypePrecision vertexLowpFloat; + TypePrecision vertexHighpInt; + TypePrecision vertexMediumpInt; + TypePrecision vertexLowpInt; + TypePrecision fragmentHighpFloat; + TypePrecision fragmentMediumpFloat; + TypePrecision fragmentLowpFloat; + TypePrecision fragmentHighpInt; + TypePrecision fragmentMediumpInt; + TypePrecision fragmentLowpInt; + GLuint64 maxServerWaitTimeout; + + // Table 6.31, implementation dependent vertex shader limits + GLuint maxVertexAttributes; + GLuint maxVertexUniformComponents; + GLuint maxVertexUniformVectors; + GLuint maxVertexUniformBlocks; + GLuint maxVertexOutputComponents; + GLuint maxVertexTextureImageUnits; + + // Table 6.32, implementation dependent fragment shader limits + GLuint maxFragmentUniformComponents; + GLuint maxFragmentUniformVectors; + GLuint maxFragmentUniformBlocks; + GLuint maxFragmentInputComponents; + GLuint maxTextureImageUnits; + GLint minProgramTexelOffset; + GLint maxProgramTexelOffset; + + // Table 6.33, implementation dependent aggregate shader limits + GLuint maxUniformBufferBindings; + GLuint64 maxUniformBlockSize; + GLuint uniformBufferOffsetAlignment; + GLuint maxCombinedUniformBlocks; + GLuint64 maxCombinedVertexUniformComponents; + GLuint64 maxCombinedFragmentUniformComponents; + GLuint maxVaryingComponents; + GLuint maxVaryingVectors; + GLuint maxCombinedTextureImageUnits; + + // Table 6.34, implementation dependent transform feedback limits + GLuint maxTransformFeedbackInterleavedComponents; + GLuint maxTransformFeedbackSeparateAttributes; + GLuint maxTransformFeedbackSeparateComponents; +}; + +} + +namespace egl +{ + +struct Caps +{ + Caps(); + + // Support for NPOT surfaces + bool textureNPOT; +}; + +struct DisplayExtensions +{ + DisplayExtensions(); + + // Generate a vector of supported extension strings + std::vector getStrings() const; + + // EGL_EXT_create_context_robustness + bool createContextRobustness; + + // EGL_ANGLE_d3d_share_handle_client_buffer + bool d3dShareHandleClientBuffer; + + // EGL_ANGLE_surface_d3d_texture_2d_share_handle + bool surfaceD3DTexture2DShareHandle; + + // EGL_ANGLE_query_surface_pointer + bool querySurfacePointer; + + // EGL_ANGLE_window_fixed_size + bool windowFixedSize; + + // EGL_NV_post_sub_buffer + bool postSubBuffer; + + // EGL_KHR_create_context + bool createContext; +}; + +struct ClientExtensions +{ + ClientExtensions(); + + // Generate a vector of supported extension strings + std::vector getStrings() const; + + // EGL_EXT_client_extensions + bool clientExtensions; + + // EGL_EXT_platform_base + bool platformBase; + + // EGL_ANGLE_platform_angle + bool platformANGLE; + + // EGL_ANGLE_platform_angle_d3d + bool platformANGLED3D; + + // EGL_ANGLE_platform_angle_opengl + bool platformANGLEOpenGL; +}; + +} + +#endif // LIBANGLE_CAPS_H_ diff --git a/src/3rdparty/angle/src/libANGLE/Compiler.cpp b/src/3rdparty/angle/src/libANGLE/Compiler.cpp new file mode 100644 index 0000000000..7d0efea220 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/Compiler.cpp @@ -0,0 +1,38 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Compiler.cpp: implements the gl::Compiler class. + +#include "libANGLE/Compiler.h" +#include "libANGLE/renderer/CompilerImpl.h" + +#include "common/debug.h" + +namespace gl +{ + +Compiler::Compiler(rx::CompilerImpl *impl) + : mCompiler(impl) +{ + ASSERT(mCompiler); +} + +Compiler::~Compiler() +{ + SafeDelete(mCompiler); +} + +Error Compiler::release() +{ + return mCompiler->release(); +} + +rx::CompilerImpl *Compiler::getImplementation() +{ + return mCompiler; +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/Compiler.h b/src/3rdparty/angle/src/libANGLE/Compiler.h new file mode 100644 index 0000000000..05de15ec97 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/Compiler.h @@ -0,0 +1,39 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Compiler.h: Defines the gl::Compiler class, abstracting the ESSL compiler +// that a GL context holds. + +#ifndef LIBANGLE_COMPILER_H_ +#define LIBANGLE_COMPILER_H_ + +#include "libANGLE/Error.h" + +namespace rx +{ +class CompilerImpl; +} + +namespace gl +{ + +class Compiler final +{ + public: + explicit Compiler(rx::CompilerImpl *impl); + ~Compiler(); + + Error release(); + + rx::CompilerImpl *getImplementation(); + + private: + rx::CompilerImpl *mCompiler; +}; + +} + +#endif // LIBANGLE_COMPILER_H_ diff --git a/src/3rdparty/angle/src/libANGLE/Config.cpp b/src/3rdparty/angle/src/libANGLE/Config.cpp new file mode 100644 index 0000000000..1b1fc50cb3 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/Config.cpp @@ -0,0 +1,275 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Config.cpp: Implements the egl::Config class, describing the format, type +// and size for an egl::Surface. Implements EGLConfig and related functionality. +// [EGL 1.5] section 3.4 page 19. + +#include "libANGLE/Config.h" +#include "libANGLE/AttributeMap.h" + +#include +#include + +#include "angle_gl.h" +#include + +#include "common/debug.h" + +namespace egl +{ + +Config::Config() + : renderTargetFormat(GL_NONE), + depthStencilFormat(GL_NONE), + bufferSize(0), + redSize(0), + greenSize(0), + blueSize(0), + luminanceSize(0), + alphaSize(0), + alphaMaskSize(0), + bindToTextureRGB(EGL_FALSE), + bindToTextureRGBA(EGL_FALSE), + colorBufferType(EGL_NONE), + configCaveat(EGL_NONE), + configID(0), + conformant(0), + depthSize(0), + level(0), + matchNativePixmap(EGL_FALSE), + maxPBufferWidth(0), + maxPBufferHeight(0), + maxPBufferPixels(0), + maxSwapInterval(0), + minSwapInterval(0), + nativeRenderable(EGL_FALSE), + nativeVisualID(0), + nativeVisualType(0), + renderableType(0), + sampleBuffers(0), + samples(0), + stencilSize(0), + surfaceType(0), + transparentType(EGL_NONE), + transparentRedValue(0), + transparentGreenValue(0), + transparentBlueValue(0) +{ +} + +EGLint ConfigSet::add(const Config &config) +{ + // Set the config's ID to a small number that starts at 1 ([EGL 1.5] section 3.4) + EGLint id = mConfigs.size() + 1; + + Config copyConfig(config); + copyConfig.configID = id; + mConfigs.insert(std::make_pair(id, copyConfig)); + + return id; +} + +const Config &ConfigSet::get(EGLint id) const +{ + ASSERT(mConfigs.find(id) != mConfigs.end()); + return mConfigs.find(id)->second; +} + +void ConfigSet::clear() +{ + mConfigs.clear(); +} + +size_t ConfigSet::size() const +{ + return mConfigs.size(); +} + +bool ConfigSet::contains(const Config *config) const +{ + for (auto i = mConfigs.begin(); i != mConfigs.end(); i++) + { + const Config &item = i->second; + if (config == &item) + { + return true; + } + } + + return false; +} + +// Function object used by STL sorting routines for ordering Configs according to [EGL 1.5] section 3.4.1.2 page 28. +class ConfigSorter +{ + public: + explicit ConfigSorter(const AttributeMap &attributeMap) + : mWantRed(false), + mWantGreen(false), + mWantBlue(false), + mWantAlpha(false), + mWantLuminance(false) + { + scanForWantedComponents(attributeMap); + } + + bool operator()(const Config *x, const Config *y) const + { + return (*this)(*x, *y); + } + + bool operator()(const Config &x, const Config &y) const + { + #define SORT(attribute) \ + if (x.attribute != y.attribute) \ + { \ + return x.attribute < y.attribute; \ + } + + static_assert(EGL_NONE < EGL_SLOW_CONFIG && EGL_SLOW_CONFIG < EGL_NON_CONFORMANT_CONFIG, "Unexpected EGL enum value."); + SORT(configCaveat); + + static_assert(EGL_RGB_BUFFER < EGL_LUMINANCE_BUFFER, "Unexpected EGL enum value."); + SORT(colorBufferType); + + // By larger total number of color bits, only considering those that are requested to be > 0. + EGLint xComponentsSize = wantedComponentsSize(x); + EGLint yComponentsSize = wantedComponentsSize(y); + if (xComponentsSize != yComponentsSize) + { + return xComponentsSize > yComponentsSize; + } + + SORT(bufferSize); + SORT(sampleBuffers); + SORT(samples); + SORT(depthSize); + SORT(stencilSize); + SORT(alphaMaskSize); + SORT(nativeVisualType); + SORT(configID); + + #undef SORT + + return false; + } + + private: + void scanForWantedComponents(const AttributeMap &attributeMap) + { + // [EGL 1.5] section 3.4.1.2 page 30 + // Sorting rule #3: by larger total number of color bits, not considering + // components that are 0 or don't-care. + for (auto attribIter = attributeMap.begin(); attribIter != attributeMap.end(); attribIter++) + { + EGLint attributeKey = attribIter->first; + EGLint attributeValue = attribIter->second; + if (attributeKey != 0 && attributeValue != EGL_DONT_CARE) + { + switch (attributeKey) + { + case EGL_RED_SIZE: mWantRed = true; break; + case EGL_GREEN_SIZE: mWantGreen = true; break; + case EGL_BLUE_SIZE: mWantBlue = true; break; + case EGL_ALPHA_SIZE: mWantAlpha = true; break; + case EGL_LUMINANCE_SIZE: mWantLuminance = true; break; + } + } + } + } + + EGLint wantedComponentsSize(const Config &config) const + { + EGLint total = 0; + + if (mWantRed) total += config.redSize; + if (mWantGreen) total += config.greenSize; + if (mWantBlue) total += config.blueSize; + if (mWantAlpha) total += config.alphaSize; + if (mWantLuminance) total += config.luminanceSize; + + return total; + } + + bool mWantRed; + bool mWantGreen; + bool mWantBlue; + bool mWantAlpha; + bool mWantLuminance; +}; + +std::vector ConfigSet::filter(const AttributeMap &attributeMap) const +{ + std::vector result; + result.reserve(mConfigs.size()); + + for (auto configIter = mConfigs.begin(); configIter != mConfigs.end(); configIter++) + { + const Config &config = configIter->second; + bool match = true; + + for (auto attribIter = attributeMap.begin(); attribIter != attributeMap.end(); attribIter++) + { + EGLint attributeKey = attribIter->first; + EGLint attributeValue = attribIter->second; + + switch (attributeKey) + { + case EGL_BUFFER_SIZE: match = config.bufferSize >= attributeValue; break; + case EGL_ALPHA_SIZE: match = config.alphaSize >= attributeValue; break; + case EGL_BLUE_SIZE: match = config.blueSize >= attributeValue; break; + case EGL_GREEN_SIZE: match = config.greenSize >= attributeValue; break; + case EGL_RED_SIZE: match = config.redSize >= attributeValue; break; + case EGL_DEPTH_SIZE: match = config.depthSize >= attributeValue; break; + case EGL_STENCIL_SIZE: match = config.stencilSize >= attributeValue; break; + case EGL_CONFIG_CAVEAT: match = config.configCaveat == (EGLenum)attributeValue; break; + case EGL_CONFIG_ID: match = config.configID == attributeValue; break; + case EGL_LEVEL: match = config.level >= attributeValue; break; + case EGL_NATIVE_RENDERABLE: match = config.nativeRenderable == (EGLBoolean)attributeValue; break; + case EGL_NATIVE_VISUAL_TYPE: match = config.nativeVisualType == attributeValue; break; + case EGL_SAMPLES: match = config.samples >= attributeValue; break; + case EGL_SAMPLE_BUFFERS: match = config.sampleBuffers >= attributeValue; break; + case EGL_SURFACE_TYPE: match = (config.surfaceType & attributeValue) == attributeValue; break; + case EGL_TRANSPARENT_TYPE: match = config.transparentType == (EGLenum)attributeValue; break; + case EGL_TRANSPARENT_BLUE_VALUE: match = config.transparentBlueValue == attributeValue; break; + case EGL_TRANSPARENT_GREEN_VALUE: match = config.transparentGreenValue == attributeValue; break; + case EGL_TRANSPARENT_RED_VALUE: match = config.transparentRedValue == attributeValue; break; + case EGL_BIND_TO_TEXTURE_RGB: match = config.bindToTextureRGB == (EGLBoolean)attributeValue; break; + case EGL_BIND_TO_TEXTURE_RGBA: match = config.bindToTextureRGBA == (EGLBoolean)attributeValue; break; + case EGL_MIN_SWAP_INTERVAL: match = config.minSwapInterval == attributeValue; break; + case EGL_MAX_SWAP_INTERVAL: match = config.maxSwapInterval == attributeValue; break; + case EGL_LUMINANCE_SIZE: match = config.luminanceSize >= attributeValue; break; + case EGL_ALPHA_MASK_SIZE: match = config.alphaMaskSize >= attributeValue; break; + case EGL_COLOR_BUFFER_TYPE: match = config.colorBufferType == (EGLenum)attributeValue; break; + case EGL_RENDERABLE_TYPE: match = (config.renderableType & attributeValue) == attributeValue; break; + case EGL_MATCH_NATIVE_PIXMAP: match = false; UNIMPLEMENTED(); break; + case EGL_CONFORMANT: match = (config.conformant & attributeValue) == attributeValue; break; + case EGL_MAX_PBUFFER_WIDTH: match = config.maxPBufferWidth >= attributeValue; break; + case EGL_MAX_PBUFFER_HEIGHT: match = config.maxPBufferHeight >= attributeValue; break; + case EGL_MAX_PBUFFER_PIXELS: match = config.maxPBufferPixels >= attributeValue; break; + default: UNREACHABLE(); + } + + if (!match) + { + break; + } + } + + if (match) + { + result.push_back(&config); + } + } + + // Sort the result + std::sort(result.begin(), result.end(), ConfigSorter(attributeMap)); + + return result; +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/Config.h b/src/3rdparty/angle/src/libANGLE/Config.h new file mode 100644 index 0000000000..aed8aedb1d --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/Config.h @@ -0,0 +1,91 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Config.h: Defines the egl::Config class, describing the format, type +// and size for an egl::Surface. Implements EGLConfig and related functionality. +// [EGL 1.5] section 3.4 page 19. + +#ifndef INCLUDE_CONFIG_H_ +#define INCLUDE_CONFIG_H_ + +#include "libANGLE/AttributeMap.h" + +#include "common/angleutils.h" + +#include +#include + +#include +#include + +namespace egl +{ + +struct Config +{ + Config(); + + GLenum renderTargetFormat; // TODO(geofflang): remove this + GLenum depthStencilFormat; // TODO(geofflang): remove this + + EGLint bufferSize; // Depth of the color buffer + EGLint redSize; // Bits of Red in the color buffer + EGLint greenSize; // Bits of Green in the color buffer + EGLint blueSize; // Bits of Blue in the color buffer + EGLint luminanceSize; // Bits of Luminance in the color buffer + EGLint alphaSize; // Bits of Alpha in the color buffer + EGLint alphaMaskSize; // Bits of Alpha Mask in the mask buffer + EGLBoolean bindToTextureRGB; // True if bindable to RGB textures. + EGLBoolean bindToTextureRGBA; // True if bindable to RGBA textures. + EGLenum colorBufferType; // Color buffer type + EGLenum configCaveat; // Any caveats for the configuration + EGLint configID; // Unique EGLConfig identifier + EGLint conformant; // Whether contexts created with this config are conformant + EGLint depthSize; // Bits of Z in the depth buffer + EGLint level; // Frame buffer level + EGLBoolean matchNativePixmap; // Match the native pixmap format + EGLint maxPBufferWidth; // Maximum width of pbuffer + EGLint maxPBufferHeight; // Maximum height of pbuffer + EGLint maxPBufferPixels; // Maximum size of pbuffer + EGLint maxSwapInterval; // Maximum swap interval + EGLint minSwapInterval; // Minimum swap interval + EGLBoolean nativeRenderable; // EGL_TRUE if native rendering APIs can render to surface + EGLint nativeVisualID; // Handle of corresponding native visual + EGLint nativeVisualType; // Native visual type of the associated visual + EGLint renderableType; // Which client rendering APIs are supported. + EGLint sampleBuffers; // Number of multisample buffers + EGLint samples; // Number of samples per pixel + EGLint stencilSize; // Bits of Stencil in the stencil buffer + EGLint surfaceType; // Which types of EGL surfaces are supported. + EGLenum transparentType; // Type of transparency supported + EGLint transparentRedValue; // Transparent red value + EGLint transparentGreenValue; // Transparent green value + EGLint transparentBlueValue; // Transparent blue value +}; + +class ConfigSet +{ + public: + EGLint add(const Config &config); + const Config &get(EGLint id) const; + + void clear(); + + size_t size() const; + + bool contains(const Config *config) const; + + // Filter configurations based on the table in [EGL 1.5] section 3.4.1.2 page 29 + std::vector filter(const AttributeMap &attributeMap) const; + + private: + typedef std::map ConfigMap; + ConfigMap mConfigs; +}; + +} + +#endif // INCLUDE_CONFIG_H_ diff --git a/src/3rdparty/angle/src/libANGLE/Constants.h b/src/3rdparty/angle/src/libANGLE/Constants.h new file mode 100644 index 0000000000..dc8f9555b8 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/Constants.h @@ -0,0 +1,44 @@ +// +// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Contants.h: Defines some implementation specific and gl constants + +#ifndef LIBANGLE_CONSTANTS_H_ +#define LIBANGLE_CONSTANTS_H_ + +namespace gl +{ + +enum +{ + MAX_VERTEX_ATTRIBS = 16, + + // Implementation upper limits, real maximums depend on the hardware + IMPLEMENTATION_MAX_VARYING_VECTORS = 32, + IMPLEMENTATION_MAX_DRAW_BUFFERS = 8, + IMPLEMENTATION_MAX_FRAMEBUFFER_ATTACHMENTS = IMPLEMENTATION_MAX_DRAW_BUFFERS + 2, // 2 extra for depth and/or stencil buffers + + IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS = 16, + IMPLEMENTATION_MAX_FRAGMENT_SHADER_UNIFORM_BUFFERS = 16, + IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS = IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS + + IMPLEMENTATION_MAX_FRAGMENT_SHADER_UNIFORM_BUFFERS, + + IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS = 4, + + // These are the maximums the implementation can support + // The actual GL caps are limited by the device caps + // and should be queried from the Context + IMPLEMENTATION_MAX_2D_TEXTURE_SIZE = 16384, + IMPLEMENTATION_MAX_CUBE_MAP_TEXTURE_SIZE = 16384, + IMPLEMENTATION_MAX_3D_TEXTURE_SIZE = 2048, + IMPLEMENTATION_MAX_2D_ARRAY_TEXTURE_LAYERS = 2048, + + IMPLEMENTATION_MAX_TEXTURE_LEVELS = 15 // 1+log2 of MAX_TEXTURE_SIZE +}; + +} + +#endif // LIBANGLE_CONSTANTS_H_ diff --git a/src/3rdparty/angle/src/libANGLE/Context.cpp b/src/3rdparty/angle/src/libANGLE/Context.cpp new file mode 100644 index 0000000000..1da5fdae95 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/Context.cpp @@ -0,0 +1,1587 @@ +// +// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Context.cpp: Implements the gl::Context class, managing all GL state and performing +// rendering operations. It is the GLES2 specific implementation of EGLContext. + +#include "libANGLE/Context.h" + +#include +#include + +#include "common/platform.h" +#include "common/utilities.h" +#include "libANGLE/Buffer.h" +#include "libANGLE/Compiler.h" +#include "libANGLE/Display.h" +#include "libANGLE/Fence.h" +#include "libANGLE/Framebuffer.h" +#include "libANGLE/FramebufferAttachment.h" +#include "libANGLE/Program.h" +#include "libANGLE/Query.h" +#include "libANGLE/Renderbuffer.h" +#include "libANGLE/ResourceManager.h" +#include "libANGLE/Sampler.h" +#include "libANGLE/Surface.h" +#include "libANGLE/Texture.h" +#include "libANGLE/TransformFeedback.h" +#include "libANGLE/VertexArray.h" +#include "libANGLE/formatutils.h" +#include "libANGLE/validationES.h" +#include "libANGLE/renderer/Renderer.h" + +namespace gl +{ + +Context::Context(const egl::Config *config, int clientVersion, const Context *shareContext, rx::Renderer *renderer, bool notifyResets, bool robustAccess) + : mRenderer(renderer) +{ + ASSERT(robustAccess == false); // Unimplemented + + initCaps(clientVersion); + mState.initialize(mCaps, clientVersion); + + mClientVersion = clientVersion; + + mConfigID = config->configID; + mClientType = EGL_OPENGL_ES_API; + mRenderBuffer = EGL_NONE; + + mFenceNVHandleAllocator.setBaseHandle(0); + + if (shareContext != NULL) + { + mResourceManager = shareContext->mResourceManager; + mResourceManager->addRef(); + } + else + { + mResourceManager = new ResourceManager(mRenderer); + } + + // [OpenGL ES 2.0.24] section 3.7 page 83: + // In the initial state, TEXTURE_2D and TEXTURE_CUBE_MAP have twodimensional + // and cube map texture state vectors respectively associated with them. + // In order that access to these initial textures not be lost, they are treated as texture + // objects all of whose names are 0. + + Texture *zeroTexture2D = new Texture(mRenderer->createTexture(GL_TEXTURE_2D), 0, GL_TEXTURE_2D); + mZeroTextures[GL_TEXTURE_2D].set(zeroTexture2D); + + Texture *zeroTextureCube = new Texture(mRenderer->createTexture(GL_TEXTURE_CUBE_MAP), 0, GL_TEXTURE_CUBE_MAP); + mZeroTextures[GL_TEXTURE_CUBE_MAP].set(zeroTextureCube); + + if (mClientVersion >= 3) + { + // TODO: These could also be enabled via extension + Texture *zeroTexture3D = new Texture(mRenderer->createTexture(GL_TEXTURE_3D), 0, GL_TEXTURE_3D); + mZeroTextures[GL_TEXTURE_3D].set(zeroTexture3D); + + Texture *zeroTexture2DArray = new Texture(mRenderer->createTexture(GL_TEXTURE_2D_ARRAY), 0, GL_TEXTURE_2D_ARRAY); + mZeroTextures[GL_TEXTURE_2D_ARRAY].set(zeroTexture2DArray); + } + + mState.initializeZeroTextures(mZeroTextures); + + bindVertexArray(0); + bindArrayBuffer(0); + bindElementArrayBuffer(0); + + bindReadFramebuffer(0); + bindDrawFramebuffer(0); + bindRenderbuffer(0); + + bindGenericUniformBuffer(0); + for (unsigned int i = 0; i < mCaps.maxCombinedUniformBlocks; i++) + { + bindIndexedUniformBuffer(0, i, 0, -1); + } + + bindGenericTransformFeedbackBuffer(0); + for (unsigned int i = 0; i < mCaps.maxTransformFeedbackSeparateAttributes; i++) + { + bindIndexedTransformFeedbackBuffer(0, i, 0, -1); + } + + bindCopyReadBuffer(0); + bindCopyWriteBuffer(0); + bindPixelPackBuffer(0); + bindPixelUnpackBuffer(0); + + // [OpenGL ES 3.0.2] section 2.14.1 pg 85: + // In the initial state, a default transform feedback object is bound and treated as + // a transform feedback object with a name of zero. That object is bound any time + // BindTransformFeedback is called with id of zero + mTransformFeedbackZero.set(new TransformFeedback(mRenderer->createTransformFeedback(), 0)); + bindTransformFeedback(0); + + mHasBeenCurrent = false; + mContextLost = false; + mResetStatus = GL_NO_ERROR; + mResetStrategy = (notifyResets ? GL_LOSE_CONTEXT_ON_RESET_EXT : GL_NO_RESET_NOTIFICATION_EXT); + mRobustAccess = robustAccess; + + mCompiler = new Compiler(mRenderer->createCompiler(getData())); +} + +Context::~Context() +{ + mState.reset(); + + while (!mFramebufferMap.empty()) + { + // Delete the framebuffer in reverse order to destroy the framebuffer zero last. + deleteFramebuffer(mFramebufferMap.rbegin()->first); + } + + while (!mFenceNVMap.empty()) + { + deleteFenceNV(mFenceNVMap.begin()->first); + } + + while (!mQueryMap.empty()) + { + deleteQuery(mQueryMap.begin()->first); + } + + while (!mVertexArrayMap.empty()) + { + deleteVertexArray(mVertexArrayMap.begin()->first); + } + + mTransformFeedbackZero.set(NULL); + while (!mTransformFeedbackMap.empty()) + { + deleteTransformFeedback(mTransformFeedbackMap.begin()->first); + } + + for (auto it = mZeroTextures.begin(); it != mZeroTextures.end(); ++it) + { + it->second.set(NULL); + } + mZeroTextures.clear(); + + if (mResourceManager) + { + mResourceManager->release(); + } + + SafeDelete(mCompiler); +} + +void Context::makeCurrent(egl::Surface *surface) +{ + if (!mHasBeenCurrent) + { + initRendererString(); + initExtensionStrings(); + + mState.setViewportParams(0, 0, surface->getWidth(), surface->getHeight()); + mState.setScissorParams(0, 0, surface->getWidth(), surface->getHeight()); + + mHasBeenCurrent = true; + } + + // TODO(jmadill): do not allocate new pointers here + Framebuffer *framebufferZero = new DefaultFramebuffer(mCaps, mRenderer, surface); + + setFramebufferZero(framebufferZero); + + mRenderBuffer = surface->getRenderBuffer(); +} + +// NOTE: this function should not assume that this context is current! +void Context::markContextLost() +{ + if (mResetStrategy == GL_LOSE_CONTEXT_ON_RESET_EXT) + mResetStatus = GL_UNKNOWN_CONTEXT_RESET_EXT; + mContextLost = true; +} + +bool Context::isContextLost() +{ + return mContextLost; +} + +GLuint Context::createBuffer() +{ + return mResourceManager->createBuffer(); +} + +GLuint Context::createProgram() +{ + return mResourceManager->createProgram(); +} + +GLuint Context::createShader(GLenum type) +{ + return mResourceManager->createShader(getData(), type); +} + +GLuint Context::createTexture() +{ + return mResourceManager->createTexture(); +} + +GLuint Context::createRenderbuffer() +{ + return mResourceManager->createRenderbuffer(); +} + +GLsync Context::createFenceSync() +{ + GLuint handle = mResourceManager->createFenceSync(); + + return reinterpret_cast(static_cast(handle)); +} + +GLuint Context::createVertexArray() +{ + GLuint handle = mVertexArrayHandleAllocator.allocate(); + + // Although the spec states VAO state is not initialized until the object is bound, + // we create it immediately. The resulting behaviour is transparent to the application, + // since it's not currently possible to access the state until the object is bound. + VertexArray *vertexArray = new VertexArray(mRenderer->createVertexArray(), handle, MAX_VERTEX_ATTRIBS); + mVertexArrayMap[handle] = vertexArray; + return handle; +} + +GLuint Context::createSampler() +{ + return mResourceManager->createSampler(); +} + +GLuint Context::createTransformFeedback() +{ + GLuint handle = mTransformFeedbackAllocator.allocate(); + TransformFeedback *transformFeedback = new TransformFeedback(mRenderer->createTransformFeedback(), handle); + transformFeedback->addRef(); + mTransformFeedbackMap[handle] = transformFeedback; + return handle; +} + +// Returns an unused framebuffer name +GLuint Context::createFramebuffer() +{ + GLuint handle = mFramebufferHandleAllocator.allocate(); + + mFramebufferMap[handle] = NULL; + + return handle; +} + +GLuint Context::createFenceNV() +{ + GLuint handle = mFenceNVHandleAllocator.allocate(); + + mFenceNVMap[handle] = new FenceNV(mRenderer->createFenceNV()); + + return handle; +} + +// Returns an unused query name +GLuint Context::createQuery() +{ + GLuint handle = mQueryHandleAllocator.allocate(); + + mQueryMap[handle] = NULL; + + return handle; +} + +void Context::deleteBuffer(GLuint buffer) +{ + if (mResourceManager->getBuffer(buffer)) + { + detachBuffer(buffer); + } + + mResourceManager->deleteBuffer(buffer); +} + +void Context::deleteShader(GLuint shader) +{ + mResourceManager->deleteShader(shader); +} + +void Context::deleteProgram(GLuint program) +{ + mResourceManager->deleteProgram(program); +} + +void Context::deleteTexture(GLuint texture) +{ + if (mResourceManager->getTexture(texture)) + { + detachTexture(texture); + } + + mResourceManager->deleteTexture(texture); +} + +void Context::deleteRenderbuffer(GLuint renderbuffer) +{ + if (mResourceManager->getRenderbuffer(renderbuffer)) + { + detachRenderbuffer(renderbuffer); + } + + mResourceManager->deleteRenderbuffer(renderbuffer); +} + +void Context::deleteFenceSync(GLsync fenceSync) +{ + // The spec specifies the underlying Fence object is not deleted until all current + // wait commands finish. However, since the name becomes invalid, we cannot query the fence, + // and since our API is currently designed for being called from a single thread, we can delete + // the fence immediately. + mResourceManager->deleteFenceSync(reinterpret_cast(fenceSync)); +} + +void Context::deleteVertexArray(GLuint vertexArray) +{ + auto vertexArrayObject = mVertexArrayMap.find(vertexArray); + + if (vertexArrayObject != mVertexArrayMap.end()) + { + detachVertexArray(vertexArray); + + mVertexArrayHandleAllocator.release(vertexArrayObject->first); + delete vertexArrayObject->second; + mVertexArrayMap.erase(vertexArrayObject); + } +} + +void Context::deleteSampler(GLuint sampler) +{ + if (mResourceManager->getSampler(sampler)) + { + detachSampler(sampler); + } + + mResourceManager->deleteSampler(sampler); +} + +void Context::deleteTransformFeedback(GLuint transformFeedback) +{ + auto iter = mTransformFeedbackMap.find(transformFeedback); + if (iter != mTransformFeedbackMap.end()) + { + detachTransformFeedback(transformFeedback); + mTransformFeedbackAllocator.release(transformFeedback); + iter->second->release(); + mTransformFeedbackMap.erase(iter); + } +} + +void Context::deleteFramebuffer(GLuint framebuffer) +{ + FramebufferMap::iterator framebufferObject = mFramebufferMap.find(framebuffer); + + if (framebufferObject != mFramebufferMap.end()) + { + detachFramebuffer(framebuffer); + + mFramebufferHandleAllocator.release(framebufferObject->first); + delete framebufferObject->second; + mFramebufferMap.erase(framebufferObject); + } +} + +void Context::deleteFenceNV(GLuint fence) +{ + FenceNVMap::iterator fenceObject = mFenceNVMap.find(fence); + + if (fenceObject != mFenceNVMap.end()) + { + mFenceNVHandleAllocator.release(fenceObject->first); + delete fenceObject->second; + mFenceNVMap.erase(fenceObject); + } +} + +void Context::deleteQuery(GLuint query) +{ + QueryMap::iterator queryObject = mQueryMap.find(query); + if (queryObject != mQueryMap.end()) + { + mQueryHandleAllocator.release(queryObject->first); + if (queryObject->second) + { + queryObject->second->release(); + } + mQueryMap.erase(queryObject); + } +} + +Buffer *Context::getBuffer(GLuint handle) +{ + return mResourceManager->getBuffer(handle); +} + +Shader *Context::getShader(GLuint handle) const +{ + return mResourceManager->getShader(handle); +} + +Program *Context::getProgram(GLuint handle) const +{ + return mResourceManager->getProgram(handle); +} + +Texture *Context::getTexture(GLuint handle) const +{ + return mResourceManager->getTexture(handle); +} + +Renderbuffer *Context::getRenderbuffer(GLuint handle) +{ + return mResourceManager->getRenderbuffer(handle); +} + +FenceSync *Context::getFenceSync(GLsync handle) const +{ + return mResourceManager->getFenceSync(reinterpret_cast(handle)); +} + +VertexArray *Context::getVertexArray(GLuint handle) const +{ + auto vertexArray = mVertexArrayMap.find(handle); + + if (vertexArray == mVertexArrayMap.end()) + { + return NULL; + } + else + { + return vertexArray->second; + } +} + +Sampler *Context::getSampler(GLuint handle) const +{ + return mResourceManager->getSampler(handle); +} + +TransformFeedback *Context::getTransformFeedback(GLuint handle) const +{ + if (handle == 0) + { + return mTransformFeedbackZero.get(); + } + else + { + TransformFeedbackMap::const_iterator iter = mTransformFeedbackMap.find(handle); + return (iter != mTransformFeedbackMap.end()) ? iter->second : NULL; + } +} + +bool Context::isSampler(GLuint samplerName) const +{ + return mResourceManager->isSampler(samplerName); +} + +void Context::bindArrayBuffer(unsigned int buffer) +{ + mResourceManager->checkBufferAllocation(buffer); + + mState.setArrayBufferBinding(getBuffer(buffer)); +} + +void Context::bindElementArrayBuffer(unsigned int buffer) +{ + mResourceManager->checkBufferAllocation(buffer); + + mState.getVertexArray()->setElementArrayBuffer(getBuffer(buffer)); +} + +void Context::bindTexture(GLenum target, GLuint handle) +{ + Texture *texture = NULL; + + if (handle == 0) + { + texture = mZeroTextures[target].get(); + } + else + { + mResourceManager->checkTextureAllocation(handle, target); + texture = getTexture(handle); + } + + ASSERT(texture); + + mState.setSamplerTexture(target, texture); +} + +void Context::bindReadFramebuffer(GLuint framebuffer) +{ + if (!getFramebuffer(framebuffer)) + { + mFramebufferMap[framebuffer] = new Framebuffer(mCaps, mRenderer, framebuffer); + } + + mState.setReadFramebufferBinding(getFramebuffer(framebuffer)); +} + +void Context::bindDrawFramebuffer(GLuint framebuffer) +{ + if (!getFramebuffer(framebuffer)) + { + mFramebufferMap[framebuffer] = new Framebuffer(mCaps, mRenderer, framebuffer); + } + + mState.setDrawFramebufferBinding(getFramebuffer(framebuffer)); +} + +void Context::bindRenderbuffer(GLuint renderbuffer) +{ + mResourceManager->checkRenderbufferAllocation(renderbuffer); + + mState.setRenderbufferBinding(getRenderbuffer(renderbuffer)); +} + +void Context::bindVertexArray(GLuint vertexArray) +{ + if (!getVertexArray(vertexArray)) + { + VertexArray *vertexArrayObject = new VertexArray(mRenderer->createVertexArray(), vertexArray, MAX_VERTEX_ATTRIBS); + mVertexArrayMap[vertexArray] = vertexArrayObject; + } + + mState.setVertexArrayBinding(getVertexArray(vertexArray)); +} + +void Context::bindSampler(GLuint textureUnit, GLuint sampler) +{ + ASSERT(textureUnit < mCaps.maxCombinedTextureImageUnits); + mResourceManager->checkSamplerAllocation(sampler); + + mState.setSamplerBinding(textureUnit, getSampler(sampler)); +} + +void Context::bindGenericUniformBuffer(GLuint buffer) +{ + mResourceManager->checkBufferAllocation(buffer); + + mState.setGenericUniformBufferBinding(getBuffer(buffer)); +} + +void Context::bindIndexedUniformBuffer(GLuint buffer, GLuint index, GLintptr offset, GLsizeiptr size) +{ + mResourceManager->checkBufferAllocation(buffer); + + mState.setIndexedUniformBufferBinding(index, getBuffer(buffer), offset, size); +} + +void Context::bindGenericTransformFeedbackBuffer(GLuint buffer) +{ + mResourceManager->checkBufferAllocation(buffer); + + mState.setGenericTransformFeedbackBufferBinding(getBuffer(buffer)); +} + +void Context::bindIndexedTransformFeedbackBuffer(GLuint buffer, GLuint index, GLintptr offset, GLsizeiptr size) +{ + mResourceManager->checkBufferAllocation(buffer); + + mState.setIndexedTransformFeedbackBufferBinding(index, getBuffer(buffer), offset, size); +} + +void Context::bindCopyReadBuffer(GLuint buffer) +{ + mResourceManager->checkBufferAllocation(buffer); + + mState.setCopyReadBufferBinding(getBuffer(buffer)); +} + +void Context::bindCopyWriteBuffer(GLuint buffer) +{ + mResourceManager->checkBufferAllocation(buffer); + + mState.setCopyWriteBufferBinding(getBuffer(buffer)); +} + +void Context::bindPixelPackBuffer(GLuint buffer) +{ + mResourceManager->checkBufferAllocation(buffer); + + mState.setPixelPackBufferBinding(getBuffer(buffer)); +} + +void Context::bindPixelUnpackBuffer(GLuint buffer) +{ + mResourceManager->checkBufferAllocation(buffer); + + mState.setPixelUnpackBufferBinding(getBuffer(buffer)); +} + +void Context::useProgram(GLuint program) +{ + mState.setProgram(getProgram(program)); +} + +void Context::bindTransformFeedback(GLuint transformFeedback) +{ + mState.setTransformFeedbackBinding(getTransformFeedback(transformFeedback)); +} + +Error Context::beginQuery(GLenum target, GLuint query) +{ + Query *queryObject = getQuery(query, true, target); + ASSERT(queryObject); + + // begin query + Error error = queryObject->begin(); + if (error.isError()) + { + return error; + } + + // set query as active for specified target only if begin succeeded + mState.setActiveQuery(target, queryObject); + + return Error(GL_NO_ERROR); +} + +Error Context::endQuery(GLenum target) +{ + Query *queryObject = mState.getActiveQuery(target); + ASSERT(queryObject); + + gl::Error error = queryObject->end(); + + // Always unbind the query, even if there was an error. This may delete the query object. + mState.setActiveQuery(target, NULL); + + return error; +} + +void Context::setFramebufferZero(Framebuffer *buffer) +{ + // First, check to see if the old default framebuffer + // was set for draw or read framebuffer, and change + // the bindings to point to the new one before deleting it. + if (mState.getDrawFramebuffer()->id() == 0) + { + mState.setDrawFramebufferBinding(buffer); + } + + if (mState.getReadFramebuffer()->id() == 0) + { + mState.setReadFramebufferBinding(buffer); + } + + delete mFramebufferMap[0]; + mFramebufferMap[0] = buffer; +} + +Framebuffer *Context::getFramebuffer(unsigned int handle) const +{ + FramebufferMap::const_iterator framebuffer = mFramebufferMap.find(handle); + + if (framebuffer == mFramebufferMap.end()) + { + return NULL; + } + else + { + return framebuffer->second; + } +} + +FenceNV *Context::getFenceNV(unsigned int handle) +{ + FenceNVMap::iterator fence = mFenceNVMap.find(handle); + + if (fence == mFenceNVMap.end()) + { + return NULL; + } + else + { + return fence->second; + } +} + +Query *Context::getQuery(unsigned int handle, bool create, GLenum type) +{ + QueryMap::iterator query = mQueryMap.find(handle); + + if (query == mQueryMap.end()) + { + return NULL; + } + else + { + if (!query->second && create) + { + query->second = new Query(mRenderer->createQuery(type), handle); + query->second->addRef(); + } + return query->second; + } +} + +Texture *Context::getTargetTexture(GLenum target) const +{ + ASSERT(ValidTextureTarget(this, target)); + + return getSamplerTexture(mState.getActiveSampler(), target); +} + +Texture *Context::getSamplerTexture(unsigned int sampler, GLenum type) const +{ + return mState.getSamplerTexture(sampler, type); +} + +Compiler *Context::getCompiler() const +{ + return mCompiler; +} + +void Context::getBooleanv(GLenum pname, GLboolean *params) +{ + switch (pname) + { + case GL_SHADER_COMPILER: *params = GL_TRUE; break; + case GL_CONTEXT_ROBUST_ACCESS_EXT: *params = mRobustAccess ? GL_TRUE : GL_FALSE; break; + default: + mState.getBooleanv(pname, params); + break; + } +} + +void Context::getFloatv(GLenum pname, GLfloat *params) +{ + // Queries about context capabilities and maximums are answered by Context. + // Queries about current GL state values are answered by State. + switch (pname) + { + case GL_ALIASED_LINE_WIDTH_RANGE: + params[0] = mCaps.minAliasedLineWidth; + params[1] = mCaps.maxAliasedLineWidth; + break; + case GL_ALIASED_POINT_SIZE_RANGE: + params[0] = mCaps.minAliasedPointSize; + params[1] = mCaps.maxAliasedPointSize; + break; + case GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT: + ASSERT(mExtensions.textureFilterAnisotropic); + *params = mExtensions.maxTextureAnisotropy; + break; + default: + mState.getFloatv(pname, params); + break; + } +} + +void Context::getIntegerv(GLenum pname, GLint *params) +{ + // Queries about context capabilities and maximums are answered by Context. + // Queries about current GL state values are answered by State. + + switch (pname) + { + case GL_MAX_VERTEX_ATTRIBS: *params = mCaps.maxVertexAttributes; break; + case GL_MAX_VERTEX_UNIFORM_VECTORS: *params = mCaps.maxVertexUniformVectors; break; + case GL_MAX_VERTEX_UNIFORM_COMPONENTS: *params = mCaps.maxVertexUniformComponents; break; + case GL_MAX_VARYING_VECTORS: *params = mCaps.maxVaryingVectors; break; + case GL_MAX_VARYING_COMPONENTS: *params = mCaps.maxVertexOutputComponents; break; + case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS: *params = mCaps.maxCombinedTextureImageUnits; break; + case GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS: *params = mCaps.maxVertexTextureImageUnits; break; + case GL_MAX_TEXTURE_IMAGE_UNITS: *params = mCaps.maxTextureImageUnits; break; + case GL_MAX_FRAGMENT_UNIFORM_VECTORS: *params = mCaps.maxFragmentUniformVectors; break; + case GL_MAX_FRAGMENT_UNIFORM_COMPONENTS: *params = mCaps.maxFragmentInputComponents; break; + case GL_MAX_RENDERBUFFER_SIZE: *params = mCaps.maxRenderbufferSize; break; + case GL_MAX_COLOR_ATTACHMENTS_EXT: *params = mCaps.maxColorAttachments; break; + case GL_MAX_DRAW_BUFFERS_EXT: *params = mCaps.maxDrawBuffers; break; + //case GL_FRAMEBUFFER_BINDING: // now equivalent to GL_DRAW_FRAMEBUFFER_BINDING_ANGLE + case GL_SUBPIXEL_BITS: *params = 4; break; + case GL_MAX_TEXTURE_SIZE: *params = mCaps.max2DTextureSize; break; + case GL_MAX_CUBE_MAP_TEXTURE_SIZE: *params = mCaps.maxCubeMapTextureSize; break; + case GL_MAX_3D_TEXTURE_SIZE: *params = mCaps.max3DTextureSize; break; + case GL_MAX_ARRAY_TEXTURE_LAYERS: *params = mCaps.maxArrayTextureLayers; break; + case GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT: *params = mCaps.uniformBufferOffsetAlignment; break; + case GL_MAX_UNIFORM_BUFFER_BINDINGS: *params = mCaps.maxUniformBufferBindings; break; + case GL_MAX_VERTEX_UNIFORM_BLOCKS: *params = mCaps.maxVertexUniformBlocks; break; + case GL_MAX_FRAGMENT_UNIFORM_BLOCKS: *params = mCaps.maxFragmentUniformBlocks; break; + case GL_MAX_COMBINED_UNIFORM_BLOCKS: *params = mCaps.maxCombinedTextureImageUnits; break; + case GL_MAJOR_VERSION: *params = mClientVersion; break; + case GL_MINOR_VERSION: *params = 0; break; + case GL_MAX_ELEMENTS_INDICES: *params = mCaps.maxElementsIndices; break; + case GL_MAX_ELEMENTS_VERTICES: *params = mCaps.maxElementsVertices; break; + case GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS: *params = mCaps.maxTransformFeedbackInterleavedComponents; break; + case GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS: *params = mCaps.maxTransformFeedbackSeparateAttributes; break; + case GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS: *params = mCaps.maxTransformFeedbackSeparateComponents; break; + case GL_NUM_COMPRESSED_TEXTURE_FORMATS: *params = mCaps.compressedTextureFormats.size(); break; + case GL_MAX_SAMPLES_ANGLE: *params = mExtensions.maxSamples; break; + case GL_MAX_VIEWPORT_DIMS: + { + params[0] = mCaps.maxViewportWidth; + params[1] = mCaps.maxViewportHeight; + } + break; + case GL_COMPRESSED_TEXTURE_FORMATS: + std::copy(mCaps.compressedTextureFormats.begin(), mCaps.compressedTextureFormats.end(), params); + break; + case GL_RESET_NOTIFICATION_STRATEGY_EXT: + *params = mResetStrategy; + break; + case GL_NUM_SHADER_BINARY_FORMATS: + *params = mCaps.shaderBinaryFormats.size(); + break; + case GL_SHADER_BINARY_FORMATS: + std::copy(mCaps.shaderBinaryFormats.begin(), mCaps.shaderBinaryFormats.end(), params); + break; + case GL_NUM_PROGRAM_BINARY_FORMATS: + *params = mCaps.programBinaryFormats.size(); + break; + case GL_PROGRAM_BINARY_FORMATS: + std::copy(mCaps.programBinaryFormats.begin(), mCaps.programBinaryFormats.end(), params); + break; + case GL_NUM_EXTENSIONS: + *params = static_cast(mExtensionStrings.size()); + break; + default: + mState.getIntegerv(getData(), pname, params); + break; + } +} + +void Context::getInteger64v(GLenum pname, GLint64 *params) +{ + // Queries about context capabilities and maximums are answered by Context. + // Queries about current GL state values are answered by State. + switch (pname) + { + case GL_MAX_ELEMENT_INDEX: + *params = mCaps.maxElementIndex; + break; + case GL_MAX_UNIFORM_BLOCK_SIZE: + *params = mCaps.maxUniformBlockSize; + break; + case GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS: + *params = mCaps.maxCombinedVertexUniformComponents; + break; + case GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS: + *params = mCaps.maxCombinedFragmentUniformComponents; + break; + case GL_MAX_SERVER_WAIT_TIMEOUT: + *params = mCaps.maxServerWaitTimeout; + break; + default: + UNREACHABLE(); + break; + } +} + +bool Context::getIndexedIntegerv(GLenum target, GLuint index, GLint *data) +{ + // Queries about context capabilities and maximums are answered by Context. + // Queries about current GL state values are answered by State. + // Indexed integer queries all refer to current state, so this function is a + // mere passthrough. + return mState.getIndexedIntegerv(target, index, data); +} + +bool Context::getIndexedInteger64v(GLenum target, GLuint index, GLint64 *data) +{ + // Queries about context capabilities and maximums are answered by Context. + // Queries about current GL state values are answered by State. + // Indexed integer queries all refer to current state, so this function is a + // mere passthrough. + return mState.getIndexedInteger64v(target, index, data); +} + +bool Context::getQueryParameterInfo(GLenum pname, GLenum *type, unsigned int *numParams) +{ + if (pname >= GL_DRAW_BUFFER0_EXT && pname <= GL_DRAW_BUFFER15_EXT) + { + *type = GL_INT; + *numParams = 1; + return true; + } + + // Please note: the query type returned for DEPTH_CLEAR_VALUE in this implementation + // is FLOAT rather than INT, as would be suggested by the GL ES 2.0 spec. This is due + // to the fact that it is stored internally as a float, and so would require conversion + // if returned from Context::getIntegerv. Since this conversion is already implemented + // in the case that one calls glGetIntegerv to retrieve a float-typed state variable, we + // place DEPTH_CLEAR_VALUE with the floats. This should make no difference to the calling + // application. + switch (pname) + { + case GL_COMPRESSED_TEXTURE_FORMATS: + { + *type = GL_INT; + *numParams = mCaps.compressedTextureFormats.size(); + } + return true; + case GL_PROGRAM_BINARY_FORMATS_OES: + { + *type = GL_INT; + *numParams = mCaps.programBinaryFormats.size(); + } + return true; + case GL_SHADER_BINARY_FORMATS: + { + *type = GL_INT; + *numParams = mCaps.shaderBinaryFormats.size(); + } + return true; + + case GL_MAX_VERTEX_ATTRIBS: + case GL_MAX_VERTEX_UNIFORM_VECTORS: + case GL_MAX_VARYING_VECTORS: + case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS: + case GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS: + case GL_MAX_TEXTURE_IMAGE_UNITS: + case GL_MAX_FRAGMENT_UNIFORM_VECTORS: + case GL_MAX_RENDERBUFFER_SIZE: + case GL_MAX_COLOR_ATTACHMENTS_EXT: + case GL_MAX_DRAW_BUFFERS_EXT: + case GL_NUM_SHADER_BINARY_FORMATS: + case GL_NUM_COMPRESSED_TEXTURE_FORMATS: + case GL_ARRAY_BUFFER_BINDING: + //case GL_FRAMEBUFFER_BINDING: // equivalent to DRAW_FRAMEBUFFER_BINDING_ANGLE + case GL_DRAW_FRAMEBUFFER_BINDING_ANGLE: + case GL_READ_FRAMEBUFFER_BINDING_ANGLE: + case GL_RENDERBUFFER_BINDING: + case GL_CURRENT_PROGRAM: + case GL_PACK_ALIGNMENT: + case GL_PACK_REVERSE_ROW_ORDER_ANGLE: + case GL_UNPACK_ALIGNMENT: + case GL_GENERATE_MIPMAP_HINT: + case GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES: + case GL_RED_BITS: + case GL_GREEN_BITS: + case GL_BLUE_BITS: + case GL_ALPHA_BITS: + case GL_DEPTH_BITS: + case GL_STENCIL_BITS: + case GL_ELEMENT_ARRAY_BUFFER_BINDING: + case GL_CULL_FACE_MODE: + case GL_FRONT_FACE: + case GL_ACTIVE_TEXTURE: + case GL_STENCIL_FUNC: + case GL_STENCIL_VALUE_MASK: + case GL_STENCIL_REF: + case GL_STENCIL_FAIL: + case GL_STENCIL_PASS_DEPTH_FAIL: + case GL_STENCIL_PASS_DEPTH_PASS: + case GL_STENCIL_BACK_FUNC: + case GL_STENCIL_BACK_VALUE_MASK: + case GL_STENCIL_BACK_REF: + case GL_STENCIL_BACK_FAIL: + case GL_STENCIL_BACK_PASS_DEPTH_FAIL: + case GL_STENCIL_BACK_PASS_DEPTH_PASS: + case GL_DEPTH_FUNC: + case GL_BLEND_SRC_RGB: + case GL_BLEND_SRC_ALPHA: + case GL_BLEND_DST_RGB: + case GL_BLEND_DST_ALPHA: + case GL_BLEND_EQUATION_RGB: + case GL_BLEND_EQUATION_ALPHA: + case GL_STENCIL_WRITEMASK: + case GL_STENCIL_BACK_WRITEMASK: + case GL_STENCIL_CLEAR_VALUE: + case GL_SUBPIXEL_BITS: + case GL_MAX_TEXTURE_SIZE: + case GL_MAX_CUBE_MAP_TEXTURE_SIZE: + case GL_SAMPLE_BUFFERS: + case GL_SAMPLES: + case GL_IMPLEMENTATION_COLOR_READ_TYPE: + case GL_IMPLEMENTATION_COLOR_READ_FORMAT: + case GL_TEXTURE_BINDING_2D: + case GL_TEXTURE_BINDING_CUBE_MAP: + case GL_RESET_NOTIFICATION_STRATEGY_EXT: + case GL_NUM_PROGRAM_BINARY_FORMATS_OES: + { + *type = GL_INT; + *numParams = 1; + } + return true; + case GL_MAX_SAMPLES_ANGLE: + { + if (mExtensions.framebufferMultisample) + { + *type = GL_INT; + *numParams = 1; + } + else + { + return false; + } + } + return true; + case GL_PIXEL_PACK_BUFFER_BINDING: + case GL_PIXEL_UNPACK_BUFFER_BINDING: + { + if (mExtensions.pixelBufferObject) + { + *type = GL_INT; + *numParams = 1; + } + else + { + return false; + } + } + return true; + case GL_MAX_VIEWPORT_DIMS: + { + *type = GL_INT; + *numParams = 2; + } + return true; + case GL_VIEWPORT: + case GL_SCISSOR_BOX: + { + *type = GL_INT; + *numParams = 4; + } + return true; + case GL_SHADER_COMPILER: + case GL_SAMPLE_COVERAGE_INVERT: + case GL_DEPTH_WRITEMASK: + case GL_CULL_FACE: // CULL_FACE through DITHER are natural to IsEnabled, + case GL_POLYGON_OFFSET_FILL: // but can be retrieved through the Get{Type}v queries. + case GL_SAMPLE_ALPHA_TO_COVERAGE: // For this purpose, they are treated here as bool-natural + case GL_SAMPLE_COVERAGE: + case GL_SCISSOR_TEST: + case GL_STENCIL_TEST: + case GL_DEPTH_TEST: + case GL_BLEND: + case GL_DITHER: + case GL_CONTEXT_ROBUST_ACCESS_EXT: + { + *type = GL_BOOL; + *numParams = 1; + } + return true; + case GL_COLOR_WRITEMASK: + { + *type = GL_BOOL; + *numParams = 4; + } + return true; + case GL_POLYGON_OFFSET_FACTOR: + case GL_POLYGON_OFFSET_UNITS: + case GL_SAMPLE_COVERAGE_VALUE: + case GL_DEPTH_CLEAR_VALUE: + case GL_LINE_WIDTH: + { + *type = GL_FLOAT; + *numParams = 1; + } + return true; + case GL_ALIASED_LINE_WIDTH_RANGE: + case GL_ALIASED_POINT_SIZE_RANGE: + case GL_DEPTH_RANGE: + { + *type = GL_FLOAT; + *numParams = 2; + } + return true; + case GL_COLOR_CLEAR_VALUE: + case GL_BLEND_COLOR: + { + *type = GL_FLOAT; + *numParams = 4; + } + return true; + case GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT: + if (!mExtensions.maxTextureAnisotropy) + { + return false; + } + *type = GL_FLOAT; + *numParams = 1; + return true; + } + + if (mClientVersion < 3) + { + return false; + } + + // Check for ES3.0+ parameter names + switch (pname) + { + case GL_MAX_UNIFORM_BUFFER_BINDINGS: + case GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT: + case GL_UNIFORM_BUFFER_BINDING: + case GL_TRANSFORM_FEEDBACK_BINDING: + case GL_COPY_READ_BUFFER_BINDING: + case GL_COPY_WRITE_BUFFER_BINDING: + case GL_TEXTURE_BINDING_3D: + case GL_TEXTURE_BINDING_2D_ARRAY: + case GL_MAX_3D_TEXTURE_SIZE: + case GL_MAX_ARRAY_TEXTURE_LAYERS: + case GL_MAX_VERTEX_UNIFORM_BLOCKS: + case GL_MAX_FRAGMENT_UNIFORM_BLOCKS: + case GL_MAX_COMBINED_UNIFORM_BLOCKS: + case GL_MAX_VARYING_COMPONENTS: + case GL_VERTEX_ARRAY_BINDING: + case GL_MAX_VERTEX_UNIFORM_COMPONENTS: + case GL_MAX_FRAGMENT_UNIFORM_COMPONENTS: + case GL_NUM_EXTENSIONS: + case GL_MAJOR_VERSION: + case GL_MINOR_VERSION: + case GL_MAX_ELEMENTS_INDICES: + case GL_MAX_ELEMENTS_VERTICES: + case GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS: + case GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS: + case GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS: + { + *type = GL_INT; + *numParams = 1; + } + return true; + + case GL_MAX_ELEMENT_INDEX: + case GL_MAX_UNIFORM_BLOCK_SIZE: + case GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS: + case GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS: + case GL_MAX_SERVER_WAIT_TIMEOUT: + { + *type = GL_INT_64_ANGLEX; + *numParams = 1; + } + return true; + + case GL_TRANSFORM_FEEDBACK_ACTIVE: + case GL_TRANSFORM_FEEDBACK_PAUSED: + { + *type = GL_BOOL; + *numParams = 1; + } + return true; + } + + return false; +} + +bool Context::getIndexedQueryParameterInfo(GLenum target, GLenum *type, unsigned int *numParams) +{ + if (mClientVersion < 3) + { + return false; + } + + switch (target) + { + case GL_TRANSFORM_FEEDBACK_BUFFER_BINDING: + case GL_UNIFORM_BUFFER_BINDING: + { + *type = GL_INT; + *numParams = 1; + } + return true; + case GL_TRANSFORM_FEEDBACK_BUFFER_START: + case GL_TRANSFORM_FEEDBACK_BUFFER_SIZE: + case GL_UNIFORM_BUFFER_START: + case GL_UNIFORM_BUFFER_SIZE: + { + *type = GL_INT_64_ANGLEX; + *numParams = 1; + } + } + + return false; +} + +Error Context::drawArrays(GLenum mode, GLint first, GLsizei count, GLsizei instances) +{ + return mRenderer->drawArrays(getData(), mode, first, count, instances); +} + +Error Context::drawElements(GLenum mode, GLsizei count, GLenum type, + const GLvoid *indices, GLsizei instances, + const rx::RangeUI &indexRange) +{ + return mRenderer->drawElements(getData(), mode, count, type, indices, instances, indexRange); +} + +Error Context::flush() +{ + return mRenderer->flush(); +} + +Error Context::finish() +{ + return mRenderer->finish(); +} + +void Context::recordError(const Error &error) +{ + if (error.isError()) + { + mErrors.insert(error.getCode()); + } +} + +// Get one of the recorded errors and clear its flag, if any. +// [OpenGL ES 2.0.24] section 2.5 page 13. +GLenum Context::getError() +{ + if (mErrors.empty()) + { + return GL_NO_ERROR; + } + else + { + GLenum error = *mErrors.begin(); + mErrors.erase(mErrors.begin()); + return error; + } +} + +GLenum Context::getResetStatus() +{ + //TODO(jmadill): needs MANGLE reworking + if (mResetStatus == GL_NO_ERROR && !mContextLost) + { + // mResetStatus will be set by the markContextLost callback + // in the case a notification is sent + if (mRenderer->testDeviceLost()) + { + mRenderer->notifyDeviceLost(); + } + } + + GLenum status = mResetStatus; + + if (mResetStatus != GL_NO_ERROR) + { + ASSERT(mContextLost); + + if (mRenderer->testDeviceResettable()) + { + mResetStatus = GL_NO_ERROR; + } + } + + return status; +} + +bool Context::isResetNotificationEnabled() +{ + return (mResetStrategy == GL_LOSE_CONTEXT_ON_RESET_EXT); +} + +int Context::getClientVersion() const +{ + return mClientVersion; +} + +EGLint Context::getConfigID() const +{ + return mConfigID; +} + +EGLenum Context::getClientType() const +{ + return mClientType; +} + +EGLenum Context::getRenderBuffer() const +{ + return mRenderBuffer; +} + +const Caps &Context::getCaps() const +{ + return mCaps; +} + +const TextureCapsMap &Context::getTextureCaps() const +{ + return mTextureCaps; +} + +const Extensions &Context::getExtensions() const +{ + return mExtensions; +} + +void Context::detachTexture(GLuint texture) +{ + // Simple pass-through to State's detachTexture method, as textures do not require + // allocation map management either here or in the resource manager at detach time. + // Zero textures are held by the Context, and we don't attempt to request them from + // the State. + mState.detachTexture(mZeroTextures, texture); +} + +void Context::detachBuffer(GLuint buffer) +{ + // Buffer detachment is handled by Context, because the buffer must also be + // attached from any VAOs in existence, and Context holds the VAO map. + + // [OpenGL ES 2.0.24] section 2.9 page 22: + // If a buffer object is deleted while it is bound, all bindings to that object in the current context + // (i.e. in the thread that called Delete-Buffers) are reset to zero. + + mState.removeArrayBufferBinding(buffer); + + // mark as freed among the vertex array objects + for (auto vaoIt = mVertexArrayMap.begin(); vaoIt != mVertexArrayMap.end(); vaoIt++) + { + vaoIt->second->detachBuffer(buffer); + } +} + +void Context::detachFramebuffer(GLuint framebuffer) +{ + // Framebuffer detachment is handled by Context, because 0 is a valid + // Framebuffer object, and a pointer to it must be passed from Context + // to State at binding time. + + // [OpenGL ES 2.0.24] section 4.4 page 107: + // If a framebuffer that is currently bound to the target FRAMEBUFFER is deleted, it is as though + // BindFramebuffer had been executed with the target of FRAMEBUFFER and framebuffer of zero. + + if (mState.removeReadFramebufferBinding(framebuffer) && framebuffer != 0) + { + bindReadFramebuffer(0); + } + + if (mState.removeDrawFramebufferBinding(framebuffer) && framebuffer != 0) + { + bindDrawFramebuffer(0); + } +} + +void Context::detachRenderbuffer(GLuint renderbuffer) +{ + mState.detachRenderbuffer(renderbuffer); +} + +void Context::detachVertexArray(GLuint vertexArray) +{ + // Vertex array detachment is handled by Context, because 0 is a valid + // VAO, and a pointer to it must be passed from Context to State at + // binding time. + + // [OpenGL ES 3.0.2] section 2.10 page 43: + // If a vertex array object that is currently bound is deleted, the binding + // for that object reverts to zero and the default vertex array becomes current. + if (mState.removeVertexArrayBinding(vertexArray)) + { + bindVertexArray(0); + } +} + +void Context::detachTransformFeedback(GLuint transformFeedback) +{ + mState.detachTransformFeedback(transformFeedback); +} + +void Context::detachSampler(GLuint sampler) +{ + mState.detachSampler(sampler); +} + +void Context::setVertexAttribDivisor(GLuint index, GLuint divisor) +{ + mState.getVertexArray()->setVertexAttribDivisor(index, divisor); +} + +void Context::samplerParameteri(GLuint sampler, GLenum pname, GLint param) +{ + mResourceManager->checkSamplerAllocation(sampler); + + Sampler *samplerObject = getSampler(sampler); + ASSERT(samplerObject); + + switch (pname) + { + case GL_TEXTURE_MIN_FILTER: samplerObject->setMinFilter(static_cast(param)); break; + case GL_TEXTURE_MAG_FILTER: samplerObject->setMagFilter(static_cast(param)); break; + case GL_TEXTURE_WRAP_S: samplerObject->setWrapS(static_cast(param)); break; + case GL_TEXTURE_WRAP_T: samplerObject->setWrapT(static_cast(param)); break; + case GL_TEXTURE_WRAP_R: samplerObject->setWrapR(static_cast(param)); break; + case GL_TEXTURE_MIN_LOD: samplerObject->setMinLod(static_cast(param)); break; + case GL_TEXTURE_MAX_LOD: samplerObject->setMaxLod(static_cast(param)); break; + case GL_TEXTURE_COMPARE_MODE: samplerObject->setComparisonMode(static_cast(param)); break; + case GL_TEXTURE_COMPARE_FUNC: samplerObject->setComparisonFunc(static_cast(param)); break; + default: UNREACHABLE(); break; + } +} + +void Context::samplerParameterf(GLuint sampler, GLenum pname, GLfloat param) +{ + mResourceManager->checkSamplerAllocation(sampler); + + Sampler *samplerObject = getSampler(sampler); + ASSERT(samplerObject); + + switch (pname) + { + case GL_TEXTURE_MIN_FILTER: samplerObject->setMinFilter(uiround(param)); break; + case GL_TEXTURE_MAG_FILTER: samplerObject->setMagFilter(uiround(param)); break; + case GL_TEXTURE_WRAP_S: samplerObject->setWrapS(uiround(param)); break; + case GL_TEXTURE_WRAP_T: samplerObject->setWrapT(uiround(param)); break; + case GL_TEXTURE_WRAP_R: samplerObject->setWrapR(uiround(param)); break; + case GL_TEXTURE_MIN_LOD: samplerObject->setMinLod(param); break; + case GL_TEXTURE_MAX_LOD: samplerObject->setMaxLod(param); break; + case GL_TEXTURE_COMPARE_MODE: samplerObject->setComparisonMode(uiround(param)); break; + case GL_TEXTURE_COMPARE_FUNC: samplerObject->setComparisonFunc(uiround(param)); break; + default: UNREACHABLE(); break; + } +} + +GLint Context::getSamplerParameteri(GLuint sampler, GLenum pname) +{ + mResourceManager->checkSamplerAllocation(sampler); + + Sampler *samplerObject = getSampler(sampler); + ASSERT(samplerObject); + + switch (pname) + { + case GL_TEXTURE_MIN_FILTER: return static_cast(samplerObject->getMinFilter()); + case GL_TEXTURE_MAG_FILTER: return static_cast(samplerObject->getMagFilter()); + case GL_TEXTURE_WRAP_S: return static_cast(samplerObject->getWrapS()); + case GL_TEXTURE_WRAP_T: return static_cast(samplerObject->getWrapT()); + case GL_TEXTURE_WRAP_R: return static_cast(samplerObject->getWrapR()); + case GL_TEXTURE_MIN_LOD: return uiround(samplerObject->getMinLod()); + case GL_TEXTURE_MAX_LOD: return uiround(samplerObject->getMaxLod()); + case GL_TEXTURE_COMPARE_MODE: return static_cast(samplerObject->getComparisonMode()); + case GL_TEXTURE_COMPARE_FUNC: return static_cast(samplerObject->getComparisonFunc()); + default: UNREACHABLE(); return 0; + } +} + +GLfloat Context::getSamplerParameterf(GLuint sampler, GLenum pname) +{ + mResourceManager->checkSamplerAllocation(sampler); + + Sampler *samplerObject = getSampler(sampler); + ASSERT(samplerObject); + + switch (pname) + { + case GL_TEXTURE_MIN_FILTER: return static_cast(samplerObject->getMinFilter()); + case GL_TEXTURE_MAG_FILTER: return static_cast(samplerObject->getMagFilter()); + case GL_TEXTURE_WRAP_S: return static_cast(samplerObject->getWrapS()); + case GL_TEXTURE_WRAP_T: return static_cast(samplerObject->getWrapT()); + case GL_TEXTURE_WRAP_R: return static_cast(samplerObject->getWrapR()); + case GL_TEXTURE_MIN_LOD: return samplerObject->getMinLod(); + case GL_TEXTURE_MAX_LOD: return samplerObject->getMaxLod(); + case GL_TEXTURE_COMPARE_MODE: return static_cast(samplerObject->getComparisonMode()); + case GL_TEXTURE_COMPARE_FUNC: return static_cast(samplerObject->getComparisonFunc()); + default: UNREACHABLE(); return 0; + } +} + +void Context::initRendererString() +{ + std::ostringstream rendererString; + rendererString << "ANGLE ("; + rendererString << mRenderer->getRendererDescription(); + rendererString << ")"; + + mRendererString = MakeStaticString(rendererString.str()); +} + +const std::string &Context::getRendererString() const +{ + return mRendererString; +} + +void Context::initExtensionStrings() +{ + mExtensionStrings = mExtensions.getStrings(); + + std::ostringstream combinedStringStream; + std::copy(mExtensionStrings.begin(), mExtensionStrings.end(), std::ostream_iterator(combinedStringStream, " ")); + mExtensionString = combinedStringStream.str(); +} + +const std::string &Context::getExtensionString() const +{ + return mExtensionString; +} + +const std::string &Context::getExtensionString(size_t idx) const +{ + return mExtensionStrings[idx]; +} + +size_t Context::getExtensionStringCount() const +{ + return mExtensionStrings.size(); +} + +void Context::initCaps(GLuint clientVersion) +{ + mCaps = mRenderer->getRendererCaps(); + + mExtensions = mRenderer->getRendererExtensions(); + + if (clientVersion < 3) + { + // Disable ES3+ extensions + mExtensions.colorBufferFloat = false; + } + + if (clientVersion > 2) + { + // FIXME(geofflang): Don't support EXT_sRGB in non-ES2 contexts + //mExtensions.sRGB = false; + } + + // Apply implementation limits + mCaps.maxVertexAttributes = std::min(mCaps.maxVertexAttributes, MAX_VERTEX_ATTRIBS); + mCaps.maxVertexUniformBlocks = std::min(mCaps.maxVertexUniformBlocks, IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS); + mCaps.maxVertexOutputComponents = std::min(mCaps.maxVertexOutputComponents, IMPLEMENTATION_MAX_VARYING_VECTORS * 4); + + mCaps.maxFragmentInputComponents = std::min(mCaps.maxFragmentInputComponents, IMPLEMENTATION_MAX_VARYING_VECTORS * 4); + + GLuint maxSamples = 0; + mCaps.compressedTextureFormats.clear(); + + const TextureCapsMap &rendererFormats = mRenderer->getRendererTextureCaps(); + for (TextureCapsMap::const_iterator i = rendererFormats.begin(); i != rendererFormats.end(); i++) + { + GLenum format = i->first; + TextureCaps formatCaps = i->second; + + const InternalFormat &formatInfo = GetInternalFormatInfo(format); + + // Update the format caps based on the client version and extensions + formatCaps.texturable = formatInfo.textureSupport(clientVersion, mExtensions); + formatCaps.renderable = formatInfo.renderSupport(clientVersion, mExtensions); + formatCaps.filterable = formatInfo.filterSupport(clientVersion, mExtensions); + + // OpenGL ES does not support multisampling with integer formats + if (!formatInfo.renderSupport || formatInfo.componentType == GL_INT || formatInfo.componentType == GL_UNSIGNED_INT) + { + formatCaps.sampleCounts.clear(); + } + maxSamples = std::max(maxSamples, formatCaps.getMaxSamples()); + + if (formatCaps.texturable && formatInfo.compressed) + { + mCaps.compressedTextureFormats.push_back(format); + } + + mTextureCaps.insert(format, formatCaps); + } + + mExtensions.maxSamples = maxSamples; +} + +Data Context::getData() const +{ + return Data(mClientVersion, mState, mCaps, mTextureCaps, mExtensions, mResourceManager); +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/Context.h b/src/3rdparty/angle/src/libANGLE/Context.h new file mode 100644 index 0000000000..eeada43355 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/Context.h @@ -0,0 +1,277 @@ +// +// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Context.h: Defines the gl::Context class, managing all GL state and performing +// rendering operations. It is the GLES2 specific implementation of EGLContext. + +#ifndef LIBANGLE_CONTEXT_H_ +#define LIBANGLE_CONTEXT_H_ + +#include "common/angleutils.h" +#include "libANGLE/RefCountObject.h" +#include "libANGLE/Caps.h" +#include "libANGLE/Constants.h" +#include "libANGLE/Data.h" +#include "libANGLE/Error.h" +#include "libANGLE/HandleAllocator.h" +#include "libANGLE/VertexAttribute.h" +#include "libANGLE/angletypes.h" + +#include "angle_gl.h" + +#include +#include +#include + +namespace rx +{ +class Renderer; +} + +namespace egl +{ +class Surface; +struct Config; +} + +namespace gl +{ +class Compiler; +class Shader; +class Program; +class Texture; +class Framebuffer; +class Renderbuffer; +class FenceNV; +class FenceSync; +class Query; +class ResourceManager; +class Buffer; +struct VertexAttribute; +class VertexArray; +class Sampler; +class TransformFeedback; + +class Context final : angle::NonCopyable +{ + public: + Context(const egl::Config *config, int clientVersion, const Context *shareContext, rx::Renderer *renderer, bool notifyResets, bool robustAccess); + + virtual ~Context(); + + void makeCurrent(egl::Surface *surface); + + virtual void markContextLost(); + bool isContextLost(); + + // These create and destroy methods are merely pass-throughs to + // ResourceManager, which owns these object types + GLuint createBuffer(); + GLuint createShader(GLenum type); + GLuint createProgram(); + GLuint createTexture(); + GLuint createRenderbuffer(); + GLuint createSampler(); + GLuint createTransformFeedback(); + GLsync createFenceSync(); + + void deleteBuffer(GLuint buffer); + void deleteShader(GLuint shader); + void deleteProgram(GLuint program); + void deleteTexture(GLuint texture); + void deleteRenderbuffer(GLuint renderbuffer); + void deleteSampler(GLuint sampler); + void deleteTransformFeedback(GLuint transformFeedback); + void deleteFenceSync(GLsync fenceSync); + + // Framebuffers are owned by the Context, so these methods do not pass through + GLuint createFramebuffer(); + void deleteFramebuffer(GLuint framebuffer); + + // NV Fences are owned by the Context. + GLuint createFenceNV(); + void deleteFenceNV(GLuint fence); + + // Queries are owned by the Context; + GLuint createQuery(); + void deleteQuery(GLuint query); + + // Vertex arrays are owned by the Context + GLuint createVertexArray(); + void deleteVertexArray(GLuint vertexArray); + + void bindArrayBuffer(GLuint buffer); + void bindElementArrayBuffer(GLuint buffer); + void bindTexture(GLenum target, GLuint handle); + void bindReadFramebuffer(GLuint framebuffer); + void bindDrawFramebuffer(GLuint framebuffer); + void bindRenderbuffer(GLuint renderbuffer); + void bindVertexArray(GLuint vertexArray); + void bindSampler(GLuint textureUnit, GLuint sampler); + void bindGenericUniformBuffer(GLuint buffer); + void bindIndexedUniformBuffer(GLuint buffer, GLuint index, GLintptr offset, GLsizeiptr size); + void bindGenericTransformFeedbackBuffer(GLuint buffer); + void bindIndexedTransformFeedbackBuffer(GLuint buffer, GLuint index, GLintptr offset, GLsizeiptr size); + void bindCopyReadBuffer(GLuint buffer); + void bindCopyWriteBuffer(GLuint buffer); + void bindPixelPackBuffer(GLuint buffer); + void bindPixelUnpackBuffer(GLuint buffer); + void useProgram(GLuint program); + void bindTransformFeedback(GLuint transformFeedback); + + Error beginQuery(GLenum target, GLuint query); + Error endQuery(GLenum target); + + void setFramebufferZero(Framebuffer *framebuffer); + + void setVertexAttribDivisor(GLuint index, GLuint divisor); + + void samplerParameteri(GLuint sampler, GLenum pname, GLint param); + void samplerParameterf(GLuint sampler, GLenum pname, GLfloat param); + GLint getSamplerParameteri(GLuint sampler, GLenum pname); + GLfloat getSamplerParameterf(GLuint sampler, GLenum pname); + + Buffer *getBuffer(GLuint handle); + FenceNV *getFenceNV(GLuint handle); + FenceSync *getFenceSync(GLsync handle) const; + Shader *getShader(GLuint handle) const; + Program *getProgram(GLuint handle) const; + Texture *getTexture(GLuint handle) const; + Framebuffer *getFramebuffer(GLuint handle) const; + Renderbuffer *getRenderbuffer(GLuint handle); + VertexArray *getVertexArray(GLuint handle) const; + Sampler *getSampler(GLuint handle) const; + Query *getQuery(GLuint handle, bool create, GLenum type); + TransformFeedback *getTransformFeedback(GLuint handle) const; + + Texture *getTargetTexture(GLenum target) const; + Texture *getSamplerTexture(unsigned int sampler, GLenum type) const; + + Compiler *getCompiler() const; + + bool isSampler(GLuint samplerName) const; + + void getBooleanv(GLenum pname, GLboolean *params); + void getFloatv(GLenum pname, GLfloat *params); + void getIntegerv(GLenum pname, GLint *params); + void getInteger64v(GLenum pname, GLint64 *params); + + bool getIndexedIntegerv(GLenum target, GLuint index, GLint *data); + bool getIndexedInteger64v(GLenum target, GLuint index, GLint64 *data); + + bool getQueryParameterInfo(GLenum pname, GLenum *type, unsigned int *numParams); + bool getIndexedQueryParameterInfo(GLenum target, GLenum *type, unsigned int *numParams); + + Error drawArrays(GLenum mode, GLint first, GLsizei count, GLsizei instances); + Error drawElements(GLenum mode, GLsizei count, GLenum type, + const GLvoid *indices, GLsizei instances, + const rx::RangeUI &indexRange); + Error flush(); + Error finish(); + + void recordError(const Error &error); + + GLenum getError(); + GLenum getResetStatus(); + virtual bool isResetNotificationEnabled(); + + virtual int getClientVersion() const; + + EGLint getConfigID() const; + EGLenum getClientType() const; + EGLenum getRenderBuffer() const; + + const Caps &getCaps() const; + const TextureCapsMap &getTextureCaps() const; + const Extensions &getExtensions() const; + + const std::string &getRendererString() const; + + const std::string &getExtensionString() const; + const std::string &getExtensionString(size_t idx) const; + size_t getExtensionStringCount() const; + + rx::Renderer *getRenderer() { return mRenderer; } + + State &getState() { return mState; } + const State &getState() const { return mState; } + + Data getData() const; + + private: + void detachBuffer(GLuint buffer); + void detachTexture(GLuint texture); + void detachFramebuffer(GLuint framebuffer); + void detachRenderbuffer(GLuint renderbuffer); + void detachVertexArray(GLuint vertexArray); + void detachTransformFeedback(GLuint transformFeedback); + void detachSampler(GLuint sampler); + + void initRendererString(); + void initExtensionStrings(); + + void initCaps(GLuint clientVersion); + + // Caps to use for validation + Caps mCaps; + TextureCapsMap mTextureCaps; + Extensions mExtensions; + + // Shader compiler + Compiler *mCompiler; + + rx::Renderer *const mRenderer; + State mState; + + int mClientVersion; + + EGLint mConfigID; + EGLenum mClientType; + EGLenum mRenderBuffer; + + TextureMap mZeroTextures; + + typedef std::map FramebufferMap; + FramebufferMap mFramebufferMap; + HandleAllocator mFramebufferHandleAllocator; + + typedef std::map FenceNVMap; + FenceNVMap mFenceNVMap; + HandleAllocator mFenceNVHandleAllocator; + + typedef std::map QueryMap; + QueryMap mQueryMap; + HandleAllocator mQueryHandleAllocator; + + typedef std::map VertexArrayMap; + VertexArrayMap mVertexArrayMap; + HandleAllocator mVertexArrayHandleAllocator; + + BindingPointer mTransformFeedbackZero; + typedef std::map TransformFeedbackMap; + TransformFeedbackMap mTransformFeedbackMap; + HandleAllocator mTransformFeedbackAllocator; + + std::string mRendererString; + std::string mExtensionString; + std::vector mExtensionStrings; + + // Recorded errors + typedef std::set ErrorSet; + ErrorSet mErrors; + + // Current/lost context flags + bool mHasBeenCurrent; + bool mContextLost; + GLenum mResetStatus; + GLenum mResetStrategy; + bool mRobustAccess; + + ResourceManager *mResourceManager; +}; +} + +#endif // LIBANGLE_CONTEXT_H_ diff --git a/src/3rdparty/angle/src/libANGLE/Data.cpp b/src/3rdparty/angle/src/libANGLE/Data.cpp new file mode 100644 index 0000000000..7832e21b23 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/Data.cpp @@ -0,0 +1,51 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Data.cpp: Container class for all GL relevant state, caps and objects + +#include "libANGLE/Data.h" +#include "libANGLE/ResourceManager.h" + +namespace gl +{ + +Data::Data(GLint clientVersionIn, const State &stateIn, const Caps &capsIn, + const TextureCapsMap &textureCapsIn, const Extensions &extensionsIn, + const ResourceManager *resourceManagerIn) + : clientVersion(clientVersionIn), + state(&stateIn), + caps(&capsIn), + textureCaps(&textureCapsIn), + extensions(&extensionsIn), + resourceManager(resourceManagerIn) +{} + +Data::~Data() +{ +} + +Data::Data(const Data &other) + : clientVersion(other.clientVersion), + state(other.state), + caps(other.caps), + textureCaps(other.textureCaps), + extensions(other.extensions), + resourceManager(other.resourceManager) +{ +} + +Data &Data::operator=(const Data &other) +{ + clientVersion = other.clientVersion; + state = other.state; + caps = other.caps; + textureCaps = other.textureCaps; + extensions = other.extensions; + resourceManager = other.resourceManager; + return *this; +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/Data.h b/src/3rdparty/angle/src/libANGLE/Data.h new file mode 100644 index 0000000000..7eb6827dfc --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/Data.h @@ -0,0 +1,38 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Data.h: Container class for all GL relevant state, caps and objects + +#ifndef LIBANGLE_DATA_H_ +#define LIBANGLE_DATA_H_ + +#include "libANGLE/State.h" + +namespace gl +{ + +struct Data final +{ + public: + Data(GLint clientVersion, const State &state, const Caps &caps, + const TextureCapsMap &textureCaps, const Extensions &extensions, + const ResourceManager *resourceManager); + ~Data(); + + Data(const Data &other); + Data &operator=(const Data &other); + + GLint clientVersion; + const State *state; + const Caps *caps; + const TextureCapsMap *textureCaps; + const Extensions *extensions; + const ResourceManager *resourceManager; +}; + +} + +#endif // LIBANGLE_DATA_H_ diff --git a/src/3rdparty/angle/src/libANGLE/Display.cpp b/src/3rdparty/angle/src/libANGLE/Display.cpp new file mode 100644 index 0000000000..1f54f82dea --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/Display.cpp @@ -0,0 +1,675 @@ +// +// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Display.cpp: Implements the egl::Display class, representing the abstract +// display on which graphics are drawn. Implements EGLDisplay. +// [EGL 1.4] section 2.1.2 page 3. + +#include "libANGLE/Display.h" + +#include +#include +#include +#include +#include + +#include +#include + +#include "common/debug.h" +#include "common/mathutil.h" +#include "common/platform.h" +#include "libANGLE/Context.h" +#include "libANGLE/Surface.h" +#include "libANGLE/renderer/DisplayImpl.h" + +#if defined(ANGLE_ENABLE_D3D9) || defined(ANGLE_ENABLE_D3D11) +# include "libANGLE/renderer/d3d/DisplayD3D.h" +#endif + +#if defined(ANGLE_ENABLE_OPENGL) +# if defined(ANGLE_PLATFORM_WINDOWS) +# include "libANGLE/renderer/gl/wgl/DisplayWGL.h" +# else +# error Unsupported OpenGL platform. +# endif +#endif + +namespace egl +{ + +namespace +{ + +class DefaultPlatform : public angle::Platform +{ +public: + DefaultPlatform() {} + ~DefaultPlatform() override {} +}; + +DefaultPlatform *defaultPlatform = nullptr; + +void InitDefaultPlatformImpl() +{ + if (ANGLEPlatformCurrent() == nullptr) + { + if (defaultPlatform == nullptr) + { + defaultPlatform = new DefaultPlatform(); + } + + ANGLEPlatformInitialize(defaultPlatform); + } +} + +void DeinitDefaultPlatformImpl() +{ + if (defaultPlatform != nullptr) + { + if (ANGLEPlatformCurrent() == defaultPlatform) + { + ANGLEPlatformShutdown(); + } + + SafeDelete(defaultPlatform); + } +} + +typedef std::map WindowSurfaceMap; +// Get a map of all EGL window surfaces to validate that no window has more than one EGL surface +// associated with it. +static WindowSurfaceMap *GetWindowSurfaces() +{ + static WindowSurfaceMap windowSurfaces; + return &windowSurfaces; +} + +typedef std::map DisplayMap; +static DisplayMap *GetDisplayMap() +{ + static DisplayMap displays; + return &displays; +} + +rx::DisplayImpl *CreateDisplayImpl(const AttributeMap &attribMap) +{ + rx::DisplayImpl *impl = nullptr; + EGLint displayType = attribMap.get(EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE); + switch (displayType) + { + case EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE: +#if defined(ANGLE_ENABLE_D3D9) || defined(ANGLE_ENABLE_D3D11) + // Default to D3D displays + impl = new rx::DisplayD3D(); +#else + // No display available + UNREACHABLE(); +#endif + break; + + case EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE: + case EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE: +#if defined(ANGLE_ENABLE_D3D9) || defined(ANGLE_ENABLE_D3D11) + impl = new rx::DisplayD3D(); +#else + // A D3D display was requested on a platform that doesn't support it + UNREACHABLE(); +#endif + break; + + case EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE: +#if defined(ANGLE_ENABLE_OPENGL) +#if defined(ANGLE_PLATFORM_WINDOWS) + impl = new rx::DisplayWGL(); +#else +#error Unsupported OpenGL platform. +#endif +#else + UNREACHABLE(); +#endif + break; + + default: + UNREACHABLE(); + break; + } + + ASSERT(impl != nullptr); + return impl; +} + +} + +Display *Display::getDisplay(EGLNativeDisplayType displayId, const AttributeMap &attribMap) +{ + // Initialize the global platform if not already + InitDefaultPlatformImpl(); + + Display *display = NULL; + + DisplayMap *displays = GetDisplayMap(); + DisplayMap::const_iterator iter = displays->find(displayId); + if (iter != displays->end()) + { + display = iter->second; + } + + if (display == nullptr) + { + // Validate the native display + if (!Display::isValidNativeDisplay(displayId)) + { + return NULL; + } + + display = new Display(displayId); + displays->insert(std::make_pair(displayId, display)); + } + + // Apply new attributes if the display is not initialized yet. + if (!display->isInitialized()) + { + rx::DisplayImpl* impl = CreateDisplayImpl(attribMap); + display->setAttributes(impl, attribMap); + } + + return display; +} + +Display::Display(EGLNativeDisplayType displayId) + : mImplementation(nullptr), + mDisplayId(displayId), + mAttributeMap(), + mConfigSet(), + mContextSet(), + mInitialized(false), + mCaps(), + mDisplayExtensions(), + mDisplayExtensionString(), + mVendorString() +{ +} + +Display::~Display() +{ + terminate(); + + DisplayMap *displays = GetDisplayMap(); + DisplayMap::iterator iter = displays->find(mDisplayId); + if (iter != displays->end()) + { + displays->erase(iter); + } + + SafeDelete(mImplementation); +} + +void Display::setAttributes(rx::DisplayImpl *impl, const AttributeMap &attribMap) +{ + ASSERT(!mInitialized); + + ASSERT(impl != nullptr); + SafeDelete(mImplementation); + mImplementation = impl; + + mAttributeMap = attribMap; +} + +Error Display::initialize() +{ + ASSERT(mImplementation != nullptr); + + if (isInitialized()) + { + return Error(EGL_SUCCESS); + } + + Error error = mImplementation->initialize(this); + if (error.isError()) + { + return error; + } + + mCaps = mImplementation->getCaps(); + + mConfigSet = mImplementation->generateConfigs(); + if (mConfigSet.size() == 0) + { + mImplementation->terminate(); + return Error(EGL_NOT_INITIALIZED); + } + + initDisplayExtensions(); + initVendorString(); + + mInitialized = true; + return Error(EGL_SUCCESS); +} + +void Display::terminate() +{ + makeCurrent(nullptr, nullptr, nullptr); + + while (!mContextSet.empty()) + { + destroyContext(*mContextSet.begin()); + } + + mConfigSet.clear(); + + mImplementation->terminate(); + mInitialized = false; + + // De-init default platform + DeinitDefaultPlatformImpl(); +} + +std::vector Display::getConfigs(const egl::AttributeMap &attribs) const +{ + return mConfigSet.filter(attribs); +} + +bool Display::getConfigAttrib(const Config *configuration, EGLint attribute, EGLint *value) +{ + switch (attribute) + { + case EGL_BUFFER_SIZE: *value = configuration->bufferSize; break; + case EGL_ALPHA_SIZE: *value = configuration->alphaSize; break; + case EGL_BLUE_SIZE: *value = configuration->blueSize; break; + case EGL_GREEN_SIZE: *value = configuration->greenSize; break; + case EGL_RED_SIZE: *value = configuration->redSize; break; + case EGL_DEPTH_SIZE: *value = configuration->depthSize; break; + case EGL_STENCIL_SIZE: *value = configuration->stencilSize; break; + case EGL_CONFIG_CAVEAT: *value = configuration->configCaveat; break; + case EGL_CONFIG_ID: *value = configuration->configID; break; + case EGL_LEVEL: *value = configuration->level; break; + case EGL_NATIVE_RENDERABLE: *value = configuration->nativeRenderable; break; + case EGL_NATIVE_VISUAL_TYPE: *value = configuration->nativeVisualType; break; + case EGL_SAMPLES: *value = configuration->samples; break; + case EGL_SAMPLE_BUFFERS: *value = configuration->sampleBuffers; break; + case EGL_SURFACE_TYPE: *value = configuration->surfaceType; break; + case EGL_TRANSPARENT_TYPE: *value = configuration->transparentType; break; + case EGL_TRANSPARENT_BLUE_VALUE: *value = configuration->transparentBlueValue; break; + case EGL_TRANSPARENT_GREEN_VALUE: *value = configuration->transparentGreenValue; break; + case EGL_TRANSPARENT_RED_VALUE: *value = configuration->transparentRedValue; break; + case EGL_BIND_TO_TEXTURE_RGB: *value = configuration->bindToTextureRGB; break; + case EGL_BIND_TO_TEXTURE_RGBA: *value = configuration->bindToTextureRGBA; break; + case EGL_MIN_SWAP_INTERVAL: *value = configuration->minSwapInterval; break; + case EGL_MAX_SWAP_INTERVAL: *value = configuration->maxSwapInterval; break; + case EGL_LUMINANCE_SIZE: *value = configuration->luminanceSize; break; + case EGL_ALPHA_MASK_SIZE: *value = configuration->alphaMaskSize; break; + case EGL_COLOR_BUFFER_TYPE: *value = configuration->colorBufferType; break; + case EGL_RENDERABLE_TYPE: *value = configuration->renderableType; break; + case EGL_MATCH_NATIVE_PIXMAP: *value = false; UNIMPLEMENTED(); break; + case EGL_CONFORMANT: *value = configuration->conformant; break; + case EGL_MAX_PBUFFER_WIDTH: *value = configuration->maxPBufferWidth; break; + case EGL_MAX_PBUFFER_HEIGHT: *value = configuration->maxPBufferHeight; break; + case EGL_MAX_PBUFFER_PIXELS: *value = configuration->maxPBufferPixels; break; + default: + return false; + } + + return true; +} + +Error Display::createWindowSurface(const Config *configuration, EGLNativeWindowType window, const AttributeMap &attribs, + Surface **outSurface) +{ + if (mImplementation->testDeviceLost()) + { + Error error = restoreLostDevice(); + if (error.isError()) + { + return error; + } + } + + rx::SurfaceImpl *surfaceImpl = nullptr; + Error error = mImplementation->createWindowSurface(configuration, window, attribs, &surfaceImpl); + if (error.isError()) + { + return error; + } + + ASSERT(surfaceImpl != nullptr); + Surface *surface = new Surface(surfaceImpl, EGL_WINDOW_BIT, configuration, attribs); + mImplementation->getSurfaceSet().insert(surface); + + WindowSurfaceMap *windowSurfaces = GetWindowSurfaces(); + ASSERT(windowSurfaces && windowSurfaces->find(window) == windowSurfaces->end()); + windowSurfaces->insert(std::make_pair(window, surface)); + + ASSERT(outSurface != nullptr); + *outSurface = surface; + return Error(EGL_SUCCESS); +} + +Error Display::createPbufferSurface(const Config *configuration, const AttributeMap &attribs, Surface **outSurface) +{ + ASSERT(isInitialized()); + + if (mImplementation->testDeviceLost()) + { + Error error = restoreLostDevice(); + if (error.isError()) + { + return error; + } + } + + rx::SurfaceImpl *surfaceImpl = nullptr; + Error error = mImplementation->createPbufferSurface(configuration, attribs, &surfaceImpl); + if (error.isError()) + { + return error; + } + + ASSERT(surfaceImpl != nullptr); + Surface *surface = new Surface(surfaceImpl, EGL_PBUFFER_BIT, configuration, attribs); + mImplementation->getSurfaceSet().insert(surface); + + ASSERT(outSurface != nullptr); + *outSurface = surface; + return Error(EGL_SUCCESS); +} + +Error Display::createPbufferFromClientBuffer(const Config *configuration, EGLClientBuffer shareHandle, + const AttributeMap &attribs, Surface **outSurface) +{ + ASSERT(isInitialized()); + + if (mImplementation->testDeviceLost()) + { + Error error = restoreLostDevice(); + if (error.isError()) + { + return error; + } + } + + rx::SurfaceImpl *surfaceImpl = nullptr; + Error error = mImplementation->createPbufferFromClientBuffer(configuration, shareHandle, attribs, &surfaceImpl); + if (error.isError()) + { + return error; + } + + ASSERT(surfaceImpl != nullptr); + Surface *surface = new Surface(surfaceImpl, EGL_PBUFFER_BIT, configuration, attribs); + mImplementation->getSurfaceSet().insert(surface); + + ASSERT(outSurface != nullptr); + *outSurface = surface; + return Error(EGL_SUCCESS); +} + +Error Display::createPixmapSurface(const Config *configuration, NativePixmapType nativePixmap, const AttributeMap &attribs, + Surface **outSurface) +{ + ASSERT(isInitialized()); + + if (mImplementation->testDeviceLost()) + { + Error error = restoreLostDevice(); + if (error.isError()) + { + return error; + } + } + + rx::SurfaceImpl *surfaceImpl = nullptr; + Error error = mImplementation->createPixmapSurface(configuration, nativePixmap, attribs, &surfaceImpl); + if (error.isError()) + { + return error; + } + + ASSERT(surfaceImpl != nullptr); + Surface *surface = new Surface(surfaceImpl, EGL_PIXMAP_BIT, configuration, attribs); + mImplementation->getSurfaceSet().insert(surface); + + ASSERT(outSurface != nullptr); + *outSurface = surface; + return Error(EGL_SUCCESS); +} + +Error Display::createContext(const Config *configuration, gl::Context *shareContext, const AttributeMap &attribs, + gl::Context **outContext) +{ + ASSERT(isInitialized()); + + if (mImplementation->testDeviceLost()) + { + Error error = restoreLostDevice(); + if (error.isError()) + { + return error; + } + } + + gl::Context *context = nullptr; + Error error = mImplementation->createContext(configuration, shareContext, attribs, &context); + if (error.isError()) + { + return error; + } + + ASSERT(context != nullptr); + mContextSet.insert(context); + + ASSERT(outContext != nullptr); + *outContext = context; + return Error(EGL_SUCCESS); +} + +Error Display::makeCurrent(egl::Surface *drawSurface, egl::Surface *readSurface, gl::Context *context) +{ + Error error = mImplementation->makeCurrent(drawSurface, readSurface, context); + if (error.isError()) + { + return error; + } + + if (context && drawSurface) + { + context->makeCurrent(drawSurface); + } + + return egl::Error(EGL_SUCCESS); +} + +Error Display::restoreLostDevice() +{ + for (ContextSet::iterator ctx = mContextSet.begin(); ctx != mContextSet.end(); ctx++) + { + if ((*ctx)->isResetNotificationEnabled()) + { + // If reset notifications have been requested, application must delete all contexts first + return Error(EGL_CONTEXT_LOST); + } + } + + return mImplementation->restoreLostDevice(); +} + +void Display::destroySurface(Surface *surface) +{ + if (surface->getType() == EGL_WINDOW_BIT) + { + WindowSurfaceMap *windowSurfaces = GetWindowSurfaces(); + ASSERT(windowSurfaces); + + bool surfaceRemoved = false; + for (WindowSurfaceMap::iterator iter = windowSurfaces->begin(); iter != windowSurfaces->end(); iter++) + { + if (iter->second == surface) + { + windowSurfaces->erase(iter); + surfaceRemoved = true; + break; + } + } + + ASSERT(surfaceRemoved); + } + + mImplementation->destroySurface(surface); +} + +void Display::destroyContext(gl::Context *context) +{ + mContextSet.erase(context); + SafeDelete(context); +} + +bool Display::isDeviceLost() const +{ + ASSERT(isInitialized()); + return mImplementation->isDeviceLost(); +} + +bool Display::testDeviceLost() +{ + ASSERT(isInitialized()); + return mImplementation->testDeviceLost(); +} + +void Display::notifyDeviceLost() +{ + for (ContextSet::iterator context = mContextSet.begin(); context != mContextSet.end(); context++) + { + (*context)->markContextLost(); + } +} + +const Caps &Display::getCaps() const +{ + return mCaps; +} + +bool Display::isInitialized() const +{ + return mInitialized; +} + +bool Display::isValidConfig(const Config *config) const +{ + return mConfigSet.contains(config); +} + +bool Display::isValidContext(gl::Context *context) const +{ + return mContextSet.find(context) != mContextSet.end(); +} + +bool Display::isValidSurface(Surface *surface) const +{ + return mImplementation->getSurfaceSet().find(surface) != mImplementation->getSurfaceSet().end(); +} + +bool Display::hasExistingWindowSurface(EGLNativeWindowType window) +{ + WindowSurfaceMap *windowSurfaces = GetWindowSurfaces(); + ASSERT(windowSurfaces); + + return windowSurfaces->find(window) != windowSurfaces->end(); +} + +static ClientExtensions GenerateClientExtensions() +{ + ClientExtensions extensions; + + extensions.clientExtensions = true; + extensions.platformBase = true; + extensions.platformANGLE = true; + +#if defined(ANGLE_ENABLE_D3D9) || defined(ANGLE_ENABLE_D3D11) + extensions.platformANGLED3D = true; +#endif + +#if defined(ANGLE_ENABLE_OPENGL) + extensions.platformANGLEOpenGL = true; +#endif + + return extensions; +} + +template +static std::string GenerateExtensionsString(const T &extensions) +{ + std::vector extensionsVector = extensions.getStrings(); + + std::ostringstream stream; + std::copy(extensionsVector.begin(), extensionsVector.end(), std::ostream_iterator(stream, " ")); + return stream.str(); +} + +const ClientExtensions &Display::getClientExtensions() +{ + static const ClientExtensions clientExtensions = GenerateClientExtensions(); + return clientExtensions; +} + +const std::string &Display::getClientExtensionString() +{ + static const std::string clientExtensionsString = GenerateExtensionsString(getClientExtensions()); + return clientExtensionsString; +} + +void Display::initDisplayExtensions() +{ + mDisplayExtensions = mImplementation->getExtensions(); + mDisplayExtensionString = GenerateExtensionsString(mDisplayExtensions); +} + +bool Display::isValidNativeWindow(EGLNativeWindowType window) const +{ + return mImplementation->isValidNativeWindow(window); +} + +bool Display::isValidNativeDisplay(EGLNativeDisplayType display) +{ + // TODO(jmadill): handle this properly + if (display == EGL_DEFAULT_DISPLAY) + { + return true; + } + +#if defined(ANGLE_PLATFORM_WINDOWS) && !defined(ANGLE_ENABLE_WINDOWS_STORE) + if (display == EGL_SOFTWARE_DISPLAY_ANGLE || + display == EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE || + display == EGL_D3D11_ONLY_DISPLAY_ANGLE) + { + return true; + } + return (WindowFromDC(display) != NULL); +#else + return true; +#endif +} + +void Display::initVendorString() +{ + mVendorString = mImplementation->getVendorString(); +} + +const DisplayExtensions &Display::getExtensions() const +{ + return mDisplayExtensions; +} + +const std::string &Display::getExtensionString() const +{ + return mDisplayExtensionString; +} + +const std::string &Display::getVendorString() const +{ + return mVendorString; +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/Display.h b/src/3rdparty/angle/src/libANGLE/Display.h new file mode 100644 index 0000000000..5ab3f9c0e9 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/Display.h @@ -0,0 +1,124 @@ +// +// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Display.h: Defines the egl::Display class, representing the abstract +// display on which graphics are drawn. Implements EGLDisplay. +// [EGL 1.4] section 2.1.2 page 3. + +#ifndef LIBANGLE_DISPLAY_H_ +#define LIBANGLE_DISPLAY_H_ + +#include +#include + +#include "libANGLE/Error.h" +#include "libANGLE/Caps.h" +#include "libANGLE/Config.h" +#include "libANGLE/AttributeMap.h" + +namespace gl +{ +class Context; +} + +namespace rx +{ +class DisplayImpl; +} + +namespace egl +{ +class Surface; + +class Display final : angle::NonCopyable +{ + public: + ~Display(); + + Error initialize(); + void terminate(); + + static egl::Display *getDisplay(EGLNativeDisplayType displayId, const AttributeMap &attribMap); + + static const ClientExtensions &getClientExtensions(); + static const std::string &getClientExtensionString(); + + std::vector getConfigs(const egl::AttributeMap &attribs) const; + bool getConfigAttrib(const Config *configuration, EGLint attribute, EGLint *value); + + Error createWindowSurface(const Config *configuration, EGLNativeWindowType window, const AttributeMap &attribs, + Surface **outSurface); + Error createPbufferSurface(const Config *configuration, const AttributeMap &attribs, Surface **outSurface); + Error createPbufferFromClientBuffer(const Config *configuration, EGLClientBuffer shareHandle, const AttributeMap &attribs, + Surface **outSurface); + Error createPixmapSurface(const Config *configuration, NativePixmapType nativePixmap, const AttributeMap &attribs, + Surface **outSurface); + + Error createContext(const Config *configuration, gl::Context *shareContext, const AttributeMap &attribs, + gl::Context **outContext); + + Error makeCurrent(egl::Surface *drawSurface, egl::Surface *readSurface, gl::Context *context); + + void destroySurface(egl::Surface *surface); + void destroyContext(gl::Context *context); + + bool isInitialized() const; + bool isValidConfig(const Config *config) const; + bool isValidContext(gl::Context *context) const; + bool isValidSurface(egl::Surface *surface) const; + bool isValidNativeWindow(EGLNativeWindowType window) const; + + static bool isValidNativeDisplay(EGLNativeDisplayType display); + static bool hasExistingWindowSurface(EGLNativeWindowType window); + + bool isDeviceLost() const; + bool testDeviceLost(); + void notifyDeviceLost(); + + const Caps &getCaps() const; + + const DisplayExtensions &getExtensions() const; + const std::string &getExtensionString() const; + const std::string &getVendorString() const; + + const AttributeMap &getAttributeMap() const { return mAttributeMap; } + EGLNativeDisplayType getNativeDisplayId() const { return mDisplayId; } + + rx::DisplayImpl *getImplementation() { return mImplementation; } + + private: + Display(EGLNativeDisplayType displayId); + + void setAttributes(rx::DisplayImpl *impl, const AttributeMap &attribMap); + + Error restoreLostDevice(); + + void initDisplayExtensions(); + void initVendorString(); + + rx::DisplayImpl *mImplementation; + + EGLNativeDisplayType mDisplayId; + AttributeMap mAttributeMap; + + ConfigSet mConfigSet; + + typedef std::set ContextSet; + ContextSet mContextSet; + + bool mInitialized; + + Caps mCaps; + + DisplayExtensions mDisplayExtensions; + std::string mDisplayExtensionString; + + std::string mVendorString; +}; + +} + +#endif // LIBANGLE_DISPLAY_H_ diff --git a/src/3rdparty/angle/src/libANGLE/Error.cpp b/src/3rdparty/angle/src/libANGLE/Error.cpp new file mode 100644 index 0000000000..e17f26bec4 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/Error.cpp @@ -0,0 +1,86 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Error.cpp: Implements the egl::Error and gl::Error classes which encapsulate API errors +// and optional error messages. + +#include "libANGLE/Error.h" + +#include "common/angleutils.h" + +#include + +namespace gl +{ + +Error::Error(GLenum errorCode, const char *msg, ...) + : mCode(errorCode), + mMessage(nullptr) +{ + va_list vararg; + va_start(vararg, msg); + createMessageString(); + *mMessage = FormatString(msg, vararg); + va_end(vararg); +} + +void Error::createMessageString() const +{ + if (mMessage == nullptr) + { + mMessage = new std::string(); + } +} + +const std::string &Error::getMessage() const +{ + createMessageString(); + return *mMessage; +} + +} + +namespace egl +{ + +Error::Error(EGLint errorCode, const char *msg, ...) + : mCode(errorCode), + mID(0), + mMessage(nullptr) +{ + va_list vararg; + va_start(vararg, msg); + createMessageString(); + *mMessage = FormatString(msg, vararg); + va_end(vararg); +} + +Error::Error(EGLint errorCode, EGLint id, const char *msg, ...) + : mCode(errorCode), + mID(id), + mMessage(nullptr) +{ + va_list vararg; + va_start(vararg, msg); + createMessageString(); + *mMessage = FormatString(msg, vararg); + va_end(vararg); +} +void Error::createMessageString() const +{ + if (mMessage == nullptr) + { + mMessage = new std::string(); + } +} + +const std::string &Error::getMessage() const +{ + createMessageString(); + return *mMessage; +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/Error.h b/src/3rdparty/angle/src/libANGLE/Error.h new file mode 100644 index 0000000000..896b777567 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/Error.h @@ -0,0 +1,83 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Error.h: Defines the egl::Error and gl::Error classes which encapsulate API errors +// and optional error messages. + +#ifndef LIBANGLE_ERROR_H_ +#define LIBANGLE_ERROR_H_ + +#include "angle_gl.h" +#include "common/platform.h" +#include + +#include + +namespace gl +{ + +class Error final +{ + public: + explicit inline Error(GLenum errorCode); + Error(GLenum errorCode, const char *msg, ...); + inline Error(const Error &other); + inline Error(Error &&other); + + inline ~Error(); + + inline Error &operator=(const Error &other); + inline Error &operator=(Error &&other); + + inline GLenum getCode() const; + inline bool isError() const; + + const std::string &getMessage() const; + + private: + void createMessageString() const; + + GLenum mCode; + mutable std::string *mMessage; +}; + +} + +namespace egl +{ + +class Error final +{ + public: + explicit inline Error(EGLint errorCode); + Error(EGLint errorCode, const char *msg, ...); + Error(EGLint errorCode, EGLint id, const char *msg, ...); + inline Error(const Error &other); + inline Error(Error &&other); + + inline ~Error(); + + inline Error &operator=(const Error &other); + inline Error &operator=(Error &&other); + + inline EGLint getCode() const; + inline EGLint getID() const; + inline bool isError() const; + + const std::string &getMessage() const; + + private: + void createMessageString() const; + + EGLint mCode; + EGLint mID; + mutable std::string *mMessage; +}; + +} + +#include "Error.inl" + +#endif // LIBANGLE_ERROR_H_ diff --git a/src/3rdparty/angle/src/libANGLE/Error.inl b/src/3rdparty/angle/src/libANGLE/Error.inl new file mode 100644 index 0000000000..32e8f05828 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/Error.inl @@ -0,0 +1,163 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Error.inl: Inline definitions of egl::Error and gl::Error classes which encapsulate API errors +// and optional error messages. + +#include "common/angleutils.h" + +#include + +namespace gl +{ + +Error::Error(GLenum errorCode) + : mCode(errorCode), + mMessage(nullptr) +{ +} + +Error::Error(const Error &other) + : mCode(other.mCode), + mMessage(nullptr) +{ + if (other.mMessage != nullptr) + { + createMessageString(); + *mMessage = *(other.mMessage); + } +} + +Error::Error(Error &&other) + : mCode(other.mCode), + mMessage(other.mMessage) +{ + other.mMessage = nullptr; +} + +Error::~Error() +{ + SafeDelete(mMessage); +} + +Error &Error::operator=(const Error &other) +{ + mCode = other.mCode; + + if (other.mMessage != nullptr) + { + createMessageString(); + *mMessage = *(other.mMessage); + } + else + { + SafeDelete(mMessage); + } + + return *this; +} + +Error &Error::operator=(Error &&other) +{ + mCode = other.mCode; + mMessage = other.mMessage; + + other.mMessage = nullptr; + + return *this; +} + +GLenum Error::getCode() const +{ + return mCode; +} + +bool Error::isError() const +{ + return (mCode != GL_NO_ERROR); +} + +} + +namespace egl +{ + +Error::Error(EGLint errorCode) + : mCode(errorCode), + mID(0), + mMessage(nullptr) +{ +} + +Error::Error(const Error &other) + : mCode(other.mCode), + mID(other.mID), + mMessage(nullptr) +{ + if (other.mMessage != nullptr) + { + createMessageString(); + *mMessage = *(other.mMessage); + } +} + +Error::Error(Error &&other) + : mCode(other.mCode), + mID(other.mID), + mMessage(other.mMessage) +{ + other.mMessage = nullptr; +} + +Error::~Error() +{ + SafeDelete(mMessage); +} + +Error &Error::operator=(const Error &other) +{ + mCode = other.mCode; + mID = other.mID; + + if (other.mMessage != nullptr) + { + createMessageString(); + *mMessage = *(other.mMessage); + } + else + { + SafeDelete(mMessage); + } + + return *this; +} + +Error &Error::operator=(Error &&other) +{ + mCode = other.mCode; + mID = other.mID; + mMessage = other.mMessage; + + other.mMessage = nullptr; + + return *this; +} + +EGLint Error::getCode() const +{ + return mCode; +} + +EGLint Error::getID() const +{ + return mID; +} + +bool Error::isError() const +{ + return (mCode != EGL_SUCCESS); +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/Fence.cpp b/src/3rdparty/angle/src/libANGLE/Fence.cpp new file mode 100644 index 0000000000..8ab4cc9daa --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/Fence.cpp @@ -0,0 +1,117 @@ +// +// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Fence.cpp: Implements the gl::FenceNV and gl::FenceSync classes, which support the GL_NV_fence +// extension and GLES3 sync objects. + +#include "libANGLE/Fence.h" + +#include "libANGLE/renderer/FenceNVImpl.h" +#include "libANGLE/renderer/FenceSyncImpl.h" +#include "libANGLE/renderer/Renderer.h" +#include "common/utilities.h" + +#include "angle_gl.h" + +namespace gl +{ + +FenceNV::FenceNV(rx::FenceNVImpl *impl) + : mFence(impl), + mIsSet(false), + mStatus(GL_FALSE), + mCondition(GL_NONE) +{ +} + +FenceNV::~FenceNV() +{ + SafeDelete(mFence); +} + +GLboolean FenceNV::isFence() const +{ + // GL_NV_fence spec: + // A name returned by GenFencesNV, but not yet set via SetFenceNV, is not the name of an existing fence. + return (mIsSet ? GL_TRUE : GL_FALSE); +} + +Error FenceNV::setFence(GLenum condition) +{ + Error error = mFence->set(); + if (error.isError()) + { + return error; + } + + mCondition = condition; + mStatus = GL_FALSE; + mIsSet = true; + + return Error(GL_NO_ERROR); +} + +Error FenceNV::testFence(GLboolean *outResult) +{ + // Flush the command buffer by default + Error error = mFence->test(true, &mStatus); + if (error.isError()) + { + return error; + } + + *outResult = mStatus; + return Error(GL_NO_ERROR); +} + +Error FenceNV::finishFence() +{ + ASSERT(mIsSet); + + return mFence->finishFence(&mStatus); +} + +FenceSync::FenceSync(rx::FenceSyncImpl *impl, GLuint id) + : RefCountObject(id), + mFence(impl), + mCondition(GL_NONE) +{ +} + +FenceSync::~FenceSync() +{ + SafeDelete(mFence); +} + +Error FenceSync::set(GLenum condition) +{ + Error error = mFence->set(); + if (error.isError()) + { + return error; + } + + mCondition = condition; + return Error(GL_NO_ERROR); +} + +Error FenceSync::clientWait(GLbitfield flags, GLuint64 timeout, GLenum *outResult) +{ + ASSERT(mCondition != GL_NONE); + return mFence->clientWait(flags, timeout, outResult); +} + +Error FenceSync::serverWait(GLbitfield flags, GLuint64 timeout) +{ + return mFence->serverWait(flags, timeout); +} + +Error FenceSync::getStatus(GLint *outResult) const +{ + return mFence->getStatus(outResult); +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/Fence.h b/src/3rdparty/angle/src/libANGLE/Fence.h new file mode 100644 index 0000000000..bcd66b6831 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/Fence.h @@ -0,0 +1,71 @@ +// +// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Fence.h: Defines the gl::FenceNV and gl::FenceSync classes, which support the GL_NV_fence +// extension and GLES3 sync objects. + +#ifndef LIBANGLE_FENCE_H_ +#define LIBANGLE_FENCE_H_ + +#include "libANGLE/Error.h" +#include "libANGLE/RefCountObject.h" + +#include "common/angleutils.h" + +namespace rx +{ +class FenceNVImpl; +class FenceSyncImpl; +} + +namespace gl +{ + +class FenceNV final : angle::NonCopyable +{ + public: + explicit FenceNV(rx::FenceNVImpl *impl); + virtual ~FenceNV(); + + GLboolean isFence() const; + Error setFence(GLenum condition); + Error testFence(GLboolean *outResult); + Error finishFence(); + + GLboolean getStatus() const { return mStatus; } + GLenum getCondition() const { return mCondition; } + + private: + rx::FenceNVImpl *mFence; + + bool mIsSet; + + GLboolean mStatus; + GLenum mCondition; +}; + +class FenceSync final : public RefCountObject +{ + public: + explicit FenceSync(rx::FenceSyncImpl *impl, GLuint id); + virtual ~FenceSync(); + + Error set(GLenum condition); + Error clientWait(GLbitfield flags, GLuint64 timeout, GLenum *outResult); + Error serverWait(GLbitfield flags, GLuint64 timeout); + Error getStatus(GLint *outResult) const; + + GLenum getCondition() const { return mCondition; } + + private: + rx::FenceSyncImpl *mFence; + + GLenum mCondition; +}; + +} + +#endif // LIBANGLE_FENCE_H_ diff --git a/src/3rdparty/angle/src/libANGLE/Float16ToFloat32.cpp b/src/3rdparty/angle/src/libANGLE/Float16ToFloat32.cpp new file mode 100644 index 0000000000..5bf7b3fce8 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/Float16ToFloat32.cpp @@ -0,0 +1,2203 @@ +// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// This file is automatically generated. + +namespace gl +{ + +const static unsigned g_mantissa[2048] = { + 0x00000000, + 0x33800000, + 0x34000000, + 0x34400000, + 0x34800000, + 0x34a00000, + 0x34c00000, + 0x34e00000, + 0x35000000, + 0x35100000, + 0x35200000, + 0x35300000, + 0x35400000, + 0x35500000, + 0x35600000, + 0x35700000, + 0x35800000, + 0x35880000, + 0x35900000, + 0x35980000, + 0x35a00000, + 0x35a80000, + 0x35b00000, + 0x35b80000, + 0x35c00000, + 0x35c80000, + 0x35d00000, + 0x35d80000, + 0x35e00000, + 0x35e80000, + 0x35f00000, + 0x35f80000, + 0x36000000, + 0x36040000, + 0x36080000, + 0x360c0000, + 0x36100000, + 0x36140000, + 0x36180000, + 0x361c0000, + 0x36200000, + 0x36240000, + 0x36280000, + 0x362c0000, + 0x36300000, + 0x36340000, + 0x36380000, + 0x363c0000, + 0x36400000, + 0x36440000, + 0x36480000, + 0x364c0000, + 0x36500000, + 0x36540000, + 0x36580000, + 0x365c0000, + 0x36600000, + 0x36640000, + 0x36680000, + 0x366c0000, + 0x36700000, + 0x36740000, + 0x36780000, + 0x367c0000, + 0x36800000, + 0x36820000, + 0x36840000, + 0x36860000, + 0x36880000, + 0x368a0000, + 0x368c0000, + 0x368e0000, + 0x36900000, + 0x36920000, + 0x36940000, + 0x36960000, + 0x36980000, + 0x369a0000, + 0x369c0000, + 0x369e0000, + 0x36a00000, + 0x36a20000, + 0x36a40000, + 0x36a60000, + 0x36a80000, + 0x36aa0000, + 0x36ac0000, + 0x36ae0000, + 0x36b00000, + 0x36b20000, + 0x36b40000, + 0x36b60000, + 0x36b80000, + 0x36ba0000, + 0x36bc0000, + 0x36be0000, + 0x36c00000, + 0x36c20000, + 0x36c40000, + 0x36c60000, + 0x36c80000, + 0x36ca0000, + 0x36cc0000, + 0x36ce0000, + 0x36d00000, + 0x36d20000, + 0x36d40000, + 0x36d60000, + 0x36d80000, + 0x36da0000, + 0x36dc0000, + 0x36de0000, + 0x36e00000, + 0x36e20000, + 0x36e40000, + 0x36e60000, + 0x36e80000, + 0x36ea0000, + 0x36ec0000, + 0x36ee0000, + 0x36f00000, + 0x36f20000, + 0x36f40000, + 0x36f60000, + 0x36f80000, + 0x36fa0000, + 0x36fc0000, + 0x36fe0000, + 0x37000000, + 0x37010000, + 0x37020000, + 0x37030000, + 0x37040000, + 0x37050000, + 0x37060000, + 0x37070000, + 0x37080000, + 0x37090000, + 0x370a0000, + 0x370b0000, + 0x370c0000, + 0x370d0000, + 0x370e0000, + 0x370f0000, + 0x37100000, + 0x37110000, + 0x37120000, + 0x37130000, + 0x37140000, + 0x37150000, + 0x37160000, + 0x37170000, + 0x37180000, + 0x37190000, + 0x371a0000, + 0x371b0000, + 0x371c0000, + 0x371d0000, + 0x371e0000, + 0x371f0000, + 0x37200000, + 0x37210000, + 0x37220000, + 0x37230000, + 0x37240000, + 0x37250000, + 0x37260000, + 0x37270000, + 0x37280000, + 0x37290000, + 0x372a0000, + 0x372b0000, + 0x372c0000, + 0x372d0000, + 0x372e0000, + 0x372f0000, + 0x37300000, + 0x37310000, + 0x37320000, + 0x37330000, + 0x37340000, + 0x37350000, + 0x37360000, + 0x37370000, + 0x37380000, + 0x37390000, + 0x373a0000, + 0x373b0000, + 0x373c0000, + 0x373d0000, + 0x373e0000, + 0x373f0000, + 0x37400000, + 0x37410000, + 0x37420000, + 0x37430000, + 0x37440000, + 0x37450000, + 0x37460000, + 0x37470000, + 0x37480000, + 0x37490000, + 0x374a0000, + 0x374b0000, + 0x374c0000, + 0x374d0000, + 0x374e0000, + 0x374f0000, + 0x37500000, + 0x37510000, + 0x37520000, + 0x37530000, + 0x37540000, + 0x37550000, + 0x37560000, + 0x37570000, + 0x37580000, + 0x37590000, + 0x375a0000, + 0x375b0000, + 0x375c0000, + 0x375d0000, + 0x375e0000, + 0x375f0000, + 0x37600000, + 0x37610000, + 0x37620000, + 0x37630000, + 0x37640000, + 0x37650000, + 0x37660000, + 0x37670000, + 0x37680000, + 0x37690000, + 0x376a0000, + 0x376b0000, + 0x376c0000, + 0x376d0000, + 0x376e0000, + 0x376f0000, + 0x37700000, + 0x37710000, + 0x37720000, + 0x37730000, + 0x37740000, + 0x37750000, + 0x37760000, + 0x37770000, + 0x37780000, + 0x37790000, + 0x377a0000, + 0x377b0000, + 0x377c0000, + 0x377d0000, + 0x377e0000, + 0x377f0000, + 0x37800000, + 0x37808000, + 0x37810000, + 0x37818000, + 0x37820000, + 0x37828000, + 0x37830000, + 0x37838000, + 0x37840000, + 0x37848000, + 0x37850000, + 0x37858000, + 0x37860000, + 0x37868000, + 0x37870000, + 0x37878000, + 0x37880000, + 0x37888000, + 0x37890000, + 0x37898000, + 0x378a0000, + 0x378a8000, + 0x378b0000, + 0x378b8000, + 0x378c0000, + 0x378c8000, + 0x378d0000, + 0x378d8000, + 0x378e0000, + 0x378e8000, + 0x378f0000, + 0x378f8000, + 0x37900000, + 0x37908000, + 0x37910000, + 0x37918000, + 0x37920000, + 0x37928000, + 0x37930000, + 0x37938000, + 0x37940000, + 0x37948000, + 0x37950000, + 0x37958000, + 0x37960000, + 0x37968000, + 0x37970000, + 0x37978000, + 0x37980000, + 0x37988000, + 0x37990000, + 0x37998000, + 0x379a0000, + 0x379a8000, + 0x379b0000, + 0x379b8000, + 0x379c0000, + 0x379c8000, + 0x379d0000, + 0x379d8000, + 0x379e0000, + 0x379e8000, + 0x379f0000, + 0x379f8000, + 0x37a00000, + 0x37a08000, + 0x37a10000, + 0x37a18000, + 0x37a20000, + 0x37a28000, + 0x37a30000, + 0x37a38000, + 0x37a40000, + 0x37a48000, + 0x37a50000, + 0x37a58000, + 0x37a60000, + 0x37a68000, + 0x37a70000, + 0x37a78000, + 0x37a80000, + 0x37a88000, + 0x37a90000, + 0x37a98000, + 0x37aa0000, + 0x37aa8000, + 0x37ab0000, + 0x37ab8000, + 0x37ac0000, + 0x37ac8000, + 0x37ad0000, + 0x37ad8000, + 0x37ae0000, + 0x37ae8000, + 0x37af0000, + 0x37af8000, + 0x37b00000, + 0x37b08000, + 0x37b10000, + 0x37b18000, + 0x37b20000, + 0x37b28000, + 0x37b30000, + 0x37b38000, + 0x37b40000, + 0x37b48000, + 0x37b50000, + 0x37b58000, + 0x37b60000, + 0x37b68000, + 0x37b70000, + 0x37b78000, + 0x37b80000, + 0x37b88000, + 0x37b90000, + 0x37b98000, + 0x37ba0000, + 0x37ba8000, + 0x37bb0000, + 0x37bb8000, + 0x37bc0000, + 0x37bc8000, + 0x37bd0000, + 0x37bd8000, + 0x37be0000, + 0x37be8000, + 0x37bf0000, + 0x37bf8000, + 0x37c00000, + 0x37c08000, + 0x37c10000, + 0x37c18000, + 0x37c20000, + 0x37c28000, + 0x37c30000, + 0x37c38000, + 0x37c40000, + 0x37c48000, + 0x37c50000, + 0x37c58000, + 0x37c60000, + 0x37c68000, + 0x37c70000, + 0x37c78000, + 0x37c80000, + 0x37c88000, + 0x37c90000, + 0x37c98000, + 0x37ca0000, + 0x37ca8000, + 0x37cb0000, + 0x37cb8000, + 0x37cc0000, + 0x37cc8000, + 0x37cd0000, + 0x37cd8000, + 0x37ce0000, + 0x37ce8000, + 0x37cf0000, + 0x37cf8000, + 0x37d00000, + 0x37d08000, + 0x37d10000, + 0x37d18000, + 0x37d20000, + 0x37d28000, + 0x37d30000, + 0x37d38000, + 0x37d40000, + 0x37d48000, + 0x37d50000, + 0x37d58000, + 0x37d60000, + 0x37d68000, + 0x37d70000, + 0x37d78000, + 0x37d80000, + 0x37d88000, + 0x37d90000, + 0x37d98000, + 0x37da0000, + 0x37da8000, + 0x37db0000, + 0x37db8000, + 0x37dc0000, + 0x37dc8000, + 0x37dd0000, + 0x37dd8000, + 0x37de0000, + 0x37de8000, + 0x37df0000, + 0x37df8000, + 0x37e00000, + 0x37e08000, + 0x37e10000, + 0x37e18000, + 0x37e20000, + 0x37e28000, + 0x37e30000, + 0x37e38000, + 0x37e40000, + 0x37e48000, + 0x37e50000, + 0x37e58000, + 0x37e60000, + 0x37e68000, + 0x37e70000, + 0x37e78000, + 0x37e80000, + 0x37e88000, + 0x37e90000, + 0x37e98000, + 0x37ea0000, + 0x37ea8000, + 0x37eb0000, + 0x37eb8000, + 0x37ec0000, + 0x37ec8000, + 0x37ed0000, + 0x37ed8000, + 0x37ee0000, + 0x37ee8000, + 0x37ef0000, + 0x37ef8000, + 0x37f00000, + 0x37f08000, + 0x37f10000, + 0x37f18000, + 0x37f20000, + 0x37f28000, + 0x37f30000, + 0x37f38000, + 0x37f40000, + 0x37f48000, + 0x37f50000, + 0x37f58000, + 0x37f60000, + 0x37f68000, + 0x37f70000, + 0x37f78000, + 0x37f80000, + 0x37f88000, + 0x37f90000, + 0x37f98000, + 0x37fa0000, + 0x37fa8000, + 0x37fb0000, + 0x37fb8000, + 0x37fc0000, + 0x37fc8000, + 0x37fd0000, + 0x37fd8000, + 0x37fe0000, + 0x37fe8000, + 0x37ff0000, + 0x37ff8000, + 0x38000000, + 0x38004000, + 0x38008000, + 0x3800c000, + 0x38010000, + 0x38014000, + 0x38018000, + 0x3801c000, + 0x38020000, + 0x38024000, + 0x38028000, + 0x3802c000, + 0x38030000, + 0x38034000, + 0x38038000, + 0x3803c000, + 0x38040000, + 0x38044000, + 0x38048000, + 0x3804c000, + 0x38050000, + 0x38054000, + 0x38058000, + 0x3805c000, + 0x38060000, + 0x38064000, + 0x38068000, + 0x3806c000, + 0x38070000, + 0x38074000, + 0x38078000, + 0x3807c000, + 0x38080000, + 0x38084000, + 0x38088000, + 0x3808c000, + 0x38090000, + 0x38094000, + 0x38098000, + 0x3809c000, + 0x380a0000, + 0x380a4000, + 0x380a8000, + 0x380ac000, + 0x380b0000, + 0x380b4000, + 0x380b8000, + 0x380bc000, + 0x380c0000, + 0x380c4000, + 0x380c8000, + 0x380cc000, + 0x380d0000, + 0x380d4000, + 0x380d8000, + 0x380dc000, + 0x380e0000, + 0x380e4000, + 0x380e8000, + 0x380ec000, + 0x380f0000, + 0x380f4000, + 0x380f8000, + 0x380fc000, + 0x38100000, + 0x38104000, + 0x38108000, + 0x3810c000, + 0x38110000, + 0x38114000, + 0x38118000, + 0x3811c000, + 0x38120000, + 0x38124000, + 0x38128000, + 0x3812c000, + 0x38130000, + 0x38134000, + 0x38138000, + 0x3813c000, + 0x38140000, + 0x38144000, + 0x38148000, + 0x3814c000, + 0x38150000, + 0x38154000, + 0x38158000, + 0x3815c000, + 0x38160000, + 0x38164000, + 0x38168000, + 0x3816c000, + 0x38170000, + 0x38174000, + 0x38178000, + 0x3817c000, + 0x38180000, + 0x38184000, + 0x38188000, + 0x3818c000, + 0x38190000, + 0x38194000, + 0x38198000, + 0x3819c000, + 0x381a0000, + 0x381a4000, + 0x381a8000, + 0x381ac000, + 0x381b0000, + 0x381b4000, + 0x381b8000, + 0x381bc000, + 0x381c0000, + 0x381c4000, + 0x381c8000, + 0x381cc000, + 0x381d0000, + 0x381d4000, + 0x381d8000, + 0x381dc000, + 0x381e0000, + 0x381e4000, + 0x381e8000, + 0x381ec000, + 0x381f0000, + 0x381f4000, + 0x381f8000, + 0x381fc000, + 0x38200000, + 0x38204000, + 0x38208000, + 0x3820c000, + 0x38210000, + 0x38214000, + 0x38218000, + 0x3821c000, + 0x38220000, + 0x38224000, + 0x38228000, + 0x3822c000, + 0x38230000, + 0x38234000, + 0x38238000, + 0x3823c000, + 0x38240000, + 0x38244000, + 0x38248000, + 0x3824c000, + 0x38250000, + 0x38254000, + 0x38258000, + 0x3825c000, + 0x38260000, + 0x38264000, + 0x38268000, + 0x3826c000, + 0x38270000, + 0x38274000, + 0x38278000, + 0x3827c000, + 0x38280000, + 0x38284000, + 0x38288000, + 0x3828c000, + 0x38290000, + 0x38294000, + 0x38298000, + 0x3829c000, + 0x382a0000, + 0x382a4000, + 0x382a8000, + 0x382ac000, + 0x382b0000, + 0x382b4000, + 0x382b8000, + 0x382bc000, + 0x382c0000, + 0x382c4000, + 0x382c8000, + 0x382cc000, + 0x382d0000, + 0x382d4000, + 0x382d8000, + 0x382dc000, + 0x382e0000, + 0x382e4000, + 0x382e8000, + 0x382ec000, + 0x382f0000, + 0x382f4000, + 0x382f8000, + 0x382fc000, + 0x38300000, + 0x38304000, + 0x38308000, + 0x3830c000, + 0x38310000, + 0x38314000, + 0x38318000, + 0x3831c000, + 0x38320000, + 0x38324000, + 0x38328000, + 0x3832c000, + 0x38330000, + 0x38334000, + 0x38338000, + 0x3833c000, + 0x38340000, + 0x38344000, + 0x38348000, + 0x3834c000, + 0x38350000, + 0x38354000, + 0x38358000, + 0x3835c000, + 0x38360000, + 0x38364000, + 0x38368000, + 0x3836c000, + 0x38370000, + 0x38374000, + 0x38378000, + 0x3837c000, + 0x38380000, + 0x38384000, + 0x38388000, + 0x3838c000, + 0x38390000, + 0x38394000, + 0x38398000, + 0x3839c000, + 0x383a0000, + 0x383a4000, + 0x383a8000, + 0x383ac000, + 0x383b0000, + 0x383b4000, + 0x383b8000, + 0x383bc000, + 0x383c0000, + 0x383c4000, + 0x383c8000, + 0x383cc000, + 0x383d0000, + 0x383d4000, + 0x383d8000, + 0x383dc000, + 0x383e0000, + 0x383e4000, + 0x383e8000, + 0x383ec000, + 0x383f0000, + 0x383f4000, + 0x383f8000, + 0x383fc000, + 0x38400000, + 0x38404000, + 0x38408000, + 0x3840c000, + 0x38410000, + 0x38414000, + 0x38418000, + 0x3841c000, + 0x38420000, + 0x38424000, + 0x38428000, + 0x3842c000, + 0x38430000, + 0x38434000, + 0x38438000, + 0x3843c000, + 0x38440000, + 0x38444000, + 0x38448000, + 0x3844c000, + 0x38450000, + 0x38454000, + 0x38458000, + 0x3845c000, + 0x38460000, + 0x38464000, + 0x38468000, + 0x3846c000, + 0x38470000, + 0x38474000, + 0x38478000, + 0x3847c000, + 0x38480000, + 0x38484000, + 0x38488000, + 0x3848c000, + 0x38490000, + 0x38494000, + 0x38498000, + 0x3849c000, + 0x384a0000, + 0x384a4000, + 0x384a8000, + 0x384ac000, + 0x384b0000, + 0x384b4000, + 0x384b8000, + 0x384bc000, + 0x384c0000, + 0x384c4000, + 0x384c8000, + 0x384cc000, + 0x384d0000, + 0x384d4000, + 0x384d8000, + 0x384dc000, + 0x384e0000, + 0x384e4000, + 0x384e8000, + 0x384ec000, + 0x384f0000, + 0x384f4000, + 0x384f8000, + 0x384fc000, + 0x38500000, + 0x38504000, + 0x38508000, + 0x3850c000, + 0x38510000, + 0x38514000, + 0x38518000, + 0x3851c000, + 0x38520000, + 0x38524000, + 0x38528000, + 0x3852c000, + 0x38530000, + 0x38534000, + 0x38538000, + 0x3853c000, + 0x38540000, + 0x38544000, + 0x38548000, + 0x3854c000, + 0x38550000, + 0x38554000, + 0x38558000, + 0x3855c000, + 0x38560000, + 0x38564000, + 0x38568000, + 0x3856c000, + 0x38570000, + 0x38574000, + 0x38578000, + 0x3857c000, + 0x38580000, + 0x38584000, + 0x38588000, + 0x3858c000, + 0x38590000, + 0x38594000, + 0x38598000, + 0x3859c000, + 0x385a0000, + 0x385a4000, + 0x385a8000, + 0x385ac000, + 0x385b0000, + 0x385b4000, + 0x385b8000, + 0x385bc000, + 0x385c0000, + 0x385c4000, + 0x385c8000, + 0x385cc000, + 0x385d0000, + 0x385d4000, + 0x385d8000, + 0x385dc000, + 0x385e0000, + 0x385e4000, + 0x385e8000, + 0x385ec000, + 0x385f0000, + 0x385f4000, + 0x385f8000, + 0x385fc000, + 0x38600000, + 0x38604000, + 0x38608000, + 0x3860c000, + 0x38610000, + 0x38614000, + 0x38618000, + 0x3861c000, + 0x38620000, + 0x38624000, + 0x38628000, + 0x3862c000, + 0x38630000, + 0x38634000, + 0x38638000, + 0x3863c000, + 0x38640000, + 0x38644000, + 0x38648000, + 0x3864c000, + 0x38650000, + 0x38654000, + 0x38658000, + 0x3865c000, + 0x38660000, + 0x38664000, + 0x38668000, + 0x3866c000, + 0x38670000, + 0x38674000, + 0x38678000, + 0x3867c000, + 0x38680000, + 0x38684000, + 0x38688000, + 0x3868c000, + 0x38690000, + 0x38694000, + 0x38698000, + 0x3869c000, + 0x386a0000, + 0x386a4000, + 0x386a8000, + 0x386ac000, + 0x386b0000, + 0x386b4000, + 0x386b8000, + 0x386bc000, + 0x386c0000, + 0x386c4000, + 0x386c8000, + 0x386cc000, + 0x386d0000, + 0x386d4000, + 0x386d8000, + 0x386dc000, + 0x386e0000, + 0x386e4000, + 0x386e8000, + 0x386ec000, + 0x386f0000, + 0x386f4000, + 0x386f8000, + 0x386fc000, + 0x38700000, + 0x38704000, + 0x38708000, + 0x3870c000, + 0x38710000, + 0x38714000, + 0x38718000, + 0x3871c000, + 0x38720000, + 0x38724000, + 0x38728000, + 0x3872c000, + 0x38730000, + 0x38734000, + 0x38738000, + 0x3873c000, + 0x38740000, + 0x38744000, + 0x38748000, + 0x3874c000, + 0x38750000, + 0x38754000, + 0x38758000, + 0x3875c000, + 0x38760000, + 0x38764000, + 0x38768000, + 0x3876c000, + 0x38770000, + 0x38774000, + 0x38778000, + 0x3877c000, + 0x38780000, + 0x38784000, + 0x38788000, + 0x3878c000, + 0x38790000, + 0x38794000, + 0x38798000, + 0x3879c000, + 0x387a0000, + 0x387a4000, + 0x387a8000, + 0x387ac000, + 0x387b0000, + 0x387b4000, + 0x387b8000, + 0x387bc000, + 0x387c0000, + 0x387c4000, + 0x387c8000, + 0x387cc000, + 0x387d0000, + 0x387d4000, + 0x387d8000, + 0x387dc000, + 0x387e0000, + 0x387e4000, + 0x387e8000, + 0x387ec000, + 0x387f0000, + 0x387f4000, + 0x387f8000, + 0x387fc000, + 0x38000000, + 0x38002000, + 0x38004000, + 0x38006000, + 0x38008000, + 0x3800a000, + 0x3800c000, + 0x3800e000, + 0x38010000, + 0x38012000, + 0x38014000, + 0x38016000, + 0x38018000, + 0x3801a000, + 0x3801c000, + 0x3801e000, + 0x38020000, + 0x38022000, + 0x38024000, + 0x38026000, + 0x38028000, + 0x3802a000, + 0x3802c000, + 0x3802e000, + 0x38030000, + 0x38032000, + 0x38034000, + 0x38036000, + 0x38038000, + 0x3803a000, + 0x3803c000, + 0x3803e000, + 0x38040000, + 0x38042000, + 0x38044000, + 0x38046000, + 0x38048000, + 0x3804a000, + 0x3804c000, + 0x3804e000, + 0x38050000, + 0x38052000, + 0x38054000, + 0x38056000, + 0x38058000, + 0x3805a000, + 0x3805c000, + 0x3805e000, + 0x38060000, + 0x38062000, + 0x38064000, + 0x38066000, + 0x38068000, + 0x3806a000, + 0x3806c000, + 0x3806e000, + 0x38070000, + 0x38072000, + 0x38074000, + 0x38076000, + 0x38078000, + 0x3807a000, + 0x3807c000, + 0x3807e000, + 0x38080000, + 0x38082000, + 0x38084000, + 0x38086000, + 0x38088000, + 0x3808a000, + 0x3808c000, + 0x3808e000, + 0x38090000, + 0x38092000, + 0x38094000, + 0x38096000, + 0x38098000, + 0x3809a000, + 0x3809c000, + 0x3809e000, + 0x380a0000, + 0x380a2000, + 0x380a4000, + 0x380a6000, + 0x380a8000, + 0x380aa000, + 0x380ac000, + 0x380ae000, + 0x380b0000, + 0x380b2000, + 0x380b4000, + 0x380b6000, + 0x380b8000, + 0x380ba000, + 0x380bc000, + 0x380be000, + 0x380c0000, + 0x380c2000, + 0x380c4000, + 0x380c6000, + 0x380c8000, + 0x380ca000, + 0x380cc000, + 0x380ce000, + 0x380d0000, + 0x380d2000, + 0x380d4000, + 0x380d6000, + 0x380d8000, + 0x380da000, + 0x380dc000, + 0x380de000, + 0x380e0000, + 0x380e2000, + 0x380e4000, + 0x380e6000, + 0x380e8000, + 0x380ea000, + 0x380ec000, + 0x380ee000, + 0x380f0000, + 0x380f2000, + 0x380f4000, + 0x380f6000, + 0x380f8000, + 0x380fa000, + 0x380fc000, + 0x380fe000, + 0x38100000, + 0x38102000, + 0x38104000, + 0x38106000, + 0x38108000, + 0x3810a000, + 0x3810c000, + 0x3810e000, + 0x38110000, + 0x38112000, + 0x38114000, + 0x38116000, + 0x38118000, + 0x3811a000, + 0x3811c000, + 0x3811e000, + 0x38120000, + 0x38122000, + 0x38124000, + 0x38126000, + 0x38128000, + 0x3812a000, + 0x3812c000, + 0x3812e000, + 0x38130000, + 0x38132000, + 0x38134000, + 0x38136000, + 0x38138000, + 0x3813a000, + 0x3813c000, + 0x3813e000, + 0x38140000, + 0x38142000, + 0x38144000, + 0x38146000, + 0x38148000, + 0x3814a000, + 0x3814c000, + 0x3814e000, + 0x38150000, + 0x38152000, + 0x38154000, + 0x38156000, + 0x38158000, + 0x3815a000, + 0x3815c000, + 0x3815e000, + 0x38160000, + 0x38162000, + 0x38164000, + 0x38166000, + 0x38168000, + 0x3816a000, + 0x3816c000, + 0x3816e000, + 0x38170000, + 0x38172000, + 0x38174000, + 0x38176000, + 0x38178000, + 0x3817a000, + 0x3817c000, + 0x3817e000, + 0x38180000, + 0x38182000, + 0x38184000, + 0x38186000, + 0x38188000, + 0x3818a000, + 0x3818c000, + 0x3818e000, + 0x38190000, + 0x38192000, + 0x38194000, + 0x38196000, + 0x38198000, + 0x3819a000, + 0x3819c000, + 0x3819e000, + 0x381a0000, + 0x381a2000, + 0x381a4000, + 0x381a6000, + 0x381a8000, + 0x381aa000, + 0x381ac000, + 0x381ae000, + 0x381b0000, + 0x381b2000, + 0x381b4000, + 0x381b6000, + 0x381b8000, + 0x381ba000, + 0x381bc000, + 0x381be000, + 0x381c0000, + 0x381c2000, + 0x381c4000, + 0x381c6000, + 0x381c8000, + 0x381ca000, + 0x381cc000, + 0x381ce000, + 0x381d0000, + 0x381d2000, + 0x381d4000, + 0x381d6000, + 0x381d8000, + 0x381da000, + 0x381dc000, + 0x381de000, + 0x381e0000, + 0x381e2000, + 0x381e4000, + 0x381e6000, + 0x381e8000, + 0x381ea000, + 0x381ec000, + 0x381ee000, + 0x381f0000, + 0x381f2000, + 0x381f4000, + 0x381f6000, + 0x381f8000, + 0x381fa000, + 0x381fc000, + 0x381fe000, + 0x38200000, + 0x38202000, + 0x38204000, + 0x38206000, + 0x38208000, + 0x3820a000, + 0x3820c000, + 0x3820e000, + 0x38210000, + 0x38212000, + 0x38214000, + 0x38216000, + 0x38218000, + 0x3821a000, + 0x3821c000, + 0x3821e000, + 0x38220000, + 0x38222000, + 0x38224000, + 0x38226000, + 0x38228000, + 0x3822a000, + 0x3822c000, + 0x3822e000, + 0x38230000, + 0x38232000, + 0x38234000, + 0x38236000, + 0x38238000, + 0x3823a000, + 0x3823c000, + 0x3823e000, + 0x38240000, + 0x38242000, + 0x38244000, + 0x38246000, + 0x38248000, + 0x3824a000, + 0x3824c000, + 0x3824e000, + 0x38250000, + 0x38252000, + 0x38254000, + 0x38256000, + 0x38258000, + 0x3825a000, + 0x3825c000, + 0x3825e000, + 0x38260000, + 0x38262000, + 0x38264000, + 0x38266000, + 0x38268000, + 0x3826a000, + 0x3826c000, + 0x3826e000, + 0x38270000, + 0x38272000, + 0x38274000, + 0x38276000, + 0x38278000, + 0x3827a000, + 0x3827c000, + 0x3827e000, + 0x38280000, + 0x38282000, + 0x38284000, + 0x38286000, + 0x38288000, + 0x3828a000, + 0x3828c000, + 0x3828e000, + 0x38290000, + 0x38292000, + 0x38294000, + 0x38296000, + 0x38298000, + 0x3829a000, + 0x3829c000, + 0x3829e000, + 0x382a0000, + 0x382a2000, + 0x382a4000, + 0x382a6000, + 0x382a8000, + 0x382aa000, + 0x382ac000, + 0x382ae000, + 0x382b0000, + 0x382b2000, + 0x382b4000, + 0x382b6000, + 0x382b8000, + 0x382ba000, + 0x382bc000, + 0x382be000, + 0x382c0000, + 0x382c2000, + 0x382c4000, + 0x382c6000, + 0x382c8000, + 0x382ca000, + 0x382cc000, + 0x382ce000, + 0x382d0000, + 0x382d2000, + 0x382d4000, + 0x382d6000, + 0x382d8000, + 0x382da000, + 0x382dc000, + 0x382de000, + 0x382e0000, + 0x382e2000, + 0x382e4000, + 0x382e6000, + 0x382e8000, + 0x382ea000, + 0x382ec000, + 0x382ee000, + 0x382f0000, + 0x382f2000, + 0x382f4000, + 0x382f6000, + 0x382f8000, + 0x382fa000, + 0x382fc000, + 0x382fe000, + 0x38300000, + 0x38302000, + 0x38304000, + 0x38306000, + 0x38308000, + 0x3830a000, + 0x3830c000, + 0x3830e000, + 0x38310000, + 0x38312000, + 0x38314000, + 0x38316000, + 0x38318000, + 0x3831a000, + 0x3831c000, + 0x3831e000, + 0x38320000, + 0x38322000, + 0x38324000, + 0x38326000, + 0x38328000, + 0x3832a000, + 0x3832c000, + 0x3832e000, + 0x38330000, + 0x38332000, + 0x38334000, + 0x38336000, + 0x38338000, + 0x3833a000, + 0x3833c000, + 0x3833e000, + 0x38340000, + 0x38342000, + 0x38344000, + 0x38346000, + 0x38348000, + 0x3834a000, + 0x3834c000, + 0x3834e000, + 0x38350000, + 0x38352000, + 0x38354000, + 0x38356000, + 0x38358000, + 0x3835a000, + 0x3835c000, + 0x3835e000, + 0x38360000, + 0x38362000, + 0x38364000, + 0x38366000, + 0x38368000, + 0x3836a000, + 0x3836c000, + 0x3836e000, + 0x38370000, + 0x38372000, + 0x38374000, + 0x38376000, + 0x38378000, + 0x3837a000, + 0x3837c000, + 0x3837e000, + 0x38380000, + 0x38382000, + 0x38384000, + 0x38386000, + 0x38388000, + 0x3838a000, + 0x3838c000, + 0x3838e000, + 0x38390000, + 0x38392000, + 0x38394000, + 0x38396000, + 0x38398000, + 0x3839a000, + 0x3839c000, + 0x3839e000, + 0x383a0000, + 0x383a2000, + 0x383a4000, + 0x383a6000, + 0x383a8000, + 0x383aa000, + 0x383ac000, + 0x383ae000, + 0x383b0000, + 0x383b2000, + 0x383b4000, + 0x383b6000, + 0x383b8000, + 0x383ba000, + 0x383bc000, + 0x383be000, + 0x383c0000, + 0x383c2000, + 0x383c4000, + 0x383c6000, + 0x383c8000, + 0x383ca000, + 0x383cc000, + 0x383ce000, + 0x383d0000, + 0x383d2000, + 0x383d4000, + 0x383d6000, + 0x383d8000, + 0x383da000, + 0x383dc000, + 0x383de000, + 0x383e0000, + 0x383e2000, + 0x383e4000, + 0x383e6000, + 0x383e8000, + 0x383ea000, + 0x383ec000, + 0x383ee000, + 0x383f0000, + 0x383f2000, + 0x383f4000, + 0x383f6000, + 0x383f8000, + 0x383fa000, + 0x383fc000, + 0x383fe000, + 0x38400000, + 0x38402000, + 0x38404000, + 0x38406000, + 0x38408000, + 0x3840a000, + 0x3840c000, + 0x3840e000, + 0x38410000, + 0x38412000, + 0x38414000, + 0x38416000, + 0x38418000, + 0x3841a000, + 0x3841c000, + 0x3841e000, + 0x38420000, + 0x38422000, + 0x38424000, + 0x38426000, + 0x38428000, + 0x3842a000, + 0x3842c000, + 0x3842e000, + 0x38430000, + 0x38432000, + 0x38434000, + 0x38436000, + 0x38438000, + 0x3843a000, + 0x3843c000, + 0x3843e000, + 0x38440000, + 0x38442000, + 0x38444000, + 0x38446000, + 0x38448000, + 0x3844a000, + 0x3844c000, + 0x3844e000, + 0x38450000, + 0x38452000, + 0x38454000, + 0x38456000, + 0x38458000, + 0x3845a000, + 0x3845c000, + 0x3845e000, + 0x38460000, + 0x38462000, + 0x38464000, + 0x38466000, + 0x38468000, + 0x3846a000, + 0x3846c000, + 0x3846e000, + 0x38470000, + 0x38472000, + 0x38474000, + 0x38476000, + 0x38478000, + 0x3847a000, + 0x3847c000, + 0x3847e000, + 0x38480000, + 0x38482000, + 0x38484000, + 0x38486000, + 0x38488000, + 0x3848a000, + 0x3848c000, + 0x3848e000, + 0x38490000, + 0x38492000, + 0x38494000, + 0x38496000, + 0x38498000, + 0x3849a000, + 0x3849c000, + 0x3849e000, + 0x384a0000, + 0x384a2000, + 0x384a4000, + 0x384a6000, + 0x384a8000, + 0x384aa000, + 0x384ac000, + 0x384ae000, + 0x384b0000, + 0x384b2000, + 0x384b4000, + 0x384b6000, + 0x384b8000, + 0x384ba000, + 0x384bc000, + 0x384be000, + 0x384c0000, + 0x384c2000, + 0x384c4000, + 0x384c6000, + 0x384c8000, + 0x384ca000, + 0x384cc000, + 0x384ce000, + 0x384d0000, + 0x384d2000, + 0x384d4000, + 0x384d6000, + 0x384d8000, + 0x384da000, + 0x384dc000, + 0x384de000, + 0x384e0000, + 0x384e2000, + 0x384e4000, + 0x384e6000, + 0x384e8000, + 0x384ea000, + 0x384ec000, + 0x384ee000, + 0x384f0000, + 0x384f2000, + 0x384f4000, + 0x384f6000, + 0x384f8000, + 0x384fa000, + 0x384fc000, + 0x384fe000, + 0x38500000, + 0x38502000, + 0x38504000, + 0x38506000, + 0x38508000, + 0x3850a000, + 0x3850c000, + 0x3850e000, + 0x38510000, + 0x38512000, + 0x38514000, + 0x38516000, + 0x38518000, + 0x3851a000, + 0x3851c000, + 0x3851e000, + 0x38520000, + 0x38522000, + 0x38524000, + 0x38526000, + 0x38528000, + 0x3852a000, + 0x3852c000, + 0x3852e000, + 0x38530000, + 0x38532000, + 0x38534000, + 0x38536000, + 0x38538000, + 0x3853a000, + 0x3853c000, + 0x3853e000, + 0x38540000, + 0x38542000, + 0x38544000, + 0x38546000, + 0x38548000, + 0x3854a000, + 0x3854c000, + 0x3854e000, + 0x38550000, + 0x38552000, + 0x38554000, + 0x38556000, + 0x38558000, + 0x3855a000, + 0x3855c000, + 0x3855e000, + 0x38560000, + 0x38562000, + 0x38564000, + 0x38566000, + 0x38568000, + 0x3856a000, + 0x3856c000, + 0x3856e000, + 0x38570000, + 0x38572000, + 0x38574000, + 0x38576000, + 0x38578000, + 0x3857a000, + 0x3857c000, + 0x3857e000, + 0x38580000, + 0x38582000, + 0x38584000, + 0x38586000, + 0x38588000, + 0x3858a000, + 0x3858c000, + 0x3858e000, + 0x38590000, + 0x38592000, + 0x38594000, + 0x38596000, + 0x38598000, + 0x3859a000, + 0x3859c000, + 0x3859e000, + 0x385a0000, + 0x385a2000, + 0x385a4000, + 0x385a6000, + 0x385a8000, + 0x385aa000, + 0x385ac000, + 0x385ae000, + 0x385b0000, + 0x385b2000, + 0x385b4000, + 0x385b6000, + 0x385b8000, + 0x385ba000, + 0x385bc000, + 0x385be000, + 0x385c0000, + 0x385c2000, + 0x385c4000, + 0x385c6000, + 0x385c8000, + 0x385ca000, + 0x385cc000, + 0x385ce000, + 0x385d0000, + 0x385d2000, + 0x385d4000, + 0x385d6000, + 0x385d8000, + 0x385da000, + 0x385dc000, + 0x385de000, + 0x385e0000, + 0x385e2000, + 0x385e4000, + 0x385e6000, + 0x385e8000, + 0x385ea000, + 0x385ec000, + 0x385ee000, + 0x385f0000, + 0x385f2000, + 0x385f4000, + 0x385f6000, + 0x385f8000, + 0x385fa000, + 0x385fc000, + 0x385fe000, + 0x38600000, + 0x38602000, + 0x38604000, + 0x38606000, + 0x38608000, + 0x3860a000, + 0x3860c000, + 0x3860e000, + 0x38610000, + 0x38612000, + 0x38614000, + 0x38616000, + 0x38618000, + 0x3861a000, + 0x3861c000, + 0x3861e000, + 0x38620000, + 0x38622000, + 0x38624000, + 0x38626000, + 0x38628000, + 0x3862a000, + 0x3862c000, + 0x3862e000, + 0x38630000, + 0x38632000, + 0x38634000, + 0x38636000, + 0x38638000, + 0x3863a000, + 0x3863c000, + 0x3863e000, + 0x38640000, + 0x38642000, + 0x38644000, + 0x38646000, + 0x38648000, + 0x3864a000, + 0x3864c000, + 0x3864e000, + 0x38650000, + 0x38652000, + 0x38654000, + 0x38656000, + 0x38658000, + 0x3865a000, + 0x3865c000, + 0x3865e000, + 0x38660000, + 0x38662000, + 0x38664000, + 0x38666000, + 0x38668000, + 0x3866a000, + 0x3866c000, + 0x3866e000, + 0x38670000, + 0x38672000, + 0x38674000, + 0x38676000, + 0x38678000, + 0x3867a000, + 0x3867c000, + 0x3867e000, + 0x38680000, + 0x38682000, + 0x38684000, + 0x38686000, + 0x38688000, + 0x3868a000, + 0x3868c000, + 0x3868e000, + 0x38690000, + 0x38692000, + 0x38694000, + 0x38696000, + 0x38698000, + 0x3869a000, + 0x3869c000, + 0x3869e000, + 0x386a0000, + 0x386a2000, + 0x386a4000, + 0x386a6000, + 0x386a8000, + 0x386aa000, + 0x386ac000, + 0x386ae000, + 0x386b0000, + 0x386b2000, + 0x386b4000, + 0x386b6000, + 0x386b8000, + 0x386ba000, + 0x386bc000, + 0x386be000, + 0x386c0000, + 0x386c2000, + 0x386c4000, + 0x386c6000, + 0x386c8000, + 0x386ca000, + 0x386cc000, + 0x386ce000, + 0x386d0000, + 0x386d2000, + 0x386d4000, + 0x386d6000, + 0x386d8000, + 0x386da000, + 0x386dc000, + 0x386de000, + 0x386e0000, + 0x386e2000, + 0x386e4000, + 0x386e6000, + 0x386e8000, + 0x386ea000, + 0x386ec000, + 0x386ee000, + 0x386f0000, + 0x386f2000, + 0x386f4000, + 0x386f6000, + 0x386f8000, + 0x386fa000, + 0x386fc000, + 0x386fe000, + 0x38700000, + 0x38702000, + 0x38704000, + 0x38706000, + 0x38708000, + 0x3870a000, + 0x3870c000, + 0x3870e000, + 0x38710000, + 0x38712000, + 0x38714000, + 0x38716000, + 0x38718000, + 0x3871a000, + 0x3871c000, + 0x3871e000, + 0x38720000, + 0x38722000, + 0x38724000, + 0x38726000, + 0x38728000, + 0x3872a000, + 0x3872c000, + 0x3872e000, + 0x38730000, + 0x38732000, + 0x38734000, + 0x38736000, + 0x38738000, + 0x3873a000, + 0x3873c000, + 0x3873e000, + 0x38740000, + 0x38742000, + 0x38744000, + 0x38746000, + 0x38748000, + 0x3874a000, + 0x3874c000, + 0x3874e000, + 0x38750000, + 0x38752000, + 0x38754000, + 0x38756000, + 0x38758000, + 0x3875a000, + 0x3875c000, + 0x3875e000, + 0x38760000, + 0x38762000, + 0x38764000, + 0x38766000, + 0x38768000, + 0x3876a000, + 0x3876c000, + 0x3876e000, + 0x38770000, + 0x38772000, + 0x38774000, + 0x38776000, + 0x38778000, + 0x3877a000, + 0x3877c000, + 0x3877e000, + 0x38780000, + 0x38782000, + 0x38784000, + 0x38786000, + 0x38788000, + 0x3878a000, + 0x3878c000, + 0x3878e000, + 0x38790000, + 0x38792000, + 0x38794000, + 0x38796000, + 0x38798000, + 0x3879a000, + 0x3879c000, + 0x3879e000, + 0x387a0000, + 0x387a2000, + 0x387a4000, + 0x387a6000, + 0x387a8000, + 0x387aa000, + 0x387ac000, + 0x387ae000, + 0x387b0000, + 0x387b2000, + 0x387b4000, + 0x387b6000, + 0x387b8000, + 0x387ba000, + 0x387bc000, + 0x387be000, + 0x387c0000, + 0x387c2000, + 0x387c4000, + 0x387c6000, + 0x387c8000, + 0x387ca000, + 0x387cc000, + 0x387ce000, + 0x387d0000, + 0x387d2000, + 0x387d4000, + 0x387d6000, + 0x387d8000, + 0x387da000, + 0x387dc000, + 0x387de000, + 0x387e0000, + 0x387e2000, + 0x387e4000, + 0x387e6000, + 0x387e8000, + 0x387ea000, + 0x387ec000, + 0x387ee000, + 0x387f0000, + 0x387f2000, + 0x387f4000, + 0x387f6000, + 0x387f8000, + 0x387fa000, + 0x387fc000, + 0x387fe000, +}; + +const static unsigned g_exponent[64] = { + 0x00000000, + 0x00800000, + 0x01000000, + 0x01800000, + 0x02000000, + 0x02800000, + 0x03000000, + 0x03800000, + 0x04000000, + 0x04800000, + 0x05000000, + 0x05800000, + 0x06000000, + 0x06800000, + 0x07000000, + 0x07800000, + 0x08000000, + 0x08800000, + 0x09000000, + 0x09800000, + 0x0a000000, + 0x0a800000, + 0x0b000000, + 0x0b800000, + 0x0c000000, + 0x0c800000, + 0x0d000000, + 0x0d800000, + 0x0e000000, + 0x0e800000, + 0x0f000000, + 0x47800000, + 0x80000000, + 0x80800000, + 0x81000000, + 0x81800000, + 0x82000000, + 0x82800000, + 0x83000000, + 0x83800000, + 0x84000000, + 0x84800000, + 0x85000000, + 0x85800000, + 0x86000000, + 0x86800000, + 0x87000000, + 0x87800000, + 0x88000000, + 0x88800000, + 0x89000000, + 0x89800000, + 0x8a000000, + 0x8a800000, + 0x8b000000, + 0x8b800000, + 0x8c000000, + 0x8c800000, + 0x8d000000, + 0x8d800000, + 0x8e000000, + 0x8e800000, + 0x8f000000, + 0xc7800000, +}; + +const static unsigned g_offset[64] = { + 0x00000000, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000000, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, +}; + +float float16ToFloat32(unsigned short h) +{ + unsigned i32 = g_mantissa[g_offset[h >> 10] + (h & 0x3ff)] + g_exponent[h >> 10]; + return *(float*) &i32; +} +} + diff --git a/src/3rdparty/angle/src/libANGLE/Framebuffer.cpp b/src/3rdparty/angle/src/libANGLE/Framebuffer.cpp new file mode 100644 index 0000000000..b1dd4a1b0f --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/Framebuffer.cpp @@ -0,0 +1,658 @@ +// +// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Framebuffer.cpp: Implements the gl::Framebuffer class. Implements GL framebuffer +// objects and related functionality. [OpenGL ES 2.0.24] section 4.4 page 105. + +#include "libANGLE/Framebuffer.h" + +#include "common/utilities.h" +#include "libANGLE/Config.h" +#include "libANGLE/Context.h" +#include "libANGLE/FramebufferAttachment.h" +#include "libANGLE/Renderbuffer.h" +#include "libANGLE/Surface.h" +#include "libANGLE/Texture.h" +#include "libANGLE/formatutils.h" +#include "libANGLE/renderer/FramebufferImpl.h" +#include "libANGLE/renderer/ImplFactory.h" +#include "libANGLE/renderer/RenderbufferImpl.h" +#include "libANGLE/renderer/Workarounds.h" + +namespace gl +{ + +namespace +{ +void DeleteMatchingAttachment(FramebufferAttachment *&attachment, GLenum matchType, GLuint matchId) +{ + if (attachment && attachment->type() == matchType && attachment->id() == matchId) + { + SafeDelete(attachment); + } +} +} + +Framebuffer::Data::Data(const Caps &caps) + : mColorAttachments(caps.maxColorAttachments, nullptr), + mDepthAttachment(nullptr), + mStencilAttachment(nullptr), + mDrawBufferStates(caps.maxDrawBuffers, GL_NONE), + mReadBufferState(GL_COLOR_ATTACHMENT0_EXT) +{ + mDrawBufferStates[0] = GL_COLOR_ATTACHMENT0_EXT; +} + +Framebuffer::Data::~Data() +{ + for (auto it = mColorAttachments.begin(); it != mColorAttachments.end(); ++it) + { + SafeDelete(*it); + } + SafeDelete(mDepthAttachment); + SafeDelete(mStencilAttachment); +} + +FramebufferAttachment *Framebuffer::Data::getReadAttachment() const +{ + ASSERT(mReadBufferState == GL_BACK || (mReadBufferState >= GL_COLOR_ATTACHMENT0 && mReadBufferState <= GL_COLOR_ATTACHMENT15)); + size_t readIndex = (mReadBufferState == GL_BACK ? 0 : static_cast(mReadBufferState - GL_COLOR_ATTACHMENT0)); + ASSERT(readIndex < mColorAttachments.size()); + return mColorAttachments[readIndex]; +} + +FramebufferAttachment *Framebuffer::Data::getFirstColorAttachment() const +{ + for (auto it = mColorAttachments.cbegin(); it != mColorAttachments.cend(); ++it) + { + if (*it != nullptr) + { + return *it; + } + } + + return nullptr; +} + +FramebufferAttachment *Framebuffer::Data::getDepthOrStencilAttachment() const +{ + return (mDepthAttachment != nullptr ? mDepthAttachment : mStencilAttachment); +} + +Framebuffer::Framebuffer(const Caps &caps, rx::ImplFactory *factory, GLuint id) + : mData(caps), + mImpl(nullptr), + mId(id) +{ + if (mId == 0) + { + mImpl = factory->createDefaultFramebuffer(mData); + } + else + { + mImpl = factory->createFramebuffer(mData); + } + ASSERT(mImpl != nullptr); +} + +Framebuffer::~Framebuffer() +{ + SafeDelete(mImpl); +} + +void Framebuffer::detachTexture(GLuint textureId) +{ + detachResourceById(GL_TEXTURE, textureId); +} + +void Framebuffer::detachRenderbuffer(GLuint renderbufferId) +{ + detachResourceById(GL_RENDERBUFFER, renderbufferId); +} + +void Framebuffer::detachResourceById(GLenum resourceType, GLuint resourceId) +{ + for (auto it = mData.mColorAttachments.begin(); it != mData.mColorAttachments.end(); ++it) + { + DeleteMatchingAttachment(*it, resourceType, resourceId); + } + + DeleteMatchingAttachment(mData.mDepthAttachment, resourceType, resourceId); + DeleteMatchingAttachment(mData.mStencilAttachment, resourceType, resourceId); +} + +FramebufferAttachment *Framebuffer::getColorbuffer(unsigned int colorAttachment) const +{ + ASSERT(colorAttachment < mData.mColorAttachments.size()); + return mData.mColorAttachments[colorAttachment]; +} + +FramebufferAttachment *Framebuffer::getDepthbuffer() const +{ + return mData.mDepthAttachment; +} + +FramebufferAttachment *Framebuffer::getStencilbuffer() const +{ + return mData.mStencilAttachment; +} + +FramebufferAttachment *Framebuffer::getDepthStencilBuffer() const +{ + return (hasValidDepthStencil() ? mData.mDepthAttachment : NULL); +} + +FramebufferAttachment *Framebuffer::getDepthOrStencilbuffer() const +{ + return mData.getDepthOrStencilAttachment(); +} + +FramebufferAttachment *Framebuffer::getReadColorbuffer() const +{ + return mData.getReadAttachment(); +} + +GLenum Framebuffer::getReadColorbufferType() const +{ + FramebufferAttachment *readAttachment = mData.getReadAttachment(); + return (readAttachment ? readAttachment->type() : GL_NONE); +} + +FramebufferAttachment *Framebuffer::getFirstColorbuffer() const +{ + return mData.getFirstColorAttachment(); +} + +FramebufferAttachment *Framebuffer::getAttachment(GLenum attachment) const +{ + if (attachment >= GL_COLOR_ATTACHMENT0 && attachment <= GL_COLOR_ATTACHMENT15) + { + return getColorbuffer(attachment - GL_COLOR_ATTACHMENT0); + } + else + { + switch (attachment) + { + case GL_COLOR: + case GL_BACK: + return getColorbuffer(0); + case GL_DEPTH: + case GL_DEPTH_ATTACHMENT: + return getDepthbuffer(); + case GL_STENCIL: + case GL_STENCIL_ATTACHMENT: + return getStencilbuffer(); + case GL_DEPTH_STENCIL: + case GL_DEPTH_STENCIL_ATTACHMENT: + return getDepthStencilBuffer(); + default: + UNREACHABLE(); + return NULL; + } + } +} + +GLenum Framebuffer::getDrawBufferState(unsigned int colorAttachment) const +{ + ASSERT(colorAttachment < mData.mDrawBufferStates.size()); + return mData.mDrawBufferStates[colorAttachment]; +} + +void Framebuffer::setDrawBuffers(size_t count, const GLenum *buffers) +{ + auto &drawStates = mData.mDrawBufferStates; + + ASSERT(count <= drawStates.size()); + std::copy(buffers, buffers + count, drawStates.begin()); + std::fill(drawStates.begin() + count, drawStates.end(), GL_NONE); + mImpl->setDrawBuffers(count, buffers); +} + +GLenum Framebuffer::getReadBufferState() const +{ + return mData.mReadBufferState; +} + +void Framebuffer::setReadBuffer(GLenum buffer) +{ + ASSERT(buffer == GL_BACK || buffer == GL_NONE || + (buffer >= GL_COLOR_ATTACHMENT0 && + (buffer - GL_COLOR_ATTACHMENT0) < mData.mColorAttachments.size())); + mData.mReadBufferState = buffer; + mImpl->setReadBuffer(buffer); +} + +bool Framebuffer::isEnabledColorAttachment(unsigned int colorAttachment) const +{ + ASSERT(colorAttachment < mData.mColorAttachments.size()); + return (mData.mColorAttachments[colorAttachment] && + mData.mDrawBufferStates[colorAttachment] != GL_NONE); +} + +bool Framebuffer::hasEnabledColorAttachment() const +{ + for (size_t colorAttachment = 0; colorAttachment < mData.mColorAttachments.size(); ++colorAttachment) + { + if (isEnabledColorAttachment(colorAttachment)) + { + return true; + } + } + + return false; +} + +bool Framebuffer::hasStencil() const +{ + return (mData.mStencilAttachment && mData.mStencilAttachment->getStencilSize() > 0); +} + +bool Framebuffer::usingExtendedDrawBuffers() const +{ + for (size_t colorAttachment = 1; colorAttachment < mData.mColorAttachments.size(); ++colorAttachment) + { + if (isEnabledColorAttachment(colorAttachment)) + { + return true; + } + } + + return false; +} + +GLenum Framebuffer::checkStatus(const gl::Data &data) const +{ + // The default framebuffer *must* always be complete, though it may not be + // subject to the same rules as application FBOs. ie, it could have 0x0 size. + if (mId == 0) + { + return GL_FRAMEBUFFER_COMPLETE; + } + + int width = 0; + int height = 0; + unsigned int colorbufferSize = 0; + int samples = -1; + bool missingAttachment = true; + + for (auto it = mData.mColorAttachments.cbegin(); it != mData.mColorAttachments.cend(); ++it) + { + const auto &colorAttachment = *it; + if (colorAttachment != nullptr) + { + if (colorAttachment->getWidth() == 0 || colorAttachment->getHeight() == 0) + { + return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; + } + + GLenum internalformat = colorAttachment->getInternalFormat(); + const TextureCaps &formatCaps = data.textureCaps->get(internalformat); + const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat); + if (colorAttachment->type() == GL_TEXTURE) + { + if (!formatCaps.renderable) + { + return GL_FRAMEBUFFER_UNSUPPORTED; + } + + if (formatInfo.depthBits > 0 || formatInfo.stencilBits > 0) + { + return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; + } + } + else if (colorAttachment->type() == GL_RENDERBUFFER) + { + if (!formatCaps.renderable || formatInfo.depthBits > 0 || formatInfo.stencilBits > 0) + { + return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; + } + } + + if (!missingAttachment) + { + // all color attachments must have the same width and height + if (colorAttachment->getWidth() != width || colorAttachment->getHeight() != height) + { + return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS; + } + + // APPLE_framebuffer_multisample, which EXT_draw_buffers refers to, requires that + // all color attachments have the same number of samples for the FBO to be complete. + if (colorAttachment->getSamples() != samples) + { + return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT; + } + + // in GLES 2.0, all color attachments attachments must have the same number of bitplanes + // in GLES 3.0, there is no such restriction + if (data.clientVersion < 3) + { + if (formatInfo.pixelBytes != colorbufferSize) + { + return GL_FRAMEBUFFER_UNSUPPORTED; + } + } + } + else + { + width = colorAttachment->getWidth(); + height = colorAttachment->getHeight(); + samples = colorAttachment->getSamples(); + colorbufferSize = formatInfo.pixelBytes; + missingAttachment = false; + } + } + } + + const FramebufferAttachment *depthAttachment = mData.mDepthAttachment; + if (depthAttachment != nullptr) + { + if (depthAttachment->getWidth() == 0 || depthAttachment->getHeight() == 0) + { + return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; + } + + GLenum internalformat = depthAttachment->getInternalFormat(); + const TextureCaps &formatCaps = data.textureCaps->get(internalformat); + const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat); + if (depthAttachment->type() == GL_TEXTURE) + { + // depth texture attachments require OES/ANGLE_depth_texture + if (!data.extensions->depthTextures) + { + return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; + } + + if (!formatCaps.renderable) + { + return GL_FRAMEBUFFER_UNSUPPORTED; + } + + if (formatInfo.depthBits == 0) + { + return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; + } + } + else if (depthAttachment->type() == GL_RENDERBUFFER) + { + if (!formatCaps.renderable || formatInfo.depthBits == 0) + { + return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; + } + } + + if (missingAttachment) + { + width = depthAttachment->getWidth(); + height = depthAttachment->getHeight(); + samples = depthAttachment->getSamples(); + missingAttachment = false; + } + else if (width != depthAttachment->getWidth() || height != depthAttachment->getHeight()) + { + return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS; + } + else if (samples != depthAttachment->getSamples()) + { + return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE; + } + } + + const FramebufferAttachment *stencilAttachment = mData.mStencilAttachment; + if (stencilAttachment) + { + if (stencilAttachment->getWidth() == 0 || stencilAttachment->getHeight() == 0) + { + return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; + } + + GLenum internalformat = stencilAttachment->getInternalFormat(); + const TextureCaps &formatCaps = data.textureCaps->get(internalformat); + const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat); + if (stencilAttachment->type() == GL_TEXTURE) + { + // texture stencil attachments come along as part + // of OES_packed_depth_stencil + OES/ANGLE_depth_texture + if (!data.extensions->depthTextures) + { + return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; + } + + if (!formatCaps.renderable) + { + return GL_FRAMEBUFFER_UNSUPPORTED; + } + + if (formatInfo.stencilBits == 0) + { + return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; + } + } + else if (stencilAttachment->type() == GL_RENDERBUFFER) + { + if (!formatCaps.renderable || formatInfo.stencilBits == 0) + { + return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; + } + } + + if (missingAttachment) + { + width = stencilAttachment->getWidth(); + height = stencilAttachment->getHeight(); + samples = stencilAttachment->getSamples(); + missingAttachment = false; + } + else if (width != stencilAttachment->getWidth() || height != stencilAttachment->getHeight()) + { + return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS; + } + else if (samples != stencilAttachment->getSamples()) + { + return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE; + } + } + + // if we have both a depth and stencil buffer, they must refer to the same object + // since we only support packed_depth_stencil and not separate depth and stencil + if (depthAttachment && stencilAttachment && !hasValidDepthStencil()) + { + return GL_FRAMEBUFFER_UNSUPPORTED; + } + + // we need to have at least one attachment to be complete + if (missingAttachment) + { + return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT; + } + + return mImpl->checkStatus(); +} + +Error Framebuffer::invalidate(size_t count, const GLenum *attachments) +{ + return mImpl->invalidate(count, attachments); +} + +Error Framebuffer::invalidateSub(size_t count, const GLenum *attachments, const gl::Rectangle &area) +{ + return mImpl->invalidateSub(count, attachments, area); +} + +Error Framebuffer::clear(const gl::Data &data, GLbitfield mask) +{ + return mImpl->clear(data, mask); +} + +Error Framebuffer::clearBufferfv(const State &state, GLenum buffer, GLint drawbuffer, const GLfloat *values) +{ + return mImpl->clearBufferfv(state, buffer, drawbuffer, values); +} + +Error Framebuffer::clearBufferuiv(const State &state, GLenum buffer, GLint drawbuffer, const GLuint *values) +{ + return mImpl->clearBufferuiv(state, buffer, drawbuffer, values); +} + +Error Framebuffer::clearBufferiv(const State &state, GLenum buffer, GLint drawbuffer, const GLint *values) +{ + return mImpl->clearBufferiv(state, buffer, drawbuffer, values); +} + +Error Framebuffer::clearBufferfi(const State &state, GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil) +{ + return mImpl->clearBufferfi(state, buffer, drawbuffer, depth, stencil); +} + +GLenum Framebuffer::getImplementationColorReadFormat() const +{ + return mImpl->getImplementationColorReadFormat(); +} + +GLenum Framebuffer::getImplementationColorReadType() const +{ + return mImpl->getImplementationColorReadType(); +} + +Error Framebuffer::readPixels(const gl::State &state, const gl::Rectangle &area, GLenum format, GLenum type, GLvoid *pixels) const +{ + return mImpl->readPixels(state, area, format, type, pixels); +} + +Error Framebuffer::blit(const gl::State &state, const gl::Rectangle &sourceArea, const gl::Rectangle &destArea, + GLbitfield mask, GLenum filter, const gl::Framebuffer *sourceFramebuffer) +{ + return mImpl->blit(state, sourceArea, destArea, mask, filter, sourceFramebuffer); +} + +int Framebuffer::getSamples(const gl::Data &data) const +{ + if (checkStatus(data) == GL_FRAMEBUFFER_COMPLETE) + { + // for a complete framebuffer, all attachments must have the same sample count + // in this case return the first nonzero sample size + for (auto it = mData.mColorAttachments.cbegin(); it != mData.mColorAttachments.cend(); ++it) + { + if (*it != nullptr) + { + return (*it)->getSamples(); + } + } + } + + return 0; +} + +bool Framebuffer::hasValidDepthStencil() const +{ + // A valid depth-stencil attachment has the same resource bound to both the + // depth and stencil attachment points. + return (mData.mDepthAttachment && mData.mStencilAttachment && + mData.mDepthAttachment->type() == mData.mStencilAttachment->type() && + mData.mDepthAttachment->id() == mData.mStencilAttachment->id()); +} + +void Framebuffer::setTextureAttachment(GLenum attachment, Texture *texture, const ImageIndex &imageIndex) +{ + setAttachment(attachment, new TextureAttachment(attachment, texture, imageIndex)); +} + +void Framebuffer::setRenderbufferAttachment(GLenum attachment, Renderbuffer *renderbuffer) +{ + setAttachment(attachment, new RenderbufferAttachment(attachment, renderbuffer)); +} + +void Framebuffer::setNULLAttachment(GLenum attachment) +{ + setAttachment(attachment, NULL); +} + +void Framebuffer::setAttachment(GLenum attachment, FramebufferAttachment *attachmentObj) +{ + if (attachment >= GL_COLOR_ATTACHMENT0 && attachment < (GL_COLOR_ATTACHMENT0 + mData.mColorAttachments.size())) + { + size_t colorAttachment = attachment - GL_COLOR_ATTACHMENT0; + SafeDelete(mData.mColorAttachments[colorAttachment]); + mData.mColorAttachments[colorAttachment] = attachmentObj; + mImpl->setColorAttachment(colorAttachment, attachmentObj); + } + else if (attachment == GL_BACK) + { + SafeDelete(mData.mColorAttachments[0]); + mData.mColorAttachments[0] = attachmentObj; + mImpl->setColorAttachment(0, attachmentObj); + } + else if (attachment == GL_DEPTH_ATTACHMENT || attachment == GL_DEPTH) + { + SafeDelete(mData.mDepthAttachment); + mData.mDepthAttachment = attachmentObj; + mImpl->setDepthAttachment(attachmentObj); + } + else if (attachment == GL_STENCIL_ATTACHMENT || attachment == GL_STENCIL) + { + SafeDelete(mData.mStencilAttachment); + mData.mStencilAttachment = attachmentObj; + mImpl->setStencilAttachment(attachmentObj); + } + else if (attachment == GL_DEPTH_STENCIL_ATTACHMENT || attachment == GL_DEPTH_STENCIL) + { + SafeDelete(mData.mDepthAttachment); + SafeDelete(mData.mStencilAttachment); + + // ensure this is a legitimate depth+stencil format + if (attachmentObj && attachmentObj->getDepthSize() > 0 && attachmentObj->getStencilSize() > 0) + { + mData.mDepthAttachment = attachmentObj; + mImpl->setDepthAttachment(attachmentObj); + + // Make a new attachment object to ensure we do not double-delete + // See angle issue 686 + if (attachmentObj->type() == GL_TEXTURE) + { + mData.mStencilAttachment = new TextureAttachment(GL_DEPTH_STENCIL_ATTACHMENT, attachmentObj->getTexture(), + *attachmentObj->getTextureImageIndex()); + mImpl->setStencilAttachment(mData.mStencilAttachment); + } + else if (attachmentObj->type() == GL_RENDERBUFFER) + { + mData.mStencilAttachment = new RenderbufferAttachment(GL_DEPTH_STENCIL_ATTACHMENT, attachmentObj->getRenderbuffer()); + mImpl->setStencilAttachment(mData.mStencilAttachment); + } + else + { + UNREACHABLE(); + } + } + } + else + { + UNREACHABLE(); + } +} + +DefaultFramebuffer::DefaultFramebuffer(const Caps &caps, rx::ImplFactory *factory, egl::Surface *surface) + : Framebuffer(caps, factory, 0) +{ + const egl::Config *config = surface->getConfig(); + + setAttachment(GL_BACK, new DefaultAttachment(GL_BACK, surface)); + + if (config->depthSize > 0) + { + setAttachment(GL_DEPTH, new DefaultAttachment(GL_DEPTH, surface)); + } + if (config->stencilSize > 0) + { + setAttachment(GL_STENCIL, new DefaultAttachment(GL_STENCIL, surface)); + } + + GLenum drawBufferState = GL_BACK; + setDrawBuffers(1, &drawBufferState); + + setReadBuffer(GL_BACK); +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/Framebuffer.h b/src/3rdparty/angle/src/libANGLE/Framebuffer.h new file mode 100644 index 0000000000..8b24cf984e --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/Framebuffer.h @@ -0,0 +1,144 @@ +// +// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Framebuffer.h: Defines the gl::Framebuffer class. Implements GL framebuffer +// objects and related functionality. [OpenGL ES 2.0.24] section 4.4 page 105. + +#ifndef LIBANGLE_FRAMEBUFFER_H_ +#define LIBANGLE_FRAMEBUFFER_H_ + +#include + +#include "common/angleutils.h" +#include "libANGLE/Constants.h" +#include "libANGLE/Error.h" +#include "libANGLE/RefCountObject.h" + +namespace rx +{ +class ImplFactory; +class FramebufferImpl; +class RenderbufferImpl; +struct Workarounds; +} + +namespace egl +{ +class Surface; +} + +namespace gl +{ +class FramebufferAttachment; +class Renderbuffer; +class State; +class Texture; +class TextureCapsMap; +struct Caps; +struct Data; +struct Extensions; +struct ImageIndex; +struct Rectangle; + +typedef std::vector AttachmentList; + +class Framebuffer +{ + public: + + class Data final : angle::NonCopyable + { + public: + explicit Data(const Caps &caps); + ~Data(); + + FramebufferAttachment *getReadAttachment() const; + FramebufferAttachment *getFirstColorAttachment() const; + FramebufferAttachment *getDepthOrStencilAttachment() const; + + AttachmentList mColorAttachments; + FramebufferAttachment *mDepthAttachment; + FramebufferAttachment *mStencilAttachment; + + std::vector mDrawBufferStates; + GLenum mReadBufferState; + }; + + Framebuffer(const Caps &caps, rx::ImplFactory *factory, GLuint id); + virtual ~Framebuffer(); + + const rx::FramebufferImpl *getImplementation() const { return mImpl; } + rx::FramebufferImpl *getImplementation() { return mImpl; } + + GLuint id() const { return mId; } + + void setTextureAttachment(GLenum attachment, Texture *texture, const ImageIndex &imageIndex); + void setRenderbufferAttachment(GLenum attachment, Renderbuffer *renderbuffer); + void setNULLAttachment(GLenum attachment); + + void detachTexture(GLuint texture); + void detachRenderbuffer(GLuint renderbuffer); + + FramebufferAttachment *getColorbuffer(unsigned int colorAttachment) const; + FramebufferAttachment *getDepthbuffer() const; + FramebufferAttachment *getStencilbuffer() const; + FramebufferAttachment *getDepthStencilBuffer() const; + FramebufferAttachment *getDepthOrStencilbuffer() const; + FramebufferAttachment *getReadColorbuffer() const; + GLenum getReadColorbufferType() const; + FramebufferAttachment *getFirstColorbuffer() const; + + FramebufferAttachment *getAttachment(GLenum attachment) const; + + GLenum getDrawBufferState(unsigned int colorAttachment) const; + void setDrawBuffers(size_t count, const GLenum *buffers); + + GLenum getReadBufferState() const; + void setReadBuffer(GLenum buffer); + + bool isEnabledColorAttachment(unsigned int colorAttachment) const; + bool hasEnabledColorAttachment() const; + bool hasStencil() const; + int getSamples(const gl::Data &data) const; + bool usingExtendedDrawBuffers() const; + + GLenum checkStatus(const gl::Data &data) const; + bool hasValidDepthStencil() const; + + Error invalidate(size_t count, const GLenum *attachments); + Error invalidateSub(size_t count, const GLenum *attachments, const gl::Rectangle &area); + + Error clear(const gl::Data &data, GLbitfield mask); + Error clearBufferfv(const State &state, GLenum buffer, GLint drawbuffer, const GLfloat *values); + Error clearBufferuiv(const State &state, GLenum buffer, GLint drawbuffer, const GLuint *values); + Error clearBufferiv(const State &state, GLenum buffer, GLint drawbuffer, const GLint *values); + Error clearBufferfi(const State &state, GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil); + + GLenum getImplementationColorReadFormat() const; + GLenum getImplementationColorReadType() const; + Error readPixels(const gl::State &state, const gl::Rectangle &area, GLenum format, GLenum type, GLvoid *pixels) const; + + Error blit(const gl::State &state, const gl::Rectangle &sourceArea, const gl::Rectangle &destArea, + GLbitfield mask, GLenum filter, const gl::Framebuffer *sourceFramebuffer); + + protected: + void setAttachment(GLenum attachment, FramebufferAttachment *attachmentObj); + void detachResourceById(GLenum resourceType, GLuint resourceId); + + Data mData; + rx::FramebufferImpl *mImpl; + GLuint mId; +}; + +class DefaultFramebuffer : public Framebuffer +{ + public: + DefaultFramebuffer(const gl::Caps &caps, rx::ImplFactory *factory, egl::Surface *surface); +}; + +} + +#endif // LIBANGLE_FRAMEBUFFER_H_ diff --git a/src/3rdparty/angle/src/libANGLE/FramebufferAttachment.cpp b/src/3rdparty/angle/src/libANGLE/FramebufferAttachment.cpp new file mode 100644 index 0000000000..e56fc750ad --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/FramebufferAttachment.cpp @@ -0,0 +1,302 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// FramebufferAttachment.cpp: the gl::FramebufferAttachment class and its derived classes +// objects and related functionality. [OpenGL ES 2.0.24] section 4.4.3 page 108. + +#include "libANGLE/FramebufferAttachment.h" + +#include "common/utilities.h" +#include "libANGLE/Config.h" +#include "libANGLE/Renderbuffer.h" +#include "libANGLE/Surface.h" +#include "libANGLE/Texture.h" +#include "libANGLE/formatutils.h" +#include "libANGLE/renderer/FramebufferImpl.h" + +namespace gl +{ + +////// FramebufferAttachment Implementation ////// + +FramebufferAttachment::FramebufferAttachment(GLenum binding) + : mBinding(binding) +{ +} + +FramebufferAttachment::~FramebufferAttachment() +{ +} + +GLuint FramebufferAttachment::getRedSize() const +{ + return GetInternalFormatInfo(getInternalFormat()).redBits; +} + +GLuint FramebufferAttachment::getGreenSize() const +{ + return GetInternalFormatInfo(getInternalFormat()).greenBits; +} + +GLuint FramebufferAttachment::getBlueSize() const +{ + return GetInternalFormatInfo(getInternalFormat()).blueBits; +} + +GLuint FramebufferAttachment::getAlphaSize() const +{ + return GetInternalFormatInfo(getInternalFormat()).alphaBits; +} + +GLuint FramebufferAttachment::getDepthSize() const +{ + return GetInternalFormatInfo(getInternalFormat()).depthBits; +} + +GLuint FramebufferAttachment::getStencilSize() const +{ + return GetInternalFormatInfo(getInternalFormat()).stencilBits; +} + +GLenum FramebufferAttachment::getComponentType() const +{ + return GetInternalFormatInfo(getInternalFormat()).componentType; +} + +GLenum FramebufferAttachment::getColorEncoding() const +{ + return GetInternalFormatInfo(getInternalFormat()).colorEncoding; +} + +///// TextureAttachment Implementation //////// + +TextureAttachment::TextureAttachment(GLenum binding, Texture *texture, const ImageIndex &index) + : FramebufferAttachment(binding), + mIndex(index) +{ + mTexture.set(texture); +} + +TextureAttachment::~TextureAttachment() +{ + mTexture.set(NULL); +} + +GLsizei TextureAttachment::getSamples() const +{ + return 0; +} + +GLuint TextureAttachment::id() const +{ + return mTexture->id(); +} + +GLsizei TextureAttachment::getWidth() const +{ + return mTexture->getWidth(mIndex.type, mIndex.mipIndex); +} + +GLsizei TextureAttachment::getHeight() const +{ + return mTexture->getHeight(mIndex.type, mIndex.mipIndex); +} + +GLenum TextureAttachment::getInternalFormat() const +{ + return mTexture->getInternalFormat(mIndex.type, mIndex.mipIndex); +} + +GLenum TextureAttachment::type() const +{ + return GL_TEXTURE; +} + +GLint TextureAttachment::mipLevel() const +{ + return mIndex.mipIndex; +} + +GLenum TextureAttachment::cubeMapFace() const +{ + return IsCubeMapTextureTarget(mIndex.type) ? mIndex.type : GL_NONE; +} + +GLint TextureAttachment::layer() const +{ + return mIndex.layerIndex; +} + +Texture *TextureAttachment::getTexture() const +{ + return mTexture.get(); +} + +const ImageIndex *TextureAttachment::getTextureImageIndex() const +{ + return &mIndex; +} + +Renderbuffer *TextureAttachment::getRenderbuffer() const +{ + UNREACHABLE(); + return NULL; +} + +////// RenderbufferAttachment Implementation ////// + +RenderbufferAttachment::RenderbufferAttachment(GLenum binding, Renderbuffer *renderbuffer) + : FramebufferAttachment(binding) +{ + ASSERT(renderbuffer); + mRenderbuffer.set(renderbuffer); +} + +RenderbufferAttachment::~RenderbufferAttachment() +{ + mRenderbuffer.set(NULL); +} + +GLsizei RenderbufferAttachment::getWidth() const +{ + return mRenderbuffer->getWidth(); +} + +GLsizei RenderbufferAttachment::getHeight() const +{ + return mRenderbuffer->getHeight(); +} + +GLenum RenderbufferAttachment::getInternalFormat() const +{ + return mRenderbuffer->getInternalFormat(); +} + +GLsizei RenderbufferAttachment::getSamples() const +{ + return mRenderbuffer->getSamples(); +} + +GLuint RenderbufferAttachment::id() const +{ + return mRenderbuffer->id(); +} + +GLenum RenderbufferAttachment::type() const +{ + return GL_RENDERBUFFER; +} + +GLint RenderbufferAttachment::mipLevel() const +{ + return 0; +} + +GLenum RenderbufferAttachment::cubeMapFace() const +{ + return GL_NONE; +} + +GLint RenderbufferAttachment::layer() const +{ + return 0; +} + +Texture *RenderbufferAttachment::getTexture() const +{ + UNREACHABLE(); + return NULL; +} + +const ImageIndex *RenderbufferAttachment::getTextureImageIndex() const +{ + UNREACHABLE(); + return NULL; +} + +Renderbuffer *RenderbufferAttachment::getRenderbuffer() const +{ + return mRenderbuffer.get(); +} + + +DefaultAttachment::DefaultAttachment(GLenum binding, egl::Surface *surface) + : FramebufferAttachment(binding) +{ + mSurface.set(surface); +} + +DefaultAttachment::~DefaultAttachment() +{ + mSurface.set(nullptr); +} + +GLsizei DefaultAttachment::getWidth() const +{ + return mSurface->getWidth(); +} + +GLsizei DefaultAttachment::getHeight() const +{ + return mSurface->getHeight(); +} + +GLenum DefaultAttachment::getInternalFormat() const +{ + const egl::Config *config = mSurface->getConfig(); + return (getBinding() == GL_BACK ? config->renderTargetFormat : config->depthStencilFormat); +} + +GLsizei DefaultAttachment::getSamples() const +{ + const egl::Config *config = mSurface->getConfig(); + return config->samples; +} + +GLuint DefaultAttachment::id() const +{ + return 0; +} + +GLenum DefaultAttachment::type() const +{ + return GL_FRAMEBUFFER_DEFAULT; +} + +GLint DefaultAttachment::mipLevel() const +{ + return 0; +} + +GLenum DefaultAttachment::cubeMapFace() const +{ + return GL_NONE; +} + +GLint DefaultAttachment::layer() const +{ + return 0; +} + +Texture *DefaultAttachment::getTexture() const +{ + UNREACHABLE(); + return NULL; +} + +const ImageIndex *DefaultAttachment::getTextureImageIndex() const +{ + UNREACHABLE(); + return NULL; +} + +Renderbuffer *DefaultAttachment::getRenderbuffer() const +{ + UNREACHABLE(); + return NULL; +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/FramebufferAttachment.h b/src/3rdparty/angle/src/libANGLE/FramebufferAttachment.h new file mode 100644 index 0000000000..0662130931 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/FramebufferAttachment.h @@ -0,0 +1,154 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// FramebufferAttachment.h: Defines the wrapper class gl::FramebufferAttachment, as well as the +// objects and related functionality. [OpenGL ES 2.0.24] section 4.4.3 page 108. + +#ifndef LIBANGLE_FRAMEBUFFERATTACHMENT_H_ +#define LIBANGLE_FRAMEBUFFERATTACHMENT_H_ + +#include "libANGLE/Texture.h" +#include "libANGLE/RefCountObject.h" + +#include "common/angleutils.h" + +#include "angle_gl.h" + +namespace gl +{ +class Renderbuffer; + +// FramebufferAttachment implements a GL framebuffer attachment. +// Attachments are "light" containers, which store pointers to ref-counted GL objects. +// We support GL texture (2D/3D/Cube/2D array) and renderbuffer object attachments. +// Note: Our old naming scheme used the term "Renderbuffer" for both GL renderbuffers and for +// framebuffer attachments, which confused their usage. + +class FramebufferAttachment : angle::NonCopyable +{ + public: + explicit FramebufferAttachment(GLenum binding); + virtual ~FramebufferAttachment(); + + // Helper methods + GLuint getRedSize() const; + GLuint getGreenSize() const; + GLuint getBlueSize() const; + GLuint getAlphaSize() const; + GLuint getDepthSize() const; + GLuint getStencilSize() const; + GLenum getComponentType() const; + GLenum getColorEncoding() const; + + bool isTextureWithId(GLuint textureId) const { return type() == GL_TEXTURE && id() == textureId; } + bool isRenderbufferWithId(GLuint renderbufferId) const { return type() == GL_RENDERBUFFER && id() == renderbufferId; } + + GLenum getBinding() const { return mBinding; } + + // Child class interface + virtual GLsizei getWidth() const = 0; + virtual GLsizei getHeight() const = 0; + virtual GLenum getInternalFormat() const = 0; + virtual GLsizei getSamples() const = 0; + + virtual GLuint id() const = 0; + virtual GLenum type() const = 0; + virtual GLint mipLevel() const = 0; + virtual GLenum cubeMapFace() const = 0; + virtual GLint layer() const = 0; + + virtual Texture *getTexture() const = 0; + virtual const ImageIndex *getTextureImageIndex() const = 0; + virtual Renderbuffer *getRenderbuffer() const = 0; + + private: + GLenum mBinding; +}; + +class TextureAttachment : public FramebufferAttachment +{ + public: + TextureAttachment(GLenum binding, Texture *texture, const ImageIndex &index); + virtual ~TextureAttachment(); + + virtual GLsizei getSamples() const; + virtual GLuint id() const; + + virtual GLsizei getWidth() const; + virtual GLsizei getHeight() const; + virtual GLenum getInternalFormat() const; + + virtual GLenum type() const; + virtual GLint mipLevel() const; + virtual GLenum cubeMapFace() const; + virtual GLint layer() const; + + virtual Texture *getTexture() const; + virtual const ImageIndex *getTextureImageIndex() const; + virtual Renderbuffer *getRenderbuffer() const; + + private: + BindingPointer mTexture; + ImageIndex mIndex; +}; + +class RenderbufferAttachment : public FramebufferAttachment +{ + public: + RenderbufferAttachment(GLenum binding, Renderbuffer *renderbuffer); + + virtual ~RenderbufferAttachment(); + + virtual GLsizei getWidth() const; + virtual GLsizei getHeight() const; + virtual GLenum getInternalFormat() const; + virtual GLsizei getSamples() const; + + virtual GLuint id() const; + virtual GLenum type() const; + virtual GLint mipLevel() const; + virtual GLenum cubeMapFace() const; + virtual GLint layer() const; + + virtual Texture *getTexture() const; + virtual const ImageIndex *getTextureImageIndex() const; + virtual Renderbuffer *getRenderbuffer() const; + + private: + BindingPointer mRenderbuffer; +}; + +class DefaultAttachment : public FramebufferAttachment +{ + public: + DefaultAttachment(GLenum binding, egl::Surface *surface); + + virtual ~DefaultAttachment(); + + virtual GLsizei getWidth() const; + virtual GLsizei getHeight() const; + virtual GLenum getInternalFormat() const; + virtual GLsizei getSamples() const; + + virtual GLuint id() const; + virtual GLenum type() const; + virtual GLint mipLevel() const; + virtual GLenum cubeMapFace() const; + virtual GLint layer() const; + + virtual Texture *getTexture() const; + virtual const ImageIndex *getTextureImageIndex() const; + virtual Renderbuffer *getRenderbuffer() const; + + const egl::Surface *getSurface() const { return mSurface.get(); } + + private: + BindingPointer mSurface; +}; + +} + +#endif // LIBANGLE_FRAMEBUFFERATTACHMENT_H_ diff --git a/src/3rdparty/angle/src/libANGLE/HandleAllocator.cpp b/src/3rdparty/angle/src/libANGLE/HandleAllocator.cpp new file mode 100644 index 0000000000..59d3966758 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/HandleAllocator.cpp @@ -0,0 +1,133 @@ +// +// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// HandleAllocator.cpp: Implements the gl::HandleAllocator class, which is used +// to allocate GL handles. + +#include "libANGLE/HandleAllocator.h" + +#include + +#include "common/debug.h" + +namespace gl +{ + +struct HandleAllocator::HandleRangeComparator +{ + bool operator()(const HandleRange &range, GLuint handle) const + { + return (handle < range.begin); + } +}; + +HandleAllocator::HandleAllocator() : mBaseValue(1), mNextValue(1) +{ + mUnallocatedList.push_back(HandleRange(1, std::numeric_limits::max() - 1)); +} + +HandleAllocator::HandleAllocator(GLuint maximumHandleValue) : mBaseValue(1), mNextValue(1) +{ + mUnallocatedList.push_back(HandleRange(1, maximumHandleValue)); +} + +HandleAllocator::~HandleAllocator() +{ +} + +void HandleAllocator::setBaseHandle(GLuint value) +{ + ASSERT(mBaseValue == mNextValue); + mBaseValue = value; + mNextValue = value; +} + +GLuint HandleAllocator::allocate() +{ + ASSERT(!mUnallocatedList.empty() || !mReleasedList.empty()); + + // Allocate from released list, constant time. + if (!mReleasedList.empty()) + { + GLuint reusedHandle = mReleasedList.back(); + mReleasedList.pop_back(); + return reusedHandle; + } + + // Allocate from unallocated list, constant time. + auto listIt = mUnallocatedList.begin(); + + GLuint freeListHandle = listIt->begin; + ASSERT(freeListHandle > 0); + + listIt->begin++; + if (listIt->begin == listIt->end) + { + mUnallocatedList.erase(listIt); + } + + return freeListHandle; +} + +void HandleAllocator::release(GLuint handle) +{ + // Add to released list, constant time. + mReleasedList.push_back(handle); +} + +void HandleAllocator::reserve(GLuint handle) +{ + // Clear from released list -- might be a slow operation. + if (!mReleasedList.empty()) + { + auto releasedIt = std::find(mReleasedList.begin(), mReleasedList.end(), handle); + if (releasedIt != mReleasedList.end()) + { + mReleasedList.erase(releasedIt); + return; + } + } + + // Not in released list, reserve in the unallocated list. + auto boundIt = std::lower_bound(mUnallocatedList.begin(), mUnallocatedList.end(), handle, HandleRangeComparator()); + + ASSERT(boundIt != mUnallocatedList.end()); + + GLuint begin = boundIt->begin; + GLuint end = boundIt->end; + + if (handle == begin || handle == end) + { + if (begin + 1 == end) + { + mUnallocatedList.erase(boundIt); + } + else if (handle == begin) + { + boundIt->begin++; + } + else + { + ASSERT(handle == end); + boundIt->end--; + } + return; + } + + // need to split the range + auto placementIt = mUnallocatedList.erase(boundIt); + + if (begin != handle) + { + placementIt = mUnallocatedList.insert(placementIt, HandleRange(begin, handle)); + } + if (handle + 1 != end) + { + mUnallocatedList.insert(placementIt, HandleRange(handle + 1, end)); + } +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/HandleAllocator.h b/src/3rdparty/angle/src/libANGLE/HandleAllocator.h new file mode 100644 index 0000000000..c22f2ba61a --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/HandleAllocator.h @@ -0,0 +1,63 @@ +// +// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// HandleAllocator.h: Defines the gl::HandleAllocator class, which is used to +// allocate GL handles. + +#ifndef LIBANGLE_HANDLEALLOCATOR_H_ +#define LIBANGLE_HANDLEALLOCATOR_H_ + +#include "common/angleutils.h" + +#include "angle_gl.h" + +#include + +namespace gl +{ + +class HandleAllocator final : angle::NonCopyable +{ + public: + // Maximum handle = MAX_UINT-1 + HandleAllocator(); + // Specify maximum handle value + HandleAllocator(GLuint maximumHandleValue); + + ~HandleAllocator(); + + void setBaseHandle(GLuint value); + + GLuint allocate(); + void release(GLuint handle); + void reserve(GLuint handle); + + private: + GLuint mBaseValue; + GLuint mNextValue; + typedef std::vector HandleList; + HandleList mFreeValues; + + struct HandleRange + { + HandleRange(GLuint beginIn, GLuint endIn) : begin(beginIn), end(endIn) {} + + GLuint begin; + GLuint end; + }; + + struct HandleRangeComparator; + + // The freelist consists of never-allocated handles, stored + // as ranges, and handles that were previously allocated and + // released, stored in a stack. + std::vector mUnallocatedList; + std::vector mReleasedList; +}; + +} + +#endif // LIBANGLE_HANDLEALLOCATOR_H_ diff --git a/src/3rdparty/angle/src/libANGLE/ImageIndex.cpp b/src/3rdparty/angle/src/libANGLE/ImageIndex.cpp new file mode 100644 index 0000000000..ac7302d121 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/ImageIndex.cpp @@ -0,0 +1,170 @@ +// +// Copyright 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// ImageIndex.cpp: Implementation for ImageIndex methods. + +#include "libANGLE/ImageIndex.h" +#include "libANGLE/Constants.h" +#include "common/utilities.h" + +namespace gl +{ + +ImageIndex::ImageIndex(const ImageIndex &other) + : type(other.type), + mipIndex(other.mipIndex), + layerIndex(other.layerIndex) +{} + +ImageIndex &ImageIndex::operator=(const ImageIndex &other) +{ + type = other.type; + mipIndex = other.mipIndex; + layerIndex = other.layerIndex; + return *this; +} + +ImageIndex ImageIndex::Make2D(GLint mipIndex) +{ + return ImageIndex(GL_TEXTURE_2D, mipIndex, ENTIRE_LEVEL); +} + +ImageIndex ImageIndex::MakeCube(GLenum target, GLint mipIndex) +{ + ASSERT(gl::IsCubeMapTextureTarget(target)); + return ImageIndex(target, mipIndex, CubeMapTextureTargetToLayerIndex(target)); +} + +ImageIndex ImageIndex::Make2DArray(GLint mipIndex, GLint layerIndex) +{ + return ImageIndex(GL_TEXTURE_2D_ARRAY, mipIndex, layerIndex); +} + +ImageIndex ImageIndex::Make3D(GLint mipIndex, GLint layerIndex) +{ + return ImageIndex(GL_TEXTURE_3D, mipIndex, layerIndex); +} + +ImageIndex ImageIndex::MakeGeneric(GLenum target, GLint mipIndex) +{ + GLint layerIndex = IsCubeMapTextureTarget(target) ? CubeMapTextureTargetToLayerIndex(target) : ENTIRE_LEVEL; + return ImageIndex(target, mipIndex, layerIndex); +} + +ImageIndex ImageIndex::MakeInvalid() +{ + return ImageIndex(GL_NONE, -1, -1); +} + +bool ImageIndex::operator<(const ImageIndex &other) const +{ + if (type != other.type) + { + return type < other.type; + } + else if (mipIndex != other.mipIndex) + { + return mipIndex < other.mipIndex; + } + else + { + return layerIndex < other.layerIndex; + } +} + +ImageIndex::ImageIndex(GLenum typeIn, GLint mipIndexIn, GLint layerIndexIn) + : type(typeIn), + mipIndex(mipIndexIn), + layerIndex(layerIndexIn) +{} + +ImageIndexIterator ImageIndexIterator::Make2D(GLint minMip, GLint maxMip) +{ + return ImageIndexIterator(GL_TEXTURE_2D, rx::Range(minMip, maxMip), + rx::Range(ImageIndex::ENTIRE_LEVEL, ImageIndex::ENTIRE_LEVEL), NULL); +} + +ImageIndexIterator ImageIndexIterator::MakeCube(GLint minMip, GLint maxMip) +{ + return ImageIndexIterator(GL_TEXTURE_CUBE_MAP, rx::Range(minMip, maxMip), rx::Range(0, 6), NULL); +} + +ImageIndexIterator ImageIndexIterator::Make3D(GLint minMip, GLint maxMip, + GLint minLayer, GLint maxLayer) +{ + return ImageIndexIterator(GL_TEXTURE_3D, rx::Range(minMip, maxMip), rx::Range(minLayer, maxLayer), NULL); +} + +ImageIndexIterator ImageIndexIterator::Make2DArray(GLint minMip, GLint maxMip, + const GLsizei *layerCounts) +{ + return ImageIndexIterator(GL_TEXTURE_2D_ARRAY, rx::Range(minMip, maxMip), + rx::Range(0, IMPLEMENTATION_MAX_2D_ARRAY_TEXTURE_LAYERS), layerCounts); +} + +ImageIndexIterator::ImageIndexIterator(GLenum type, const rx::Range &mipRange, + const rx::Range &layerRange, const GLsizei *layerCounts) + : mType(type), + mMipRange(mipRange), + mLayerRange(layerRange), + mLayerCounts(layerCounts), + mCurrentMip(mipRange.start), + mCurrentLayer(layerRange.start) +{} + +GLint ImageIndexIterator::maxLayer() const +{ + return (mLayerCounts ? static_cast(mLayerCounts[mCurrentMip]) : mLayerRange.end); +} + +ImageIndex ImageIndexIterator::next() +{ + ASSERT(hasNext()); + + ImageIndex value = current(); + + // Iterate layers in the inner loop for now. We can add switchable + // layer or mip iteration if we need it. + + if (mCurrentLayer != ImageIndex::ENTIRE_LEVEL) + { + if (mCurrentLayer < maxLayer()-1) + { + mCurrentLayer++; + } + else if (mCurrentMip < mMipRange.end-1) + { + mCurrentMip++; + mCurrentLayer = mLayerRange.start; + } + } + else if (mCurrentMip < mMipRange.end-1) + { + mCurrentMip++; + mCurrentLayer = mLayerRange.start; + } + + return value; +} + +ImageIndex ImageIndexIterator::current() const +{ + ImageIndex value(mType, mCurrentMip, mCurrentLayer); + + if (mType == GL_TEXTURE_CUBE_MAP) + { + value.type = LayerIndexToCubeMapTextureTarget(mCurrentLayer); + } + + return value; +} + +bool ImageIndexIterator::hasNext() const +{ + return (mCurrentMip < mMipRange.end || mCurrentLayer < maxLayer()); +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/ImageIndex.h b/src/3rdparty/angle/src/libANGLE/ImageIndex.h new file mode 100644 index 0000000000..820c650f20 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/ImageIndex.h @@ -0,0 +1,79 @@ +// +// Copyright 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// ImageIndex.h: A helper struct for indexing into an Image array + +#ifndef LIBANGLE_IMAGE_INDEX_H_ +#define LIBANGLE_IMAGE_INDEX_H_ + +#include "common/mathutil.h" + +#include "angle_gl.h" + +namespace gl +{ + +class ImageIndexIterator; + +struct ImageIndex +{ + GLenum type; + GLint mipIndex; + GLint layerIndex; + + ImageIndex(const ImageIndex &other); + ImageIndex &operator=(const ImageIndex &other); + + bool hasLayer() const { return layerIndex != ENTIRE_LEVEL; } + + static ImageIndex Make2D(GLint mipIndex); + static ImageIndex MakeCube(GLenum target, GLint mipIndex); + static ImageIndex Make2DArray(GLint mipIndex, GLint layerIndex); + static ImageIndex Make3D(GLint mipIndex, GLint layerIndex = ENTIRE_LEVEL); + static ImageIndex MakeGeneric(GLenum target, GLint mipIndex); + + static ImageIndex MakeInvalid(); + + static const GLint ENTIRE_LEVEL = static_cast(-1); + + bool operator<(const ImageIndex &other) const; + + private: + friend class ImageIndexIterator; + + ImageIndex(GLenum typeIn, GLint mipIndexIn, GLint layerIndexIn); +}; + +class ImageIndexIterator +{ + public: + static ImageIndexIterator Make2D(GLint minMip, GLint maxMip); + static ImageIndexIterator MakeCube(GLint minMip, GLint maxMip); + static ImageIndexIterator Make3D(GLint minMip, GLint maxMip, GLint minLayer, GLint maxLayer); + static ImageIndexIterator Make2DArray(GLint minMip, GLint maxMip, const GLsizei *layerCounts); + + ImageIndex next(); + ImageIndex current() const; + bool hasNext() const; + + private: + + ImageIndexIterator(GLenum type, const rx::Range &mipRange, + const rx::Range &layerRange, const GLsizei *layerCounts); + + GLint maxLayer() const; + + GLenum mType; + rx::Range mMipRange; + rx::Range mLayerRange; + const GLsizei *mLayerCounts; + GLint mCurrentMip; + GLint mCurrentLayer; +}; + +} + +#endif // LIBANGLE_IMAGE_INDEX_H_ diff --git a/src/3rdparty/angle/src/libANGLE/Platform.cpp b/src/3rdparty/angle/src/libANGLE/Platform.cpp new file mode 100644 index 0000000000..ab75bbba5a --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/Platform.cpp @@ -0,0 +1,35 @@ +// +// Copyright 2015 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Platform.cpp: Implementation methods for angle::Platform. + +#include + +#include "common/debug.h" + +namespace +{ +angle::Platform *currentPlatform = nullptr; +} + +// static +ANGLE_EXPORT angle::Platform *ANGLEPlatformCurrent() +{ + return currentPlatform; +} + +// static +ANGLE_EXPORT void ANGLEPlatformInitialize(angle::Platform *platformImpl) +{ + ASSERT(platformImpl != nullptr); + currentPlatform = platformImpl; +} + +// static +ANGLE_EXPORT void ANGLEPlatformShutdown() +{ + currentPlatform = nullptr; +} diff --git a/src/3rdparty/angle/src/libANGLE/Program.cpp b/src/3rdparty/angle/src/libANGLE/Program.cpp new file mode 100644 index 0000000000..daf0a403f0 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/Program.cpp @@ -0,0 +1,1617 @@ +// +// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Program.cpp: Implements the gl::Program class. Implements GL program objects +// and related functionality. [OpenGL ES 2.0.24] section 2.10.3 page 28. + +#include "libANGLE/Program.h" + +#include + +#include "common/debug.h" +#include "common/platform.h" +#include "common/utilities.h" +#include "common/version.h" +#include "compiler/translator/blocklayout.h" +#include "libANGLE/Data.h" +#include "libANGLE/ResourceManager.h" +#include "libANGLE/features.h" +#include "libANGLE/renderer/Renderer.h" +#include "libANGLE/renderer/ProgramImpl.h" + +namespace gl +{ +const char * const g_fakepath = "C:\\fakepath"; + +namespace +{ + +unsigned int ParseAndStripArrayIndex(std::string* name) +{ + unsigned int subscript = GL_INVALID_INDEX; + + // Strip any trailing array operator and retrieve the subscript + size_t open = name->find_last_of('['); + size_t close = name->find_last_of(']'); + if (open != std::string::npos && close == name->length() - 1) + { + subscript = atoi(name->substr(open + 1).c_str()); + name->erase(open); + } + + return subscript; +} + +} + +AttributeBindings::AttributeBindings() +{ +} + +AttributeBindings::~AttributeBindings() +{ +} + +InfoLog::InfoLog() : mInfoLog(NULL) +{ +} + +InfoLog::~InfoLog() +{ + delete[] mInfoLog; +} + + +int InfoLog::getLength() const +{ + if (!mInfoLog) + { + return 0; + } + else + { + return strlen(mInfoLog) + 1; + } +} + +void InfoLog::getLog(GLsizei bufSize, GLsizei *length, char *infoLog) +{ + int index = 0; + + if (bufSize > 0) + { + if (mInfoLog) + { + index = std::min(bufSize - 1, (int)strlen(mInfoLog)); + memcpy(infoLog, mInfoLog, index); + } + + infoLog[index] = '\0'; + } + + if (length) + { + *length = index; + } +} + +// append a santized message to the program info log. +// The D3D compiler includes a fake file path in some of the warning or error +// messages, so lets remove all occurrences of this fake file path from the log. +void InfoLog::appendSanitized(const char *message) +{ + std::string msg(message); + + size_t found; + do + { + found = msg.find(g_fakepath); + if (found != std::string::npos) + { + msg.erase(found, strlen(g_fakepath)); + } + } + while (found != std::string::npos); + + append("%s", msg.c_str()); +} + +void InfoLog::append(const char *format, ...) +{ + if (!format) + { + return; + } + + va_list vararg; + va_start(vararg, format); + size_t infoLength = vsnprintf(NULL, 0, format, vararg); + va_end(vararg); + + char *logPointer = NULL; + + if (!mInfoLog) + { + mInfoLog = new char[infoLength + 2]; + logPointer = mInfoLog; + } + else + { + size_t currentlogLength = strlen(mInfoLog); + char *newLog = new char[currentlogLength + infoLength + 2]; + strcpy(newLog, mInfoLog); + + delete[] mInfoLog; + mInfoLog = newLog; + + logPointer = mInfoLog + currentlogLength; + } + + va_start(vararg, format); + vsnprintf(logPointer, infoLength, format, vararg); + va_end(vararg); + + logPointer[infoLength] = 0; + strcpy(logPointer + infoLength, "\n"); +} + +void InfoLog::reset() +{ + if (mInfoLog) + { + delete [] mInfoLog; + mInfoLog = NULL; + } +} + +VariableLocation::VariableLocation() + : name(), element(0), index(0) +{ +} + +VariableLocation::VariableLocation(const std::string &name, unsigned int element, unsigned int index) + : name(name), element(element), index(index) +{ +} + +LinkedVarying::LinkedVarying() +{ +} + +LinkedVarying::LinkedVarying(const std::string &name, GLenum type, GLsizei size, const std::string &semanticName, + unsigned int semanticIndex, unsigned int semanticIndexCount) + : name(name), type(type), size(size), semanticName(semanticName), semanticIndex(semanticIndex), semanticIndexCount(semanticIndexCount) +{ +} + +Program::Program(rx::ProgramImpl *impl, ResourceManager *manager, GLuint handle) + : mProgram(impl), + mValidated(false), + mTransformFeedbackVaryings(), + mTransformFeedbackBufferMode(GL_NONE), + mFragmentShader(NULL), + mVertexShader(NULL), + mLinked(false), + mDeleteStatus(false), + mRefCount(0), + mResourceManager(manager), + mHandle(handle) +{ + ASSERT(mProgram); + + resetUniformBlockBindings(); + unlink(); +} + +Program::~Program() +{ + unlink(true); + + if (mVertexShader != NULL) + { + mVertexShader->release(); + } + + if (mFragmentShader != NULL) + { + mFragmentShader->release(); + } + + SafeDelete(mProgram); +} + +bool Program::attachShader(Shader *shader) +{ + if (shader->getType() == GL_VERTEX_SHADER) + { + if (mVertexShader) + { + return false; + } + + mVertexShader = shader; + mVertexShader->addRef(); + } + else if (shader->getType() == GL_FRAGMENT_SHADER) + { + if (mFragmentShader) + { + return false; + } + + mFragmentShader = shader; + mFragmentShader->addRef(); + } + else UNREACHABLE(); + + return true; +} + +bool Program::detachShader(Shader *shader) +{ + if (shader->getType() == GL_VERTEX_SHADER) + { + if (mVertexShader != shader) + { + return false; + } + + mVertexShader->release(); + mVertexShader = NULL; + } + else if (shader->getType() == GL_FRAGMENT_SHADER) + { + if (mFragmentShader != shader) + { + return false; + } + + mFragmentShader->release(); + mFragmentShader = NULL; + } + else UNREACHABLE(); + + return true; +} + +int Program::getAttachedShadersCount() const +{ + return (mVertexShader ? 1 : 0) + (mFragmentShader ? 1 : 0); +} + +void AttributeBindings::bindAttributeLocation(GLuint index, const char *name) +{ + if (index < MAX_VERTEX_ATTRIBS) + { + for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++) + { + mAttributeBinding[i].erase(name); + } + + mAttributeBinding[index].insert(name); + } +} + +void Program::bindAttributeLocation(GLuint index, const char *name) +{ + mAttributeBindings.bindAttributeLocation(index, name); +} + +// Links the HLSL code of the vertex and pixel shader by matching up their varyings, +// compiling them into binaries, determining the attribute mappings, and collecting +// a list of uniforms +Error Program::link(const Data &data) +{ + unlink(false); + + mInfoLog.reset(); + resetUniformBlockBindings(); + + if (!mFragmentShader || !mFragmentShader->isCompiled()) + { + return Error(GL_NO_ERROR); + } + ASSERT(mFragmentShader->getType() == GL_FRAGMENT_SHADER); + + if (!mVertexShader || !mVertexShader->isCompiled()) + { + return Error(GL_NO_ERROR); + } + ASSERT(mVertexShader->getType() == GL_VERTEX_SHADER); + + if (!linkAttributes(mInfoLog, mAttributeBindings, mVertexShader)) + { + return Error(GL_NO_ERROR); + } + + int registers; + std::vector linkedVaryings; + rx::LinkResult result = mProgram->link(data, mInfoLog, mFragmentShader, mVertexShader, mTransformFeedbackVaryings, mTransformFeedbackBufferMode, + ®isters, &linkedVaryings, &mOutputVariables); + if (result.error.isError() || !result.linkSuccess) + { + return result.error; + } + + if (!mProgram->linkUniforms(mInfoLog, *mVertexShader, *mFragmentShader, *data.caps)) + { + return Error(GL_NO_ERROR); + } + + if (!linkUniformBlocks(mInfoLog, *mVertexShader, *mFragmentShader, *data.caps)) + { + return Error(GL_NO_ERROR); + } + + if (!gatherTransformFeedbackLinkedVaryings(mInfoLog, linkedVaryings, mTransformFeedbackVaryings, + mTransformFeedbackBufferMode, &mProgram->getTransformFeedbackLinkedVaryings(), *data.caps)) + { + return Error(GL_NO_ERROR); + } + + // TODO: The concept of "executables" is D3D only, and as such this belongs in ProgramD3D. It must be called, + // however, last in this function, so it can't simply be moved to ProgramD3D::link without further shuffling. + result = mProgram->compileProgramExecutables(mInfoLog, mFragmentShader, mVertexShader, registers); + if (result.error.isError() || !result.linkSuccess) + { + mInfoLog.append("Failed to create D3D shaders."); + unlink(false); + return result.error; + } + + mLinked = true; + return gl::Error(GL_NO_ERROR); +} + +int AttributeBindings::getAttributeBinding(const std::string &name) const +{ + for (int location = 0; location < MAX_VERTEX_ATTRIBS; location++) + { + if (mAttributeBinding[location].find(name) != mAttributeBinding[location].end()) + { + return location; + } + } + + return -1; +} + +// Returns the program object to an unlinked state, before re-linking, or at destruction +void Program::unlink(bool destroy) +{ + if (destroy) // Object being destructed + { + if (mFragmentShader) + { + mFragmentShader->release(); + mFragmentShader = NULL; + } + + if (mVertexShader) + { + mVertexShader->release(); + mVertexShader = NULL; + } + } + + std::fill(mLinkedAttribute, mLinkedAttribute + ArraySize(mLinkedAttribute), sh::Attribute()); + mOutputVariables.clear(); + + mProgram->reset(); + + mValidated = false; + + mLinked = false; +} + +bool Program::isLinked() +{ + return mLinked; +} + +Error Program::loadBinary(GLenum binaryFormat, const void *binary, GLsizei length) +{ + unlink(false); + +#if ANGLE_PROGRAM_BINARY_LOAD != ANGLE_ENABLED + return Error(GL_NO_ERROR); +#else + ASSERT(binaryFormat == mProgram->getBinaryFormat()); + + BinaryInputStream stream(binary, length); + + GLenum format = stream.readInt(); + if (format != mProgram->getBinaryFormat()) + { + mInfoLog.append("Invalid program binary format."); + return Error(GL_NO_ERROR); + } + + int majorVersion = stream.readInt(); + int minorVersion = stream.readInt(); + if (majorVersion != ANGLE_MAJOR_VERSION || minorVersion != ANGLE_MINOR_VERSION) + { + mInfoLog.append("Invalid program binary version."); + return Error(GL_NO_ERROR); + } + + unsigned char commitString[ANGLE_COMMIT_HASH_SIZE]; + stream.readBytes(commitString, ANGLE_COMMIT_HASH_SIZE); + if (memcmp(commitString, ANGLE_COMMIT_HASH, sizeof(unsigned char) * ANGLE_COMMIT_HASH_SIZE) != 0) + { + mInfoLog.append("Invalid program binary version."); + return Error(GL_NO_ERROR); + } + + for (int i = 0; i < MAX_VERTEX_ATTRIBS; ++i) + { + stream.readInt(&mLinkedAttribute[i].type); + stream.readString(&mLinkedAttribute[i].name); + stream.readInt(&mProgram->getShaderAttributes()[i].type); + stream.readString(&mProgram->getShaderAttributes()[i].name); + stream.readInt(&mProgram->getSemanticIndexes()[i]); + } + + rx::LinkResult result = mProgram->load(mInfoLog, &stream); + if (result.error.isError() || !result.linkSuccess) + { + return result.error; + } + + mLinked = true; + return Error(GL_NO_ERROR); +#endif // #if ANGLE_PROGRAM_BINARY_LOAD == ANGLE_ENABLED +} + +Error Program::saveBinary(GLenum *binaryFormat, void *binary, GLsizei bufSize, GLsizei *length) const +{ + if (binaryFormat) + { + *binaryFormat = mProgram->getBinaryFormat(); + } + + BinaryOutputStream stream; + + stream.writeInt(mProgram->getBinaryFormat()); + stream.writeInt(ANGLE_MAJOR_VERSION); + stream.writeInt(ANGLE_MINOR_VERSION); + stream.writeBytes(reinterpret_cast(ANGLE_COMMIT_HASH), ANGLE_COMMIT_HASH_SIZE); + + for (unsigned int i = 0; i < MAX_VERTEX_ATTRIBS; ++i) + { + stream.writeInt(mLinkedAttribute[i].type); + stream.writeString(mLinkedAttribute[i].name); + stream.writeInt(mProgram->getShaderAttributes()[i].type); + stream.writeString(mProgram->getShaderAttributes()[i].name); + stream.writeInt(mProgram->getSemanticIndexes()[i]); + } + + gl::Error error = mProgram->save(&stream); + if (error.isError()) + { + return error; + } + + GLsizei streamLength = stream.length(); + const void *streamData = stream.data(); + + if (streamLength > bufSize) + { + if (length) + { + *length = 0; + } + + // TODO: This should be moved to the validation layer but computing the size of the binary before saving + // it causes the save to happen twice. It may be possible to write the binary to a separate buffer, validate + // sizes and then copy it. + return Error(GL_INVALID_OPERATION); + } + + if (binary) + { + char *ptr = reinterpret_cast(binary); + + memcpy(ptr, streamData, streamLength); + ptr += streamLength; + + ASSERT(ptr - streamLength == binary); + } + + if (length) + { + *length = streamLength; + } + + return Error(GL_NO_ERROR); +} + +GLint Program::getBinaryLength() const +{ + GLint length; + Error error = saveBinary(NULL, NULL, std::numeric_limits::max(), &length); + if (error.isError()) + { + return 0; + } + + return length; +} + +void Program::release() +{ + mRefCount--; + + if (mRefCount == 0 && mDeleteStatus) + { + mResourceManager->deleteProgram(mHandle); + } +} + +void Program::addRef() +{ + mRefCount++; +} + +unsigned int Program::getRefCount() const +{ + return mRefCount; +} + +int Program::getInfoLogLength() const +{ + return mInfoLog.getLength(); +} + +void Program::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog) +{ + return mInfoLog.getLog(bufSize, length, infoLog); +} + +void Program::getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders) +{ + int total = 0; + + if (mVertexShader) + { + if (total < maxCount) + { + shaders[total] = mVertexShader->getHandle(); + } + + total++; + } + + if (mFragmentShader) + { + if (total < maxCount) + { + shaders[total] = mFragmentShader->getHandle(); + } + + total++; + } + + if (count) + { + *count = total; + } +} + +GLuint Program::getAttributeLocation(const std::string &name) +{ + for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++) + { + if (mLinkedAttribute[index].name == name) + { + return index; + } + } + + return static_cast(-1); +} + +int Program::getSemanticIndex(int attributeIndex) +{ + ASSERT(attributeIndex >= 0 && attributeIndex < MAX_VERTEX_ATTRIBS); + + return mProgram->getSemanticIndexes()[attributeIndex]; +} + +void Program::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) +{ + if (mLinked) + { + // Skip over inactive attributes + unsigned int activeAttribute = 0; + unsigned int attribute; + for (attribute = 0; attribute < MAX_VERTEX_ATTRIBS; attribute++) + { + if (mLinkedAttribute[attribute].name.empty()) + { + continue; + } + + if (activeAttribute == index) + { + break; + } + + activeAttribute++; + } + + if (bufsize > 0) + { + const char *string = mLinkedAttribute[attribute].name.c_str(); + + strncpy(name, string, bufsize); + name[bufsize - 1] = '\0'; + + if (length) + { + *length = strlen(name); + } + } + + *size = 1; // Always a single 'type' instance + + *type = mLinkedAttribute[attribute].type; + } + else + { + if (bufsize > 0) + { + name[0] = '\0'; + } + + if (length) + { + *length = 0; + } + + *type = GL_NONE; + *size = 1; + } +} + +GLint Program::getActiveAttributeCount() +{ + int count = 0; + + if (mLinked) + { + for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++) + { + if (!mLinkedAttribute[attributeIndex].name.empty()) + { + count++; + } + } + } + + return count; +} + +GLint Program::getActiveAttributeMaxLength() +{ + int maxLength = 0; + + if (mLinked) + { + for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++) + { + if (!mLinkedAttribute[attributeIndex].name.empty()) + { + maxLength = std::max((int)(mLinkedAttribute[attributeIndex].name.length() + 1), maxLength); + } + } + } + + return maxLength; +} + +// Returns one more than the highest sampler index used. +GLint Program::getUsedSamplerRange(SamplerType type) +{ + return mProgram->getUsedSamplerRange(type); +} + +bool Program::usesPointSize() const +{ + return mProgram->usesPointSize(); +} + +GLint Program::getSamplerMapping(SamplerType type, unsigned int samplerIndex, const Caps &caps) +{ + return mProgram->getSamplerMapping(type, samplerIndex, caps); +} + +GLenum Program::getSamplerTextureType(SamplerType type, unsigned int samplerIndex) +{ + return mProgram->getSamplerTextureType(type, samplerIndex); +} + +GLint Program::getFragDataLocation(const std::string &name) const +{ + std::string baseName(name); + unsigned int arrayIndex = ParseAndStripArrayIndex(&baseName); + for (auto locationIt = mOutputVariables.begin(); locationIt != mOutputVariables.end(); locationIt++) + { + const VariableLocation &outputVariable = locationIt->second; + if (outputVariable.name == baseName && (arrayIndex == GL_INVALID_INDEX || arrayIndex == outputVariable.element)) + { + return static_cast(locationIt->first); + } + } + return -1; +} + +void Program::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) +{ + if (mLinked) + { + ASSERT(index < mProgram->getUniforms().size()); // index must be smaller than getActiveUniformCount() + LinkedUniform *uniform = mProgram->getUniforms()[index]; + + if (bufsize > 0) + { + std::string string = uniform->name; + if (uniform->isArray()) + { + string += "[0]"; + } + + strncpy(name, string.c_str(), bufsize); + name[bufsize - 1] = '\0'; + + if (length) + { + *length = strlen(name); + } + } + + *size = uniform->elementCount(); + *type = uniform->type; + } + else + { + if (bufsize > 0) + { + name[0] = '\0'; + } + + if (length) + { + *length = 0; + } + + *size = 0; + *type = GL_NONE; + } +} + +GLint Program::getActiveUniformCount() +{ + if (mLinked) + { + return mProgram->getUniforms().size(); + } + else + { + return 0; + } +} + +GLint Program::getActiveUniformMaxLength() +{ + int maxLength = 0; + + if (mLinked) + { + unsigned int numUniforms = mProgram->getUniforms().size(); + for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++) + { + if (!mProgram->getUniforms()[uniformIndex]->name.empty()) + { + int length = (int)(mProgram->getUniforms()[uniformIndex]->name.length() + 1); + if (mProgram->getUniforms()[uniformIndex]->isArray()) + { + length += 3; // Counting in "[0]". + } + maxLength = std::max(length, maxLength); + } + } + } + + return maxLength; +} + +GLint Program::getActiveUniformi(GLuint index, GLenum pname) const +{ + const gl::LinkedUniform& uniform = *mProgram->getUniforms()[index]; + switch (pname) + { + case GL_UNIFORM_TYPE: return static_cast(uniform.type); + case GL_UNIFORM_SIZE: return static_cast(uniform.elementCount()); + case GL_UNIFORM_NAME_LENGTH: return static_cast(uniform.name.size() + 1 + (uniform.isArray() ? 3 : 0)); + case GL_UNIFORM_BLOCK_INDEX: return uniform.blockIndex; + case GL_UNIFORM_OFFSET: return uniform.blockInfo.offset; + case GL_UNIFORM_ARRAY_STRIDE: return uniform.blockInfo.arrayStride; + case GL_UNIFORM_MATRIX_STRIDE: return uniform.blockInfo.matrixStride; + case GL_UNIFORM_IS_ROW_MAJOR: return static_cast(uniform.blockInfo.isRowMajorMatrix); + default: + UNREACHABLE(); + break; + } + return 0; +} + +bool Program::isValidUniformLocation(GLint location) const +{ + ASSERT(rx::IsIntegerCastSafe(mProgram->getUniformIndices().size())); + return (location >= 0 && location < static_cast(mProgram->getUniformIndices().size())); +} + +LinkedUniform *Program::getUniformByLocation(GLint location) const +{ + return mProgram->getUniformByLocation(location); +} + +LinkedUniform *Program::getUniformByName(const std::string &name) const +{ + return mProgram->getUniformByName(name); +} + +GLint Program::getUniformLocation(const std::string &name) +{ + return mProgram->getUniformLocation(name); +} + +GLuint Program::getUniformIndex(const std::string &name) +{ + return mProgram->getUniformIndex(name); +} + +void Program::setUniform1fv(GLint location, GLsizei count, const GLfloat *v) +{ + mProgram->setUniform1fv(location, count, v); +} + +void Program::setUniform2fv(GLint location, GLsizei count, const GLfloat *v) +{ + mProgram->setUniform2fv(location, count, v); +} + +void Program::setUniform3fv(GLint location, GLsizei count, const GLfloat *v) +{ + mProgram->setUniform3fv(location, count, v); +} + +void Program::setUniform4fv(GLint location, GLsizei count, const GLfloat *v) +{ + mProgram->setUniform4fv(location, count, v); +} + +void Program::setUniform1iv(GLint location, GLsizei count, const GLint *v) +{ + mProgram->setUniform1iv(location, count, v); +} + +void Program::setUniform2iv(GLint location, GLsizei count, const GLint *v) +{ + mProgram->setUniform2iv(location, count, v); +} + +void Program::setUniform3iv(GLint location, GLsizei count, const GLint *v) +{ + mProgram->setUniform3iv(location, count, v); +} + +void Program::setUniform4iv(GLint location, GLsizei count, const GLint *v) +{ + mProgram->setUniform4iv(location, count, v); +} + +void Program::setUniform1uiv(GLint location, GLsizei count, const GLuint *v) +{ + mProgram->setUniform1uiv(location, count, v); +} + +void Program::setUniform2uiv(GLint location, GLsizei count, const GLuint *v) +{ + mProgram->setUniform2uiv(location, count, v); +} + +void Program::setUniform3uiv(GLint location, GLsizei count, const GLuint *v) +{ + mProgram->setUniform3uiv(location, count, v); +} + +void Program::setUniform4uiv(GLint location, GLsizei count, const GLuint *v) +{ + mProgram->setUniform4uiv(location, count, v); +} + +void Program::setUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v) +{ + mProgram->setUniformMatrix2fv(location, count, transpose, v); +} + +void Program::setUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v) +{ + mProgram->setUniformMatrix3fv(location, count, transpose, v); +} + +void Program::setUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v) +{ + mProgram->setUniformMatrix4fv(location, count, transpose, v); +} + +void Program::setUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v) +{ + mProgram->setUniformMatrix2x3fv(location, count, transpose, v); +} + +void Program::setUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v) +{ + mProgram->setUniformMatrix2x4fv(location, count, transpose, v); +} + +void Program::setUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v) +{ + mProgram->setUniformMatrix3x2fv(location, count, transpose, v); +} + +void Program::setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v) +{ + mProgram->setUniformMatrix3x4fv(location, count, transpose, v); +} + +void Program::setUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v) +{ + mProgram->setUniformMatrix4x2fv(location, count, transpose, v); +} + +void Program::setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v) +{ + mProgram->setUniformMatrix4x3fv(location, count, transpose, v); +} + +void Program::getUniformfv(GLint location, GLfloat *v) +{ + mProgram->getUniformfv(location, v); +} + +void Program::getUniformiv(GLint location, GLint *v) +{ + mProgram->getUniformiv(location, v); +} + +void Program::getUniformuiv(GLint location, GLuint *v) +{ + mProgram->getUniformuiv(location, v); +} + +// Applies all the uniforms set for this program object to the renderer +Error Program::applyUniforms() +{ + return mProgram->applyUniforms(); +} + +Error Program::applyUniformBuffers(const gl::Data &data) +{ + return mProgram->applyUniformBuffers(data, mUniformBlockBindings); +} + +void Program::flagForDeletion() +{ + mDeleteStatus = true; +} + +bool Program::isFlaggedForDeletion() const +{ + return mDeleteStatus; +} + +void Program::validate(const Caps &caps) +{ + mInfoLog.reset(); + mValidated = false; + + if (mLinked) + { + applyUniforms(); + mValidated = mProgram->validateSamplers(&mInfoLog, caps); + } + else + { + mInfoLog.append("Program has not been successfully linked."); + } +} + +bool Program::validateSamplers(InfoLog *infoLog, const Caps &caps) +{ + return mProgram->validateSamplers(infoLog, caps); +} + +bool Program::isValidated() const +{ + return mValidated; +} + +void Program::updateSamplerMapping() +{ + return mProgram->updateSamplerMapping(); +} + +GLuint Program::getActiveUniformBlockCount() +{ + return mProgram->getUniformBlocks().size(); +} + +void Program::getActiveUniformBlockName(GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName) const +{ + ASSERT(uniformBlockIndex < mProgram->getUniformBlocks().size()); // index must be smaller than getActiveUniformBlockCount() + + const UniformBlock &uniformBlock = *mProgram->getUniformBlocks()[uniformBlockIndex]; + + if (bufSize > 0) + { + std::string string = uniformBlock.name; + + if (uniformBlock.isArrayElement()) + { + string += ArrayString(uniformBlock.elementIndex); + } + + strncpy(uniformBlockName, string.c_str(), bufSize); + uniformBlockName[bufSize - 1] = '\0'; + + if (length) + { + *length = strlen(uniformBlockName); + } + } +} + +void Program::getActiveUniformBlockiv(GLuint uniformBlockIndex, GLenum pname, GLint *params) const +{ + ASSERT(uniformBlockIndex < mProgram->getUniformBlocks().size()); // index must be smaller than getActiveUniformBlockCount() + + const UniformBlock &uniformBlock = *mProgram->getUniformBlocks()[uniformBlockIndex]; + + switch (pname) + { + case GL_UNIFORM_BLOCK_DATA_SIZE: + *params = static_cast(uniformBlock.dataSize); + break; + case GL_UNIFORM_BLOCK_NAME_LENGTH: + *params = static_cast(uniformBlock.name.size() + 1 + (uniformBlock.isArrayElement() ? 3 : 0)); + break; + case GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS: + *params = static_cast(uniformBlock.memberUniformIndexes.size()); + break; + case GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES: + { + for (unsigned int blockMemberIndex = 0; blockMemberIndex < uniformBlock.memberUniformIndexes.size(); blockMemberIndex++) + { + params[blockMemberIndex] = static_cast(uniformBlock.memberUniformIndexes[blockMemberIndex]); + } + } + break; + case GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER: + *params = static_cast(uniformBlock.isReferencedByVertexShader()); + break; + case GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER: + *params = static_cast(uniformBlock.isReferencedByFragmentShader()); + break; + default: UNREACHABLE(); + } +} + +GLint Program::getActiveUniformBlockMaxLength() +{ + int maxLength = 0; + + if (mLinked) + { + unsigned int numUniformBlocks = mProgram->getUniformBlocks().size(); + for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < numUniformBlocks; uniformBlockIndex++) + { + const UniformBlock &uniformBlock = *mProgram->getUniformBlocks()[uniformBlockIndex]; + if (!uniformBlock.name.empty()) + { + const int length = uniformBlock.name.length() + 1; + + // Counting in "[0]". + const int arrayLength = (uniformBlock.isArrayElement() ? 3 : 0); + + maxLength = std::max(length + arrayLength, maxLength); + } + } + } + + return maxLength; +} + +GLuint Program::getUniformBlockIndex(const std::string &name) +{ + return mProgram->getUniformBlockIndex(name); +} + +const UniformBlock *Program::getUniformBlockByIndex(GLuint index) const +{ + return mProgram->getUniformBlockByIndex(index); +} + +void Program::bindUniformBlock(GLuint uniformBlockIndex, GLuint uniformBlockBinding) +{ + mUniformBlockBindings[uniformBlockIndex] = uniformBlockBinding; +} + +GLuint Program::getUniformBlockBinding(GLuint uniformBlockIndex) const +{ + return mUniformBlockBindings[uniformBlockIndex]; +} + +void Program::resetUniformBlockBindings() +{ + for (unsigned int blockId = 0; blockId < IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS; blockId++) + { + mUniformBlockBindings[blockId] = 0; + } +} + +void Program::setTransformFeedbackVaryings(GLsizei count, const GLchar *const *varyings, GLenum bufferMode) +{ + mTransformFeedbackVaryings.resize(count); + for (GLsizei i = 0; i < count; i++) + { + mTransformFeedbackVaryings[i] = varyings[i]; + } + + mTransformFeedbackBufferMode = bufferMode; +} + +void Program::getTransformFeedbackVarying(GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name) const +{ + if (mLinked) + { + ASSERT(index < mProgram->getTransformFeedbackLinkedVaryings().size()); + const LinkedVarying &varying = mProgram->getTransformFeedbackLinkedVaryings()[index]; + GLsizei lastNameIdx = std::min(bufSize - 1, static_cast(varying.name.length())); + if (length) + { + *length = lastNameIdx; + } + if (size) + { + *size = varying.size; + } + if (type) + { + *type = varying.type; + } + if (name) + { + memcpy(name, varying.name.c_str(), lastNameIdx); + name[lastNameIdx] = '\0'; + } + } +} + +GLsizei Program::getTransformFeedbackVaryingCount() const +{ + if (mLinked) + { + return static_cast(mProgram->getTransformFeedbackLinkedVaryings().size()); + } + else + { + return 0; + } +} + +GLsizei Program::getTransformFeedbackVaryingMaxLength() const +{ + if (mLinked) + { + GLsizei maxSize = 0; + for (size_t i = 0; i < mProgram->getTransformFeedbackLinkedVaryings().size(); i++) + { + const LinkedVarying &varying = mProgram->getTransformFeedbackLinkedVaryings()[i]; + maxSize = std::max(maxSize, static_cast(varying.name.length() + 1)); + } + + return maxSize; + } + else + { + return 0; + } +} + +GLenum Program::getTransformFeedbackBufferMode() const +{ + return mTransformFeedbackBufferMode; +} + +bool Program::linkVaryings(InfoLog &infoLog, Shader *fragmentShader, Shader *vertexShader) +{ + std::vector &fragmentVaryings = fragmentShader->getVaryings(); + std::vector &vertexVaryings = vertexShader->getVaryings(); + + for (size_t fragVaryingIndex = 0; fragVaryingIndex < fragmentVaryings.size(); fragVaryingIndex++) + { + PackedVarying *input = &fragmentVaryings[fragVaryingIndex]; + bool matched = false; + + // Built-in varyings obey special rules + if (input->isBuiltIn()) + { + continue; + } + + for (size_t vertVaryingIndex = 0; vertVaryingIndex < vertexVaryings.size(); vertVaryingIndex++) + { + PackedVarying *output = &vertexVaryings[vertVaryingIndex]; + if (output->name == input->name) + { + if (!linkValidateVaryings(infoLog, output->name, *input, *output)) + { + return false; + } + + output->registerIndex = input->registerIndex; + output->columnIndex = input->columnIndex; + + matched = true; + break; + } + } + + // We permit unmatched, unreferenced varyings + if (!matched && input->staticUse) + { + infoLog.append("Fragment varying %s does not match any vertex varying", input->name.c_str()); + return false; + } + } + + return true; +} + +bool Program::linkValidateInterfaceBlockFields(InfoLog &infoLog, const std::string &uniformName, const sh::InterfaceBlockField &vertexUniform, const sh::InterfaceBlockField &fragmentUniform) +{ + if (!linkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform, true)) + { + return false; + } + + if (vertexUniform.isRowMajorLayout != fragmentUniform.isRowMajorLayout) + { + infoLog.append("Matrix packings for %s differ between vertex and fragment shaders", uniformName.c_str()); + return false; + } + + return true; +} + +// Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices +bool Program::linkAttributes(InfoLog &infoLog, const AttributeBindings &attributeBindings, const Shader *vertexShader) +{ + unsigned int usedLocations = 0; + const std::vector &shaderAttributes = vertexShader->getActiveAttributes(); + + // Link attributes that have a binding location + for (unsigned int attributeIndex = 0; attributeIndex < shaderAttributes.size(); attributeIndex++) + { + const sh::Attribute &attribute = shaderAttributes[attributeIndex]; + + ASSERT(attribute.staticUse); + + const int location = attribute.location == -1 ? attributeBindings.getAttributeBinding(attribute.name) : attribute.location; + + mProgram->getShaderAttributes()[attributeIndex] = attribute; + + if (location != -1) // Set by glBindAttribLocation or by location layout qualifier + { + const int rows = VariableRegisterCount(attribute.type); + + if (rows + location > MAX_VERTEX_ATTRIBS) + { + infoLog.append("Active attribute (%s) at location %d is too big to fit", attribute.name.c_str(), location); + + return false; + } + + for (int row = 0; row < rows; row++) + { + const int rowLocation = location + row; + sh::ShaderVariable &linkedAttribute = mLinkedAttribute[rowLocation]; + + // In GLSL 3.00, attribute aliasing produces a link error + // In GLSL 1.00, attribute aliasing is allowed + if (mProgram->getShaderVersion() >= 300) + { + if (!linkedAttribute.name.empty()) + { + infoLog.append("Attribute '%s' aliases attribute '%s' at location %d", attribute.name.c_str(), linkedAttribute.name.c_str(), rowLocation); + return false; + } + } + + linkedAttribute = attribute; + usedLocations |= 1 << rowLocation; + } + } + } + + // Link attributes that don't have a binding location + for (unsigned int attributeIndex = 0; attributeIndex < shaderAttributes.size(); attributeIndex++) + { + const sh::Attribute &attribute = shaderAttributes[attributeIndex]; + + ASSERT(attribute.staticUse); + + const int location = attribute.location == -1 ? attributeBindings.getAttributeBinding(attribute.name) : attribute.location; + + if (location == -1) // Not set by glBindAttribLocation or by location layout qualifier + { + int rows = VariableRegisterCount(attribute.type); + int availableIndex = AllocateFirstFreeBits(&usedLocations, rows, MAX_VERTEX_ATTRIBS); + + if (availableIndex == -1 || availableIndex + rows > MAX_VERTEX_ATTRIBS) + { + infoLog.append("Too many active attributes (%s)", attribute.name.c_str()); + + return false; // Fail to link + } + + mLinkedAttribute[availableIndex] = attribute; + } + } + + for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; ) + { + int index = vertexShader->getSemanticIndex(mLinkedAttribute[attributeIndex].name); + int rows = VariableRegisterCount(mLinkedAttribute[attributeIndex].type); + + for (int r = 0; r < rows; r++) + { + mProgram->getSemanticIndexes()[attributeIndex++] = index++; + } + } + + return true; +} + +bool Program::linkUniformBlocks(InfoLog &infoLog, const Shader &vertexShader, const Shader &fragmentShader, const Caps &caps) +{ + const std::vector &vertexInterfaceBlocks = vertexShader.getInterfaceBlocks(); + const std::vector &fragmentInterfaceBlocks = fragmentShader.getInterfaceBlocks(); + // Check that interface blocks defined in the vertex and fragment shaders are identical + typedef std::map UniformBlockMap; + UniformBlockMap linkedUniformBlocks; + for (unsigned int blockIndex = 0; blockIndex < vertexInterfaceBlocks.size(); blockIndex++) + { + const sh::InterfaceBlock &vertexInterfaceBlock = vertexInterfaceBlocks[blockIndex]; + linkedUniformBlocks[vertexInterfaceBlock.name] = &vertexInterfaceBlock; + } + for (unsigned int blockIndex = 0; blockIndex < fragmentInterfaceBlocks.size(); blockIndex++) + { + const sh::InterfaceBlock &fragmentInterfaceBlock = fragmentInterfaceBlocks[blockIndex]; + UniformBlockMap::const_iterator entry = linkedUniformBlocks.find(fragmentInterfaceBlock.name); + if (entry != linkedUniformBlocks.end()) + { + const sh::InterfaceBlock &vertexInterfaceBlock = *entry->second; + if (!areMatchingInterfaceBlocks(infoLog, vertexInterfaceBlock, fragmentInterfaceBlock)) + { + return false; + } + } + } + for (unsigned int blockIndex = 0; blockIndex < vertexInterfaceBlocks.size(); blockIndex++) + { + const sh::InterfaceBlock &interfaceBlock = vertexInterfaceBlocks[blockIndex]; + // Note: shared and std140 layouts are always considered active + if (interfaceBlock.staticUse || interfaceBlock.layout != sh::BLOCKLAYOUT_PACKED) + { + if (!mProgram->defineUniformBlock(infoLog, vertexShader, interfaceBlock, caps)) + { + return false; + } + } + } + for (unsigned int blockIndex = 0; blockIndex < fragmentInterfaceBlocks.size(); blockIndex++) + { + const sh::InterfaceBlock &interfaceBlock = fragmentInterfaceBlocks[blockIndex]; + // Note: shared and std140 layouts are always considered active + if (interfaceBlock.staticUse || interfaceBlock.layout != sh::BLOCKLAYOUT_PACKED) + { + if (!mProgram->defineUniformBlock(infoLog, fragmentShader, interfaceBlock, caps)) + { + return false; + } + } + } + return true; +} + +bool Program::areMatchingInterfaceBlocks(gl::InfoLog &infoLog, const sh::InterfaceBlock &vertexInterfaceBlock, + const sh::InterfaceBlock &fragmentInterfaceBlock) +{ + const char* blockName = vertexInterfaceBlock.name.c_str(); + // validate blocks for the same member types + if (vertexInterfaceBlock.fields.size() != fragmentInterfaceBlock.fields.size()) + { + infoLog.append("Types for interface block '%s' differ between vertex and fragment shaders", blockName); + return false; + } + if (vertexInterfaceBlock.arraySize != fragmentInterfaceBlock.arraySize) + { + infoLog.append("Array sizes differ for interface block '%s' between vertex and fragment shaders", blockName); + return false; + } + if (vertexInterfaceBlock.layout != fragmentInterfaceBlock.layout || vertexInterfaceBlock.isRowMajorLayout != fragmentInterfaceBlock.isRowMajorLayout) + { + infoLog.append("Layout qualifiers differ for interface block '%s' between vertex and fragment shaders", blockName); + return false; + } + const unsigned int numBlockMembers = vertexInterfaceBlock.fields.size(); + for (unsigned int blockMemberIndex = 0; blockMemberIndex < numBlockMembers; blockMemberIndex++) + { + const sh::InterfaceBlockField &vertexMember = vertexInterfaceBlock.fields[blockMemberIndex]; + const sh::InterfaceBlockField &fragmentMember = fragmentInterfaceBlock.fields[blockMemberIndex]; + if (vertexMember.name != fragmentMember.name) + { + infoLog.append("Name mismatch for field %d of interface block '%s': (in vertex: '%s', in fragment: '%s')", + blockMemberIndex, blockName, vertexMember.name.c_str(), fragmentMember.name.c_str()); + return false; + } + std::string memberName = "interface block '" + vertexInterfaceBlock.name + "' member '" + vertexMember.name + "'"; + if (!linkValidateInterfaceBlockFields(infoLog, memberName, vertexMember, fragmentMember)) + { + return false; + } + } + return true; +} + +bool Program::linkValidateVariablesBase(InfoLog &infoLog, const std::string &variableName, const sh::ShaderVariable &vertexVariable, + const sh::ShaderVariable &fragmentVariable, bool validatePrecision) +{ + if (vertexVariable.type != fragmentVariable.type) + { + infoLog.append("Types for %s differ between vertex and fragment shaders", variableName.c_str()); + return false; + } + if (vertexVariable.arraySize != fragmentVariable.arraySize) + { + infoLog.append("Array sizes for %s differ between vertex and fragment shaders", variableName.c_str()); + return false; + } + if (validatePrecision && vertexVariable.precision != fragmentVariable.precision) + { + infoLog.append("Precisions for %s differ between vertex and fragment shaders", variableName.c_str()); + return false; + } + + if (vertexVariable.fields.size() != fragmentVariable.fields.size()) + { + infoLog.append("Structure lengths for %s differ between vertex and fragment shaders", variableName.c_str()); + return false; + } + const unsigned int numMembers = vertexVariable.fields.size(); + for (unsigned int memberIndex = 0; memberIndex < numMembers; memberIndex++) + { + const sh::ShaderVariable &vertexMember = vertexVariable.fields[memberIndex]; + const sh::ShaderVariable &fragmentMember = fragmentVariable.fields[memberIndex]; + + if (vertexMember.name != fragmentMember.name) + { + infoLog.append("Name mismatch for field '%d' of %s: (in vertex: '%s', in fragment: '%s')", + memberIndex, variableName.c_str(), + vertexMember.name.c_str(), fragmentMember.name.c_str()); + return false; + } + + const std::string memberName = variableName.substr(0, variableName.length() - 1) + "." + + vertexMember.name + "'"; + + if (!linkValidateVariablesBase(infoLog, vertexMember.name, vertexMember, fragmentMember, validatePrecision)) + { + return false; + } + } + + return true; +} + +bool Program::linkValidateUniforms(InfoLog &infoLog, const std::string &uniformName, const sh::Uniform &vertexUniform, const sh::Uniform &fragmentUniform) +{ + if (!linkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform, true)) + { + return false; + } + + return true; +} + +bool Program::linkValidateVaryings(InfoLog &infoLog, const std::string &varyingName, const sh::Varying &vertexVarying, const sh::Varying &fragmentVarying) +{ + if (!linkValidateVariablesBase(infoLog, varyingName, vertexVarying, fragmentVarying, false)) + { + return false; + } + + if (!sh::InterpolationTypesMatch(vertexVarying.interpolation, fragmentVarying.interpolation)) + { + infoLog.append("Interpolation types for %s differ between vertex and fragment shaders", varyingName.c_str()); + return false; + } + + return true; +} + +bool Program::gatherTransformFeedbackLinkedVaryings(InfoLog &infoLog, const std::vector &linkedVaryings, + const std::vector &transformFeedbackVaryingNames, + GLenum transformFeedbackBufferMode, + std::vector *outTransformFeedbackLinkedVaryings, + const Caps &caps) const +{ + size_t totalComponents = 0; + + // Gather the linked varyings that are used for transform feedback, they should all exist. + outTransformFeedbackLinkedVaryings->clear(); + for (size_t i = 0; i < transformFeedbackVaryingNames.size(); i++) + { + bool found = false; + for (size_t j = 0; j < linkedVaryings.size(); j++) + { + if (transformFeedbackVaryingNames[i] == linkedVaryings[j].name) + { + for (size_t k = 0; k < outTransformFeedbackLinkedVaryings->size(); k++) + { + if (outTransformFeedbackLinkedVaryings->at(k).name == linkedVaryings[j].name) + { + infoLog.append("Two transform feedback varyings specify the same output variable (%s).", linkedVaryings[j].name.c_str()); + return false; + } + } + + size_t componentCount = linkedVaryings[j].semanticIndexCount * 4; + if (transformFeedbackBufferMode == GL_SEPARATE_ATTRIBS && + componentCount > caps.maxTransformFeedbackSeparateComponents) + { + infoLog.append("Transform feedback varying's %s components (%u) exceed the maximum separate components (%u).", + linkedVaryings[j].name.c_str(), componentCount, caps.maxTransformFeedbackSeparateComponents); + return false; + } + + totalComponents += componentCount; + + outTransformFeedbackLinkedVaryings->push_back(linkedVaryings[j]); + found = true; + break; + } + } + + // All transform feedback varyings are expected to exist since packVaryings checks for them. + ASSERT(found); + } + + if (transformFeedbackBufferMode == GL_INTERLEAVED_ATTRIBS && totalComponents > caps.maxTransformFeedbackInterleavedComponents) + { + infoLog.append("Transform feedback varying total components (%u) exceed the maximum interleaved components (%u).", + totalComponents, caps.maxTransformFeedbackInterleavedComponents); + return false; + } + + return true; +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/Program.h b/src/3rdparty/angle/src/libANGLE/Program.h new file mode 100644 index 0000000000..38fc83d29d --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/Program.h @@ -0,0 +1,276 @@ +// +// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Program.h: Defines the gl::Program class. Implements GL program objects +// and related functionality. [OpenGL ES 2.0.24] section 2.10.3 page 28. + +#ifndef LIBANGLE_PROGRAM_H_ +#define LIBANGLE_PROGRAM_H_ + +#include "libANGLE/angletypes.h" +#include "libANGLE/Constants.h" +#include "libANGLE/Error.h" +#include "libANGLE/RefCountObject.h" + +#include "common/angleutils.h" + +#include +#include + +#include +#include +#include + +namespace rx +{ +class Renderer; +class Renderer; +struct TranslatedAttribute; +class ProgramImpl; +} + +namespace gl +{ +struct Caps; +struct Data; +class ResourceManager; +class Shader; +class InfoLog; +class AttributeBindings; +class Buffer; +class Framebuffer; +struct UniformBlock; +struct LinkedUniform; + +extern const char * const g_fakepath; + +class AttributeBindings +{ + public: + AttributeBindings(); + ~AttributeBindings(); + + void bindAttributeLocation(GLuint index, const char *name); + int getAttributeBinding(const std::string &name) const; + + private: + std::set mAttributeBinding[MAX_VERTEX_ATTRIBS]; +}; + +class InfoLog : angle::NonCopyable +{ + public: + InfoLog(); + ~InfoLog(); + + int getLength() const; + void getLog(GLsizei bufSize, GLsizei *length, char *infoLog); + + void appendSanitized(const char *message); + void append(const char *info, ...); + void reset(); + private: + char *mInfoLog; +}; + +// Struct used for correlating uniforms/elements of uniform arrays to handles +struct VariableLocation +{ + VariableLocation(); + VariableLocation(const std::string &name, unsigned int element, unsigned int index); + + std::string name; + unsigned int element; + unsigned int index; +}; + +struct LinkedVarying +{ + LinkedVarying(); + LinkedVarying(const std::string &name, GLenum type, GLsizei size, const std::string &semanticName, + unsigned int semanticIndex, unsigned int semanticIndexCount); + + // Original GL name + std::string name; + + GLenum type; + GLsizei size; + + // DirectX semantic information + std::string semanticName; + unsigned int semanticIndex; + unsigned int semanticIndexCount; +}; + +class Program : angle::NonCopyable +{ + public: + Program(rx::ProgramImpl *impl, ResourceManager *manager, GLuint handle); + ~Program(); + + GLuint id() const { return mHandle; } + + rx::ProgramImpl *getImplementation() { return mProgram; } + const rx::ProgramImpl *getImplementation() const { return mProgram; } + + bool attachShader(Shader *shader); + bool detachShader(Shader *shader); + int getAttachedShadersCount() const; + + void bindAttributeLocation(GLuint index, const char *name); + + Error link(const Data &data); + bool isLinked(); + + Error loadBinary(GLenum binaryFormat, const void *binary, GLsizei length); + Error saveBinary(GLenum *binaryFormat, void *binary, GLsizei bufSize, GLsizei *length) const; + GLint getBinaryLength() const; + + int getInfoLogLength() const; + void getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog); + void getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders); + + GLuint getAttributeLocation(const std::string &name); + int getSemanticIndex(int attributeIndex); + + void getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); + GLint getActiveAttributeCount(); + GLint getActiveAttributeMaxLength(); + + GLint getSamplerMapping(SamplerType type, unsigned int samplerIndex, const Caps &caps); + GLenum getSamplerTextureType(SamplerType type, unsigned int samplerIndex); + GLint getUsedSamplerRange(SamplerType type); + bool usesPointSize() const; + + GLint getFragDataLocation(const std::string &name) const; + + void getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); + GLint getActiveUniformCount(); + GLint getActiveUniformMaxLength(); + GLint getActiveUniformi(GLuint index, GLenum pname) const; + bool isValidUniformLocation(GLint location) const; + LinkedUniform *getUniformByLocation(GLint location) const; + LinkedUniform *getUniformByName(const std::string &name) const; + + GLint getUniformLocation(const std::string &name); + GLuint getUniformIndex(const std::string &name); + void setUniform1fv(GLint location, GLsizei count, const GLfloat *v); + void setUniform2fv(GLint location, GLsizei count, const GLfloat *v); + void setUniform3fv(GLint location, GLsizei count, const GLfloat *v); + void setUniform4fv(GLint location, GLsizei count, const GLfloat *v); + void setUniform1iv(GLint location, GLsizei count, const GLint *v); + void setUniform2iv(GLint location, GLsizei count, const GLint *v); + void setUniform3iv(GLint location, GLsizei count, const GLint *v); + void setUniform4iv(GLint location, GLsizei count, const GLint *v); + void setUniform1uiv(GLint location, GLsizei count, const GLuint *v); + void setUniform2uiv(GLint location, GLsizei count, const GLuint *v); + void setUniform3uiv(GLint location, GLsizei count, const GLuint *v); + void setUniform4uiv(GLint location, GLsizei count, const GLuint *v); + void setUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); + void setUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); + void setUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); + void setUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); + void setUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); + void setUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); + void setUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); + void setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); + void setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); + + void getUniformfv(GLint location, GLfloat *params); + void getUniformiv(GLint location, GLint *params); + void getUniformuiv(GLint location, GLuint *params); + + Error applyUniforms(); + Error applyUniformBuffers(const gl::Data &data); + + void getActiveUniformBlockName(GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName) const; + void getActiveUniformBlockiv(GLuint uniformBlockIndex, GLenum pname, GLint *params) const; + GLuint getActiveUniformBlockCount(); + GLint getActiveUniformBlockMaxLength(); + + GLuint getUniformBlockIndex(const std::string &name); + + void bindUniformBlock(GLuint uniformBlockIndex, GLuint uniformBlockBinding); + GLuint getUniformBlockBinding(GLuint uniformBlockIndex) const; + + const UniformBlock *getUniformBlockByIndex(GLuint index) const; + + void setTransformFeedbackVaryings(GLsizei count, const GLchar *const *varyings, GLenum bufferMode); + void getTransformFeedbackVarying(GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name) const; + GLsizei getTransformFeedbackVaryingCount() const; + GLsizei getTransformFeedbackVaryingMaxLength() const; + GLenum getTransformFeedbackBufferMode() const; + + static bool linkVaryings(InfoLog &infoLog, Shader *fragmentShader, Shader *vertexShader); + static bool linkValidateUniforms(InfoLog &infoLog, const std::string &uniformName, const sh::Uniform &vertexUniform, const sh::Uniform &fragmentUniform); + static bool linkValidateInterfaceBlockFields(InfoLog &infoLog, const std::string &uniformName, const sh::InterfaceBlockField &vertexUniform, const sh::InterfaceBlockField &fragmentUniform); + + void addRef(); + void release(); + unsigned int getRefCount() const; + void flagForDeletion(); + bool isFlaggedForDeletion() const; + + void validate(const Caps &caps); + bool validateSamplers(InfoLog *infoLog, const Caps &caps); + bool isValidated() const; + void updateSamplerMapping(); + + private: + void unlink(bool destroy = false); + void resetUniformBlockBindings(); + + bool linkAttributes(InfoLog &infoLog, const AttributeBindings &attributeBindings, const Shader *vertexShader); + bool linkUniformBlocks(InfoLog &infoLog, const Shader &vertexShader, const Shader &fragmentShader, const Caps &caps); + bool areMatchingInterfaceBlocks(gl::InfoLog &infoLog, const sh::InterfaceBlock &vertexInterfaceBlock, + const sh::InterfaceBlock &fragmentInterfaceBlock); + + static bool linkValidateVariablesBase(InfoLog &infoLog, + const std::string &variableName, + const sh::ShaderVariable &vertexVariable, + const sh::ShaderVariable &fragmentVariable, + bool validatePrecision); + + static bool linkValidateVaryings(InfoLog &infoLog, const std::string &varyingName, const sh::Varying &vertexVarying, const sh::Varying &fragmentVarying); + bool gatherTransformFeedbackLinkedVaryings(InfoLog &infoLog, const std::vector &linkedVaryings, + const std::vector &transformFeedbackVaryingNames, + GLenum transformFeedbackBufferMode, + std::vector *outTransformFeedbackLinkedVaryings, + const Caps &caps) const; + bool assignUniformBlockRegister(InfoLog &infoLog, UniformBlock *uniformBlock, GLenum shader, unsigned int registerIndex, const Caps &caps); + void defineOutputVariables(Shader *fragmentShader); + + rx::ProgramImpl *mProgram; + + sh::Attribute mLinkedAttribute[MAX_VERTEX_ATTRIBS]; + + std::map mOutputVariables; + + bool mValidated; + + Shader *mFragmentShader; + Shader *mVertexShader; + + AttributeBindings mAttributeBindings; + + GLuint mUniformBlockBindings[IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS]; + + std::vector mTransformFeedbackVaryings; + GLenum mTransformFeedbackBufferMode; + + bool mLinked; + bool mDeleteStatus; // Flag to indicate that the program can be deleted when no longer in use + + unsigned int mRefCount; + + ResourceManager *mResourceManager; + const GLuint mHandle; + + InfoLog mInfoLog; +}; +} + +#endif // LIBANGLE_PROGRAM_H_ diff --git a/src/3rdparty/angle/src/libANGLE/Query.cpp b/src/3rdparty/angle/src/libANGLE/Query.cpp new file mode 100644 index 0000000000..a402b732bf --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/Query.cpp @@ -0,0 +1,50 @@ +// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Query.cpp: Implements the gl::Query class + +#include "libANGLE/Query.h" +#include "libANGLE/renderer/QueryImpl.h" + +namespace gl +{ +Query::Query(rx::QueryImpl *impl, GLuint id) + : RefCountObject(id), + mQuery(impl) +{ +} + +Query::~Query() +{ + SafeDelete(mQuery); +} + +Error Query::begin() +{ + return mQuery->begin(); +} + +Error Query::end() +{ + return mQuery->end(); +} + +Error Query::getResult(GLuint *params) +{ + return mQuery->getResult(params); +} + +Error Query::isResultAvailable(GLuint *available) +{ + return mQuery->isResultAvailable(available); +} + +GLenum Query::getType() const +{ + return mQuery->getType(); +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/Query.h b/src/3rdparty/angle/src/libANGLE/Query.h new file mode 100644 index 0000000000..8585fde0e2 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/Query.h @@ -0,0 +1,47 @@ +// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Query.h: Defines the gl::Query class + +#ifndef LIBANGLE_QUERY_H_ +#define LIBANGLE_QUERY_H_ + +#include "libANGLE/Error.h" +#include "libANGLE/RefCountObject.h" + +#include "common/angleutils.h" + +#include "angle_gl.h" + +namespace rx +{ +class QueryImpl; +} + +namespace gl +{ + +class Query : public RefCountObject +{ + public: + Query(rx::QueryImpl *impl, GLuint id); + virtual ~Query(); + + Error begin(); + Error end(); + + Error getResult(GLuint *params); + Error isResultAvailable(GLuint *available); + + GLenum getType() const; + + private: + rx::QueryImpl *mQuery; +}; + +} + +#endif // LIBANGLE_QUERY_H_ diff --git a/src/3rdparty/angle/src/libANGLE/RefCountObject.cpp b/src/3rdparty/angle/src/libANGLE/RefCountObject.cpp new file mode 100644 index 0000000000..b1210200cf --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/RefCountObject.cpp @@ -0,0 +1,39 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// RefCountObject.cpp: Defines the gl::RefCountObject base class that provides +// lifecycle support for GL objects using the traditional BindObject scheme, but +// that need to be reference counted for correct cross-context deletion. +// (Concretely, textures, buffers and renderbuffers.) + +#include "RefCountObject.h" + +RefCountObject::RefCountObject(GLuint id) + : mId(id), + mRefCount(0) +{ +} + +RefCountObject::~RefCountObject() +{ + ASSERT(mRefCount == 0); +} + +void RefCountObject::addRef() const +{ + mRefCount++; +} + +void RefCountObject::release() const +{ + ASSERT(mRefCount > 0); + + if (--mRefCount == 0) + { + delete this; + } +} + diff --git a/src/3rdparty/angle/src/libANGLE/RefCountObject.h b/src/3rdparty/angle/src/libANGLE/RefCountObject.h new file mode 100644 index 0000000000..48c0338c3f --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/RefCountObject.h @@ -0,0 +1,110 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// RefCountObject.h: Defines the gl::RefCountObject base class that provides +// lifecycle support for GL objects using the traditional BindObject scheme, but +// that need to be reference counted for correct cross-context deletion. +// (Concretely, textures, buffers and renderbuffers.) + +#ifndef LIBANGLE_REFCOUNTOBJECT_H_ +#define LIBANGLE_REFCOUNTOBJECT_H_ + +#include "common/debug.h" + +#include "angle_gl.h" + +#include + +class RefCountObject : angle::NonCopyable +{ + public: + explicit RefCountObject(GLuint id); + virtual ~RefCountObject(); + + virtual void addRef() const; + virtual void release() const; + + GLuint id() const { return mId; } + + private: + GLuint mId; + + mutable std::size_t mRefCount; +}; + +template +class BindingPointer +{ +public: + BindingPointer() + : mObject(nullptr) + { + } + + BindingPointer(const BindingPointer &other) + : mObject(nullptr) + { + set(other.mObject); + } + + void operator=(const BindingPointer &other) + { + set(other.mObject); + } + + virtual ~BindingPointer() + { + // Objects have to be released before the resource manager is destroyed, so they must be explicitly cleaned up. + ASSERT(mObject == nullptr); + } + + virtual void set(ObjectType *newObject) + { + // addRef first in case newObject == mObject and this is the last reference to it. + if (newObject != nullptr) reinterpret_cast(newObject)->addRef(); + if (mObject != nullptr) reinterpret_cast(mObject)->release(); + mObject = newObject; + } + + ObjectType *get() const { return mObject; } + ObjectType *operator->() const { return mObject; } + + GLuint id() const { return (mObject != nullptr) ? mObject->id() : 0; } + bool operator!() const { return (mObject == nullptr); } + + private: + ObjectType *mObject; +}; + +template +class OffsetBindingPointer : public BindingPointer +{ + public: + OffsetBindingPointer() : mOffset(0), mSize(0) { } + + void set(ObjectType *newObject) override + { + BindingPointer::set(newObject); + mOffset = 0; + mSize = 0; + } + + void set(ObjectType *newObject, GLintptr offset, GLsizeiptr size) + { + BindingPointer::set(newObject); + mOffset = offset; + mSize = size; + } + + GLintptr getOffset() const { return mOffset; } + GLsizeiptr getSize() const { return mSize; } + + private: + GLintptr mOffset; + GLsizeiptr mSize; +}; + +#endif // LIBANGLE_REFCOUNTOBJECT_H_ diff --git a/src/3rdparty/angle/src/libANGLE/Renderbuffer.cpp b/src/3rdparty/angle/src/libANGLE/Renderbuffer.cpp new file mode 100644 index 0000000000..6a0cde812b --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/Renderbuffer.cpp @@ -0,0 +1,130 @@ +// +// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Renderbuffer.cpp: Implements the renderer-agnostic gl::Renderbuffer class, +// GL renderbuffer objects and related functionality. +// [OpenGL ES 2.0.24] section 4.4.3 page 108. + +#include "libANGLE/Renderbuffer.h" + +#include "common/utilities.h" +#include "libANGLE/FramebufferAttachment.h" +#include "libANGLE/Texture.h" +#include "libANGLE/formatutils.h" +#include "libANGLE/renderer/d3d/RenderTargetD3D.h" +#include "libANGLE/renderer/RenderbufferImpl.h" + +namespace gl +{ +Renderbuffer::Renderbuffer(rx::RenderbufferImpl *impl, GLuint id) + : RefCountObject(id), + mRenderbuffer(impl), + mWidth(0), + mHeight(0), + mInternalFormat(GL_RGBA4), + mSamples(0) +{ +} + +Renderbuffer::~Renderbuffer() +{ + SafeDelete(mRenderbuffer); +} + +Error Renderbuffer::setStorage(GLenum internalformat, size_t width, size_t height) +{ + Error error = mRenderbuffer->setStorage(internalformat, width, height); + if (error.isError()) + { + return error; + } + + mWidth = width; + mHeight = height; + mInternalFormat = internalformat; + mSamples = 0; + + return Error(GL_NO_ERROR); +} + +Error Renderbuffer::setStorageMultisample(size_t samples, GLenum internalformat, size_t width, size_t height) +{ + Error error = mRenderbuffer->setStorageMultisample(samples, internalformat, width, height); + if (error.isError()) + { + return error; + } + + mWidth = width; + mHeight = height; + mInternalFormat = internalformat; + mSamples = samples; + + return Error(GL_NO_ERROR); +} + +rx::RenderbufferImpl *Renderbuffer::getImplementation() +{ + ASSERT(mRenderbuffer); + return mRenderbuffer; +} + +const rx::RenderbufferImpl *Renderbuffer::getImplementation() const +{ + return mRenderbuffer; +} + +GLsizei Renderbuffer::getWidth() const +{ + return mWidth; +} + +GLsizei Renderbuffer::getHeight() const +{ + return mHeight; +} + +GLenum Renderbuffer::getInternalFormat() const +{ + return mInternalFormat; +} + +GLsizei Renderbuffer::getSamples() const +{ + return mSamples; +} + +GLuint Renderbuffer::getRedSize() const +{ + return GetInternalFormatInfo(mInternalFormat).redBits; +} + +GLuint Renderbuffer::getGreenSize() const +{ + return GetInternalFormatInfo(mInternalFormat).greenBits; +} + +GLuint Renderbuffer::getBlueSize() const +{ + return GetInternalFormatInfo(mInternalFormat).blueBits; +} + +GLuint Renderbuffer::getAlphaSize() const +{ + return GetInternalFormatInfo(mInternalFormat).alphaBits; +} + +GLuint Renderbuffer::getDepthSize() const +{ + return GetInternalFormatInfo(mInternalFormat).depthBits; +} + +GLuint Renderbuffer::getStencilSize() const +{ + return GetInternalFormatInfo(mInternalFormat).stencilBits; +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/Renderbuffer.h b/src/3rdparty/angle/src/libANGLE/Renderbuffer.h new file mode 100644 index 0000000000..98c7eb0f10 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/Renderbuffer.h @@ -0,0 +1,69 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Renderbuffer.h: Defines the renderer-agnostic container class gl::Renderbuffer. +// Implements GL renderbuffer objects and related functionality. +// [OpenGL ES 2.0.24] section 4.4.3 page 108. + +#ifndef LIBANGLE_RENDERBUFFER_H_ +#define LIBANGLE_RENDERBUFFER_H_ + +#include "angle_gl.h" + +#include "libANGLE/Error.h" +#include "libANGLE/RefCountObject.h" + +#include "common/angleutils.h" + +namespace rx +{ +class RenderbufferImpl; +} + +namespace gl +{ +class FramebufferAttachment; + +// A GL renderbuffer object is usually used as a depth or stencil buffer attachment +// for a framebuffer object. The renderbuffer itself is a distinct GL object, see +// FramebufferAttachment and Framebuffer for how they are applied to an FBO via an +// attachment point. + +class Renderbuffer : public RefCountObject +{ + public: + Renderbuffer(rx::RenderbufferImpl *impl, GLuint id); + virtual ~Renderbuffer(); + + Error setStorage(GLenum internalformat, size_t width, size_t height); + Error setStorageMultisample(size_t samples, GLenum internalformat, size_t width, size_t height); + + rx::RenderbufferImpl *getImplementation(); + const rx::RenderbufferImpl *getImplementation() const; + + GLsizei getWidth() const; + GLsizei getHeight() const; + GLenum getInternalFormat() const; + GLsizei getSamples() const; + GLuint getRedSize() const; + GLuint getGreenSize() const; + GLuint getBlueSize() const; + GLuint getAlphaSize() const; + GLuint getDepthSize() const; + GLuint getStencilSize() const; + + private: + rx::RenderbufferImpl *mRenderbuffer; + + GLsizei mWidth; + GLsizei mHeight; + GLenum mInternalFormat; + GLsizei mSamples; +}; + +} + +#endif // LIBANGLE_RENDERBUFFER_H_ diff --git a/src/3rdparty/angle/src/libANGLE/ResourceManager.cpp b/src/3rdparty/angle/src/libANGLE/ResourceManager.cpp new file mode 100644 index 0000000000..aaf144cfa9 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/ResourceManager.cpp @@ -0,0 +1,456 @@ +// +// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// ResourceManager.cpp: Implements the gl::ResourceManager class, which tracks and +// retrieves objects which may be shared by multiple Contexts. + +#include "libANGLE/ResourceManager.h" + +#include "libANGLE/Buffer.h" +#include "libANGLE/Program.h" +#include "libANGLE/Renderbuffer.h" +#include "libANGLE/Shader.h" +#include "libANGLE/Texture.h" +#include "libANGLE/Sampler.h" +#include "libANGLE/Fence.h" +#include "libANGLE/renderer/Renderer.h" + +namespace gl +{ +ResourceManager::ResourceManager(rx::ImplFactory *factory) + : mFactory(factory), + mRefCount(1) +{ +} + +ResourceManager::~ResourceManager() +{ + while (!mBufferMap.empty()) + { + deleteBuffer(mBufferMap.begin()->first); + } + + while (!mProgramMap.empty()) + { + deleteProgram(mProgramMap.begin()->first); + } + + while (!mShaderMap.empty()) + { + deleteShader(mShaderMap.begin()->first); + } + + while (!mRenderbufferMap.empty()) + { + deleteRenderbuffer(mRenderbufferMap.begin()->first); + } + + while (!mTextureMap.empty()) + { + deleteTexture(mTextureMap.begin()->first); + } + + while (!mSamplerMap.empty()) + { + deleteSampler(mSamplerMap.begin()->first); + } + + while (!mFenceSyncMap.empty()) + { + deleteFenceSync(mFenceSyncMap.begin()->first); + } +} + +void ResourceManager::addRef() +{ + mRefCount++; +} + +void ResourceManager::release() +{ + if (--mRefCount == 0) + { + delete this; + } +} + +// Returns an unused buffer name +GLuint ResourceManager::createBuffer() +{ + GLuint handle = mBufferHandleAllocator.allocate(); + + mBufferMap[handle] = NULL; + + return handle; +} + +// Returns an unused shader/program name +GLuint ResourceManager::createShader(const gl::Data &data, GLenum type) +{ + GLuint handle = mProgramShaderHandleAllocator.allocate(); + + if (type == GL_VERTEX_SHADER || type == GL_FRAGMENT_SHADER) + { + mShaderMap[handle] = new Shader(this, mFactory->createShader(type), type, handle); + } + else UNREACHABLE(); + + return handle; +} + +// Returns an unused program/shader name +GLuint ResourceManager::createProgram() +{ + GLuint handle = mProgramShaderHandleAllocator.allocate(); + + mProgramMap[handle] = new Program(mFactory->createProgram(), this, handle); + + return handle; +} + +// Returns an unused texture name +GLuint ResourceManager::createTexture() +{ + GLuint handle = mTextureHandleAllocator.allocate(); + + mTextureMap[handle] = NULL; + + return handle; +} + +// Returns an unused renderbuffer name +GLuint ResourceManager::createRenderbuffer() +{ + GLuint handle = mRenderbufferHandleAllocator.allocate(); + + mRenderbufferMap[handle] = NULL; + + return handle; +} + +// Returns an unused sampler name +GLuint ResourceManager::createSampler() +{ + GLuint handle = mSamplerHandleAllocator.allocate(); + + mSamplerMap[handle] = NULL; + + return handle; +} + +// Returns the next unused fence name, and allocates the fence +GLuint ResourceManager::createFenceSync() +{ + GLuint handle = mFenceSyncHandleAllocator.allocate(); + + FenceSync *fenceSync = new FenceSync(mFactory->createFenceSync(), handle); + fenceSync->addRef(); + mFenceSyncMap[handle] = fenceSync; + + return handle; +} + +void ResourceManager::deleteBuffer(GLuint buffer) +{ + BufferMap::iterator bufferObject = mBufferMap.find(buffer); + + if (bufferObject != mBufferMap.end()) + { + mBufferHandleAllocator.release(bufferObject->first); + if (bufferObject->second) bufferObject->second->release(); + mBufferMap.erase(bufferObject); + } +} + +void ResourceManager::deleteShader(GLuint shader) +{ + ShaderMap::iterator shaderObject = mShaderMap.find(shader); + + if (shaderObject != mShaderMap.end()) + { + if (shaderObject->second->getRefCount() == 0) + { + mProgramShaderHandleAllocator.release(shaderObject->first); + delete shaderObject->second; + mShaderMap.erase(shaderObject); + } + else + { + shaderObject->second->flagForDeletion(); + } + } +} + +void ResourceManager::deleteProgram(GLuint program) +{ + ProgramMap::iterator programObject = mProgramMap.find(program); + + if (programObject != mProgramMap.end()) + { + if (programObject->second->getRefCount() == 0) + { + mProgramShaderHandleAllocator.release(programObject->first); + delete programObject->second; + mProgramMap.erase(programObject); + } + else + { + programObject->second->flagForDeletion(); + } + } +} + +void ResourceManager::deleteTexture(GLuint texture) +{ + TextureMap::iterator textureObject = mTextureMap.find(texture); + + if (textureObject != mTextureMap.end()) + { + mTextureHandleAllocator.release(textureObject->first); + if (textureObject->second) textureObject->second->release(); + mTextureMap.erase(textureObject); + } +} + +void ResourceManager::deleteRenderbuffer(GLuint renderbuffer) +{ + RenderbufferMap::iterator renderbufferObject = mRenderbufferMap.find(renderbuffer); + + if (renderbufferObject != mRenderbufferMap.end()) + { + mRenderbufferHandleAllocator.release(renderbufferObject->first); + if (renderbufferObject->second) renderbufferObject->second->release(); + mRenderbufferMap.erase(renderbufferObject); + } +} + +void ResourceManager::deleteSampler(GLuint sampler) +{ + auto samplerObject = mSamplerMap.find(sampler); + + if (samplerObject != mSamplerMap.end()) + { + mSamplerHandleAllocator.release(samplerObject->first); + if (samplerObject->second) samplerObject->second->release(); + mSamplerMap.erase(samplerObject); + } +} + +void ResourceManager::deleteFenceSync(GLuint fenceSync) +{ + auto fenceObjectIt = mFenceSyncMap.find(fenceSync); + + if (fenceObjectIt != mFenceSyncMap.end()) + { + mFenceSyncHandleAllocator.release(fenceObjectIt->first); + if (fenceObjectIt->second) fenceObjectIt->second->release(); + mFenceSyncMap.erase(fenceObjectIt); + } +} + +Buffer *ResourceManager::getBuffer(unsigned int handle) +{ + BufferMap::iterator buffer = mBufferMap.find(handle); + + if (buffer == mBufferMap.end()) + { + return NULL; + } + else + { + return buffer->second; + } +} + +Shader *ResourceManager::getShader(unsigned int handle) +{ + ShaderMap::iterator shader = mShaderMap.find(handle); + + if (shader == mShaderMap.end()) + { + return NULL; + } + else + { + return shader->second; + } +} + +Texture *ResourceManager::getTexture(unsigned int handle) +{ + if (handle == 0) return NULL; + + TextureMap::iterator texture = mTextureMap.find(handle); + + if (texture == mTextureMap.end()) + { + return NULL; + } + else + { + return texture->second; + } +} + +Program *ResourceManager::getProgram(unsigned int handle) const +{ + ProgramMap::const_iterator program = mProgramMap.find(handle); + + if (program == mProgramMap.end()) + { + return NULL; + } + else + { + return program->second; + } +} + +Renderbuffer *ResourceManager::getRenderbuffer(unsigned int handle) +{ + RenderbufferMap::iterator renderbuffer = mRenderbufferMap.find(handle); + + if (renderbuffer == mRenderbufferMap.end()) + { + return NULL; + } + else + { + return renderbuffer->second; + } +} + +Sampler *ResourceManager::getSampler(unsigned int handle) +{ + auto sampler = mSamplerMap.find(handle); + + if (sampler == mSamplerMap.end()) + { + return NULL; + } + else + { + return sampler->second; + } +} + +FenceSync *ResourceManager::getFenceSync(unsigned int handle) +{ + auto fenceObjectIt = mFenceSyncMap.find(handle); + + if (fenceObjectIt == mFenceSyncMap.end()) + { + return NULL; + } + else + { + return fenceObjectIt->second; + } +} + +void ResourceManager::setRenderbuffer(GLuint handle, Renderbuffer *buffer) +{ + mRenderbufferMap[handle] = buffer; +} + +void ResourceManager::checkBufferAllocation(GLuint handle) +{ + if (handle != 0) + { + auto bufferMapIt = mBufferMap.find(handle); + bool handleAllocated = (bufferMapIt != mBufferMap.end()); + + if (handleAllocated && bufferMapIt->second != nullptr) + { + return; + } + + Buffer *buffer = new Buffer(mFactory->createBuffer(), handle); + buffer->addRef(); + + if (handleAllocated) + { + bufferMapIt->second = buffer; + } + else + { + mBufferHandleAllocator.reserve(handle); + mBufferMap[handle] = buffer; + } + } +} + +void ResourceManager::checkTextureAllocation(GLuint handle, GLenum type) +{ + if (handle != 0) + { + auto textureMapIt = mTextureMap.find(handle); + bool handleAllocated = (textureMapIt != mTextureMap.end()); + + if (handleAllocated && textureMapIt->second != nullptr) + { + return; + } + + Texture *texture = new Texture(mFactory->createTexture(type), handle, type); + texture->addRef(); + + if (handleAllocated) + { + textureMapIt->second = texture; + } + else + { + mTextureHandleAllocator.reserve(handle); + mTextureMap[handle] = texture; + } + } +} + +void ResourceManager::checkRenderbufferAllocation(GLuint handle) +{ + if (handle != 0) + { + auto renderbufferMapIt = mRenderbufferMap.find(handle); + bool handleAllocated = (renderbufferMapIt != mRenderbufferMap.end()); + + if (handleAllocated && renderbufferMapIt->second != nullptr) + { + return; + } + + Renderbuffer *renderbuffer = new Renderbuffer(mFactory->createRenderbuffer(), handle); + renderbuffer->addRef(); + + if (handleAllocated) + { + renderbufferMapIt->second = renderbuffer; + } + else + { + mRenderbufferHandleAllocator.reserve(handle); + mRenderbufferMap[handle] = renderbuffer; + } + } +} + +void ResourceManager::checkSamplerAllocation(GLuint sampler) +{ + if (sampler != 0 && !getSampler(sampler)) + { + Sampler *samplerObject = new Sampler(sampler); + mSamplerMap[sampler] = samplerObject; + samplerObject->addRef(); + // Samplers cannot be created via Bind + } +} + +bool ResourceManager::isSampler(GLuint sampler) +{ + return mSamplerMap.find(sampler) != mSamplerMap.end(); +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/ResourceManager.h b/src/3rdparty/angle/src/libANGLE/ResourceManager.h new file mode 100644 index 0000000000..8e95e8840a --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/ResourceManager.h @@ -0,0 +1,114 @@ +// +// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// ResourceManager.h : Defines the ResourceManager class, which tracks objects +// shared by multiple GL contexts. + +#ifndef LIBANGLE_RESOURCEMANAGER_H_ +#define LIBANGLE_RESOURCEMANAGER_H_ + +#include "angle_gl.h" +#include "common/angleutils.h" +#include "libANGLE/angletypes.h" +#include "libANGLE/HandleAllocator.h" + +#include + +namespace rx +{ +class ImplFactory; +} + +namespace gl +{ +class Buffer; +class Shader; +class Program; +class Texture; +class Renderbuffer; +class Sampler; +class FenceSync; +struct Data; + +class ResourceManager : angle::NonCopyable +{ + public: + explicit ResourceManager(rx::ImplFactory *factory); + ~ResourceManager(); + + void addRef(); + void release(); + + GLuint createBuffer(); + GLuint createShader(const gl::Data &data, GLenum type); + GLuint createProgram(); + GLuint createTexture(); + GLuint createRenderbuffer(); + GLuint createSampler(); + GLuint createFenceSync(); + + void deleteBuffer(GLuint buffer); + void deleteShader(GLuint shader); + void deleteProgram(GLuint program); + void deleteTexture(GLuint texture); + void deleteRenderbuffer(GLuint renderbuffer); + void deleteSampler(GLuint sampler); + void deleteFenceSync(GLuint fenceSync); + + Buffer *getBuffer(GLuint handle); + Shader *getShader(GLuint handle); + Program *getProgram(GLuint handle) const; + Texture *getTexture(GLuint handle); + Renderbuffer *getRenderbuffer(GLuint handle); + Sampler *getSampler(GLuint handle); + FenceSync *getFenceSync(GLuint handle); + + void setRenderbuffer(GLuint handle, Renderbuffer *renderbuffer); + + void checkBufferAllocation(GLuint handle); + void checkTextureAllocation(GLuint handle, GLenum type); + void checkRenderbufferAllocation(GLuint handle); + void checkSamplerAllocation(GLuint sampler); + + bool isSampler(GLuint sampler); + + private: + void createTextureInternal(GLuint handle); + + rx::ImplFactory *mFactory; + std::size_t mRefCount; + + typedef std::map BufferMap; + BufferMap mBufferMap; + HandleAllocator mBufferHandleAllocator; + + typedef std::map ShaderMap; + ShaderMap mShaderMap; + + typedef std::map ProgramMap; + ProgramMap mProgramMap; + HandleAllocator mProgramShaderHandleAllocator; + + typedef std::map TextureMap; + TextureMap mTextureMap; + HandleAllocator mTextureHandleAllocator; + + typedef std::map RenderbufferMap; + RenderbufferMap mRenderbufferMap; + HandleAllocator mRenderbufferHandleAllocator; + + typedef std::map SamplerMap; + SamplerMap mSamplerMap; + HandleAllocator mSamplerHandleAllocator; + + typedef std::map FenceMap; + FenceMap mFenceSyncMap; + HandleAllocator mFenceSyncHandleAllocator; +}; + +} + +#endif // LIBANGLE_RESOURCEMANAGER_H_ diff --git a/src/3rdparty/angle/src/libANGLE/Sampler.cpp b/src/3rdparty/angle/src/libANGLE/Sampler.cpp new file mode 100644 index 0000000000..d58bd5a862 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/Sampler.cpp @@ -0,0 +1,43 @@ +// +// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Sampler.cpp : Implements the Sampler class, which represents a GLES 3 +// sampler object. Sampler objects store some state needed to sample textures. + +#include "libANGLE/Sampler.h" +#include "libANGLE/angletypes.h" + +namespace gl +{ + +Sampler::Sampler(GLuint id) + : RefCountObject(id), + mMinFilter(GL_NEAREST_MIPMAP_LINEAR), + mMagFilter(GL_LINEAR), + mWrapS(GL_REPEAT), + mWrapT(GL_REPEAT), + mWrapR(GL_REPEAT), + mMinLod(-1000.0f), + mMaxLod(1000.0f), + mComparisonMode(GL_NONE), + mComparisonFunc(GL_LEQUAL) +{ +} + +void Sampler::getState(SamplerState *samplerState) const +{ + samplerState->minFilter = mMinFilter; + samplerState->magFilter = mMagFilter; + samplerState->wrapS = mWrapS; + samplerState->wrapT = mWrapT; + samplerState->wrapR = mWrapR; + samplerState->minLod = mMinLod; + samplerState->maxLod = mMaxLod; + samplerState->compareMode = mComparisonMode; + samplerState->compareFunc = mComparisonFunc; +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/Sampler.h b/src/3rdparty/angle/src/libANGLE/Sampler.h new file mode 100644 index 0000000000..d33798ff15 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/Sampler.h @@ -0,0 +1,60 @@ +// +// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Sampler.h : Defines the Sampler class, which represents a GLES 3 +// sampler object. Sampler objects store some state needed to sample textures. + +#ifndef LIBANGLE_SAMPLER_H_ +#define LIBANGLE_SAMPLER_H_ + +#include "libANGLE/RefCountObject.h" + +namespace gl +{ +struct SamplerState; + +class Sampler : public RefCountObject +{ + public: + Sampler(GLuint id); + + void setMinFilter(GLenum minFilter) { mMinFilter = minFilter; } + void setMagFilter(GLenum magFilter) { mMagFilter = magFilter; } + void setWrapS(GLenum wrapS) { mWrapS = wrapS; } + void setWrapT(GLenum wrapT) { mWrapT = wrapT; } + void setWrapR(GLenum wrapR) { mWrapR = wrapR; } + void setMinLod(GLfloat minLod) { mMinLod = minLod; } + void setMaxLod(GLfloat maxLod) { mMaxLod = maxLod; } + void setComparisonMode(GLenum comparisonMode) { mComparisonMode = comparisonMode; } + void setComparisonFunc(GLenum comparisonFunc) { mComparisonFunc = comparisonFunc; } + + GLenum getMinFilter() const { return mMinFilter; } + GLenum getMagFilter() const { return mMagFilter; } + GLenum getWrapS() const { return mWrapS; } + GLenum getWrapT() const { return mWrapT; } + GLenum getWrapR() const { return mWrapR; } + GLfloat getMinLod() const { return mMinLod; } + GLfloat getMaxLod() const { return mMaxLod; } + GLenum getComparisonMode() const { return mComparisonMode; } + GLenum getComparisonFunc() const { return mComparisonFunc; } + + void getState(SamplerState *samplerState) const; + + private: + GLenum mMinFilter; + GLenum mMagFilter; + GLenum mWrapS; + GLenum mWrapT; + GLenum mWrapR; + GLfloat mMinLod; + GLfloat mMaxLod; + GLenum mComparisonMode; + GLenum mComparisonFunc; +}; + +} + +#endif // LIBANGLE_SAMPLER_H_ diff --git a/src/3rdparty/angle/src/libANGLE/Shader.cpp b/src/3rdparty/angle/src/libANGLE/Shader.cpp new file mode 100644 index 0000000000..7af4ff358d --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/Shader.cpp @@ -0,0 +1,243 @@ +// +// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Shader.cpp: Implements the gl::Shader class and its derived classes +// VertexShader and FragmentShader. Implements GL shader objects and related +// functionality. [OpenGL ES 2.0.24] section 2.10 page 24 and section 3.8 page 84. + +#include "libANGLE/Shader.h" +#include "libANGLE/renderer/Renderer.h" +#include "libANGLE/renderer/ShaderImpl.h" +#include "libANGLE/Constants.h" +#include "libANGLE/ResourceManager.h" + +#include "common/utilities.h" + +#include "GLSLANG/ShaderLang.h" + +#include + +namespace gl +{ + +Shader::Shader(ResourceManager *manager, rx::ShaderImpl *impl, GLenum type, GLuint handle) + : mShader(impl), + mType(type), + mHandle(handle), + mResourceManager(manager), + mRefCount(0), + mDeleteStatus(false), + mCompiled(false) +{ + ASSERT(impl); +} + +Shader::~Shader() +{ + SafeDelete(mShader); +} + +GLuint Shader::getHandle() const +{ + return mHandle; +} + +void Shader::setSource(GLsizei count, const char *const *string, const GLint *length) +{ + std::ostringstream stream; + + for (int i = 0; i < count; i++) + { + if (length == nullptr || length[i] < 0) + { + stream.write(string[i], strlen(string[i])); + } + else + { + stream.write(string[i], length[i]); + } + } + + mSource = stream.str(); +} + +int Shader::getInfoLogLength() const +{ + return mShader->getInfoLog().empty() ? 0 : (mShader->getInfoLog().length() + 1); +} + +void Shader::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog) const +{ + int index = 0; + + if (bufSize > 0) + { + index = std::min(bufSize - 1, static_cast(mShader->getInfoLog().length())); + memcpy(infoLog, mShader->getInfoLog().c_str(), index); + + infoLog[index] = '\0'; + } + + if (length) + { + *length = index; + } +} + +int Shader::getSourceLength() const +{ + return mSource.empty() ? 0 : (mSource.length() + 1); +} + +int Shader::getTranslatedSourceLength() const +{ + return mShader->getTranslatedSource().empty() ? 0 : (mShader->getTranslatedSource().length() + 1); +} + +void Shader::getSourceImpl(const std::string &source, GLsizei bufSize, GLsizei *length, char *buffer) +{ + int index = 0; + + if (bufSize > 0) + { + index = std::min(bufSize - 1, static_cast(source.length())); + memcpy(buffer, source.c_str(), index); + + buffer[index] = '\0'; + } + + if (length) + { + *length = index; + } +} + +void Shader::getSource(GLsizei bufSize, GLsizei *length, char *buffer) const +{ + getSourceImpl(mSource, bufSize, length, buffer); +} + +void Shader::getTranslatedSource(GLsizei bufSize, GLsizei *length, char *buffer) const +{ + getSourceImpl(mShader->getTranslatedSource(), bufSize, length, buffer); +} + +void Shader::getTranslatedSourceWithDebugInfo(GLsizei bufSize, GLsizei *length, char *buffer) const +{ + std::string debugInfo(mShader->getDebugInfo()); + getSourceImpl(debugInfo, bufSize, length, buffer); +} + +void Shader::compile(Compiler *compiler) +{ + mCompiled = mShader->compile(compiler, mSource); +} + +void Shader::addRef() +{ + mRefCount++; +} + +void Shader::release() +{ + mRefCount--; + + if (mRefCount == 0 && mDeleteStatus) + { + mResourceManager->deleteShader(mHandle); + } +} + +unsigned int Shader::getRefCount() const +{ + return mRefCount; +} + +bool Shader::isFlaggedForDeletion() const +{ + return mDeleteStatus; +} + +void Shader::flagForDeletion() +{ + mDeleteStatus = true; +} + +const std::vector &Shader::getVaryings() const +{ + return mShader->getVaryings(); +} + +const std::vector &Shader::getUniforms() const +{ + return mShader->getUniforms(); +} + +const std::vector &Shader::getInterfaceBlocks() const +{ + return mShader->getInterfaceBlocks(); +} + +const std::vector &Shader::getActiveAttributes() const +{ + return mShader->getActiveAttributes(); +} + +const std::vector &Shader::getActiveOutputVariables() const +{ + return mShader->getActiveOutputVariables(); +} + +std::vector &Shader::getVaryings() +{ + return mShader->getVaryings(); +} + +std::vector &Shader::getUniforms() +{ + return mShader->getUniforms(); +} + +std::vector &Shader::getInterfaceBlocks() +{ + return mShader->getInterfaceBlocks(); +} + +std::vector &Shader::getActiveAttributes() +{ + return mShader->getActiveAttributes(); +} + +std::vector &Shader::getActiveOutputVariables() +{ + return mShader->getActiveOutputVariables(); +} + + +int Shader::getSemanticIndex(const std::string &attributeName) const +{ + if (!attributeName.empty()) + { + const auto &activeAttributes = mShader->getActiveAttributes(); + + int semanticIndex = 0; + for (size_t attributeIndex = 0; attributeIndex < activeAttributes.size(); attributeIndex++) + { + const sh::ShaderVariable &attribute = activeAttributes[attributeIndex]; + + if (attribute.name == attributeName) + { + return semanticIndex; + } + + semanticIndex += gl::VariableRegisterCount(attribute.type); + } + } + + return -1; +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/Shader.h b/src/3rdparty/angle/src/libANGLE/Shader.h new file mode 100644 index 0000000000..10e79c7499 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/Shader.h @@ -0,0 +1,118 @@ +// +// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Shader.h: Defines the abstract gl::Shader class and its concrete derived +// classes VertexShader and FragmentShader. Implements GL shader objects and +// related functionality. [OpenGL ES 2.0.24] section 2.10 page 24 and section +// 3.8 page 84. + +#ifndef LIBANGLE_SHADER_H_ +#define LIBANGLE_SHADER_H_ + +#include +#include +#include + +#include "angle_gl.h" +#include + +#include "common/angleutils.h" +#include "libANGLE/angletypes.h" + +namespace rx +{ +class ShaderImpl; +} + +namespace gl +{ +class Compiler; +class ResourceManager; +struct Data; + +struct PackedVarying : public sh::Varying +{ + unsigned int registerIndex; // Assigned during link + unsigned int columnIndex; // Assigned during link, defaults to 0 + + PackedVarying(const sh::Varying &varying) + : sh::Varying(varying), + registerIndex(GL_INVALID_INDEX), + columnIndex(0) + {} + + bool registerAssigned() const { return registerIndex != GL_INVALID_INDEX; } + bool isBuiltIn() const { return name.compare(0, 3, "gl_") == 0; } + + void resetRegisterAssignment() + { + registerIndex = GL_INVALID_INDEX; + } +}; + +class Shader : angle::NonCopyable +{ + public: + Shader(ResourceManager *manager, rx::ShaderImpl *impl, GLenum type, GLuint handle); + + virtual ~Shader(); + + GLenum getType() const { return mType; } + GLuint getHandle() const; + + rx::ShaderImpl *getImplementation() { return mShader; } + const rx::ShaderImpl *getImplementation() const { return mShader; } + + void deleteSource(); + void setSource(GLsizei count, const char *const *string, const GLint *length); + int getInfoLogLength() const; + void getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog) const; + int getSourceLength() const; + void getSource(GLsizei bufSize, GLsizei *length, char *buffer) const; + int getTranslatedSourceLength() const; + void getTranslatedSource(GLsizei bufSize, GLsizei *length, char *buffer) const; + void getTranslatedSourceWithDebugInfo(GLsizei bufSize, GLsizei *length, char *buffer) const; + + void compile(Compiler *compiler); + bool isCompiled() const { return mCompiled; } + + void addRef(); + void release(); + unsigned int getRefCount() const; + bool isFlaggedForDeletion() const; + void flagForDeletion(); + + const std::vector &getVaryings() const; + const std::vector &getUniforms() const; + const std::vector &getInterfaceBlocks() const; + const std::vector &getActiveAttributes() const; + const std::vector &getActiveOutputVariables() const; + + std::vector &getVaryings(); + std::vector &getUniforms(); + std::vector &getInterfaceBlocks(); + std::vector &getActiveAttributes(); + std::vector &getActiveOutputVariables(); + + int getSemanticIndex(const std::string &attributeName) const; + + private: + static void getSourceImpl(const std::string &source, GLsizei bufSize, GLsizei *length, char *buffer); + + rx::ShaderImpl *mShader; + const GLuint mHandle; + const GLenum mType; + std::string mSource; + unsigned int mRefCount; // Number of program objects this shader is attached to + bool mDeleteStatus; // Flag to indicate that the shader can be deleted when no longer in use + bool mCompiled; // Indicates if this shader has been successfully compiled + + ResourceManager *mResourceManager; +}; + +} + +#endif // LIBANGLE_SHADER_H_ diff --git a/src/3rdparty/angle/src/libANGLE/State.cpp b/src/3rdparty/angle/src/libANGLE/State.cpp new file mode 100644 index 0000000000..4c044d2950 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/State.cpp @@ -0,0 +1,1470 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// State.cpp: Implements the State class, encapsulating raw GL state. + +#include "libANGLE/State.h" + +#include "libANGLE/Context.h" +#include "libANGLE/Caps.h" +#include "libANGLE/Framebuffer.h" +#include "libANGLE/FramebufferAttachment.h" +#include "libANGLE/Query.h" +#include "libANGLE/VertexArray.h" +#include "libANGLE/formatutils.h" + +namespace gl +{ + +State::State() +{ + mMaxDrawBuffers = 0; + mMaxCombinedTextureImageUnits = 0; +} + +State::~State() +{ + reset(); +} + +void State::initialize(const Caps& caps, GLuint clientVersion) +{ + mMaxDrawBuffers = caps.maxDrawBuffers; + mMaxCombinedTextureImageUnits = caps.maxCombinedTextureImageUnits; + + setColorClearValue(0.0f, 0.0f, 0.0f, 0.0f); + + mDepthClearValue = 1.0f; + mStencilClearValue = 0; + + mRasterizer.rasterizerDiscard = false; + mRasterizer.cullFace = false; + mRasterizer.cullMode = GL_BACK; + mRasterizer.frontFace = GL_CCW; + mRasterizer.polygonOffsetFill = false; + mRasterizer.polygonOffsetFactor = 0.0f; + mRasterizer.polygonOffsetUnits = 0.0f; + mRasterizer.pointDrawMode = false; + mRasterizer.multiSample = false; + mScissorTest = false; + mScissor.x = 0; + mScissor.y = 0; + mScissor.width = 0; + mScissor.height = 0; + + mBlend.blend = false; + mBlend.sourceBlendRGB = GL_ONE; + mBlend.sourceBlendAlpha = GL_ONE; + mBlend.destBlendRGB = GL_ZERO; + mBlend.destBlendAlpha = GL_ZERO; + mBlend.blendEquationRGB = GL_FUNC_ADD; + mBlend.blendEquationAlpha = GL_FUNC_ADD; + mBlend.sampleAlphaToCoverage = false; + mBlend.dither = true; + + mBlendColor.red = 0; + mBlendColor.green = 0; + mBlendColor.blue = 0; + mBlendColor.alpha = 0; + + mDepthStencil.depthTest = false; + mDepthStencil.depthFunc = GL_LESS; + mDepthStencil.depthMask = true; + mDepthStencil.stencilTest = false; + mDepthStencil.stencilFunc = GL_ALWAYS; + mDepthStencil.stencilMask = static_cast(-1); + mDepthStencil.stencilWritemask = static_cast(-1); + mDepthStencil.stencilBackFunc = GL_ALWAYS; + mDepthStencil.stencilBackMask = static_cast(-1); + mDepthStencil.stencilBackWritemask = static_cast(-1); + mDepthStencil.stencilFail = GL_KEEP; + mDepthStencil.stencilPassDepthFail = GL_KEEP; + mDepthStencil.stencilPassDepthPass = GL_KEEP; + mDepthStencil.stencilBackFail = GL_KEEP; + mDepthStencil.stencilBackPassDepthFail = GL_KEEP; + mDepthStencil.stencilBackPassDepthPass = GL_KEEP; + + mStencilRef = 0; + mStencilBackRef = 0; + + mSampleCoverage = false; + mSampleCoverageValue = 1.0f; + mSampleCoverageInvert = false; + mGenerateMipmapHint = GL_DONT_CARE; + mFragmentShaderDerivativeHint = GL_DONT_CARE; + + mLineWidth = 1.0f; + + mViewport.x = 0; + mViewport.y = 0; + mViewport.width = 0; + mViewport.height = 0; + mNearZ = 0.0f; + mFarZ = 1.0f; + + mBlend.colorMaskRed = true; + mBlend.colorMaskGreen = true; + mBlend.colorMaskBlue = true; + mBlend.colorMaskAlpha = true; + + mActiveSampler = 0; + + const GLfloat defaultFloatValues[] = { 0.0f, 0.0f, 0.0f, 1.0f }; + mVertexAttribCurrentValues.resize(caps.maxVertexAttributes); + for (size_t attribIndex = 0; attribIndex < mVertexAttribCurrentValues.size(); ++attribIndex) + { + mVertexAttribCurrentValues[attribIndex].setFloatValues(defaultFloatValues); + } + + mUniformBuffers.resize(caps.maxCombinedUniformBlocks); + mTransformFeedbackBuffers.resize(caps.maxTransformFeedbackSeparateAttributes); + + mSamplerTextures[GL_TEXTURE_2D].resize(caps.maxCombinedTextureImageUnits); + mSamplerTextures[GL_TEXTURE_CUBE_MAP].resize(caps.maxCombinedTextureImageUnits); + if (clientVersion >= 3) + { + // TODO: These could also be enabled via extension + mSamplerTextures[GL_TEXTURE_2D_ARRAY].resize(caps.maxCombinedTextureImageUnits); + mSamplerTextures[GL_TEXTURE_3D].resize(caps.maxCombinedTextureImageUnits); + } + + mSamplers.resize(caps.maxCombinedTextureImageUnits); + + mActiveQueries[GL_ANY_SAMPLES_PASSED].set(NULL); + mActiveQueries[GL_ANY_SAMPLES_PASSED_CONSERVATIVE].set(NULL); + mActiveQueries[GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN].set(NULL); + + mProgram = NULL; + + mReadFramebuffer = NULL; + mDrawFramebuffer = NULL; + + mPrimitiveRestart = false; +} + +void State::reset() +{ + for (TextureBindingMap::iterator bindingVec = mSamplerTextures.begin(); bindingVec != mSamplerTextures.end(); bindingVec++) + { + TextureBindingVector &textureVector = bindingVec->second; + for (size_t textureIdx = 0; textureIdx < textureVector.size(); textureIdx++) + { + textureVector[textureIdx].set(NULL); + } + } + for (size_t samplerIdx = 0; samplerIdx < mSamplers.size(); samplerIdx++) + { + mSamplers[samplerIdx].set(NULL); + } + + mArrayBuffer.set(NULL); + mRenderbuffer.set(NULL); + + if (mProgram) + { + mProgram->release(); + } + mProgram = NULL; + + mTransformFeedback.set(NULL); + + for (State::ActiveQueryMap::iterator i = mActiveQueries.begin(); i != mActiveQueries.end(); i++) + { + i->second.set(NULL); + } + + mGenericUniformBuffer.set(NULL); + mGenericTransformFeedbackBuffer.set(NULL); + for (BufferVector::iterator bufItr = mUniformBuffers.begin(); bufItr != mUniformBuffers.end(); ++bufItr) + { + bufItr->set(NULL); + } + + for (BufferVector::iterator bufItr = mTransformFeedbackBuffers.begin(); bufItr != mTransformFeedbackBuffers.end(); ++bufItr) + { + bufItr->set(NULL); + } + + mCopyReadBuffer.set(NULL); + mCopyWriteBuffer.set(NULL); + + mPack.pixelBuffer.set(NULL); + mUnpack.pixelBuffer.set(NULL); + + mProgram = NULL; +} + +const RasterizerState &State::getRasterizerState() const +{ + return mRasterizer; +} + +const BlendState &State::getBlendState() const +{ + return mBlend; +} + +const DepthStencilState &State::getDepthStencilState() const +{ + return mDepthStencil; +} + +void State::setColorClearValue(float red, float green, float blue, float alpha) +{ + mColorClearValue.red = red; + mColorClearValue.green = green; + mColorClearValue.blue = blue; + mColorClearValue.alpha = alpha; +} + +void State::setDepthClearValue(float depth) +{ + mDepthClearValue = depth; +} + +void State::setStencilClearValue(int stencil) +{ + mStencilClearValue = stencil; +} + +void State::setColorMask(bool red, bool green, bool blue, bool alpha) +{ + mBlend.colorMaskRed = red; + mBlend.colorMaskGreen = green; + mBlend.colorMaskBlue = blue; + mBlend.colorMaskAlpha = alpha; +} + +void State::setDepthMask(bool mask) +{ + mDepthStencil.depthMask = mask; +} + +bool State::isRasterizerDiscardEnabled() const +{ + return mRasterizer.rasterizerDiscard; +} + +void State::setRasterizerDiscard(bool enabled) +{ + mRasterizer.rasterizerDiscard = enabled; +} + +bool State::isCullFaceEnabled() const +{ + return mRasterizer.cullFace; +} + +void State::setCullFace(bool enabled) +{ + mRasterizer.cullFace = enabled; +} + +void State::setCullMode(GLenum mode) +{ + mRasterizer.cullMode = mode; +} + +void State::setFrontFace(GLenum front) +{ + mRasterizer.frontFace = front; +} + +bool State::isDepthTestEnabled() const +{ + return mDepthStencil.depthTest; +} + +void State::setDepthTest(bool enabled) +{ + mDepthStencil.depthTest = enabled; +} + +void State::setDepthFunc(GLenum depthFunc) +{ + mDepthStencil.depthFunc = depthFunc; +} + +void State::setDepthRange(float zNear, float zFar) +{ + mNearZ = zNear; + mFarZ = zFar; +} + +void State::getDepthRange(float *zNear, float *zFar) const +{ + *zNear = mNearZ; + *zFar = mFarZ; +} + +bool State::isBlendEnabled() const +{ + return mBlend.blend; +} + +void State::setBlend(bool enabled) +{ + mBlend.blend = enabled; +} + +void State::setBlendFactors(GLenum sourceRGB, GLenum destRGB, GLenum sourceAlpha, GLenum destAlpha) +{ + mBlend.sourceBlendRGB = sourceRGB; + mBlend.destBlendRGB = destRGB; + mBlend.sourceBlendAlpha = sourceAlpha; + mBlend.destBlendAlpha = destAlpha; +} + +void State::setBlendColor(float red, float green, float blue, float alpha) +{ + mBlendColor.red = red; + mBlendColor.green = green; + mBlendColor.blue = blue; + mBlendColor.alpha = alpha; +} + +void State::setBlendEquation(GLenum rgbEquation, GLenum alphaEquation) +{ + mBlend.blendEquationRGB = rgbEquation; + mBlend.blendEquationAlpha = alphaEquation; +} + +const ColorF &State::getBlendColor() const +{ + return mBlendColor; +} + +bool State::isStencilTestEnabled() const +{ + return mDepthStencil.stencilTest; +} + +void State::setStencilTest(bool enabled) +{ + mDepthStencil.stencilTest = enabled; +} + +void State::setStencilParams(GLenum stencilFunc, GLint stencilRef, GLuint stencilMask) +{ + mDepthStencil.stencilFunc = stencilFunc; + mStencilRef = (stencilRef > 0) ? stencilRef : 0; + mDepthStencil.stencilMask = stencilMask; +} + +void State::setStencilBackParams(GLenum stencilBackFunc, GLint stencilBackRef, GLuint stencilBackMask) +{ + mDepthStencil.stencilBackFunc = stencilBackFunc; + mStencilBackRef = (stencilBackRef > 0) ? stencilBackRef : 0; + mDepthStencil.stencilBackMask = stencilBackMask; +} + +void State::setStencilWritemask(GLuint stencilWritemask) +{ + mDepthStencil.stencilWritemask = stencilWritemask; +} + +void State::setStencilBackWritemask(GLuint stencilBackWritemask) +{ + mDepthStencil.stencilBackWritemask = stencilBackWritemask; +} + +void State::setStencilOperations(GLenum stencilFail, GLenum stencilPassDepthFail, GLenum stencilPassDepthPass) +{ + mDepthStencil.stencilFail = stencilFail; + mDepthStencil.stencilPassDepthFail = stencilPassDepthFail; + mDepthStencil.stencilPassDepthPass = stencilPassDepthPass; +} + +void State::setStencilBackOperations(GLenum stencilBackFail, GLenum stencilBackPassDepthFail, GLenum stencilBackPassDepthPass) +{ + mDepthStencil.stencilBackFail = stencilBackFail; + mDepthStencil.stencilBackPassDepthFail = stencilBackPassDepthFail; + mDepthStencil.stencilBackPassDepthPass = stencilBackPassDepthPass; +} + +GLint State::getStencilRef() const +{ + return mStencilRef; +} + +GLint State::getStencilBackRef() const +{ + return mStencilBackRef; +} + +bool State::isPolygonOffsetFillEnabled() const +{ + return mRasterizer.polygonOffsetFill; +} + +void State::setPolygonOffsetFill(bool enabled) +{ + mRasterizer.polygonOffsetFill = enabled; +} + +void State::setPolygonOffsetParams(GLfloat factor, GLfloat units) +{ + // An application can pass NaN values here, so handle this gracefully + mRasterizer.polygonOffsetFactor = factor != factor ? 0.0f : factor; + mRasterizer.polygonOffsetUnits = units != units ? 0.0f : units; +} + +bool State::isSampleAlphaToCoverageEnabled() const +{ + return mBlend.sampleAlphaToCoverage; +} + +void State::setSampleAlphaToCoverage(bool enabled) +{ + mBlend.sampleAlphaToCoverage = enabled; +} + +bool State::isSampleCoverageEnabled() const +{ + return mSampleCoverage; +} + +void State::setSampleCoverage(bool enabled) +{ + mSampleCoverage = enabled; +} + +void State::setSampleCoverageParams(GLclampf value, bool invert) +{ + mSampleCoverageValue = value; + mSampleCoverageInvert = invert; +} + +void State::getSampleCoverageParams(GLclampf *value, bool *invert) const +{ + ASSERT(value != NULL && invert != NULL); + + *value = mSampleCoverageValue; + *invert = mSampleCoverageInvert; +} + +bool State::isScissorTestEnabled() const +{ + return mScissorTest; +} + +void State::setScissorTest(bool enabled) +{ + mScissorTest = enabled; +} + +void State::setScissorParams(GLint x, GLint y, GLsizei width, GLsizei height) +{ + mScissor.x = x; + mScissor.y = y; + mScissor.width = width; + mScissor.height = height; +} + +const Rectangle &State::getScissor() const +{ + return mScissor; +} + +bool State::isDitherEnabled() const +{ + return mBlend.dither; +} + +void State::setDither(bool enabled) +{ + mBlend.dither = enabled; +} + +bool State::isPrimitiveRestartEnabled() const +{ + return mPrimitiveRestart; +} + +void State::setPrimitiveRestart(bool enabled) +{ + mPrimitiveRestart = enabled; +} + +void State::setEnableFeature(GLenum feature, bool enabled) +{ + switch (feature) + { + case GL_CULL_FACE: setCullFace(enabled); break; + case GL_POLYGON_OFFSET_FILL: setPolygonOffsetFill(enabled); break; + case GL_SAMPLE_ALPHA_TO_COVERAGE: setSampleAlphaToCoverage(enabled); break; + case GL_SAMPLE_COVERAGE: setSampleCoverage(enabled); break; + case GL_SCISSOR_TEST: setScissorTest(enabled); break; + case GL_STENCIL_TEST: setStencilTest(enabled); break; + case GL_DEPTH_TEST: setDepthTest(enabled); break; + case GL_BLEND: setBlend(enabled); break; + case GL_DITHER: setDither(enabled); break; + case GL_PRIMITIVE_RESTART_FIXED_INDEX: setPrimitiveRestart(enabled); break; + case GL_RASTERIZER_DISCARD: setRasterizerDiscard(enabled); break; + default: UNREACHABLE(); + } +} + +bool State::getEnableFeature(GLenum feature) +{ + switch (feature) + { + case GL_CULL_FACE: return isCullFaceEnabled(); + case GL_POLYGON_OFFSET_FILL: return isPolygonOffsetFillEnabled(); + case GL_SAMPLE_ALPHA_TO_COVERAGE: return isSampleAlphaToCoverageEnabled(); + case GL_SAMPLE_COVERAGE: return isSampleCoverageEnabled(); + case GL_SCISSOR_TEST: return isScissorTestEnabled(); + case GL_STENCIL_TEST: return isStencilTestEnabled(); + case GL_DEPTH_TEST: return isDepthTestEnabled(); + case GL_BLEND: return isBlendEnabled(); + case GL_DITHER: return isDitherEnabled(); + case GL_PRIMITIVE_RESTART_FIXED_INDEX: return isPrimitiveRestartEnabled(); + case GL_RASTERIZER_DISCARD: return isRasterizerDiscardEnabled(); + default: UNREACHABLE(); return false; + } +} + +void State::setLineWidth(GLfloat width) +{ + mLineWidth = width; +} + +void State::setGenerateMipmapHint(GLenum hint) +{ + mGenerateMipmapHint = hint; +} + +void State::setFragmentShaderDerivativeHint(GLenum hint) +{ + mFragmentShaderDerivativeHint = hint; + // TODO: Propagate the hint to shader translator so we can write + // ddx, ddx_coarse, or ddx_fine depending on the hint. + // Ignore for now. It is valid for implementations to ignore hint. +} + +void State::setViewportParams(GLint x, GLint y, GLsizei width, GLsizei height) +{ + mViewport.x = x; + mViewport.y = y; + mViewport.width = width; + mViewport.height = height; +} + +const Rectangle &State::getViewport() const +{ + return mViewport; +} + +void State::setActiveSampler(unsigned int active) +{ + mActiveSampler = active; +} + +unsigned int State::getActiveSampler() const +{ + return mActiveSampler; +} + +void State::setSamplerTexture(GLenum type, Texture *texture) +{ + mSamplerTextures[type][mActiveSampler].set(texture); +} + +Texture *State::getSamplerTexture(unsigned int sampler, GLenum type) const +{ + const auto it = mSamplerTextures.find(type); + ASSERT(it != mSamplerTextures.end()); + return it->second[sampler].get(); +} + +GLuint State::getSamplerTextureId(unsigned int sampler, GLenum type) const +{ + const auto it = mSamplerTextures.find(type); + ASSERT(it != mSamplerTextures.end()); + return it->second[sampler].id(); +} + +void State::detachTexture(const TextureMap &zeroTextures, GLuint texture) +{ + // Textures have a detach method on State rather than a simple + // removeBinding, because the zero/null texture objects are managed + // separately, and don't have to go through the Context's maps or + // the ResourceManager. + + // [OpenGL ES 2.0.24] section 3.8 page 84: + // If a texture object is deleted, it is as if all texture units which are bound to that texture object are + // rebound to texture object zero + + for (TextureBindingMap::iterator bindingVec = mSamplerTextures.begin(); bindingVec != mSamplerTextures.end(); bindingVec++) + { + GLenum textureType = bindingVec->first; + TextureBindingVector &textureVector = bindingVec->second; + for (size_t textureIdx = 0; textureIdx < textureVector.size(); textureIdx++) + { + BindingPointer &binding = textureVector[textureIdx]; + if (binding.id() == texture) + { + auto it = zeroTextures.find(textureType); + ASSERT(it != zeroTextures.end()); + // Zero textures are the "default" textures instead of NULL + binding.set(it->second.get()); + } + } + } + + // [OpenGL ES 2.0.24] section 4.4 page 112: + // If a texture object is deleted while its image is attached to the currently bound framebuffer, then it is + // as if Texture2DAttachment had been called, with a texture of 0, for each attachment point to which this + // image was attached in the currently bound framebuffer. + + if (mReadFramebuffer) + { + mReadFramebuffer->detachTexture(texture); + } + + if (mDrawFramebuffer) + { + mDrawFramebuffer->detachTexture(texture); + } +} + +void State::initializeZeroTextures(const TextureMap &zeroTextures) +{ + for (auto it = zeroTextures.cbegin(); it != zeroTextures.cend(); ++it) + { + const auto &zeroTexture = *it; + auto &samplerTextureArray = mSamplerTextures[zeroTexture.first]; + + for (size_t textureUnit = 0; textureUnit < samplerTextureArray.size(); ++textureUnit) + { + samplerTextureArray[textureUnit].set(zeroTexture.second.get()); + } + } +} + +void State::setSamplerBinding(GLuint textureUnit, Sampler *sampler) +{ + mSamplers[textureUnit].set(sampler); +} + +GLuint State::getSamplerId(GLuint textureUnit) const +{ + ASSERT(textureUnit < mSamplers.size()); + return mSamplers[textureUnit].id(); +} + +Sampler *State::getSampler(GLuint textureUnit) const +{ + return mSamplers[textureUnit].get(); +} + +void State::detachSampler(GLuint sampler) +{ + // [OpenGL ES 3.0.2] section 3.8.2 pages 123-124: + // If a sampler object that is currently bound to one or more texture units is + // deleted, it is as though BindSampler is called once for each texture unit to + // which the sampler is bound, with unit set to the texture unit and sampler set to zero. + for (size_t textureUnit = 0; textureUnit < mSamplers.size(); textureUnit++) + { + BindingPointer &samplerBinding = mSamplers[textureUnit]; + if (samplerBinding.id() == sampler) + { + samplerBinding.set(NULL); + } + } +} + +void State::setRenderbufferBinding(Renderbuffer *renderbuffer) +{ + mRenderbuffer.set(renderbuffer); +} + +GLuint State::getRenderbufferId() const +{ + return mRenderbuffer.id(); +} + +Renderbuffer *State::getCurrentRenderbuffer() +{ + return mRenderbuffer.get(); +} + +void State::detachRenderbuffer(GLuint renderbuffer) +{ + // [OpenGL ES 2.0.24] section 4.4 page 109: + // If a renderbuffer that is currently bound to RENDERBUFFER is deleted, it is as though BindRenderbuffer + // had been executed with the target RENDERBUFFER and name of zero. + + if (mRenderbuffer.id() == renderbuffer) + { + mRenderbuffer.set(NULL); + } + + // [OpenGL ES 2.0.24] section 4.4 page 111: + // If a renderbuffer object is deleted while its image is attached to the currently bound framebuffer, + // then it is as if FramebufferRenderbuffer had been called, with a renderbuffer of 0, for each attachment + // point to which this image was attached in the currently bound framebuffer. + + Framebuffer *readFramebuffer = mReadFramebuffer; + Framebuffer *drawFramebuffer = mDrawFramebuffer; + + if (readFramebuffer) + { + readFramebuffer->detachRenderbuffer(renderbuffer); + } + + if (drawFramebuffer && drawFramebuffer != readFramebuffer) + { + drawFramebuffer->detachRenderbuffer(renderbuffer); + } + +} + +void State::setReadFramebufferBinding(Framebuffer *framebuffer) +{ + mReadFramebuffer = framebuffer; +} + +void State::setDrawFramebufferBinding(Framebuffer *framebuffer) +{ + mDrawFramebuffer = framebuffer; +} + +Framebuffer *State::getTargetFramebuffer(GLenum target) const +{ + switch (target) + { + case GL_READ_FRAMEBUFFER_ANGLE: return mReadFramebuffer; + case GL_DRAW_FRAMEBUFFER_ANGLE: + case GL_FRAMEBUFFER: return mDrawFramebuffer; + default: UNREACHABLE(); return NULL; + } +} + +Framebuffer *State::getReadFramebuffer() +{ + return mReadFramebuffer; +} + +Framebuffer *State::getDrawFramebuffer() +{ + return mDrawFramebuffer; +} + +const Framebuffer *State::getReadFramebuffer() const +{ + return mReadFramebuffer; +} + +const Framebuffer *State::getDrawFramebuffer() const +{ + return mDrawFramebuffer; +} + +bool State::removeReadFramebufferBinding(GLuint framebuffer) +{ + if (mReadFramebuffer->id() == framebuffer) + { + mReadFramebuffer = NULL; + return true; + } + + return false; +} + +bool State::removeDrawFramebufferBinding(GLuint framebuffer) +{ + if (mDrawFramebuffer->id() == framebuffer) + { + mDrawFramebuffer = NULL; + return true; + } + + return false; +} + +void State::setVertexArrayBinding(VertexArray *vertexArray) +{ + mVertexArray = vertexArray; +} + +GLuint State::getVertexArrayId() const +{ + ASSERT(mVertexArray != NULL); + return mVertexArray->id(); +} + +VertexArray *State::getVertexArray() const +{ + ASSERT(mVertexArray != NULL); + return mVertexArray; +} + +bool State::removeVertexArrayBinding(GLuint vertexArray) +{ + if (mVertexArray->id() == vertexArray) + { + mVertexArray = NULL; + return true; + } + + return false; +} + +void State::setProgram(Program *newProgram) +{ + if (mProgram != newProgram) + { + if (mProgram) + { + mProgram->release(); + } + + mProgram = newProgram; + + if (mProgram) + { + newProgram->addRef(); + } + } +} + +Program *State::getProgram() const +{ + return mProgram; +} + +void State::setTransformFeedbackBinding(TransformFeedback *transformFeedback) +{ + mTransformFeedback.set(transformFeedback); +} + +TransformFeedback *State::getCurrentTransformFeedback() const +{ + return mTransformFeedback.get(); +} + +bool State::isTransformFeedbackActiveUnpaused() const +{ + gl::TransformFeedback *curTransformFeedback = getCurrentTransformFeedback(); + return curTransformFeedback && curTransformFeedback->isStarted() && !curTransformFeedback->isPaused(); +} + +void State::detachTransformFeedback(GLuint transformFeedback) +{ + if (mTransformFeedback.id() == transformFeedback) + { + mTransformFeedback.set(NULL); + } +} + +bool State::isQueryActive() const +{ + for (State::ActiveQueryMap::const_iterator i = mActiveQueries.begin(); + i != mActiveQueries.end(); i++) + { + if (i->second.get() != NULL) + { + return true; + } + } + + return false; +} + +void State::setActiveQuery(GLenum target, Query *query) +{ + mActiveQueries[target].set(query); +} + +GLuint State::getActiveQueryId(GLenum target) const +{ + const Query *query = getActiveQuery(target); + return (query ? query->id() : 0u); +} + +Query *State::getActiveQuery(GLenum target) const +{ + const auto it = mActiveQueries.find(target); + + // All query types should already exist in the activeQueries map + ASSERT(it != mActiveQueries.end()); + + return it->second.get(); +} + +void State::setArrayBufferBinding(Buffer *buffer) +{ + mArrayBuffer.set(buffer); +} + +GLuint State::getArrayBufferId() const +{ + return mArrayBuffer.id(); +} + +bool State::removeArrayBufferBinding(GLuint buffer) +{ + if (mArrayBuffer.id() == buffer) + { + mArrayBuffer.set(NULL); + return true; + } + + return false; +} + +void State::setGenericUniformBufferBinding(Buffer *buffer) +{ + mGenericUniformBuffer.set(buffer); +} + +void State::setIndexedUniformBufferBinding(GLuint index, Buffer *buffer, GLintptr offset, GLsizeiptr size) +{ + mUniformBuffers[index].set(buffer, offset, size); +} + +GLuint State::getIndexedUniformBufferId(GLuint index) const +{ + ASSERT(static_cast(index) < mUniformBuffers.size()); + + return mUniformBuffers[index].id(); +} + +Buffer *State::getIndexedUniformBuffer(GLuint index) const +{ + ASSERT(static_cast(index) < mUniformBuffers.size()); + + return mUniformBuffers[index].get(); +} + +GLintptr State::getIndexedUniformBufferOffset(GLuint index) const +{ + ASSERT(static_cast(index) < mUniformBuffers.size()); + + return mUniformBuffers[index].getOffset(); +} + +GLsizeiptr State::getIndexedUniformBufferSize(GLuint index) const +{ + ASSERT(static_cast(index) < mUniformBuffers.size()); + + return mUniformBuffers[index].getSize(); +} + +void State::setGenericTransformFeedbackBufferBinding(Buffer *buffer) +{ + mGenericTransformFeedbackBuffer.set(buffer); +} + +void State::setIndexedTransformFeedbackBufferBinding(GLuint index, Buffer *buffer, GLintptr offset, GLsizeiptr size) +{ + mTransformFeedbackBuffers[index].set(buffer, offset, size); +} + +GLuint State::getIndexedTransformFeedbackBufferId(GLuint index) const +{ + ASSERT(static_cast(index) < mTransformFeedbackBuffers.size()); + + return mTransformFeedbackBuffers[index].id(); +} + +Buffer *State::getIndexedTransformFeedbackBuffer(GLuint index) const +{ + ASSERT(static_cast(index) < mTransformFeedbackBuffers.size()); + + return mTransformFeedbackBuffers[index].get(); +} + +GLuint State::getIndexedTransformFeedbackBufferOffset(GLuint index) const +{ + ASSERT(static_cast(index) < mTransformFeedbackBuffers.size()); + + return mTransformFeedbackBuffers[index].getOffset(); +} + +size_t State::getTransformFeedbackBufferIndexRange() const +{ + return mTransformFeedbackBuffers.size(); +} + +void State::setCopyReadBufferBinding(Buffer *buffer) +{ + mCopyReadBuffer.set(buffer); +} + +void State::setCopyWriteBufferBinding(Buffer *buffer) +{ + mCopyWriteBuffer.set(buffer); +} + +void State::setPixelPackBufferBinding(Buffer *buffer) +{ + mPack.pixelBuffer.set(buffer); +} + +void State::setPixelUnpackBufferBinding(Buffer *buffer) +{ + mUnpack.pixelBuffer.set(buffer); +} + +Buffer *State::getTargetBuffer(GLenum target) const +{ + switch (target) + { + case GL_ARRAY_BUFFER: return mArrayBuffer.get(); + case GL_COPY_READ_BUFFER: return mCopyReadBuffer.get(); + case GL_COPY_WRITE_BUFFER: return mCopyWriteBuffer.get(); + case GL_ELEMENT_ARRAY_BUFFER: return getVertexArray()->getElementArrayBuffer(); + case GL_PIXEL_PACK_BUFFER: return mPack.pixelBuffer.get(); + case GL_PIXEL_UNPACK_BUFFER: return mUnpack.pixelBuffer.get(); + case GL_TRANSFORM_FEEDBACK_BUFFER: return mGenericTransformFeedbackBuffer.get(); + case GL_UNIFORM_BUFFER: return mGenericUniformBuffer.get(); + default: UNREACHABLE(); return NULL; + } +} + +void State::setEnableVertexAttribArray(unsigned int attribNum, bool enabled) +{ + getVertexArray()->enableAttribute(attribNum, enabled); +} + +void State::setVertexAttribf(GLuint index, const GLfloat values[4]) +{ + ASSERT(static_cast(index) < mVertexAttribCurrentValues.size()); + mVertexAttribCurrentValues[index].setFloatValues(values); +} + +void State::setVertexAttribu(GLuint index, const GLuint values[4]) +{ + ASSERT(static_cast(index) < mVertexAttribCurrentValues.size()); + mVertexAttribCurrentValues[index].setUnsignedIntValues(values); +} + +void State::setVertexAttribi(GLuint index, const GLint values[4]) +{ + ASSERT(static_cast(index) < mVertexAttribCurrentValues.size()); + mVertexAttribCurrentValues[index].setIntValues(values); +} + +void State::setVertexAttribState(unsigned int attribNum, Buffer *boundBuffer, GLint size, GLenum type, bool normalized, + bool pureInteger, GLsizei stride, const void *pointer) +{ + getVertexArray()->setAttributeState(attribNum, boundBuffer, size, type, normalized, pureInteger, stride, pointer); +} + +const VertexAttribCurrentValueData &State::getVertexAttribCurrentValue(unsigned int attribNum) const +{ + ASSERT(static_cast(attribNum) < mVertexAttribCurrentValues.size()); + return mVertexAttribCurrentValues[attribNum]; +} + +const void *State::getVertexAttribPointer(unsigned int attribNum) const +{ + return getVertexArray()->getVertexAttribute(attribNum).pointer; +} + +void State::setPackAlignment(GLint alignment) +{ + mPack.alignment = alignment; +} + +GLint State::getPackAlignment() const +{ + return mPack.alignment; +} + +void State::setPackReverseRowOrder(bool reverseRowOrder) +{ + mPack.reverseRowOrder = reverseRowOrder; +} + +bool State::getPackReverseRowOrder() const +{ + return mPack.reverseRowOrder; +} + +const PixelPackState &State::getPackState() const +{ + return mPack; +} + +PixelPackState &State::getPackState() +{ + return mPack; +} + +void State::setUnpackAlignment(GLint alignment) +{ + mUnpack.alignment = alignment; +} + +GLint State::getUnpackAlignment() const +{ + return mUnpack.alignment; +} + +void State::setUnpackRowLength(GLint rowLength) +{ + mUnpack.rowLength = rowLength; +} + +GLint State::getUnpackRowLength() const +{ + return mUnpack.rowLength; +} + +const PixelUnpackState &State::getUnpackState() const +{ + return mUnpack; +} + +PixelUnpackState &State::getUnpackState() +{ + return mUnpack; +} + +void State::getBooleanv(GLenum pname, GLboolean *params) +{ + switch (pname) + { + case GL_SAMPLE_COVERAGE_INVERT: *params = mSampleCoverageInvert; break; + case GL_DEPTH_WRITEMASK: *params = mDepthStencil.depthMask; break; + case GL_COLOR_WRITEMASK: + params[0] = mBlend.colorMaskRed; + params[1] = mBlend.colorMaskGreen; + params[2] = mBlend.colorMaskBlue; + params[3] = mBlend.colorMaskAlpha; + break; + case GL_CULL_FACE: *params = mRasterizer.cullFace; break; + case GL_POLYGON_OFFSET_FILL: *params = mRasterizer.polygonOffsetFill; break; + case GL_SAMPLE_ALPHA_TO_COVERAGE: *params = mBlend.sampleAlphaToCoverage; break; + case GL_SAMPLE_COVERAGE: *params = mSampleCoverage; break; + case GL_SCISSOR_TEST: *params = mScissorTest; break; + case GL_STENCIL_TEST: *params = mDepthStencil.stencilTest; break; + case GL_DEPTH_TEST: *params = mDepthStencil.depthTest; break; + case GL_BLEND: *params = mBlend.blend; break; + case GL_DITHER: *params = mBlend.dither; break; + case GL_TRANSFORM_FEEDBACK_ACTIVE: *params = getCurrentTransformFeedback()->isStarted(); break; + case GL_TRANSFORM_FEEDBACK_PAUSED: *params = getCurrentTransformFeedback()->isPaused(); break; + default: + UNREACHABLE(); + break; + } +} + +void State::getFloatv(GLenum pname, GLfloat *params) +{ + // Please note: DEPTH_CLEAR_VALUE is included in our internal getFloatv implementation + // because it is stored as a float, despite the fact that the GL ES 2.0 spec names + // GetIntegerv as its native query function. As it would require conversion in any + // case, this should make no difference to the calling application. + switch (pname) + { + case GL_LINE_WIDTH: *params = mLineWidth; break; + case GL_SAMPLE_COVERAGE_VALUE: *params = mSampleCoverageValue; break; + case GL_DEPTH_CLEAR_VALUE: *params = mDepthClearValue; break; + case GL_POLYGON_OFFSET_FACTOR: *params = mRasterizer.polygonOffsetFactor; break; + case GL_POLYGON_OFFSET_UNITS: *params = mRasterizer.polygonOffsetUnits; break; + case GL_DEPTH_RANGE: + params[0] = mNearZ; + params[1] = mFarZ; + break; + case GL_COLOR_CLEAR_VALUE: + params[0] = mColorClearValue.red; + params[1] = mColorClearValue.green; + params[2] = mColorClearValue.blue; + params[3] = mColorClearValue.alpha; + break; + case GL_BLEND_COLOR: + params[0] = mBlendColor.red; + params[1] = mBlendColor.green; + params[2] = mBlendColor.blue; + params[3] = mBlendColor.alpha; + break; + default: + UNREACHABLE(); + break; + } +} + +void State::getIntegerv(const gl::Data &data, GLenum pname, GLint *params) +{ + if (pname >= GL_DRAW_BUFFER0_EXT && pname <= GL_DRAW_BUFFER15_EXT) + { + unsigned int colorAttachment = (pname - GL_DRAW_BUFFER0_EXT); + ASSERT(colorAttachment < mMaxDrawBuffers); + Framebuffer *framebuffer = mDrawFramebuffer; + *params = framebuffer->getDrawBufferState(colorAttachment); + return; + } + + // Please note: DEPTH_CLEAR_VALUE is not included in our internal getIntegerv implementation + // because it is stored as a float, despite the fact that the GL ES 2.0 spec names + // GetIntegerv as its native query function. As it would require conversion in any + // case, this should make no difference to the calling application. You may find it in + // State::getFloatv. + switch (pname) + { + case GL_ARRAY_BUFFER_BINDING: *params = mArrayBuffer.id(); break; + case GL_ELEMENT_ARRAY_BUFFER_BINDING: *params = getVertexArray()->getElementArrayBufferId(); break; + //case GL_FRAMEBUFFER_BINDING: // now equivalent to GL_DRAW_FRAMEBUFFER_BINDING_ANGLE + case GL_DRAW_FRAMEBUFFER_BINDING_ANGLE: *params = mDrawFramebuffer->id(); break; + case GL_READ_FRAMEBUFFER_BINDING_ANGLE: *params = mReadFramebuffer->id(); break; + case GL_RENDERBUFFER_BINDING: *params = mRenderbuffer.id(); break; + case GL_VERTEX_ARRAY_BINDING: *params = mVertexArray->id(); break; + case GL_CURRENT_PROGRAM: *params = mProgram ? mProgram->id() : 0; break; + case GL_PACK_ALIGNMENT: *params = mPack.alignment; break; + case GL_PACK_REVERSE_ROW_ORDER_ANGLE: *params = mPack.reverseRowOrder; break; + case GL_UNPACK_ALIGNMENT: *params = mUnpack.alignment; break; + case GL_UNPACK_ROW_LENGTH: *params = mUnpack.rowLength; break; + case GL_GENERATE_MIPMAP_HINT: *params = mGenerateMipmapHint; break; + case GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES: *params = mFragmentShaderDerivativeHint; break; + case GL_ACTIVE_TEXTURE: *params = (mActiveSampler + GL_TEXTURE0); break; + case GL_STENCIL_FUNC: *params = mDepthStencil.stencilFunc; break; + case GL_STENCIL_REF: *params = mStencilRef; break; + case GL_STENCIL_VALUE_MASK: *params = clampToInt(mDepthStencil.stencilMask); break; + case GL_STENCIL_BACK_FUNC: *params = mDepthStencil.stencilBackFunc; break; + case GL_STENCIL_BACK_REF: *params = mStencilBackRef; break; + case GL_STENCIL_BACK_VALUE_MASK: *params = clampToInt(mDepthStencil.stencilBackMask); break; + case GL_STENCIL_FAIL: *params = mDepthStencil.stencilFail; break; + case GL_STENCIL_PASS_DEPTH_FAIL: *params = mDepthStencil.stencilPassDepthFail; break; + case GL_STENCIL_PASS_DEPTH_PASS: *params = mDepthStencil.stencilPassDepthPass; break; + case GL_STENCIL_BACK_FAIL: *params = mDepthStencil.stencilBackFail; break; + case GL_STENCIL_BACK_PASS_DEPTH_FAIL: *params = mDepthStencil.stencilBackPassDepthFail; break; + case GL_STENCIL_BACK_PASS_DEPTH_PASS: *params = mDepthStencil.stencilBackPassDepthPass; break; + case GL_DEPTH_FUNC: *params = mDepthStencil.depthFunc; break; + case GL_BLEND_SRC_RGB: *params = mBlend.sourceBlendRGB; break; + case GL_BLEND_SRC_ALPHA: *params = mBlend.sourceBlendAlpha; break; + case GL_BLEND_DST_RGB: *params = mBlend.destBlendRGB; break; + case GL_BLEND_DST_ALPHA: *params = mBlend.destBlendAlpha; break; + case GL_BLEND_EQUATION_RGB: *params = mBlend.blendEquationRGB; break; + case GL_BLEND_EQUATION_ALPHA: *params = mBlend.blendEquationAlpha; break; + case GL_STENCIL_WRITEMASK: *params = clampToInt(mDepthStencil.stencilWritemask); break; + case GL_STENCIL_BACK_WRITEMASK: *params = clampToInt(mDepthStencil.stencilBackWritemask); break; + case GL_STENCIL_CLEAR_VALUE: *params = mStencilClearValue; break; + case GL_IMPLEMENTATION_COLOR_READ_TYPE: *params = mReadFramebuffer->getImplementationColorReadType(); break; + case GL_IMPLEMENTATION_COLOR_READ_FORMAT: *params = mReadFramebuffer->getImplementationColorReadFormat(); break; + case GL_SAMPLE_BUFFERS: + case GL_SAMPLES: + { + gl::Framebuffer *framebuffer = mDrawFramebuffer; + if (framebuffer->checkStatus(data) == GL_FRAMEBUFFER_COMPLETE) + { + switch (pname) + { + case GL_SAMPLE_BUFFERS: + if (framebuffer->getSamples(data) != 0) + { + *params = 1; + } + else + { + *params = 0; + } + break; + case GL_SAMPLES: + *params = framebuffer->getSamples(data); + break; + } + } + else + { + *params = 0; + } + } + break; + case GL_VIEWPORT: + params[0] = mViewport.x; + params[1] = mViewport.y; + params[2] = mViewport.width; + params[3] = mViewport.height; + break; + case GL_SCISSOR_BOX: + params[0] = mScissor.x; + params[1] = mScissor.y; + params[2] = mScissor.width; + params[3] = mScissor.height; + break; + case GL_CULL_FACE_MODE: *params = mRasterizer.cullMode; break; + case GL_FRONT_FACE: *params = mRasterizer.frontFace; break; + case GL_RED_BITS: + case GL_GREEN_BITS: + case GL_BLUE_BITS: + case GL_ALPHA_BITS: + { + gl::Framebuffer *framebuffer = getDrawFramebuffer(); + gl::FramebufferAttachment *colorbuffer = framebuffer->getFirstColorbuffer(); + + if (colorbuffer) + { + switch (pname) + { + case GL_RED_BITS: *params = colorbuffer->getRedSize(); break; + case GL_GREEN_BITS: *params = colorbuffer->getGreenSize(); break; + case GL_BLUE_BITS: *params = colorbuffer->getBlueSize(); break; + case GL_ALPHA_BITS: *params = colorbuffer->getAlphaSize(); break; + } + } + else + { + *params = 0; + } + } + break; + case GL_DEPTH_BITS: + { + gl::Framebuffer *framebuffer = getDrawFramebuffer(); + gl::FramebufferAttachment *depthbuffer = framebuffer->getDepthbuffer(); + + if (depthbuffer) + { + *params = depthbuffer->getDepthSize(); + } + else + { + *params = 0; + } + } + break; + case GL_STENCIL_BITS: + { + gl::Framebuffer *framebuffer = getDrawFramebuffer(); + gl::FramebufferAttachment *stencilbuffer = framebuffer->getStencilbuffer(); + + if (stencilbuffer) + { + *params = stencilbuffer->getStencilSize(); + } + else + { + *params = 0; + } + } + break; + case GL_TEXTURE_BINDING_2D: + ASSERT(mActiveSampler < mMaxCombinedTextureImageUnits); + *params = getSamplerTextureId(mActiveSampler, GL_TEXTURE_2D) ; + break; + case GL_TEXTURE_BINDING_CUBE_MAP: + ASSERT(mActiveSampler < mMaxCombinedTextureImageUnits); + *params = getSamplerTextureId(mActiveSampler, GL_TEXTURE_CUBE_MAP); + break; + case GL_TEXTURE_BINDING_3D: + ASSERT(mActiveSampler < mMaxCombinedTextureImageUnits); + *params = getSamplerTextureId(mActiveSampler, GL_TEXTURE_3D); + break; + case GL_TEXTURE_BINDING_2D_ARRAY: + ASSERT(mActiveSampler < mMaxCombinedTextureImageUnits); + *params = getSamplerTextureId(mActiveSampler, GL_TEXTURE_2D_ARRAY); + break; + case GL_UNIFORM_BUFFER_BINDING: + *params = mGenericUniformBuffer.id(); + break; + case GL_TRANSFORM_FEEDBACK_BUFFER_BINDING: + *params = mGenericTransformFeedbackBuffer.id(); + break; + case GL_COPY_READ_BUFFER_BINDING: + *params = mCopyReadBuffer.id(); + break; + case GL_COPY_WRITE_BUFFER_BINDING: + *params = mCopyWriteBuffer.id(); + break; + case GL_PIXEL_PACK_BUFFER_BINDING: + *params = mPack.pixelBuffer.id(); + break; + case GL_PIXEL_UNPACK_BUFFER_BINDING: + *params = mUnpack.pixelBuffer.id(); + break; + default: + UNREACHABLE(); + break; + } +} + +bool State::getIndexedIntegerv(GLenum target, GLuint index, GLint *data) +{ + switch (target) + { + case GL_TRANSFORM_FEEDBACK_BUFFER_BINDING: + if (static_cast(index) < mTransformFeedbackBuffers.size()) + { + *data = mTransformFeedbackBuffers[index].id(); + } + break; + case GL_UNIFORM_BUFFER_BINDING: + if (static_cast(index) < mUniformBuffers.size()) + { + *data = mUniformBuffers[index].id(); + } + break; + default: + return false; + } + + return true; +} + +bool State::getIndexedInteger64v(GLenum target, GLuint index, GLint64 *data) +{ + switch (target) + { + case GL_TRANSFORM_FEEDBACK_BUFFER_START: + if (static_cast(index) < mTransformFeedbackBuffers.size()) + { + *data = mTransformFeedbackBuffers[index].getOffset(); + } + break; + case GL_TRANSFORM_FEEDBACK_BUFFER_SIZE: + if (static_cast(index) < mTransformFeedbackBuffers.size()) + { + *data = mTransformFeedbackBuffers[index].getSize(); + } + break; + case GL_UNIFORM_BUFFER_START: + if (static_cast(index) < mUniformBuffers.size()) + { + *data = mUniformBuffers[index].getOffset(); + } + break; + case GL_UNIFORM_BUFFER_SIZE: + if (static_cast(index) < mUniformBuffers.size()) + { + *data = mUniformBuffers[index].getSize(); + } + break; + default: + return false; + } + + return true; +} + +bool State::hasMappedBuffer(GLenum target) const +{ + if (target == GL_ARRAY_BUFFER) + { + const VertexArray *vao = getVertexArray(); + for (size_t attribIndex = 0; attribIndex < mVertexAttribCurrentValues.size(); attribIndex++) + { + const gl::VertexAttribute &vertexAttrib = vao->getVertexAttribute(attribIndex); + gl::Buffer *boundBuffer = vertexAttrib.buffer.get(); + if (vertexAttrib.enabled && boundBuffer && boundBuffer->isMapped()) + { + return true; + } + } + + return false; + } + else + { + Buffer *buffer = getTargetBuffer(target); + return (buffer && buffer->isMapped()); + } +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/State.h b/src/3rdparty/angle/src/libANGLE/State.h new file mode 100644 index 0000000000..4370a2f16f --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/State.h @@ -0,0 +1,335 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// State.h: Defines the State class, encapsulating raw GL state + +#ifndef LIBANGLE_STATE_H_ +#define LIBANGLE_STATE_H_ + +#include "common/angleutils.h" +#include "libANGLE/RefCountObject.h" +#include "libANGLE/angletypes.h" +#include "libANGLE/VertexAttribute.h" +#include "libANGLE/Renderbuffer.h" +#include "libANGLE/Texture.h" +#include "libANGLE/TransformFeedback.h" +#include "libANGLE/Program.h" +#include "libANGLE/Sampler.h" + +namespace gl +{ +class Query; +class VertexArray; +class Context; +struct Caps; +struct Data; + +typedef std::map< GLenum, BindingPointer > TextureMap; + +class State : angle::NonCopyable +{ + public: + State(); + ~State(); + + void initialize(const Caps& caps, GLuint clientVersion); + void reset(); + + // State chunk getters + const RasterizerState &getRasterizerState() const; + const BlendState &getBlendState() const; + const DepthStencilState &getDepthStencilState() const; + + // Clear behavior setters & state parameter block generation function + void setColorClearValue(float red, float green, float blue, float alpha); + void setDepthClearValue(float depth); + void setStencilClearValue(int stencil); + + const ColorF &getColorClearValue() const { return mColorClearValue; } + float getDepthClearValue() const { return mDepthClearValue; } + int getStencilClearValue() const { return mStencilClearValue; } + + // Write mask manipulation + void setColorMask(bool red, bool green, bool blue, bool alpha); + void setDepthMask(bool mask); + + // Discard toggle & query + bool isRasterizerDiscardEnabled() const; + void setRasterizerDiscard(bool enabled); + + // Primitive restart + bool isPrimitiveRestartEnabled() const; + void setPrimitiveRestart(bool enabled); + + // Face culling state manipulation + bool isCullFaceEnabled() const; + void setCullFace(bool enabled); + void setCullMode(GLenum mode); + void setFrontFace(GLenum front); + + // Depth test state manipulation + bool isDepthTestEnabled() const; + void setDepthTest(bool enabled); + void setDepthFunc(GLenum depthFunc); + void setDepthRange(float zNear, float zFar); + void getDepthRange(float *zNear, float *zFar) const; + + // Blend state manipulation + bool isBlendEnabled() const; + void setBlend(bool enabled); + void setBlendFactors(GLenum sourceRGB, GLenum destRGB, GLenum sourceAlpha, GLenum destAlpha); + void setBlendColor(float red, float green, float blue, float alpha); + void setBlendEquation(GLenum rgbEquation, GLenum alphaEquation); + const ColorF &getBlendColor() const; + + // Stencil state maniupulation + bool isStencilTestEnabled() const; + void setStencilTest(bool enabled); + void setStencilParams(GLenum stencilFunc, GLint stencilRef, GLuint stencilMask); + void setStencilBackParams(GLenum stencilBackFunc, GLint stencilBackRef, GLuint stencilBackMask); + void setStencilWritemask(GLuint stencilWritemask); + void setStencilBackWritemask(GLuint stencilBackWritemask); + void setStencilOperations(GLenum stencilFail, GLenum stencilPassDepthFail, GLenum stencilPassDepthPass); + void setStencilBackOperations(GLenum stencilBackFail, GLenum stencilBackPassDepthFail, GLenum stencilBackPassDepthPass); + GLint getStencilRef() const; + GLint getStencilBackRef() const; + + // Depth bias/polygon offset state manipulation + bool isPolygonOffsetFillEnabled() const; + void setPolygonOffsetFill(bool enabled); + void setPolygonOffsetParams(GLfloat factor, GLfloat units); + + // Multisample coverage state manipulation + bool isSampleAlphaToCoverageEnabled() const; + void setSampleAlphaToCoverage(bool enabled); + bool isSampleCoverageEnabled() const; + void setSampleCoverage(bool enabled); + void setSampleCoverageParams(GLclampf value, bool invert); + void getSampleCoverageParams(GLclampf *value, bool *invert) const; + + // Scissor test state toggle & query + bool isScissorTestEnabled() const; + void setScissorTest(bool enabled); + void setScissorParams(GLint x, GLint y, GLsizei width, GLsizei height); + const Rectangle &getScissor() const; + + // Dither state toggle & query + bool isDitherEnabled() const; + void setDither(bool enabled); + + // Generic state toggle & query + void setEnableFeature(GLenum feature, bool enabled); + bool getEnableFeature(GLenum feature); + + // Line width state setter + void setLineWidth(GLfloat width); + + // Hint setters + void setGenerateMipmapHint(GLenum hint); + void setFragmentShaderDerivativeHint(GLenum hint); + + // Viewport state setter/getter + void setViewportParams(GLint x, GLint y, GLsizei width, GLsizei height); + const Rectangle &getViewport() const; + + // Texture binding & active texture unit manipulation + void setActiveSampler(unsigned int active); + unsigned int getActiveSampler() const; + void setSamplerTexture(GLenum type, Texture *texture); + Texture *getSamplerTexture(unsigned int sampler, GLenum type) const; + GLuint getSamplerTextureId(unsigned int sampler, GLenum type) const; + void detachTexture(const TextureMap &zeroTextures, GLuint texture); + void initializeZeroTextures(const TextureMap &zeroTextures); + + // Sampler object binding manipulation + void setSamplerBinding(GLuint textureUnit, Sampler *sampler); + GLuint getSamplerId(GLuint textureUnit) const; + Sampler *getSampler(GLuint textureUnit) const; + void detachSampler(GLuint sampler); + + // Renderbuffer binding manipulation + void setRenderbufferBinding(Renderbuffer *renderbuffer); + GLuint getRenderbufferId() const; + Renderbuffer *getCurrentRenderbuffer(); + void detachRenderbuffer(GLuint renderbuffer); + + // Framebuffer binding manipulation + void setReadFramebufferBinding(Framebuffer *framebuffer); + void setDrawFramebufferBinding(Framebuffer *framebuffer); + Framebuffer *getTargetFramebuffer(GLenum target) const; + Framebuffer *getReadFramebuffer(); + Framebuffer *getDrawFramebuffer(); + const Framebuffer *getReadFramebuffer() const; + const Framebuffer *getDrawFramebuffer() const; + bool removeReadFramebufferBinding(GLuint framebuffer); + bool removeDrawFramebufferBinding(GLuint framebuffer); + + // Vertex array object binding manipulation + void setVertexArrayBinding(VertexArray *vertexArray); + GLuint getVertexArrayId() const; + VertexArray *getVertexArray() const; + bool removeVertexArrayBinding(GLuint vertexArray); + + // Program binding manipulation + void setProgram(Program *newProgram); + Program *getProgram() const; + + // Transform feedback object (not buffer) binding manipulation + void setTransformFeedbackBinding(TransformFeedback *transformFeedback); + TransformFeedback *getCurrentTransformFeedback() const; + bool isTransformFeedbackActiveUnpaused() const; + void detachTransformFeedback(GLuint transformFeedback); + + // Query binding manipulation + bool isQueryActive() const; + void setActiveQuery(GLenum target, Query *query); + GLuint getActiveQueryId(GLenum target) const; + Query *getActiveQuery(GLenum target) const; + + //// Typed buffer binding point manipulation //// + // GL_ARRAY_BUFFER + void setArrayBufferBinding(Buffer *buffer); + GLuint getArrayBufferId() const; + bool removeArrayBufferBinding(GLuint buffer); + + // GL_UNIFORM_BUFFER - Both indexed and generic targets + void setGenericUniformBufferBinding(Buffer *buffer); + void setIndexedUniformBufferBinding(GLuint index, Buffer *buffer, GLintptr offset, GLsizeiptr size); + GLuint getIndexedUniformBufferId(GLuint index) const; + Buffer *getIndexedUniformBuffer(GLuint index) const; + GLintptr getIndexedUniformBufferOffset(GLuint index) const; + GLsizeiptr getIndexedUniformBufferSize(GLuint index) const; + + // GL_TRANSFORM_FEEDBACK_BUFFER - Both indexed and generic targets + void setGenericTransformFeedbackBufferBinding(Buffer *buffer); + void setIndexedTransformFeedbackBufferBinding(GLuint index, Buffer *buffer, GLintptr offset, GLsizeiptr size); + GLuint getIndexedTransformFeedbackBufferId(GLuint index) const; + Buffer *getIndexedTransformFeedbackBuffer(GLuint index) const; + GLuint getIndexedTransformFeedbackBufferOffset(GLuint index) const; + size_t getTransformFeedbackBufferIndexRange() const; + + // GL_COPY_[READ/WRITE]_BUFFER + void setCopyReadBufferBinding(Buffer *buffer); + void setCopyWriteBufferBinding(Buffer *buffer); + + // GL_PIXEL[PACK/UNPACK]_BUFFER + void setPixelPackBufferBinding(Buffer *buffer); + void setPixelUnpackBufferBinding(Buffer *buffer); + + // Retrieve typed buffer by target (non-indexed) + Buffer *getTargetBuffer(GLenum target) const; + + // Vertex attrib manipulation + void setEnableVertexAttribArray(unsigned int attribNum, bool enabled); + void setVertexAttribf(GLuint index, const GLfloat values[4]); + void setVertexAttribu(GLuint index, const GLuint values[4]); + void setVertexAttribi(GLuint index, const GLint values[4]); + void setVertexAttribState(unsigned int attribNum, Buffer *boundBuffer, GLint size, GLenum type, + bool normalized, bool pureInteger, GLsizei stride, const void *pointer); + const VertexAttribCurrentValueData &getVertexAttribCurrentValue(unsigned int attribNum) const; + const void *getVertexAttribPointer(unsigned int attribNum) const; + + // Pixel pack state manipulation + void setPackAlignment(GLint alignment); + GLint getPackAlignment() const; + void setPackReverseRowOrder(bool reverseRowOrder); + bool getPackReverseRowOrder() const; + const PixelPackState &getPackState() const; + PixelPackState &getPackState(); + + // Pixel unpack state manipulation + void setUnpackAlignment(GLint alignment); + GLint getUnpackAlignment() const; + void setUnpackRowLength(GLint rowLength); + GLint getUnpackRowLength() const; + const PixelUnpackState &getUnpackState() const; + PixelUnpackState &getUnpackState(); + + // State query functions + void getBooleanv(GLenum pname, GLboolean *params); + void getFloatv(GLenum pname, GLfloat *params); + void getIntegerv(const gl::Data &data, GLenum pname, GLint *params); + bool getIndexedIntegerv(GLenum target, GLuint index, GLint *data); + bool getIndexedInteger64v(GLenum target, GLuint index, GLint64 *data); + + bool hasMappedBuffer(GLenum target) const; + + private: + // Cached values from Context's caps + GLuint mMaxDrawBuffers; + GLuint mMaxCombinedTextureImageUnits; + + ColorF mColorClearValue; + GLclampf mDepthClearValue; + int mStencilClearValue; + + RasterizerState mRasterizer; + bool mScissorTest; + Rectangle mScissor; + + BlendState mBlend; + ColorF mBlendColor; + bool mSampleCoverage; + GLclampf mSampleCoverageValue; + bool mSampleCoverageInvert; + + DepthStencilState mDepthStencil; + GLint mStencilRef; + GLint mStencilBackRef; + + GLfloat mLineWidth; + + GLenum mGenerateMipmapHint; + GLenum mFragmentShaderDerivativeHint; + + Rectangle mViewport; + float mNearZ; + float mFarZ; + + BindingPointer mArrayBuffer; + Framebuffer *mReadFramebuffer; + Framebuffer *mDrawFramebuffer; + BindingPointer mRenderbuffer; + Program *mProgram; + + typedef std::vector VertexAttribVector; + VertexAttribVector mVertexAttribCurrentValues; // From glVertexAttrib + VertexArray *mVertexArray; + + // Texture and sampler bindings + size_t mActiveSampler; // Active texture unit selector - GL_TEXTURE0 + + typedef std::vector< BindingPointer > TextureBindingVector; + typedef std::map TextureBindingMap; + TextureBindingMap mSamplerTextures; + + typedef std::vector< BindingPointer > SamplerBindingVector; + SamplerBindingVector mSamplers; + + typedef std::map< GLenum, BindingPointer > ActiveQueryMap; + ActiveQueryMap mActiveQueries; + + BindingPointer mGenericUniformBuffer; + typedef std::vector< OffsetBindingPointer > BufferVector; + BufferVector mUniformBuffers; + + BindingPointer mTransformFeedback; + BindingPointer mGenericTransformFeedbackBuffer; + BufferVector mTransformFeedbackBuffers; + + BindingPointer mCopyReadBuffer; + BindingPointer mCopyWriteBuffer; + + PixelUnpackState mUnpack; + PixelPackState mPack; + + bool mPrimitiveRestart; +}; + +} + +#endif // LIBANGLE_STATE_H_ + diff --git a/src/3rdparty/angle/src/libANGLE/Surface.cpp b/src/3rdparty/angle/src/libANGLE/Surface.cpp new file mode 100644 index 0000000000..ac455f3905 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/Surface.cpp @@ -0,0 +1,166 @@ +// +// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Surface.cpp: Implements the egl::Surface class, representing a drawing surface +// such as the client area of a window, including any back buffers. +// Implements EGLSurface and related functionality. [EGL 1.4] section 2.2 page 3. + +#include "libANGLE/Surface.h" + +#include "libANGLE/Config.h" +#include "libANGLE/Texture.h" +#include "libANGLE/renderer/SurfaceImpl.h" + +#include + +namespace egl +{ + +Surface::Surface(rx::SurfaceImpl *impl, EGLint surfaceType, const egl::Config *config, const AttributeMap &attributes) + : RefCountObject(0), // id unused + mImplementation(impl), + mType(surfaceType), + mConfig(config), + mPostSubBufferRequested(false), + mFixedSize(false), + mFixedWidth(0), + mFixedHeight(0), + mTextureFormat(EGL_NO_TEXTURE), + mTextureTarget(EGL_NO_TEXTURE), + // FIXME: Determine actual pixel aspect ratio + mPixelAspectRatio(static_cast(1.0 * EGL_DISPLAY_SCALING)), + mRenderBuffer(EGL_BACK_BUFFER), + mSwapBehavior(EGL_BUFFER_PRESERVED), + mTexture(NULL) +{ + addRef(); + + mPostSubBufferRequested = (attributes.get(EGL_POST_SUB_BUFFER_SUPPORTED_NV, EGL_FALSE) == EGL_TRUE); + + mFixedSize = (attributes.get(EGL_FIXED_SIZE_ANGLE, EGL_FALSE) == EGL_TRUE); + if (mFixedSize) + { + mFixedWidth = attributes.get(EGL_WIDTH, 0); + mFixedHeight = attributes.get(EGL_HEIGHT, 0); + } + + if (mType != EGL_WINDOW_BIT) + { + mTextureFormat = attributes.get(EGL_TEXTURE_FORMAT, EGL_NO_TEXTURE); + mTextureTarget = attributes.get(EGL_TEXTURE_TARGET, EGL_NO_TEXTURE); + } +} + +Surface::~Surface() +{ + if (mTexture) + { + if (mImplementation) + { + mImplementation->releaseTexImage(mTexture->id()); + } + mTexture->releaseTexImage(); + mTexture = NULL; + } + + SafeDelete(mImplementation); +} + +EGLint Surface::getType() const +{ + return mType; +} + +Error Surface::swap() +{ + return mImplementation->swap(); +} + +Error Surface::postSubBuffer(EGLint x, EGLint y, EGLint width, EGLint height) +{ + return mImplementation->postSubBuffer(x, y, width, height); +} + +Error Surface::querySurfacePointerANGLE(EGLint attribute, void **value) +{ + return mImplementation->querySurfacePointerANGLE(attribute, value); +} + +EGLint Surface::isPostSubBufferSupported() const +{ + return mPostSubBufferRequested && mImplementation->isPostSubBufferSupported(); +} + +void Surface::setSwapInterval(EGLint interval) +{ + mImplementation->setSwapInterval(interval); +} + +const Config *Surface::getConfig() const +{ + return mConfig; +} + +EGLint Surface::getPixelAspectRatio() const +{ + return mPixelAspectRatio; +} + +EGLenum Surface::getRenderBuffer() const +{ + return mRenderBuffer; +} + +EGLenum Surface::getSwapBehavior() const +{ + return mSwapBehavior; +} + +EGLenum Surface::getTextureFormat() const +{ + return mTextureFormat; +} + +EGLenum Surface::getTextureTarget() const +{ + return mTextureTarget; +} + +EGLint Surface::isFixedSize() const +{ + return mFixedSize; +} + +EGLint Surface::getWidth() const +{ + return mFixedSize ? mFixedWidth : mImplementation->getWidth(); +} + +EGLint Surface::getHeight() const +{ + return mFixedSize ? mFixedHeight : mImplementation->getHeight(); +} + +Error Surface::bindTexImage(gl::Texture *texture, EGLint buffer) +{ + ASSERT(!mTexture); + + texture->bindTexImage(this); + mTexture = texture; + return mImplementation->bindTexImage(buffer); +} + +Error Surface::releaseTexImage(EGLint buffer) +{ + ASSERT(mTexture); + gl::Texture *boundTexture = mTexture; + mTexture = NULL; + + boundTexture->releaseTexImage(); + return mImplementation->releaseTexImage(buffer); +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/Surface.h b/src/3rdparty/angle/src/libANGLE/Surface.h new file mode 100644 index 0000000000..430bf0195d --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/Surface.h @@ -0,0 +1,98 @@ +// +// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Surface.h: Defines the egl::Surface class, representing a drawing surface +// such as the client area of a window, including any back buffers. +// Implements EGLSurface and related functionality. [EGL 1.4] section 2.2 page 3. + +#ifndef LIBANGLE_SURFACE_H_ +#define LIBANGLE_SURFACE_H_ + +#include + +#include "common/angleutils.h" +#include "libANGLE/Error.h" +#include "libANGLE/RefCountObject.h" + +namespace gl +{ +class Texture; +} + +namespace rx +{ +class SurfaceImpl; +} + +namespace egl +{ +class AttributeMap; +class Display; +struct Config; + +class Surface final : public RefCountObject +{ + public: + Surface(rx::SurfaceImpl *impl, EGLint surfaceType, const egl::Config *config, const AttributeMap &attributes); + + rx::SurfaceImpl *getImplementation() { return mImplementation; } + const rx::SurfaceImpl *getImplementation() const { return mImplementation; } + + EGLint getType() const; + + Error swap(); + Error postSubBuffer(EGLint x, EGLint y, EGLint width, EGLint height); + Error querySurfacePointerANGLE(EGLint attribute, void **value); + Error bindTexImage(gl::Texture *texture, EGLint buffer); + Error releaseTexImage(EGLint buffer); + + EGLint isPostSubBufferSupported() const; + + void setSwapInterval(EGLint interval); + + const Config *getConfig() const; + + // width and height can change with client window resizing + EGLint getWidth() const; + EGLint getHeight() const; + EGLint getPixelAspectRatio() const; + EGLenum getRenderBuffer() const; + EGLenum getSwapBehavior() const; + EGLenum getTextureFormat() const; + EGLenum getTextureTarget() const; + + gl::Texture *getBoundTexture() const { return mTexture; } + + EGLint isFixedSize() const; + + private: + virtual ~Surface(); + + rx::SurfaceImpl *mImplementation; + + EGLint mType; + + const egl::Config *mConfig; + + bool mPostSubBufferRequested; + + bool mFixedSize; + size_t mFixedWidth; + size_t mFixedHeight; + + EGLenum mTextureFormat; + EGLenum mTextureTarget; + + EGLint mPixelAspectRatio; // Display aspect ratio + EGLenum mRenderBuffer; // Render buffer + EGLenum mSwapBehavior; // Buffer swap behavior + + gl::Texture *mTexture; +}; + +} + +#endif // LIBANGLE_SURFACE_H_ diff --git a/src/3rdparty/angle/src/libANGLE/Texture.cpp b/src/3rdparty/angle/src/libANGLE/Texture.cpp new file mode 100644 index 0000000000..cd4584f694 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/Texture.cpp @@ -0,0 +1,573 @@ +// +// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Texture.cpp: Implements the gl::Texture class. [OpenGL ES 2.0.24] section 3.7 page 63. + +#include "libANGLE/Texture.h" +#include "libANGLE/Data.h" +#include "libANGLE/formatutils.h" + +#include "libANGLE/Config.h" +#include "libANGLE/Surface.h" + +#include "common/mathutil.h" +#include "common/utilities.h" + +namespace gl +{ + +bool IsMipmapFiltered(const gl::SamplerState &samplerState) +{ + switch (samplerState.minFilter) + { + case GL_NEAREST: + case GL_LINEAR: + return false; + case GL_NEAREST_MIPMAP_NEAREST: + case GL_LINEAR_MIPMAP_NEAREST: + case GL_NEAREST_MIPMAP_LINEAR: + case GL_LINEAR_MIPMAP_LINEAR: + return true; + default: UNREACHABLE(); + return false; + } +} + +bool IsPointSampled(const gl::SamplerState &samplerState) +{ + return (samplerState.magFilter == GL_NEAREST && (samplerState.minFilter == GL_NEAREST || samplerState.minFilter == GL_NEAREST_MIPMAP_NEAREST)); +} + +static size_t GetImageDescIndex(GLenum target, size_t level) +{ + return IsCubeMapTextureTarget(target) ? ((level * 6) + CubeMapTextureTargetToLayerIndex(target)) : level; +} + +unsigned int Texture::mCurrentTextureSerial = 1; + +Texture::Texture(rx::TextureImpl *impl, GLuint id, GLenum target) + : RefCountObject(id), + mTexture(impl), + mTextureSerial(issueTextureSerial()), + mUsage(GL_NONE), + mImmutableLevelCount(0), + mTarget(target), + mImageDescs(IMPLEMENTATION_MAX_TEXTURE_LEVELS * (target == GL_TEXTURE_CUBE_MAP ? 6 : 1)), + mCompletenessCache(), + mBoundSurface(NULL) +{ +} + +Texture::~Texture() +{ + if (mBoundSurface) + { + mBoundSurface->releaseTexImage(EGL_BACK_BUFFER); + mBoundSurface = NULL; + } + SafeDelete(mTexture); +} + +GLenum Texture::getTarget() const +{ + return mTarget; +} + +void Texture::setUsage(GLenum usage) +{ + mUsage = usage; + getImplementation()->setUsage(usage); +} + +GLenum Texture::getUsage() const +{ + return mUsage; +} + +size_t Texture::getWidth(GLenum target, size_t level) const +{ + ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target))); + return getImageDesc(target, level).size.width; +} + +size_t Texture::getHeight(GLenum target, size_t level) const +{ + ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target))); + return getImageDesc(target, level).size.height; +} + +size_t Texture::getDepth(GLenum target, size_t level) const +{ + ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target))); + return getImageDesc(target, level).size.depth; +} + +GLenum Texture::getInternalFormat(GLenum target, size_t level) const +{ + ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target))); + return getImageDesc(target, level).internalFormat; +} + +bool Texture::isSamplerComplete(const SamplerState &samplerState, const Data &data) const +{ + const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), samplerState.baseLevel); + const TextureCaps &textureCaps = data.textureCaps->get(baseImageDesc.internalFormat); + if (!mCompletenessCache.cacheValid || + mCompletenessCache.samplerState != samplerState || + mCompletenessCache.filterable != textureCaps.filterable || + mCompletenessCache.clientVersion != data.clientVersion || + mCompletenessCache.supportsNPOT != data.extensions->textureNPOT) + { + mCompletenessCache.cacheValid = true; + mCompletenessCache.samplerState = samplerState; + mCompletenessCache.filterable = textureCaps.filterable; + mCompletenessCache.clientVersion = data.clientVersion; + mCompletenessCache.supportsNPOT = data.extensions->textureNPOT; + mCompletenessCache.samplerComplete = computeSamplerCompleteness(samplerState, data); + } + return mCompletenessCache.samplerComplete; +} + +// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81. +bool Texture::isCubeComplete() const +{ + ASSERT(mTarget == GL_TEXTURE_CUBE_MAP); + + const ImageDesc &baseImageDesc = getImageDesc(FirstCubeMapTextureTarget, 0); + if (baseImageDesc.size.width == 0 || baseImageDesc.size.width != baseImageDesc.size.height) + { + return false; + } + + for (GLenum face = FirstCubeMapTextureTarget + 1; face <= LastCubeMapTextureTarget; face++) + { + const ImageDesc &faceImageDesc = getImageDesc(face, 0); + if (faceImageDesc.size.width != baseImageDesc.size.width || + faceImageDesc.size.height != baseImageDesc.size.height || + faceImageDesc.internalFormat != baseImageDesc.internalFormat) + { + return false; + } + } + + return true; +} + +unsigned int Texture::getTextureSerial() const +{ + return mTextureSerial; +} + +unsigned int Texture::issueTextureSerial() +{ + return mCurrentTextureSerial++; +} + +bool Texture::isImmutable() const +{ + return (mImmutableLevelCount > 0); +} + +int Texture::immutableLevelCount() +{ + return mImmutableLevelCount; +} + +Error Texture::setImage(GLenum target, size_t level, GLenum internalFormat, const Extents &size, GLenum format, GLenum type, + const PixelUnpackState &unpack, const uint8_t *pixels) +{ + ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target))); + + Error error = mTexture->setImage(target, level, internalFormat, size, format, type, unpack, pixels); + if (error.isError()) + { + return error; + } + + releaseTexImage(); + + setImageDesc(target, level, ImageDesc(size, GetSizedInternalFormat(internalFormat, type))); + + return Error(GL_NO_ERROR); +} + +Error Texture::setSubImage(GLenum target, size_t level, const Box &area, GLenum format, GLenum type, + const PixelUnpackState &unpack, const uint8_t *pixels) +{ + ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target))); + + return mTexture->setSubImage(target, level, area, format, type, unpack, pixels); +} + +Error Texture::setCompressedImage(GLenum target, size_t level, GLenum internalFormat, const Extents &size, + const PixelUnpackState &unpack, const uint8_t *pixels) +{ + ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target))); + + Error error = mTexture->setCompressedImage(target, level, internalFormat, size, unpack, pixels); + if (error.isError()) + { + return error; + } + + releaseTexImage(); + + setImageDesc(target, level, ImageDesc(size, GetSizedInternalFormat(internalFormat, GL_UNSIGNED_BYTE))); + + return Error(GL_NO_ERROR); +} + +Error Texture::setCompressedSubImage(GLenum target, size_t level, const Box &area, GLenum format, + const PixelUnpackState &unpack, const uint8_t *pixels) +{ + ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target))); + + return mTexture->setCompressedSubImage(target, level, area, format, unpack, pixels); +} + +Error Texture::copyImage(GLenum target, size_t level, const Rectangle &sourceArea, GLenum internalFormat, + const Framebuffer *source) +{ + ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target))); + + Error error = mTexture->copyImage(target, level, sourceArea, internalFormat, source); + if (error.isError()) + { + return error; + } + + releaseTexImage(); + + setImageDesc(target, level, ImageDesc(Extents(sourceArea.width, sourceArea.height, 1), + GetSizedInternalFormat(internalFormat, GL_UNSIGNED_BYTE))); + + return Error(GL_NO_ERROR); +} + +Error Texture::copySubImage(GLenum target, size_t level, const Offset &destOffset, const Rectangle &sourceArea, + const Framebuffer *source) +{ + ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target))); + + return mTexture->copySubImage(target, level, destOffset, sourceArea, source); +} + +Error Texture::setStorage(GLenum target, size_t levels, GLenum internalFormat, const Extents &size) +{ + ASSERT(target == mTarget); + + Error error = mTexture->setStorage(target, levels, internalFormat, size); + if (error.isError()) + { + return error; + } + + releaseTexImage(); + + mImmutableLevelCount = levels; + clearImageDescs(); + setImageDescChain(levels, size, internalFormat); + + return Error(GL_NO_ERROR); +} + + +Error Texture::generateMipmaps() +{ + Error error = mTexture->generateMipmaps(); + if (error.isError()) + { + return error; + } + + releaseTexImage(); + + const ImageDesc &baseImageInfo = getImageDesc(getBaseImageTarget(), 0); + size_t mipLevels = log2(std::max(std::max(baseImageInfo.size.width, baseImageInfo.size.height), baseImageInfo.size.depth)) + 1; + setImageDescChain(mipLevels, baseImageInfo.size, baseImageInfo.internalFormat); + + return Error(GL_NO_ERROR); +} + +void Texture::setImageDescChain(size_t levels, Extents baseSize, GLenum sizedInternalFormat) +{ + for (size_t level = 0; level < levels; level++) + { + Extents levelSize(std::max(baseSize.width >> level, 1), + std::max(baseSize.height >> level, 1), + (mTarget == GL_TEXTURE_2D_ARRAY) ? baseSize.depth : std::max(baseSize.depth >> level, 1)); + ImageDesc levelInfo(levelSize, sizedInternalFormat); + + if (mTarget == GL_TEXTURE_CUBE_MAP) + { + for (size_t face = FirstCubeMapTextureTarget; face <= LastCubeMapTextureTarget; face++) + { + setImageDesc(face, level, levelInfo); + } + } + else + { + setImageDesc(mTarget, level, levelInfo); + } + } +} + +Texture::ImageDesc::ImageDesc() + : size(0, 0, 0), internalFormat(GL_NONE) +{ +} + +Texture::ImageDesc::ImageDesc(const Extents &size, GLenum internalFormat) + : size(size), + internalFormat(internalFormat) +{ +} + +const Texture::ImageDesc &Texture::getImageDesc(GLenum target, size_t level) const +{ + size_t descIndex = GetImageDescIndex(target, level); + ASSERT(descIndex < mImageDescs.size()); + return mImageDescs[descIndex]; +} + +void Texture::setImageDesc(GLenum target, size_t level, const ImageDesc &desc) +{ + size_t descIndex = GetImageDescIndex(target, level); + ASSERT(descIndex < mImageDescs.size()); + mImageDescs[descIndex] = desc; + mCompletenessCache.cacheValid = false; +} + +void Texture::clearImageDesc(GLenum target, size_t level) +{ + setImageDesc(target, level, ImageDesc()); +} + +void Texture::clearImageDescs() +{ + for (size_t descIndex = 0; descIndex < mImageDescs.size(); descIndex++) + { + mImageDescs[descIndex] = ImageDesc(); + } + mCompletenessCache.cacheValid = false; +} + +void Texture::bindTexImage(egl::Surface *surface) +{ + ASSERT(surface); + + releaseTexImage(); + mTexture->bindTexImage(surface); + mBoundSurface = surface; + + // Set the image info to the size and format of the surface + ASSERT(mTarget == GL_TEXTURE_2D); + Extents size(surface->getWidth(), surface->getHeight(), 1); + ImageDesc desc(size, surface->getConfig()->renderTargetFormat); + setImageDesc(mTarget, 0, desc); +} + +void Texture::releaseTexImage() +{ + if (mBoundSurface) + { + mBoundSurface = NULL; + mTexture->releaseTexImage(); + + // Erase the image info for level 0 + ASSERT(mTarget == GL_TEXTURE_2D); + clearImageDesc(mTarget, 0); + } +} + +GLenum Texture::getBaseImageTarget() const +{ + return mTarget == GL_TEXTURE_CUBE_MAP ? FirstCubeMapTextureTarget : mTarget; +} + +size_t Texture::getExpectedMipLevels() const +{ + const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), 0); + if (mTarget == GL_TEXTURE_3D) + { + return log2(std::max(std::max(baseImageDesc.size.width, baseImageDesc.size.height), baseImageDesc.size.depth)) + 1; + } + else + { + return log2(std::max(baseImageDesc.size.width, baseImageDesc.size.height)) + 1; + } +} + +bool Texture::computeSamplerCompleteness(const SamplerState &samplerState, const Data &data) const +{ + const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), samplerState.baseLevel); + if (baseImageDesc.size.width == 0 || baseImageDesc.size.height == 0 || baseImageDesc.size.depth == 0) + { + return false; + } + + if (mTarget == GL_TEXTURE_CUBE_MAP && baseImageDesc.size.width != baseImageDesc.size.height) + { + return false; + } + + const TextureCaps &textureCaps = data.textureCaps->get(baseImageDesc.internalFormat); + if (!textureCaps.filterable && !IsPointSampled(samplerState)) + { + return false; + } + + bool npotSupport = data.extensions->textureNPOT || data.clientVersion >= 3; + if (!npotSupport) + { + if ((samplerState.wrapS != GL_CLAMP_TO_EDGE && !gl::isPow2(baseImageDesc.size.width)) || + (samplerState.wrapT != GL_CLAMP_TO_EDGE && !gl::isPow2(baseImageDesc.size.height))) + { + return false; + } + } + + if (IsMipmapFiltered(samplerState)) + { + if (!npotSupport) + { + if (!gl::isPow2(baseImageDesc.size.width) || !gl::isPow2(baseImageDesc.size.height)) + { + return false; + } + } + + if (!computeMipmapCompleteness(samplerState)) + { + return false; + } + } + else + { + if (mTarget == GL_TEXTURE_CUBE_MAP && !isCubeComplete()) + { + return false; + } + } + + // OpenGLES 3.0.2 spec section 3.8.13 states that a texture is not mipmap complete if: + // The internalformat specified for the texture arrays is a sized internal depth or + // depth and stencil format (see table 3.13), the value of TEXTURE_COMPARE_- + // MODE is NONE, and either the magnification filter is not NEAREST or the mini- + // fication filter is neither NEAREST nor NEAREST_MIPMAP_NEAREST. + const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(baseImageDesc.internalFormat); + if (formatInfo.depthBits > 0 && data.clientVersion > 2) + { + if (samplerState.compareMode == GL_NONE) + { + if ((samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST) || + samplerState.magFilter != GL_NEAREST) + { + return false; + } + } + } + + return true; +} + +bool Texture::computeMipmapCompleteness(const gl::SamplerState &samplerState) const +{ + size_t expectedMipLevels = getExpectedMipLevels(); + + size_t maxLevel = std::min(expectedMipLevels, samplerState.maxLevel + 1); + + for (size_t level = samplerState.baseLevel; level < maxLevel; level++) + { + if (mTarget == GL_TEXTURE_CUBE_MAP) + { + for (GLenum face = FirstCubeMapTextureTarget; face <= LastCubeMapTextureTarget; face++) + { + if (!computeLevelCompleteness(face, level, samplerState)) + { + return false; + } + } + } + else + { + if (!computeLevelCompleteness(mTarget, level, samplerState)) + { + return false; + } + } + } + + return true; +} + + +bool Texture::computeLevelCompleteness(GLenum target, size_t level, const gl::SamplerState &samplerState) const +{ + ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS); + + if (isImmutable()) + { + return true; + } + + const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), samplerState.baseLevel); + if (baseImageDesc.size.width == 0 || baseImageDesc.size.height == 0 || baseImageDesc.size.depth == 0) + { + return false; + } + + // The base image level is complete if the width and height are positive + if (level == 0) + { + return true; + } + + const ImageDesc &levelImageDesc = getImageDesc(target, level); + if (levelImageDesc.internalFormat != baseImageDesc.internalFormat) + { + return false; + } + + if (levelImageDesc.size.width != std::max(1, baseImageDesc.size.width >> level)) + { + return false; + } + + if (levelImageDesc.size.height != std::max(1, baseImageDesc.size.height >> level)) + { + return false; + } + + if (mTarget == GL_TEXTURE_3D) + { + if (levelImageDesc.size.depth != std::max(1, baseImageDesc.size.depth >> level)) + { + return false; + } + } + else if (mTarget == GL_TEXTURE_2D_ARRAY) + { + if (levelImageDesc.size.depth != baseImageDesc.size.depth) + { + return false; + } + } + + return true; +} + +Texture::SamplerCompletenessCache::SamplerCompletenessCache() + : cacheValid(false), + samplerState(), + filterable(false), + clientVersion(0), + supportsNPOT(false), + samplerComplete(false) +{ +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/Texture.h b/src/3rdparty/angle/src/libANGLE/Texture.h new file mode 100644 index 0000000000..b5a0717713 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/Texture.h @@ -0,0 +1,156 @@ +// +// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Texture.h: Defines the gl::Texture class [OpenGL ES 2.0.24] section 3.7 page 63. + +#ifndef LIBANGLE_TEXTURE_H_ +#define LIBANGLE_TEXTURE_H_ + +#include "common/debug.h" +#include "libANGLE/RefCountObject.h" +#include "libANGLE/angletypes.h" +#include "libANGLE/Constants.h" +#include "libANGLE/renderer/TextureImpl.h" +#include "libANGLE/Caps.h" + +#include "angle_gl.h" + +#include +#include + +namespace egl +{ +class Surface; +} + +namespace gl +{ +class Framebuffer; +struct Data; + +bool IsMipmapFiltered(const gl::SamplerState &samplerState); + +class Texture final : public RefCountObject +{ + public: + Texture(rx::TextureImpl *impl, GLuint id, GLenum target); + + virtual ~Texture(); + + GLenum getTarget() const; + + const SamplerState &getSamplerState() const { return mSamplerState; } + SamplerState &getSamplerState() { return mSamplerState; } + + void setUsage(GLenum usage); + GLenum getUsage() const; + + size_t getWidth(GLenum target, size_t level) const; + size_t getHeight(GLenum target, size_t level) const; + size_t getDepth(GLenum target, size_t level) const; + GLenum getInternalFormat(GLenum target, size_t level) const; + + bool isSamplerComplete(const SamplerState &samplerState, const Data &data) const; + bool isCubeComplete() const; + + virtual Error setImage(GLenum target, size_t level, GLenum internalFormat, const Extents &size, GLenum format, GLenum type, + const PixelUnpackState &unpack, const uint8_t *pixels); + virtual Error setSubImage(GLenum target, size_t level, const Box &area, GLenum format, GLenum type, + const PixelUnpackState &unpack, const uint8_t *pixels); + + virtual Error setCompressedImage(GLenum target, size_t level, GLenum internalFormat, const Extents &size, + const PixelUnpackState &unpack, const uint8_t *pixels); + virtual Error setCompressedSubImage(GLenum target, size_t level, const Box &area, GLenum format, + const PixelUnpackState &unpack, const uint8_t *pixels); + + virtual Error copyImage(GLenum target, size_t level, const Rectangle &sourceArea, GLenum internalFormat, + const Framebuffer *source); + virtual Error copySubImage(GLenum target, size_t level, const Offset &destOffset, const Rectangle &sourceArea, + const Framebuffer *source); + + virtual Error setStorage(GLenum target, size_t levels, GLenum internalFormat, const Extents &size); + + virtual Error generateMipmaps(); + + // Texture serials provide a unique way of identifying a Texture that isn't a raw pointer. + // "id" is not good enough, as Textures can be deleted, then re-allocated with the same id. + unsigned int getTextureSerial() const; + + bool isImmutable() const; + GLsizei immutableLevelCount(); + + void bindTexImage(egl::Surface *surface); + void releaseTexImage(); + + rx::TextureImpl *getImplementation() { return mTexture; } + const rx::TextureImpl *getImplementation() const { return mTexture; } + + static const GLuint INCOMPLETE_TEXTURE_ID = static_cast(-1); // Every texture takes an id at creation time. The value is arbitrary because it is never registered with the resource manager. + + private: + static unsigned int issueTextureSerial(); + + rx::TextureImpl *mTexture; + + SamplerState mSamplerState; + GLenum mUsage; + + GLsizei mImmutableLevelCount; + + GLenum mTarget; + + + struct ImageDesc + { + Extents size; + GLenum internalFormat; + + ImageDesc(); + ImageDesc(const Extents &size, GLenum internalFormat); + }; + + const unsigned int mTextureSerial; + static unsigned int mCurrentTextureSerial; + + GLenum getBaseImageTarget() const; + size_t getExpectedMipLevels() const; + + bool computeSamplerCompleteness(const SamplerState &samplerState, const Data &data) const; + bool computeMipmapCompleteness(const gl::SamplerState &samplerState) const; + bool computeLevelCompleteness(GLenum target, size_t level, const gl::SamplerState &samplerState) const; + + const ImageDesc &getImageDesc(GLenum target, size_t level) const; + void setImageDesc(GLenum target, size_t level, const ImageDesc &desc); + void setImageDescChain(size_t levels, Extents baseSize, GLenum sizedInternalFormat); + void clearImageDesc(GLenum target, size_t level); + void clearImageDescs(); + + std::vector mImageDescs; + + struct SamplerCompletenessCache + { + SamplerCompletenessCache(); + + bool cacheValid; + + // All values that affect sampler completeness that are not stored within + // the texture itself + SamplerState samplerState; + bool filterable; + GLint clientVersion; + bool supportsNPOT; + + // Result of the sampler completeness with the above parameters + bool samplerComplete; + }; + mutable SamplerCompletenessCache mCompletenessCache; + + egl::Surface *mBoundSurface; +}; + +} + +#endif // LIBANGLE_TEXTURE_H_ diff --git a/src/3rdparty/angle/src/libANGLE/TransformFeedback.cpp b/src/3rdparty/angle/src/libANGLE/TransformFeedback.cpp new file mode 100644 index 0000000000..6effaca976 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/TransformFeedback.cpp @@ -0,0 +1,71 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "libANGLE/TransformFeedback.h" +#include "libANGLE/renderer/TransformFeedbackImpl.h" + +namespace gl +{ + +TransformFeedback::TransformFeedback(rx::TransformFeedbackImpl* impl, GLuint id) + : RefCountObject(id), + mTransformFeedback(impl), + mStarted(GL_FALSE), + mPrimitiveMode(GL_NONE), + mPaused(GL_FALSE) +{ + ASSERT(impl != NULL); +} + +TransformFeedback::~TransformFeedback() +{ + SafeDelete(mTransformFeedback); +} + +void TransformFeedback::start(GLenum primitiveMode) +{ + mStarted = GL_TRUE; + mPrimitiveMode = primitiveMode; + mPaused = GL_FALSE; + mTransformFeedback->begin(primitiveMode); +} + +void TransformFeedback::stop() +{ + mStarted = GL_FALSE; + mPrimitiveMode = GL_NONE; + mPaused = GL_FALSE; + mTransformFeedback->end(); +} + +GLboolean TransformFeedback::isStarted() const +{ + return mStarted; +} + +GLenum TransformFeedback::getDrawMode() const +{ + return mPrimitiveMode; +} + +void TransformFeedback::pause() +{ + mPaused = GL_TRUE; + mTransformFeedback->pause(); +} + +void TransformFeedback::resume() +{ + mPaused = GL_FALSE; + mTransformFeedback->resume(); +} + +GLboolean TransformFeedback::isPaused() const +{ + return mPaused; +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/TransformFeedback.h b/src/3rdparty/angle/src/libANGLE/TransformFeedback.h new file mode 100644 index 0000000000..7673db93ff --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/TransformFeedback.h @@ -0,0 +1,50 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef LIBANGLE_TRANSFORM_FEEDBACK_H_ +#define LIBANGLE_TRANSFORM_FEEDBACK_H_ + +#include "libANGLE/RefCountObject.h" + +#include "common/angleutils.h" + +#include "angle_gl.h" + +namespace rx +{ +class TransformFeedbackImpl; +} + +namespace gl +{ + +class TransformFeedback : public RefCountObject +{ + public: + TransformFeedback(rx::TransformFeedbackImpl* impl, GLuint id); + virtual ~TransformFeedback(); + + void start(GLenum primitiveMode); + void stop(); + GLboolean isStarted() const; + + GLenum getDrawMode() const; + + void pause(); + void resume(); + GLboolean isPaused() const; + + private: + rx::TransformFeedbackImpl* mTransformFeedback; + + GLboolean mStarted; + GLenum mPrimitiveMode; + GLboolean mPaused; +}; + +} + +#endif // LIBANGLE_TRANSFORM_FEEDBACK_H_ diff --git a/src/3rdparty/angle/src/libANGLE/Uniform.cpp b/src/3rdparty/angle/src/libANGLE/Uniform.cpp new file mode 100644 index 0000000000..f161b9d6bd --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/Uniform.cpp @@ -0,0 +1,107 @@ +// +// Copyright (c) 2010-2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "libANGLE/Uniform.h" + +#include "common/utilities.h" + +#include + +namespace gl +{ + +LinkedUniform::LinkedUniform(GLenum type, GLenum precision, const std::string &name, unsigned int arraySize, + const int blockIndex, const sh::BlockMemberInfo &blockInfo) + : type(type), + precision(precision), + name(name), + arraySize(arraySize), + blockIndex(blockIndex), + blockInfo(blockInfo), + data(NULL), + dirty(true), + psRegisterIndex(GL_INVALID_INDEX), + vsRegisterIndex(GL_INVALID_INDEX), + registerCount(0), + registerElement(0) +{ + // We use data storage for default block uniforms to cache values that are sent to D3D during rendering + // Uniform blocks/buffers are treated separately by the Renderer (ES3 path only) + if (isInDefaultBlock()) + { + size_t bytes = dataSize(); + data = new unsigned char[bytes]; + memset(data, 0, bytes); + registerCount = VariableRowCount(type) * elementCount(); + } +} + +LinkedUniform::~LinkedUniform() +{ + delete[] data; +} + +bool LinkedUniform::isArray() const +{ + return arraySize > 0; +} + +unsigned int LinkedUniform::elementCount() const +{ + return arraySize > 0 ? arraySize : 1; +} + +bool LinkedUniform::isReferencedByVertexShader() const +{ + return vsRegisterIndex != GL_INVALID_INDEX; +} + +bool LinkedUniform::isReferencedByFragmentShader() const +{ + return psRegisterIndex != GL_INVALID_INDEX; +} + +bool LinkedUniform::isInDefaultBlock() const +{ + return blockIndex == -1; +} + +size_t LinkedUniform::dataSize() const +{ + ASSERT(type != GL_STRUCT_ANGLEX); + return VariableInternalSize(type) * elementCount(); +} + +bool LinkedUniform::isSampler() const +{ + return IsSamplerType(type); +} + +UniformBlock::UniformBlock(const std::string &name, unsigned int elementIndex, unsigned int dataSize) + : name(name), + elementIndex(elementIndex), + dataSize(dataSize), + psRegisterIndex(GL_INVALID_INDEX), + vsRegisterIndex(GL_INVALID_INDEX) +{ +} + +bool UniformBlock::isArrayElement() const +{ + return elementIndex != GL_INVALID_INDEX; +} + +bool UniformBlock::isReferencedByVertexShader() const +{ + return vsRegisterIndex != GL_INVALID_INDEX; +} + +bool UniformBlock::isReferencedByFragmentShader() const +{ + return psRegisterIndex != GL_INVALID_INDEX; +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/Uniform.h b/src/3rdparty/angle/src/libANGLE/Uniform.h new file mode 100644 index 0000000000..dcf30f23cc --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/Uniform.h @@ -0,0 +1,77 @@ +// +// Copyright (c) 2010-2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef LIBANGLE_UNIFORM_H_ +#define LIBANGLE_UNIFORM_H_ + +#include +#include + +#include "angle_gl.h" +#include "common/debug.h" +#include "compiler/translator/blocklayout.h" +#include "libANGLE/angletypes.h" + +namespace gl +{ + +// Helper struct representing a single shader uniform +struct LinkedUniform : angle::NonCopyable +{ + LinkedUniform(GLenum type, GLenum precision, const std::string &name, unsigned int arraySize, const int blockIndex, const sh::BlockMemberInfo &blockInfo); + + ~LinkedUniform(); + + bool isArray() const; + unsigned int elementCount() const; + bool isReferencedByVertexShader() const; + bool isReferencedByFragmentShader() const; + bool isInDefaultBlock() const; + size_t dataSize() const; + bool isSampler() const; + + const GLenum type; + const GLenum precision; + const std::string name; + const unsigned int arraySize; + const int blockIndex; + const sh::BlockMemberInfo blockInfo; + + unsigned char *data; + bool dirty; + + unsigned int psRegisterIndex; + unsigned int vsRegisterIndex; + unsigned int registerCount; + + // Register "elements" are used for uniform structs in ES3, to appropriately identify single uniforms + // inside aggregate types, which are packed according C-like structure rules. + unsigned int registerElement; +}; + +// Helper struct representing a single shader uniform block +struct UniformBlock : angle::NonCopyable +{ + // use GL_INVALID_INDEX for non-array elements + UniformBlock(const std::string &name, unsigned int elementIndex, unsigned int dataSize); + + bool isArrayElement() const; + bool isReferencedByVertexShader() const; + bool isReferencedByFragmentShader() const; + + const std::string name; + const unsigned int elementIndex; + const unsigned int dataSize; + + std::vector memberUniformIndexes; + + unsigned int psRegisterIndex; + unsigned int vsRegisterIndex; +}; + +} + +#endif // LIBANGLE_UNIFORM_H_ diff --git a/src/3rdparty/angle/src/libANGLE/VertexArray.cpp b/src/3rdparty/angle/src/libANGLE/VertexArray.cpp new file mode 100644 index 0000000000..f0aded905d --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/VertexArray.cpp @@ -0,0 +1,101 @@ +// +// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// Implementation of the state class for mananging GLES 3 Vertex Array Objects. +// + +#include "libANGLE/VertexArray.h" +#include "libANGLE/Buffer.h" +#include "libANGLE/renderer/VertexArrayImpl.h" + +namespace gl +{ + +VertexArray::VertexArray(rx::VertexArrayImpl *impl, GLuint id, size_t maxAttribs) + : mId(id), + mVertexArray(impl), + mVertexAttributes(maxAttribs) +{ + ASSERT(impl != NULL); +} + +VertexArray::~VertexArray() +{ + SafeDelete(mVertexArray); + + for (size_t i = 0; i < getMaxAttribs(); i++) + { + mVertexAttributes[i].buffer.set(NULL); + } + mElementArrayBuffer.set(NULL); +} + +GLuint VertexArray::id() const +{ + return mId; +} + +void VertexArray::detachBuffer(GLuint bufferName) +{ + for (size_t attribute = 0; attribute < getMaxAttribs(); attribute++) + { + if (mVertexAttributes[attribute].buffer.id() == bufferName) + { + mVertexAttributes[attribute].buffer.set(NULL); + } + } + + if (mElementArrayBuffer.id() == bufferName) + { + mElementArrayBuffer.set(NULL); + } +} + +const VertexAttribute& VertexArray::getVertexAttribute(size_t attributeIndex) const +{ + ASSERT(attributeIndex < getMaxAttribs()); + return mVertexAttributes[attributeIndex]; +} + +const std::vector &VertexArray::getVertexAttributes() const +{ + return mVertexAttributes; +} + +void VertexArray::setVertexAttribDivisor(GLuint index, GLuint divisor) +{ + ASSERT(index < getMaxAttribs()); + mVertexAttributes[index].divisor = divisor; + mVertexArray->setAttributeDivisor(index, divisor); +} + +void VertexArray::enableAttribute(unsigned int attributeIndex, bool enabledState) +{ + ASSERT(attributeIndex < getMaxAttribs()); + mVertexAttributes[attributeIndex].enabled = enabledState; + mVertexArray->enableAttribute(attributeIndex, enabledState); +} + +void VertexArray::setAttributeState(unsigned int attributeIndex, gl::Buffer *boundBuffer, GLint size, GLenum type, + bool normalized, bool pureInteger, GLsizei stride, const void *pointer) +{ + ASSERT(attributeIndex < getMaxAttribs()); + mVertexAttributes[attributeIndex].buffer.set(boundBuffer); + mVertexAttributes[attributeIndex].size = size; + mVertexAttributes[attributeIndex].type = type; + mVertexAttributes[attributeIndex].normalized = normalized; + mVertexAttributes[attributeIndex].pureInteger = pureInteger; + mVertexAttributes[attributeIndex].stride = stride; + mVertexAttributes[attributeIndex].pointer = pointer; + mVertexArray->setAttribute(attributeIndex, mVertexAttributes[attributeIndex]); +} + +void VertexArray::setElementArrayBuffer(Buffer *buffer) +{ + mElementArrayBuffer.set(buffer); + mVertexArray->setElementArrayBuffer(buffer); +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/VertexArray.h b/src/3rdparty/angle/src/libANGLE/VertexArray.h new file mode 100644 index 0000000000..5c79b9953d --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/VertexArray.h @@ -0,0 +1,66 @@ +// +// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// This class contains prototypes for representing GLES 3 Vertex Array Objects: +// +// The buffer objects that are to be used by the vertex stage of the GL are collected +// together to form a vertex array object. All state related to the definition of data used +// by the vertex processor is encapsulated in a vertex array object. +// + +#ifndef LIBANGLE_VERTEXARRAY_H_ +#define LIBANGLE_VERTEXARRAY_H_ + +#include "libANGLE/RefCountObject.h" +#include "libANGLE/Constants.h" +#include "libANGLE/VertexAttribute.h" + +#include + +namespace rx +{ +class VertexArrayImpl; +} + +namespace gl +{ +class Buffer; + +class VertexArray +{ + public: + VertexArray(rx::VertexArrayImpl *impl, GLuint id, size_t maxAttribs); + ~VertexArray(); + + GLuint id() const; + + const VertexAttribute& getVertexAttribute(size_t attributeIndex) const; + const std::vector &getVertexAttributes() const; + + void detachBuffer(GLuint bufferName); + void setVertexAttribDivisor(GLuint index, GLuint divisor); + void enableAttribute(unsigned int attributeIndex, bool enabledState); + void setAttributeState(unsigned int attributeIndex, gl::Buffer *boundBuffer, GLint size, GLenum type, + bool normalized, bool pureInteger, GLsizei stride, const void *pointer); + + Buffer *getElementArrayBuffer() const { return mElementArrayBuffer.get(); } + void setElementArrayBuffer(Buffer *buffer); + GLuint getElementArrayBufferId() const { return mElementArrayBuffer.id(); } + size_t getMaxAttribs() const { return mVertexAttributes.size(); } + + rx::VertexArrayImpl *getImplementation() { return mVertexArray; } + const rx::VertexArrayImpl *getImplementation() const { return mVertexArray; } + + private: + GLuint mId; + + rx::VertexArrayImpl *mVertexArray; + std::vector mVertexAttributes; + BindingPointer mElementArrayBuffer; +}; + +} + +#endif // LIBANGLE_VERTEXARRAY_H_ diff --git a/src/3rdparty/angle/src/libANGLE/VertexAttribute.cpp b/src/3rdparty/angle/src/libANGLE/VertexAttribute.cpp new file mode 100644 index 0000000000..19934e7fac --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/VertexAttribute.cpp @@ -0,0 +1,73 @@ +// +// Copyright 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// Implementation of the state class for mananging GLES 3 Vertex Array Objects. +// + +#include "libANGLE/VertexAttribute.h" + +namespace gl +{ + +VertexAttribute::VertexAttribute() + : enabled(false), + type(GL_FLOAT), + size(4), + normalized(false), + pureInteger(false), + stride(0), + pointer(NULL), + divisor(0) +{ +} + +bool operator==(const VertexAttribute &a, const VertexAttribute &b) +{ + return a.enabled == b.enabled && + a.type == b.type && + a.size == b.size && + a.normalized == b.normalized && + a.pureInteger == b.pureInteger && + a.stride == b.stride && + a.pointer == b.pointer && + a.buffer.get() == b.buffer.get() && + a.divisor == b.divisor; +} + +bool operator!=(const VertexAttribute &a, const VertexAttribute &b) +{ + return !(a == b); +} + +size_t ComputeVertexAttributeTypeSize(const VertexAttribute& attrib) +{ + GLuint size = attrib.size; + switch (attrib.type) + { + case GL_BYTE: return size * sizeof(GLbyte); + case GL_UNSIGNED_BYTE: return size * sizeof(GLubyte); + case GL_SHORT: return size * sizeof(GLshort); + case GL_UNSIGNED_SHORT: return size * sizeof(GLushort); + case GL_INT: return size * sizeof(GLint); + case GL_UNSIGNED_INT: return size * sizeof(GLuint); + case GL_INT_2_10_10_10_REV: return 4; + case GL_UNSIGNED_INT_2_10_10_10_REV: return 4; + case GL_FIXED: return size * sizeof(GLfixed); + case GL_HALF_FLOAT: return size * sizeof(GLhalf); + case GL_FLOAT: return size * sizeof(GLfloat); + default: UNREACHABLE(); return size * sizeof(GLfloat); + } +} + +size_t ComputeVertexAttributeStride(const VertexAttribute& attrib) +{ + if (!attrib.enabled) + { + return 16; + } + return attrib.stride ? attrib.stride : ComputeVertexAttributeTypeSize(attrib); +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/VertexAttribute.h b/src/3rdparty/angle/src/libANGLE/VertexAttribute.h new file mode 100644 index 0000000000..bdffe97466 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/VertexAttribute.h @@ -0,0 +1,122 @@ +// +// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// Helper structure describing a single vertex attribute +// + +#ifndef LIBANGLE_VERTEXATTRIBUTE_H_ +#define LIBANGLE_VERTEXATTRIBUTE_H_ + +#include "libANGLE/Buffer.h" + +namespace gl +{ + +struct VertexAttribute +{ + bool enabled; // From glEnable/DisableVertexAttribArray + + GLenum type; + GLuint size; + bool normalized; + bool pureInteger; + GLuint stride; // 0 means natural stride + + union + { + const GLvoid *pointer; + GLintptr offset; + }; + BindingPointer buffer; // Captured when glVertexAttribPointer is called. + + GLuint divisor; + + VertexAttribute(); +}; + +bool operator==(const VertexAttribute &a, const VertexAttribute &b); +bool operator!=(const VertexAttribute &a, const VertexAttribute &b); + +template +T QuerySingleVertexAttributeParameter(const VertexAttribute& attrib, GLenum pname) +{ + switch (pname) + { + case GL_VERTEX_ATTRIB_ARRAY_ENABLED: + return static_cast(attrib.enabled ? GL_TRUE : GL_FALSE); + case GL_VERTEX_ATTRIB_ARRAY_SIZE: + return static_cast(attrib.size); + case GL_VERTEX_ATTRIB_ARRAY_STRIDE: + return static_cast(attrib.stride); + case GL_VERTEX_ATTRIB_ARRAY_TYPE: + return static_cast(attrib.type); + case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED: + return static_cast(attrib.normalized ? GL_TRUE : GL_FALSE); + case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING: + return static_cast(attrib.buffer.id()); + case GL_VERTEX_ATTRIB_ARRAY_DIVISOR: + return static_cast(attrib.divisor); + case GL_VERTEX_ATTRIB_ARRAY_INTEGER: + return static_cast(attrib.pureInteger ? GL_TRUE : GL_FALSE); + default: + UNREACHABLE(); + return static_cast(0); + } +} + +size_t ComputeVertexAttributeTypeSize(const VertexAttribute& attrib); +size_t ComputeVertexAttributeStride(const VertexAttribute& attrib); + +struct VertexAttribCurrentValueData +{ + union + { + GLfloat FloatValues[4]; + GLint IntValues[4]; + GLuint UnsignedIntValues[4]; + }; + GLenum Type; + + void setFloatValues(const GLfloat floatValues[4]) + { + for (unsigned int valueIndex = 0; valueIndex < 4; valueIndex++) + { + FloatValues[valueIndex] = floatValues[valueIndex]; + } + Type = GL_FLOAT; + } + + void setIntValues(const GLint intValues[4]) + { + for (unsigned int valueIndex = 0; valueIndex < 4; valueIndex++) + { + IntValues[valueIndex] = intValues[valueIndex]; + } + Type = GL_INT; + } + + void setUnsignedIntValues(const GLuint unsignedIntValues[4]) + { + for (unsigned int valueIndex = 0; valueIndex < 4; valueIndex++) + { + UnsignedIntValues[valueIndex] = unsignedIntValues[valueIndex]; + } + Type = GL_UNSIGNED_INT; + } + + bool operator==(const VertexAttribCurrentValueData &other) + { + return (Type == other.Type && memcmp(FloatValues, other.FloatValues, sizeof(float) * 4) == 0); + } + + bool operator!=(const VertexAttribCurrentValueData &other) + { + return !(*this == other); + } +}; + +} + +#endif // LIBANGLE_VERTEXATTRIBUTE_H_ diff --git a/src/3rdparty/angle/src/libANGLE/angletypes.cpp b/src/3rdparty/angle/src/libANGLE/angletypes.cpp new file mode 100644 index 0000000000..16879f8041 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/angletypes.cpp @@ -0,0 +1,246 @@ +// +// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// angletypes.h : Defines a variety of structures and enum types that are used throughout libGLESv2 + +#include "libANGLE/angletypes.h" +#include "libANGLE/Program.h" +#include "libANGLE/VertexAttribute.h" +#include "libANGLE/State.h" +#include "libANGLE/VertexArray.h" + +namespace gl +{ + +bool operator==(const Rectangle &a, const Rectangle &b) +{ + return a.x == b.x && + a.y == b.y && + a.width == b.width && + a.height == b.height; +} + +bool operator!=(const Rectangle &a, const Rectangle &b) +{ + return !(a == b); +} + +SamplerState::SamplerState() + : minFilter(GL_NEAREST_MIPMAP_LINEAR), + magFilter(GL_LINEAR), + wrapS(GL_REPEAT), + wrapT(GL_REPEAT), + wrapR(GL_REPEAT), + maxAnisotropy(1.0f), + baseLevel(0), + maxLevel(1000), + minLod(-1000.0f), + maxLod(1000.0f), + compareMode(GL_NONE), + compareFunc(GL_LEQUAL), + swizzleRed(GL_RED), + swizzleGreen(GL_GREEN), + swizzleBlue(GL_BLUE), + swizzleAlpha(GL_ALPHA) +{} + +bool SamplerState::swizzleRequired() const +{ + return swizzleRed != GL_RED || swizzleGreen != GL_GREEN || + swizzleBlue != GL_BLUE || swizzleAlpha != GL_ALPHA; +} + +bool SamplerState::operator==(const SamplerState &other) const +{ + return minFilter == other.minFilter && + magFilter == other.magFilter && + wrapS == other.wrapS && + wrapT == other.wrapT && + wrapR == other.wrapR && + maxAnisotropy == other.maxAnisotropy && + baseLevel == other.baseLevel && + maxLevel == other.maxLevel && + minLod == other.minLod && + maxLod == other.maxLod && + compareMode == other.compareMode && + compareFunc == other.compareFunc && + swizzleRed == other.swizzleRed && + swizzleGreen == other.swizzleGreen && + swizzleBlue == other.swizzleBlue && + swizzleAlpha == other.swizzleAlpha; +} + +bool SamplerState::operator!=(const SamplerState &other) const +{ + return !(*this == other); +} + +static void MinMax(int a, int b, int *minimum, int *maximum) +{ + if (a < b) + { + *minimum = a; + *maximum = b; + } + else + { + *minimum = b; + *maximum = a; + } +} + +bool ClipRectangle(const Rectangle &source, const Rectangle &clip, Rectangle *intersection) +{ + int minSourceX, maxSourceX, minSourceY, maxSourceY; + MinMax(source.x, source.x + source.width, &minSourceX, &maxSourceX); + MinMax(source.y, source.y + source.height, &minSourceY, &maxSourceY); + + int minClipX, maxClipX, minClipY, maxClipY; + MinMax(clip.x, clip.x + clip.width, &minClipX, &maxClipX); + MinMax(clip.y, clip.y + clip.height, &minClipY, &maxClipY); + + if (minSourceX >= maxClipX || maxSourceX <= minClipX || minSourceY >= maxClipY || maxSourceY <= minClipY) + { + if (intersection) + { + intersection->x = minSourceX; + intersection->y = maxSourceY; + intersection->width = maxSourceX - minSourceX; + intersection->height = maxSourceY - minSourceY; + } + + return false; + } + else + { + if (intersection) + { + intersection->x = std::max(minSourceX, minClipX); + intersection->y = std::max(minSourceY, minClipY); + intersection->width = std::min(maxSourceX, maxClipX) - std::max(minSourceX, minClipX); + intersection->height = std::min(maxSourceY, maxClipY) - std::max(minSourceY, minClipY); + } + + return true; + } +} + +VertexFormat::VertexFormat() + : mType(GL_NONE), + mNormalized(GL_FALSE), + mComponents(0), + mPureInteger(false) +{} + +VertexFormat::VertexFormat(GLenum type, GLboolean normalized, GLuint components, bool pureInteger) + : mType(type), + mNormalized(normalized), + mComponents(components), + mPureInteger(pureInteger) +{ + // Float data can not be normalized, so ignore the user setting + if (mType == GL_FLOAT || mType == GL_HALF_FLOAT || mType == GL_FIXED) + { + mNormalized = GL_FALSE; + } +} + +VertexFormat::VertexFormat(const VertexAttribute &attrib) + : mType(attrib.type), + mNormalized(attrib.normalized ? GL_TRUE : GL_FALSE), + mComponents(attrib.size), + mPureInteger(attrib.pureInteger) +{ + // Ensure we aren't initializing a vertex format which should be using + // the current-value type + ASSERT(attrib.enabled); + + // Float data can not be normalized, so ignore the user setting + if (mType == GL_FLOAT || mType == GL_HALF_FLOAT || mType == GL_FIXED) + { + mNormalized = GL_FALSE; + } +} + +VertexFormat::VertexFormat(const VertexAttribute &attrib, GLenum currentValueType) + : mType(attrib.type), + mNormalized(attrib.normalized ? GL_TRUE : GL_FALSE), + mComponents(attrib.size), + mPureInteger(attrib.pureInteger) +{ + if (!attrib.enabled) + { + mType = currentValueType; + mNormalized = GL_FALSE; + mComponents = 4; + mPureInteger = (currentValueType != GL_FLOAT); + } + + // Float data can not be normalized, so ignore the user setting + if (mType == GL_FLOAT || mType == GL_HALF_FLOAT || mType == GL_FIXED) + { + mNormalized = GL_FALSE; + } +} + +void VertexFormat::GetInputLayout(VertexFormat *inputLayout, + Program *program, + const State &state) +{ + const std::vector &vertexAttributes = state.getVertexArray()->getVertexAttributes(); + for (unsigned int attributeIndex = 0; attributeIndex < vertexAttributes.size(); attributeIndex++) + { + int semanticIndex = program->getSemanticIndex(attributeIndex); + + if (semanticIndex != -1) + { + inputLayout[semanticIndex] = VertexFormat(vertexAttributes[attributeIndex], state.getVertexAttribCurrentValue(attributeIndex).Type); + } + } +} + +bool VertexFormat::operator==(const VertexFormat &other) const +{ + return (mType == other.mType && + mComponents == other.mComponents && + mNormalized == other.mNormalized && + mPureInteger == other.mPureInteger ); +} + +bool VertexFormat::operator!=(const VertexFormat &other) const +{ + return !(*this == other); +} + +bool VertexFormat::operator<(const VertexFormat& other) const +{ + if (mType != other.mType) + { + return mType < other.mType; + } + if (mNormalized != other.mNormalized) + { + return mNormalized < other.mNormalized; + } + if (mComponents != other.mComponents) + { + return mComponents < other.mComponents; + } + return mPureInteger < other.mPureInteger; +} + +bool Box::operator==(const Box &other) const +{ + return (x == other.x && y == other.y && z == other.z && + width == other.width && height == other.height && depth == other.depth); +} + +bool Box::operator!=(const Box &other) const +{ + return !(*this == other); +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/angletypes.h b/src/3rdparty/angle/src/libANGLE/angletypes.h new file mode 100644 index 0000000000..e4e08b5512 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/angletypes.h @@ -0,0 +1,323 @@ +// +// Copyright (c) 2012-2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// angletypes.h : Defines a variety of structures and enum types that are used throughout libGLESv2 + +#ifndef LIBANGLE_ANGLETYPES_H_ +#define LIBANGLE_ANGLETYPES_H_ + +#include "libANGLE/Constants.h" +#include "libANGLE/RefCountObject.h" + +#include +#include + +namespace gl +{ +class Buffer; +class State; +class Program; +struct VertexAttribute; +struct VertexAttribCurrentValueData; + +enum SamplerType +{ + SAMPLER_PIXEL, + SAMPLER_VERTEX +}; + +template +struct Color +{ + T red; + T green; + T blue; + T alpha; + + Color() : red(0), green(0), blue(0), alpha(0) { } + Color(T r, T g, T b, T a) : red(r), green(g), blue(b), alpha(a) { } +}; + +template +bool operator==(const Color &a, const Color &b) +{ + return a.red == b.red && + a.green == b.green && + a.blue == b.blue && + a.alpha == b.alpha; +} + +template +bool operator!=(const Color &a, const Color &b) +{ + return !(a == b); +} + +typedef Color ColorF; +typedef Color ColorI; +typedef Color ColorUI; + +struct Rectangle +{ + int x; + int y; + int width; + int height; + + Rectangle() : x(0), y(0), width(0), height(0) { } + Rectangle(int x_in, int y_in, int width_in, int height_in) : x(x_in), y(y_in), width(width_in), height(height_in) { } +}; + +bool operator==(const Rectangle &a, const Rectangle &b); +bool operator!=(const Rectangle &a, const Rectangle &b); + +bool ClipRectangle(const Rectangle &source, const Rectangle &clip, Rectangle *intersection); + +struct Offset +{ + int x; + int y; + int z; + + Offset() : x(0), y(0), z(0) { } + Offset(int x_in, int y_in, int z_in) : x(x_in), y(y_in), z(z_in) { } +}; + +struct Extents +{ + int width; + int height; + int depth; + + Extents() : width(0), height(0), depth(0) { } + Extents(int width_, int height_, int depth_) : width(width_), height(height_), depth(depth_) { } + + bool empty() const { return (width * height * depth) == 0; } +}; + +struct Box +{ + int x; + int y; + int z; + int width; + int height; + int depth; + + Box() : x(0), y(0), z(0), width(0), height(0), depth(0) { } + Box(int x_in, int y_in, int z_in, int width_in, int height_in, int depth_in) : x(x_in), y(y_in), z(z_in), width(width_in), height(height_in), depth(depth_in) { } + Box(const Offset &offset, const Extents &size) : x(offset.x), y(offset.y), z(offset.z), width(size.width), height(size.height), depth(size.depth) { } + bool operator==(const Box &other) const; + bool operator!=(const Box &other) const; +}; + + +struct RasterizerState +{ + bool cullFace; + GLenum cullMode; + GLenum frontFace; + + bool polygonOffsetFill; + GLfloat polygonOffsetFactor; + GLfloat polygonOffsetUnits; + + bool pointDrawMode; + bool multiSample; + + bool rasterizerDiscard; +}; + +struct BlendState +{ + bool blend; + GLenum sourceBlendRGB; + GLenum destBlendRGB; + GLenum sourceBlendAlpha; + GLenum destBlendAlpha; + GLenum blendEquationRGB; + GLenum blendEquationAlpha; + + bool colorMaskRed; + bool colorMaskGreen; + bool colorMaskBlue; + bool colorMaskAlpha; + + bool sampleAlphaToCoverage; + + bool dither; +}; + +struct DepthStencilState +{ + bool depthTest; + GLenum depthFunc; + bool depthMask; + + bool stencilTest; + GLenum stencilFunc; + GLuint stencilMask; + GLenum stencilFail; + GLenum stencilPassDepthFail; + GLenum stencilPassDepthPass; + GLuint stencilWritemask; + GLenum stencilBackFunc; + GLuint stencilBackMask; + GLenum stencilBackFail; + GLenum stencilBackPassDepthFail; + GLenum stencilBackPassDepthPass; + GLuint stencilBackWritemask; +}; + +struct SamplerState +{ + SamplerState(); + + GLenum minFilter; + GLenum magFilter; + GLenum wrapS; + GLenum wrapT; + GLenum wrapR; + float maxAnisotropy; + + GLint baseLevel; + GLint maxLevel; + GLfloat minLod; + GLfloat maxLod; + + GLenum compareMode; + GLenum compareFunc; + + GLenum swizzleRed; + GLenum swizzleGreen; + GLenum swizzleBlue; + GLenum swizzleAlpha; + + bool swizzleRequired() const; + + bool operator==(const SamplerState &other) const; + bool operator!=(const SamplerState &other) const; +}; + +struct PixelUnpackState +{ + BindingPointer pixelBuffer; + GLint alignment; + GLint rowLength; + GLint skipRows; + GLint skipPixels; + GLint imageHeight; + GLint skipImages; + + PixelUnpackState() + : alignment(4), + rowLength(0), + skipRows(0), + skipPixels(0), + imageHeight(0), + skipImages(0) + {} + + PixelUnpackState(GLint alignmentIn, GLint rowLengthIn) + : alignment(alignmentIn), + rowLength(rowLengthIn), + skipRows(0), + skipPixels(0), + imageHeight(0), + skipImages(0) + {} +}; + +struct PixelPackState +{ + BindingPointer pixelBuffer; + GLint alignment; + bool reverseRowOrder; + GLint rowLength; + GLint skipRows; + GLint skipPixels; + + PixelPackState() + : alignment(4), + reverseRowOrder(false), + rowLength(0), + skipRows(0), + skipPixels(0) + {} + + explicit PixelPackState(GLint alignmentIn, bool reverseRowOrderIn) + : alignment(alignmentIn), + reverseRowOrder(reverseRowOrderIn), + rowLength(0), + skipRows(0), + skipPixels(0) + {} +}; + +struct VertexFormat +{ + GLenum mType; + GLboolean mNormalized; + GLuint mComponents; + bool mPureInteger; + + VertexFormat(); + VertexFormat(GLenum type, GLboolean normalized, GLuint components, bool pureInteger); + explicit VertexFormat(const VertexAttribute &attribute); + VertexFormat(const VertexAttribute &attribute, GLenum currentValueType); + + static void GetInputLayout(VertexFormat *inputLayout, + Program *program, + const State& currentValues); + + bool operator==(const VertexFormat &other) const; + bool operator!=(const VertexFormat &other) const; + bool operator<(const VertexFormat& other) const; +}; + +} + +namespace rx +{ + +enum VendorID : uint32_t +{ + VENDOR_ID_AMD = 0x1002, + VENDOR_ID_INTEL = 0x8086, + VENDOR_ID_NVIDIA = 0x10DE, +}; + +// Downcast a base implementation object (EG TextureImpl to TextureD3D) +template +inline DestT *GetAs(SrcT *src) +{ + ASSERT(HAS_DYNAMIC_TYPE(DestT*, src)); + return static_cast(src); +} + +template +inline const DestT *GetAs(const SrcT *src) +{ + ASSERT(HAS_DYNAMIC_TYPE(const DestT*, src)); + return static_cast(src); +} + +// Downcast a GL object to an Impl (EG gl::Texture to rx::TextureD3D) +template +inline DestT *GetImplAs(SrcT *src) +{ + return GetAs(src->getImplementation()); +} + +template +inline const DestT *GetImplAs(const SrcT *src) +{ + return GetAs(src->getImplementation()); +} + +} + +#endif // LIBANGLE_ANGLETYPES_H_ diff --git a/src/3rdparty/angle/src/libANGLE/features.h b/src/3rdparty/angle/src/libANGLE/features.h new file mode 100644 index 0000000000..fbe013f47d --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/features.h @@ -0,0 +1,40 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef LIBANGLE_FEATURES_H_ +#define LIBANGLE_FEATURES_H_ + +#define ANGLE_DISABLED 0 +#define ANGLE_ENABLED 1 + +// Feature defaults + +// Direct3D9EX +// The "Debug This Pixel..." feature in PIX often fails when using the +// D3D9Ex interfaces. In order to get debug pixel to work on a Vista/Win 7 +// machine, define "ANGLE_D3D9EX=0" in your project file. +#if !defined(ANGLE_D3D9EX) +#define ANGLE_D3D9EX ANGLE_ENABLED +#endif + +// Vsync +// ENABLED allows Vsync to be configured at runtime +// DISABLED disallows Vsync +#if !defined(ANGLE_VSYNC) +#define ANGLE_VSYNC ANGLE_ENABLED +#endif + +// Program binary loading +#if !defined(ANGLE_PROGRAM_BINARY_LOAD) +#define ANGLE_PROGRAM_BINARY_LOAD ANGLE_ENABLED +#endif + +// Shader debug info +#if !defined(ANGLE_SHADER_DEBUG_INFO) +#define ANGLE_SHADER_DEBUG_INFO ANGLE_DISABLED +#endif + +#endif // LIBANGLE_FEATURES_H_ diff --git a/src/3rdparty/angle/src/libANGLE/formatutils.cpp b/src/3rdparty/angle/src/libANGLE/formatutils.cpp new file mode 100644 index 0000000000..51e6a5a65d --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/formatutils.cpp @@ -0,0 +1,650 @@ +// +// Copyright (c) 2013-2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// formatutils.cpp: Queries for GL image formats. + +#include "common/mathutil.h" +#include "libANGLE/formatutils.h" +#include "libANGLE/Context.h" +#include "libANGLE/Framebuffer.h" +#include "libANGLE/renderer/Renderer.h" + +namespace gl +{ + +// ES2 requires that format is equal to internal format at all glTex*Image2D entry points and the implementation +// can decide the true, sized, internal format. The ES2FormatMap determines the internal format for all valid +// format and type combinations. + +typedef std::pair FormatTypePair; +typedef std::pair FormatPair; +typedef std::map FormatMap; + +// A helper function to insert data into the format map with fewer characters. +static inline void InsertFormatMapping(FormatMap *map, GLenum format, GLenum type, GLenum internalFormat) +{ + map->insert(FormatPair(FormatTypePair(format, type), internalFormat)); +} + +FormatMap BuildFormatMap() +{ + FormatMap map; + + // | Format | Type | Internal format | + InsertFormatMapping(&map, GL_RGBA, GL_UNSIGNED_BYTE, GL_RGBA8); + InsertFormatMapping(&map, GL_RGBA, GL_BYTE, GL_RGBA8_SNORM); + InsertFormatMapping(&map, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, GL_RGBA4); + InsertFormatMapping(&map, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, GL_RGB5_A1); + InsertFormatMapping(&map, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV, GL_RGB10_A2); + InsertFormatMapping(&map, GL_RGBA, GL_FLOAT, GL_RGBA32F); + InsertFormatMapping(&map, GL_RGBA, GL_HALF_FLOAT, GL_RGBA16F); + InsertFormatMapping(&map, GL_RGBA, GL_HALF_FLOAT_OES, GL_RGBA16F); + + InsertFormatMapping(&map, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE, GL_RGBA8UI); + InsertFormatMapping(&map, GL_RGBA_INTEGER, GL_BYTE, GL_RGBA8I); + InsertFormatMapping(&map, GL_RGBA_INTEGER, GL_UNSIGNED_SHORT, GL_RGBA16UI); + InsertFormatMapping(&map, GL_RGBA_INTEGER, GL_SHORT, GL_RGBA16I); + InsertFormatMapping(&map, GL_RGBA_INTEGER, GL_UNSIGNED_INT, GL_RGBA32UI); + InsertFormatMapping(&map, GL_RGBA_INTEGER, GL_INT, GL_RGBA32I); + InsertFormatMapping(&map, GL_RGBA_INTEGER, GL_UNSIGNED_INT_2_10_10_10_REV, GL_RGB10_A2UI); + + InsertFormatMapping(&map, GL_RGB, GL_UNSIGNED_BYTE, GL_RGB8); + InsertFormatMapping(&map, GL_RGB, GL_BYTE, GL_RGB8_SNORM); + InsertFormatMapping(&map, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, GL_RGB565); + InsertFormatMapping(&map, GL_RGB, GL_UNSIGNED_INT_10F_11F_11F_REV, GL_R11F_G11F_B10F); + InsertFormatMapping(&map, GL_RGB, GL_UNSIGNED_INT_5_9_9_9_REV, GL_RGB9_E5); + InsertFormatMapping(&map, GL_RGB, GL_FLOAT, GL_RGB32F); + InsertFormatMapping(&map, GL_RGB, GL_HALF_FLOAT, GL_RGB16F); + InsertFormatMapping(&map, GL_RGB, GL_HALF_FLOAT_OES, GL_RGB16F); + + InsertFormatMapping(&map, GL_RGB_INTEGER, GL_UNSIGNED_BYTE, GL_RGB8UI); + InsertFormatMapping(&map, GL_RGB_INTEGER, GL_BYTE, GL_RGB8I); + InsertFormatMapping(&map, GL_RGB_INTEGER, GL_UNSIGNED_SHORT, GL_RGB16UI); + InsertFormatMapping(&map, GL_RGB_INTEGER, GL_SHORT, GL_RGB16I); + InsertFormatMapping(&map, GL_RGB_INTEGER, GL_UNSIGNED_INT, GL_RGB32UI); + InsertFormatMapping(&map, GL_RGB_INTEGER, GL_INT, GL_RGB32I); + + InsertFormatMapping(&map, GL_RG, GL_UNSIGNED_BYTE, GL_RG8); + InsertFormatMapping(&map, GL_RG, GL_BYTE, GL_RG8_SNORM); + InsertFormatMapping(&map, GL_RG, GL_FLOAT, GL_RG32F); + InsertFormatMapping(&map, GL_RG, GL_HALF_FLOAT, GL_RG16F); + InsertFormatMapping(&map, GL_RG, GL_HALF_FLOAT_OES, GL_RG16F); + + InsertFormatMapping(&map, GL_RG_INTEGER, GL_UNSIGNED_BYTE, GL_RG8UI); + InsertFormatMapping(&map, GL_RG_INTEGER, GL_BYTE, GL_RG8I); + InsertFormatMapping(&map, GL_RG_INTEGER, GL_UNSIGNED_SHORT, GL_RG16UI); + InsertFormatMapping(&map, GL_RG_INTEGER, GL_SHORT, GL_RG16I); + InsertFormatMapping(&map, GL_RG_INTEGER, GL_UNSIGNED_INT, GL_RG32UI); + InsertFormatMapping(&map, GL_RG_INTEGER, GL_INT, GL_RG32I); + + InsertFormatMapping(&map, GL_RED, GL_UNSIGNED_BYTE, GL_R8); + InsertFormatMapping(&map, GL_RED, GL_BYTE, GL_R8_SNORM); + InsertFormatMapping(&map, GL_RED, GL_FLOAT, GL_R32F); + InsertFormatMapping(&map, GL_RED, GL_HALF_FLOAT, GL_R16F); + InsertFormatMapping(&map, GL_RED, GL_HALF_FLOAT_OES, GL_R16F); + + InsertFormatMapping(&map, GL_RED_INTEGER, GL_UNSIGNED_BYTE, GL_R8UI); + InsertFormatMapping(&map, GL_RED_INTEGER, GL_BYTE, GL_R8I); + InsertFormatMapping(&map, GL_RED_INTEGER, GL_UNSIGNED_SHORT, GL_R16UI); + InsertFormatMapping(&map, GL_RED_INTEGER, GL_SHORT, GL_R16I); + InsertFormatMapping(&map, GL_RED_INTEGER, GL_UNSIGNED_INT, GL_R32UI); + InsertFormatMapping(&map, GL_RED_INTEGER, GL_INT, GL_R32I); + + InsertFormatMapping(&map, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, GL_LUMINANCE8_ALPHA8_EXT); + InsertFormatMapping(&map, GL_LUMINANCE, GL_UNSIGNED_BYTE, GL_LUMINANCE8_EXT); + InsertFormatMapping(&map, GL_ALPHA, GL_UNSIGNED_BYTE, GL_ALPHA8_EXT); + InsertFormatMapping(&map, GL_LUMINANCE_ALPHA, GL_FLOAT, GL_LUMINANCE_ALPHA32F_EXT); + InsertFormatMapping(&map, GL_LUMINANCE, GL_FLOAT, GL_LUMINANCE32F_EXT); + InsertFormatMapping(&map, GL_ALPHA, GL_FLOAT, GL_ALPHA32F_EXT); + InsertFormatMapping(&map, GL_LUMINANCE_ALPHA, GL_HALF_FLOAT, GL_LUMINANCE_ALPHA16F_EXT); + InsertFormatMapping(&map, GL_LUMINANCE_ALPHA, GL_HALF_FLOAT_OES, GL_LUMINANCE_ALPHA16F_EXT); + InsertFormatMapping(&map, GL_LUMINANCE, GL_HALF_FLOAT, GL_LUMINANCE16F_EXT); + InsertFormatMapping(&map, GL_LUMINANCE, GL_HALF_FLOAT_OES, GL_LUMINANCE16F_EXT); + InsertFormatMapping(&map, GL_ALPHA, GL_HALF_FLOAT, GL_ALPHA16F_EXT); + InsertFormatMapping(&map, GL_ALPHA, GL_HALF_FLOAT_OES, GL_ALPHA16F_EXT); + + InsertFormatMapping(&map, GL_BGRA_EXT, GL_UNSIGNED_BYTE, GL_BGRA8_EXT); + InsertFormatMapping(&map, GL_BGRA_EXT, GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT, GL_BGRA4_ANGLEX); + InsertFormatMapping(&map, GL_BGRA_EXT, GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT, GL_BGR5_A1_ANGLEX); + + InsertFormatMapping(&map, GL_SRGB_EXT, GL_UNSIGNED_BYTE, GL_SRGB8); + InsertFormatMapping(&map, GL_SRGB_ALPHA_EXT, GL_UNSIGNED_BYTE, GL_SRGB8_ALPHA8); + + InsertFormatMapping(&map, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_UNSIGNED_BYTE, GL_COMPRESSED_RGB_S3TC_DXT1_EXT); + InsertFormatMapping(&map, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, GL_UNSIGNED_BYTE, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT); + InsertFormatMapping(&map, GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE, GL_UNSIGNED_BYTE, GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE); + InsertFormatMapping(&map, GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE, GL_UNSIGNED_BYTE, GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE); + + InsertFormatMapping(&map, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, GL_DEPTH_COMPONENT16); + InsertFormatMapping(&map, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, GL_DEPTH_COMPONENT32_OES); + InsertFormatMapping(&map, GL_DEPTH_COMPONENT, GL_FLOAT, GL_DEPTH_COMPONENT32F); + + InsertFormatMapping(&map, GL_STENCIL, GL_UNSIGNED_BYTE, GL_STENCIL_INDEX8); + + InsertFormatMapping(&map, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, GL_DEPTH24_STENCIL8); + InsertFormatMapping(&map, GL_DEPTH_STENCIL, GL_FLOAT_32_UNSIGNED_INT_24_8_REV, GL_DEPTH32F_STENCIL8); + + return map; +} + +Type::Type() + : bytes(0), + bytesShift(0), + specialInterpretation(false) +{ +} + +static Type GenTypeInfo(GLuint bytes, bool specialInterpretation) +{ + Type info; + info.bytes = bytes; + GLuint i = 0; + while ((1u << i) < bytes) + { + ++i; + } + info.bytesShift = i; + ASSERT((1u << info.bytesShift) == bytes); + info.specialInterpretation = specialInterpretation; + return info; +} + +bool operator<(const Type& a, const Type& b) +{ + return memcmp(&a, &b, sizeof(Type)) < 0; +} + +// Information about internal formats +static bool AlwaysSupported(GLuint, const Extensions &) +{ + return true; +} + +static bool UnimplementedSupport(GLuint, const Extensions &) +{ + return false; +} + +static bool NeverSupported(GLuint, const Extensions &) +{ + return false; +} + +template +static bool RequireES(GLuint clientVersion, const Extensions &) +{ + return clientVersion >= minCoreGLVersion; +} + +// Pointer to a boolean memeber of the Extensions struct +typedef bool(Extensions::*ExtensionBool); + +// Check support for a single extension +template +static bool RequireExt(GLuint, const Extensions & extensions) +{ + return extensions.*bool1; +} + +// Check for a minimum client version or a single extension +template +static bool RequireESOrExt(GLuint clientVersion, const Extensions &extensions) +{ + return clientVersion >= minCoreGLVersion || extensions.*bool1; +} + +// Check for a minimum client version or two extensions +template +static bool RequireESOrExtAndExt(GLuint clientVersion, const Extensions &extensions) +{ + return clientVersion >= minCoreGLVersion || (extensions.*bool1 && extensions.*bool2); +} + +// Check for a minimum client version or at least one of two extensions +template +static bool RequireESOrExtOrExt(GLuint clientVersion, const Extensions &extensions) +{ + return clientVersion >= minCoreGLVersion || extensions.*bool1 || extensions.*bool2; +} + +// Check support for two extensions +template +static bool RequireExtAndExt(GLuint, const Extensions &extensions) +{ + return extensions.*bool1 && extensions.*bool2; +} + +InternalFormat::InternalFormat() + : redBits(0), + greenBits(0), + blueBits(0), + luminanceBits(0), + alphaBits(0), + sharedBits(0), + depthBits(0), + stencilBits(0), + pixelBytes(0), + componentCount(0), + compressedBlockWidth(0), + compressedBlockHeight(0), + format(GL_NONE), + type(GL_NONE), + componentType(GL_NONE), + colorEncoding(GL_NONE), + compressed(false), + textureSupport(NeverSupported), + renderSupport(NeverSupported), + filterSupport(NeverSupported) +{ +} + +static InternalFormat UnsizedFormat(GLenum format, InternalFormat::SupportCheckFunction textureSupport, + InternalFormat::SupportCheckFunction renderSupport, + InternalFormat::SupportCheckFunction filterSupport) +{ + InternalFormat formatInfo; + formatInfo.format = format; + formatInfo.textureSupport = textureSupport; + formatInfo.renderSupport = renderSupport; + formatInfo.filterSupport = filterSupport; + return formatInfo; +} + +static InternalFormat RGBAFormat(GLuint red, GLuint green, GLuint blue, GLuint alpha, GLuint shared, + GLenum format, GLenum type, GLenum componentType, bool srgb, + InternalFormat::SupportCheckFunction textureSupport, + InternalFormat::SupportCheckFunction renderSupport, + InternalFormat::SupportCheckFunction filterSupport) +{ + InternalFormat formatInfo; + formatInfo.redBits = red; + formatInfo.greenBits = green; + formatInfo.blueBits = blue; + formatInfo.alphaBits = alpha; + formatInfo.sharedBits = shared; + formatInfo.pixelBytes = (red + green + blue + alpha + shared) / 8; + formatInfo.componentCount = ((red > 0) ? 1 : 0) + ((green > 0) ? 1 : 0) + ((blue > 0) ? 1 : 0) + ((alpha > 0) ? 1 : 0); + formatInfo.format = format; + formatInfo.type = type; + formatInfo.componentType = componentType; + formatInfo.colorEncoding = (srgb ? GL_SRGB : GL_LINEAR); + formatInfo.textureSupport = textureSupport; + formatInfo.renderSupport = renderSupport; + formatInfo.filterSupport = filterSupport; + return formatInfo; +} + +static InternalFormat LUMAFormat(GLuint luminance, GLuint alpha, GLenum format, GLenum type, GLenum componentType, + InternalFormat::SupportCheckFunction textureSupport, + InternalFormat::SupportCheckFunction renderSupport, + InternalFormat::SupportCheckFunction filterSupport) +{ + InternalFormat formatInfo; + formatInfo.luminanceBits = luminance; + formatInfo.alphaBits = alpha; + formatInfo.pixelBytes = (luminance + alpha) / 8; + formatInfo.componentCount = ((luminance > 0) ? 1 : 0) + ((alpha > 0) ? 1 : 0); + formatInfo.format = format; + formatInfo.type = type; + formatInfo.componentType = componentType; + formatInfo.colorEncoding = GL_LINEAR; + formatInfo.textureSupport = textureSupport; + formatInfo.renderSupport = renderSupport; + formatInfo.filterSupport = filterSupport; + return formatInfo; +} + +static InternalFormat DepthStencilFormat(GLuint depthBits, GLuint stencilBits, GLuint unusedBits, GLenum format, + GLenum type, GLenum componentType, InternalFormat::SupportCheckFunction textureSupport, + InternalFormat::SupportCheckFunction renderSupport, + InternalFormat::SupportCheckFunction filterSupport) +{ + InternalFormat formatInfo; + formatInfo.depthBits = depthBits; + formatInfo.stencilBits = stencilBits; + formatInfo.pixelBytes = (depthBits + stencilBits + unusedBits) / 8; + formatInfo.componentCount = ((depthBits > 0) ? 1 : 0) + ((stencilBits > 0) ? 1 : 0); + formatInfo.format = format; + formatInfo.type = type; + formatInfo.componentType = componentType; + formatInfo.colorEncoding = GL_LINEAR; + formatInfo.textureSupport = textureSupport; + formatInfo.renderSupport = renderSupport; + formatInfo.filterSupport = filterSupport; + return formatInfo; +} + +static InternalFormat CompressedFormat(GLuint compressedBlockWidth, GLuint compressedBlockHeight, GLuint compressedBlockSize, + GLuint componentCount, GLenum format, GLenum type, bool srgb, + InternalFormat::SupportCheckFunction textureSupport, + InternalFormat::SupportCheckFunction renderSupport, + InternalFormat::SupportCheckFunction filterSupport) +{ + InternalFormat formatInfo; + formatInfo.compressedBlockWidth = compressedBlockWidth; + formatInfo.compressedBlockHeight = compressedBlockHeight; + formatInfo.pixelBytes = compressedBlockSize / 8; + formatInfo.componentCount = componentCount; + formatInfo.format = format; + formatInfo.type = type; + formatInfo.componentType = GL_UNSIGNED_NORMALIZED; + formatInfo.colorEncoding = (srgb ? GL_SRGB : GL_LINEAR); + formatInfo.compressed = true; + formatInfo.textureSupport = textureSupport; + formatInfo.renderSupport = renderSupport; + formatInfo.filterSupport = filterSupport; + return formatInfo; +} + +typedef std::pair InternalFormatInfoPair; +typedef std::map InternalFormatInfoMap; + +static InternalFormatInfoMap BuildInternalFormatInfoMap() +{ + InternalFormatInfoMap map; + + // From ES 3.0.1 spec, table 3.12 + map.insert(InternalFormatInfoPair(GL_NONE, InternalFormat())); + + // | Internal format | | R | G | B | A |S | Format | Type | Component type | SRGB | Texture supported | Renderable | Filterable | + map.insert(InternalFormatInfoPair(GL_R8, RGBAFormat( 8, 0, 0, 0, 0, GL_RED, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, false, RequireESOrExt<3, &Extensions::textureRG>, RequireESOrExt<3, &Extensions::textureRG>, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_R8_SNORM, RGBAFormat( 8, 0, 0, 0, 0, GL_RED, GL_BYTE, GL_SIGNED_NORMALIZED, false, RequireES<3>, NeverSupported, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_RG8, RGBAFormat( 8, 8, 0, 0, 0, GL_RG, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, false, RequireESOrExt<3, &Extensions::textureRG>, RequireESOrExt<3, &Extensions::textureRG>, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_RG8_SNORM, RGBAFormat( 8, 8, 0, 0, 0, GL_RG, GL_BYTE, GL_SIGNED_NORMALIZED, false, RequireES<3>, NeverSupported, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_RGB8, RGBAFormat( 8, 8, 8, 0, 0, GL_RGB, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, false, RequireESOrExt<3, &Extensions::rgb8rgba8>, RequireESOrExt<3, &Extensions::rgb8rgba8>, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_RGB8_SNORM, RGBAFormat( 8, 8, 8, 0, 0, GL_RGB, GL_BYTE, GL_SIGNED_NORMALIZED, false, RequireES<3>, NeverSupported, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_RGB565, RGBAFormat( 5, 6, 5, 0, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, GL_UNSIGNED_NORMALIZED, false, RequireES<2>, RequireES<2>, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_RGBA4, RGBAFormat( 4, 4, 4, 4, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, GL_UNSIGNED_NORMALIZED, false, RequireES<2>, RequireES<2>, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_RGB5_A1, RGBAFormat( 5, 5, 5, 1, 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, GL_UNSIGNED_NORMALIZED, false, RequireES<2>, RequireES<2>, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_RGBA8, RGBAFormat( 8, 8, 8, 8, 0, GL_RGBA, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, false, RequireESOrExt<3, &Extensions::rgb8rgba8>, RequireESOrExt<3, &Extensions::rgb8rgba8>, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_RGBA8_SNORM, RGBAFormat( 8, 8, 8, 8, 0, GL_RGBA, GL_BYTE, GL_SIGNED_NORMALIZED, false, RequireES<3>, NeverSupported, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_RGB10_A2, RGBAFormat(10, 10, 10, 2, 0, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV, GL_UNSIGNED_NORMALIZED, false, RequireES<3>, RequireES<3>, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_RGB10_A2UI, RGBAFormat(10, 10, 10, 2, 0, GL_RGBA_INTEGER, GL_UNSIGNED_INT_2_10_10_10_REV, GL_UNSIGNED_INT, false, RequireES<3>, NeverSupported, NeverSupported))); + map.insert(InternalFormatInfoPair(GL_SRGB8, RGBAFormat( 8, 8, 8, 0, 0, GL_RGB, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, true, RequireESOrExt<3, &Extensions::sRGB>, NeverSupported, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_SRGB8_ALPHA8, RGBAFormat( 8, 8, 8, 8, 0, GL_RGBA, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, true, RequireESOrExt<3, &Extensions::sRGB>, RequireESOrExt<3, &Extensions::sRGB>, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_R11F_G11F_B10F, RGBAFormat(11, 11, 10, 0, 0, GL_RGB, GL_UNSIGNED_INT_10F_11F_11F_REV, GL_FLOAT, false, RequireES<3>, RequireExt<&Extensions::colorBufferFloat>, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_RGB9_E5, RGBAFormat( 9, 9, 9, 0, 5, GL_RGB, GL_UNSIGNED_INT_5_9_9_9_REV, GL_FLOAT, false, RequireES<3>, NeverSupported, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_R8I, RGBAFormat( 8, 0, 0, 0, 0, GL_RED_INTEGER, GL_BYTE, GL_INT, false, RequireES<3>, RequireES<3>, NeverSupported))); + map.insert(InternalFormatInfoPair(GL_R8UI, RGBAFormat( 8, 0, 0, 0, 0, GL_RED_INTEGER, GL_UNSIGNED_BYTE, GL_UNSIGNED_INT, false, RequireES<3>, RequireES<3>, NeverSupported))); + map.insert(InternalFormatInfoPair(GL_R16I, RGBAFormat(16, 0, 0, 0, 0, GL_RED_INTEGER, GL_SHORT, GL_INT, false, RequireES<3>, RequireES<3>, NeverSupported))); + map.insert(InternalFormatInfoPair(GL_R16UI, RGBAFormat(16, 0, 0, 0, 0, GL_RED_INTEGER, GL_UNSIGNED_SHORT, GL_UNSIGNED_INT, false, RequireES<3>, RequireES<3>, NeverSupported))); + map.insert(InternalFormatInfoPair(GL_R32I, RGBAFormat(32, 0, 0, 0, 0, GL_RED_INTEGER, GL_INT, GL_INT, false, RequireES<3>, RequireES<3>, NeverSupported))); + map.insert(InternalFormatInfoPair(GL_R32UI, RGBAFormat(32, 0, 0, 0, 0, GL_RED_INTEGER, GL_UNSIGNED_INT, GL_UNSIGNED_INT, false, RequireES<3>, RequireES<3>, NeverSupported))); + map.insert(InternalFormatInfoPair(GL_RG8I, RGBAFormat( 8, 8, 0, 0, 0, GL_RG_INTEGER, GL_BYTE, GL_INT, false, RequireES<3>, RequireES<3>, NeverSupported))); + map.insert(InternalFormatInfoPair(GL_RG8UI, RGBAFormat( 8, 8, 0, 0, 0, GL_RG_INTEGER, GL_UNSIGNED_BYTE, GL_UNSIGNED_INT, false, RequireES<3>, RequireES<3>, NeverSupported))); + map.insert(InternalFormatInfoPair(GL_RG16I, RGBAFormat(16, 16, 0, 0, 0, GL_RG_INTEGER, GL_SHORT, GL_INT, false, RequireES<3>, RequireES<3>, NeverSupported))); + map.insert(InternalFormatInfoPair(GL_RG16UI, RGBAFormat(16, 16, 0, 0, 0, GL_RG_INTEGER, GL_UNSIGNED_SHORT, GL_UNSIGNED_INT, false, RequireES<3>, RequireES<3>, NeverSupported))); + map.insert(InternalFormatInfoPair(GL_RG32I, RGBAFormat(32, 32, 0, 0, 0, GL_RG_INTEGER, GL_INT, GL_INT, false, RequireES<3>, RequireES<3>, NeverSupported))); + map.insert(InternalFormatInfoPair(GL_RG32UI, RGBAFormat(32, 32, 0, 0, 0, GL_RG_INTEGER, GL_UNSIGNED_INT, GL_UNSIGNED_INT, false, RequireES<3>, RequireES<3>, NeverSupported))); + map.insert(InternalFormatInfoPair(GL_RGB8I, RGBAFormat( 8, 8, 8, 0, 0, GL_RGB_INTEGER, GL_BYTE, GL_INT, false, RequireES<3>, NeverSupported, NeverSupported))); + map.insert(InternalFormatInfoPair(GL_RGB8UI, RGBAFormat( 8, 8, 8, 0, 0, GL_RGB_INTEGER, GL_UNSIGNED_BYTE, GL_UNSIGNED_INT, false, RequireES<3>, NeverSupported, NeverSupported))); + map.insert(InternalFormatInfoPair(GL_RGB16I, RGBAFormat(16, 16, 16, 0, 0, GL_RGB_INTEGER, GL_SHORT, GL_INT, false, RequireES<3>, NeverSupported, NeverSupported))); + map.insert(InternalFormatInfoPair(GL_RGB16UI, RGBAFormat(16, 16, 16, 0, 0, GL_RGB_INTEGER, GL_UNSIGNED_SHORT, GL_UNSIGNED_INT, false, RequireES<3>, NeverSupported, NeverSupported))); + map.insert(InternalFormatInfoPair(GL_RGB32I, RGBAFormat(32, 32, 32, 0, 0, GL_RGB_INTEGER, GL_INT, GL_INT, false, RequireES<3>, NeverSupported, NeverSupported))); + map.insert(InternalFormatInfoPair(GL_RGB32UI, RGBAFormat(32, 32, 32, 0, 0, GL_RGB_INTEGER, GL_UNSIGNED_INT, GL_UNSIGNED_INT, false, RequireES<3>, NeverSupported, NeverSupported))); + map.insert(InternalFormatInfoPair(GL_RGBA8I, RGBAFormat( 8, 8, 8, 8, 0, GL_RGBA_INTEGER, GL_BYTE, GL_INT, false, RequireES<3>, RequireES<3>, NeverSupported))); + map.insert(InternalFormatInfoPair(GL_RGBA8UI, RGBAFormat( 8, 8, 8, 8, 0, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE, GL_UNSIGNED_INT, false, RequireES<3>, RequireES<3>, NeverSupported))); + map.insert(InternalFormatInfoPair(GL_RGBA16I, RGBAFormat(16, 16, 16, 16, 0, GL_RGBA_INTEGER, GL_SHORT, GL_INT, false, RequireES<3>, RequireES<3>, NeverSupported))); + map.insert(InternalFormatInfoPair(GL_RGBA16UI, RGBAFormat(16, 16, 16, 16, 0, GL_RGBA_INTEGER, GL_UNSIGNED_SHORT, GL_UNSIGNED_INT, false, RequireES<3>, RequireES<3>, NeverSupported))); + map.insert(InternalFormatInfoPair(GL_RGBA32I, RGBAFormat(32, 32, 32, 32, 0, GL_RGBA_INTEGER, GL_INT, GL_INT, false, RequireES<3>, RequireES<3>, NeverSupported))); + map.insert(InternalFormatInfoPair(GL_RGBA32UI, RGBAFormat(32, 32, 32, 32, 0, GL_RGBA_INTEGER, GL_UNSIGNED_INT, GL_UNSIGNED_INT, false, RequireES<3>, RequireES<3>, NeverSupported))); + + map.insert(InternalFormatInfoPair(GL_BGRA8_EXT, RGBAFormat( 8, 8, 8, 8, 0, GL_BGRA_EXT, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, false, RequireExt<&Extensions::textureFormatBGRA8888>, RequireExt<&Extensions::textureFormatBGRA8888>, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_BGRA4_ANGLEX, RGBAFormat( 4, 4, 4, 4, 0, GL_BGRA_EXT, GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT, GL_UNSIGNED_NORMALIZED, false, RequireExt<&Extensions::textureFormatBGRA8888>, RequireExt<&Extensions::textureFormatBGRA8888>, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_BGR5_A1_ANGLEX, RGBAFormat( 5, 5, 5, 1, 0, GL_BGRA_EXT, GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT, GL_UNSIGNED_NORMALIZED, false, RequireExt<&Extensions::textureFormatBGRA8888>, RequireExt<&Extensions::textureFormatBGRA8888>, AlwaysSupported))); + + // Floating point renderability and filtering is provided by OES_texture_float and OES_texture_half_float + // | Internal format | | D |S | Format | Type | Comp | SRGB | Texture supported | Renderable | Filterable | + // | | | | | | | type | | | | | + map.insert(InternalFormatInfoPair(GL_R16F, RGBAFormat(16, 0, 0, 0, 0, GL_RED, GL_HALF_FLOAT, GL_FLOAT, false, RequireESOrExtAndExt<3, &Extensions::textureHalfFloat, &Extensions::textureRG>, RequireESOrExtAndExt<3, &Extensions::textureHalfFloat, &Extensions::textureRG>, RequireExt<&Extensions::textureHalfFloatLinear>))); + map.insert(InternalFormatInfoPair(GL_RG16F, RGBAFormat(16, 16, 0, 0, 0, GL_RG, GL_HALF_FLOAT, GL_FLOAT, false, RequireESOrExtAndExt<3, &Extensions::textureHalfFloat, &Extensions::textureRG>, RequireESOrExtAndExt<3, &Extensions::textureHalfFloat, &Extensions::textureRG>, RequireExt<&Extensions::textureHalfFloatLinear>))); + map.insert(InternalFormatInfoPair(GL_RGB16F, RGBAFormat(16, 16, 16, 0, 0, GL_RGB, GL_HALF_FLOAT, GL_FLOAT, false, RequireESOrExt<3, &Extensions::textureHalfFloat>, RequireESOrExt<3, &Extensions::textureHalfFloat>, RequireExt<&Extensions::textureHalfFloatLinear>))); + map.insert(InternalFormatInfoPair(GL_RGBA16F, RGBAFormat(16, 16, 16, 16, 0, GL_RGBA, GL_HALF_FLOAT, GL_FLOAT, false, RequireESOrExt<3, &Extensions::textureHalfFloat>, RequireESOrExt<3, &Extensions::textureHalfFloat>, RequireExt<&Extensions::textureHalfFloatLinear>))); + map.insert(InternalFormatInfoPair(GL_R32F, RGBAFormat(32, 0, 0, 0, 0, GL_RED, GL_FLOAT, GL_FLOAT, false, RequireESOrExtAndExt<3, &Extensions::textureFloat, &Extensions::textureRG>, RequireESOrExtAndExt<3, &Extensions::textureFloat, &Extensions::textureRG>, RequireExt<&Extensions::textureFloatLinear> ))); + map.insert(InternalFormatInfoPair(GL_RG32F, RGBAFormat(32, 32, 0, 0, 0, GL_RG, GL_FLOAT, GL_FLOAT, false, RequireESOrExtAndExt<3, &Extensions::textureFloat, &Extensions::textureRG>, RequireESOrExtAndExt<3, &Extensions::textureFloat, &Extensions::textureRG>, RequireExt<&Extensions::textureFloatLinear> ))); + map.insert(InternalFormatInfoPair(GL_RGB32F, RGBAFormat(32, 32, 32, 0, 0, GL_RGB, GL_FLOAT, GL_FLOAT, false, RequireESOrExt<3, &Extensions::textureFloat>, RequireESOrExt<3, &Extensions::textureFloat>, RequireExt<&Extensions::textureFloatLinear> ))); + map.insert(InternalFormatInfoPair(GL_RGBA32F, RGBAFormat(32, 32, 32, 32, 0, GL_RGBA, GL_FLOAT, GL_FLOAT, false, RequireESOrExt<3, &Extensions::textureFloat>, RequireESOrExt<3, &Extensions::textureFloat>, RequireExt<&Extensions::textureFloatLinear> ))); + + // Depth stencil formats + // | Internal format | | D |S | X | Format | Type | Component type | Supported | Renderable | Filterable | + map.insert(InternalFormatInfoPair(GL_DEPTH_COMPONENT16, DepthStencilFormat(16, 0, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, GL_UNSIGNED_NORMALIZED, RequireES<2>, RequireES<2>, RequireESOrExt<3, &Extensions::depthTextures>))); + map.insert(InternalFormatInfoPair(GL_DEPTH_COMPONENT24, DepthStencilFormat(24, 0, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, GL_UNSIGNED_NORMALIZED, RequireES<3>, RequireES<3>, RequireESOrExt<3, &Extensions::depthTextures>))); + map.insert(InternalFormatInfoPair(GL_DEPTH_COMPONENT32F, DepthStencilFormat(32, 0, 0, GL_DEPTH_COMPONENT, GL_FLOAT, GL_FLOAT, RequireES<3>, RequireES<3>, RequireESOrExt<3, &Extensions::depthTextures>))); + map.insert(InternalFormatInfoPair(GL_DEPTH_COMPONENT32_OES, DepthStencilFormat(32, 0, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, GL_UNSIGNED_NORMALIZED, RequireExt<&Extensions::depthTextures>, RequireExt<&Extensions::depthTextures>, AlwaysSupported ))); + map.insert(InternalFormatInfoPair(GL_DEPTH24_STENCIL8, DepthStencilFormat(24, 8, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, GL_UNSIGNED_NORMALIZED, RequireESOrExt<3, &Extensions::depthTextures>, RequireESOrExtOrExt<3, &Extensions::depthTextures, &Extensions::packedDepthStencil>, AlwaysSupported ))); + map.insert(InternalFormatInfoPair(GL_DEPTH32F_STENCIL8, DepthStencilFormat(32, 8, 24, GL_DEPTH_STENCIL, GL_FLOAT_32_UNSIGNED_INT_24_8_REV, GL_FLOAT, RequireES<3>, RequireES<3>, AlwaysSupported ))); + // STENCIL_INDEX8 is special-cased, see around the bottom of the list. + + // Luminance alpha formats + // | Internal format | | L | A | Format | Type | Component type | Supported | Renderable | Filterable | + map.insert(InternalFormatInfoPair(GL_ALPHA8_EXT, LUMAFormat( 0, 8, GL_ALPHA, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, RequireExt<&Extensions::textureStorage>, NeverSupported, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_LUMINANCE8_EXT, LUMAFormat( 8, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, RequireExt<&Extensions::textureStorage>, NeverSupported, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_ALPHA32F_EXT, LUMAFormat( 0, 32, GL_ALPHA, GL_FLOAT, GL_FLOAT, RequireExtAndExt<&Extensions::textureStorage, &Extensions::textureFloat>, NeverSupported, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_LUMINANCE32F_EXT, LUMAFormat(32, 0, GL_LUMINANCE, GL_FLOAT, GL_FLOAT, RequireExtAndExt<&Extensions::textureStorage, &Extensions::textureFloat>, NeverSupported, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_ALPHA16F_EXT, LUMAFormat( 0, 16, GL_ALPHA, GL_HALF_FLOAT, GL_FLOAT, RequireExtAndExt<&Extensions::textureStorage, &Extensions::textureHalfFloat>, NeverSupported, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_LUMINANCE16F_EXT, LUMAFormat(16, 0, GL_LUMINANCE, GL_HALF_FLOAT, GL_FLOAT, RequireExtAndExt<&Extensions::textureStorage, &Extensions::textureHalfFloat>, NeverSupported, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_LUMINANCE8_ALPHA8_EXT, LUMAFormat( 8, 8, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, RequireExt<&Extensions::textureStorage>, NeverSupported, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_LUMINANCE_ALPHA32F_EXT, LUMAFormat(32, 32, GL_LUMINANCE_ALPHA, GL_FLOAT, GL_FLOAT, RequireExtAndExt<&Extensions::textureStorage, &Extensions::textureFloat>, NeverSupported, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_LUMINANCE_ALPHA16F_EXT, LUMAFormat(16, 16, GL_LUMINANCE_ALPHA, GL_HALF_FLOAT, GL_FLOAT, RequireExtAndExt<&Extensions::textureStorage, &Extensions::textureHalfFloat>, NeverSupported, AlwaysSupported))); + + // Unsized formats + // | Internal format | | Format | Supported | Renderable | Filterable | + map.insert(InternalFormatInfoPair(GL_ALPHA, UnsizedFormat(GL_ALPHA, RequireES<2>, NeverSupported, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_LUMINANCE, UnsizedFormat(GL_LUMINANCE, RequireES<2>, NeverSupported, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_LUMINANCE_ALPHA, UnsizedFormat(GL_LUMINANCE_ALPHA, RequireES<2>, NeverSupported, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_RED, UnsizedFormat(GL_RED, RequireESOrExt<3, &Extensions::textureRG>, NeverSupported, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_RG, UnsizedFormat(GL_RG, RequireESOrExt<3, &Extensions::textureRG>, NeverSupported, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_RGB, UnsizedFormat(GL_RGB, RequireES<2>, RequireES<2>, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_RGBA, UnsizedFormat(GL_RGBA, RequireES<2>, RequireES<2>, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_RED_INTEGER, UnsizedFormat(GL_RED_INTEGER, RequireES<3>, NeverSupported, NeverSupported ))); + map.insert(InternalFormatInfoPair(GL_RG_INTEGER, UnsizedFormat(GL_RG_INTEGER, RequireES<3>, NeverSupported, NeverSupported ))); + map.insert(InternalFormatInfoPair(GL_RGB_INTEGER, UnsizedFormat(GL_RGB_INTEGER, RequireES<3>, NeverSupported, NeverSupported ))); + map.insert(InternalFormatInfoPair(GL_RGBA_INTEGER, UnsizedFormat(GL_RGBA_INTEGER, RequireES<3>, NeverSupported, NeverSupported ))); + map.insert(InternalFormatInfoPair(GL_BGRA_EXT, UnsizedFormat(GL_BGRA_EXT, RequireExt<&Extensions::textureFormatBGRA8888>, RequireExt<&Extensions::textureFormatBGRA8888>, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_DEPTH_COMPONENT, UnsizedFormat(GL_DEPTH_COMPONENT, RequireES<2>, RequireES<2>, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_DEPTH_STENCIL, UnsizedFormat(GL_DEPTH_STENCIL, RequireESOrExt<3, &Extensions::packedDepthStencil>, RequireESOrExt<3, &Extensions::packedDepthStencil>, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_SRGB_EXT, UnsizedFormat(GL_RGB, RequireESOrExt<3, &Extensions::sRGB>, NeverSupported, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_SRGB_ALPHA_EXT, UnsizedFormat(GL_RGBA, RequireESOrExt<3, &Extensions::sRGB>, RequireESOrExt<3, &Extensions::sRGB>, AlwaysSupported))); + + // Compressed formats, From ES 3.0.1 spec, table 3.16 + // | Internal format | |W |H | BS |CC| Format | Type | SRGB | Supported | Renderable | Filterable | + map.insert(InternalFormatInfoPair(GL_COMPRESSED_R11_EAC, CompressedFormat(4, 4, 64, 1, GL_COMPRESSED_R11_EAC, GL_UNSIGNED_BYTE, false, UnimplementedSupport, UnimplementedSupport, UnimplementedSupport))); + map.insert(InternalFormatInfoPair(GL_COMPRESSED_SIGNED_R11_EAC, CompressedFormat(4, 4, 64, 1, GL_COMPRESSED_SIGNED_R11_EAC, GL_UNSIGNED_BYTE, false, UnimplementedSupport, UnimplementedSupport, UnimplementedSupport))); + map.insert(InternalFormatInfoPair(GL_COMPRESSED_RG11_EAC, CompressedFormat(4, 4, 128, 2, GL_COMPRESSED_RG11_EAC, GL_UNSIGNED_BYTE, false, UnimplementedSupport, UnimplementedSupport, UnimplementedSupport))); + map.insert(InternalFormatInfoPair(GL_COMPRESSED_SIGNED_RG11_EAC, CompressedFormat(4, 4, 128, 2, GL_COMPRESSED_SIGNED_RG11_EAC, GL_UNSIGNED_BYTE, false, UnimplementedSupport, UnimplementedSupport, UnimplementedSupport))); + map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGB8_ETC2, CompressedFormat(4, 4, 64, 3, GL_COMPRESSED_RGB8_ETC2, GL_UNSIGNED_BYTE, false, UnimplementedSupport, UnimplementedSupport, UnimplementedSupport))); + map.insert(InternalFormatInfoPair(GL_COMPRESSED_SRGB8_ETC2, CompressedFormat(4, 4, 64, 3, GL_COMPRESSED_SRGB8_ETC2, GL_UNSIGNED_BYTE, true, UnimplementedSupport, UnimplementedSupport, UnimplementedSupport))); + map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2, CompressedFormat(4, 4, 64, 3, GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2, GL_UNSIGNED_BYTE, false, UnimplementedSupport, UnimplementedSupport, UnimplementedSupport))); + map.insert(InternalFormatInfoPair(GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2, CompressedFormat(4, 4, 64, 3, GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2, GL_UNSIGNED_BYTE, true, UnimplementedSupport, UnimplementedSupport, UnimplementedSupport))); + map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGBA8_ETC2_EAC, CompressedFormat(4, 4, 128, 4, GL_COMPRESSED_RGBA8_ETC2_EAC, GL_UNSIGNED_BYTE, false, UnimplementedSupport, UnimplementedSupport, UnimplementedSupport))); + map.insert(InternalFormatInfoPair(GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC, CompressedFormat(4, 4, 128, 4, GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC, GL_UNSIGNED_BYTE, true, UnimplementedSupport, UnimplementedSupport, UnimplementedSupport))); + + // From GL_EXT_texture_compression_dxt1 + // | Internal format | |W |H | BS |CC| Format | Type | SRGB | Supported | Renderable | Filterable | + map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGB_S3TC_DXT1_EXT, CompressedFormat(4, 4, 64, 3, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_UNSIGNED_BYTE, false, RequireExt<&Extensions::textureCompressionDXT1>, NeverSupported, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, CompressedFormat(4, 4, 64, 4, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, GL_UNSIGNED_BYTE, false, RequireExt<&Extensions::textureCompressionDXT1>, NeverSupported, AlwaysSupported))); + + // From GL_ANGLE_texture_compression_dxt3 + map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE, CompressedFormat(4, 4, 128, 4, GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE, GL_UNSIGNED_BYTE, false, RequireExt<&Extensions::textureCompressionDXT5>, NeverSupported, AlwaysSupported))); + + // From GL_ANGLE_texture_compression_dxt5 + map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE, CompressedFormat(4, 4, 128, 4, GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE, GL_UNSIGNED_BYTE, false, RequireExt<&Extensions::textureCompressionDXT5>, NeverSupported, AlwaysSupported))); + + // For STENCIL_INDEX8 we chose a normalized component type for the following reasons: + // - Multisampled buffer are disallowed for non-normalized integer component types and we want to support it for STENCIL_INDEX8 + // - All other stencil formats (all depth-stencil) are either float or normalized + // - It affects only validation of internalformat in RenderbufferStorageMultisample. + // | Internal format | |D |S |X | Format | Type | Component type | Supported | Renderable | Filterable | + map.insert(InternalFormatInfoPair(GL_STENCIL_INDEX8, DepthStencilFormat(0, 8, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, RequireES<2>, RequireES<2>, NeverSupported))); + + return map; +} + +static const InternalFormatInfoMap &GetInternalFormatMap() +{ + static const InternalFormatInfoMap formatMap = BuildInternalFormatInfoMap(); + return formatMap; +} + +static FormatSet BuildAllSizedInternalFormatSet() +{ + FormatSet result; + + const InternalFormatInfoMap &formats = GetInternalFormatMap(); + for (InternalFormatInfoMap::const_iterator i = formats.begin(); i != formats.end(); i++) + { + if (i->second.pixelBytes > 0) + { + result.insert(i->first); + } + } + + return result; +} + +const Type &GetTypeInfo(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + case GL_BYTE: + { + static const Type info = GenTypeInfo(1, false); + return info; + } + case GL_UNSIGNED_SHORT: + case GL_SHORT: + case GL_HALF_FLOAT: + case GL_HALF_FLOAT_OES: + { + static const Type info = GenTypeInfo(2, false); + return info; + } + case GL_UNSIGNED_INT: + case GL_INT: + case GL_FLOAT: + { + static const Type info = GenTypeInfo(4, false); + return info; + } + case GL_UNSIGNED_SHORT_5_6_5: + case GL_UNSIGNED_SHORT_4_4_4_4: + case GL_UNSIGNED_SHORT_5_5_5_1: + case GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT: + case GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT: + { + static const Type info = GenTypeInfo(2, true); + return info; + } + case GL_UNSIGNED_INT_2_10_10_10_REV: + case GL_UNSIGNED_INT_24_8: + case GL_UNSIGNED_INT_10F_11F_11F_REV: + case GL_UNSIGNED_INT_5_9_9_9_REV: + { + ASSERT(GL_UNSIGNED_INT_24_8_OES == GL_UNSIGNED_INT_24_8); + static const Type info = GenTypeInfo(4, true); + return info; + } + case GL_FLOAT_32_UNSIGNED_INT_24_8_REV: + { + static const Type info = GenTypeInfo(8, true); + return info; + } + default: + { + static const Type defaultInfo; + return defaultInfo; + } + } +} + +const InternalFormat &GetInternalFormatInfo(GLenum internalFormat) +{ + const InternalFormatInfoMap &formatMap = GetInternalFormatMap(); + InternalFormatInfoMap::const_iterator iter = formatMap.find(internalFormat); + if (iter != formatMap.end()) + { + return iter->second; + } + else + { + static const InternalFormat defaultInternalFormat; + return defaultInternalFormat; + } +} + +GLuint InternalFormat::computeRowPitch(GLenum formatType, GLsizei width, GLint alignment, GLint rowLength) const +{ + ASSERT(alignment > 0 && isPow2(alignment)); + GLuint rowBytes; + if (rowLength > 0) + { + ASSERT(!compressed); + rowBytes = pixelBytes * rowLength; + } + else + { + rowBytes = computeBlockSize(formatType, width, 1); + } + return rx::roundUp(rowBytes, static_cast(alignment)); +} + +GLuint InternalFormat::computeDepthPitch(GLenum formatType, GLsizei width, GLsizei height, GLint alignment, GLint rowLength) const +{ + return computeRowPitch(formatType, width, alignment, rowLength) * height; +} + +GLuint InternalFormat::computeBlockSize(GLenum formatType, GLsizei width, GLsizei height) const +{ + if (compressed) + { + GLsizei numBlocksWide = (width + compressedBlockWidth - 1) / compressedBlockWidth; + GLsizei numBlocksHight = (height + compressedBlockHeight - 1) / compressedBlockHeight; + return (pixelBytes * numBlocksWide * numBlocksHight); + } + else + { + const Type &typeInfo = GetTypeInfo(formatType); + if (typeInfo.specialInterpretation) + { + return typeInfo.bytes * width * height; + } + else + { + return componentCount * typeInfo.bytes * width * height; + } + } +} + +GLenum GetSizedInternalFormat(GLenum internalFormat, GLenum type) +{ + const InternalFormat& formatInfo = GetInternalFormatInfo(internalFormat); + if (formatInfo.pixelBytes > 0) + { + return internalFormat; + } + else + { + static const FormatMap formatMap = BuildFormatMap(); + FormatMap::const_iterator iter = formatMap.find(FormatTypePair(internalFormat, type)); + if (iter != formatMap.end()) + { + return iter->second; + } + else + { + return GL_NONE; + } + } +} + +const FormatSet &GetAllSizedInternalFormats() +{ + static FormatSet formatSet = BuildAllSizedInternalFormatSet(); + return formatSet; +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/formatutils.h b/src/3rdparty/angle/src/libANGLE/formatutils.h new file mode 100644 index 0000000000..37d4a8f8ef --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/formatutils.h @@ -0,0 +1,81 @@ +// +// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// formatutils.h: Queries for GL image formats. + +#ifndef LIBANGLE_FORMATUTILS_H_ +#define LIBANGLE_FORMATUTILS_H_ + +#include "libANGLE/Caps.h" +#include "libANGLE/angletypes.h" + +#include "angle_gl.h" + +#include +#include + +namespace gl +{ + +struct Type +{ + Type(); + + GLuint bytes; + GLuint bytesShift; // Bit shift by this value to effectively divide/multiply by "bytes" in a more optimal way + bool specialInterpretation; +}; +const Type &GetTypeInfo(GLenum type); + +struct InternalFormat +{ + InternalFormat(); + + GLuint redBits; + GLuint greenBits; + GLuint blueBits; + + GLuint luminanceBits; + + GLuint alphaBits; + GLuint sharedBits; + + GLuint depthBits; + GLuint stencilBits; + + GLuint pixelBytes; + + GLuint componentCount; + + bool compressed; + GLuint compressedBlockWidth; + GLuint compressedBlockHeight; + + GLenum format; + GLenum type; + + GLenum componentType; + GLenum colorEncoding; + + typedef bool (*SupportCheckFunction)(GLuint, const Extensions &); + SupportCheckFunction textureSupport; + SupportCheckFunction renderSupport; + SupportCheckFunction filterSupport; + + GLuint computeRowPitch(GLenum formatType, GLsizei width, GLint alignment, GLint rowLength) const; + GLuint computeDepthPitch(GLenum formatType, GLsizei width, GLsizei height, GLint alignment, GLint rowLength) const; + GLuint computeBlockSize(GLenum formatType, GLsizei width, GLsizei height) const; +}; +const InternalFormat &GetInternalFormatInfo(GLenum internalFormat); + +GLenum GetSizedInternalFormat(GLenum internalFormat, GLenum type); + +typedef std::set FormatSet; +const FormatSet &GetAllSizedInternalFormats(); + +} + +#endif // LIBANGLE_FORMATUTILS_H_ diff --git a/src/3rdparty/angle/src/libANGLE/queryconversions.cpp b/src/3rdparty/angle/src/libANGLE/queryconversions.cpp new file mode 100644 index 0000000000..460e346eac --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/queryconversions.cpp @@ -0,0 +1,147 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// queryconversions.cpp: Implementation of state query cast conversions + +#include "libANGLE/Context.h" +#include "common/utilities.h" + +namespace gl +{ + +// Helper class for converting a GL type to a GLenum: +// We can't use CastStateValueEnum generally, because of GLboolean + GLubyte overlap. +// We restrict our use to CastStateValue, where it eliminates duplicate parameters. + +template +struct CastStateValueEnum { static GLenum mEnumForType; }; + +template <> GLenum CastStateValueEnum::mEnumForType = GL_INT; +template <> GLenum CastStateValueEnum::mEnumForType = GL_UNSIGNED_INT; +template <> GLenum CastStateValueEnum::mEnumForType = GL_BOOL; +template <> GLenum CastStateValueEnum::mEnumForType = GL_INT_64_ANGLEX; +template <> GLenum CastStateValueEnum::mEnumForType = GL_FLOAT; + +template +QueryT CastStateValueToInt(GLenum pname, NativeT value) +{ + GLenum queryType = CastStateValueEnum::mEnumForType; + GLenum nativeType = CastStateValueEnum::mEnumForType; + + if (nativeType == GL_FLOAT) + { + // RGBA color values and DepthRangeF values are converted to integer using Equation 2.4 from Table 4.5 + if (pname == GL_DEPTH_RANGE || pname == GL_COLOR_CLEAR_VALUE || pname == GL_DEPTH_CLEAR_VALUE || pname == GL_BLEND_COLOR) + { + return static_cast((static_cast(0xFFFFFFFF) * value - 1.0f) / 2.0f); + } + else + { + return gl::iround(value); + } + } + + // Clamp 64-bit int values when casting to int + if (nativeType == GL_INT_64_ANGLEX && queryType == GL_INT) + { + GLint64 minIntValue = static_cast(std::numeric_limits::min()); + GLint64 maxIntValue = static_cast(std::numeric_limits::max()); + GLint64 clampedValue = std::max(std::min(static_cast(value), maxIntValue), minIntValue); + return static_cast(clampedValue); + } + + return static_cast(value); +} + +template +QueryT CastStateValue(GLenum pname, NativeT value) +{ + GLenum queryType = CastStateValueEnum::mEnumForType; + + switch (queryType) + { + case GL_INT: return CastStateValueToInt(pname, value); + case GL_INT_64_ANGLEX: return CastStateValueToInt(pname, value); + case GL_FLOAT: return static_cast(value); + case GL_BOOL: return (value == static_cast(0) ? GL_FALSE : GL_TRUE); + default: UNREACHABLE(); return 0; + } +} + +template +void CastStateValues(Context *context, GLenum nativeType, GLenum pname, + unsigned int numParams, QueryT *outParams) +{ + if (nativeType == GL_INT) + { + GLint *intParams = NULL; + intParams = new GLint[numParams]; + + context->getIntegerv(pname, intParams); + + for (unsigned int i = 0; i < numParams; ++i) + { + outParams[i] = CastStateValue(pname, intParams[i]); + } + + delete [] intParams; + } + else if (nativeType == GL_BOOL) + { + GLboolean *boolParams = NULL; + boolParams = new GLboolean[numParams]; + + context->getBooleanv(pname, boolParams); + + for (unsigned int i = 0; i < numParams; ++i) + { + outParams[i] = (boolParams[i] == GL_FALSE ? static_cast(0) : static_cast(1)); + } + + delete [] boolParams; + } + else if (nativeType == GL_FLOAT) + { + GLfloat *floatParams = NULL; + floatParams = new GLfloat[numParams]; + + context->getFloatv(pname, floatParams); + + for (unsigned int i = 0; i < numParams; ++i) + { + outParams[i] = CastStateValue(pname, floatParams[i]); + } + + delete [] floatParams; + } + else if (nativeType == GL_INT_64_ANGLEX) + { + GLint64 *int64Params = NULL; + int64Params = new GLint64[numParams]; + + context->getInteger64v(pname, int64Params); + + for (unsigned int i = 0; i < numParams; ++i) + { + outParams[i] = CastStateValue(pname, int64Params[i]); + } + + delete [] int64Params; + } + else UNREACHABLE(); +} + +// Explicit template instantiation (how we export template functions in different files) +// The calls below will make CastStateValues successfully link with the GL state query types +// The GL state query API types are: bool, int, uint, float, int64 + +template void CastStateValues(Context *, GLenum, GLenum, unsigned int, GLboolean *); +template void CastStateValues(Context *, GLenum, GLenum, unsigned int, GLint *); +template void CastStateValues(Context *, GLenum, GLenum, unsigned int, GLuint *); +template void CastStateValues(Context *, GLenum, GLenum, unsigned int, GLfloat *); +template void CastStateValues(Context *, GLenum, GLenum, unsigned int, GLint64 *); + +} diff --git a/src/3rdparty/angle/src/libANGLE/queryconversions.h b/src/3rdparty/angle/src/libANGLE/queryconversions.h new file mode 100644 index 0000000000..da7047f730 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/queryconversions.h @@ -0,0 +1,17 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// queryconversions.h: Declaration of state query cast conversions + +namespace gl +{ + +// The GL state query API types are: bool, int, uint, float, int64 +template +void CastStateValues(Context *context, GLenum nativeType, GLenum pname, + unsigned int numParams, QueryT *outParams); + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/BufferImpl.h b/src/3rdparty/angle/src/libANGLE/renderer/BufferImpl.h new file mode 100644 index 0000000000..9bc5eaff58 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/BufferImpl.h @@ -0,0 +1,38 @@ +// +// Copyright 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// BufferImpl.h: Defines the abstract rx::BufferImpl class. + +#ifndef LIBANGLE_RENDERER_BUFFERIMPL_H_ +#define LIBANGLE_RENDERER_BUFFERIMPL_H_ + +#include "common/angleutils.h" +#include "libANGLE/Buffer.h" + +#include + +namespace rx +{ + +class BufferImpl : angle::NonCopyable +{ + public: + virtual ~BufferImpl() { } + + virtual gl::Error setData(const void* data, size_t size, GLenum usage) = 0; + virtual gl::Error setSubData(const void* data, size_t size, size_t offset) = 0; + virtual gl::Error copySubData(BufferImpl* source, GLintptr sourceOffset, GLintptr destOffset, GLsizeiptr size) = 0; + virtual gl::Error map(size_t offset, size_t length, GLbitfield access, GLvoid **mapPtr) = 0; + virtual gl::Error unmap() = 0; + + // This method may not have a corresponding GL-backed function. It is necessary + // for validation, for certain indexed draw calls. + virtual gl::Error getData(const uint8_t **outData) = 0; +}; + +} + +#endif // LIBANGLE_RENDERER_BUFFERIMPL_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/CompilerImpl.h b/src/3rdparty/angle/src/libANGLE/renderer/CompilerImpl.h new file mode 100644 index 0000000000..ccc78d8c2a --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/CompilerImpl.h @@ -0,0 +1,30 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// CompilerImpl.h: Defines the rx::CompilerImpl class, an implementation interface +// for the gl::Compiler object. + +#include "common/angleutils.h" +#include "libANGLE/Error.h" + +#ifndef LIBANGLE_RENDERER_COMPILERIMPL_H_ +#define LIBANGLE_RENDERER_COMPILERIMPL_H_ + +namespace rx +{ + +class CompilerImpl : angle::NonCopyable +{ + public: + CompilerImpl() {} + virtual ~CompilerImpl() {} + + virtual gl::Error release() = 0; +}; + +} + +#endif // LIBANGLE_RENDERER_COMPILERIMPL_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/DisplayImpl.cpp b/src/3rdparty/angle/src/libANGLE/renderer/DisplayImpl.cpp new file mode 100644 index 0000000000..7713ee2d6d --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/DisplayImpl.cpp @@ -0,0 +1,58 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// DisplayImpl.cpp: Implementation methods of egl::Display + +#include "libANGLE/renderer/DisplayImpl.h" + +#include "libANGLE/Surface.h" + +namespace rx +{ + +DisplayImpl::DisplayImpl() + : mExtensionsInitialized(false), + mCapsInitialized(false) +{ +} + +DisplayImpl::~DisplayImpl() +{ + while (!mSurfaceSet.empty()) + { + destroySurface(*mSurfaceSet.begin()); + } +} + +void DisplayImpl::destroySurface(egl::Surface *surface) +{ + mSurfaceSet.erase(surface); + surface->release(); +} + +const egl::DisplayExtensions &DisplayImpl::getExtensions() const +{ + if (!mExtensionsInitialized) + { + generateExtensions(&mExtensions); + mExtensionsInitialized = true; + } + + return mExtensions; +} + +const egl::Caps &DisplayImpl::getCaps() const +{ + if (!mCapsInitialized) + { + generateCaps(&mCaps); + mCapsInitialized = true; + } + + return mCaps; +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/DisplayImpl.h b/src/3rdparty/angle/src/libANGLE/renderer/DisplayImpl.h new file mode 100644 index 0000000000..381fa67f71 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/DisplayImpl.h @@ -0,0 +1,99 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// DisplayImpl.h: Implementation methods of egl::Display + +#ifndef LIBANGLE_RENDERER_DISPLAYIMPL_H_ +#define LIBANGLE_RENDERER_DISPLAYIMPL_H_ + +#include "common/angleutils.h" +#include "libANGLE/Caps.h" +#include "libANGLE/Config.h" +#include "libANGLE/Error.h" +#include "libANGLE/renderer/Renderer.h" + +#include +#include + +namespace egl +{ +class AttributeMap; +class Display; +struct Config; +class Surface; +} + +namespace gl +{ +class Context; +} + +namespace rx +{ +class SurfaceImpl; +struct ConfigDesc; + +class DisplayImpl : angle::NonCopyable +{ + public: + DisplayImpl(); + virtual ~DisplayImpl(); + + virtual egl::Error initialize(egl::Display *display) = 0; + virtual void terminate() = 0; + + virtual egl::Error createWindowSurface(const egl::Config *configuration, EGLNativeWindowType window, const egl::AttributeMap &attribs, + SurfaceImpl **outSurface) = 0; + virtual egl::Error createPbufferSurface(const egl::Config *configuration, const egl::AttributeMap &attribs, + SurfaceImpl **outSurface) = 0; + virtual egl::Error createPbufferFromClientBuffer(const egl::Config *configuration, EGLClientBuffer shareHandle, + const egl::AttributeMap &attribs, SurfaceImpl **outSurface) = 0; + virtual egl::Error createPixmapSurface(const egl::Config *configuration, NativePixmapType nativePixmap, + const egl::AttributeMap &attribs, SurfaceImpl **outSurface) = 0; + virtual egl::Error createContext(const egl::Config *config, const gl::Context *shareContext, const egl::AttributeMap &attribs, + gl::Context **outContext) = 0; + + virtual egl::Error makeCurrent(egl::Surface *drawSurface, egl::Surface *readSurface, gl::Context *context) = 0; + + virtual egl::ConfigSet generateConfigs() const = 0; + + virtual bool isDeviceLost() const = 0; + virtual bool testDeviceLost() = 0; + virtual egl::Error restoreLostDevice() = 0; + + virtual bool isValidNativeWindow(EGLNativeWindowType window) const = 0; + + virtual std::string getVendorString() const = 0; + + const egl::Caps &getCaps() const; + + typedef std::set SurfaceSet; + const SurfaceSet &getSurfaceSet() const { return mSurfaceSet; } + SurfaceSet &getSurfaceSet() { return mSurfaceSet; } + + void destroySurface(egl::Surface *surface); + + const egl::DisplayExtensions &getExtensions() const; + + protected: + // Place the surface set here so it can be accessible for handling + // context loss events. (It is shared between the Display and Impl.) + SurfaceSet mSurfaceSet; + + private: + virtual void generateExtensions(egl::DisplayExtensions *outExtensions) const = 0; + virtual void generateCaps(egl::Caps *outCaps) const = 0; + + mutable bool mExtensionsInitialized; + mutable egl::DisplayExtensions mExtensions; + + mutable bool mCapsInitialized; + mutable egl::Caps mCaps; +}; + +} + +#endif // LIBANGLE_RENDERER_DISPLAYIMPL_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/FenceNVImpl.h b/src/3rdparty/angle/src/libANGLE/renderer/FenceNVImpl.h new file mode 100644 index 0000000000..3463921d6e --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/FenceNVImpl.h @@ -0,0 +1,34 @@ +// +// Copyright (c) 2015 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// FenceNVImpl.h: Defines the rx::FenceNVImpl class. + +#ifndef LIBANGLE_RENDERER_FENCENVIMPL_H_ +#define LIBANGLE_RENDERER_FENCENVIMPL_H_ + +#include "libANGLE/Error.h" + +#include "common/angleutils.h" + +#include "angle_gl.h" + +namespace rx +{ + +class FenceNVImpl : angle::NonCopyable +{ + public: + FenceNVImpl() { }; + virtual ~FenceNVImpl() { }; + + virtual gl::Error set() = 0; + virtual gl::Error test(bool flushCommandBuffer, GLboolean *outFinished) = 0; + virtual gl::Error finishFence(GLboolean *outFinished) = 0; +}; + +} + +#endif // LIBANGLE_RENDERER_FENCENVIMPL_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/FenceSyncImpl.h b/src/3rdparty/angle/src/libANGLE/renderer/FenceSyncImpl.h new file mode 100644 index 0000000000..321964113f --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/FenceSyncImpl.h @@ -0,0 +1,35 @@ +// +// Copyright (c) 2015 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// FenceSyncImpl.h: Defines the rx::FenceSyncImpl class. + +#ifndef LIBANGLE_RENDERER_FENCESYNCIMPL_H_ +#define LIBANGLE_RENDERER_FENCESYNCIMPL_H_ + +#include "libANGLE/Error.h" + +#include "common/angleutils.h" + +#include "angle_gl.h" + +namespace rx +{ + +class FenceSyncImpl : angle::NonCopyable +{ + public: + FenceSyncImpl() { }; + virtual ~FenceSyncImpl() { }; + + virtual gl::Error set() = 0; + virtual gl::Error clientWait(GLbitfield flags, GLuint64 timeout, GLenum *outResult) = 0; + virtual gl::Error serverWait(GLbitfield flags, GLuint64 timeout) = 0; + virtual gl::Error getStatus(GLint *outResult) = 0; +}; + +} + +#endif // LIBANGLE_RENDERER_FENCESYNCIMPL_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/FramebufferImpl.h b/src/3rdparty/angle/src/libANGLE/renderer/FramebufferImpl.h new file mode 100644 index 0000000000..728f949a0f --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/FramebufferImpl.h @@ -0,0 +1,68 @@ +// +// Copyright 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// FramebufferImpl.h: Defines the abstract rx::FramebufferImpl class. + +#ifndef LIBANGLE_RENDERER_FRAMEBUFFERIMPL_H_ +#define LIBANGLE_RENDERER_FRAMEBUFFERIMPL_H_ + +#include "angle_gl.h" +#include "common/angleutils.h" +#include "libANGLE/Error.h" +#include "libANGLE/Framebuffer.h" + +namespace gl +{ +class State; +class Framebuffer; +class FramebufferAttachment; +struct Rectangle; +} + +namespace rx +{ + +class FramebufferImpl : angle::NonCopyable +{ + public: + explicit FramebufferImpl(const gl::Framebuffer::Data &data) : mData(data) { } + virtual ~FramebufferImpl() { } + + virtual void setColorAttachment(size_t index, const gl::FramebufferAttachment *attachment) = 0; + virtual void setDepthAttachment(const gl::FramebufferAttachment *attachment) = 0; + virtual void setStencilAttachment(const gl::FramebufferAttachment *attachment) = 0; + virtual void setDepthStencilAttachment(const gl::FramebufferAttachment *attachment) = 0; + + virtual void setDrawBuffers(size_t count, const GLenum *buffers) = 0; + virtual void setReadBuffer(GLenum buffer) = 0; + + virtual gl::Error invalidate(size_t count, const GLenum *attachments) = 0; + virtual gl::Error invalidateSub(size_t count, const GLenum *attachments, const gl::Rectangle &area) = 0; + + virtual gl::Error clear(const gl::Data &data, GLbitfield mask) = 0; + virtual gl::Error clearBufferfv(const gl::State &state, GLenum buffer, GLint drawbuffer, const GLfloat *values) = 0; + virtual gl::Error clearBufferuiv(const gl::State &state, GLenum buffer, GLint drawbuffer, const GLuint *values) = 0; + virtual gl::Error clearBufferiv(const gl::State &state, GLenum buffer, GLint drawbuffer, const GLint *values) = 0; + virtual gl::Error clearBufferfi(const gl::State &state, GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil) = 0; + + virtual GLenum getImplementationColorReadFormat() const = 0; + virtual GLenum getImplementationColorReadType() const = 0; + virtual gl::Error readPixels(const gl::State &state, const gl::Rectangle &area, GLenum format, GLenum type, GLvoid *pixels) const = 0; + + virtual gl::Error blit(const gl::State &state, const gl::Rectangle &sourceArea, const gl::Rectangle &destArea, + GLbitfield mask, GLenum filter, const gl::Framebuffer *sourceFramebuffer) = 0; + + virtual GLenum checkStatus() const = 0; + + const gl::Framebuffer::Data &getData() const { return mData; } + + protected: + const gl::Framebuffer::Data &mData; +}; + +} + +#endif // LIBANGLE_RENDERER_FRAMEBUFFERIMPL_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/Image.h b/src/3rdparty/angle/src/libANGLE/renderer/Image.h new file mode 100644 index 0000000000..62d854c9b6 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/Image.h @@ -0,0 +1,77 @@ +// +// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Image.h: Defines the rx::Image class, an abstract base class for the +// renderer-specific classes which will define the interface to the underlying +// surfaces or resources. + +#ifndef LIBANGLE_RENDERER_IMAGE_H_ +#define LIBANGLE_RENDERER_IMAGE_H_ + +#include "common/debug.h" +#include "libANGLE/Error.h" + +#include + +namespace gl +{ +class Framebuffer; +struct Rectangle; +struct Extents; +struct Box; +struct Offset; +struct ImageIndex; +} + +namespace rx +{ +class RendererD3D; +class RenderTarget; +class TextureStorage; + +class Image +{ + public: + Image(); + virtual ~Image() {}; + + GLsizei getWidth() const { return mWidth; } + GLsizei getHeight() const { return mHeight; } + GLsizei getDepth() const { return mDepth; } + GLenum getInternalFormat() const { return mInternalFormat; } + GLenum getTarget() const { return mTarget; } + bool isRenderableFormat() const { return mRenderable; } + + void markDirty() {mDirty = true;} + void markClean() {mDirty = false;} + virtual bool isDirty() const = 0; + + virtual bool redefine(GLenum target, GLenum internalformat, const gl::Extents &size, bool forceRelease) = 0; + + virtual gl::Error loadData(const gl::Box &area, GLint unpackAlignment, GLenum type, const void *input) = 0; + virtual gl::Error loadCompressedData(const gl::Box &area, const void *input) = 0; + + virtual gl::Error copy(const gl::Offset &destOffset, const gl::Rectangle &sourceArea, const gl::Framebuffer *source) = 0; + virtual gl::Error copy(const gl::Offset &destOffset, const gl::Box &sourceArea, + const gl::ImageIndex &sourceIndex, TextureStorage *source) = 0; + + protected: + GLsizei mWidth; + GLsizei mHeight; + GLsizei mDepth; + GLenum mInternalFormat; + bool mRenderable; + GLenum mTarget; + + bool mDirty; + + private: + DISALLOW_COPY_AND_ASSIGN(Image); +}; + +} + +#endif // LIBANGLE_RENDERER_IMAGE_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/ImplFactory.h b/src/3rdparty/angle/src/libANGLE/renderer/ImplFactory.h new file mode 100644 index 0000000000..d77e59f7df --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/ImplFactory.h @@ -0,0 +1,68 @@ +// +// Copyright 2015 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// ImplFactory.h: +// Factory interface for Impl objects. +// + +#ifndef LIBANGLE_RENDERER_IMPLFACTORY_H_ +#define LIBANGLE_RENDERER_IMPLFACTORY_H_ + +#include "libANGLE/Framebuffer.h" + +namespace rx +{ +class BufferImpl; +class CompilerImpl; +class FenceNVImpl; +class FenceSyncImpl; +class FramebufferImpl; +class ProgramImpl; +class QueryImpl; +class RenderbufferImpl; +class ShaderImpl; +class TextureImpl; +class TransformFeedbackImpl; +class VertexArrayImpl; + +class ImplFactory : angle::NonCopyable +{ + public: + ImplFactory() {} + virtual ~ImplFactory() {} + + // Shader creation + virtual CompilerImpl *createCompiler(const gl::Data &data) = 0; + virtual ShaderImpl *createShader(GLenum type) = 0; + virtual ProgramImpl *createProgram() = 0; + + // Framebuffer creation + virtual FramebufferImpl *createDefaultFramebuffer(const gl::Framebuffer::Data &data) = 0; + virtual FramebufferImpl *createFramebuffer(const gl::Framebuffer::Data &data) = 0; + + // Texture creation + virtual TextureImpl *createTexture(GLenum target) = 0; + + // Renderbuffer creation + virtual RenderbufferImpl *createRenderbuffer() = 0; + + // Buffer creation + virtual BufferImpl *createBuffer() = 0; + + // Vertex Array creation + virtual VertexArrayImpl *createVertexArray() = 0; + + // Query and Fence creation + virtual QueryImpl *createQuery(GLenum type) = 0; + virtual FenceNVImpl *createFenceNV() = 0; + virtual FenceSyncImpl *createFenceSync() = 0; + + // Transform Feedback creation + virtual TransformFeedbackImpl *createTransformFeedback() = 0; +}; + +} + +#endif // LIBANGLE_RENDERER_IMPLFACTORY_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/IndexRangeCache.cpp b/src/3rdparty/angle/src/libANGLE/renderer/IndexRangeCache.cpp new file mode 100644 index 0000000000..4a71cf4b45 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/IndexRangeCache.cpp @@ -0,0 +1,114 @@ +// +// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// IndexRangeCache.cpp: Defines the rx::IndexRangeCache class which stores information about +// ranges of indices. + +#include "libANGLE/renderer/IndexRangeCache.h" +#include "libANGLE/formatutils.h" + +#include "common/debug.h" + +namespace rx +{ + +template +static RangeUI ComputeTypedRange(const IndexType *indices, GLsizei count) +{ + unsigned int minIndex = indices[0]; + unsigned int maxIndex = indices[0]; + + for (GLsizei i = 1; i < count; i++) + { + if (minIndex > indices[i]) minIndex = indices[i]; + if (maxIndex < indices[i]) maxIndex = indices[i]; + } + + return RangeUI(minIndex, maxIndex); +} + +RangeUI IndexRangeCache::ComputeRange(GLenum type, const GLvoid *indices, GLsizei count) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return ComputeTypedRange(static_cast(indices), count); + case GL_UNSIGNED_INT: + return ComputeTypedRange(static_cast(indices), count); + case GL_UNSIGNED_SHORT: + return ComputeTypedRange(static_cast(indices), count); + default: + UNREACHABLE(); + return RangeUI(); + } +} + +void IndexRangeCache::addRange(GLenum type, unsigned int offset, GLsizei count, const RangeUI &range) +{ + mIndexRangeCache[IndexRange(type, offset, count)] = range; +} + +void IndexRangeCache::invalidateRange(unsigned int offset, unsigned int size) +{ + unsigned int invalidateStart = offset; + unsigned int invalidateEnd = offset + size; + + IndexRangeMap::iterator i = mIndexRangeCache.begin(); + while (i != mIndexRangeCache.end()) + { + unsigned int rangeStart = i->first.offset; + unsigned int rangeEnd = i->first.offset + (gl::GetTypeInfo(i->first.type).bytes * i->first.count); + + if (invalidateEnd < rangeStart || invalidateStart > rangeEnd) + { + ++i; + } + else + { + mIndexRangeCache.erase(i++); + } + } +} + +bool IndexRangeCache::findRange(GLenum type, unsigned int offset, GLsizei count, + RangeUI *outRange) const +{ + IndexRangeMap::const_iterator i = mIndexRangeCache.find(IndexRange(type, offset, count)); + if (i != mIndexRangeCache.end()) + { + if (outRange) *outRange = i->second; + return true; + } + else + { + if (outRange) *outRange = RangeUI(0, 0); + return false; + } +} + +void IndexRangeCache::clear() +{ + mIndexRangeCache.clear(); +} + +IndexRangeCache::IndexRange::IndexRange() + : type(GL_NONE), offset(0), count(0) +{ +} + +IndexRangeCache::IndexRange::IndexRange(GLenum typ, intptr_t off, GLsizei c) + : type(typ), offset(off), count(c) +{ +} + +bool IndexRangeCache::IndexRange::operator<(const IndexRange& rhs) const +{ + if (type != rhs.type) return type < rhs.type; + if (offset != rhs.offset) return offset < rhs.offset; + return count < rhs.count; +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/IndexRangeCache.h b/src/3rdparty/angle/src/libANGLE/renderer/IndexRangeCache.h new file mode 100644 index 0000000000..77249f5ff6 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/IndexRangeCache.h @@ -0,0 +1,53 @@ +// +// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// IndexRangeCache.h: Defines the rx::IndexRangeCache class which stores information about +// ranges of indices. + +#ifndef LIBANGLE_RENDERER_INDEXRANGECACHE_H_ +#define LIBANGLE_RENDERER_INDEXRANGECACHE_H_ + +#include "common/angleutils.h" +#include "common/mathutil.h" + +#include "angle_gl.h" + +#include + +namespace rx +{ + +class IndexRangeCache +{ + public: + void addRange(GLenum type, unsigned int offset, GLsizei count, const RangeUI &range); + bool findRange(GLenum type, unsigned int offset, GLsizei count, RangeUI *rangeOut) const; + + void invalidateRange(unsigned int offset, unsigned int size); + void clear(); + + static RangeUI ComputeRange(GLenum type, const GLvoid *indices, GLsizei count); + + private: + struct IndexRange + { + GLenum type; + unsigned int offset; + GLsizei count; + + IndexRange(); + IndexRange(GLenum type, intptr_t offset, GLsizei count); + + bool operator<(const IndexRange& rhs) const; + }; + + typedef std::map IndexRangeMap; + IndexRangeMap mIndexRangeCache; +}; + +} + +#endif // LIBANGLE_RENDERER_INDEXRANGECACHE_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/ProgramImpl.cpp b/src/3rdparty/angle/src/libANGLE/renderer/ProgramImpl.cpp new file mode 100644 index 0000000000..8fbc53768f --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/ProgramImpl.cpp @@ -0,0 +1,152 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// ProgramD3D.cpp: Defines the rx::ProgramD3D class which implements rx::ProgramImpl. + +#include "libANGLE/renderer/ProgramImpl.h" + +#include "common/utilities.h" + +namespace rx +{ + +namespace +{ + +unsigned int ParseAndStripArrayIndex(std::string* name) +{ + unsigned int subscript = GL_INVALID_INDEX; + + // Strip any trailing array operator and retrieve the subscript + size_t open = name->find_last_of('['); + size_t close = name->find_last_of(']'); + if (open != std::string::npos && close == name->length() - 1) + { + subscript = atoi(name->substr(open + 1).c_str()); + name->erase(open); + } + + return subscript; +} + +} + +LinkResult::LinkResult(bool linkSuccess, const gl::Error &error) + : linkSuccess(linkSuccess), + error(error) +{ +} + +ProgramImpl::~ProgramImpl() +{ + // Ensure that reset was called by the inherited class during destruction + ASSERT(mUniformIndex.size() == 0); +} + +gl::LinkedUniform *ProgramImpl::getUniformByLocation(GLint location) const +{ + ASSERT(location >= 0 && static_cast(location) < mUniformIndex.size()); + return mUniforms[mUniformIndex[location].index]; +} + +gl::LinkedUniform *ProgramImpl::getUniformByName(const std::string &name) const +{ + for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++) + { + if (mUniforms[uniformIndex]->name == name) + { + return mUniforms[uniformIndex]; + } + } + + return NULL; +} + +gl::UniformBlock *ProgramImpl::getUniformBlockByIndex(GLuint blockIndex) const +{ + ASSERT(blockIndex < mUniformBlocks.size()); + return mUniformBlocks[blockIndex]; +} + +GLint ProgramImpl::getUniformLocation(std::string name) +{ + unsigned int subscript = ParseAndStripArrayIndex(&name); + + unsigned int numUniforms = mUniformIndex.size(); + for (unsigned int location = 0; location < numUniforms; location++) + { + if (mUniformIndex[location].name == name) + { + const int index = mUniformIndex[location].index; + const bool isArray = mUniforms[index]->isArray(); + + if ((isArray && mUniformIndex[location].element == subscript) || + (subscript == GL_INVALID_INDEX)) + { + return location; + } + } + } + + return -1; +} + +GLuint ProgramImpl::getUniformIndex(std::string name) +{ + unsigned int subscript = ParseAndStripArrayIndex(&name); + + // The app is not allowed to specify array indices other than 0 for arrays of basic types + if (subscript != 0 && subscript != GL_INVALID_INDEX) + { + return GL_INVALID_INDEX; + } + + unsigned int numUniforms = mUniforms.size(); + for (unsigned int index = 0; index < numUniforms; index++) + { + if (mUniforms[index]->name == name) + { + if (mUniforms[index]->isArray() || subscript == GL_INVALID_INDEX) + { + return index; + } + } + } + + return GL_INVALID_INDEX; +} + +GLuint ProgramImpl::getUniformBlockIndex(std::string name) const +{ + unsigned int subscript = ParseAndStripArrayIndex(&name); + + unsigned int numUniformBlocks = mUniformBlocks.size(); + for (unsigned int blockIndex = 0; blockIndex < numUniformBlocks; blockIndex++) + { + const gl::UniformBlock &uniformBlock = *mUniformBlocks[blockIndex]; + if (uniformBlock.name == name) + { + const bool arrayElementZero = (subscript == GL_INVALID_INDEX && uniformBlock.elementIndex == 0); + if (subscript == uniformBlock.elementIndex || arrayElementZero) + { + return blockIndex; + } + } + } + + return GL_INVALID_INDEX; +} + +void ProgramImpl::reset() +{ + std::fill(mSemanticIndex, mSemanticIndex + ArraySize(mSemanticIndex), -1); + SafeDeleteContainer(mUniforms); + mUniformIndex.clear(); + SafeDeleteContainer(mUniformBlocks); + mTransformFeedbackLinkedVaryings.clear(); +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/ProgramImpl.h b/src/3rdparty/angle/src/libANGLE/renderer/ProgramImpl.h new file mode 100644 index 0000000000..1128ab6741 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/ProgramImpl.h @@ -0,0 +1,137 @@ +// +// Copyright 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// ProgramImpl.h: Defines the abstract rx::ProgramImpl class. + +#ifndef LIBANGLE_RENDERER_PROGRAMIMPL_H_ +#define LIBANGLE_RENDERER_PROGRAMIMPL_H_ + +#include "common/angleutils.h" +#include "libANGLE/BinaryStream.h" +#include "libANGLE/Constants.h" +#include "libANGLE/Program.h" +#include "libANGLE/Shader.h" +#include "libANGLE/renderer/Renderer.h" + +#include + +namespace rx +{ + +struct LinkResult +{ + bool linkSuccess; + gl::Error error; + LinkResult(bool linkSuccess, const gl::Error &error); +}; + +class ProgramImpl : angle::NonCopyable +{ + public: + typedef int SemanticIndexArray[gl::MAX_VERTEX_ATTRIBS]; + + ProgramImpl() { } + virtual ~ProgramImpl(); + + virtual bool usesPointSize() const = 0; + virtual int getShaderVersion() const = 0; + virtual GLenum getTransformFeedbackBufferMode() const = 0; + + virtual GLenum getBinaryFormat() = 0; + virtual LinkResult load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream) = 0; + virtual gl::Error save(gl::BinaryOutputStream *stream) = 0; + + virtual LinkResult link(const gl::Data &data, gl::InfoLog &infoLog, + gl::Shader *fragmentShader, gl::Shader *vertexShader, + const std::vector &transformFeedbackVaryings, + GLenum transformFeedbackBufferMode, + int *registers, std::vector *linkedVaryings, + std::map *outputVariables) = 0; + + virtual void setUniform1fv(GLint location, GLsizei count, const GLfloat *v) = 0; + virtual void setUniform2fv(GLint location, GLsizei count, const GLfloat *v) = 0; + virtual void setUniform3fv(GLint location, GLsizei count, const GLfloat *v) = 0; + virtual void setUniform4fv(GLint location, GLsizei count, const GLfloat *v) = 0; + virtual void setUniform1iv(GLint location, GLsizei count, const GLint *v) = 0; + virtual void setUniform2iv(GLint location, GLsizei count, const GLint *v) = 0; + virtual void setUniform3iv(GLint location, GLsizei count, const GLint *v) = 0; + virtual void setUniform4iv(GLint location, GLsizei count, const GLint *v) = 0; + virtual void setUniform1uiv(GLint location, GLsizei count, const GLuint *v) = 0; + virtual void setUniform2uiv(GLint location, GLsizei count, const GLuint *v) = 0; + virtual void setUniform3uiv(GLint location, GLsizei count, const GLuint *v) = 0; + virtual void setUniform4uiv(GLint location, GLsizei count, const GLuint *v) = 0; + virtual void setUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) = 0; + virtual void setUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) = 0; + virtual void setUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) = 0; + virtual void setUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) = 0; + virtual void setUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) = 0; + virtual void setUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) = 0; + virtual void setUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) = 0; + virtual void setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) = 0; + virtual void setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) = 0; + + virtual void getUniformfv(GLint location, GLfloat *params) = 0; + virtual void getUniformiv(GLint location, GLint *params) = 0; + virtual void getUniformuiv(GLint location, GLuint *params) = 0; + + // TODO: The following functions are possibly only applicable to D3D backends. The should be carefully evaluated to + // determine if they can be removed from this interface. + virtual GLint getSamplerMapping(gl::SamplerType type, unsigned int samplerIndex, const gl::Caps &caps) const = 0; + virtual GLenum getSamplerTextureType(gl::SamplerType type, unsigned int samplerIndex) const = 0; + virtual GLint getUsedSamplerRange(gl::SamplerType type) const = 0; + virtual void updateSamplerMapping() = 0; + virtual bool validateSamplers(gl::InfoLog *infoLog, const gl::Caps &caps) = 0; + + virtual LinkResult compileProgramExecutables(gl::InfoLog &infoLog, gl::Shader *fragmentShader, gl::Shader *vertexShader, + int registers) = 0; + + virtual bool linkUniforms(gl::InfoLog &infoLog, const gl::Shader &vertexShader, const gl::Shader &fragmentShader, + const gl::Caps &caps) = 0; + virtual bool defineUniformBlock(gl::InfoLog &infoLog, const gl::Shader &shader, const sh::InterfaceBlock &interfaceBlock, + const gl::Caps &caps) = 0; + + virtual gl::Error applyUniforms() = 0; + virtual gl::Error applyUniformBuffers(const gl::Data &data, GLuint uniformBlockBindings[]) = 0; + virtual bool assignUniformBlockRegister(gl::InfoLog &infoLog, gl::UniformBlock *uniformBlock, GLenum shader, + unsigned int registerIndex, const gl::Caps &caps) = 0; + + const std::vector &getUniforms() const { return mUniforms; } + const std::vector &getUniformIndices() const { return mUniformIndex; } + const std::vector &getUniformBlocks() const { return mUniformBlocks; } + const std::vector &getTransformFeedbackLinkedVaryings() const { return mTransformFeedbackLinkedVaryings; } + const sh::Attribute *getShaderAttributes() const { return mShaderAttributes; } + const SemanticIndexArray &getSemanticIndexes() const { return mSemanticIndex; } + + std::vector &getUniforms() { return mUniforms; } + std::vector &getUniformIndices() { return mUniformIndex; } + std::vector &getUniformBlocks() { return mUniformBlocks; } + std::vector &getTransformFeedbackLinkedVaryings() { return mTransformFeedbackLinkedVaryings; } + sh::Attribute *getShaderAttributes() { return mShaderAttributes; } + SemanticIndexArray &getSemanticIndexes() { return mSemanticIndex; } + + gl::LinkedUniform *getUniformByLocation(GLint location) const; + gl::LinkedUniform *getUniformByName(const std::string &name) const; + gl::UniformBlock *getUniformBlockByIndex(GLuint blockIndex) const; + + GLint getUniformLocation(std::string name); + GLuint getUniformIndex(std::string name); + GLuint getUniformBlockIndex(std::string name) const; + + virtual void reset(); + + protected: + std::vector mUniforms; + std::vector mUniformIndex; + std::vector mUniformBlocks; + std::vector mTransformFeedbackLinkedVaryings; + + SemanticIndexArray mSemanticIndex; + sh::Attribute mShaderAttributes[gl::MAX_VERTEX_ATTRIBS]; +}; + +} + +#endif // LIBANGLE_RENDERER_PROGRAMIMPL_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/QueryImpl.h b/src/3rdparty/angle/src/libANGLE/renderer/QueryImpl.h new file mode 100644 index 0000000000..bed63ea1b0 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/QueryImpl.h @@ -0,0 +1,40 @@ +// +// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// QueryImpl.h: Defines the abstract rx::QueryImpl class. + +#ifndef LIBANGLE_RENDERER_QUERYIMPL_H_ +#define LIBANGLE_RENDERER_QUERYIMPL_H_ + +#include "libANGLE/Error.h" + +#include "common/angleutils.h" + +#include + +namespace rx +{ + +class QueryImpl : angle::NonCopyable +{ + public: + explicit QueryImpl(GLenum type) { mType = type; } + virtual ~QueryImpl() { } + + virtual gl::Error begin() = 0; + virtual gl::Error end() = 0; + virtual gl::Error getResult(GLuint *params) = 0; + virtual gl::Error isResultAvailable(GLuint *available) = 0; + + GLenum getType() const { return mType; } + + private: + GLenum mType; +}; + +} + +#endif // LIBANGLE_RENDERER_QUERYIMPL_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/RenderbufferImpl.cpp b/src/3rdparty/angle/src/libANGLE/renderer/RenderbufferImpl.cpp new file mode 100644 index 0000000000..ea5a40a21a --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/RenderbufferImpl.cpp @@ -0,0 +1,21 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// RenderbufferImpl.h: Implements the shared methods of the abstract class gl::RenderbufferImpl + +#include "libANGLE/renderer/RenderbufferImpl.h" + +namespace rx +{ +RenderbufferImpl::RenderbufferImpl() +{ +} + +RenderbufferImpl::~RenderbufferImpl() +{ +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/RenderbufferImpl.h b/src/3rdparty/angle/src/libANGLE/renderer/RenderbufferImpl.h new file mode 100644 index 0000000000..8ce257c833 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/RenderbufferImpl.h @@ -0,0 +1,33 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// RenderbufferImpl.h: Defines the abstract class gl::RenderbufferImpl + +#ifndef LIBANGLE_RENDERER_RENDERBUFFERIMPL_H_ +#define LIBANGLE_RENDERER_RENDERBUFFERIMPL_H_ + +#include "angle_gl.h" + +#include "libANGLE/Error.h" + +#include "common/angleutils.h" + +namespace rx +{ + +class RenderbufferImpl : angle::NonCopyable +{ + public: + RenderbufferImpl(); + virtual ~RenderbufferImpl() = 0; + + virtual gl::Error setStorage(GLenum internalformat, size_t width, size_t height) = 0; + virtual gl::Error setStorageMultisample(size_t samples, GLenum internalformat, size_t width, size_t height) = 0; +}; + +} + +#endif // LIBANGLE_RENDERER_RENDERBUFFERIMPL_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/Renderer.cpp b/src/3rdparty/angle/src/libANGLE/renderer/Renderer.cpp new file mode 100644 index 0000000000..fbc2ad5d1c --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/Renderer.cpp @@ -0,0 +1,72 @@ +// +// Copyright (c) 2012-2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Renderer.cpp: Implements EGL dependencies for creating and destroying Renderer instances. + +#include "common/utilities.h" +#include "libANGLE/AttributeMap.h" +#include "libANGLE/renderer/Renderer.h" + +#include + +namespace rx +{ + +Renderer::Renderer() + : mCapsInitialized(false), + mWorkaroundsInitialized(false) +{ +} + +Renderer::~Renderer() +{ +} + +const gl::Caps &Renderer::getRendererCaps() const +{ + if (!mCapsInitialized) + { + generateCaps(&mCaps, &mTextureCaps, &mExtensions); + mCapsInitialized = true; + } + + return mCaps; +} + +const gl::TextureCapsMap &Renderer::getRendererTextureCaps() const +{ + if (!mCapsInitialized) + { + generateCaps(&mCaps, &mTextureCaps, &mExtensions); + mCapsInitialized = true; + } + + return mTextureCaps; +} + +const gl::Extensions &Renderer::getRendererExtensions() const +{ + if (!mCapsInitialized) + { + generateCaps(&mCaps, &mTextureCaps, &mExtensions); + mCapsInitialized = true; + } + + return mExtensions; +} + +const Workarounds &Renderer::getWorkarounds() const +{ + if (!mWorkaroundsInitialized) + { + mWorkarounds = generateWorkarounds(); + mWorkaroundsInitialized = true; + } + + return mWorkarounds; +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/Renderer.h b/src/3rdparty/angle/src/libANGLE/renderer/Renderer.h new file mode 100644 index 0000000000..b607fe5613 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/Renderer.h @@ -0,0 +1,91 @@ +// +// Copyright (c) 2012-2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Renderer.h: Defines a back-end specific class that hides the details of the +// implementation-specific renderer. + +#ifndef LIBANGLE_RENDERER_RENDERER_H_ +#define LIBANGLE_RENDERER_RENDERER_H_ + +#include "libANGLE/Caps.h" +#include "libANGLE/Error.h" +#include "libANGLE/Framebuffer.h" +#include "libANGLE/Uniform.h" +#include "libANGLE/angletypes.h" +#include "libANGLE/renderer/ImplFactory.h" +#include "libANGLE/renderer/Workarounds.h" +#include "common/mathutil.h" + +#include + +#include + +namespace egl +{ +class AttributeMap; +class Display; +class Surface; +} + +namespace gl +{ +class Buffer; +struct Data; +} + +namespace rx +{ +struct TranslatedIndexData; +struct Workarounds; +class DisplayImpl; + +class Renderer : public ImplFactory +{ + public: + Renderer(); + virtual ~Renderer(); + + virtual gl::Error flush() = 0; + virtual gl::Error finish() = 0; + + virtual gl::Error drawArrays(const gl::Data &data, GLenum mode, + GLint first, GLsizei count, GLsizei instances) = 0; + virtual gl::Error drawElements(const gl::Data &data, GLenum mode, GLsizei count, GLenum type, + const GLvoid *indices, GLsizei instances, + const RangeUI &indexRange) = 0; + + // lost device + //TODO(jmadill): investigate if this stuff is necessary in GL + virtual void notifyDeviceLost() = 0; + virtual bool isDeviceLost() const = 0; + virtual bool testDeviceLost() = 0; + virtual bool testDeviceResettable() = 0; + + virtual VendorID getVendorId() const = 0; + virtual std::string getVendorString() const = 0; + virtual std::string getRendererDescription() const = 0; + + // Renderer capabilities + const gl::Caps &getRendererCaps() const; + const gl::TextureCapsMap &getRendererTextureCaps() const; + const gl::Extensions &getRendererExtensions() const; + const Workarounds &getWorkarounds() const; + + private: + virtual void generateCaps(gl::Caps *outCaps, gl::TextureCapsMap* outTextureCaps, gl::Extensions *outExtensions) const = 0; + virtual Workarounds generateWorkarounds() const = 0; + + mutable bool mCapsInitialized; + mutable gl::Caps mCaps; + mutable gl::TextureCapsMap mTextureCaps; + mutable gl::Extensions mExtensions; + + mutable bool mWorkaroundsInitialized; + mutable Workarounds mWorkarounds; +}; + +} +#endif // LIBANGLE_RENDERER_RENDERER_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/ShaderImpl.h b/src/3rdparty/angle/src/libANGLE/renderer/ShaderImpl.h new file mode 100644 index 0000000000..3011bc57f8 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/ShaderImpl.h @@ -0,0 +1,57 @@ +// +// Copyright 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// ShaderImpl.h: Defines the abstract rx::ShaderImpl class. + +#ifndef LIBANGLE_RENDERER_SHADERIMPL_H_ +#define LIBANGLE_RENDERER_SHADERIMPL_H_ + +#include + +#include "common/angleutils.h" +#include "libANGLE/Shader.h" + +namespace rx +{ + +class ShaderImpl : angle::NonCopyable +{ + public: + ShaderImpl() { } + virtual ~ShaderImpl() { } + + virtual bool compile(gl::Compiler *compiler, const std::string &source) = 0; + virtual std::string getDebugInfo() const = 0; + + virtual const std::string &getInfoLog() const { return mInfoLog; } + virtual const std::string &getTranslatedSource() const { return mTranslatedSource; } + + const std::vector &getVaryings() const { return mVaryings; } + const std::vector &getUniforms() const { return mUniforms; } + const std::vector &getInterfaceBlocks() const { return mInterfaceBlocks; } + const std::vector &getActiveAttributes() const { return mActiveAttributes; } + const std::vector &getActiveOutputVariables() const { return mActiveOutputVariables; } + + std::vector &getVaryings() { return mVaryings; } + std::vector &getUniforms() { return mUniforms; } + std::vector &getInterfaceBlocks() { return mInterfaceBlocks; } + std::vector &getActiveAttributes() { return mActiveAttributes; } + std::vector &getActiveOutputVariables() { return mActiveOutputVariables; } + + protected: + std::string mInfoLog; + std::string mTranslatedSource; + + std::vector mVaryings; + std::vector mUniforms; + std::vector mInterfaceBlocks; + std::vector mActiveAttributes; + std::vector mActiveOutputVariables; +}; + +} + +#endif // LIBANGLE_RENDERER_SHADERIMPL_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/SurfaceImpl.cpp b/src/3rdparty/angle/src/libANGLE/renderer/SurfaceImpl.cpp new file mode 100644 index 0000000000..36f5fdca3f --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/SurfaceImpl.cpp @@ -0,0 +1,22 @@ +// +// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// SurfaceImpl.cpp: Implementation of Surface stub method class + +#include "libANGLE/renderer/SurfaceImpl.h" + +namespace rx +{ + +SurfaceImpl::SurfaceImpl() +{ +} + +SurfaceImpl::~SurfaceImpl() +{ +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/SurfaceImpl.h b/src/3rdparty/angle/src/libANGLE/renderer/SurfaceImpl.h new file mode 100644 index 0000000000..ca04a42bd1 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/SurfaceImpl.h @@ -0,0 +1,48 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// SurfaceImpl.h: Implementation methods of egl::Surface + +#ifndef LIBANGLE_RENDERER_SURFACEIMPL_H_ +#define LIBANGLE_RENDERER_SURFACEIMPL_H_ + +#include "common/angleutils.h" +#include "libANGLE/Error.h" + +namespace egl +{ +class Display; +struct Config; +} + +namespace rx +{ + +class SurfaceImpl : angle::NonCopyable +{ + public: + SurfaceImpl(); + virtual ~SurfaceImpl(); + + virtual egl::Error initialize() = 0; + virtual egl::Error swap() = 0; + virtual egl::Error postSubBuffer(EGLint x, EGLint y, EGLint width, EGLint height) = 0; + virtual egl::Error querySurfacePointerANGLE(EGLint attribute, void **value) = 0; + virtual egl::Error bindTexImage(EGLint buffer) = 0; + virtual egl::Error releaseTexImage(EGLint buffer) = 0; + virtual void setSwapInterval(EGLint interval) = 0; + + // width and height can change with client window resizing + virtual EGLint getWidth() const = 0; + virtual EGLint getHeight() const = 0; + + virtual EGLint isPostSubBufferSupported() const = 0; +}; + +} + +#endif // LIBANGLE_RENDERER_SURFACEIMPL_H_ + diff --git a/src/3rdparty/angle/src/libANGLE/renderer/TextureImpl.h b/src/3rdparty/angle/src/libANGLE/renderer/TextureImpl.h new file mode 100644 index 0000000000..d628906116 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/TextureImpl.h @@ -0,0 +1,72 @@ +// +// Copyright 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// TextureImpl.h: Defines the abstract rx::TextureImpl classes. + +#ifndef LIBANGLE_RENDERER_TEXTUREIMPL_H_ +#define LIBANGLE_RENDERER_TEXTUREIMPL_H_ + +#include "libANGLE/Error.h" +#include "libANGLE/ImageIndex.h" + +#include "common/angleutils.h" + +#include "angle_gl.h" + +#include + +namespace egl +{ +class Surface; +} + +namespace gl +{ +struct Box; +struct Extents; +struct Offset; +struct Rectangle; +class Framebuffer; +struct PixelUnpackState; +struct SamplerState; +} + +namespace rx +{ + +class TextureImpl : angle::NonCopyable +{ + public: + virtual ~TextureImpl() {}; + + virtual void setUsage(GLenum usage) = 0; + + virtual gl::Error setImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size, GLenum format, GLenum type, + const gl::PixelUnpackState &unpack, const uint8_t *pixels) = 0; + virtual gl::Error setSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format, GLenum type, + const gl::PixelUnpackState &unpack, const uint8_t *pixels) = 0; + + virtual gl::Error setCompressedImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size, + const gl::PixelUnpackState &unpack, const uint8_t *pixels) = 0; + virtual gl::Error setCompressedSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format, + const gl::PixelUnpackState &unpack, const uint8_t *pixels) = 0; + + virtual gl::Error copyImage(GLenum target, size_t level, const gl::Rectangle &sourceArea, GLenum internalFormat, + const gl::Framebuffer *source) = 0; + virtual gl::Error copySubImage(GLenum target, size_t level, const gl::Offset &destOffset, const gl::Rectangle &sourceArea, + const gl::Framebuffer *source) = 0; + + virtual gl::Error setStorage(GLenum target, size_t levels, GLenum internalFormat, const gl::Extents &size) = 0; + + virtual gl::Error generateMipmaps() = 0; + + virtual void bindTexImage(egl::Surface *surface) = 0; + virtual void releaseTexImage() = 0; +}; + +} + +#endif // LIBANGLE_RENDERER_TEXTUREIMPL_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/TransformFeedbackImpl.h b/src/3rdparty/angle/src/libANGLE/renderer/TransformFeedbackImpl.h new file mode 100644 index 0000000000..8f9133cfe5 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/TransformFeedbackImpl.h @@ -0,0 +1,31 @@ +// +// Copyright 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// TransformFeedbackImpl.h: Defines the abstract rx::TransformFeedbackImpl class. + +#ifndef LIBANGLE_RENDERER_TRANSFORMFEEDBACKIMPL_H_ +#define LIBANGLE_RENDERER_TRANSFORMFEEDBACKIMPL_H_ + +#include "common/angleutils.h" +#include "libANGLE/TransformFeedback.h" + +namespace rx +{ + +class TransformFeedbackImpl : angle::NonCopyable +{ + public: + virtual ~TransformFeedbackImpl() { } + + virtual void begin(GLenum primitiveMode) = 0; + virtual void end() = 0; + virtual void pause() = 0; + virtual void resume() = 0; +}; + +} + +#endif // LIBANGLE_RENDERER_TRANSFORMFEEDBACKIMPL_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/VertexArrayImpl.h b/src/3rdparty/angle/src/libANGLE/renderer/VertexArrayImpl.h new file mode 100644 index 0000000000..0e25f952c2 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/VertexArrayImpl.h @@ -0,0 +1,32 @@ +// +// Copyright 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// VertexAttribImpl.h: Defines the abstract rx::VertexAttribImpl class. + +#ifndef LIBANGLE_RENDERER_VERTEXARRAYIMPL_H_ +#define LIBANGLE_RENDERER_VERTEXARRAYIMPL_H_ + +#include "common/angleutils.h" +#include "libANGLE/Buffer.h" +#include "libANGLE/VertexAttribute.h" + +namespace rx +{ + +class VertexArrayImpl : angle::NonCopyable +{ + public: + virtual ~VertexArrayImpl() { } + + virtual void setElementArrayBuffer(const gl::Buffer *buffer) = 0; + virtual void setAttribute(size_t idx, const gl::VertexAttribute &attr) = 0; + virtual void setAttributeDivisor(size_t idx, GLuint divisor) = 0; + virtual void enableAttribute(size_t idx, bool enabledState) = 0; +}; + +} + +#endif // LIBANGLE_RENDERER_VERTEXARRAYIMPL_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/Workarounds.h b/src/3rdparty/angle/src/libANGLE/renderer/Workarounds.h new file mode 100644 index 0000000000..b73f4a5472 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/Workarounds.h @@ -0,0 +1,74 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// angletypes.h: Workarounds for driver bugs and other issues. + +#ifndef LIBANGLE_RENDERER_WORKAROUNDS_H_ +#define LIBANGLE_RENDERER_WORKAROUNDS_H_ + +// TODO(jmadill,zmo,geofflang): make a workarounds library that can operate +// independent of ANGLE's renderer. Workarounds should also be accessible +// outside of the Renderer. + +namespace rx +{ + +struct D3DCompilerWorkarounds : angle::NonCopyable +{ + D3DCompilerWorkarounds() + : skipOptimization(false), + useMaxOptimization(false), + enableIEEEStrictness(false) + {} + + void reset() + { + skipOptimization = false; + useMaxOptimization = false; + enableIEEEStrictness = false; + } + + bool skipOptimization; + bool useMaxOptimization; + + // IEEE strictness needs to be enabled for NANs to work. + bool enableIEEEStrictness; +}; + +struct Workarounds +{ + Workarounds() + : mrtPerfWorkaround(false), + setDataFasterThanImageUpload(false), + zeroMaxLodWorkaround(false), + useInstancedPointSpriteEmulation(false) + {} + + // On some systems, having extra rendertargets than necessary slows down the shader. + // We can fix this by optimizing those out of the shader. At the same time, we can + // work around a bug on some nVidia drivers that they ignore "null" render targets + // in D3D11, by compacting the active color attachments list to omit null entries. + bool mrtPerfWorkaround; + + bool setDataFasterThanImageUpload; + + // Some renderers can't disable mipmaps on a mipmapped texture (i.e. solely sample from level zero, and ignore the other levels). + // D3D11 Feature Level 10+ does this by setting MaxLOD to 0.0f in the Sampler state. D3D9 sets D3DSAMP_MIPFILTER to D3DTEXF_NONE. + // There is no equivalent to this in D3D11 Feature Level 9_3. + // This causes problems when (for example) an application creates a mipmapped texture2D, but sets GL_TEXTURE_MIN_FILTER to GL_NEAREST (i.e disables mipmaps). + // To work around this, D3D11 FL9_3 has to create two copies of the texture. The textures' level zeros are identical, but only one texture has mips. + bool zeroMaxLodWorkaround; + + // Some renderers do not support Geometry Shaders so the Geometry Shader-based + // PointSprite emulation will not work. + // To work around this, D3D11 FL9_3 has to use a different pointsprite + // emulation that is implemented using instanced quads. + bool useInstancedPointSpriteEmulation; +}; + +} + +#endif // LIBANGLE_RENDERER_WORKAROUNDS_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/BufferD3D.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/BufferD3D.cpp new file mode 100644 index 0000000000..1af8794356 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/BufferD3D.cpp @@ -0,0 +1,80 @@ +// +// Copyright 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// BufferD3D.cpp Defines common functionality between the Buffer9 and Buffer11 classes. + +#include "libANGLE/renderer/d3d/BufferD3D.h" + +#include "libANGLE/renderer/d3d/IndexBuffer.h" +#include "libANGLE/renderer/d3d/VertexBuffer.h" + +namespace rx +{ + +unsigned int BufferD3D::mNextSerial = 1; + +BufferD3D::BufferD3D(BufferFactoryD3D *factory) + : BufferImpl(), + mFactory(factory), + mStaticVertexBuffer(nullptr), + mStaticIndexBuffer(nullptr), + mUnmodifiedDataUse(0) +{ + updateSerial(); +} + +BufferD3D::~BufferD3D() +{ + SafeDelete(mStaticVertexBuffer); + SafeDelete(mStaticIndexBuffer); +} + +void BufferD3D::updateSerial() +{ + mSerial = mNextSerial++; +} + +void BufferD3D::initializeStaticData() +{ + if (!mStaticVertexBuffer) + { + mStaticVertexBuffer = new StaticVertexBufferInterface(mFactory); + } + if (!mStaticIndexBuffer) + { + mStaticIndexBuffer = new StaticIndexBufferInterface(mFactory); + } +} + +void BufferD3D::invalidateStaticData() +{ + if ((mStaticVertexBuffer && mStaticVertexBuffer->getBufferSize() != 0) || (mStaticIndexBuffer && mStaticIndexBuffer->getBufferSize() != 0)) + { + SafeDelete(mStaticVertexBuffer); + SafeDelete(mStaticIndexBuffer); + + // Re-init static data to track that we're in a static buffer + initializeStaticData(); + } + + mUnmodifiedDataUse = 0; +} + +// Creates static buffers if sufficient used data has been left unmodified +void BufferD3D::promoteStaticUsage(int dataSize) +{ + if (!mStaticVertexBuffer && !mStaticIndexBuffer) + { + mUnmodifiedDataUse += dataSize; + + if (mUnmodifiedDataUse > 3 * getSize()) + { + initializeStaticData(); + } + } +} + +} \ No newline at end of file diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/BufferD3D.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/BufferD3D.h new file mode 100644 index 0000000000..a46398f911 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/BufferD3D.h @@ -0,0 +1,56 @@ +// +// Copyright 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// BufferD3D.h: Defines the rx::BufferD3D class, an implementation of BufferImpl. + +#ifndef LIBANGLE_RENDERER_D3D_BUFFERD3D_H_ +#define LIBANGLE_RENDERER_D3D_BUFFERD3D_H_ + +#include "libANGLE/renderer/BufferImpl.h" +#include "libANGLE/angletypes.h" + +#include + +namespace rx +{ +class BufferFactoryD3D; +class StaticIndexBufferInterface; +class StaticVertexBufferInterface; + +class BufferD3D : public BufferImpl +{ + public: + BufferD3D(BufferFactoryD3D *factory); + virtual ~BufferD3D(); + + unsigned int getSerial() const { return mSerial; } + + virtual size_t getSize() const = 0; + virtual bool supportsDirectBinding() const = 0; + virtual void markTransformFeedbackUsage() = 0; + + StaticVertexBufferInterface *getStaticVertexBuffer() { return mStaticVertexBuffer; } + StaticIndexBufferInterface *getStaticIndexBuffer() { return mStaticIndexBuffer; } + + void initializeStaticData(); + void invalidateStaticData(); + void promoteStaticUsage(int dataSize); + + protected: + void updateSerial(); + + BufferFactoryD3D *mFactory; + unsigned int mSerial; + static unsigned int mNextSerial; + + StaticVertexBufferInterface *mStaticVertexBuffer; + StaticIndexBufferInterface *mStaticIndexBuffer; + unsigned int mUnmodifiedDataUse; +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_BUFFERD3D_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/CompilerD3D.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/CompilerD3D.cpp new file mode 100644 index 0000000000..a22757cf9f --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/CompilerD3D.cpp @@ -0,0 +1,128 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// CompilerD3D.cpp: Implementation of the rx::CompilerD3D class. + +#include "libANGLE/renderer/d3d/CompilerD3D.h" + +#include "libANGLE/Caps.h" +#include "libANGLE/Data.h" + +#include "common/debug.h" + +namespace rx +{ + +// Global count of active shader compiler handles. Needed to know when to call ShInitialize and ShFinalize. +static size_t activeCompilerHandles = 0; + +CompilerD3D::CompilerD3D(const gl::Data &data, ShShaderOutput outputType) + : mSpec(data.clientVersion > 2 ? SH_GLES3_SPEC : SH_GLES2_SPEC), + mOutputType(outputType), + mResources(), + mFragmentCompiler(NULL), + mVertexCompiler(NULL) +{ + ASSERT(data.clientVersion == 2 || data.clientVersion == 3); + + const gl::Caps &caps = *data.caps; + const gl::Extensions &extensions = *data.extensions; + + ShInitBuiltInResources(&mResources); + mResources.MaxVertexAttribs = caps.maxVertexAttributes; + mResources.MaxVertexUniformVectors = caps.maxVertexUniformVectors; + mResources.MaxVaryingVectors = caps.maxVaryingVectors; + mResources.MaxVertexTextureImageUnits = caps.maxVertexTextureImageUnits; + mResources.MaxCombinedTextureImageUnits = caps.maxCombinedTextureImageUnits; + mResources.MaxTextureImageUnits = caps.maxTextureImageUnits; + mResources.MaxFragmentUniformVectors = caps.maxFragmentUniformVectors; + mResources.MaxDrawBuffers = caps.maxDrawBuffers; + mResources.OES_standard_derivatives = extensions.standardDerivatives; + mResources.EXT_draw_buffers = extensions.drawBuffers; + mResources.EXT_shader_texture_lod = 1; + // resources.OES_EGL_image_external = mRenderer->getShareHandleSupport() ? 1 : 0; // TODO: commented out until the extension is actually supported. + mResources.FragmentPrecisionHigh = 1; // Shader Model 2+ always supports FP24 (s16e7) which corresponds to highp + mResources.EXT_frag_depth = 1; // Shader Model 2+ always supports explicit depth output + + // GLSL ES 3.0 constants + mResources.MaxVertexOutputVectors = caps.maxVertexOutputComponents / 4; + mResources.MaxFragmentInputVectors = caps.maxFragmentInputComponents / 4; + mResources.MinProgramTexelOffset = caps.minProgramTexelOffset; + mResources.MaxProgramTexelOffset = caps.maxProgramTexelOffset; +} + +CompilerD3D::~CompilerD3D() +{ + release(); +} + +CompilerD3D *CompilerD3D::makeCompilerD3D(CompilerImpl *compiler) +{ + ASSERT(HAS_DYNAMIC_TYPE(CompilerD3D*, compiler)); + return static_cast(compiler); +} + +gl::Error CompilerD3D::release() +{ + if (mFragmentCompiler) + { + ShDestruct(mFragmentCompiler); + mFragmentCompiler = NULL; + + ASSERT(activeCompilerHandles > 0); + activeCompilerHandles--; + } + + if (mVertexCompiler) + { + ShDestruct(mVertexCompiler); + mVertexCompiler = NULL; + + ASSERT(activeCompilerHandles > 0); + activeCompilerHandles--; + } + + if (activeCompilerHandles == 0) + { + ShFinalize(); + } + + return gl::Error(GL_NO_ERROR); +} + +ShHandle CompilerD3D::getCompilerHandle(GLenum type) +{ + ShHandle *compiler = NULL; + switch (type) + { + case GL_VERTEX_SHADER: + compiler = &mVertexCompiler; + break; + + case GL_FRAGMENT_SHADER: + compiler = &mFragmentCompiler; + break; + + default: + UNREACHABLE(); + return NULL; + } + + if (!(*compiler)) + { + if (activeCompilerHandles == 0) + { + ShInitialize(); + } + + *compiler = ShConstructCompiler(type, mSpec, mOutputType, &mResources); + activeCompilerHandles++; + } + + return *compiler; +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/CompilerD3D.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/CompilerD3D.h new file mode 100644 index 0000000000..0f83e4f8c8 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/CompilerD3D.h @@ -0,0 +1,48 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// CompilerD3D.h: Defines the rx::CompilerD3D class, an implementation of rx::CompilerImpl. + +#ifndef LIBANGLE_RENDERER_COMPILERD3D_H_ +#define LIBANGLE_RENDERER_COMPILERD3D_H_ + +#include "libANGLE/renderer/CompilerImpl.h" +#include "libANGLE/Caps.h" + +#include "GLSLANG/ShaderLang.h" + +namespace gl +{ +struct Data; +} + +namespace rx +{ + +class CompilerD3D : public CompilerImpl +{ + public: + CompilerD3D(const gl::Data &data, ShShaderOutput outputType); + virtual ~CompilerD3D(); + + static CompilerD3D *makeCompilerD3D(CompilerImpl *compiler); + + gl::Error release() override; + + ShHandle getCompilerHandle(GLenum type); + + private: + ShShaderSpec mSpec; + ShShaderOutput mOutputType; + ShBuiltInResources mResources; + + ShHandle mFragmentCompiler; + ShHandle mVertexCompiler; +}; + +} + +#endif // LIBANGLE_RENDERER_COMPILERD3D_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/DisplayD3D.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/DisplayD3D.cpp new file mode 100644 index 0000000000..add5d62fae --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/DisplayD3D.cpp @@ -0,0 +1,357 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// DisplayD3D.cpp: D3D implementation of egl::Display + +#include "libANGLE/renderer/d3d/DisplayD3D.h" + +#include "libANGLE/Context.h" +#include "libANGLE/Config.h" +#include "libANGLE/Display.h" +#include "libANGLE/Surface.h" +#include "libANGLE/renderer/d3d/RendererD3D.h" +#include "libANGLE/renderer/d3d/SurfaceD3D.h" +#include "libANGLE/renderer/d3d/SwapChainD3D.h" +#include "platform/Platform.h" + +#include + +#if defined (ANGLE_ENABLE_D3D9) +# include "libANGLE/renderer/d3d/d3d9/Renderer9.h" +#endif // ANGLE_ENABLE_D3D9 + +#if defined (ANGLE_ENABLE_D3D11) +# include "libANGLE/renderer/d3d/d3d11/Renderer11.h" +#endif // ANGLE_ENABLE_D3D11 + +#if defined (ANGLE_TEST_CONFIG) +# define ANGLE_DEFAULT_D3D11 1 +#endif + +#if !defined(ANGLE_DEFAULT_D3D11) +// Enables use of the Direct3D 11 API for a default display, when available +# define ANGLE_DEFAULT_D3D11 0 +#endif + +namespace rx +{ + +typedef RendererD3D *(*CreateRendererD3DFunction)(egl::Display*); + +template +static RendererD3D *CreateTypedRendererD3D(egl::Display *display) +{ + return new RendererType(display); +} + +egl::Error CreateRendererD3D(egl::Display *display, RendererD3D **outRenderer) +{ + ASSERT(outRenderer != nullptr); + + std::vector rendererCreationFunctions; + + const auto &attribMap = display->getAttributeMap(); + EGLNativeDisplayType nativeDisplay = display->getNativeDisplayId(); + + EGLint requestedDisplayType = attribMap.get(EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE); + +# if defined(ANGLE_ENABLE_D3D11) + if (nativeDisplay == EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE || + nativeDisplay == EGL_D3D11_ONLY_DISPLAY_ANGLE || + requestedDisplayType == EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE) + { + rendererCreationFunctions.push_back(CreateTypedRendererD3D); + } +# endif + +# if defined(ANGLE_ENABLE_D3D9) + if (nativeDisplay == EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE || + requestedDisplayType == EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE) + { + rendererCreationFunctions.push_back(CreateTypedRendererD3D); + } +# endif + + if (nativeDisplay != EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE && + nativeDisplay != EGL_D3D11_ONLY_DISPLAY_ANGLE && + requestedDisplayType == EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE) + { + // The default display is requested, try the D3D9 and D3D11 renderers, order them using + // the definition of ANGLE_DEFAULT_D3D11 +# if ANGLE_DEFAULT_D3D11 +# if defined(ANGLE_ENABLE_D3D11) + rendererCreationFunctions.push_back(CreateTypedRendererD3D); +# endif +# if defined(ANGLE_ENABLE_D3D9) + rendererCreationFunctions.push_back(CreateTypedRendererD3D); +# endif +# else +# if defined(ANGLE_ENABLE_D3D9) + rendererCreationFunctions.push_back(CreateTypedRendererD3D); +# endif +# if defined(ANGLE_ENABLE_D3D11) + rendererCreationFunctions.push_back(CreateTypedRendererD3D); +# endif +# endif + } + + egl::Error result(EGL_NOT_INITIALIZED, "No available renderers."); + for (size_t i = 0; i < rendererCreationFunctions.size(); i++) + { + RendererD3D *renderer = rendererCreationFunctions[i](display); + result = renderer->initialize(); + +# if defined(ANGLE_ENABLE_D3D11) + if (renderer->getRendererClass() == RENDERER_D3D11) + { + ASSERT(result.getID() >= 0 && result.getID() < NUM_D3D11_INIT_ERRORS); + + angle::Platform *platform = ANGLEPlatformCurrent(); + platform->histogramEnumeration("GPU.ANGLE.D3D11InitializeResult", + result.getID(), NUM_D3D11_INIT_ERRORS); + } +# endif + +# if defined(ANGLE_ENABLE_D3D9) + if (renderer->getRendererClass() == RENDERER_D3D9) + { + ASSERT(result.getID() >= 0 && result.getID() < NUM_D3D9_INIT_ERRORS); + + angle::Platform *platform = ANGLEPlatformCurrent(); + platform->histogramEnumeration("GPU.ANGLE.D3D9InitializeResult", + result.getID(), NUM_D3D9_INIT_ERRORS); + } +# endif + + if (!result.isError()) + { + *outRenderer = renderer; + break; + } + else + { + // Failed to create the renderer, try the next + SafeDelete(renderer); + } + } + + return result; +} + +DisplayD3D::DisplayD3D() + : mRenderer(nullptr) +{ +} + +egl::Error DisplayD3D::createWindowSurface(const egl::Config *configuration, EGLNativeWindowType window, + const egl::AttributeMap &attribs, SurfaceImpl **outSurface) +{ + ASSERT(mRenderer != nullptr); + + EGLint width = attribs.get(EGL_WIDTH, 0); + EGLint height = attribs.get(EGL_HEIGHT, 0); + EGLint fixedSize = attribs.get(EGL_FIXED_SIZE_ANGLE, EGL_FALSE); + + if (!fixedSize) + { + width = -1; + height = -1; + } + + SurfaceD3D *surface = SurfaceD3D::createFromWindow(mRenderer, mDisplay, configuration, window, fixedSize, + width, height); + egl::Error error = surface->initialize(); + if (error.isError()) + { + SafeDelete(surface); + return error; + } + + *outSurface = surface; + return egl::Error(EGL_SUCCESS); +} + +egl::Error DisplayD3D::createPbufferSurface(const egl::Config *configuration, const egl::AttributeMap &attribs, + SurfaceImpl **outSurface) +{ + ASSERT(mRenderer != nullptr); + + EGLint width = attribs.get(EGL_WIDTH, 0); + EGLint height = attribs.get(EGL_HEIGHT, 0); + + SurfaceD3D *surface = SurfaceD3D::createOffscreen(mRenderer, mDisplay, configuration, NULL, width, height); + egl::Error error = surface->initialize(); + if (error.isError()) + { + SafeDelete(surface); + return error; + } + + *outSurface = surface; + return egl::Error(EGL_SUCCESS); +} + +egl::Error DisplayD3D::createPbufferFromClientBuffer(const egl::Config *configuration, EGLClientBuffer shareHandle, + const egl::AttributeMap &attribs, SurfaceImpl **outSurface) +{ + ASSERT(mRenderer != nullptr); + + EGLint width = attribs.get(EGL_WIDTH, 0); + EGLint height = attribs.get(EGL_HEIGHT, 0); + + SurfaceD3D *surface = SurfaceD3D::createOffscreen(mRenderer, mDisplay, configuration, shareHandle, + width, height); + egl::Error error = surface->initialize(); + if (error.isError()) + { + SafeDelete(surface); + return error; + } + + *outSurface = surface; + return egl::Error(EGL_SUCCESS); +} + +egl::Error DisplayD3D::createPixmapSurface(const egl::Config *configuration, NativePixmapType nativePixmap, + const egl::AttributeMap &attribs, SurfaceImpl **outSurface) +{ + ASSERT(mRenderer != nullptr); + + UNIMPLEMENTED(); + *outSurface = nullptr; + return egl::Error(EGL_BAD_DISPLAY); +} + +egl::Error DisplayD3D::createContext(const egl::Config *config, const gl::Context *shareContext, const egl::AttributeMap &attribs, + gl::Context **outContext) +{ + ASSERT(mRenderer != nullptr); + + EGLint clientVersion = attribs.get(EGL_CONTEXT_CLIENT_VERSION, 1); + bool notifyResets = (attribs.get(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT, EGL_NO_RESET_NOTIFICATION_EXT) == EGL_LOSE_CONTEXT_ON_RESET_EXT); + bool robustAccess = (attribs.get(EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT, EGL_FALSE) == EGL_TRUE); + + *outContext = new gl::Context(config, clientVersion, shareContext, mRenderer, notifyResets, robustAccess); + return egl::Error(EGL_SUCCESS); +} + +egl::Error DisplayD3D::makeCurrent(egl::Surface *drawSurface, egl::Surface *readSurface, gl::Context *context) +{ + return egl::Error(EGL_SUCCESS); +} + +egl::Error DisplayD3D::initialize(egl::Display *display) +{ + ASSERT(mRenderer == nullptr && display != nullptr); + mDisplay = display; + return CreateRendererD3D(display, &mRenderer); +} + +void DisplayD3D::terminate() +{ + SafeDelete(mRenderer); +} + +egl::ConfigSet DisplayD3D::generateConfigs() const +{ + ASSERT(mRenderer != nullptr); + return mRenderer->generateConfigs(); +} + +bool DisplayD3D::isDeviceLost() const +{ + ASSERT(mRenderer != nullptr); + return mRenderer->isDeviceLost(); +} + +bool DisplayD3D::testDeviceLost() +{ + ASSERT(mRenderer != nullptr); + return mRenderer->testDeviceLost(); +} + +egl::Error DisplayD3D::restoreLostDevice() +{ + // Release surface resources to make the Reset() succeed + for (auto it = mSurfaceSet.cbegin(); it != mSurfaceSet.cend(); ++it) + { + const auto &surface = *it; + if (surface->getBoundTexture()) + { + surface->releaseTexImage(EGL_BACK_BUFFER); + } + SurfaceD3D *surfaceD3D = GetImplAs(surface); + surfaceD3D->releaseSwapChain(); + } + + if (!mRenderer->resetDevice()) + { + return egl::Error(EGL_BAD_ALLOC); + } + + // Restore any surfaces that may have been lost + for (auto it = mSurfaceSet.cbegin(); it != mSurfaceSet.cend(); ++it) + { + const auto &surface = *it; + SurfaceD3D *surfaceD3D = GetImplAs(surface); + + egl::Error error = surfaceD3D->resetSwapChain(); + if (error.isError()) + { + return error; + } + } + + return egl::Error(EGL_SUCCESS); +} + +bool DisplayD3D::isValidNativeWindow(EGLNativeWindowType window) const +{ + return NativeWindow::isValidNativeWindow(window); +} + +void DisplayD3D::generateExtensions(egl::DisplayExtensions *outExtensions) const +{ + outExtensions->createContextRobustness = true; + + // ANGLE-specific extensions + if (mRenderer->getShareHandleSupport()) + { + outExtensions->d3dShareHandleClientBuffer = true; + outExtensions->surfaceD3DTexture2DShareHandle = true; + } + + outExtensions->querySurfacePointer = true; + outExtensions->windowFixedSize = true; + + if (mRenderer->getPostSubBufferSupport()) + { + outExtensions->postSubBuffer = true; + } + + outExtensions->createContext = true; +} + +std::string DisplayD3D::getVendorString() const +{ + std::string vendorString = "Google Inc."; + if (mRenderer) + { + vendorString += " " + mRenderer->getVendorString(); + } + + return vendorString; +} + +void DisplayD3D::generateCaps(egl::Caps *outCaps) const +{ + // Display must be initialized to generate caps + ASSERT(mRenderer != nullptr); + + outCaps->textureNPOT = mRenderer->getRendererExtensions().textureNPOT; +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/DisplayD3D.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/DisplayD3D.h new file mode 100644 index 0000000000..f007ba9a19 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/DisplayD3D.h @@ -0,0 +1,61 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// DisplayD3D.h: D3D implementation of egl::Display + +#ifndef LIBANGLE_RENDERER_D3D_DISPLAYD3D_H_ +#define LIBANGLE_RENDERER_D3D_DISPLAYD3D_H_ + +#include "libANGLE/renderer/DisplayImpl.h" + +namespace rx +{ +class RendererD3D; + +class DisplayD3D : public DisplayImpl +{ + public: + DisplayD3D(); + + egl::Error initialize(egl::Display *display) override; + virtual void terminate() override; + + egl::Error createWindowSurface(const egl::Config *configuration, EGLNativeWindowType window, const egl::AttributeMap &attribs, + SurfaceImpl **outSurface) override; + egl::Error createPbufferSurface(const egl::Config *configuration, const egl::AttributeMap &attribs, + SurfaceImpl **outSurface) override; + egl::Error createPbufferFromClientBuffer(const egl::Config *configuration, EGLClientBuffer shareHandle, + const egl::AttributeMap &attribs, SurfaceImpl **outSurface) override; + egl::Error createPixmapSurface(const egl::Config *configuration, NativePixmapType nativePixmap, + const egl::AttributeMap &attribs, SurfaceImpl **outSurface) override; + + egl::Error createContext(const egl::Config *config, const gl::Context *shareContext, const egl::AttributeMap &attribs, + gl::Context **outContext) override; + + egl::Error makeCurrent(egl::Surface *drawSurface, egl::Surface *readSurface, gl::Context *context) override; + + egl::ConfigSet generateConfigs() const override; + + bool isDeviceLost() const override; + bool testDeviceLost() override; + egl::Error restoreLostDevice() override; + + bool isValidNativeWindow(EGLNativeWindowType window) const override; + + std::string getVendorString() const override; + + private: + void generateExtensions(egl::DisplayExtensions *outExtensions) const override; + void generateCaps(egl::Caps *outCaps) const override; + + egl::Display *mDisplay; + + rx::RendererD3D *mRenderer; +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_DISPLAYD3D_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/DynamicHLSL.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/DynamicHLSL.cpp new file mode 100644 index 0000000000..0dbc30ae36 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/DynamicHLSL.cpp @@ -0,0 +1,1265 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// DynamicHLSL.cpp: Implementation for link and run-time HLSL generation +// + +#include "libANGLE/renderer/d3d/DynamicHLSL.h" + +#include "common/utilities.h" +#include "compiler/translator/blocklayoutHLSL.h" +#include "libANGLE/renderer/d3d/ShaderD3D.h" +#include "libANGLE/renderer/d3d/RendererD3D.h" +#include "libANGLE/Program.h" +#include "libANGLE/Shader.h" +#include "libANGLE/formatutils.h" + +// For use with ArrayString, see angleutils.h +static_assert(GL_INVALID_INDEX == UINT_MAX, "GL_INVALID_INDEX must be equal to the max unsigned int."); + +using namespace gl; + +namespace rx +{ + +namespace +{ + +std::string HLSLComponentTypeString(GLenum componentType) +{ + switch (componentType) + { + case GL_UNSIGNED_INT: return "uint"; + case GL_INT: return "int"; + case GL_UNSIGNED_NORMALIZED: + case GL_SIGNED_NORMALIZED: + case GL_FLOAT: return "float"; + default: UNREACHABLE(); return "not-component-type"; + } +} + +std::string HLSLComponentTypeString(GLenum componentType, int componentCount) +{ + return HLSLComponentTypeString(componentType) + (componentCount > 1 ? Str(componentCount) : ""); +} + +std::string HLSLMatrixTypeString(GLenum type) +{ + switch (type) + { + case GL_FLOAT_MAT2: return "float2x2"; + case GL_FLOAT_MAT3: return "float3x3"; + case GL_FLOAT_MAT4: return "float4x4"; + case GL_FLOAT_MAT2x3: return "float2x3"; + case GL_FLOAT_MAT3x2: return "float3x2"; + case GL_FLOAT_MAT2x4: return "float2x4"; + case GL_FLOAT_MAT4x2: return "float4x2"; + case GL_FLOAT_MAT3x4: return "float3x4"; + case GL_FLOAT_MAT4x3: return "float4x3"; + default: UNREACHABLE(); return "not-matrix-type"; + } +} + +std::string HLSLTypeString(GLenum type) +{ + if (gl::IsMatrixType(type)) + { + return HLSLMatrixTypeString(type); + } + + return HLSLComponentTypeString(gl::VariableComponentType(type), gl::VariableComponentCount(type)); +} + +const PixelShaderOutputVariable *FindOutputAtLocation(const std::vector &outputVariables, + unsigned int location) +{ + for (size_t variableIndex = 0; variableIndex < outputVariables.size(); ++variableIndex) + { + if (outputVariables[variableIndex].outputIndex == location) + { + return &outputVariables[variableIndex]; + } + } + + return NULL; +} + +const std::string VERTEX_ATTRIBUTE_STUB_STRING = "@@ VERTEX ATTRIBUTES @@"; +const std::string PIXEL_OUTPUT_STUB_STRING = "@@ PIXEL OUTPUT @@"; + +} + +DynamicHLSL::DynamicHLSL(RendererD3D *const renderer) + : mRenderer(renderer) +{ +} + +static bool packVarying(PackedVarying *varying, const int maxVaryingVectors, VaryingPacking packing) +{ + // Make sure we use transposed matrix types to count registers correctly. + int registers = 0; + int elements = 0; + + if (varying->isStruct()) + { + registers = HLSLVariableRegisterCount(*varying, true) * varying->elementCount(); + elements = 4; + } + else + { + GLenum transposedType = TransposeMatrixType(varying->type); + registers = VariableRowCount(transposedType) * varying->elementCount(); + elements = VariableColumnCount(transposedType); + } + + if (elements >= 2 && elements <= 4) + { + for (int r = 0; r <= maxVaryingVectors - registers; r++) + { + bool available = true; + + for (int y = 0; y < registers && available; y++) + { + for (int x = 0; x < elements && available; x++) + { + if (packing[r + y][x]) + { + available = false; + } + } + } + + if (available) + { + varying->registerIndex = r; + varying->columnIndex = 0; + + for (int y = 0; y < registers; y++) + { + for (int x = 0; x < elements; x++) + { + packing[r + y][x] = &*varying; + } + } + + return true; + } + } + + if (elements == 2) + { + for (int r = maxVaryingVectors - registers; r >= 0; r--) + { + bool available = true; + + for (int y = 0; y < registers && available; y++) + { + for (int x = 2; x < 4 && available; x++) + { + if (packing[r + y][x]) + { + available = false; + } + } + } + + if (available) + { + varying->registerIndex = r; + varying->columnIndex = 2; + + for (int y = 0; y < registers; y++) + { + for (int x = 2; x < 4; x++) + { + packing[r + y][x] = &*varying; + } + } + + return true; + } + } + } + } + else if (elements == 1) + { + int space[4] = { 0 }; + + for (int y = 0; y < maxVaryingVectors; y++) + { + for (int x = 0; x < 4; x++) + { + space[x] += packing[y][x] ? 0 : 1; + } + } + + int column = 0; + + for (int x = 0; x < 4; x++) + { + if (space[x] >= registers && (space[column] < registers || space[x] < space[column])) + { + column = x; + } + } + + if (space[column] >= registers) + { + for (int r = 0; r < maxVaryingVectors; r++) + { + if (!packing[r][column]) + { + varying->registerIndex = r; + varying->columnIndex = column; + + for (int y = r; y < r + registers; y++) + { + packing[y][column] = &*varying; + } + + break; + } + } + + return true; + } + } + else UNREACHABLE(); + + return false; +} + +// Packs varyings into generic varying registers, using the algorithm from [OpenGL ES Shading Language 1.00 rev. 17] appendix A section 7 page 111 +// Returns the number of used varying registers, or -1 if unsuccesful +int DynamicHLSL::packVaryings(InfoLog &infoLog, VaryingPacking packing, ShaderD3D *fragmentShader, + ShaderD3D *vertexShader, const std::vector &transformFeedbackVaryings) +{ + // TODO (geofflang): Use context's caps + const int maxVaryingVectors = mRenderer->getRendererCaps().maxVaryingVectors; + + vertexShader->resetVaryingsRegisterAssignment(); + fragmentShader->resetVaryingsRegisterAssignment(); + + std::set packedVaryings; + + std::vector &fragmentVaryings = fragmentShader->getVaryings(); + std::vector &vertexVaryings = vertexShader->getVaryings(); + for (unsigned int varyingIndex = 0; varyingIndex < fragmentVaryings.size(); varyingIndex++) + { + PackedVarying *varying = &fragmentVaryings[varyingIndex]; + + // Do not assign registers to built-in or unreferenced varyings + if (varying->isBuiltIn() || !varying->staticUse) + { + continue; + } + + if (packVarying(varying, maxVaryingVectors, packing)) + { + packedVaryings.insert(varying->name); + } + else + { + infoLog.append("Could not pack varying %s", varying->name.c_str()); + return -1; + } + } + + for (unsigned int feedbackVaryingIndex = 0; feedbackVaryingIndex < transformFeedbackVaryings.size(); feedbackVaryingIndex++) + { + const std::string &transformFeedbackVarying = transformFeedbackVaryings[feedbackVaryingIndex]; + + if (transformFeedbackVarying == "gl_Position" || transformFeedbackVarying == "gl_PointSize") + { + // do not pack builtin XFB varyings + continue; + } + + if (packedVaryings.find(transformFeedbackVarying) == packedVaryings.end()) + { + bool found = false; + for (unsigned int varyingIndex = 0; varyingIndex < vertexVaryings.size(); varyingIndex++) + { + PackedVarying *varying = &vertexVaryings[varyingIndex]; + if (transformFeedbackVarying == varying->name) + { + if (!packVarying(varying, maxVaryingVectors, packing)) + { + infoLog.append("Could not pack varying %s", varying->name.c_str()); + return -1; + } + + found = true; + break; + } + } + + if (!found) + { + infoLog.append("Transform feedback varying %s does not exist in the vertex shader.", transformFeedbackVarying.c_str()); + return -1; + } + } + } + + // Return the number of used registers + int registers = 0; + + for (int r = 0; r < maxVaryingVectors; r++) + { + if (packing[r][0] || packing[r][1] || packing[r][2] || packing[r][3]) + { + registers++; + } + } + + return registers; +} + +std::string DynamicHLSL::generateVaryingHLSL(const ShaderD3D *shader) const +{ + std::string varyingSemantic = getVaryingSemantic(shader->mUsesPointSize); + std::string varyingHLSL; + + const std::vector &varyings = shader->getVaryings(); + + for (unsigned int varyingIndex = 0; varyingIndex < varyings.size(); varyingIndex++) + { + const PackedVarying &varying = varyings[varyingIndex]; + if (varying.registerAssigned()) + { + ASSERT(!varying.isBuiltIn()); + GLenum transposedType = TransposeMatrixType(varying.type); + int variableRows = (varying.isStruct() ? 1 : VariableRowCount(transposedType)); + + for (unsigned int elementIndex = 0; elementIndex < varying.elementCount(); elementIndex++) + { + for (int row = 0; row < variableRows; row++) + { + // TODO: Add checks to ensure D3D interpolation modifiers don't result in too many registers being used. + // For example, if there are N registers, and we have N vec3 varyings and 1 float varying, then D3D will pack them into N registers. + // If the float varying has the 'nointerpolation' modifier on it then we would need N + 1 registers, and D3D compilation will fail. + + switch (varying.interpolation) + { + case sh::INTERPOLATION_SMOOTH: varyingHLSL += " "; break; + case sh::INTERPOLATION_FLAT: varyingHLSL += " nointerpolation "; break; + case sh::INTERPOLATION_CENTROID: varyingHLSL += " centroid "; break; + default: UNREACHABLE(); + } + + unsigned int semanticIndex = elementIndex * variableRows + + varying.columnIndex * mRenderer->getRendererCaps().maxVaryingVectors + + varying.registerIndex + row; + std::string n = Str(semanticIndex); + + std::string typeString; + + if (varying.isStruct()) + { + // TODO(jmadill): pass back translated name from the shader translator + typeString = decorateVariable(varying.structName); + } + else + { + GLenum componentType = VariableComponentType(transposedType); + int columnCount = VariableColumnCount(transposedType); + typeString = HLSLComponentTypeString(componentType, columnCount); + } + varyingHLSL += typeString + " v" + n + " : " + varyingSemantic + n + ";\n"; + } + } + } + } + + return varyingHLSL; +} + +std::string DynamicHLSL::generateVertexShaderForInputLayout(const std::string &sourceShader, + const VertexFormat inputLayout[], + const sh::Attribute shaderAttributes[]) const +{ + std::string structHLSL, initHLSL; + + int semanticIndex = 0; + unsigned int inputIndex = 0; + + // If gl_PointSize is used in the shader then pointsprites rendering is expected. + // If the renderer does not support Geometry shaders then Instanced PointSprite emulation + // must be used. + bool usesPointSize = sourceShader.find("GL_USES_POINT_SIZE") != std::string::npos; + bool useInstancedPointSpriteEmulation = usesPointSize && mRenderer->getWorkarounds().useInstancedPointSpriteEmulation; + + // Instanced PointSprite emulation requires additional entries in the + // VS_INPUT structure to support the vertices that make up the quad vertices. + // These values must be in sync with the cooresponding values added during inputlayout creation + // in InputLayoutCache::applyVertexBuffers(). + // + // The additional entries must appear first in the VS_INPUT layout because + // Windows Phone 8 era devices require per vertex data to physically come + // before per instance data in the shader. + if (useInstancedPointSpriteEmulation) + { + structHLSL += " float3 spriteVertexPos : SPRITEPOSITION0;\n"; + structHLSL += " float2 spriteTexCoord : SPRITETEXCOORD0;\n"; + } + + for (unsigned int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++) + { + const sh::Attribute &shaderAttribute = shaderAttributes[attributeIndex]; + if (!shaderAttribute.name.empty()) + { + ASSERT(inputIndex < MAX_VERTEX_ATTRIBS); + const VertexFormat &vertexFormat = inputLayout[inputIndex]; + + // HLSL code for input structure + if (IsMatrixType(shaderAttribute.type)) + { + // Matrix types are always transposed + structHLSL += " " + HLSLMatrixTypeString(TransposeMatrixType(shaderAttribute.type)); + } + else + { + GLenum componentType = mRenderer->getVertexComponentType(vertexFormat); + + if (shaderAttribute.name == "gl_InstanceID") + { + // The input type of the instance ID in HLSL (uint) differs from the one in ESSL (int). + structHLSL += " uint"; + } + else + { + structHLSL += " " + HLSLComponentTypeString(componentType, VariableComponentCount(shaderAttribute.type)); + } + } + + structHLSL += " " + decorateVariable(shaderAttribute.name) + " : "; + + if (shaderAttribute.name == "gl_InstanceID") + { + structHLSL += "SV_InstanceID"; + } + else + { + structHLSL += "TEXCOORD" + Str(semanticIndex); + semanticIndex += VariableRegisterCount(shaderAttribute.type); + } + + structHLSL += ";\n"; + + // HLSL code for initialization + initHLSL += " " + decorateVariable(shaderAttribute.name) + " = "; + + // Mismatched vertex attribute to vertex input may result in an undefined + // data reinterpretation (eg for pure integer->float, float->pure integer) + // TODO: issue warning with gl debug info extension, when supported + if (IsMatrixType(shaderAttribute.type) || + (mRenderer->getVertexConversionType(vertexFormat) & VERTEX_CONVERT_GPU) != 0) + { + initHLSL += generateAttributeConversionHLSL(vertexFormat, shaderAttribute); + } + else + { + initHLSL += "input." + decorateVariable(shaderAttribute.name); + } + + initHLSL += ";\n"; + + inputIndex += VariableRowCount(TransposeMatrixType(shaderAttribute.type)); + } + } + + std::string replacementHLSL = "struct VS_INPUT\n" + "{\n" + + structHLSL + + "};\n" + "\n" + "void initAttributes(VS_INPUT input)\n" + "{\n" + + initHLSL + + "}\n"; + + std::string vertexHLSL(sourceShader); + + size_t copyInsertionPos = vertexHLSL.find(VERTEX_ATTRIBUTE_STUB_STRING); + vertexHLSL.replace(copyInsertionPos, VERTEX_ATTRIBUTE_STUB_STRING.length(), replacementHLSL); + + return vertexHLSL; +} + +std::string DynamicHLSL::generatePixelShaderForOutputSignature(const std::string &sourceShader, const std::vector &outputVariables, + bool usesFragDepth, const std::vector &outputLayout) const +{ + const int shaderModel = mRenderer->getMajorShaderModel(); + std::string targetSemantic = (shaderModel >= 4) ? "SV_TARGET" : "COLOR"; + std::string depthSemantic = (shaderModel >= 4) ? "SV_Depth" : "DEPTH"; + + std::string declarationHLSL; + std::string copyHLSL; + + for (size_t layoutIndex = 0; layoutIndex < outputLayout.size(); ++layoutIndex) + { + GLenum binding = outputLayout[layoutIndex]; + + if (binding != GL_NONE) + { + unsigned int location = (binding - GL_COLOR_ATTACHMENT0); + + const PixelShaderOutputVariable *outputVariable = FindOutputAtLocation(outputVariables, location); + + // OpenGL ES 3.0 spec $4.2.1 + // If [...] not all user-defined output variables are written, the values of fragment colors + // corresponding to unwritten variables are similarly undefined. + if (outputVariable) + { + declarationHLSL += " " + HLSLTypeString(outputVariable->type) + " " + outputVariable->name + + " : " + targetSemantic + Str(layoutIndex) + ";\n"; + + copyHLSL += " output." + outputVariable->name + " = " + outputVariable->source + ";\n"; + } + } + } + + if (usesFragDepth) + { + declarationHLSL += " float gl_Depth : " + depthSemantic + ";\n"; + copyHLSL += " output.gl_Depth = gl_Depth; \n"; + } + + std::string replacementHLSL = "struct PS_OUTPUT\n" + "{\n" + + declarationHLSL + + "};\n" + "\n" + "PS_OUTPUT generateOutput()\n" + "{\n" + " PS_OUTPUT output;\n" + + copyHLSL + + " return output;\n" + "}\n"; + + std::string pixelHLSL(sourceShader); + + size_t outputInsertionPos = pixelHLSL.find(PIXEL_OUTPUT_STUB_STRING); + pixelHLSL.replace(outputInsertionPos, PIXEL_OUTPUT_STUB_STRING.length(), replacementHLSL); + + return pixelHLSL; +} + +std::string DynamicHLSL::getVaryingSemantic(bool pointSize) const +{ + // SM3 reserves the TEXCOORD semantic for point sprite texcoords (gl_PointCoord) + // In D3D11 we manually compute gl_PointCoord in the GS. + int shaderModel = mRenderer->getMajorShaderModel(); + return ((pointSize && shaderModel < 4) ? "COLOR" : "TEXCOORD"); +} + +struct DynamicHLSL::SemanticInfo +{ + struct BuiltinInfo + { + BuiltinInfo() + : enabled(false), + index(0), + systemValue(false) + {} + + bool enabled; + std::string semantic; + unsigned int index; + bool systemValue; + + std::string str() const + { + return (systemValue ? semantic : (semantic + Str(index))); + } + + void enableSystem(const std::string &systemValueSemantic) + { + enabled = true; + semantic = systemValueSemantic; + systemValue = true; + } + + void enable(const std::string &semanticVal, unsigned int indexVal) + { + enabled = true; + semantic = semanticVal; + index = indexVal; + } + }; + + BuiltinInfo dxPosition; + BuiltinInfo glPosition; + BuiltinInfo glFragCoord; + BuiltinInfo glPointCoord; + BuiltinInfo glPointSize; +}; + +DynamicHLSL::SemanticInfo DynamicHLSL::getSemanticInfo(int startRegisters, bool position, bool fragCoord, + bool pointCoord, bool pointSize, bool pixelShader) const +{ + SemanticInfo info; + bool hlsl4 = (mRenderer->getMajorShaderModel() >= 4); + const std::string &varyingSemantic = getVaryingSemantic(pointSize); + + int reservedRegisterIndex = startRegisters; + + if (hlsl4) + { + info.dxPosition.enableSystem("SV_Position"); + } + else if (pixelShader) + { + info.dxPosition.enableSystem("VPOS"); + } + else + { + info.dxPosition.enableSystem("POSITION"); + } + + if (position) + { + info.glPosition.enable(varyingSemantic, reservedRegisterIndex++); + } + + if (fragCoord) + { + info.glFragCoord.enable(varyingSemantic, reservedRegisterIndex++); + } + + if (pointCoord) + { + // SM3 reserves the TEXCOORD semantic for point sprite texcoords (gl_PointCoord) + // In D3D11 we manually compute gl_PointCoord in the GS. + if (hlsl4) + { + info.glPointCoord.enable(varyingSemantic, reservedRegisterIndex++); + } + else + { + info.glPointCoord.enable("TEXCOORD", 0); + } + } + + // Special case: do not include PSIZE semantic in HLSL 3 pixel shaders + if (pointSize && (!pixelShader || hlsl4)) + { + info.glPointSize.enableSystem("PSIZE"); + } + + return info; +} + +std::string DynamicHLSL::generateVaryingLinkHLSL(const SemanticInfo &info, const std::string &varyingHLSL) const +{ + std::string linkHLSL = "{\n"; + + ASSERT(info.dxPosition.enabled); + linkHLSL += " float4 dx_Position : " + info.dxPosition.str() + ";\n"; + + if (info.glPosition.enabled) + { + linkHLSL += " float4 gl_Position : " + info.glPosition.str() + ";\n"; + } + + if (info.glFragCoord.enabled) + { + linkHLSL += " float4 gl_FragCoord : " + info.glFragCoord.str() + ";\n"; + } + + if (info.glPointCoord.enabled) + { + linkHLSL += " float2 gl_PointCoord : " + info.glPointCoord.str() + ";\n"; + } + + if (info.glPointSize.enabled) + { + linkHLSL += " float gl_PointSize : " + info.glPointSize.str() + ";\n"; + } + + // Do this after glPointSize, to potentially combine gl_PointCoord and gl_PointSize into the same register. + linkHLSL += varyingHLSL; + + linkHLSL += "};\n"; + + return linkHLSL; +} + +void DynamicHLSL::storeBuiltinLinkedVaryings(const SemanticInfo &info, + std::vector *linkedVaryings) const +{ + if (info.glPosition.enabled) + { + linkedVaryings->push_back(LinkedVarying("gl_Position", GL_FLOAT_VEC4, 1, info.glPosition.semantic, + info.glPosition.index, 1)); + } + + if (info.glFragCoord.enabled) + { + linkedVaryings->push_back(LinkedVarying("gl_FragCoord", GL_FLOAT_VEC4, 1, info.glFragCoord.semantic, + info.glFragCoord.index, 1)); + } + + if (info.glPointSize.enabled) + { + linkedVaryings->push_back(LinkedVarying("gl_PointSize", GL_FLOAT, 1, "PSIZE", 0, 1)); + } +} + +void DynamicHLSL::storeUserLinkedVaryings(const ShaderD3D *vertexShader, + std::vector *linkedVaryings) const +{ + const std::string &varyingSemantic = getVaryingSemantic(vertexShader->mUsesPointSize); + const std::vector &varyings = vertexShader->getVaryings(); + + for (unsigned int varyingIndex = 0; varyingIndex < varyings.size(); varyingIndex++) + { + const PackedVarying &varying = varyings[varyingIndex]; + + if (varying.registerAssigned()) + { + ASSERT(!varying.isBuiltIn()); + GLenum transposedType = TransposeMatrixType(varying.type); + int variableRows = (varying.isStruct() ? 1 : VariableRowCount(transposedType)); + + linkedVaryings->push_back(LinkedVarying(varying.name, varying.type, varying.elementCount(), + varyingSemantic, varying.registerIndex, + variableRows * varying.elementCount())); + } + } +} + +bool DynamicHLSL::generateShaderLinkHLSL(const gl::Data &data, InfoLog &infoLog, int registers, + const VaryingPacking packing, + std::string &pixelHLSL, std::string &vertexHLSL, + ShaderD3D *fragmentShader, ShaderD3D *vertexShader, + const std::vector &transformFeedbackVaryings, + std::vector *linkedVaryings, + std::map *programOutputVars, + std::vector *outPixelShaderKey, + bool *outUsesFragDepth) const +{ + if (pixelHLSL.empty() || vertexHLSL.empty()) + { + return false; + } + + bool usesMRT = fragmentShader->mUsesMultipleRenderTargets; + bool usesFragColor = fragmentShader->mUsesFragColor; + bool usesFragData = fragmentShader->mUsesFragData; + bool usesFragCoord = fragmentShader->mUsesFragCoord; + bool usesPointCoord = fragmentShader->mUsesPointCoord; + bool usesPointSize = vertexShader->mUsesPointSize; + bool useInstancedPointSpriteEmulation = usesPointSize && mRenderer->getWorkarounds().useInstancedPointSpriteEmulation; + + if (usesFragColor && usesFragData) + { + infoLog.append("Cannot use both gl_FragColor and gl_FragData in the same fragment shader."); + return false; + } + + // Write the HLSL input/output declarations + const int shaderModel = mRenderer->getMajorShaderModel(); + const int registersNeeded = registers + (usesFragCoord ? 1 : 0) + (usesPointCoord ? 1 : 0); + + // Two cases when writing to gl_FragColor and using ESSL 1.0: + // - with a 3.0 context, the output color is copied to channel 0 + // - with a 2.0 context, the output color is broadcast to all channels + const bool broadcast = (fragmentShader->mUsesFragColor && data.clientVersion < 3); + const unsigned int numRenderTargets = (broadcast || usesMRT ? data.caps->maxDrawBuffers : 1); + + // gl_Position only needs to be outputted from the vertex shader if transform feedback is active. + // This isn't supported on D3D11 Feature Level 9_3, so we don't output gl_Position from the vertex shader in this case. + // This saves us 1 output vector. + bool outputPositionFromVS = !(shaderModel >= 4 && mRenderer->getShaderModelSuffix() != ""); + + int shaderVersion = vertexShader->getShaderVersion(); + + if (static_cast(registersNeeded) > data.caps->maxVaryingVectors) + { + infoLog.append("No varying registers left to support gl_FragCoord/gl_PointCoord"); + return false; + } + + const std::string &varyingHLSL = generateVaryingHLSL(vertexShader); + + // Instanced PointSprite emulation requires that gl_PointCoord is present in the vertex shader VS_OUTPUT + // structure to ensure compatibility with the generated PS_INPUT of the pixel shader. + // GeometryShader PointSprite emulation does not require this additional entry because the + // GS_OUTPUT of the Geometry shader contains the pointCoord value and already matches the PS_INPUT of the + // generated pixel shader. + // The Geometry Shader point sprite implementation needs gl_PointSize to be in VS_OUTPUT and GS_INPUT. + // Instanced point sprites doesn't need gl_PointSize in VS_OUTPUT. + const SemanticInfo &vertexSemantics = getSemanticInfo(registers, outputPositionFromVS, + usesFragCoord, (useInstancedPointSpriteEmulation && usesPointCoord), + (!useInstancedPointSpriteEmulation && usesPointSize), false); + + storeUserLinkedVaryings(vertexShader, linkedVaryings); + storeBuiltinLinkedVaryings(vertexSemantics, linkedVaryings); + + // Instanced PointSprite emulation requires additional entries originally generated in the + // GeometryShader HLSL. These include pointsize clamp values. + if (useInstancedPointSpriteEmulation) + { + vertexHLSL += "static float minPointSize = " + Str((int)mRenderer->getRendererCaps().minAliasedPointSize) + ".0f;\n" + "static float maxPointSize = " + Str((int)mRenderer->getRendererCaps().maxAliasedPointSize) + ".0f;\n"; + } + + // Add stub string to be replaced when shader is dynamically defined by its layout + vertexHLSL += "\n" + VERTEX_ATTRIBUTE_STUB_STRING + "\n" + "struct VS_OUTPUT\n" + generateVaryingLinkHLSL(vertexSemantics, varyingHLSL) + "\n" + "VS_OUTPUT main(VS_INPUT input)\n" + "{\n" + " initAttributes(input);\n"; + + if (vertexShader->usesDeferredInit()) + { + vertexHLSL += "\n" + " initializeDeferredGlobals();\n"; + } + + vertexHLSL += "\n" + " gl_main();\n" + "\n" + " VS_OUTPUT output;\n"; + + if (outputPositionFromVS) + { + vertexHLSL += " output.gl_Position = gl_Position;\n"; + } + + // On D3D9 or D3D11 Feature Level 9, we need to emulate large viewports using dx_ViewAdjust. + if (shaderModel >= 4 && mRenderer->getShaderModelSuffix() == "") + { + vertexHLSL += " output.dx_Position.x = gl_Position.x;\n" + " output.dx_Position.y = -gl_Position.y;\n" + " output.dx_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n" + " output.dx_Position.w = gl_Position.w;\n"; + } + else + { + vertexHLSL += " output.dx_Position.x = gl_Position.x * dx_ViewAdjust.z + dx_ViewAdjust.x * gl_Position.w;\n" + " output.dx_Position.y = -(gl_Position.y * dx_ViewAdjust.w + dx_ViewAdjust.y * gl_Position.w);\n" + " output.dx_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n" + " output.dx_Position.w = gl_Position.w;\n"; + } + + // We don't need to output gl_PointSize if we use are emulating point sprites via instancing. + if (usesPointSize && shaderModel >= 3 && !useInstancedPointSpriteEmulation) + { + vertexHLSL += " output.gl_PointSize = gl_PointSize;\n"; + } + + if (usesFragCoord) + { + vertexHLSL += " output.gl_FragCoord = gl_Position;\n"; + } + + const std::vector &vertexVaryings = vertexShader->getVaryings(); + for (unsigned int vertVaryingIndex = 0; vertVaryingIndex < vertexVaryings.size(); vertVaryingIndex++) + { + const PackedVarying &varying = vertexVaryings[vertVaryingIndex]; + if (varying.registerAssigned()) + { + for (unsigned int elementIndex = 0; elementIndex < varying.elementCount(); elementIndex++) + { + int variableRows = (varying.isStruct() ? 1 : VariableRowCount(TransposeMatrixType(varying.type))); + + for (int row = 0; row < variableRows; row++) + { + int r = varying.registerIndex + varying.columnIndex * data.caps->maxVaryingVectors + elementIndex * variableRows + row; + vertexHLSL += " output.v" + Str(r); + + vertexHLSL += " = _" + varying.name; + + if (varying.isArray()) + { + vertexHLSL += ArrayString(elementIndex); + } + + if (variableRows > 1) + { + vertexHLSL += ArrayString(row); + } + + vertexHLSL += ";\n"; + } + } + } + } + + // Instanced PointSprite emulation requires additional entries to calculate + // the final output vertex positions of the quad that represents each sprite. + if (useInstancedPointSpriteEmulation) + { + vertexHLSL += "\n" + " gl_PointSize = clamp(gl_PointSize, minPointSize, maxPointSize);\n" + " output.dx_Position.xyz += float3(input.spriteVertexPos.x * gl_PointSize / (dx_ViewCoords.x*2), input.spriteVertexPos.y * gl_PointSize / (dx_ViewCoords.y*2), input.spriteVertexPos.z) * output.dx_Position.w;\n"; + + if (usesPointCoord) + { + vertexHLSL += "\n" + " output.gl_PointCoord = input.spriteTexCoord;\n"; + } + } + + vertexHLSL += "\n" + " return output;\n" + "}\n"; + + const SemanticInfo &pixelSemantics = getSemanticInfo(registers, outputPositionFromVS, usesFragCoord, usesPointCoord, + (!useInstancedPointSpriteEmulation && usesPointSize), true); + + pixelHLSL += "struct PS_INPUT\n" + generateVaryingLinkHLSL(pixelSemantics, varyingHLSL) + "\n"; + + if (shaderVersion < 300) + { + for (unsigned int renderTargetIndex = 0; renderTargetIndex < numRenderTargets; renderTargetIndex++) + { + PixelShaderOutputVariable outputKeyVariable; + outputKeyVariable.type = GL_FLOAT_VEC4; + outputKeyVariable.name = "gl_Color" + Str(renderTargetIndex); + outputKeyVariable.source = broadcast ? "gl_Color[0]" : "gl_Color[" + Str(renderTargetIndex) + "]"; + outputKeyVariable.outputIndex = renderTargetIndex; + + outPixelShaderKey->push_back(outputKeyVariable); + } + + *outUsesFragDepth = fragmentShader->mUsesFragDepth; + } + else + { + defineOutputVariables(fragmentShader, programOutputVars); + + const std::vector &shaderOutputVars = fragmentShader->getActiveOutputVariables(); + for (auto locationIt = programOutputVars->begin(); locationIt != programOutputVars->end(); locationIt++) + { + const VariableLocation &outputLocation = locationIt->second; + const sh::ShaderVariable &outputVariable = shaderOutputVars[outputLocation.index]; + const std::string &variableName = "out_" + outputLocation.name; + const std::string &elementString = (outputLocation.element == GL_INVALID_INDEX ? "" : Str(outputLocation.element)); + + ASSERT(outputVariable.staticUse); + + PixelShaderOutputVariable outputKeyVariable; + outputKeyVariable.type = outputVariable.type; + outputKeyVariable.name = variableName + elementString; + outputKeyVariable.source = variableName + ArrayString(outputLocation.element); + outputKeyVariable.outputIndex = locationIt->first; + + outPixelShaderKey->push_back(outputKeyVariable); + } + + *outUsesFragDepth = false; + } + + pixelHLSL += PIXEL_OUTPUT_STUB_STRING + "\n"; + + if (fragmentShader->mUsesFrontFacing) + { + if (shaderModel >= 4) + { + pixelHLSL += "PS_OUTPUT main(PS_INPUT input, bool isFrontFace : SV_IsFrontFace)\n" + "{\n"; + } + else + { + pixelHLSL += "PS_OUTPUT main(PS_INPUT input, float vFace : VFACE)\n" + "{\n"; + } + } + else + { + pixelHLSL += "PS_OUTPUT main(PS_INPUT input)\n" + "{\n"; + } + + if (usesFragCoord) + { + pixelHLSL += " float rhw = 1.0 / input.gl_FragCoord.w;\n"; + + // Certain Shader Models (4_0+ and 3_0) allow reading from dx_Position in the pixel shader. + // Other Shader Models (4_0_level_9_3 and 2_x) don't support this, so we emulate it using dx_ViewCoords. + if (shaderModel >= 4 && mRenderer->getShaderModelSuffix() == "") + { + pixelHLSL += " gl_FragCoord.x = input.dx_Position.x;\n" + " gl_FragCoord.y = input.dx_Position.y;\n"; + } + else if (shaderModel == 3) + { + pixelHLSL += " gl_FragCoord.x = input.dx_Position.x + 0.5;\n" + " gl_FragCoord.y = input.dx_Position.y + 0.5;\n"; + } + else + { + // dx_ViewCoords contains the viewport width/2, height/2, center.x and center.y. See Renderer::setViewport() + pixelHLSL += " gl_FragCoord.x = (input.gl_FragCoord.x * rhw) * dx_ViewCoords.x + dx_ViewCoords.z;\n" + " gl_FragCoord.y = (input.gl_FragCoord.y * rhw) * dx_ViewCoords.y + dx_ViewCoords.w;\n"; + } + + pixelHLSL += " gl_FragCoord.z = (input.gl_FragCoord.z * rhw) * dx_DepthFront.x + dx_DepthFront.y;\n" + " gl_FragCoord.w = rhw;\n"; + } + + if (usesPointCoord && shaderModel >= 3) + { + pixelHLSL += " gl_PointCoord.x = input.gl_PointCoord.x;\n"; + pixelHLSL += " gl_PointCoord.y = 1.0 - input.gl_PointCoord.y;\n"; + } + + if (fragmentShader->mUsesFrontFacing) + { + if (shaderModel <= 3) + { + pixelHLSL += " gl_FrontFacing = (vFace * dx_DepthFront.z >= 0.0);\n"; + } + else + { + pixelHLSL += " gl_FrontFacing = isFrontFace;\n"; + } + } + + const std::vector &fragmentVaryings = fragmentShader->getVaryings(); + for (unsigned int varyingIndex = 0; varyingIndex < fragmentVaryings.size(); varyingIndex++) + { + const PackedVarying &varying = fragmentVaryings[varyingIndex]; + if (varying.registerAssigned()) + { + ASSERT(!varying.isBuiltIn()); + for (unsigned int elementIndex = 0; elementIndex < varying.elementCount(); elementIndex++) + { + GLenum transposedType = TransposeMatrixType(varying.type); + int variableRows = (varying.isStruct() ? 1 : VariableRowCount(transposedType)); + for (int row = 0; row < variableRows; row++) + { + std::string n = Str(varying.registerIndex + varying.columnIndex * data.caps->maxVaryingVectors + elementIndex * variableRows + row); + pixelHLSL += " _" + varying.name; + + if (varying.isArray()) + { + pixelHLSL += ArrayString(elementIndex); + } + + if (variableRows > 1) + { + pixelHLSL += ArrayString(row); + } + + if (varying.isStruct()) + { + pixelHLSL += " = input.v" + n + ";\n"; break; + } + else + { + switch (VariableColumnCount(transposedType)) + { + case 1: pixelHLSL += " = input.v" + n + ".x;\n"; break; + case 2: pixelHLSL += " = input.v" + n + ".xy;\n"; break; + case 3: pixelHLSL += " = input.v" + n + ".xyz;\n"; break; + case 4: pixelHLSL += " = input.v" + n + ";\n"; break; + default: UNREACHABLE(); + } + } + } + } + } + else + { + ASSERT(varying.isBuiltIn() || !varying.staticUse); + } + } + + if (fragmentShader->usesDeferredInit()) + { + pixelHLSL += "\n" + " initializeDeferredGlobals();\n"; + } + + pixelHLSL += "\n" + " gl_main();\n" + "\n" + " return generateOutput();\n" + "}\n"; + + return true; +} + +void DynamicHLSL::defineOutputVariables(ShaderD3D *fragmentShader, std::map *programOutputVars) const +{ + const std::vector &shaderOutputVars = fragmentShader->getActiveOutputVariables(); + + for (unsigned int outputVariableIndex = 0; outputVariableIndex < shaderOutputVars.size(); outputVariableIndex++) + { + const sh::Attribute &outputVariable = shaderOutputVars[outputVariableIndex]; + const int baseLocation = outputVariable.location == -1 ? 0 : outputVariable.location; + + ASSERT(outputVariable.staticUse); + + if (outputVariable.arraySize > 0) + { + for (unsigned int elementIndex = 0; elementIndex < outputVariable.arraySize; elementIndex++) + { + const int location = baseLocation + elementIndex; + ASSERT(programOutputVars->count(location) == 0); + (*programOutputVars)[location] = VariableLocation(outputVariable.name, elementIndex, outputVariableIndex); + } + } + else + { + ASSERT(programOutputVars->count(baseLocation) == 0); + (*programOutputVars)[baseLocation] = VariableLocation(outputVariable.name, GL_INVALID_INDEX, outputVariableIndex); + } + } +} + +std::string DynamicHLSL::generateGeometryShaderHLSL(int registers, ShaderD3D *fragmentShader, ShaderD3D *vertexShader) const +{ + // for now we only handle point sprite emulation + ASSERT(vertexShader->mUsesPointSize && mRenderer->getMajorShaderModel() >= 4); + return generatePointSpriteHLSL(registers, fragmentShader, vertexShader); +} + +std::string DynamicHLSL::generatePointSpriteHLSL(int registers, ShaderD3D *fragmentShader, ShaderD3D *vertexShader) const +{ + ASSERT(registers >= 0); + ASSERT(vertexShader->mUsesPointSize); + ASSERT(mRenderer->getMajorShaderModel() >= 4); + + std::string geomHLSL; + + const SemanticInfo &inSemantics = getSemanticInfo(registers, true, fragmentShader->mUsesFragCoord, + false, true, false); + const SemanticInfo &outSemantics = getSemanticInfo(registers, true, fragmentShader->mUsesFragCoord, + fragmentShader->mUsesPointCoord, true, false); + + std::string varyingHLSL = generateVaryingHLSL(vertexShader); + std::string inLinkHLSL = generateVaryingLinkHLSL(inSemantics, varyingHLSL); + std::string outLinkHLSL = generateVaryingLinkHLSL(outSemantics, varyingHLSL); + + // TODO(geofflang): use context's caps + geomHLSL += "uniform float4 dx_ViewCoords : register(c1);\n" + "\n" + "struct GS_INPUT\n" + inLinkHLSL + "\n" + + "struct GS_OUTPUT\n" + outLinkHLSL + "\n" + + "\n" + "static float2 pointSpriteCorners[] = \n" + "{\n" + " float2( 0.5f, -0.5f),\n" + " float2( 0.5f, 0.5f),\n" + " float2(-0.5f, -0.5f),\n" + " float2(-0.5f, 0.5f)\n" + "};\n" + "\n" + "static float2 pointSpriteTexcoords[] = \n" + "{\n" + " float2(1.0f, 1.0f),\n" + " float2(1.0f, 0.0f),\n" + " float2(0.0f, 1.0f),\n" + " float2(0.0f, 0.0f)\n" + "};\n" + "\n" + "static float minPointSize = " + Str(mRenderer->getRendererCaps().minAliasedPointSize) + ".0f;\n" + "static float maxPointSize = " + Str(mRenderer->getRendererCaps().maxAliasedPointSize) + ".0f;\n" + "\n" + "[maxvertexcount(4)]\n" + "void main(point GS_INPUT input[1], inout TriangleStream outStream)\n" + "{\n" + " GS_OUTPUT output = (GS_OUTPUT)0;\n" + " output.gl_Position = input[0].gl_Position;\n" + " output.gl_PointSize = input[0].gl_PointSize;\n"; + + for (int r = 0; r < registers; r++) + { + geomHLSL += " output.v" + Str(r) + " = input[0].v" + Str(r) + ";\n"; + } + + if (fragmentShader->mUsesFragCoord) + { + geomHLSL += " output.gl_FragCoord = input[0].gl_FragCoord;\n"; + } + + geomHLSL += " \n" + " float gl_PointSize = clamp(input[0].gl_PointSize, minPointSize, maxPointSize);\n" + " float4 dx_Position = input[0].dx_Position;\n" + " float2 viewportScale = float2(1.0f / dx_ViewCoords.x, 1.0f / dx_ViewCoords.y) * dx_Position.w;\n"; + + for (int corner = 0; corner < 4; corner++) + { + geomHLSL += " \n" + " output.dx_Position = dx_Position + float4(pointSpriteCorners[" + Str(corner) + "] * viewportScale * gl_PointSize, 0.0f, 0.0f);\n"; + + if (fragmentShader->mUsesPointCoord) + { + geomHLSL += " output.gl_PointCoord = pointSpriteTexcoords[" + Str(corner) + "];\n"; + } + + geomHLSL += " outStream.Append(output);\n"; + } + + geomHLSL += " \n" + " outStream.RestartStrip();\n" + "}\n"; + + return geomHLSL; +} + +// This method needs to match OutputHLSL::decorate +std::string DynamicHLSL::decorateVariable(const std::string &name) +{ + if (name.compare(0, 3, "gl_") != 0) + { + return "_" + name; + } + + return name; +} + +std::string DynamicHLSL::generateAttributeConversionHLSL(const VertexFormat &vertexFormat, const sh::ShaderVariable &shaderAttrib) const +{ + std::string attribString = "input." + decorateVariable(shaderAttrib.name); + + // Matrix + if (IsMatrixType(shaderAttrib.type)) + { + return "transpose(" + attribString + ")"; + } + + GLenum shaderComponentType = VariableComponentType(shaderAttrib.type); + int shaderComponentCount = VariableComponentCount(shaderAttrib.type); + + // Perform integer to float conversion (if necessary) + bool requiresTypeConversion = (shaderComponentType == GL_FLOAT && vertexFormat.mType != GL_FLOAT); + + if (requiresTypeConversion) + { + // TODO: normalization for 32-bit integer formats + ASSERT(!vertexFormat.mNormalized && !vertexFormat.mPureInteger); + return "float" + Str(shaderComponentCount) + "(" + attribString + ")"; + } + + // No conversion necessary + return attribString; +} + +void DynamicHLSL::getInputLayoutSignature(const VertexFormat inputLayout[], GLenum signature[]) const +{ + for (size_t inputIndex = 0; inputIndex < MAX_VERTEX_ATTRIBS; inputIndex++) + { + const VertexFormat &vertexFormat = inputLayout[inputIndex]; + + if (vertexFormat.mType == GL_NONE) + { + signature[inputIndex] = GL_NONE; + } + else + { + bool gpuConverted = ((mRenderer->getVertexConversionType(vertexFormat) & VERTEX_CONVERT_GPU) != 0); + signature[inputIndex] = (gpuConverted ? GL_TRUE : GL_FALSE); + } + } +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/DynamicHLSL.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/DynamicHLSL.h new file mode 100644 index 0000000000..26ae13b342 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/DynamicHLSL.h @@ -0,0 +1,99 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// DynamicHLSL.h: Interface for link and run-time HLSL generation +// + +#ifndef LIBANGLE_RENDERER_D3D_DYNAMICHLSL_H_ +#define LIBANGLE_RENDERER_D3D_DYNAMICHLSL_H_ + +#include "common/angleutils.h" +#include "libANGLE/Constants.h" + +#include "angle_gl.h" + +#include +#include + +namespace sh +{ +struct Attribute; +struct ShaderVariable; +} + +namespace gl +{ +class InfoLog; +struct VariableLocation; +struct LinkedVarying; +struct VertexAttribute; +struct VertexFormat; +struct PackedVarying; +struct Data; +} + +namespace rx +{ +class RendererD3D; +class ShaderD3D; + +typedef const gl::PackedVarying *VaryingPacking[gl::IMPLEMENTATION_MAX_VARYING_VECTORS][4]; + +struct PixelShaderOutputVariable +{ + GLenum type; + std::string name; + std::string source; + size_t outputIndex; +}; + +class DynamicHLSL : angle::NonCopyable +{ + public: + explicit DynamicHLSL(RendererD3D *const renderer); + + int packVaryings(gl::InfoLog &infoLog, VaryingPacking packing, ShaderD3D *fragmentShader, + ShaderD3D *vertexShader, const std::vector& transformFeedbackVaryings); + std::string generateVertexShaderForInputLayout(const std::string &sourceShader, const gl::VertexFormat inputLayout[], + const sh::Attribute shaderAttributes[]) const; + std::string generatePixelShaderForOutputSignature(const std::string &sourceShader, const std::vector &outputVariables, + bool usesFragDepth, const std::vector &outputLayout) const; + bool generateShaderLinkHLSL(const gl::Data &data, gl::InfoLog &infoLog, int registers, + const VaryingPacking packing, + std::string &pixelHLSL, std::string &vertexHLSL, + ShaderD3D *fragmentShader, ShaderD3D *vertexShader, + const std::vector &transformFeedbackVaryings, + std::vector *linkedVaryings, + std::map *programOutputVars, + std::vector *outPixelShaderKey, + bool *outUsesFragDepth) const; + + std::string generateGeometryShaderHLSL(int registers, ShaderD3D *fragmentShader, ShaderD3D *vertexShader) const; + void getInputLayoutSignature(const gl::VertexFormat inputLayout[], GLenum signature[]) const; + + private: + RendererD3D *const mRenderer; + + struct SemanticInfo; + + std::string getVaryingSemantic(bool pointSize) const; + SemanticInfo getSemanticInfo(int startRegisters, bool position, bool fragCoord, bool pointCoord, + bool pointSize, bool pixelShader) const; + std::string generateVaryingLinkHLSL(const SemanticInfo &info, const std::string &varyingHLSL) const; + std::string generateVaryingHLSL(const ShaderD3D *shader) const; + void storeUserLinkedVaryings(const ShaderD3D *vertexShader, std::vector *linkedVaryings) const; + void storeBuiltinLinkedVaryings(const SemanticInfo &info, std::vector *linkedVaryings) const; + void defineOutputVariables(ShaderD3D *fragmentShader, std::map *programOutputVars) const; + std::string generatePointSpriteHLSL(int registers, ShaderD3D *fragmentShader, ShaderD3D *vertexShader) const; + + // Prepend an underscore + static std::string decorateVariable(const std::string &name); + + std::string generateAttributeConversionHLSL(const gl::VertexFormat &vertexFormat, const sh::ShaderVariable &shaderAttrib) const; +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_DYNAMICHLSL_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/FramebufferD3D.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/FramebufferD3D.cpp new file mode 100644 index 0000000000..1a4734b269 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/FramebufferD3D.cpp @@ -0,0 +1,463 @@ +// +// Copyright 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// FramebufferD3D.cpp: Implements the DefaultAttachmentD3D and FramebufferD3D classes. + +#include "libANGLE/renderer/d3d/FramebufferD3D.h" + +#include "libANGLE/formatutils.h" +#include "libANGLE/Framebuffer.h" +#include "libANGLE/FramebufferAttachment.h" +#include "libANGLE/Surface.h" +#include "libANGLE/renderer/d3d/RendererD3D.h" +#include "libANGLE/renderer/d3d/RenderbufferD3D.h" +#include "libANGLE/renderer/d3d/RenderTargetD3D.h" +#include "libANGLE/renderer/d3d/SurfaceD3D.h" +#include "libANGLE/renderer/d3d/SwapChainD3D.h" +#include "libANGLE/renderer/d3d/TextureD3D.h" + +namespace rx +{ + +namespace +{ + +ClearParameters GetClearParameters(const gl::State &state, GLbitfield mask) +{ + ClearParameters clearParams; + memset(&clearParams, 0, sizeof(ClearParameters)); + + const auto &blendState = state.getBlendState(); + + for (unsigned int i = 0; i < ArraySize(clearParams.clearColor); i++) + { + clearParams.clearColor[i] = false; + } + clearParams.colorFClearValue = state.getColorClearValue(); + clearParams.colorClearType = GL_FLOAT; + clearParams.colorMaskRed = blendState.colorMaskRed; + clearParams.colorMaskGreen = blendState.colorMaskGreen; + clearParams.colorMaskBlue = blendState.colorMaskBlue; + clearParams.colorMaskAlpha = blendState.colorMaskAlpha; + clearParams.clearDepth = false; + clearParams.depthClearValue = state.getDepthClearValue(); + clearParams.clearStencil = false; + clearParams.stencilClearValue = state.getStencilClearValue(); + clearParams.stencilWriteMask = state.getDepthStencilState().stencilWritemask; + clearParams.scissorEnabled = state.isScissorTestEnabled(); + clearParams.scissor = state.getScissor(); + + const gl::Framebuffer *framebufferObject = state.getDrawFramebuffer(); + if (mask & GL_COLOR_BUFFER_BIT) + { + if (framebufferObject->hasEnabledColorAttachment()) + { + for (unsigned int i = 0; i < ArraySize(clearParams.clearColor); i++) + { + clearParams.clearColor[i] = true; + } + } + } + + if (mask & GL_DEPTH_BUFFER_BIT) + { + if (state.getDepthStencilState().depthMask && framebufferObject->getDepthbuffer() != NULL) + { + clearParams.clearDepth = true; + } + } + + if (mask & GL_STENCIL_BUFFER_BIT) + { + if (framebufferObject->getStencilbuffer() != NULL && + framebufferObject->getStencilbuffer()->getStencilSize() > 0) + { + clearParams.clearStencil = true; + } + } + + return clearParams; +} + +} + +FramebufferD3D::FramebufferD3D(const gl::Framebuffer::Data &data, RendererD3D *renderer) + : FramebufferImpl(data), + mRenderer(renderer), + mColorAttachmentsForRender(mData.mColorAttachments.size(), nullptr), + mInvalidateColorAttachmentCache(true) +{ + ASSERT(mRenderer != nullptr); +} + +FramebufferD3D::~FramebufferD3D() +{ +} + +void FramebufferD3D::setColorAttachment(size_t, const gl::FramebufferAttachment *) +{ + mInvalidateColorAttachmentCache = true; +} + +void FramebufferD3D::setDepthAttachment(const gl::FramebufferAttachment *) +{ +} + +void FramebufferD3D::setStencilAttachment(const gl::FramebufferAttachment *) +{ +} + +void FramebufferD3D::setDepthStencilAttachment(const gl::FramebufferAttachment *) +{ +} + +void FramebufferD3D::setDrawBuffers(size_t, const GLenum *) +{ + mInvalidateColorAttachmentCache = true; +} + +void FramebufferD3D::setReadBuffer(GLenum) +{ +} + +gl::Error FramebufferD3D::invalidate(size_t, const GLenum *) +{ + // No-op in D3D + return gl::Error(GL_NO_ERROR); +} + +gl::Error FramebufferD3D::invalidateSub(size_t, const GLenum *, const gl::Rectangle &) +{ + // No-op in D3D + return gl::Error(GL_NO_ERROR); +} + +gl::Error FramebufferD3D::clear(const gl::Data &data, GLbitfield mask) +{ + const gl::State &state = *data.state; + ClearParameters clearParams = GetClearParameters(state, mask); + return clear(state, clearParams); +} + +gl::Error FramebufferD3D::clearBufferfv(const gl::State &state, GLenum buffer, GLint drawbuffer, const GLfloat *values) +{ + // glClearBufferfv can be called to clear the color buffer or depth buffer + ClearParameters clearParams = GetClearParameters(state, 0); + + if (buffer == GL_COLOR) + { + for (unsigned int i = 0; i < ArraySize(clearParams.clearColor); i++) + { + clearParams.clearColor[i] = (drawbuffer == static_cast(i)); + } + clearParams.colorFClearValue = gl::ColorF(values[0], values[1], values[2], values[3]); + clearParams.colorClearType = GL_FLOAT; + } + + if (buffer == GL_DEPTH) + { + clearParams.clearDepth = true; + clearParams.depthClearValue = values[0]; + } + + return clear(state, clearParams); +} + +gl::Error FramebufferD3D::clearBufferuiv(const gl::State &state, GLenum buffer, GLint drawbuffer, const GLuint *values) +{ + // glClearBufferuiv can only be called to clear a color buffer + ClearParameters clearParams = GetClearParameters(state, 0); + for (unsigned int i = 0; i < ArraySize(clearParams.clearColor); i++) + { + clearParams.clearColor[i] = (drawbuffer == static_cast(i)); + } + clearParams.colorUIClearValue = gl::ColorUI(values[0], values[1], values[2], values[3]); + clearParams.colorClearType = GL_UNSIGNED_INT; + + return clear(state, clearParams); +} + +gl::Error FramebufferD3D::clearBufferiv(const gl::State &state, GLenum buffer, GLint drawbuffer, const GLint *values) +{ + // glClearBufferiv can be called to clear the color buffer or stencil buffer + ClearParameters clearParams = GetClearParameters(state, 0); + + if (buffer == GL_COLOR) + { + for (unsigned int i = 0; i < ArraySize(clearParams.clearColor); i++) + { + clearParams.clearColor[i] = (drawbuffer == static_cast(i)); + } + clearParams.colorIClearValue = gl::ColorI(values[0], values[1], values[2], values[3]); + clearParams.colorClearType = GL_INT; + } + + if (buffer == GL_STENCIL) + { + clearParams.clearStencil = true; + clearParams.stencilClearValue = values[1]; + } + + return clear(state, clearParams); +} + +gl::Error FramebufferD3D::clearBufferfi(const gl::State &state, GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil) +{ + // glClearBufferfi can only be called to clear a depth stencil buffer + ClearParameters clearParams = GetClearParameters(state, 0); + clearParams.clearDepth = true; + clearParams.depthClearValue = depth; + clearParams.clearStencil = true; + clearParams.stencilClearValue = stencil; + + return clear(state, clearParams); +} + +GLenum FramebufferD3D::getImplementationColorReadFormat() const +{ + const gl::FramebufferAttachment *readAttachment = mData.getReadAttachment(); + + if (readAttachment == nullptr) + { + return GL_NONE; + } + + RenderTargetD3D *attachmentRenderTarget = NULL; + gl::Error error = GetAttachmentRenderTarget(readAttachment, &attachmentRenderTarget); + if (error.isError()) + { + return GL_NONE; + } + + GLenum implementationFormat = getRenderTargetImplementationFormat(attachmentRenderTarget); + const gl::InternalFormat &implementationFormatInfo = gl::GetInternalFormatInfo(implementationFormat); + + return implementationFormatInfo.format; +} + +GLenum FramebufferD3D::getImplementationColorReadType() const +{ + const gl::FramebufferAttachment *readAttachment = mData.getReadAttachment(); + + if (readAttachment == nullptr) + { + return GL_NONE; + } + + RenderTargetD3D *attachmentRenderTarget = NULL; + gl::Error error = GetAttachmentRenderTarget(readAttachment, &attachmentRenderTarget); + if (error.isError()) + { + return GL_NONE; + } + + GLenum implementationFormat = getRenderTargetImplementationFormat(attachmentRenderTarget); + const gl::InternalFormat &implementationFormatInfo = gl::GetInternalFormatInfo(implementationFormat); + + return implementationFormatInfo.type; +} + +gl::Error FramebufferD3D::readPixels(const gl::State &state, const gl::Rectangle &area, GLenum format, GLenum type, GLvoid *pixels) const +{ + const gl::PixelPackState &packState = state.getPackState(); + + if (packState.rowLength != 0 || packState.skipRows != 0 || packState.skipPixels != 0) + { + UNIMPLEMENTED(); + return gl::Error(GL_INVALID_OPERATION, "invalid pixel store parameters in readPixels"); + } + + GLenum sizedInternalFormat = gl::GetSizedInternalFormat(format, type); + const gl::InternalFormat &sizedFormatInfo = gl::GetInternalFormatInfo(sizedInternalFormat); + GLuint outputPitch = sizedFormatInfo.computeRowPitch(type, area.width, packState.alignment, 0); + + return readPixels(area, format, type, outputPitch, packState, reinterpret_cast(pixels)); +} + +gl::Error FramebufferD3D::blit(const gl::State &state, const gl::Rectangle &sourceArea, const gl::Rectangle &destArea, + GLbitfield mask, GLenum filter, const gl::Framebuffer *sourceFramebuffer) +{ + bool blitRenderTarget = false; + if ((mask & GL_COLOR_BUFFER_BIT) && + sourceFramebuffer->getReadColorbuffer() != nullptr && + mData.getFirstColorAttachment() != nullptr) + { + blitRenderTarget = true; + } + + bool blitStencil = false; + if ((mask & GL_STENCIL_BUFFER_BIT) && + sourceFramebuffer->getStencilbuffer() != nullptr && + mData.mStencilAttachment != nullptr) + { + blitStencil = true; + } + + bool blitDepth = false; + if ((mask & GL_DEPTH_BUFFER_BIT) && + sourceFramebuffer->getDepthbuffer() != nullptr && + mData.mDepthAttachment != nullptr) + { + blitDepth = true; + } + + if (blitRenderTarget || blitDepth || blitStencil) + { + const gl::Rectangle *scissor = state.isScissorTestEnabled() ? &state.getScissor() : NULL; + gl::Error error = blit(sourceArea, destArea, scissor, blitRenderTarget, blitDepth, blitStencil, + filter, sourceFramebuffer); + if (error.isError()) + { + return error; + } + } + + return gl::Error(GL_NO_ERROR); +} + +GLenum FramebufferD3D::checkStatus() const +{ + // D3D11 does not allow for overlapping RenderTargetViews, so ensure uniqueness + for (size_t colorAttachment = 0; colorAttachment < mData.mColorAttachments.size(); colorAttachment++) + { + const gl::FramebufferAttachment *attachment = mData.mColorAttachments[colorAttachment]; + if (attachment != nullptr) + { + for (size_t prevColorAttachment = 0; prevColorAttachment < colorAttachment; prevColorAttachment++) + { + const gl::FramebufferAttachment *prevAttachment = mData.mColorAttachments[prevColorAttachment]; + if (prevAttachment != nullptr && + (attachment->id() == prevAttachment->id() && + attachment->type() == prevAttachment->type())) + { + return GL_FRAMEBUFFER_UNSUPPORTED; + } + } + } + } + + return GL_FRAMEBUFFER_COMPLETE; +} + +const gl::AttachmentList &FramebufferD3D::getColorAttachmentsForRender(const Workarounds &workarounds) const +{ + if (!workarounds.mrtPerfWorkaround) + { + return mData.mColorAttachments; + } + + if (!mInvalidateColorAttachmentCache) + { + return mColorAttachmentsForRender; + } + + // Does not actually free memory + mColorAttachmentsForRender.clear(); + + for (size_t attachmentIndex = 0; attachmentIndex < mData.mColorAttachments.size(); ++attachmentIndex) + { + GLenum drawBufferState = mData.mDrawBufferStates[attachmentIndex]; + gl::FramebufferAttachment *colorAttachment = mData.mColorAttachments[attachmentIndex]; + + if (colorAttachment != nullptr && drawBufferState != GL_NONE) + { + ASSERT(drawBufferState == GL_BACK || drawBufferState == (GL_COLOR_ATTACHMENT0_EXT + attachmentIndex)); + mColorAttachmentsForRender.push_back(colorAttachment); + } + } + + mInvalidateColorAttachmentCache = false; + return mColorAttachmentsForRender; +} + +gl::Error GetAttachmentRenderTarget(const gl::FramebufferAttachment *attachment, RenderTargetD3D **outRT) +{ + if (attachment->type() == GL_TEXTURE) + { + gl::Texture *texture = attachment->getTexture(); + ASSERT(texture); + TextureD3D *textureD3D = GetImplAs(texture); + const gl::ImageIndex *index = attachment->getTextureImageIndex(); + ASSERT(index); + return textureD3D->getRenderTarget(*index, outRT); + } + else if (attachment->type() == GL_RENDERBUFFER) + { + gl::Renderbuffer *renderbuffer = attachment->getRenderbuffer(); + ASSERT(renderbuffer); + RenderbufferD3D *renderbufferD3D = RenderbufferD3D::makeRenderbufferD3D(renderbuffer->getImplementation()); + *outRT = renderbufferD3D->getRenderTarget(); + return gl::Error(GL_NO_ERROR); + } + else if (attachment->type() == GL_FRAMEBUFFER_DEFAULT) + { + const gl::DefaultAttachment *defaultAttachment = static_cast(attachment); + const egl::Surface *surface = defaultAttachment->getSurface(); + ASSERT(surface); + const SurfaceD3D *surfaceD3D = GetImplAs(surface); + ASSERT(surfaceD3D); + + if (defaultAttachment->getBinding() == GL_BACK) + { + *outRT = surfaceD3D->getSwapChain()->getColorRenderTarget(); + } + else + { + *outRT = surfaceD3D->getSwapChain()->getDepthStencilRenderTarget(); + } + return gl::Error(GL_NO_ERROR); + } + else + { + UNREACHABLE(); + return gl::Error(GL_INVALID_OPERATION); + } +} + +// Note: RenderTarget serials should ideally be in the RenderTargets themselves. +unsigned int GetAttachmentSerial(const gl::FramebufferAttachment *attachment) +{ + if (attachment->type() == GL_TEXTURE) + { + gl::Texture *texture = attachment->getTexture(); + ASSERT(texture); + TextureD3D *textureD3D = GetImplAs(texture); + const gl::ImageIndex *index = attachment->getTextureImageIndex(); + ASSERT(index); + return textureD3D->getRenderTargetSerial(*index); + } + else if (attachment->type() == GL_RENDERBUFFER) + { + gl::Renderbuffer *renderbuffer = attachment->getRenderbuffer(); + ASSERT(renderbuffer); + RenderbufferD3D *renderbufferD3D = RenderbufferD3D::makeRenderbufferD3D(renderbuffer->getImplementation()); + return renderbufferD3D->getRenderTargetSerial(); + } + else if (attachment->type() == GL_FRAMEBUFFER_DEFAULT) + { + const gl::DefaultAttachment *defaultAttachment = static_cast(attachment); + const egl::Surface *surface = defaultAttachment->getSurface(); + ASSERT(surface); + const SurfaceD3D *surfaceD3D = GetImplAs(surface); + ASSERT(surfaceD3D); + + if (defaultAttachment->getBinding() == GL_BACK) + { + return surfaceD3D->getSwapChain()->getColorRenderTarget()->getSerial(); + } + else + { + return surfaceD3D->getSwapChain()->getDepthStencilRenderTarget()->getSerial(); + } + } + else + { + UNREACHABLE(); + return 0; + } +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/FramebufferD3D.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/FramebufferD3D.h new file mode 100644 index 0000000000..d5d2dae8bd --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/FramebufferD3D.h @@ -0,0 +1,111 @@ +// +// Copyright 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// FramebufferD3D.h: Defines the DefaultAttachmentD3D and FramebufferD3D classes. + +#ifndef LIBANGLE_RENDERER_D3D_FRAMBUFFERD3D_H_ +#define LIBANGLE_RENDERER_D3D_FRAMBUFFERD3D_H_ + +#include +#include + +#include "libANGLE/angletypes.h" +#include "libANGLE/renderer/FramebufferImpl.h" + +namespace gl +{ +class FramebufferAttachment; +struct PixelPackState; +} + +namespace rx +{ +class RenderTargetD3D; +class RendererD3D; + +struct ClearParameters +{ + bool clearColor[gl::IMPLEMENTATION_MAX_DRAW_BUFFERS]; + gl::ColorF colorFClearValue; + gl::ColorI colorIClearValue; + gl::ColorUI colorUIClearValue; + GLenum colorClearType; + bool colorMaskRed; + bool colorMaskGreen; + bool colorMaskBlue; + bool colorMaskAlpha; + + bool clearDepth; + float depthClearValue; + + bool clearStencil; + GLint stencilClearValue; + GLuint stencilWriteMask; + + bool scissorEnabled; + gl::Rectangle scissor; +}; + +class FramebufferD3D : public FramebufferImpl +{ + public: + FramebufferD3D(const gl::Framebuffer::Data &data, RendererD3D *renderer); + virtual ~FramebufferD3D(); + + void setColorAttachment(size_t index, const gl::FramebufferAttachment *attachment) override; + void setDepthAttachment(const gl::FramebufferAttachment *attachment) override; + void setStencilAttachment(const gl::FramebufferAttachment *attachment) override; + void setDepthStencilAttachment(const gl::FramebufferAttachment *attachment) override; + + void setDrawBuffers(size_t count, const GLenum *buffers) override; + void setReadBuffer(GLenum buffer) override; + + gl::Error invalidate(size_t count, const GLenum *attachments) override; + gl::Error invalidateSub(size_t count, const GLenum *attachments, const gl::Rectangle &area) override; + + gl::Error clear(const gl::Data &data, GLbitfield mask) override; + gl::Error clearBufferfv(const gl::State &state, GLenum buffer, GLint drawbuffer, const GLfloat *values) override; + gl::Error clearBufferuiv(const gl::State &state, GLenum buffer, GLint drawbuffer, const GLuint *values) override; + gl::Error clearBufferiv(const gl::State &state, GLenum buffer, GLint drawbuffer, const GLint *values) override; + gl::Error clearBufferfi(const gl::State &state, GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil) override; + + GLenum getImplementationColorReadFormat() const override; + GLenum getImplementationColorReadType() const override; + gl::Error readPixels(const gl::State &state, const gl::Rectangle &area, GLenum format, GLenum type, GLvoid *pixels) const override; + + gl::Error blit(const gl::State &state, const gl::Rectangle &sourceArea, const gl::Rectangle &destArea, + GLbitfield mask, GLenum filter, const gl::Framebuffer *sourceFramebuffer) override; + + GLenum checkStatus() const override; + + const gl::AttachmentList &getColorAttachmentsForRender(const Workarounds &workarounds) const; + + protected: + // Cache variable + mutable gl::AttachmentList mColorAttachmentsForRender; + mutable bool mInvalidateColorAttachmentCache; + + private: + RendererD3D *const mRenderer; + + virtual gl::Error clear(const gl::State &state, const ClearParameters &clearParams) = 0; + + virtual gl::Error readPixels(const gl::Rectangle &area, GLenum format, GLenum type, size_t outputPitch, + const gl::PixelPackState &pack, uint8_t *pixels) const = 0; + + virtual gl::Error blit(const gl::Rectangle &sourceArea, const gl::Rectangle &destArea, const gl::Rectangle *scissor, + bool blitRenderTarget, bool blitDepth, bool blitStencil, GLenum filter, + const gl::Framebuffer *sourceFramebuffer) = 0; + + virtual GLenum getRenderTargetImplementationFormat(RenderTargetD3D *renderTarget) const = 0; +}; + +gl::Error GetAttachmentRenderTarget(const gl::FramebufferAttachment *attachment, RenderTargetD3D **outRT); +unsigned int GetAttachmentSerial(const gl::FramebufferAttachment *attachment); + +} + +#endif // LIBANGLE_RENDERER_D3D_FRAMBUFFERD3D_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/HLSLCompiler.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/HLSLCompiler.cpp new file mode 100644 index 0000000000..8961a36ec5 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/HLSLCompiler.cpp @@ -0,0 +1,340 @@ +// +// Copyright 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "libANGLE/renderer/d3d/HLSLCompiler.h" +#include "libANGLE/Program.h" +#include "libANGLE/features.h" + +#include "common/utilities.h" + +#include "third_party/trace_event/trace_event.h" + +#ifndef QT_D3DCOMPILER_DLL +#define QT_D3DCOMPILER_DLL D3DCOMPILER_DLL +#endif + +// Definitions local to the translation unit +namespace +{ + +#ifdef CREATE_COMPILER_FLAG_INFO + #undef CREATE_COMPILER_FLAG_INFO +#endif + +#define CREATE_COMPILER_FLAG_INFO(flag) { flag, #flag } + +#if defined(ANGLE_MINGW32_COMPAT) +#ifndef D3DCOMPILE_RESERVED16 +#define D3DCOMPILE_RESERVED16 0x10000 +#endif +#ifndef D3DCOMPILE_RESERVED17 +#define D3DCOMPILE_RESERVED17 0x20000 +#endif +#endif + +struct CompilerFlagInfo +{ + UINT mFlag; + const char *mName; +}; + +CompilerFlagInfo CompilerFlagInfos[] = +{ + // NOTE: The data below is copied from d3dcompiler.h + // If something changes there it should be changed here as well + CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_DEBUG), // (1 << 0) + CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_SKIP_VALIDATION), // (1 << 1) + CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_SKIP_OPTIMIZATION), // (1 << 2) + CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_PACK_MATRIX_ROW_MAJOR), // (1 << 3) + CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_PACK_MATRIX_COLUMN_MAJOR), // (1 << 4) + CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_PARTIAL_PRECISION), // (1 << 5) + CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_FORCE_VS_SOFTWARE_NO_OPT), // (1 << 6) + CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_FORCE_PS_SOFTWARE_NO_OPT), // (1 << 7) + CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_NO_PRESHADER), // (1 << 8) + CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_AVOID_FLOW_CONTROL), // (1 << 9) + CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_PREFER_FLOW_CONTROL), // (1 << 10) + CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_ENABLE_STRICTNESS), // (1 << 11) + CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_ENABLE_BACKWARDS_COMPATIBILITY), // (1 << 12) + CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_IEEE_STRICTNESS), // (1 << 13) + CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_OPTIMIZATION_LEVEL0), // (1 << 14) + CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_OPTIMIZATION_LEVEL1), // 0 + CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_OPTIMIZATION_LEVEL2), // ((1 << 14) | (1 << 15)) + CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_OPTIMIZATION_LEVEL3), // (1 << 15) + CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_RESERVED16), // (1 << 16) + CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_RESERVED17), // (1 << 17) + CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_WARNINGS_ARE_ERRORS) // (1 << 18) +}; + +#undef CREATE_COMPILER_FLAG_INFO + +bool IsCompilerFlagSet(UINT mask, UINT flag) +{ + bool isFlagSet = IsMaskFlagSet(mask, flag); + + switch(flag) + { + case D3DCOMPILE_OPTIMIZATION_LEVEL0: + return isFlagSet && !IsMaskFlagSet(mask, UINT(D3DCOMPILE_OPTIMIZATION_LEVEL3)); + + case D3DCOMPILE_OPTIMIZATION_LEVEL1: + return (mask & D3DCOMPILE_OPTIMIZATION_LEVEL2) == UINT(0); + + case D3DCOMPILE_OPTIMIZATION_LEVEL3: + return isFlagSet && !IsMaskFlagSet(mask, UINT(D3DCOMPILE_OPTIMIZATION_LEVEL0)); + + default: + return isFlagSet; + } +} + +const char *GetCompilerFlagName(UINT mask, size_t flagIx) +{ + const CompilerFlagInfo &flagInfo = CompilerFlagInfos[flagIx]; + if (IsCompilerFlagSet(mask, flagInfo.mFlag)) + { + return flagInfo.mName; + } + + return nullptr; +} + +} + +namespace rx +{ + +CompileConfig::CompileConfig() + : flags(0), + name() +{ +} + +CompileConfig::CompileConfig(UINT flags, const std::string &name) + : flags(flags), + name(name) +{ +} + +HLSLCompiler::HLSLCompiler() + : mD3DCompilerModule(NULL), + mD3DCompileFunc(NULL), + mD3DDisassembleFunc(NULL) +{ +} + +HLSLCompiler::~HLSLCompiler() +{ + release(); +} + +bool HLSLCompiler::initialize() +{ + TRACE_EVENT0("gpu", "initializeCompiler"); +#if !defined(ANGLE_ENABLE_WINDOWS_STORE) +#if defined(ANGLE_PRELOADED_D3DCOMPILER_MODULE_NAMES) + // Find a D3DCompiler module that had already been loaded based on a predefined list of versions. + static const char *d3dCompilerNames[] = ANGLE_PRELOADED_D3DCOMPILER_MODULE_NAMES; + + for (size_t i = 0; i < ArraySize(d3dCompilerNames); ++i) + { + if (GetModuleHandleExA(0, d3dCompilerNames[i], &mD3DCompilerModule)) + { + break; + } + } +#endif // ANGLE_PRELOADED_D3DCOMPILER_MODULE_NAMES + + // Load the compiler DLL specified by the environment, or default to QT_D3DCOMPILER_DLL + const wchar_t *defaultCompiler = _wgetenv(L"QT_D3DCOMPILER_DLL"); + if (!defaultCompiler) + defaultCompiler = QT_D3DCOMPILER_DLL; + + const wchar_t *compilerDlls[] = { + defaultCompiler, + L"d3dcompiler_47.dll", + L"d3dcompiler_46.dll", + L"d3dcompiler_43.dll", + 0 + }; + + // Load the first available known compiler DLL + for (int i = 0; compilerDlls[i]; ++i) + { + mD3DCompilerModule = LoadLibrary(compilerDlls[i]); + if (mD3DCompilerModule) + break; + } + + if (!mD3DCompilerModule) + { + // Load the version of the D3DCompiler DLL associated with the Direct3D version ANGLE was built with. + mD3DCompilerModule = LoadLibrary(D3DCOMPILER_DLL); + } + + if (!mD3DCompilerModule) + { + ERR("No D3D compiler module found - aborting!\n"); + return false; + } + + mD3DCompileFunc = reinterpret_cast(GetProcAddress(mD3DCompilerModule, "D3DCompile")); + ASSERT(mD3DCompileFunc); + + mD3DDisassembleFunc = reinterpret_cast(GetProcAddress(mD3DCompilerModule, "D3DDisassemble")); + ASSERT(mD3DDisassembleFunc); + +#else + // D3D Shader compiler is linked already into this module, so the export + // can be directly assigned. + mD3DCompilerModule = NULL; + mD3DCompileFunc = reinterpret_cast(D3DCompile); + mD3DDisassembleFunc = reinterpret_cast(D3DDisassemble); +#endif + + return mD3DCompileFunc != NULL; +} + +void HLSLCompiler::release() +{ + if (mD3DCompilerModule) + { + FreeLibrary(mD3DCompilerModule); + mD3DCompilerModule = NULL; + mD3DCompileFunc = NULL; + mD3DDisassembleFunc = NULL; + } +} + +gl::Error HLSLCompiler::compileToBinary(gl::InfoLog &infoLog, const std::string &hlsl, const std::string &profile, + const std::vector &configs, const D3D_SHADER_MACRO *overrideMacros, + ID3DBlob **outCompiledBlob, std::string *outDebugInfo) const +{ +#if !defined(ANGLE_ENABLE_WINDOWS_STORE) + ASSERT(mD3DCompilerModule); +#endif + ASSERT(mD3DCompileFunc); + +#if !defined(ANGLE_ENABLE_WINDOWS_STORE) + if (gl::DebugAnnotationsActive()) + { + std::string sourcePath = getTempPath(); + std::string sourceText = FormatString("#line 2 \"%s\"\n\n%s", sourcePath.c_str(), hlsl.c_str()); + writeFile(sourcePath.c_str(), sourceText.c_str(), sourceText.size()); + } +#endif + + const D3D_SHADER_MACRO *macros = overrideMacros ? overrideMacros : NULL; + + for (size_t i = 0; i < configs.size(); ++i) + { + ID3DBlob *errorMessage = NULL; + ID3DBlob *binary = NULL; + + HRESULT result = mD3DCompileFunc(hlsl.c_str(), hlsl.length(), gl::g_fakepath, macros, NULL, "main", profile.c_str(), + configs[i].flags, 0, &binary, &errorMessage); + + if (errorMessage) + { + std::string message = reinterpret_cast(errorMessage->GetBufferPointer()); + SafeRelease(errorMessage); + + infoLog.appendSanitized(message.c_str()); + TRACE("\n%s", hlsl.c_str()); + TRACE("\n%s", message.c_str()); + + if (message.find("error X3531:") != std::string::npos || // "can't unroll loops marked with loop attribute" + message.find("error X4014:") != std::string::npos) // "cannot have gradient operations inside loops with divergent flow control", + // even though it is counter-intuitive to disable unrolling for this error, + // some very long shaders have trouble deciding which loops to unroll and + // turning off forced unrolls allows them to compile properly. + { + macros = NULL; // Disable [loop] and [flatten] + + // Retry without changing compiler flags + i--; + continue; + } + } + + if (SUCCEEDED(result)) + { + *outCompiledBlob = binary; + +#if ANGLE_SHADER_DEBUG_INFO == ANGLE_ENABLED + (*outDebugInfo) += "// COMPILER INPUT HLSL BEGIN\n\n" + hlsl + "\n// COMPILER INPUT HLSL END\n"; + (*outDebugInfo) += "\n\n// ASSEMBLY BEGIN\n\n"; + (*outDebugInfo) += "// Compiler configuration: " + configs[i].name + "\n// Flags:\n"; + for (size_t fIx = 0; fIx < ArraySize(CompilerFlagInfos); ++fIx) + { + const char *flagName = GetCompilerFlagName(configs[i].flags, fIx); + if (flagName != nullptr) + { + (*outDebugInfo) += std::string("// ") + flagName + "\n"; + } + } + + (*outDebugInfo) += "// Macros:\n"; + if (macros == nullptr) + { + (*outDebugInfo) += "// - : -\n"; + } + else + { + for (const D3D_SHADER_MACRO *mIt = macros; mIt->Name != nullptr; ++mIt) + { + (*outDebugInfo) += std::string("// ") + mIt->Name + " : " + mIt->Definition + "\n"; + } + } + + (*outDebugInfo) += "\n" + disassembleBinary(binary) + "\n// ASSEMBLY END\n"; +#endif + + return gl::Error(GL_NO_ERROR); + } + else + { + if (result == E_OUTOFMEMORY) + { + *outCompiledBlob = NULL; + return gl::Error(GL_OUT_OF_MEMORY, "HLSL compiler had an unexpected failure, result: 0x%X.", result); + } + + infoLog.append("Warning: D3D shader compilation failed with %s flags.", configs[i].name.c_str()); + + if (i + 1 < configs.size()) + { + infoLog.append(" Retrying with %s.\n", configs[i + 1].name.c_str()); + } + } + } + + // None of the configurations succeeded in compiling this shader but the compiler is still intact + *outCompiledBlob = NULL; + return gl::Error(GL_NO_ERROR); +} + +std::string HLSLCompiler::disassembleBinary(ID3DBlob *shaderBinary) const +{ + // Retrieve disassembly + UINT flags = D3D_DISASM_ENABLE_DEFAULT_VALUE_PRINTS | D3D_DISASM_ENABLE_INSTRUCTION_NUMBERING; + ID3DBlob *disassembly = NULL; + pD3DDisassemble disassembleFunc = reinterpret_cast(mD3DDisassembleFunc); + LPCVOID buffer = shaderBinary->GetBufferPointer(); + SIZE_T bufSize = shaderBinary->GetBufferSize(); + HRESULT result = disassembleFunc(buffer, bufSize, flags, "", &disassembly); + + std::string asmSrc; + if (SUCCEEDED(result)) + { + asmSrc = reinterpret_cast(disassembly->GetBufferPointer()); + } + + SafeRelease(disassembly); + + return asmSrc; +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/HLSLCompiler.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/HLSLCompiler.h new file mode 100644 index 0000000000..a824952553 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/HLSLCompiler.h @@ -0,0 +1,54 @@ +#ifndef LIBANGLE_RENDERER_D3D_HLSLCOMPILER_H_ +#define LIBANGLE_RENDERER_D3D_HLSLCOMPILER_H_ + +#include "libANGLE/Error.h" + +#include "common/angleutils.h" +#include "common/platform.h" + +#include +#include + +namespace gl +{ +class InfoLog; +} + +namespace rx +{ + +struct CompileConfig +{ + UINT flags; + std::string name; + + CompileConfig(); + CompileConfig(UINT flags, const std::string &name); +}; + +class HLSLCompiler : angle::NonCopyable +{ + public: + HLSLCompiler(); + ~HLSLCompiler(); + + bool initialize(); + void release(); + + // Attempt to compile a HLSL shader using the supplied configurations, may output a NULL compiled blob + // even if no GL errors are returned. + gl::Error compileToBinary(gl::InfoLog &infoLog, const std::string &hlsl, const std::string &profile, + const std::vector &configs, const D3D_SHADER_MACRO *overrideMacros, + ID3DBlob **outCompiledBlob, std::string *outDebugInfo) const; + + std::string disassembleBinary(ID3DBlob* shaderBinary) const; + + private: + HMODULE mD3DCompilerModule; + pD3DCompile mD3DCompileFunc; + pD3DDisassemble mD3DDisassembleFunc; +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_HLSLCOMPILER_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/ImageD3D.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/ImageD3D.cpp new file mode 100644 index 0000000000..4e6f61150a --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/ImageD3D.cpp @@ -0,0 +1,47 @@ +// +// Copyright (c) 2002-2015 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Image.h: Implements the rx::Image class, an abstract base class for the +// renderer-specific classes which will define the interface to the underlying +// surfaces or resources. + +#include "libANGLE/renderer/d3d/ImageD3D.h" + +#include "libANGLE/Framebuffer.h" +#include "libANGLE/FramebufferAttachment.h" +#include "libANGLE/renderer/d3d/FramebufferD3D.h" + +namespace rx +{ + +ImageD3D::ImageD3D() + : mWidth(0), + mHeight(0), + mDepth(0), + mInternalFormat(GL_NONE), + mTarget(GL_NONE), + mRenderable(false), + mDirty(false) +{ +} + +gl::Error ImageD3D::copy(const gl::Offset &destOffset, const gl::Rectangle &sourceArea, const gl::Framebuffer *source) +{ + gl::FramebufferAttachment *colorbuffer = source->getReadColorbuffer(); + ASSERT(colorbuffer); + + RenderTargetD3D *renderTarget = NULL; + gl::Error error = GetAttachmentRenderTarget(colorbuffer, &renderTarget); + if (error.isError()) + { + return error; + } + + ASSERT(renderTarget); + return copy(destOffset, sourceArea, renderTarget); +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/ImageD3D.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/ImageD3D.h new file mode 100644 index 0000000000..0fe88a8f59 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/ImageD3D.h @@ -0,0 +1,84 @@ +// +// Copyright (c) 2002-2015 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// ImageD3D.h: Defines the rx::ImageD3D class, an abstract base class for the +// renderer-specific classes which will define the interface to the underlying +// surfaces or resources. + +#ifndef LIBANGLE_RENDERER_D3D_IMAGED3D_H_ +#define LIBANGLE_RENDERER_D3D_IMAGED3D_H_ + +#include "common/debug.h" + +#include "libANGLE/Error.h" + +namespace gl +{ +class Framebuffer; +struct ImageIndex; +struct Box; +struct Extents; +struct Offset; +struct Rectangle; +struct PixelUnpackState; +} + +namespace rx +{ +class TextureStorage; +class RendererD3D; +class RenderTargetD3D; + +class ImageD3D : angle::NonCopyable +{ + public: + ImageD3D(); + virtual ~ImageD3D() {}; + + GLsizei getWidth() const { return mWidth; } + GLsizei getHeight() const { return mHeight; } + GLsizei getDepth() const { return mDepth; } + GLenum getInternalFormat() const { return mInternalFormat; } + GLenum getTarget() const { return mTarget; } + bool isRenderableFormat() const { return mRenderable; } + + void markDirty() { mDirty = true; } + void markClean() { mDirty = false; } + virtual bool isDirty() const = 0; + + virtual bool redefine(GLenum target, GLenum internalformat, const gl::Extents &size, bool forceRelease) = 0; + + virtual gl::Error loadData(const gl::Box &area, const gl::PixelUnpackState &unpack, GLenum type, const void *input) = 0; + virtual gl::Error loadCompressedData(const gl::Box &area, const void *input) = 0; + + virtual gl::Error setManagedSurface2D(TextureStorage *storage, int level) { return gl::Error(GL_NO_ERROR); }; + virtual gl::Error setManagedSurfaceCube(TextureStorage *storage, int face, int level) { return gl::Error(GL_NO_ERROR); }; + virtual gl::Error setManagedSurface3D(TextureStorage *storage, int level) { return gl::Error(GL_NO_ERROR); }; + virtual gl::Error setManagedSurface2DArray(TextureStorage *storage, int layer, int level) { return gl::Error(GL_NO_ERROR); }; + virtual gl::Error copyToStorage(TextureStorage *storage, const gl::ImageIndex &index, const gl::Box ®ion) = 0; + + virtual gl::Error copy(const gl::Offset &destOffset, const gl::Box &sourceArea, + const gl::ImageIndex &sourceIndex, TextureStorage *source) = 0; + + gl::Error copy(const gl::Offset &destOffset, const gl::Rectangle &sourceArea, const gl::Framebuffer *source); + + protected: + GLsizei mWidth; + GLsizei mHeight; + GLsizei mDepth; + GLenum mInternalFormat; + bool mRenderable; + GLenum mTarget; + + bool mDirty; + + private: + virtual gl::Error copy(const gl::Offset &destOffset, const gl::Rectangle &sourceArea, RenderTargetD3D *source) = 0; +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_IMAGED3D_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/IndexBuffer.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/IndexBuffer.cpp new file mode 100644 index 0000000000..677b8bb240 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/IndexBuffer.cpp @@ -0,0 +1,196 @@ +// +// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// IndexBuffer.cpp: Defines the abstract IndexBuffer class and IndexBufferInterface +// class with derivations, classes that perform graphics API agnostic index buffer operations. + +#include "libANGLE/renderer/d3d/IndexBuffer.h" +#include "libANGLE/renderer/d3d/RendererD3D.h" + +namespace rx +{ + +unsigned int IndexBuffer::mNextSerial = 1; + +IndexBuffer::IndexBuffer() +{ + updateSerial(); +} + +IndexBuffer::~IndexBuffer() +{ +} + +unsigned int IndexBuffer::getSerial() const +{ + return mSerial; +} + +void IndexBuffer::updateSerial() +{ + mSerial = mNextSerial++; +} + + +IndexBufferInterface::IndexBufferInterface(BufferFactoryD3D *factory, bool dynamic) +{ + mIndexBuffer = factory->createIndexBuffer(); + + mDynamic = dynamic; + mWritePosition = 0; +} + +IndexBufferInterface::~IndexBufferInterface() +{ + if (mIndexBuffer) + { + delete mIndexBuffer; + } +} + +GLenum IndexBufferInterface::getIndexType() const +{ + return mIndexBuffer->getIndexType(); +} + +unsigned int IndexBufferInterface::getBufferSize() const +{ + return mIndexBuffer->getBufferSize(); +} + +unsigned int IndexBufferInterface::getSerial() const +{ + return mIndexBuffer->getSerial(); +} + +gl::Error IndexBufferInterface::mapBuffer(unsigned int size, void **outMappedMemory, unsigned int *streamOffset) +{ + // Protect against integer overflow + if (mWritePosition + size < mWritePosition) + { + return gl::Error(GL_OUT_OF_MEMORY, "Mapping of internal index buffer would cause an integer overflow."); + } + + gl::Error error = mIndexBuffer->mapBuffer(mWritePosition, size, outMappedMemory); + if (error.isError()) + { + if (outMappedMemory) + { + *outMappedMemory = NULL; + } + return error; + } + + if (streamOffset) + { + *streamOffset = mWritePosition; + } + + mWritePosition += size; + return gl::Error(GL_NO_ERROR); +} + +gl::Error IndexBufferInterface::unmapBuffer() +{ + return mIndexBuffer->unmapBuffer(); +} + +IndexBuffer * IndexBufferInterface::getIndexBuffer() const +{ + return mIndexBuffer; +} + +unsigned int IndexBufferInterface::getWritePosition() const +{ + return mWritePosition; +} + +void IndexBufferInterface::setWritePosition(unsigned int writePosition) +{ + mWritePosition = writePosition; +} + +gl::Error IndexBufferInterface::discard() +{ + return mIndexBuffer->discard(); +} + +gl::Error IndexBufferInterface::setBufferSize(unsigned int bufferSize, GLenum indexType) +{ + if (mIndexBuffer->getBufferSize() == 0) + { + return mIndexBuffer->initialize(bufferSize, indexType, mDynamic); + } + else + { + return mIndexBuffer->setSize(bufferSize, indexType); + } +} + +StreamingIndexBufferInterface::StreamingIndexBufferInterface(BufferFactoryD3D *factory) + : IndexBufferInterface(factory, true) +{ +} + +StreamingIndexBufferInterface::~StreamingIndexBufferInterface() +{ +} + +gl::Error StreamingIndexBufferInterface::reserveBufferSpace(unsigned int size, GLenum indexType) +{ + unsigned int curBufferSize = getBufferSize(); + unsigned int writePos = getWritePosition(); + if (size > curBufferSize) + { + gl::Error error = setBufferSize(std::max(size, 2 * curBufferSize), indexType); + if (error.isError()) + { + return error; + } + setWritePosition(0); + } + else if (writePos + size > curBufferSize || writePos + size < writePos) + { + gl::Error error = discard(); + if (error.isError()) + { + return error; + } + setWritePosition(0); + } + + return gl::Error(GL_NO_ERROR); +} + + +StaticIndexBufferInterface::StaticIndexBufferInterface(BufferFactoryD3D *factory) + : IndexBufferInterface(factory, false) +{ +} + +StaticIndexBufferInterface::~StaticIndexBufferInterface() +{ +} + +gl::Error StaticIndexBufferInterface::reserveBufferSpace(unsigned int size, GLenum indexType) +{ + unsigned int curSize = getBufferSize(); + if (curSize == 0) + { + return setBufferSize(size, indexType); + } + else if (curSize >= size && indexType == getIndexType()) + { + return gl::Error(GL_NO_ERROR); + } + else + { + UNREACHABLE(); + return gl::Error(GL_INVALID_OPERATION, "Internal static index buffers can't be resized"); + } +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/IndexBuffer.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/IndexBuffer.h new file mode 100644 index 0000000000..36262f1d09 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/IndexBuffer.h @@ -0,0 +1,101 @@ +// +// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// IndexBuffer.h: Defines the abstract IndexBuffer class and IndexBufferInterface +// class with derivations, classes that perform graphics API agnostic index buffer operations. + +#ifndef LIBANGLE_RENDERER_D3D_INDEXBUFFER_H_ +#define LIBANGLE_RENDERER_D3D_INDEXBUFFER_H_ + +#include "common/angleutils.h" +#include "libANGLE/Error.h" +#include "libANGLE/renderer/IndexRangeCache.h" + +namespace rx +{ +class BufferFactoryD3D; + +class IndexBuffer : angle::NonCopyable +{ + public: + IndexBuffer(); + virtual ~IndexBuffer(); + + virtual gl::Error initialize(unsigned int bufferSize, GLenum indexType, bool dynamic) = 0; + + virtual gl::Error mapBuffer(unsigned int offset, unsigned int size, void** outMappedMemory) = 0; + virtual gl::Error unmapBuffer() = 0; + + virtual gl::Error discard() = 0; + + virtual GLenum getIndexType() const = 0; + virtual unsigned int getBufferSize() const = 0; + virtual gl::Error setSize(unsigned int bufferSize, GLenum indexType) = 0; + + unsigned int getSerial() const; + + protected: + void updateSerial(); + + private: + unsigned int mSerial; + static unsigned int mNextSerial; +}; + +class IndexBufferInterface : angle::NonCopyable +{ + public: + IndexBufferInterface(BufferFactoryD3D *factory, bool dynamic); + virtual ~IndexBufferInterface(); + + virtual gl::Error reserveBufferSpace(unsigned int size, GLenum indexType) = 0; + + GLenum getIndexType() const; + unsigned int getBufferSize() const; + + unsigned int getSerial() const; + + gl::Error mapBuffer(unsigned int size, void** outMappedMemory, unsigned int *streamOffset); + gl::Error unmapBuffer(); + + IndexBuffer *getIndexBuffer() const; + + protected: + unsigned int getWritePosition() const; + void setWritePosition(unsigned int writePosition); + + gl::Error discard(); + + gl::Error setBufferSize(unsigned int bufferSize, GLenum indexType); + + private: + IndexBuffer *mIndexBuffer; + + unsigned int mWritePosition; + bool mDynamic; +}; + +class StreamingIndexBufferInterface : public IndexBufferInterface +{ + public: + explicit StreamingIndexBufferInterface(BufferFactoryD3D *factory); + ~StreamingIndexBufferInterface(); + + gl::Error reserveBufferSpace(unsigned int size, GLenum indexType) override; +}; + +class StaticIndexBufferInterface : public IndexBufferInterface +{ + public: + explicit StaticIndexBufferInterface(BufferFactoryD3D *factory); + ~StaticIndexBufferInterface(); + + gl::Error reserveBufferSpace(unsigned int size, GLenum indexType) override; +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_INDEXBUFFER_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/IndexDataManager.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/IndexDataManager.cpp new file mode 100644 index 0000000000..7dad269435 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/IndexDataManager.cpp @@ -0,0 +1,267 @@ +// +// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// IndexDataManager.cpp: Defines the IndexDataManager, a class that +// runs the Buffer translation process for index buffers. + +#include "libANGLE/renderer/d3d/IndexDataManager.h" +#include "libANGLE/renderer/d3d/BufferD3D.h" +#include "libANGLE/renderer/d3d/IndexBuffer.h" +#include "libANGLE/Buffer.h" +#include "libANGLE/formatutils.h" + +namespace rx +{ + +static void ConvertIndices(GLenum sourceType, GLenum destinationType, const void *input, GLsizei count, void *output) +{ + if (sourceType == GL_UNSIGNED_BYTE) + { + ASSERT(destinationType == GL_UNSIGNED_SHORT); + const GLubyte *in = static_cast(input); + GLushort *out = static_cast(output); + + for (GLsizei i = 0; i < count; i++) + { + out[i] = in[i]; + } + } + else if (sourceType == GL_UNSIGNED_INT) + { + ASSERT(destinationType == GL_UNSIGNED_INT); + memcpy(output, input, count * sizeof(GLuint)); + } + else if (sourceType == GL_UNSIGNED_SHORT) + { + if (destinationType == GL_UNSIGNED_SHORT) + { + memcpy(output, input, count * sizeof(GLushort)); + } + else if (destinationType == GL_UNSIGNED_INT) + { + const GLushort *in = static_cast(input); + GLuint *out = static_cast(output); + + for (GLsizei i = 0; i < count; i++) + { + out[i] = in[i]; + } + } + else UNREACHABLE(); + } + else UNREACHABLE(); +} + +IndexDataManager::IndexDataManager(BufferFactoryD3D *factory, RendererClass rendererClass) + : mFactory(factory), + mRendererClass(rendererClass), + mStreamingBufferShort(nullptr), + mStreamingBufferInt(nullptr) +{ +} + +IndexDataManager::~IndexDataManager() +{ + SafeDelete(mStreamingBufferShort); + SafeDelete(mStreamingBufferInt); +} + +gl::Error IndexDataManager::prepareIndexData(GLenum type, GLsizei count, gl::Buffer *buffer, const GLvoid *indices, TranslatedIndexData *translated) +{ + const gl::Type &typeInfo = gl::GetTypeInfo(type); + + GLenum destinationIndexType = (type == GL_UNSIGNED_INT) ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT; + + unsigned int offset = 0; + bool alignedOffset = false; + + BufferD3D *storage = NULL; + + if (buffer != NULL) + { + offset = static_cast(reinterpret_cast(indices)); + + storage = GetImplAs(buffer); + + // We'll trust that the compiler will optimize the % below: + // the operands are unsigned and the divisor is a constant. + switch (type) + { + case GL_UNSIGNED_BYTE: alignedOffset = (offset % sizeof(GLubyte) == 0); break; + case GL_UNSIGNED_SHORT: alignedOffset = (offset % sizeof(GLushort) == 0); break; + case GL_UNSIGNED_INT: alignedOffset = (offset % sizeof(GLuint) == 0); break; + default: UNREACHABLE(); alignedOffset = false; + } + + ASSERT(typeInfo.bytes * static_cast(count) + offset <= storage->getSize()); + + const uint8_t *bufferData = NULL; + gl::Error error = storage->getData(&bufferData); + if (error.isError()) + { + return error; + } + + indices = bufferData + offset; + } + + StaticIndexBufferInterface *staticBuffer = storage ? storage->getStaticIndexBuffer() : NULL; + IndexBufferInterface *indexBuffer = NULL; + bool directStorage = alignedOffset && storage && storage->supportsDirectBinding() && + destinationIndexType == type; + unsigned int streamOffset = 0; + + if (directStorage) + { + streamOffset = offset; + } + else if (staticBuffer && staticBuffer->getBufferSize() != 0 && staticBuffer->getIndexType() == type && alignedOffset) + { + indexBuffer = staticBuffer; + + // Using bit-shift here is faster than using division. + streamOffset = (offset >> typeInfo.bytesShift) << gl::GetTypeInfo(destinationIndexType).bytesShift; + } + + // Avoid D3D11's primitive restart index value + // see http://msdn.microsoft.com/en-us/library/windows/desktop/bb205124(v=vs.85).aspx + if (translated->indexRange.end == 0xFFFF && type == GL_UNSIGNED_SHORT && mRendererClass == RENDERER_D3D11) + { + destinationIndexType = GL_UNSIGNED_INT; + directStorage = false; + indexBuffer = NULL; + } + + const gl::Type &destTypeInfo = gl::GetTypeInfo(destinationIndexType); + + if (!directStorage && !indexBuffer) + { + gl::Error error = getStreamingIndexBuffer(destinationIndexType, &indexBuffer); + if (error.isError()) + { + return error; + } + + unsigned int convertCount = count; + + if (staticBuffer) + { + if (staticBuffer->getBufferSize() == 0 && alignedOffset) + { + indexBuffer = staticBuffer; + // Using bit-shift here is faster than using division. + convertCount = storage->getSize() >> typeInfo.bytesShift; + } + else + { + storage->invalidateStaticData(); + staticBuffer = NULL; + } + } + + ASSERT(indexBuffer); + + // Using bit-shift here is faster than using division. + if (convertCount > (std::numeric_limits::max() >> destTypeInfo.bytesShift)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Reserving %u indices of %u bytes each exceeds the maximum buffer size.", + convertCount, destTypeInfo.bytes); + } + + unsigned int bufferSizeRequired = convertCount << destTypeInfo.bytesShift; + error = indexBuffer->reserveBufferSpace(bufferSizeRequired, type); + if (error.isError()) + { + return error; + } + + void* output = NULL; + error = indexBuffer->mapBuffer(bufferSizeRequired, &output, &streamOffset); + if (error.isError()) + { + return error; + } + + const uint8_t *dataPointer = reinterpret_cast(indices); + if (staticBuffer) + { + error = storage->getData(&dataPointer); + if (error.isError()) + { + return error; + } + } + ConvertIndices(type, destinationIndexType, dataPointer, convertCount, output); + + error = indexBuffer->unmapBuffer(); + if (error.isError()) + { + return error; + } + + if (staticBuffer) + { + // Using bit-shift here is faster than using division. + streamOffset = (offset >> typeInfo.bytesShift) << destTypeInfo.bytesShift; + } + } + + translated->storage = directStorage ? storage : NULL; + translated->indexBuffer = indexBuffer ? indexBuffer->getIndexBuffer() : NULL; + translated->serial = directStorage ? storage->getSerial() : indexBuffer->getSerial(); + // Using bit-shift here is faster than using division. + translated->startIndex = (streamOffset >> destTypeInfo.bytesShift); + translated->startOffset = streamOffset; + translated->indexType = destinationIndexType; + + if (storage) + { + storage->promoteStaticUsage(count << typeInfo.bytesShift); + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error IndexDataManager::getStreamingIndexBuffer(GLenum destinationIndexType, IndexBufferInterface **outBuffer) +{ + ASSERT(outBuffer); + if (destinationIndexType == GL_UNSIGNED_INT) + { + if (!mStreamingBufferInt) + { + mStreamingBufferInt = new StreamingIndexBufferInterface(mFactory); + gl::Error error = mStreamingBufferInt->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_INT); + if (error.isError()) + { + SafeDelete(mStreamingBufferInt); + return error; + } + } + + *outBuffer = mStreamingBufferInt; + return gl::Error(GL_NO_ERROR); + } + else + { + ASSERT(destinationIndexType == GL_UNSIGNED_SHORT); + + if (!mStreamingBufferShort) + { + mStreamingBufferShort = new StreamingIndexBufferInterface(mFactory); + gl::Error error = mStreamingBufferShort->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_SHORT); + if (error.isError()) + { + SafeDelete(mStreamingBufferShort); + return error; + } + } + + *outBuffer = mStreamingBufferShort; + return gl::Error(GL_NO_ERROR); + } +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/IndexDataManager.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/IndexDataManager.h new file mode 100644 index 0000000000..275b3720c5 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/IndexDataManager.h @@ -0,0 +1,70 @@ +// +// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// IndexDataManager.h: Defines the IndexDataManager, a class that +// runs the Buffer translation process for index buffers. + +#ifndef LIBANGLE_INDEXDATAMANAGER_H_ +#define LIBANGLE_INDEXDATAMANAGER_H_ + +#include + +#include "common/angleutils.h" +#include "common/mathutil.h" +#include "libANGLE/Error.h" +#include "libANGLE/renderer/d3d/RendererD3D.h" + +namespace +{ + enum { INITIAL_INDEX_BUFFER_SIZE = 4096 * sizeof(GLuint) }; +} + +namespace gl +{ +class Buffer; +} + +namespace rx +{ +class IndexBufferInterface; +class StaticIndexBufferInterface; +class StreamingIndexBufferInterface; +class IndexBuffer; +class BufferD3D; +class RendererD3D; + +struct TranslatedIndexData +{ + RangeUI indexRange; + unsigned int startIndex; + unsigned int startOffset; // In bytes + + IndexBuffer *indexBuffer; + BufferD3D *storage; + GLenum indexType; + unsigned int serial; +}; + +class IndexDataManager : angle::NonCopyable +{ + public: + explicit IndexDataManager(BufferFactoryD3D *factory, RendererClass rendererClass); + virtual ~IndexDataManager(); + + gl::Error prepareIndexData(GLenum type, GLsizei count, gl::Buffer *arrayElementBuffer, const GLvoid *indices, TranslatedIndexData *translated); + + private: + gl::Error getStreamingIndexBuffer(GLenum destinationIndexType, IndexBufferInterface **outBuffer); + + BufferFactoryD3D *const mFactory; + RendererClass mRendererClass; + StreamingIndexBufferInterface *mStreamingBufferShort; + StreamingIndexBufferInterface *mStreamingBufferInt; +}; + +} + +#endif // LIBANGLE_INDEXDATAMANAGER_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/ProgramD3D.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/ProgramD3D.cpp new file mode 100644 index 0000000000..9ce9a27cd3 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/ProgramD3D.cpp @@ -0,0 +1,2005 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// ProgramD3D.cpp: Defines the rx::ProgramD3D class which implements rx::ProgramImpl. + +#include "libANGLE/renderer/d3d/ProgramD3D.h" + +#include "common/utilities.h" +#include "libANGLE/Framebuffer.h" +#include "libANGLE/FramebufferAttachment.h" +#include "libANGLE/Program.h" +#include "libANGLE/features.h" +#include "libANGLE/renderer/d3d/DynamicHLSL.h" +#include "libANGLE/renderer/d3d/FramebufferD3D.h" +#include "libANGLE/renderer/d3d/RendererD3D.h" +#include "libANGLE/renderer/d3d/ShaderD3D.h" +#include "libANGLE/renderer/d3d/ShaderExecutableD3D.h" +#include "libANGLE/renderer/d3d/VertexDataManager.h" + +namespace rx +{ + +namespace +{ + +GLenum GetTextureType(GLenum samplerType) +{ + switch (samplerType) + { + case GL_SAMPLER_2D: + case GL_INT_SAMPLER_2D: + case GL_UNSIGNED_INT_SAMPLER_2D: + case GL_SAMPLER_2D_SHADOW: + return GL_TEXTURE_2D; + case GL_SAMPLER_3D: + case GL_INT_SAMPLER_3D: + case GL_UNSIGNED_INT_SAMPLER_3D: + return GL_TEXTURE_3D; + case GL_SAMPLER_CUBE: + case GL_SAMPLER_CUBE_SHADOW: + return GL_TEXTURE_CUBE_MAP; + case GL_INT_SAMPLER_CUBE: + case GL_UNSIGNED_INT_SAMPLER_CUBE: + return GL_TEXTURE_CUBE_MAP; + case GL_SAMPLER_2D_ARRAY: + case GL_INT_SAMPLER_2D_ARRAY: + case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY: + case GL_SAMPLER_2D_ARRAY_SHADOW: + return GL_TEXTURE_2D_ARRAY; + default: UNREACHABLE(); + } + + return GL_TEXTURE_2D; +} + +void GetDefaultInputLayoutFromShader(const std::vector &shaderAttributes, gl::VertexFormat inputLayout[gl::MAX_VERTEX_ATTRIBS]) +{ + size_t layoutIndex = 0; + for (size_t attributeIndex = 0; attributeIndex < shaderAttributes.size(); attributeIndex++) + { + ASSERT(layoutIndex < gl::MAX_VERTEX_ATTRIBS); + + const sh::Attribute &shaderAttr = shaderAttributes[attributeIndex]; + + if (shaderAttr.type != GL_NONE) + { + GLenum transposedType = gl::TransposeMatrixType(shaderAttr.type); + + for (size_t rowIndex = 0; static_cast(rowIndex) < gl::VariableRowCount(transposedType); rowIndex++, layoutIndex++) + { + gl::VertexFormat *defaultFormat = &inputLayout[layoutIndex]; + + defaultFormat->mType = gl::VariableComponentType(transposedType); + defaultFormat->mNormalized = false; + defaultFormat->mPureInteger = (defaultFormat->mType != GL_FLOAT); // note: inputs can not be bool + defaultFormat->mComponents = gl::VariableColumnCount(transposedType); + } + } + } +} + +std::vector GetDefaultOutputLayoutFromShader(const std::vector &shaderOutputVars) +{ + std::vector defaultPixelOutput; + + if (!shaderOutputVars.empty()) + { + defaultPixelOutput.push_back(GL_COLOR_ATTACHMENT0 + shaderOutputVars[0].outputIndex); + } + + return defaultPixelOutput; +} + +bool IsRowMajorLayout(const sh::InterfaceBlockField &var) +{ + return var.isRowMajorLayout; +} + +bool IsRowMajorLayout(const sh::ShaderVariable &var) +{ + return false; +} + +struct AttributeSorter +{ + AttributeSorter(const ProgramImpl::SemanticIndexArray &semanticIndices) + : originalIndices(&semanticIndices) + { + } + + bool operator()(int a, int b) + { + int indexA = (*originalIndices)[a]; + int indexB = (*originalIndices)[b]; + + if (indexA == -1) return false; + if (indexB == -1) return true; + return (indexA < indexB); + } + + const ProgramImpl::SemanticIndexArray *originalIndices; +}; + +} + +ProgramD3D::VertexExecutable::VertexExecutable(const gl::VertexFormat inputLayout[], + const GLenum signature[], + ShaderExecutableD3D *shaderExecutable) + : mShaderExecutable(shaderExecutable) +{ + for (size_t attributeIndex = 0; attributeIndex < gl::MAX_VERTEX_ATTRIBS; attributeIndex++) + { + mInputs[attributeIndex] = inputLayout[attributeIndex]; + mSignature[attributeIndex] = signature[attributeIndex]; + } +} + +ProgramD3D::VertexExecutable::~VertexExecutable() +{ + SafeDelete(mShaderExecutable); +} + +bool ProgramD3D::VertexExecutable::matchesSignature(const GLenum signature[]) const +{ + for (size_t attributeIndex = 0; attributeIndex < gl::MAX_VERTEX_ATTRIBS; attributeIndex++) + { + if (mSignature[attributeIndex] != signature[attributeIndex]) + { + return false; + } + } + + return true; +} + +ProgramD3D::PixelExecutable::PixelExecutable(const std::vector &outputSignature, ShaderExecutableD3D *shaderExecutable) + : mOutputSignature(outputSignature), + mShaderExecutable(shaderExecutable) +{ +} + +ProgramD3D::PixelExecutable::~PixelExecutable() +{ + SafeDelete(mShaderExecutable); +} + +ProgramD3D::Sampler::Sampler() : active(false), logicalTextureUnit(0), textureType(GL_TEXTURE_2D) +{ +} + +unsigned int ProgramD3D::mCurrentSerial = 1; + +ProgramD3D::ProgramD3D(RendererD3D *renderer) + : ProgramImpl(), + mRenderer(renderer), + mDynamicHLSL(NULL), + mGeometryExecutable(NULL), + mUsesPointSize(false), + mVertexUniformStorage(NULL), + mFragmentUniformStorage(NULL), + mUsedVertexSamplerRange(0), + mUsedPixelSamplerRange(0), + mDirtySamplerMapping(true), + mTextureUnitTypesCache(renderer->getRendererCaps().maxCombinedTextureImageUnits), + mShaderVersion(100), + mSerial(issueSerial()) +{ + mDynamicHLSL = new DynamicHLSL(renderer); +} + +ProgramD3D::~ProgramD3D() +{ + reset(); + SafeDelete(mDynamicHLSL); +} + +bool ProgramD3D::usesPointSpriteEmulation() const +{ + return mUsesPointSize && mRenderer->getMajorShaderModel() >= 4; +} + +bool ProgramD3D::usesGeometryShader() const +{ + return usesPointSpriteEmulation() && !usesInstancedPointSpriteEmulation(); +} + +bool ProgramD3D::usesInstancedPointSpriteEmulation() const +{ + return mRenderer->getWorkarounds().useInstancedPointSpriteEmulation; +} + +GLint ProgramD3D::getSamplerMapping(gl::SamplerType type, unsigned int samplerIndex, const gl::Caps &caps) const +{ + GLint logicalTextureUnit = -1; + + switch (type) + { + case gl::SAMPLER_PIXEL: + ASSERT(samplerIndex < caps.maxTextureImageUnits); + if (samplerIndex < mSamplersPS.size() && mSamplersPS[samplerIndex].active) + { + logicalTextureUnit = mSamplersPS[samplerIndex].logicalTextureUnit; + } + break; + case gl::SAMPLER_VERTEX: + ASSERT(samplerIndex < caps.maxVertexTextureImageUnits); + if (samplerIndex < mSamplersVS.size() && mSamplersVS[samplerIndex].active) + { + logicalTextureUnit = mSamplersVS[samplerIndex].logicalTextureUnit; + } + break; + default: UNREACHABLE(); + } + + if (logicalTextureUnit >= 0 && logicalTextureUnit < static_cast(caps.maxCombinedTextureImageUnits)) + { + return logicalTextureUnit; + } + + return -1; +} + +// Returns the texture type for a given Direct3D 9 sampler type and +// index (0-15 for the pixel shader and 0-3 for the vertex shader). +GLenum ProgramD3D::getSamplerTextureType(gl::SamplerType type, unsigned int samplerIndex) const +{ + switch (type) + { + case gl::SAMPLER_PIXEL: + ASSERT(samplerIndex < mSamplersPS.size()); + ASSERT(mSamplersPS[samplerIndex].active); + return mSamplersPS[samplerIndex].textureType; + case gl::SAMPLER_VERTEX: + ASSERT(samplerIndex < mSamplersVS.size()); + ASSERT(mSamplersVS[samplerIndex].active); + return mSamplersVS[samplerIndex].textureType; + default: UNREACHABLE(); + } + + return GL_TEXTURE_2D; +} + +GLint ProgramD3D::getUsedSamplerRange(gl::SamplerType type) const +{ + switch (type) + { + case gl::SAMPLER_PIXEL: + return mUsedPixelSamplerRange; + case gl::SAMPLER_VERTEX: + return mUsedVertexSamplerRange; + default: + UNREACHABLE(); + return 0; + } +} + +void ProgramD3D::updateSamplerMapping() +{ + if (!mDirtySamplerMapping) + { + return; + } + + mDirtySamplerMapping = false; + + // Retrieve sampler uniform values + for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++) + { + gl::LinkedUniform *targetUniform = mUniforms[uniformIndex]; + + if (targetUniform->dirty) + { + if (gl::IsSamplerType(targetUniform->type)) + { + int count = targetUniform->elementCount(); + GLint (*v)[4] = reinterpret_cast(targetUniform->data); + + if (targetUniform->isReferencedByFragmentShader()) + { + unsigned int firstIndex = targetUniform->psRegisterIndex; + + for (int i = 0; i < count; i++) + { + unsigned int samplerIndex = firstIndex + i; + + if (samplerIndex < mSamplersPS.size()) + { + ASSERT(mSamplersPS[samplerIndex].active); + mSamplersPS[samplerIndex].logicalTextureUnit = v[i][0]; + } + } + } + + if (targetUniform->isReferencedByVertexShader()) + { + unsigned int firstIndex = targetUniform->vsRegisterIndex; + + for (int i = 0; i < count; i++) + { + unsigned int samplerIndex = firstIndex + i; + + if (samplerIndex < mSamplersVS.size()) + { + ASSERT(mSamplersVS[samplerIndex].active); + mSamplersVS[samplerIndex].logicalTextureUnit = v[i][0]; + } + } + } + } + } + } +} + +bool ProgramD3D::validateSamplers(gl::InfoLog *infoLog, const gl::Caps &caps) +{ + // if any two active samplers in a program are of different types, but refer to the same + // texture image unit, and this is the current program, then ValidateProgram will fail, and + // DrawArrays and DrawElements will issue the INVALID_OPERATION error. + updateSamplerMapping(); + + std::fill(mTextureUnitTypesCache.begin(), mTextureUnitTypesCache.end(), GL_NONE); + + for (unsigned int i = 0; i < mUsedPixelSamplerRange; ++i) + { + if (mSamplersPS[i].active) + { + unsigned int unit = mSamplersPS[i].logicalTextureUnit; + + if (unit >= caps.maxCombinedTextureImageUnits) + { + if (infoLog) + { + infoLog->append("Sampler uniform (%d) exceeds GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, caps.maxCombinedTextureImageUnits); + } + + return false; + } + + if (mTextureUnitTypesCache[unit] != GL_NONE) + { + if (mSamplersPS[i].textureType != mTextureUnitTypesCache[unit]) + { + if (infoLog) + { + infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit); + } + + return false; + } + } + else + { + mTextureUnitTypesCache[unit] = mSamplersPS[i].textureType; + } + } + } + + for (unsigned int i = 0; i < mUsedVertexSamplerRange; ++i) + { + if (mSamplersVS[i].active) + { + unsigned int unit = mSamplersVS[i].logicalTextureUnit; + + if (unit >= caps.maxCombinedTextureImageUnits) + { + if (infoLog) + { + infoLog->append("Sampler uniform (%d) exceeds GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, caps.maxCombinedTextureImageUnits); + } + + return false; + } + + if (mTextureUnitTypesCache[unit] != GL_NONE) + { + if (mSamplersVS[i].textureType != mTextureUnitTypesCache[unit]) + { + if (infoLog) + { + infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit); + } + + return false; + } + } + else + { + mTextureUnitTypesCache[unit] = mSamplersVS[i].textureType; + } + } + } + + return true; +} + +LinkResult ProgramD3D::load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream) +{ + int compileFlags = stream->readInt(); + if (compileFlags != ANGLE_COMPILE_OPTIMIZATION_LEVEL) + { + infoLog.append("Mismatched compilation flags."); + return LinkResult(false, gl::Error(GL_NO_ERROR)); + } + + stream->readInt(&mShaderVersion); + + const unsigned int psSamplerCount = stream->readInt(); + for (unsigned int i = 0; i < psSamplerCount; ++i) + { + Sampler sampler; + stream->readBool(&sampler.active); + stream->readInt(&sampler.logicalTextureUnit); + stream->readInt(&sampler.textureType); + mSamplersPS.push_back(sampler); + } + const unsigned int vsSamplerCount = stream->readInt(); + for (unsigned int i = 0; i < vsSamplerCount; ++i) + { + Sampler sampler; + stream->readBool(&sampler.active); + stream->readInt(&sampler.logicalTextureUnit); + stream->readInt(&sampler.textureType); + mSamplersVS.push_back(sampler); + } + + stream->readInt(&mUsedVertexSamplerRange); + stream->readInt(&mUsedPixelSamplerRange); + + const unsigned int uniformCount = stream->readInt(); + if (stream->error()) + { + infoLog.append("Invalid program binary."); + return LinkResult(false, gl::Error(GL_NO_ERROR)); + } + + mUniforms.resize(uniformCount); + for (unsigned int uniformIndex = 0; uniformIndex < uniformCount; uniformIndex++) + { + GLenum type = stream->readInt(); + GLenum precision = stream->readInt(); + std::string name = stream->readString(); + unsigned int arraySize = stream->readInt(); + int blockIndex = stream->readInt(); + + int offset = stream->readInt(); + int arrayStride = stream->readInt(); + int matrixStride = stream->readInt(); + bool isRowMajorMatrix = stream->readBool(); + + const sh::BlockMemberInfo blockInfo(offset, arrayStride, matrixStride, isRowMajorMatrix); + + gl::LinkedUniform *uniform = new gl::LinkedUniform(type, precision, name, arraySize, blockIndex, blockInfo); + + stream->readInt(&uniform->psRegisterIndex); + stream->readInt(&uniform->vsRegisterIndex); + stream->readInt(&uniform->registerCount); + stream->readInt(&uniform->registerElement); + + mUniforms[uniformIndex] = uniform; + } + + const unsigned int uniformIndexCount = stream->readInt(); + if (stream->error()) + { + infoLog.append("Invalid program binary."); + return LinkResult(false, gl::Error(GL_NO_ERROR)); + } + + mUniformIndex.resize(uniformIndexCount); + for (unsigned int uniformIndexIndex = 0; uniformIndexIndex < uniformIndexCount; uniformIndexIndex++) + { + stream->readString(&mUniformIndex[uniformIndexIndex].name); + stream->readInt(&mUniformIndex[uniformIndexIndex].element); + stream->readInt(&mUniformIndex[uniformIndexIndex].index); + } + + unsigned int uniformBlockCount = stream->readInt(); + if (stream->error()) + { + infoLog.append("Invalid program binary."); + return LinkResult(false, gl::Error(GL_NO_ERROR)); + } + + mUniformBlocks.resize(uniformBlockCount); + for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < uniformBlockCount; ++uniformBlockIndex) + { + std::string name = stream->readString(); + unsigned int elementIndex = stream->readInt(); + unsigned int dataSize = stream->readInt(); + + gl::UniformBlock *uniformBlock = new gl::UniformBlock(name, elementIndex, dataSize); + + stream->readInt(&uniformBlock->psRegisterIndex); + stream->readInt(&uniformBlock->vsRegisterIndex); + + unsigned int numMembers = stream->readInt(); + uniformBlock->memberUniformIndexes.resize(numMembers); + for (unsigned int blockMemberIndex = 0; blockMemberIndex < numMembers; blockMemberIndex++) + { + stream->readInt(&uniformBlock->memberUniformIndexes[blockMemberIndex]); + } + + mUniformBlocks[uniformBlockIndex] = uniformBlock; + } + + stream->readInt(&mTransformFeedbackBufferMode); + const unsigned int transformFeedbackVaryingCount = stream->readInt(); + mTransformFeedbackLinkedVaryings.resize(transformFeedbackVaryingCount); + for (unsigned int varyingIndex = 0; varyingIndex < transformFeedbackVaryingCount; varyingIndex++) + { + gl::LinkedVarying &varying = mTransformFeedbackLinkedVaryings[varyingIndex]; + + stream->readString(&varying.name); + stream->readInt(&varying.type); + stream->readInt(&varying.size); + stream->readString(&varying.semanticName); + stream->readInt(&varying.semanticIndex); + stream->readInt(&varying.semanticIndexCount); + } + + stream->readString(&mVertexHLSL); + stream->readBytes(reinterpret_cast(&mVertexWorkarounds), sizeof(D3DCompilerWorkarounds)); + stream->readString(&mPixelHLSL); + stream->readBytes(reinterpret_cast(&mPixelWorkarounds), sizeof(D3DCompilerWorkarounds)); + stream->readBool(&mUsesFragDepth); + stream->readBool(&mUsesPointSize); + + const size_t pixelShaderKeySize = stream->readInt(); + mPixelShaderKey.resize(pixelShaderKeySize); + for (size_t pixelShaderKeyIndex = 0; pixelShaderKeyIndex < pixelShaderKeySize; pixelShaderKeyIndex++) + { + stream->readInt(&mPixelShaderKey[pixelShaderKeyIndex].type); + stream->readString(&mPixelShaderKey[pixelShaderKeyIndex].name); + stream->readString(&mPixelShaderKey[pixelShaderKeyIndex].source); + stream->readInt(&mPixelShaderKey[pixelShaderKeyIndex].outputIndex); + } + + const unsigned char* binary = reinterpret_cast(stream->data()); + + const unsigned int vertexShaderCount = stream->readInt(); + for (unsigned int vertexShaderIndex = 0; vertexShaderIndex < vertexShaderCount; vertexShaderIndex++) + { + gl::VertexFormat inputLayout[gl::MAX_VERTEX_ATTRIBS]; + + for (size_t inputIndex = 0; inputIndex < gl::MAX_VERTEX_ATTRIBS; inputIndex++) + { + gl::VertexFormat *vertexInput = &inputLayout[inputIndex]; + stream->readInt(&vertexInput->mType); + stream->readInt(&vertexInput->mNormalized); + stream->readInt(&vertexInput->mComponents); + stream->readBool(&vertexInput->mPureInteger); + } + + unsigned int vertexShaderSize = stream->readInt(); + const unsigned char *vertexShaderFunction = binary + stream->offset(); + + ShaderExecutableD3D *shaderExecutable = NULL; + gl::Error error = mRenderer->loadExecutable(vertexShaderFunction, vertexShaderSize, + SHADER_VERTEX, + mTransformFeedbackLinkedVaryings, + (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS), + &shaderExecutable); + if (error.isError()) + { + return LinkResult(false, error); + } + + if (!shaderExecutable) + { + infoLog.append("Could not create vertex shader."); + return LinkResult(false, gl::Error(GL_NO_ERROR)); + } + + // generated converted input layout + GLenum signature[gl::MAX_VERTEX_ATTRIBS]; + getInputLayoutSignature(inputLayout, signature); + + // add new binary + mVertexExecutables.push_back(new VertexExecutable(inputLayout, signature, shaderExecutable)); + + stream->skip(vertexShaderSize); + } + + const size_t pixelShaderCount = stream->readInt(); + for (size_t pixelShaderIndex = 0; pixelShaderIndex < pixelShaderCount; pixelShaderIndex++) + { + const size_t outputCount = stream->readInt(); + std::vector outputs(outputCount); + for (size_t outputIndex = 0; outputIndex < outputCount; outputIndex++) + { + stream->readInt(&outputs[outputIndex]); + } + + const size_t pixelShaderSize = stream->readInt(); + const unsigned char *pixelShaderFunction = binary + stream->offset(); + ShaderExecutableD3D *shaderExecutable = NULL; + gl::Error error = mRenderer->loadExecutable(pixelShaderFunction, pixelShaderSize, SHADER_PIXEL, + mTransformFeedbackLinkedVaryings, + (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS), + &shaderExecutable); + if (error.isError()) + { + return LinkResult(false, error); + } + + if (!shaderExecutable) + { + infoLog.append("Could not create pixel shader."); + return LinkResult(false, gl::Error(GL_NO_ERROR)); + } + + // add new binary + mPixelExecutables.push_back(new PixelExecutable(outputs, shaderExecutable)); + + stream->skip(pixelShaderSize); + } + + unsigned int geometryShaderSize = stream->readInt(); + + if (geometryShaderSize > 0) + { + const unsigned char *geometryShaderFunction = binary + stream->offset(); + gl::Error error = mRenderer->loadExecutable(geometryShaderFunction, geometryShaderSize, SHADER_GEOMETRY, + mTransformFeedbackLinkedVaryings, + (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS), + &mGeometryExecutable); + if (error.isError()) + { + return LinkResult(false, error); + } + + if (!mGeometryExecutable) + { + infoLog.append("Could not create geometry shader."); + return LinkResult(false, gl::Error(GL_NO_ERROR)); + } + stream->skip(geometryShaderSize); + } + + GUID binaryIdentifier = {0}; + stream->readBytes(reinterpret_cast(&binaryIdentifier), sizeof(GUID)); + + GUID identifier = mRenderer->getAdapterIdentifier(); + if (memcmp(&identifier, &binaryIdentifier, sizeof(GUID)) != 0) + { + infoLog.append("Invalid program binary."); + return LinkResult(false, gl::Error(GL_NO_ERROR)); + } + + initializeUniformStorage(); + initAttributesByLayout(); + + return LinkResult(true, gl::Error(GL_NO_ERROR)); +} + +gl::Error ProgramD3D::save(gl::BinaryOutputStream *stream) +{ + stream->writeInt(ANGLE_COMPILE_OPTIMIZATION_LEVEL); + + stream->writeInt(mShaderVersion); + + stream->writeInt(mSamplersPS.size()); + for (unsigned int i = 0; i < mSamplersPS.size(); ++i) + { + stream->writeInt(mSamplersPS[i].active); + stream->writeInt(mSamplersPS[i].logicalTextureUnit); + stream->writeInt(mSamplersPS[i].textureType); + } + + stream->writeInt(mSamplersVS.size()); + for (unsigned int i = 0; i < mSamplersVS.size(); ++i) + { + stream->writeInt(mSamplersVS[i].active); + stream->writeInt(mSamplersVS[i].logicalTextureUnit); + stream->writeInt(mSamplersVS[i].textureType); + } + + stream->writeInt(mUsedVertexSamplerRange); + stream->writeInt(mUsedPixelSamplerRange); + + stream->writeInt(mUniforms.size()); + for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); ++uniformIndex) + { + const gl::LinkedUniform &uniform = *mUniforms[uniformIndex]; + + stream->writeInt(uniform.type); + stream->writeInt(uniform.precision); + stream->writeString(uniform.name); + stream->writeInt(uniform.arraySize); + stream->writeInt(uniform.blockIndex); + + stream->writeInt(uniform.blockInfo.offset); + stream->writeInt(uniform.blockInfo.arrayStride); + stream->writeInt(uniform.blockInfo.matrixStride); + stream->writeInt(uniform.blockInfo.isRowMajorMatrix); + + stream->writeInt(uniform.psRegisterIndex); + stream->writeInt(uniform.vsRegisterIndex); + stream->writeInt(uniform.registerCount); + stream->writeInt(uniform.registerElement); + } + + stream->writeInt(mUniformIndex.size()); + for (size_t i = 0; i < mUniformIndex.size(); ++i) + { + stream->writeString(mUniformIndex[i].name); + stream->writeInt(mUniformIndex[i].element); + stream->writeInt(mUniformIndex[i].index); + } + + stream->writeInt(mUniformBlocks.size()); + for (size_t uniformBlockIndex = 0; uniformBlockIndex < mUniformBlocks.size(); ++uniformBlockIndex) + { + const gl::UniformBlock& uniformBlock = *mUniformBlocks[uniformBlockIndex]; + + stream->writeString(uniformBlock.name); + stream->writeInt(uniformBlock.elementIndex); + stream->writeInt(uniformBlock.dataSize); + + stream->writeInt(uniformBlock.memberUniformIndexes.size()); + for (unsigned int blockMemberIndex = 0; blockMemberIndex < uniformBlock.memberUniformIndexes.size(); blockMemberIndex++) + { + stream->writeInt(uniformBlock.memberUniformIndexes[blockMemberIndex]); + } + + stream->writeInt(uniformBlock.psRegisterIndex); + stream->writeInt(uniformBlock.vsRegisterIndex); + } + + stream->writeInt(mTransformFeedbackBufferMode); + stream->writeInt(mTransformFeedbackLinkedVaryings.size()); + for (size_t i = 0; i < mTransformFeedbackLinkedVaryings.size(); i++) + { + const gl::LinkedVarying &varying = mTransformFeedbackLinkedVaryings[i]; + + stream->writeString(varying.name); + stream->writeInt(varying.type); + stream->writeInt(varying.size); + stream->writeString(varying.semanticName); + stream->writeInt(varying.semanticIndex); + stream->writeInt(varying.semanticIndexCount); + } + + stream->writeString(mVertexHLSL); + stream->writeBytes(reinterpret_cast(&mVertexWorkarounds), sizeof(D3DCompilerWorkarounds)); + stream->writeString(mPixelHLSL); + stream->writeBytes(reinterpret_cast(&mPixelWorkarounds), sizeof(D3DCompilerWorkarounds)); + stream->writeInt(mUsesFragDepth); + stream->writeInt(mUsesPointSize); + + const std::vector &pixelShaderKey = mPixelShaderKey; + stream->writeInt(pixelShaderKey.size()); + for (size_t pixelShaderKeyIndex = 0; pixelShaderKeyIndex < pixelShaderKey.size(); pixelShaderKeyIndex++) + { + const PixelShaderOutputVariable &variable = pixelShaderKey[pixelShaderKeyIndex]; + stream->writeInt(variable.type); + stream->writeString(variable.name); + stream->writeString(variable.source); + stream->writeInt(variable.outputIndex); + } + + stream->writeInt(mVertexExecutables.size()); + for (size_t vertexExecutableIndex = 0; vertexExecutableIndex < mVertexExecutables.size(); vertexExecutableIndex++) + { + VertexExecutable *vertexExecutable = mVertexExecutables[vertexExecutableIndex]; + + for (size_t inputIndex = 0; inputIndex < gl::MAX_VERTEX_ATTRIBS; inputIndex++) + { + const gl::VertexFormat &vertexInput = vertexExecutable->inputs()[inputIndex]; + stream->writeInt(vertexInput.mType); + stream->writeInt(vertexInput.mNormalized); + stream->writeInt(vertexInput.mComponents); + stream->writeInt(vertexInput.mPureInteger); + } + + size_t vertexShaderSize = vertexExecutable->shaderExecutable()->getLength(); + stream->writeInt(vertexShaderSize); + + const uint8_t *vertexBlob = vertexExecutable->shaderExecutable()->getFunction(); + stream->writeBytes(vertexBlob, vertexShaderSize); + } + + stream->writeInt(mPixelExecutables.size()); + for (size_t pixelExecutableIndex = 0; pixelExecutableIndex < mPixelExecutables.size(); pixelExecutableIndex++) + { + PixelExecutable *pixelExecutable = mPixelExecutables[pixelExecutableIndex]; + + const std::vector outputs = pixelExecutable->outputSignature(); + stream->writeInt(outputs.size()); + for (size_t outputIndex = 0; outputIndex < outputs.size(); outputIndex++) + { + stream->writeInt(outputs[outputIndex]); + } + + size_t pixelShaderSize = pixelExecutable->shaderExecutable()->getLength(); + stream->writeInt(pixelShaderSize); + + const uint8_t *pixelBlob = pixelExecutable->shaderExecutable()->getFunction(); + stream->writeBytes(pixelBlob, pixelShaderSize); + } + + size_t geometryShaderSize = (mGeometryExecutable != NULL) ? mGeometryExecutable->getLength() : 0; + stream->writeInt(geometryShaderSize); + + if (mGeometryExecutable != NULL && geometryShaderSize > 0) + { + const uint8_t *geometryBlob = mGeometryExecutable->getFunction(); + stream->writeBytes(geometryBlob, geometryShaderSize); + } + + GUID binaryIdentifier = mRenderer->getAdapterIdentifier(); + stream->writeBytes(reinterpret_cast(&binaryIdentifier), sizeof(GUID)); + + return gl::Error(GL_NO_ERROR); +} + +gl::Error ProgramD3D::getPixelExecutableForFramebuffer(const gl::Framebuffer *fbo, ShaderExecutableD3D **outExecutable) +{ + mPixelShaderOutputFormatCache.clear(); + + const FramebufferD3D *fboD3D = GetImplAs(fbo); + const gl::AttachmentList &colorbuffers = fboD3D->getColorAttachmentsForRender(mRenderer->getWorkarounds()); + + for (size_t colorAttachment = 0; colorAttachment < colorbuffers.size(); ++colorAttachment) + { + const gl::FramebufferAttachment *colorbuffer = colorbuffers[colorAttachment]; + + if (colorbuffer) + { + mPixelShaderOutputFormatCache.push_back(colorbuffer->getBinding() == GL_BACK ? GL_COLOR_ATTACHMENT0 : colorbuffer->getBinding()); + } + else + { + mPixelShaderOutputFormatCache.push_back(GL_NONE); + } + } + + return getPixelExecutableForOutputLayout(mPixelShaderOutputFormatCache, outExecutable, nullptr); +} + +gl::Error ProgramD3D::getPixelExecutableForOutputLayout(const std::vector &outputSignature, + ShaderExecutableD3D **outExectuable, + gl::InfoLog *infoLog) +{ + for (size_t executableIndex = 0; executableIndex < mPixelExecutables.size(); executableIndex++) + { + if (mPixelExecutables[executableIndex]->matchesSignature(outputSignature)) + { + *outExectuable = mPixelExecutables[executableIndex]->shaderExecutable(); + return gl::Error(GL_NO_ERROR); + } + } + + std::string finalPixelHLSL = mDynamicHLSL->generatePixelShaderForOutputSignature(mPixelHLSL, mPixelShaderKey, mUsesFragDepth, + outputSignature); + + // Generate new pixel executable + ShaderExecutableD3D *pixelExecutable = NULL; + + gl::InfoLog tempInfoLog; + gl::InfoLog *currentInfoLog = infoLog ? infoLog : &tempInfoLog; + + gl::Error error = mRenderer->compileToExecutable(*currentInfoLog, finalPixelHLSL, SHADER_PIXEL, + mTransformFeedbackLinkedVaryings, + (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS), + mPixelWorkarounds, &pixelExecutable); + if (error.isError()) + { + return error; + } + + if (pixelExecutable) + { + mPixelExecutables.push_back(new PixelExecutable(outputSignature, pixelExecutable)); + } + else if (!infoLog) + { + std::vector tempCharBuffer(tempInfoLog.getLength() + 3); + tempInfoLog.getLog(tempInfoLog.getLength(), NULL, &tempCharBuffer[0]); + ERR("Error compiling dynamic pixel executable:\n%s\n", &tempCharBuffer[0]); + } + + *outExectuable = pixelExecutable; + return gl::Error(GL_NO_ERROR); +} + +gl::Error ProgramD3D::getVertexExecutableForInputLayout(const gl::VertexFormat inputLayout[gl::MAX_VERTEX_ATTRIBS], + ShaderExecutableD3D **outExectuable, + gl::InfoLog *infoLog) +{ + GLenum signature[gl::MAX_VERTEX_ATTRIBS]; + getInputLayoutSignature(inputLayout, signature); + + for (size_t executableIndex = 0; executableIndex < mVertexExecutables.size(); executableIndex++) + { + if (mVertexExecutables[executableIndex]->matchesSignature(signature)) + { + *outExectuable = mVertexExecutables[executableIndex]->shaderExecutable(); + return gl::Error(GL_NO_ERROR); + } + } + + // Generate new dynamic layout with attribute conversions + std::string finalVertexHLSL = mDynamicHLSL->generateVertexShaderForInputLayout(mVertexHLSL, inputLayout, mShaderAttributes); + + // Generate new vertex executable + ShaderExecutableD3D *vertexExecutable = NULL; + + gl::InfoLog tempInfoLog; + gl::InfoLog *currentInfoLog = infoLog ? infoLog : &tempInfoLog; + + gl::Error error = mRenderer->compileToExecutable(*currentInfoLog, finalVertexHLSL, SHADER_VERTEX, + mTransformFeedbackLinkedVaryings, + (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS), + mVertexWorkarounds, &vertexExecutable); + if (error.isError()) + { + return error; + } + + if (vertexExecutable) + { + mVertexExecutables.push_back(new VertexExecutable(inputLayout, signature, vertexExecutable)); + } + else if (!infoLog) + { + std::vector tempCharBuffer(tempInfoLog.getLength() + 3); + tempInfoLog.getLog(tempInfoLog.getLength(), NULL, &tempCharBuffer[0]); + ERR("Error compiling dynamic vertex executable:\n%s\n", &tempCharBuffer[0]); + } + + *outExectuable = vertexExecutable; + return gl::Error(GL_NO_ERROR); +} + +LinkResult ProgramD3D::compileProgramExecutables(gl::InfoLog &infoLog, gl::Shader *fragmentShader, gl::Shader *vertexShader, + int registers) +{ + ShaderD3D *vertexShaderD3D = ShaderD3D::makeShaderD3D(vertexShader->getImplementation()); + ShaderD3D *fragmentShaderD3D = ShaderD3D::makeShaderD3D(fragmentShader->getImplementation()); + + gl::VertexFormat defaultInputLayout[gl::MAX_VERTEX_ATTRIBS]; + GetDefaultInputLayoutFromShader(vertexShader->getActiveAttributes(), defaultInputLayout); + ShaderExecutableD3D *defaultVertexExecutable = NULL; + gl::Error error = getVertexExecutableForInputLayout(defaultInputLayout, &defaultVertexExecutable, &infoLog); + if (error.isError()) + { + return LinkResult(false, error); + } + + std::vector defaultPixelOutput = GetDefaultOutputLayoutFromShader(getPixelShaderKey()); + ShaderExecutableD3D *defaultPixelExecutable = NULL; + error = getPixelExecutableForOutputLayout(defaultPixelOutput, &defaultPixelExecutable, &infoLog); + if (error.isError()) + { + return LinkResult(false, error); + } + + if (usesGeometryShader()) + { + std::string geometryHLSL = mDynamicHLSL->generateGeometryShaderHLSL(registers, fragmentShaderD3D, vertexShaderD3D); + + + error = mRenderer->compileToExecutable(infoLog, geometryHLSL, SHADER_GEOMETRY, mTransformFeedbackLinkedVaryings, + (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS), + D3DCompilerWorkarounds(), &mGeometryExecutable); + if (error.isError()) + { + return LinkResult(false, error); + } + } + +#if ANGLE_SHADER_DEBUG_INFO == ANGLE_ENABLED + if (usesGeometryShader() && mGeometryExecutable) + { + // Geometry shaders are currently only used internally, so there is no corresponding shader object at the interface level + // For now the geometry shader debug info is pre-pended to the vertex shader, this is a bit of a clutch + vertexShaderD3D->appendDebugInfo("// GEOMETRY SHADER BEGIN\n\n"); + vertexShaderD3D->appendDebugInfo(mGeometryExecutable->getDebugInfo()); + vertexShaderD3D->appendDebugInfo("\nGEOMETRY SHADER END\n\n\n"); + } + + if (defaultVertexExecutable) + { + vertexShaderD3D->appendDebugInfo(defaultVertexExecutable->getDebugInfo()); + } + + if (defaultPixelExecutable) + { + fragmentShaderD3D->appendDebugInfo(defaultPixelExecutable->getDebugInfo()); + } +#endif + + bool linkSuccess = (defaultVertexExecutable && defaultPixelExecutable && (!usesGeometryShader() || mGeometryExecutable)); + return LinkResult(linkSuccess, gl::Error(GL_NO_ERROR)); +} + +LinkResult ProgramD3D::link(const gl::Data &data, gl::InfoLog &infoLog, + gl::Shader *fragmentShader, gl::Shader *vertexShader, + const std::vector &transformFeedbackVaryings, + GLenum transformFeedbackBufferMode, + int *registers, std::vector *linkedVaryings, + std::map *outputVariables) +{ + ShaderD3D *vertexShaderD3D = ShaderD3D::makeShaderD3D(vertexShader->getImplementation()); + ShaderD3D *fragmentShaderD3D = ShaderD3D::makeShaderD3D(fragmentShader->getImplementation()); + + mSamplersPS.resize(data.caps->maxTextureImageUnits); + mSamplersVS.resize(data.caps->maxVertexTextureImageUnits); + + mTransformFeedbackBufferMode = transformFeedbackBufferMode; + + mPixelHLSL = fragmentShaderD3D->getTranslatedSource(); + fragmentShaderD3D->generateWorkarounds(&mPixelWorkarounds); + + mVertexHLSL = vertexShaderD3D->getTranslatedSource(); + vertexShaderD3D->generateWorkarounds(&mVertexWorkarounds); + mShaderVersion = vertexShaderD3D->getShaderVersion(); + + // Map the varyings to the register file + VaryingPacking packing = { NULL }; + *registers = mDynamicHLSL->packVaryings(infoLog, packing, fragmentShaderD3D, vertexShaderD3D, transformFeedbackVaryings); + + if (*registers < 0) + { + return LinkResult(false, gl::Error(GL_NO_ERROR)); + } + + if (!gl::Program::linkVaryings(infoLog, fragmentShader, vertexShader)) + { + return LinkResult(false, gl::Error(GL_NO_ERROR)); + } + + if (!mDynamicHLSL->generateShaderLinkHLSL(data, infoLog, *registers, packing, mPixelHLSL, mVertexHLSL, + fragmentShaderD3D, vertexShaderD3D, transformFeedbackVaryings, + linkedVaryings, outputVariables, &mPixelShaderKey, &mUsesFragDepth)) + { + return LinkResult(false, gl::Error(GL_NO_ERROR)); + } + + mUsesPointSize = vertexShaderD3D->usesPointSize(); + + initAttributesByLayout(); + + return LinkResult(true, gl::Error(GL_NO_ERROR)); +} + +void ProgramD3D::getInputLayoutSignature(const gl::VertexFormat inputLayout[], GLenum signature[]) const +{ + mDynamicHLSL->getInputLayoutSignature(inputLayout, signature); +} + +void ProgramD3D::initializeUniformStorage() +{ + // Compute total default block size + unsigned int vertexRegisters = 0; + unsigned int fragmentRegisters = 0; + for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++) + { + const gl::LinkedUniform &uniform = *mUniforms[uniformIndex]; + + if (!gl::IsSamplerType(uniform.type)) + { + if (uniform.isReferencedByVertexShader()) + { + vertexRegisters = std::max(vertexRegisters, uniform.vsRegisterIndex + uniform.registerCount); + } + if (uniform.isReferencedByFragmentShader()) + { + fragmentRegisters = std::max(fragmentRegisters, uniform.psRegisterIndex + uniform.registerCount); + } + } + } + + mVertexUniformStorage = mRenderer->createUniformStorage(vertexRegisters * 16u); + mFragmentUniformStorage = mRenderer->createUniformStorage(fragmentRegisters * 16u); +} + +gl::Error ProgramD3D::applyUniforms() +{ + updateSamplerMapping(); + + gl::Error error = mRenderer->applyUniforms(*this, mUniforms); + if (error.isError()) + { + return error; + } + + for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++) + { + mUniforms[uniformIndex]->dirty = false; + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error ProgramD3D::applyUniformBuffers(const gl::Data &data, GLuint uniformBlockBindings[]) +{ + GLint vertexUniformBuffers[gl::IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS]; + GLint fragmentUniformBuffers[gl::IMPLEMENTATION_MAX_FRAGMENT_SHADER_UNIFORM_BUFFERS]; + + for (unsigned int registerIndex = 0; registerIndex < gl::IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS; ++registerIndex) + { + vertexUniformBuffers[registerIndex] = -1; + } + + for (unsigned int registerIndex = 0; registerIndex < gl::IMPLEMENTATION_MAX_FRAGMENT_SHADER_UNIFORM_BUFFERS; ++registerIndex) + { + fragmentUniformBuffers[registerIndex] = -1; + } + + const unsigned int reservedBuffersInVS = mRenderer->getReservedVertexUniformBuffers(); + const unsigned int reservedBuffersInFS = mRenderer->getReservedFragmentUniformBuffers(); + + for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < mUniformBlocks.size(); uniformBlockIndex++) + { + gl::UniformBlock *uniformBlock = mUniformBlocks[uniformBlockIndex]; + GLuint blockBinding = uniformBlockBindings[uniformBlockIndex]; + + ASSERT(uniformBlock); + + // Unnecessary to apply an unreferenced standard or shared UBO + if (!uniformBlock->isReferencedByVertexShader() && !uniformBlock->isReferencedByFragmentShader()) + { + continue; + } + + if (uniformBlock->isReferencedByVertexShader()) + { + unsigned int registerIndex = uniformBlock->vsRegisterIndex - reservedBuffersInVS; + ASSERT(vertexUniformBuffers[registerIndex] == -1); + ASSERT(registerIndex < data.caps->maxVertexUniformBlocks); + vertexUniformBuffers[registerIndex] = blockBinding; + } + + if (uniformBlock->isReferencedByFragmentShader()) + { + unsigned int registerIndex = uniformBlock->psRegisterIndex - reservedBuffersInFS; + ASSERT(fragmentUniformBuffers[registerIndex] == -1); + ASSERT(registerIndex < data.caps->maxFragmentUniformBlocks); + fragmentUniformBuffers[registerIndex] = blockBinding; + } + } + + return mRenderer->setUniformBuffers(data, vertexUniformBuffers, fragmentUniformBuffers); +} + +bool ProgramD3D::assignUniformBlockRegister(gl::InfoLog &infoLog, gl::UniformBlock *uniformBlock, GLenum shader, + unsigned int registerIndex, const gl::Caps &caps) +{ + if (shader == GL_VERTEX_SHADER) + { + uniformBlock->vsRegisterIndex = registerIndex; + if (registerIndex - mRenderer->getReservedVertexUniformBuffers() >= caps.maxVertexUniformBlocks) + { + infoLog.append("Vertex shader uniform block count exceed GL_MAX_VERTEX_UNIFORM_BLOCKS (%u)", caps.maxVertexUniformBlocks); + return false; + } + } + else if (shader == GL_FRAGMENT_SHADER) + { + uniformBlock->psRegisterIndex = registerIndex; + if (registerIndex - mRenderer->getReservedFragmentUniformBuffers() >= caps.maxFragmentUniformBlocks) + { + infoLog.append("Fragment shader uniform block count exceed GL_MAX_FRAGMENT_UNIFORM_BLOCKS (%u)", caps.maxFragmentUniformBlocks); + return false; + } + } + else UNREACHABLE(); + + return true; +} + +void ProgramD3D::dirtyAllUniforms() +{ + unsigned int numUniforms = mUniforms.size(); + for (unsigned int index = 0; index < numUniforms; index++) + { + mUniforms[index]->dirty = true; + } +} + +void ProgramD3D::setUniform1fv(GLint location, GLsizei count, const GLfloat* v) +{ + setUniform(location, count, v, GL_FLOAT); +} + +void ProgramD3D::setUniform2fv(GLint location, GLsizei count, const GLfloat *v) +{ + setUniform(location, count, v, GL_FLOAT_VEC2); +} + +void ProgramD3D::setUniform3fv(GLint location, GLsizei count, const GLfloat *v) +{ + setUniform(location, count, v, GL_FLOAT_VEC3); +} + +void ProgramD3D::setUniform4fv(GLint location, GLsizei count, const GLfloat *v) +{ + setUniform(location, count, v, GL_FLOAT_VEC4); +} + +void ProgramD3D::setUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +{ + setUniformMatrixfv<2, 2>(location, count, transpose, value, GL_FLOAT_MAT2); +} + +void ProgramD3D::setUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +{ + setUniformMatrixfv<3, 3>(location, count, transpose, value, GL_FLOAT_MAT3); +} + +void ProgramD3D::setUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +{ + setUniformMatrixfv<4, 4>(location, count, transpose, value, GL_FLOAT_MAT4); +} + +void ProgramD3D::setUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +{ + setUniformMatrixfv<2, 3>(location, count, transpose, value, GL_FLOAT_MAT2x3); +} + +void ProgramD3D::setUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +{ + setUniformMatrixfv<3, 2>(location, count, transpose, value, GL_FLOAT_MAT3x2); +} + +void ProgramD3D::setUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +{ + setUniformMatrixfv<2, 4>(location, count, transpose, value, GL_FLOAT_MAT2x4); +} + +void ProgramD3D::setUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +{ + setUniformMatrixfv<4, 2>(location, count, transpose, value, GL_FLOAT_MAT4x2); +} + +void ProgramD3D::setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +{ + setUniformMatrixfv<3, 4>(location, count, transpose, value, GL_FLOAT_MAT3x4); +} + +void ProgramD3D::setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +{ + setUniformMatrixfv<4, 3>(location, count, transpose, value, GL_FLOAT_MAT4x3); +} + +void ProgramD3D::setUniform1iv(GLint location, GLsizei count, const GLint *v) +{ + setUniform(location, count, v, GL_INT); +} + +void ProgramD3D::setUniform2iv(GLint location, GLsizei count, const GLint *v) +{ + setUniform(location, count, v, GL_INT_VEC2); +} + +void ProgramD3D::setUniform3iv(GLint location, GLsizei count, const GLint *v) +{ + setUniform(location, count, v, GL_INT_VEC3); +} + +void ProgramD3D::setUniform4iv(GLint location, GLsizei count, const GLint *v) +{ + setUniform(location, count, v, GL_INT_VEC4); +} + +void ProgramD3D::setUniform1uiv(GLint location, GLsizei count, const GLuint *v) +{ + setUniform(location, count, v, GL_UNSIGNED_INT); +} + +void ProgramD3D::setUniform2uiv(GLint location, GLsizei count, const GLuint *v) +{ + setUniform(location, count, v, GL_UNSIGNED_INT_VEC2); +} + +void ProgramD3D::setUniform3uiv(GLint location, GLsizei count, const GLuint *v) +{ + setUniform(location, count, v, GL_UNSIGNED_INT_VEC3); +} + +void ProgramD3D::setUniform4uiv(GLint location, GLsizei count, const GLuint *v) +{ + setUniform(location, count, v, GL_UNSIGNED_INT_VEC4); +} + +void ProgramD3D::getUniformfv(GLint location, GLfloat *params) +{ + getUniformv(location, params, GL_FLOAT); +} + +void ProgramD3D::getUniformiv(GLint location, GLint *params) +{ + getUniformv(location, params, GL_INT); +} + +void ProgramD3D::getUniformuiv(GLint location, GLuint *params) +{ + getUniformv(location, params, GL_UNSIGNED_INT); +} + +bool ProgramD3D::linkUniforms(gl::InfoLog &infoLog, const gl::Shader &vertexShader, const gl::Shader &fragmentShader, + const gl::Caps &caps) +{ + const ShaderD3D *vertexShaderD3D = ShaderD3D::makeShaderD3D(vertexShader.getImplementation()); + const ShaderD3D *fragmentShaderD3D = ShaderD3D::makeShaderD3D(fragmentShader.getImplementation()); + + const std::vector &vertexUniforms = vertexShader.getUniforms(); + const std::vector &fragmentUniforms = fragmentShader.getUniforms(); + + // Check that uniforms defined in the vertex and fragment shaders are identical + typedef std::map UniformMap; + UniformMap linkedUniforms; + + for (unsigned int vertexUniformIndex = 0; vertexUniformIndex < vertexUniforms.size(); vertexUniformIndex++) + { + const sh::Uniform &vertexUniform = vertexUniforms[vertexUniformIndex]; + linkedUniforms[vertexUniform.name] = &vertexUniform; + } + + for (unsigned int fragmentUniformIndex = 0; fragmentUniformIndex < fragmentUniforms.size(); fragmentUniformIndex++) + { + const sh::Uniform &fragmentUniform = fragmentUniforms[fragmentUniformIndex]; + UniformMap::const_iterator entry = linkedUniforms.find(fragmentUniform.name); + if (entry != linkedUniforms.end()) + { + const sh::Uniform &vertexUniform = *entry->second; + const std::string &uniformName = "uniform '" + vertexUniform.name + "'"; + if (!gl::Program::linkValidateUniforms(infoLog, uniformName, vertexUniform, fragmentUniform)) + { + return false; + } + } + } + + for (unsigned int uniformIndex = 0; uniformIndex < vertexUniforms.size(); uniformIndex++) + { + const sh::Uniform &uniform = vertexUniforms[uniformIndex]; + + if (uniform.staticUse) + { + defineUniformBase(vertexShaderD3D, uniform, vertexShaderD3D->getUniformRegister(uniform.name)); + } + } + + for (unsigned int uniformIndex = 0; uniformIndex < fragmentUniforms.size(); uniformIndex++) + { + const sh::Uniform &uniform = fragmentUniforms[uniformIndex]; + + if (uniform.staticUse) + { + defineUniformBase(fragmentShaderD3D, uniform, fragmentShaderD3D->getUniformRegister(uniform.name)); + } + } + + if (!indexUniforms(infoLog, caps)) + { + return false; + } + + initializeUniformStorage(); + + // special case for gl_DepthRange, the only built-in uniform (also a struct) + if (vertexShaderD3D->usesDepthRange() || fragmentShaderD3D->usesDepthRange()) + { + const sh::BlockMemberInfo &defaultInfo = sh::BlockMemberInfo::getDefaultBlockInfo(); + + mUniforms.push_back(new gl::LinkedUniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.near", 0, -1, defaultInfo)); + mUniforms.push_back(new gl::LinkedUniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.far", 0, -1, defaultInfo)); + mUniforms.push_back(new gl::LinkedUniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.diff", 0, -1, defaultInfo)); + } + + return true; +} + +void ProgramD3D::defineUniformBase(const ShaderD3D *shader, const sh::Uniform &uniform, unsigned int uniformRegister) +{ + ShShaderOutput outputType = shader->getCompilerOutputType(); + sh::HLSLBlockEncoder encoder(sh::HLSLBlockEncoder::GetStrategyFor(outputType)); + encoder.skipRegisters(uniformRegister); + + defineUniform(shader, uniform, uniform.name, &encoder); +} + +void ProgramD3D::defineUniform(const ShaderD3D *shader, const sh::ShaderVariable &uniform, + const std::string &fullName, sh::HLSLBlockEncoder *encoder) +{ + if (uniform.isStruct()) + { + for (unsigned int elementIndex = 0; elementIndex < uniform.elementCount(); elementIndex++) + { + const std::string &elementString = (uniform.isArray() ? ArrayString(elementIndex) : ""); + + encoder->enterAggregateType(); + + for (size_t fieldIndex = 0; fieldIndex < uniform.fields.size(); fieldIndex++) + { + const sh::ShaderVariable &field = uniform.fields[fieldIndex]; + const std::string &fieldFullName = (fullName + elementString + "." + field.name); + + defineUniform(shader, field, fieldFullName, encoder); + } + + encoder->exitAggregateType(); + } + } + else // Not a struct + { + // Arrays are treated as aggregate types + if (uniform.isArray()) + { + encoder->enterAggregateType(); + } + + gl::LinkedUniform *linkedUniform = getUniformByName(fullName); + + // Advance the uniform offset, to track registers allocation for structs + sh::BlockMemberInfo blockInfo = encoder->encodeType(uniform.type, uniform.arraySize, false); + + if (!linkedUniform) + { + linkedUniform = new gl::LinkedUniform(uniform.type, uniform.precision, fullName, uniform.arraySize, + -1, sh::BlockMemberInfo::getDefaultBlockInfo()); + ASSERT(linkedUniform); + linkedUniform->registerElement = sh::HLSLBlockEncoder::getBlockRegisterElement(blockInfo); + mUniforms.push_back(linkedUniform); + } + + if (shader->getShaderType() == GL_FRAGMENT_SHADER) + { + linkedUniform->psRegisterIndex = sh::HLSLBlockEncoder::getBlockRegister(blockInfo); + } + else if (shader->getShaderType() == GL_VERTEX_SHADER) + { + linkedUniform->vsRegisterIndex = sh::HLSLBlockEncoder::getBlockRegister(blockInfo); + } + else UNREACHABLE(); + + // Arrays are treated as aggregate types + if (uniform.isArray()) + { + encoder->exitAggregateType(); + } + } +} + +template +static inline void SetIfDirty(T *dest, const T& source, bool *dirtyFlag) +{ + ASSERT(dest != NULL); + ASSERT(dirtyFlag != NULL); + + *dirtyFlag = *dirtyFlag || (memcmp(dest, &source, sizeof(T)) != 0); + *dest = source; +} + +template +void ProgramD3D::setUniform(GLint location, GLsizei count, const T* v, GLenum targetUniformType) +{ + const int components = gl::VariableComponentCount(targetUniformType); + const GLenum targetBoolType = gl::VariableBoolVectorType(targetUniformType); + + gl::LinkedUniform *targetUniform = getUniformByLocation(location); + + int elementCount = targetUniform->elementCount(); + + count = std::min(elementCount - (int)mUniformIndex[location].element, count); + + if (targetUniform->type == targetUniformType) + { + T *target = reinterpret_cast(targetUniform->data) + mUniformIndex[location].element * 4; + + for (int i = 0; i < count; i++) + { + T *dest = target + (i * 4); + const T *source = v + (i * components); + + for (int c = 0; c < components; c++) + { + SetIfDirty(dest + c, source[c], &targetUniform->dirty); + } + for (int c = components; c < 4; c++) + { + SetIfDirty(dest + c, T(0), &targetUniform->dirty); + } + } + } + else if (targetUniform->type == targetBoolType) + { + GLint *boolParams = reinterpret_cast(targetUniform->data) + mUniformIndex[location].element * 4; + + for (int i = 0; i < count; i++) + { + GLint *dest = boolParams + (i * 4); + const T *source = v + (i * components); + + for (int c = 0; c < components; c++) + { + SetIfDirty(dest + c, (source[c] == static_cast(0)) ? GL_FALSE : GL_TRUE, &targetUniform->dirty); + } + for (int c = components; c < 4; c++) + { + SetIfDirty(dest + c, GL_FALSE, &targetUniform->dirty); + } + } + } + else if (gl::IsSamplerType(targetUniform->type)) + { + ASSERT(targetUniformType == GL_INT); + + GLint *target = reinterpret_cast(targetUniform->data) + mUniformIndex[location].element * 4; + + bool wasDirty = targetUniform->dirty; + + for (int i = 0; i < count; i++) + { + GLint *dest = target + (i * 4); + const GLint *source = reinterpret_cast(v) + (i * components); + + SetIfDirty(dest + 0, source[0], &targetUniform->dirty); + SetIfDirty(dest + 1, 0, &targetUniform->dirty); + SetIfDirty(dest + 2, 0, &targetUniform->dirty); + SetIfDirty(dest + 3, 0, &targetUniform->dirty); + } + + if (!wasDirty && targetUniform->dirty) + { + mDirtySamplerMapping = true; + } + } + else UNREACHABLE(); +} + +template +bool transposeMatrix(T *target, const GLfloat *value, int targetWidth, int targetHeight, int srcWidth, int srcHeight) +{ + bool dirty = false; + int copyWidth = std::min(targetHeight, srcWidth); + int copyHeight = std::min(targetWidth, srcHeight); + + for (int x = 0; x < copyWidth; x++) + { + for (int y = 0; y < copyHeight; y++) + { + SetIfDirty(target + (x * targetWidth + y), static_cast(value[y * srcWidth + x]), &dirty); + } + } + // clear unfilled right side + for (int y = 0; y < copyWidth; y++) + { + for (int x = copyHeight; x < targetWidth; x++) + { + SetIfDirty(target + (y * targetWidth + x), static_cast(0), &dirty); + } + } + // clear unfilled bottom. + for (int y = copyWidth; y < targetHeight; y++) + { + for (int x = 0; x < targetWidth; x++) + { + SetIfDirty(target + (y * targetWidth + x), static_cast(0), &dirty); + } + } + + return dirty; +} + +template +bool expandMatrix(T *target, const GLfloat *value, int targetWidth, int targetHeight, int srcWidth, int srcHeight) +{ + bool dirty = false; + int copyWidth = std::min(targetWidth, srcWidth); + int copyHeight = std::min(targetHeight, srcHeight); + + for (int y = 0; y < copyHeight; y++) + { + for (int x = 0; x < copyWidth; x++) + { + SetIfDirty(target + (y * targetWidth + x), static_cast(value[y * srcWidth + x]), &dirty); + } + } + // clear unfilled right side + for (int y = 0; y < copyHeight; y++) + { + for (int x = copyWidth; x < targetWidth; x++) + { + SetIfDirty(target + (y * targetWidth + x), static_cast(0), &dirty); + } + } + // clear unfilled bottom. + for (int y = copyHeight; y < targetHeight; y++) + { + for (int x = 0; x < targetWidth; x++) + { + SetIfDirty(target + (y * targetWidth + x), static_cast(0), &dirty); + } + } + + return dirty; +} + +template +void ProgramD3D::setUniformMatrixfv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value, GLenum targetUniformType) +{ + gl::LinkedUniform *targetUniform = getUniformByLocation(location); + + int elementCount = targetUniform->elementCount(); + + count = std::min(elementCount - (int)mUniformIndex[location].element, count); + const unsigned int targetMatrixStride = (4 * rows); + GLfloat *target = (GLfloat*)(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * targetMatrixStride); + + for (int i = 0; i < count; i++) + { + // Internally store matrices as transposed versions to accomodate HLSL matrix indexing + if (transpose == GL_FALSE) + { + targetUniform->dirty = transposeMatrix(target, value, 4, rows, rows, cols) || targetUniform->dirty; + } + else + { + targetUniform->dirty = expandMatrix(target, value, 4, rows, cols, rows) || targetUniform->dirty; + } + target += targetMatrixStride; + value += cols * rows; + } +} + +template +void ProgramD3D::getUniformv(GLint location, T *params, GLenum uniformType) +{ + gl::LinkedUniform *targetUniform = mUniforms[mUniformIndex[location].index]; + + if (gl::IsMatrixType(targetUniform->type)) + { + const int rows = gl::VariableRowCount(targetUniform->type); + const int cols = gl::VariableColumnCount(targetUniform->type); + transposeMatrix(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4 * rows, rows, cols, 4, rows); + } + else if (uniformType == gl::VariableComponentType(targetUniform->type)) + { + unsigned int size = gl::VariableComponentCount(targetUniform->type); + memcpy(params, targetUniform->data + mUniformIndex[location].element * 4 * sizeof(T), + size * sizeof(T)); + } + else + { + unsigned int size = gl::VariableComponentCount(targetUniform->type); + switch (gl::VariableComponentType(targetUniform->type)) + { + case GL_BOOL: + { + GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4; + + for (unsigned int i = 0; i < size; i++) + { + params[i] = (boolParams[i] == GL_FALSE) ? static_cast(0) : static_cast(1); + } + } + break; + + case GL_FLOAT: + { + GLfloat *floatParams = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4; + + for (unsigned int i = 0; i < size; i++) + { + params[i] = static_cast(floatParams[i]); + } + } + break; + + case GL_INT: + { + GLint *intParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4; + + for (unsigned int i = 0; i < size; i++) + { + params[i] = static_cast(intParams[i]); + } + } + break; + + case GL_UNSIGNED_INT: + { + GLuint *uintParams = (GLuint*)targetUniform->data + mUniformIndex[location].element * 4; + + for (unsigned int i = 0; i < size; i++) + { + params[i] = static_cast(uintParams[i]); + } + } + break; + + default: UNREACHABLE(); + } + } +} + +template +void ProgramD3D::defineUniformBlockMembers(const std::vector &fields, const std::string &prefix, int blockIndex, + sh::BlockLayoutEncoder *encoder, std::vector *blockUniformIndexes, + bool inRowMajorLayout) +{ + for (unsigned int uniformIndex = 0; uniformIndex < fields.size(); uniformIndex++) + { + const VarT &field = fields[uniformIndex]; + const std::string &fieldName = (prefix.empty() ? field.name : prefix + "." + field.name); + + if (field.isStruct()) + { + bool rowMajorLayout = (inRowMajorLayout || IsRowMajorLayout(field)); + + for (unsigned int arrayElement = 0; arrayElement < field.elementCount(); arrayElement++) + { + encoder->enterAggregateType(); + + const std::string uniformElementName = fieldName + (field.isArray() ? ArrayString(arrayElement) : ""); + defineUniformBlockMembers(field.fields, uniformElementName, blockIndex, encoder, blockUniformIndexes, rowMajorLayout); + + encoder->exitAggregateType(); + } + } + else + { + bool isRowMajorMatrix = (gl::IsMatrixType(field.type) && inRowMajorLayout); + + sh::BlockMemberInfo memberInfo = encoder->encodeType(field.type, field.arraySize, isRowMajorMatrix); + + gl::LinkedUniform *newUniform = new gl::LinkedUniform(field.type, field.precision, fieldName, field.arraySize, + blockIndex, memberInfo); + + // add to uniform list, but not index, since uniform block uniforms have no location + blockUniformIndexes->push_back(mUniforms.size()); + mUniforms.push_back(newUniform); + } + } +} + +bool ProgramD3D::defineUniformBlock(gl::InfoLog &infoLog, const gl::Shader &shader, const sh::InterfaceBlock &interfaceBlock, + const gl::Caps &caps) +{ + const ShaderD3D* shaderD3D = ShaderD3D::makeShaderD3D(shader.getImplementation()); + + // create uniform block entries if they do not exist + if (getUniformBlockIndex(interfaceBlock.name) == GL_INVALID_INDEX) + { + std::vector blockUniformIndexes; + const unsigned int blockIndex = mUniformBlocks.size(); + + // define member uniforms + sh::BlockLayoutEncoder *encoder = NULL; + + if (interfaceBlock.layout == sh::BLOCKLAYOUT_STANDARD) + { + encoder = new sh::Std140BlockEncoder; + } + else + { + encoder = new sh::HLSLBlockEncoder(sh::HLSLBlockEncoder::ENCODE_PACKED); + } + ASSERT(encoder); + + defineUniformBlockMembers(interfaceBlock.fields, "", blockIndex, encoder, &blockUniformIndexes, interfaceBlock.isRowMajorLayout); + + size_t dataSize = encoder->getBlockSize(); + + // create all the uniform blocks + if (interfaceBlock.arraySize > 0) + { + for (unsigned int uniformBlockElement = 0; uniformBlockElement < interfaceBlock.arraySize; uniformBlockElement++) + { + gl::UniformBlock *newUniformBlock = new gl::UniformBlock(interfaceBlock.name, uniformBlockElement, dataSize); + newUniformBlock->memberUniformIndexes = blockUniformIndexes; + mUniformBlocks.push_back(newUniformBlock); + } + } + else + { + gl::UniformBlock *newUniformBlock = new gl::UniformBlock(interfaceBlock.name, GL_INVALID_INDEX, dataSize); + newUniformBlock->memberUniformIndexes = blockUniformIndexes; + mUniformBlocks.push_back(newUniformBlock); + } + } + + if (interfaceBlock.staticUse) + { + // Assign registers to the uniform blocks + const GLuint blockIndex = getUniformBlockIndex(interfaceBlock.name); + const unsigned int elementCount = std::max(1u, interfaceBlock.arraySize); + ASSERT(blockIndex != GL_INVALID_INDEX); + ASSERT(blockIndex + elementCount <= mUniformBlocks.size()); + + unsigned int interfaceBlockRegister = shaderD3D->getInterfaceBlockRegister(interfaceBlock.name); + + for (unsigned int uniformBlockElement = 0; uniformBlockElement < elementCount; uniformBlockElement++) + { + gl::UniformBlock *uniformBlock = mUniformBlocks[blockIndex + uniformBlockElement]; + ASSERT(uniformBlock->name == interfaceBlock.name); + + if (!assignUniformBlockRegister(infoLog, uniformBlock, shader.getType(), + interfaceBlockRegister + uniformBlockElement, caps)) + { + return false; + } + } + } + + return true; +} + +bool ProgramD3D::assignSamplers(unsigned int startSamplerIndex, + GLenum samplerType, + unsigned int samplerCount, + std::vector &outSamplers, + GLuint *outUsedRange) +{ + unsigned int samplerIndex = startSamplerIndex; + + do + { + if (samplerIndex < outSamplers.size()) + { + Sampler& sampler = outSamplers[samplerIndex]; + sampler.active = true; + sampler.textureType = GetTextureType(samplerType); + sampler.logicalTextureUnit = 0; + *outUsedRange = std::max(samplerIndex + 1, *outUsedRange); + } + else + { + return false; + } + + samplerIndex++; + } while (samplerIndex < startSamplerIndex + samplerCount); + + return true; +} + +bool ProgramD3D::indexSamplerUniform(const gl::LinkedUniform &uniform, gl::InfoLog &infoLog, const gl::Caps &caps) +{ + ASSERT(gl::IsSamplerType(uniform.type)); + ASSERT(uniform.vsRegisterIndex != GL_INVALID_INDEX || uniform.psRegisterIndex != GL_INVALID_INDEX); + + if (uniform.vsRegisterIndex != GL_INVALID_INDEX) + { + if (!assignSamplers(uniform.vsRegisterIndex, uniform.type, uniform.arraySize, mSamplersVS, + &mUsedVertexSamplerRange)) + { + infoLog.append("Vertex shader sampler count exceeds the maximum vertex texture units (%d).", + mSamplersVS.size()); + return false; + } + + unsigned int maxVertexVectors = mRenderer->getReservedVertexUniformVectors() + caps.maxVertexUniformVectors; + if (uniform.vsRegisterIndex + uniform.registerCount > maxVertexVectors) + { + infoLog.append("Vertex shader active uniforms exceed GL_MAX_VERTEX_UNIFORM_VECTORS (%u)", + caps.maxVertexUniformVectors); + return false; + } + } + + if (uniform.psRegisterIndex != GL_INVALID_INDEX) + { + if (!assignSamplers(uniform.psRegisterIndex, uniform.type, uniform.arraySize, mSamplersPS, + &mUsedPixelSamplerRange)) + { + infoLog.append("Pixel shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (%d).", + mSamplersPS.size()); + return false; + } + + unsigned int maxFragmentVectors = mRenderer->getReservedFragmentUniformVectors() + caps.maxFragmentUniformVectors; + if (uniform.psRegisterIndex + uniform.registerCount > maxFragmentVectors) + { + infoLog.append("Fragment shader active uniforms exceed GL_MAX_FRAGMENT_UNIFORM_VECTORS (%u)", + caps.maxFragmentUniformVectors); + return false; + } + } + + return true; +} + +bool ProgramD3D::indexUniforms(gl::InfoLog &infoLog, const gl::Caps &caps) +{ + for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++) + { + const gl::LinkedUniform &uniform = *mUniforms[uniformIndex]; + + if (gl::IsSamplerType(uniform.type)) + { + if (!indexSamplerUniform(uniform, infoLog, caps)) + { + return false; + } + } + + for (unsigned int arrayElementIndex = 0; arrayElementIndex < uniform.elementCount(); arrayElementIndex++) + { + mUniformIndex.push_back(gl::VariableLocation(uniform.name, arrayElementIndex, uniformIndex)); + } + } + + return true; +} + +void ProgramD3D::reset() +{ + ProgramImpl::reset(); + + SafeDeleteContainer(mVertexExecutables); + SafeDeleteContainer(mPixelExecutables); + SafeDelete(mGeometryExecutable); + + mTransformFeedbackBufferMode = GL_NONE; + + mVertexHLSL.clear(); + mVertexWorkarounds.reset(); + mShaderVersion = 100; + + mPixelHLSL.clear(); + mPixelWorkarounds.reset(); + mUsesFragDepth = false; + mPixelShaderKey.clear(); + mUsesPointSize = false; + + SafeDelete(mVertexUniformStorage); + SafeDelete(mFragmentUniformStorage); + + mSamplersPS.clear(); + mSamplersVS.clear(); + + mUsedVertexSamplerRange = 0; + mUsedPixelSamplerRange = 0; + mDirtySamplerMapping = true; + + std::fill(mAttributesByLayout, mAttributesByLayout + ArraySize(mAttributesByLayout), -1); +} + +unsigned int ProgramD3D::getSerial() const +{ + return mSerial; +} + +unsigned int ProgramD3D::issueSerial() +{ + return mCurrentSerial++; +} + +void ProgramD3D::initAttributesByLayout() +{ + for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) + { + mAttributesByLayout[i] = i; + } + + std::sort(&mAttributesByLayout[0], &mAttributesByLayout[gl::MAX_VERTEX_ATTRIBS], AttributeSorter(mSemanticIndex)); +} + +void ProgramD3D::sortAttributesByLayout(rx::TranslatedAttribute attributes[gl::MAX_VERTEX_ATTRIBS], + int sortedSemanticIndices[gl::MAX_VERTEX_ATTRIBS]) const +{ + rx::TranslatedAttribute oldTranslatedAttributes[gl::MAX_VERTEX_ATTRIBS]; + + for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) + { + oldTranslatedAttributes[i] = attributes[i]; + } + + for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) + { + int oldIndex = mAttributesByLayout[i]; + sortedSemanticIndices[i] = mSemanticIndex[oldIndex]; + attributes[i] = oldTranslatedAttributes[oldIndex]; + } +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/ProgramD3D.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/ProgramD3D.h new file mode 100644 index 0000000000..6f3eade81d --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/ProgramD3D.h @@ -0,0 +1,244 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// ProgramD3D.h: Defines the rx::ProgramD3D class which implements rx::ProgramImpl. + +#ifndef LIBANGLE_RENDERER_D3D_PROGRAMD3D_H_ +#define LIBANGLE_RENDERER_D3D_PROGRAMD3D_H_ + +#include "compiler/translator/blocklayoutHLSL.h" +#include "libANGLE/Constants.h" +#include "libANGLE/renderer/ProgramImpl.h" +#include "libANGLE/renderer/Workarounds.h" +#include "libANGLE/renderer/d3d/DynamicHLSL.h" + +#include +#include + +namespace gl +{ +struct LinkedUniform; +struct VariableLocation; +struct VertexFormat; +} + +namespace rx +{ +class RendererD3D; +class UniformStorageD3D; +class ShaderExecutableD3D; + +#if !defined(ANGLE_COMPILE_OPTIMIZATION_LEVEL) +// WARNING: D3DCOMPILE_OPTIMIZATION_LEVEL3 may lead to a DX9 shader compiler hang. +// It should only be used selectively to work around specific bugs. +#define ANGLE_COMPILE_OPTIMIZATION_LEVEL D3DCOMPILE_OPTIMIZATION_LEVEL1 +#endif + +class ProgramD3D : public ProgramImpl +{ + public: + ProgramD3D(RendererD3D *renderer); + virtual ~ProgramD3D(); + + const std::vector &getPixelShaderKey() { return mPixelShaderKey; } + int getShaderVersion() const { return mShaderVersion; } + GLenum getTransformFeedbackBufferMode() const { return mTransformFeedbackBufferMode; } + + GLint getSamplerMapping(gl::SamplerType type, unsigned int samplerIndex, const gl::Caps &caps) const; + GLenum getSamplerTextureType(gl::SamplerType type, unsigned int samplerIndex) const; + GLint getUsedSamplerRange(gl::SamplerType type) const; + void updateSamplerMapping(); + bool validateSamplers(gl::InfoLog *infoLog, const gl::Caps &caps); + + bool usesPointSize() const { return mUsesPointSize; } + bool usesPointSpriteEmulation() const; + bool usesGeometryShader() const; + bool usesInstancedPointSpriteEmulation() const; + + GLenum getBinaryFormat() { return GL_PROGRAM_BINARY_ANGLE; } + LinkResult load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream); + gl::Error save(gl::BinaryOutputStream *stream); + + gl::Error getPixelExecutableForFramebuffer(const gl::Framebuffer *fbo, ShaderExecutableD3D **outExectuable); + gl::Error getPixelExecutableForOutputLayout(const std::vector &outputLayout, ShaderExecutableD3D **outExectuable, gl::InfoLog *infoLog); + gl::Error getVertexExecutableForInputLayout(const gl::VertexFormat inputLayout[gl::MAX_VERTEX_ATTRIBS], ShaderExecutableD3D **outExectuable, gl::InfoLog *infoLog); + ShaderExecutableD3D *getGeometryExecutable() const { return mGeometryExecutable; } + + LinkResult compileProgramExecutables(gl::InfoLog &infoLog, gl::Shader *fragmentShader, gl::Shader *vertexShader, + int registers); + + LinkResult link(const gl::Data &data, gl::InfoLog &infoLog, + gl::Shader *fragmentShader, gl::Shader *vertexShader, + const std::vector &transformFeedbackVaryings, + GLenum transformFeedbackBufferMode, + int *registers, std::vector *linkedVaryings, + std::map *outputVariables); + + void getInputLayoutSignature(const gl::VertexFormat inputLayout[], GLenum signature[]) const; + + void initializeUniformStorage(); + gl::Error applyUniforms(); + gl::Error applyUniformBuffers(const gl::Data &data, GLuint uniformBlockBindings[]) override; + bool assignUniformBlockRegister(gl::InfoLog &infoLog, gl::UniformBlock *uniformBlock, GLenum shader, + unsigned int registerIndex, const gl::Caps &caps); + void dirtyAllUniforms(); + + void setUniform1fv(GLint location, GLsizei count, const GLfloat *v); + void setUniform2fv(GLint location, GLsizei count, const GLfloat *v); + void setUniform3fv(GLint location, GLsizei count, const GLfloat *v); + void setUniform4fv(GLint location, GLsizei count, const GLfloat *v); + void setUniform1iv(GLint location, GLsizei count, const GLint *v); + void setUniform2iv(GLint location, GLsizei count, const GLint *v); + void setUniform3iv(GLint location, GLsizei count, const GLint *v); + void setUniform4iv(GLint location, GLsizei count, const GLint *v); + void setUniform1uiv(GLint location, GLsizei count, const GLuint *v); + void setUniform2uiv(GLint location, GLsizei count, const GLuint *v); + void setUniform3uiv(GLint location, GLsizei count, const GLuint *v); + void setUniform4uiv(GLint location, GLsizei count, const GLuint *v); + void setUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); + void setUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); + void setUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); + void setUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); + void setUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); + void setUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); + void setUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); + void setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); + void setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); + + void getUniformfv(GLint location, GLfloat *params); + void getUniformiv(GLint location, GLint *params); + void getUniformuiv(GLint location, GLuint *params); + + const UniformStorageD3D &getVertexUniformStorage() const { return *mVertexUniformStorage; } + const UniformStorageD3D &getFragmentUniformStorage() const { return *mFragmentUniformStorage; } + + bool linkUniforms(gl::InfoLog &infoLog, const gl::Shader &vertexShader, const gl::Shader &fragmentShader, + const gl::Caps &caps); + bool defineUniformBlock(gl::InfoLog &infoLog, const gl::Shader &shader, const sh::InterfaceBlock &interfaceBlock, const gl::Caps &caps); + + void reset(); + + unsigned int getSerial() const; + + void initAttributesByLayout(); + void sortAttributesByLayout(rx::TranslatedAttribute attributes[gl::MAX_VERTEX_ATTRIBS], + int sortedSemanticIndices[gl::MAX_VERTEX_ATTRIBS]) const; + + private: + class VertexExecutable + { + public: + VertexExecutable(const gl::VertexFormat inputLayout[gl::MAX_VERTEX_ATTRIBS], + const GLenum signature[gl::MAX_VERTEX_ATTRIBS], + ShaderExecutableD3D *shaderExecutable); + ~VertexExecutable(); + + bool matchesSignature(const GLenum convertedLayout[gl::MAX_VERTEX_ATTRIBS]) const; + + const gl::VertexFormat *inputs() const { return mInputs; } + const GLenum *signature() const { return mSignature; } + ShaderExecutableD3D *shaderExecutable() const { return mShaderExecutable; } + + private: + gl::VertexFormat mInputs[gl::MAX_VERTEX_ATTRIBS]; + GLenum mSignature[gl::MAX_VERTEX_ATTRIBS]; + ShaderExecutableD3D *mShaderExecutable; + }; + + class PixelExecutable + { + public: + PixelExecutable(const std::vector &outputSignature, ShaderExecutableD3D *shaderExecutable); + ~PixelExecutable(); + + bool matchesSignature(const std::vector &signature) const { return mOutputSignature == signature; } + + const std::vector &outputSignature() const { return mOutputSignature; } + ShaderExecutableD3D *shaderExecutable() const { return mShaderExecutable; } + + private: + std::vector mOutputSignature; + ShaderExecutableD3D *mShaderExecutable; + }; + + struct Sampler + { + Sampler(); + + bool active; + GLint logicalTextureUnit; + GLenum textureType; + }; + + void defineUniformBase(const ShaderD3D *shader, const sh::Uniform &uniform, unsigned int uniformRegister); + void defineUniform(const ShaderD3D *shader, const sh::ShaderVariable &uniform, const std::string &fullName, + sh::HLSLBlockEncoder *encoder); + bool indexSamplerUniform(const gl::LinkedUniform &uniform, gl::InfoLog &infoLog, const gl::Caps &caps); + bool indexUniforms(gl::InfoLog &infoLog, const gl::Caps &caps); + static bool assignSamplers(unsigned int startSamplerIndex, GLenum samplerType, unsigned int samplerCount, + std::vector &outSamplers, GLuint *outUsedRange); + + template + void setUniform(GLint location, GLsizei count, const T* v, GLenum targetUniformType); + + template + void setUniformMatrixfv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value, GLenum targetUniformType); + + template + void getUniformv(GLint location, T *params, GLenum uniformType); + + template + void defineUniformBlockMembers(const std::vector &fields, const std::string &prefix, int blockIndex, + sh::BlockLayoutEncoder *encoder, std::vector *blockUniformIndexes, + bool inRowMajorLayout); + + RendererD3D *mRenderer; + DynamicHLSL *mDynamicHLSL; + + std::vector mVertexExecutables; + std::vector mPixelExecutables; + ShaderExecutableD3D *mGeometryExecutable; + + std::string mVertexHLSL; + D3DCompilerWorkarounds mVertexWorkarounds; + + std::string mPixelHLSL; + D3DCompilerWorkarounds mPixelWorkarounds; + bool mUsesFragDepth; + std::vector mPixelShaderKey; + + bool mUsesPointSize; + + UniformStorageD3D *mVertexUniformStorage; + UniformStorageD3D *mFragmentUniformStorage; + + GLenum mTransformFeedbackBufferMode; + + std::vector mSamplersPS; + std::vector mSamplersVS; + GLuint mUsedVertexSamplerRange; + GLuint mUsedPixelSamplerRange; + bool mDirtySamplerMapping; + + // Cache for validateSamplers + std::vector mTextureUnitTypesCache; + + // Cache for getPixelExecutableForFramebuffer + std::vector mPixelShaderOutputFormatCache; + + int mShaderVersion; + + int mAttributesByLayout[gl::MAX_VERTEX_ATTRIBS]; + + unsigned int mSerial; + + static unsigned int issueSerial(); + static unsigned int mCurrentSerial; +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_PROGRAMD3D_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/RenderTargetD3D.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/RenderTargetD3D.cpp new file mode 100644 index 0000000000..84b30aa106 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/RenderTargetD3D.cpp @@ -0,0 +1,36 @@ +// +// Copyright (c) 2012-2015 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// RenderTargetD3D.cpp: Implements serial handling for rx::RenderTargetD3D + +#include "libANGLE/renderer/d3d/RenderTargetD3D.h" + +namespace rx +{ +unsigned int RenderTargetD3D::mCurrentSerial = 1; + +RenderTargetD3D::RenderTargetD3D() + : mSerial(issueSerials(1)) +{ +} + +RenderTargetD3D::~RenderTargetD3D() +{ +} + +unsigned int RenderTargetD3D::getSerial() const +{ + return mSerial; +} + +unsigned int RenderTargetD3D::issueSerials(unsigned int count) +{ + unsigned int firstSerial = mCurrentSerial; + mCurrentSerial += count; + return firstSerial; +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/RenderTargetD3D.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/RenderTargetD3D.h new file mode 100644 index 0000000000..fe6afcecae --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/RenderTargetD3D.h @@ -0,0 +1,42 @@ +// +// Copyright (c) 2012-2015 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// RenderTargetD3D.h: Defines an abstract wrapper class to manage IDirect3DSurface9 +// and ID3D11View objects belonging to renderbuffers and renderable textures. + +#ifndef LIBANGLE_RENDERER_D3D_RENDERTARGETD3D_H_ +#define LIBANGLE_RENDERER_D3D_RENDERTARGETD3D_H_ + +#include "common/angleutils.h" +#include "libANGLE/angletypes.h" + +namespace rx +{ + +class RenderTargetD3D : angle::NonCopyable +{ + public: + RenderTargetD3D(); + virtual ~RenderTargetD3D(); + + virtual GLsizei getWidth() const = 0; + virtual GLsizei getHeight() const = 0; + virtual GLsizei getDepth() const = 0; + virtual GLenum getInternalFormat() const = 0; + virtual GLsizei getSamples() const = 0; + gl::Extents getExtents() const { return gl::Extents(getWidth(), getHeight(), getDepth()); } + + virtual unsigned int getSerial() const; + static unsigned int issueSerials(unsigned int count); + + private: + const unsigned int mSerial; + static unsigned int mCurrentSerial; +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_RENDERTARGETD3D_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/RenderbufferD3D.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/RenderbufferD3D.cpp new file mode 100644 index 0000000000..c91fedff06 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/RenderbufferD3D.cpp @@ -0,0 +1,73 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// RenderbufferD3d.cpp: Implements the RenderbufferD3D class, a specialization of RenderbufferImpl + + +#include "libANGLE/renderer/d3d/RenderbufferD3D.h" + +#include "libANGLE/renderer/d3d/RendererD3D.h" +#include "libANGLE/renderer/d3d/RenderTargetD3D.h" + +namespace rx +{ +RenderbufferD3D::RenderbufferD3D(RendererD3D *renderer) : mRenderer(renderer) +{ + mRenderTarget = NULL; +} + +RenderbufferD3D::~RenderbufferD3D() +{ + SafeDelete(mRenderTarget); +} + +RenderbufferD3D *RenderbufferD3D::makeRenderbufferD3D(RenderbufferImpl *renderbuffer) +{ + ASSERT(HAS_DYNAMIC_TYPE(RenderbufferD3D*, renderbuffer)); + return static_cast(renderbuffer); +} + +gl::Error RenderbufferD3D::setStorage(GLenum internalformat, size_t width, size_t height) +{ + return setStorageMultisample(0, internalformat, width, height); +} + +gl::Error RenderbufferD3D::setStorageMultisample(size_t samples, GLenum internalformat, size_t width, size_t height) +{ + // If the renderbuffer parameters are queried, the calling function + // will expect one of the valid renderbuffer formats for use in + // glRenderbufferStorage, but we should create depth and stencil buffers + // as DEPTH24_STENCIL8 + GLenum creationFormat = internalformat; + if (internalformat == GL_DEPTH_COMPONENT16 || internalformat == GL_STENCIL_INDEX8) + { + creationFormat = GL_DEPTH24_STENCIL8_OES; + } + + RenderTargetD3D *newRT = NULL; + gl::Error error = mRenderer->createRenderTarget(width, height, creationFormat, samples, &newRT); + if (error.isError()) + { + return error; + } + + SafeDelete(mRenderTarget); + mRenderTarget = newRT; + + return gl::Error(GL_NO_ERROR); +} + +RenderTargetD3D *RenderbufferD3D::getRenderTarget() +{ + return mRenderTarget; +} + +unsigned int RenderbufferD3D::getRenderTargetSerial() const +{ + return (mRenderTarget ? mRenderTarget->getSerial() : 0); +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/RenderbufferD3D.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/RenderbufferD3D.h new file mode 100644 index 0000000000..4c4b998683 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/RenderbufferD3D.h @@ -0,0 +1,43 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// RenderbufferD3d.h: Defines the RenderbufferD3D class which implements RenderbufferImpl. + +#ifndef LIBANGLE_RENDERER_D3D_RENDERBUFFERD3D_H_ +#define LIBANGLE_RENDERER_D3D_RENDERBUFFERD3D_H_ + +#include "angle_gl.h" + +#include "common/angleutils.h" +#include "libANGLE/renderer/RenderbufferImpl.h" + +namespace rx +{ +class RendererD3D; +class RenderTargetD3D; +class SwapChainD3D; + +class RenderbufferD3D : public RenderbufferImpl +{ + public: + RenderbufferD3D(RendererD3D *renderer); + virtual ~RenderbufferD3D(); + + static RenderbufferD3D *makeRenderbufferD3D(RenderbufferImpl *renderbuffer); + + virtual gl::Error setStorage(GLenum internalformat, size_t width, size_t height) override; + virtual gl::Error setStorageMultisample(size_t samples, GLenum internalformat, size_t width, size_t height) override; + + RenderTargetD3D *getRenderTarget(); + unsigned int getRenderTargetSerial() const; + + private: + RendererD3D *mRenderer; + RenderTargetD3D *mRenderTarget; +}; +} + +#endif // LIBANGLE_RENDERER_D3D_RENDERBUFFERD3D_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/RendererD3D.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/RendererD3D.cpp new file mode 100644 index 0000000000..2ce0ce5a1b --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/RendererD3D.cpp @@ -0,0 +1,628 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// RendererD3D.cpp: Implementation of the base D3D Renderer. + +#include "libANGLE/renderer/d3d/RendererD3D.h" + +#include "common/MemoryBuffer.h" +#include "common/utilities.h" +#include "libANGLE/Display.h" +#include "libANGLE/Framebuffer.h" +#include "libANGLE/FramebufferAttachment.h" +#include "libANGLE/ResourceManager.h" +#include "libANGLE/State.h" +#include "libANGLE/VertexArray.h" +#include "libANGLE/formatutils.h" +#include "libANGLE/renderer/d3d/BufferD3D.h" +#include "libANGLE/renderer/d3d/DisplayD3D.h" +#include "libANGLE/renderer/d3d/IndexDataManager.h" + +namespace rx +{ + +namespace +{ +// If we request a scratch buffer requesting a smaller size this many times, +// release and recreate the scratch buffer. This ensures we don't have a +// degenerate case where we are stuck hogging memory. +const int ScratchMemoryBufferLifetime = 1000; +} + +RendererD3D::RendererD3D(egl::Display *display) + : mDisplay(display), + mDeviceLost(false), + mScratchMemoryBufferResetCounter(0) +{ +} + +RendererD3D::~RendererD3D() +{ + cleanup(); +} + +void RendererD3D::cleanup() +{ + mScratchMemoryBuffer.resize(0); + for (auto it = mIncompleteTextures.begin(); it != mIncompleteTextures.end(); ++it) + { + it->second.set(NULL); + } + mIncompleteTextures.clear(); +} + +// static +RendererD3D *RendererD3D::makeRendererD3D(Renderer *renderer) +{ + ASSERT(HAS_DYNAMIC_TYPE(RendererD3D*, renderer)); + return static_cast(renderer); +} + +gl::Error RendererD3D::drawElements(const gl::Data &data, + GLenum mode, GLsizei count, GLenum type, + const GLvoid *indices, GLsizei instances, + const RangeUI &indexRange) +{ + if (data.state->isPrimitiveRestartEnabled()) + { + UNIMPLEMENTED(); + return gl::Error(GL_INVALID_OPERATION, "Primitive restart not implemented"); + } + + gl::Program *program = data.state->getProgram(); + ASSERT(program != NULL); + + program->updateSamplerMapping(); + + gl::Error error = generateSwizzles(data); + if (error.isError()) + { + return error; + } + + if (!applyPrimitiveType(mode, count, program->usesPointSize())) + { + return gl::Error(GL_NO_ERROR); + } + + error = applyRenderTarget(data, mode, false); + if (error.isError()) + { + return error; + } + + error = applyState(data, mode); + if (error.isError()) + { + return error; + } + + gl::VertexArray *vao = data.state->getVertexArray(); + TranslatedIndexData indexInfo; + indexInfo.indexRange = indexRange; + error = applyIndexBuffer(indices, vao->getElementArrayBuffer(), count, mode, type, &indexInfo); + if (error.isError()) + { + return error; + } + + applyTransformFeedbackBuffers(*data.state); + // Transform feedback is not allowed for DrawElements, this error should have been caught at the API validation + // layer. + ASSERT(!data.state->isTransformFeedbackActiveUnpaused()); + + GLsizei vertexCount = indexInfo.indexRange.length() + 1; + error = applyVertexBuffer(*data.state, mode, indexInfo.indexRange.start, vertexCount, instances); + if (error.isError()) + { + return error; + } + + error = applyShaders(data); + if (error.isError()) + { + return error; + } + + error = applyTextures(data); + if (error.isError()) + { + return error; + } + + error = program->applyUniformBuffers(data); + if (error.isError()) + { + return error; + } + + if (!skipDraw(data, mode)) + { + error = drawElements(mode, count, type, indices, vao->getElementArrayBuffer(), indexInfo, instances); + if (error.isError()) + { + return error; + } + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error RendererD3D::drawArrays(const gl::Data &data, + GLenum mode, GLint first, + GLsizei count, GLsizei instances) +{ + gl::Program *program = data.state->getProgram(); + ASSERT(program != NULL); + + program->updateSamplerMapping(); + + gl::Error error = generateSwizzles(data); + if (error.isError()) + { + return error; + } + + if (!applyPrimitiveType(mode, count, program->usesPointSize())) + { + return gl::Error(GL_NO_ERROR); + } + + error = applyRenderTarget(data, mode, false); + if (error.isError()) + { + return error; + } + + error = applyState(data, mode); + if (error.isError()) + { + return error; + } + + applyTransformFeedbackBuffers(*data.state); + + error = applyVertexBuffer(*data.state, mode, first, count, instances); + if (error.isError()) + { + return error; + } + + error = applyShaders(data); + if (error.isError()) + { + return error; + } + + error = applyTextures(data); + if (error.isError()) + { + return error; + } + + error = program->applyUniformBuffers(data); + if (error.isError()) + { + return error; + } + + if (!skipDraw(data, mode)) + { + error = drawArrays(data, mode, count, instances, program->usesPointSize()); + if (error.isError()) + { + return error; + } + + if (data.state->isTransformFeedbackActiveUnpaused()) + { + markTransformFeedbackUsage(data); + } + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error RendererD3D::generateSwizzles(const gl::Data &data, gl::SamplerType type) +{ + gl::Program *program = data.state->getProgram(); + + size_t samplerRange = program->getUsedSamplerRange(type); + + for (size_t i = 0; i < samplerRange; i++) + { + GLenum textureType = program->getSamplerTextureType(type, i); + GLint textureUnit = program->getSamplerMapping(type, i, *data.caps); + if (textureUnit != -1) + { + gl::Texture *texture = data.state->getSamplerTexture(textureUnit, textureType); + ASSERT(texture); + if (texture->getSamplerState().swizzleRequired()) + { + gl::Error error = generateSwizzle(texture); + if (error.isError()) + { + return error; + } + } + } + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error RendererD3D::generateSwizzles(const gl::Data &data) +{ + gl::Error error = generateSwizzles(data, gl::SAMPLER_VERTEX); + if (error.isError()) + { + return error; + } + + error = generateSwizzles(data, gl::SAMPLER_PIXEL); + if (error.isError()) + { + return error; + } + + return gl::Error(GL_NO_ERROR); +} + +// Applies the render target surface, depth stencil surface, viewport rectangle and +// scissor rectangle to the renderer +gl::Error RendererD3D::applyRenderTarget(const gl::Data &data, GLenum drawMode, bool ignoreViewport) +{ + const gl::Framebuffer *framebufferObject = data.state->getDrawFramebuffer(); + ASSERT(framebufferObject && framebufferObject->checkStatus(data) == GL_FRAMEBUFFER_COMPLETE); + + gl::Error error = applyRenderTarget(framebufferObject); + if (error.isError()) + { + return error; + } + + float nearZ, farZ; + data.state->getDepthRange(&nearZ, &farZ); + setViewport(data.state->getViewport(), nearZ, farZ, drawMode, + data.state->getRasterizerState().frontFace, ignoreViewport); + + setScissorRectangle(data.state->getScissor(), data.state->isScissorTestEnabled()); + + return gl::Error(GL_NO_ERROR); +} + +// Applies the fixed-function state (culling, depth test, alpha blending, stenciling, etc) to the Direct3D device +gl::Error RendererD3D::applyState(const gl::Data &data, GLenum drawMode) +{ + const gl::Framebuffer *framebufferObject = data.state->getDrawFramebuffer(); + int samples = framebufferObject->getSamples(data); + + gl::RasterizerState rasterizer = data.state->getRasterizerState(); + rasterizer.pointDrawMode = (drawMode == GL_POINTS); + rasterizer.multiSample = (samples != 0); + + gl::Error error = setRasterizerState(rasterizer); + if (error.isError()) + { + return error; + } + + unsigned int mask = 0; + if (data.state->isSampleCoverageEnabled()) + { + GLclampf coverageValue; + bool coverageInvert = false; + data.state->getSampleCoverageParams(&coverageValue, &coverageInvert); + if (coverageValue != 0) + { + float threshold = 0.5f; + + for (int i = 0; i < samples; ++i) + { + mask <<= 1; + + if ((i + 1) * coverageValue >= threshold) + { + threshold += 1.0f; + mask |= 1; + } + } + } + + if (coverageInvert) + { + mask = ~mask; + } + } + else + { + mask = 0xFFFFFFFF; + } + error = setBlendState(framebufferObject, data.state->getBlendState(), data.state->getBlendColor(), mask); + if (error.isError()) + { + return error; + } + + error = setDepthStencilState(data.state->getDepthStencilState(), data.state->getStencilRef(), + data.state->getStencilBackRef(), rasterizer.frontFace == GL_CCW); + if (error.isError()) + { + return error; + } + + return gl::Error(GL_NO_ERROR); +} + +// Applies the shaders and shader constants to the Direct3D device +gl::Error RendererD3D::applyShaders(const gl::Data &data) +{ + gl::Program *program = data.state->getProgram(); + + gl::VertexFormat inputLayout[gl::MAX_VERTEX_ATTRIBS]; + gl::VertexFormat::GetInputLayout(inputLayout, program, *data.state); + + const gl::Framebuffer *fbo = data.state->getDrawFramebuffer(); + + gl::Error error = applyShaders(program, inputLayout, fbo, data.state->getRasterizerState().rasterizerDiscard, data.state->isTransformFeedbackActiveUnpaused()); + if (error.isError()) + { + return error; + } + + return program->applyUniforms(); +} + +// For each Direct3D sampler of either the pixel or vertex stage, +// looks up the corresponding OpenGL texture image unit and texture type, +// and sets the texture and its addressing/filtering state (or NULL when inactive). +gl::Error RendererD3D::applyTextures(const gl::Data &data, gl::SamplerType shaderType, + const FramebufferTextureSerialArray &framebufferSerials, size_t framebufferSerialCount) +{ + gl::Program *program = data.state->getProgram(); + + size_t samplerRange = program->getUsedSamplerRange(shaderType); + for (size_t samplerIndex = 0; samplerIndex < samplerRange; samplerIndex++) + { + GLenum textureType = program->getSamplerTextureType(shaderType, samplerIndex); + GLint textureUnit = program->getSamplerMapping(shaderType, samplerIndex, *data.caps); + if (textureUnit != -1) + { + gl::Texture *texture = data.state->getSamplerTexture(textureUnit, textureType); + ASSERT(texture); + gl::SamplerState sampler = texture->getSamplerState(); + + gl::Sampler *samplerObject = data.state->getSampler(textureUnit); + if (samplerObject) + { + samplerObject->getState(&sampler); + } + + // TODO: std::binary_search may become unavailable using older versions of GCC + if (texture->isSamplerComplete(sampler, data) && + !std::binary_search(framebufferSerials.begin(), framebufferSerials.begin() + framebufferSerialCount, texture->getTextureSerial())) + { + gl::Error error = setSamplerState(shaderType, samplerIndex, texture, sampler); + if (error.isError()) + { + return error; + } + + error = setTexture(shaderType, samplerIndex, texture); + if (error.isError()) + { + return error; + } + } + else + { + // Texture is not sampler complete or it is in use by the framebuffer. Bind the incomplete texture. + gl::Texture *incompleteTexture = getIncompleteTexture(textureType); + gl::Error error = setTexture(shaderType, samplerIndex, incompleteTexture); + if (error.isError()) + { + return error; + } + } + } + else + { + // No texture bound to this slot even though it is used by the shader, bind a NULL texture + gl::Error error = setTexture(shaderType, samplerIndex, NULL); + if (error.isError()) + { + return error; + } + } + } + + // Set all the remaining textures to NULL + size_t samplerCount = (shaderType == gl::SAMPLER_PIXEL) ? data.caps->maxTextureImageUnits + : data.caps->maxVertexTextureImageUnits; + for (size_t samplerIndex = samplerRange; samplerIndex < samplerCount; samplerIndex++) + { + gl::Error error = setTexture(shaderType, samplerIndex, NULL); + if (error.isError()) + { + return error; + } + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error RendererD3D::applyTextures(const gl::Data &data) +{ + FramebufferTextureSerialArray framebufferSerials; + size_t framebufferSerialCount = getBoundFramebufferTextureSerials(data, &framebufferSerials); + + gl::Error error = applyTextures(data, gl::SAMPLER_VERTEX, framebufferSerials, framebufferSerialCount); + if (error.isError()) + { + return error; + } + + error = applyTextures(data, gl::SAMPLER_PIXEL, framebufferSerials, framebufferSerialCount); + if (error.isError()) + { + return error; + } + + return gl::Error(GL_NO_ERROR); +} + +bool RendererD3D::skipDraw(const gl::Data &data, GLenum drawMode) +{ + if (drawMode == GL_POINTS) + { + // ProgramBinary assumes non-point rendering if gl_PointSize isn't written, + // which affects varying interpolation. Since the value of gl_PointSize is + // undefined when not written, just skip drawing to avoid unexpected results. + if (!data.state->getProgram()->usesPointSize() && !data.state->isTransformFeedbackActiveUnpaused()) + { + // This is stictly speaking not an error, but developers should be + // notified of risking undefined behavior. + ERR("Point rendering without writing to gl_PointSize."); + + return true; + } + } + else if (gl::IsTriangleMode(drawMode)) + { + if (data.state->getRasterizerState().cullFace && data.state->getRasterizerState().cullMode == GL_FRONT_AND_BACK) + { + return true; + } + } + + return false; +} + +void RendererD3D::markTransformFeedbackUsage(const gl::Data &data) +{ + for (size_t i = 0; i < data.caps->maxTransformFeedbackSeparateAttributes; i++) + { + gl::Buffer *buffer = data.state->getIndexedTransformFeedbackBuffer(i); + if (buffer) + { + BufferD3D *bufferD3D = GetImplAs(buffer); + bufferD3D->markTransformFeedbackUsage(); + } + } +} + +size_t RendererD3D::getBoundFramebufferTextureSerials(const gl::Data &data, + FramebufferTextureSerialArray *outSerialArray) +{ + size_t serialCount = 0; + + const gl::Framebuffer *drawFramebuffer = data.state->getDrawFramebuffer(); + for (unsigned int i = 0; i < data.caps->maxColorAttachments; i++) + { + gl::FramebufferAttachment *attachment = drawFramebuffer->getColorbuffer(i); + if (attachment && attachment->type() == GL_TEXTURE) + { + gl::Texture *texture = attachment->getTexture(); + (*outSerialArray)[serialCount++] = texture->getTextureSerial(); + } + } + + gl::FramebufferAttachment *depthStencilAttachment = drawFramebuffer->getDepthOrStencilbuffer(); + if (depthStencilAttachment && depthStencilAttachment->type() == GL_TEXTURE) + { + gl::Texture *depthStencilTexture = depthStencilAttachment->getTexture(); + (*outSerialArray)[serialCount++] = depthStencilTexture->getTextureSerial(); + } + + std::sort(outSerialArray->begin(), outSerialArray->begin() + serialCount); + + return serialCount; +} + +gl::Texture *RendererD3D::getIncompleteTexture(GLenum type) +{ + if (mIncompleteTextures.find(type) == mIncompleteTextures.end()) + { + const GLubyte color[] = { 0, 0, 0, 255 }; + const gl::Extents colorSize(1, 1, 1); + const gl::PixelUnpackState incompleteUnpackState(1, 0); + + gl::Texture* t = new gl::Texture(createTexture(type), gl::Texture::INCOMPLETE_TEXTURE_ID, type); + + if (type == GL_TEXTURE_CUBE_MAP) + { + for (GLenum face = GL_TEXTURE_CUBE_MAP_POSITIVE_X; face <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z; face++) + { + t->setImage(face, 0, GL_RGBA, colorSize, GL_RGBA, GL_UNSIGNED_BYTE, incompleteUnpackState, color); + } + } + else + { + t->setImage(type, 0, GL_RGBA, colorSize, GL_RGBA, GL_UNSIGNED_BYTE, incompleteUnpackState, color); + } + + mIncompleteTextures[type].set(t); + } + + return mIncompleteTextures[type].get(); +} + +bool RendererD3D::isDeviceLost() const +{ + return mDeviceLost; +} + +void RendererD3D::notifyDeviceLost() +{ + mDeviceLost = true; + mDisplay->notifyDeviceLost(); +} + +std::string RendererD3D::getVendorString() const +{ + LUID adapterLuid = { 0 }; + + if (getLUID(&adapterLuid)) + { + char adapterLuidString[64]; + sprintf_s(adapterLuidString, sizeof(adapterLuidString), "(adapter LUID: %08x%08x)", adapterLuid.HighPart, adapterLuid.LowPart); + return std::string(adapterLuidString); + } + + return std::string(""); +} + +gl::Error RendererD3D::getScratchMemoryBuffer(size_t requestedSize, MemoryBuffer **bufferOut) +{ + if (mScratchMemoryBuffer.size() == requestedSize) + { + mScratchMemoryBufferResetCounter = ScratchMemoryBufferLifetime; + *bufferOut = &mScratchMemoryBuffer; + return gl::Error(GL_NO_ERROR); + } + + if (mScratchMemoryBuffer.size() > requestedSize) + { + mScratchMemoryBufferResetCounter--; + } + + if (mScratchMemoryBufferResetCounter <= 0 || mScratchMemoryBuffer.size() < requestedSize) + { + mScratchMemoryBuffer.resize(0); + if (!mScratchMemoryBuffer.resize(requestedSize)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate internal buffer."); + } + mScratchMemoryBufferResetCounter = ScratchMemoryBufferLifetime; + } + + ASSERT(mScratchMemoryBuffer.size() >= requestedSize); + + *bufferOut = &mScratchMemoryBuffer; + return gl::Error(GL_NO_ERROR); +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/RendererD3D.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/RendererD3D.h new file mode 100644 index 0000000000..3de6c20886 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/RendererD3D.h @@ -0,0 +1,241 @@ + +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// RendererD3D.h: Defines a back-end specific class for the DirectX renderer. + +#ifndef LIBANGLE_RENDERER_D3D_RENDERERD3D_H_ +#define LIBANGLE_RENDERER_D3D_RENDERERD3D_H_ + +#include "common/MemoryBuffer.h" +#include "libANGLE/Data.h" +#include "libANGLE/renderer/Renderer.h" +#include "libANGLE/renderer/d3d/formatutilsD3D.h" +#include "libANGLE/renderer/d3d/d3d11/NativeWindow.h" + +//FIXME(jmadill): std::array is currently prohibited by Chromium style guide +#include + +namespace egl +{ +class ConfigSet; +} + +namespace gl +{ +class InfoLog; +struct LinkedVarying; +class Texture; +} + +namespace rx +{ +class ImageD3D; +class IndexBuffer; +class RenderTargetD3D; +class ShaderExecutableD3D; +class SwapChainD3D; +class TextureStorage; +class UniformStorageD3D; +class VertexBuffer; + +enum ShaderType +{ + SHADER_VERTEX, + SHADER_PIXEL, + SHADER_GEOMETRY +}; + +enum RendererClass +{ + RENDERER_D3D11, + RENDERER_D3D9, +}; + +// Useful for unit testing +class BufferFactoryD3D +{ + public: + BufferFactoryD3D() {} + virtual ~BufferFactoryD3D() {} + + virtual VertexBuffer *createVertexBuffer() = 0; + virtual IndexBuffer *createIndexBuffer() = 0; + + // TODO(jmadill): add VertexFormatCaps + virtual VertexConversionType getVertexConversionType(const gl::VertexFormat &vertexFormat) const = 0; + virtual GLenum getVertexComponentType(const gl::VertexFormat &vertexFormat) const = 0; +}; + +class RendererD3D : public Renderer, public BufferFactoryD3D +{ + public: + explicit RendererD3D(egl::Display *display); + virtual ~RendererD3D(); + + virtual egl::Error initialize() = 0; + + static RendererD3D *makeRendererD3D(Renderer *renderer); + + virtual egl::ConfigSet generateConfigs() const = 0; + + gl::Error drawArrays(const gl::Data &data, + GLenum mode, GLint first, + GLsizei count, GLsizei instances) override; + + gl::Error drawElements(const gl::Data &data, + GLenum mode, GLsizei count, GLenum type, + const GLvoid *indices, GLsizei instances, + const RangeUI &indexRange) override; + + bool isDeviceLost() const override; + std::string getVendorString() const override; + + virtual int getMinorShaderModel() const = 0; + virtual std::string getShaderModelSuffix() const = 0; + + // Direct3D Specific methods + virtual GUID getAdapterIdentifier() const = 0; + + virtual SwapChainD3D *createSwapChain(NativeWindow nativeWindow, HANDLE shareHandle, GLenum backBufferFormat, GLenum depthBufferFormat) = 0; + + virtual gl::Error generateSwizzle(gl::Texture *texture) = 0; + virtual gl::Error setSamplerState(gl::SamplerType type, int index, gl::Texture *texture, const gl::SamplerState &sampler) = 0; + virtual gl::Error setTexture(gl::SamplerType type, int index, gl::Texture *texture) = 0; + + virtual gl::Error setUniformBuffers(const gl::Data &data, + const GLint vertexUniformBuffers[], + const GLint fragmentUniformBuffers[]) = 0; + + virtual gl::Error setRasterizerState(const gl::RasterizerState &rasterState) = 0; + virtual gl::Error setBlendState(const gl::Framebuffer *framebuffer, const gl::BlendState &blendState, const gl::ColorF &blendColor, + unsigned int sampleMask) = 0; + virtual gl::Error setDepthStencilState(const gl::DepthStencilState &depthStencilState, int stencilRef, + int stencilBackRef, bool frontFaceCCW) = 0; + + virtual void setScissorRectangle(const gl::Rectangle &scissor, bool enabled) = 0; + virtual void setViewport(const gl::Rectangle &viewport, float zNear, float zFar, GLenum drawMode, GLenum frontFace, + bool ignoreViewport) = 0; + + virtual gl::Error applyRenderTarget(const gl::Framebuffer *frameBuffer) = 0; + virtual gl::Error applyShaders(gl::Program *program, const gl::VertexFormat inputLayout[], const gl::Framebuffer *framebuffer, + bool rasterizerDiscard, bool transformFeedbackActive) = 0; + virtual gl::Error applyUniforms(const ProgramImpl &program, const std::vector &uniformArray) = 0; + virtual bool applyPrimitiveType(GLenum primitiveType, GLsizei elementCount, bool usesPointSize) = 0; + virtual gl::Error applyVertexBuffer(const gl::State &state, GLenum mode, GLint first, GLsizei count, GLsizei instances) = 0; + virtual gl::Error applyIndexBuffer(const GLvoid *indices, gl::Buffer *elementArrayBuffer, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo) = 0; + virtual void applyTransformFeedbackBuffers(const gl::State& state) = 0; + + virtual void markAllStateDirty() = 0; + + virtual unsigned int getReservedVertexUniformVectors() const = 0; + virtual unsigned int getReservedFragmentUniformVectors() const = 0; + virtual unsigned int getReservedVertexUniformBuffers() const = 0; + virtual unsigned int getReservedFragmentUniformBuffers() const = 0; + virtual bool getShareHandleSupport() const = 0; + virtual bool getPostSubBufferSupport() const = 0; + + virtual int getMajorShaderModel() const = 0; + + // Pixel operations + virtual gl::Error copyImage2D(const gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, + const gl::Offset &destOffset, TextureStorage *storage, GLint level) = 0; + virtual gl::Error copyImageCube(const gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, + const gl::Offset &destOffset, TextureStorage *storage, GLenum target, GLint level) = 0; + virtual gl::Error copyImage3D(const gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, + const gl::Offset &destOffset, TextureStorage *storage, GLint level) = 0; + virtual gl::Error copyImage2DArray(const gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, + const gl::Offset &destOffset, TextureStorage *storage, GLint level) = 0; + + // RenderTarget creation + virtual gl::Error createRenderTarget(int width, int height, GLenum format, GLsizei samples, RenderTargetD3D **outRT) = 0; + + // Shader operations + virtual gl::Error loadExecutable(const void *function, size_t length, ShaderType type, + const std::vector &transformFeedbackVaryings, + bool separatedOutputBuffers, ShaderExecutableD3D **outExecutable) = 0; + virtual gl::Error compileToExecutable(gl::InfoLog &infoLog, const std::string &shaderHLSL, ShaderType type, + const std::vector &transformFeedbackVaryings, + bool separatedOutputBuffers, const D3DCompilerWorkarounds &workarounds, + ShaderExecutableD3D **outExectuable) = 0; + virtual UniformStorageD3D *createUniformStorage(size_t storageSize) = 0; + + // Image operations + virtual ImageD3D *createImage() = 0; + virtual gl::Error generateMipmap(ImageD3D *dest, ImageD3D *source) = 0; + virtual TextureStorage *createTextureStorage2D(SwapChainD3D *swapChain) = 0; + virtual TextureStorage *createTextureStorage2D(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels, bool hintLevelZeroOnly) = 0; + virtual TextureStorage *createTextureStorageCube(GLenum internalformat, bool renderTarget, int size, int levels, bool hintLevelZeroOnly) = 0; + virtual TextureStorage *createTextureStorage3D(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth, int levels) = 0; + virtual TextureStorage *createTextureStorage2DArray(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth, int levels) = 0; + + // Buffer-to-texture and Texture-to-buffer copies + virtual bool supportsFastCopyBufferToTexture(GLenum internalFormat) const = 0; + virtual gl::Error fastCopyBufferToTexture(const gl::PixelUnpackState &unpack, unsigned int offset, RenderTargetD3D *destRenderTarget, + GLenum destinationFormat, GLenum sourcePixelsType, const gl::Box &destArea) = 0; + + // Device lost + void notifyDeviceLost() override; + virtual bool resetDevice() = 0; + + virtual RendererClass getRendererClass() const = 0; + + gl::Error getScratchMemoryBuffer(size_t requestedSize, MemoryBuffer **bufferOut); + + protected: + virtual gl::Error drawArrays(const gl::Data &data, GLenum mode, GLsizei count, GLsizei instances, bool usesPointSize) = 0; + virtual gl::Error drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, + gl::Buffer *elementArrayBuffer, const TranslatedIndexData &indexInfo, GLsizei instances) = 0; + + virtual bool getLUID(LUID *adapterLuid) const = 0; + + void cleanup(); + + egl::Display *mDisplay; + bool mDeviceLost; + + private: + //FIXME(jmadill): std::array is currently prohibited by Chromium style guide + typedef std::array FramebufferTextureSerialArray; + + gl::Error generateSwizzles(const gl::Data &data, gl::SamplerType type); + gl::Error generateSwizzles(const gl::Data &data); + + gl::Error applyRenderTarget(const gl::Data &data, GLenum drawMode, bool ignoreViewport); + gl::Error applyState(const gl::Data &data, GLenum drawMode); + gl::Error applyShaders(const gl::Data &data); + gl::Error applyTextures(const gl::Data &data, gl::SamplerType shaderType, + const FramebufferTextureSerialArray &framebufferSerials, size_t framebufferSerialCount); + gl::Error applyTextures(const gl::Data &data); + + bool skipDraw(const gl::Data &data, GLenum drawMode); + void markTransformFeedbackUsage(const gl::Data &data); + + size_t getBoundFramebufferTextureSerials(const gl::Data &data, + FramebufferTextureSerialArray *outSerialArray); + gl::Texture *getIncompleteTexture(GLenum type); + + gl::TextureMap mIncompleteTextures; + MemoryBuffer mScratchMemoryBuffer; + unsigned int mScratchMemoryBufferResetCounter; +}; + +struct dx_VertexConstants +{ + float depthRange[4]; + float viewAdjust[4]; + float viewCoords[4]; +}; + +struct dx_PixelConstants +{ + float depthRange[4]; + float viewCoords[4]; + float depthFront[4]; +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_RENDERERD3D_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/ShaderD3D.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/ShaderD3D.cpp new file mode 100644 index 0000000000..7d522a95d4 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/ShaderD3D.cpp @@ -0,0 +1,388 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// ShaderD3D.cpp: Defines the rx::ShaderD3D class which implements rx::ShaderImpl. + +#include "libANGLE/Shader.h" +#include "libANGLE/Compiler.h" +#include "libANGLE/renderer/d3d/RendererD3D.h" +#include "libANGLE/renderer/d3d/ShaderD3D.h" +#include "libANGLE/renderer/d3d/CompilerD3D.h" +#include "libANGLE/features.h" + +#include "common/utilities.h" + +// Definitions local to the translation unit +namespace +{ + +const char *GetShaderTypeString(GLenum type) +{ + switch (type) + { + case GL_VERTEX_SHADER: + return "VERTEX"; + + case GL_FRAGMENT_SHADER: + return "FRAGMENT"; + + default: + UNREACHABLE(); + return ""; + } +} + +} + +namespace rx +{ + +template +void FilterInactiveVariables(std::vector *variableList) +{ + ASSERT(variableList); + + for (size_t varIndex = 0; varIndex < variableList->size();) + { + if (!(*variableList)[varIndex].staticUse) + { + variableList->erase(variableList->begin() + varIndex); + } + else + { + varIndex++; + } + } +} + +template +const std::vector *GetShaderVariables(const std::vector *variableList) +{ + ASSERT(variableList); + return variableList; +} + +ShaderD3D::ShaderD3D(GLenum type) + : mShaderType(type), + mShaderVersion(100) +{ + uncompile(); +} + +ShaderD3D::~ShaderD3D() +{ +} + +ShaderD3D *ShaderD3D::makeShaderD3D(ShaderImpl *impl) +{ + ASSERT(HAS_DYNAMIC_TYPE(ShaderD3D*, impl)); + return static_cast(impl); +} + +const ShaderD3D *ShaderD3D::makeShaderD3D(const ShaderImpl *impl) +{ + ASSERT(HAS_DYNAMIC_TYPE(const ShaderD3D*, impl)); + return static_cast(impl); +} + +std::string ShaderD3D::getDebugInfo() const +{ + return mDebugInfo + std::string("\n// ") + GetShaderTypeString(mShaderType) + " SHADER END\n"; +} + + +void ShaderD3D::parseVaryings(ShHandle compiler) +{ + if (!mTranslatedSource.empty()) + { + const std::vector *varyings = ShGetVaryings(compiler); + ASSERT(varyings); + + for (size_t varyingIndex = 0; varyingIndex < varyings->size(); varyingIndex++) + { + mVaryings.push_back(gl::PackedVarying((*varyings)[varyingIndex])); + } + + mUsesMultipleRenderTargets = mTranslatedSource.find("GL_USES_MRT") != std::string::npos; + mUsesFragColor = mTranslatedSource.find("GL_USES_FRAG_COLOR") != std::string::npos; + mUsesFragData = mTranslatedSource.find("GL_USES_FRAG_DATA") != std::string::npos; + mUsesFragCoord = mTranslatedSource.find("GL_USES_FRAG_COORD") != std::string::npos; + mUsesFrontFacing = mTranslatedSource.find("GL_USES_FRONT_FACING") != std::string::npos; + mUsesPointSize = mTranslatedSource.find("GL_USES_POINT_SIZE") != std::string::npos; + mUsesPointCoord = mTranslatedSource.find("GL_USES_POINT_COORD") != std::string::npos; + mUsesDepthRange = mTranslatedSource.find("GL_USES_DEPTH_RANGE") != std::string::npos; + mUsesFragDepth = mTranslatedSource.find("GL_USES_FRAG_DEPTH") != std::string::npos; + mUsesDiscardRewriting = mTranslatedSource.find("ANGLE_USES_DISCARD_REWRITING") != std::string::npos; + mUsesNestedBreak = mTranslatedSource.find("ANGLE_USES_NESTED_BREAK") != std::string::npos; + mUsesDeferredInit = mTranslatedSource.find("ANGLE_USES_DEFERRED_INIT") != std::string::npos; + mRequiresIEEEStrictCompiling = mTranslatedSource.find("ANGLE_REQUIRES_IEEE_STRICT_COMPILING") != std::string::npos; + } +} + +void ShaderD3D::resetVaryingsRegisterAssignment() +{ + for (size_t varyingIndex = 0; varyingIndex < mVaryings.size(); varyingIndex++) + { + mVaryings[varyingIndex].resetRegisterAssignment(); + } +} + +// initialize/clean up previous state +void ShaderD3D::uncompile() +{ + // set by compileToHLSL + mCompilerOutputType = SH_ESSL_OUTPUT; + mTranslatedSource.clear(); + mInfoLog.clear(); + + mUsesMultipleRenderTargets = false; + mUsesFragColor = false; + mUsesFragData = false; + mUsesFragCoord = false; + mUsesFrontFacing = false; + mUsesPointSize = false; + mUsesPointCoord = false; + mUsesDepthRange = false; + mUsesFragDepth = false; + mShaderVersion = 100; + mUsesDiscardRewriting = false; + mUsesNestedBreak = false; + mUsesDeferredInit = false; + mRequiresIEEEStrictCompiling = false; + + mVaryings.clear(); + mUniforms.clear(); + mInterfaceBlocks.clear(); + mActiveAttributes.clear(); + mActiveOutputVariables.clear(); + mDebugInfo.clear(); +} + +void ShaderD3D::compileToHLSL(ShHandle compiler, const std::string &source) +{ + int compileOptions = (SH_OBJECT_CODE | SH_VARIABLES); + std::string sourcePath; + +#if !defined (ANGLE_ENABLE_WINDOWS_STORE) + if (gl::DebugAnnotationsActive()) + { + sourcePath = getTempPath(); + writeFile(sourcePath.c_str(), source.c_str(), source.length()); + compileOptions |= SH_LINE_DIRECTIVES; + } +#endif + + int result; + if (sourcePath.empty()) + { + const char* sourceStrings[] = + { + source.c_str(), + }; + + result = ShCompile(compiler, sourceStrings, ArraySize(sourceStrings), compileOptions); + } + else + { + const char* sourceStrings[] = + { + sourcePath.c_str(), + source.c_str(), + }; + + result = ShCompile(compiler, sourceStrings, ArraySize(sourceStrings), compileOptions | SH_SOURCE_PATH); + } + + mShaderVersion = ShGetShaderVersion(compiler); + + if (result) + { + mTranslatedSource = ShGetObjectCode(compiler); + +#ifdef _DEBUG + // Prefix hlsl shader with commented out glsl shader + // Useful in diagnostics tools like pix which capture the hlsl shaders + std::ostringstream hlslStream; + hlslStream << "// GLSL\n"; + hlslStream << "//\n"; + + size_t curPos = 0; + while (curPos != std::string::npos) + { + size_t nextLine = source.find("\n", curPos); + size_t len = (nextLine == std::string::npos) ? std::string::npos : (nextLine - curPos + 1); + + hlslStream << "// " << source.substr(curPos, len); + + curPos = (nextLine == std::string::npos) ? std::string::npos : (nextLine + 1); + } + hlslStream << "\n\n"; + hlslStream << mTranslatedSource; + mTranslatedSource = hlslStream.str(); +#endif + + mUniforms = *GetShaderVariables(ShGetUniforms(compiler)); + + for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++) + { + const sh::Uniform &uniform = mUniforms[uniformIndex]; + + if (uniform.staticUse) + { + unsigned int index = static_cast(-1); + bool getUniformRegisterResult = ShGetUniformRegister(compiler, uniform.name, &index); + UNUSED_ASSERTION_VARIABLE(getUniformRegisterResult); + ASSERT(getUniformRegisterResult); + + mUniformRegisterMap[uniform.name] = index; + } + } + + mInterfaceBlocks = *GetShaderVariables(ShGetInterfaceBlocks(compiler)); + + for (size_t blockIndex = 0; blockIndex < mInterfaceBlocks.size(); blockIndex++) + { + const sh::InterfaceBlock &interfaceBlock = mInterfaceBlocks[blockIndex]; + + if (interfaceBlock.staticUse) + { + unsigned int index = static_cast(-1); + bool blockRegisterResult = ShGetInterfaceBlockRegister(compiler, interfaceBlock.name, &index); + UNUSED_ASSERTION_VARIABLE(blockRegisterResult); + ASSERT(blockRegisterResult); + + mInterfaceBlockRegisterMap[interfaceBlock.name] = index; + } + } + } + else + { + mInfoLog = ShGetInfoLog(compiler); + + TRACE("\n%s", mInfoLog.c_str()); + } +} + +void ShaderD3D::generateWorkarounds(D3DCompilerWorkarounds *workarounds) const +{ + if (mUsesDiscardRewriting) + { + // ANGLE issue 486: + // Work-around a D3D9 compiler bug that presents itself when using conditional discard, by disabling optimization + workarounds->skipOptimization = true; + } + else if (mUsesNestedBreak) + { + // ANGLE issue 603: + // Work-around a D3D9 compiler bug that presents itself when using break in a nested loop, by maximizing optimization + // We want to keep the use of ANGLE_D3D_WORKAROUND_MAX_OPTIMIZATION minimal to prevent hangs, so usesDiscard takes precedence + workarounds->useMaxOptimization = true; + } + + if (mRequiresIEEEStrictCompiling) + { + // IEEE Strictness for D3D compiler needs to be enabled for NaNs to work. + workarounds->enableIEEEStrictness = true; + } +} + +// true if varying x has a higher priority in packing than y +bool ShaderD3D::compareVarying(const gl::PackedVarying &x, const gl::PackedVarying &y) +{ + if (x.type == y.type) + { + return x.arraySize > y.arraySize; + } + + // Special case for handling structs: we sort these to the end of the list + if (x.type == GL_STRUCT_ANGLEX) + { + return false; + } + + if (y.type == GL_STRUCT_ANGLEX) + { + return true; + } + + return gl::VariableSortOrder(x.type) < gl::VariableSortOrder(y.type); +} + +unsigned int ShaderD3D::getUniformRegister(const std::string &uniformName) const +{ + ASSERT(mUniformRegisterMap.count(uniformName) > 0); + return mUniformRegisterMap.find(uniformName)->second; +} + +unsigned int ShaderD3D::getInterfaceBlockRegister(const std::string &blockName) const +{ + ASSERT(mInterfaceBlockRegisterMap.count(blockName) > 0); + return mInterfaceBlockRegisterMap.find(blockName)->second; +} + +GLenum ShaderD3D::getShaderType() const +{ + return mShaderType; +} + +ShShaderOutput ShaderD3D::getCompilerOutputType() const +{ + return mCompilerOutputType; +} + +bool ShaderD3D::compile(gl::Compiler *compiler, const std::string &source) +{ + uncompile(); + + CompilerD3D *compilerD3D = CompilerD3D::makeCompilerD3D(compiler->getImplementation()); + ShHandle compilerHandle = compilerD3D->getCompilerHandle(mShaderType); + + mCompilerOutputType = ShGetShaderOutputType(compilerHandle); + + compileToHLSL(compilerHandle, source); + + if (mShaderType == GL_VERTEX_SHADER) + { + parseAttributes(compilerHandle); + } + + parseVaryings(compilerHandle); + + if (mShaderType == GL_FRAGMENT_SHADER) + { + std::sort(mVaryings.begin(), mVaryings.end(), compareVarying); + + const std::string &hlsl = getTranslatedSource(); + if (!hlsl.empty()) + { + mActiveOutputVariables = *GetShaderVariables(ShGetOutputVariables(compilerHandle)); + FilterInactiveVariables(&mActiveOutputVariables); + } + } + +#if ANGLE_SHADER_DEBUG_INFO == ANGLE_ENABLED + mDebugInfo += std::string("// ") + GetShaderTypeString(mShaderType) + " SHADER BEGIN\n"; + mDebugInfo += "\n// GLSL BEGIN\n\n" + source + "\n\n// GLSL END\n\n\n"; + mDebugInfo += "// INITIAL HLSL BEGIN\n\n" + getTranslatedSource() + "\n// INITIAL HLSL END\n\n\n"; + // Successive steps will append more info +#else + mDebugInfo += getTranslatedSource(); +#endif + + return !getTranslatedSource().empty(); +} + +void ShaderD3D::parseAttributes(ShHandle compiler) +{ + const std::string &hlsl = getTranslatedSource(); + if (!hlsl.empty()) + { + mActiveAttributes = *GetShaderVariables(ShGetAttributes(compiler)); + FilterInactiveVariables(&mActiveAttributes); + } +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/ShaderD3D.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/ShaderD3D.h new file mode 100644 index 0000000000..d0237b5985 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/ShaderD3D.h @@ -0,0 +1,89 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// ShaderD3D.h: Defines the rx::ShaderD3D class which implements rx::ShaderImpl. + +#ifndef LIBANGLE_RENDERER_D3D_SHADERD3D_H_ +#define LIBANGLE_RENDERER_D3D_SHADERD3D_H_ + +#include "libANGLE/renderer/ShaderImpl.h" +#include "libANGLE/renderer/Workarounds.h" +#include "libANGLE/Shader.h" + +#include + +namespace rx +{ +class DynamicHLSL; +class RendererD3D; + +class ShaderD3D : public ShaderImpl +{ + friend class DynamicHLSL; + + public: + ShaderD3D(GLenum type); + virtual ~ShaderD3D(); + + static ShaderD3D *makeShaderD3D(ShaderImpl *impl); + static const ShaderD3D *makeShaderD3D(const ShaderImpl *impl); + + // ShaderImpl implementation + virtual std::string getDebugInfo() const; + + // D3D-specific methods + virtual void uncompile(); + void resetVaryingsRegisterAssignment(); + unsigned int getUniformRegister(const std::string &uniformName) const; + unsigned int getInterfaceBlockRegister(const std::string &blockName) const; + void appendDebugInfo(const std::string &info) { mDebugInfo += info; } + + void generateWorkarounds(D3DCompilerWorkarounds *workarounds) const; + int getShaderVersion() const { return mShaderVersion; } + bool usesDepthRange() const { return mUsesDepthRange; } + bool usesPointSize() const { return mUsesPointSize; } + bool usesDeferredInit() const { return mUsesDeferredInit; } + + GLenum getShaderType() const; + ShShaderOutput getCompilerOutputType() const; + + virtual bool compile(gl::Compiler *compiler, const std::string &source); + + private: + void compileToHLSL(ShHandle compiler, const std::string &source); + void parseVaryings(ShHandle compiler); + + void parseAttributes(ShHandle compiler); + + static bool compareVarying(const gl::PackedVarying &x, const gl::PackedVarying &y); + + GLenum mShaderType; + + int mShaderVersion; + + bool mUsesMultipleRenderTargets; + bool mUsesFragColor; + bool mUsesFragData; + bool mUsesFragCoord; + bool mUsesFrontFacing; + bool mUsesPointSize; + bool mUsesPointCoord; + bool mUsesDepthRange; + bool mUsesFragDepth; + bool mUsesDiscardRewriting; + bool mUsesNestedBreak; + bool mUsesDeferredInit; + bool mRequiresIEEEStrictCompiling; + + ShShaderOutput mCompilerOutputType; + std::string mDebugInfo; + std::map mUniformRegisterMap; + std::map mInterfaceBlockRegisterMap; +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_SHADERD3D_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/ShaderExecutableD3D.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/ShaderExecutableD3D.cpp new file mode 100644 index 0000000000..97ffdf5094 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/ShaderExecutableD3D.cpp @@ -0,0 +1,61 @@ +// +// Copyright (c) 2012-2015 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// ShaderExecutable.cpp: Implements a class to contain D3D shader executable +// implementation details. + +#include "libANGLE/renderer/d3d/ShaderExecutableD3D.h" + +#include "common/angleutils.h" + +namespace rx +{ + +ShaderExecutableD3D::ShaderExecutableD3D(const void *function, size_t length) + : mFunctionBuffer(length) +{ + memcpy(mFunctionBuffer.data(), function, length); +} + +ShaderExecutableD3D::~ShaderExecutableD3D() +{ +} + +const uint8_t *ShaderExecutableD3D::getFunction() const +{ + return mFunctionBuffer.data(); +} + +size_t ShaderExecutableD3D::getLength() const +{ + return mFunctionBuffer.size(); +} + +const std::string &ShaderExecutableD3D::getDebugInfo() const +{ + return mDebugInfo; +} + +void ShaderExecutableD3D::appendDebugInfo(const std::string &info) +{ + mDebugInfo += info; +} + + +UniformStorageD3D::UniformStorageD3D(size_t initialSize) : mSize(initialSize) +{ +} + +UniformStorageD3D::~UniformStorageD3D() +{ +} + +size_t UniformStorageD3D::size() const +{ + return mSize; +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/ShaderExecutableD3D.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/ShaderExecutableD3D.h new file mode 100644 index 0000000000..71b83b7954 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/ShaderExecutableD3D.h @@ -0,0 +1,54 @@ +// +// Copyright (c) 2012-2015 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// ShaderExecutable.h: Defines a class to contain D3D shader executable +// implementation details. + +#ifndef LIBANGLE_RENDERER_D3D_SHADEREXECUTABLED3D_H_ +#define LIBANGLE_RENDERER_D3D_SHADEREXECUTABLED3D_H_ + +#include "common/debug.h" + +#include +#include + +namespace rx +{ + +class ShaderExecutableD3D : angle::NonCopyable +{ + public: + ShaderExecutableD3D(const void *function, size_t length); + virtual ~ShaderExecutableD3D(); + + const uint8_t *getFunction() const; + + size_t getLength() const; + + const std::string &getDebugInfo() const; + + void appendDebugInfo(const std::string &info); + + private: + std::vector mFunctionBuffer; + std::string mDebugInfo; +}; + +class UniformStorageD3D : angle::NonCopyable +{ + public: + UniformStorageD3D(size_t initialSize); + virtual ~UniformStorageD3D(); + + size_t size() const; + + private: + size_t mSize; +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_SHADEREXECUTABLED3D_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/SurfaceD3D.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/SurfaceD3D.cpp new file mode 100644 index 0000000000..4fde295443 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/SurfaceD3D.cpp @@ -0,0 +1,396 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// SurfaceD3D.cpp: D3D implementation of an EGL surface + +#include "libANGLE/renderer/d3d/SurfaceD3D.h" + +#include "libANGLE/Display.h" +#include "libANGLE/Surface.h" +#include "libANGLE/renderer/d3d/RendererD3D.h" +#include "libANGLE/renderer/d3d/SwapChainD3D.h" + +#include +#include +#include + +namespace rx +{ + +SurfaceD3D *SurfaceD3D::createOffscreen(RendererD3D *renderer, egl::Display *display, const egl::Config *config, EGLClientBuffer shareHandle, + EGLint width, EGLint height) +{ + return new SurfaceD3D(renderer, display, config, width, height, EGL_TRUE, shareHandle, NULL); +} + +SurfaceD3D *SurfaceD3D::createFromWindow(RendererD3D *renderer, egl::Display *display, const egl::Config *config, EGLNativeWindowType window, + EGLint fixedSize, EGLint width, EGLint height) +{ + return new SurfaceD3D(renderer, display, config, width, height, fixedSize, static_cast(0), window); +} + +SurfaceD3D::SurfaceD3D(RendererD3D *renderer, egl::Display *display, const egl::Config *config, EGLint width, EGLint height, EGLint fixedSize, + EGLClientBuffer shareHandle, EGLNativeWindowType window) + : SurfaceImpl(), + mRenderer(renderer), + mDisplay(display), + mFixedSize(fixedSize == EGL_TRUE), + mRenderTargetFormat(config->renderTargetFormat), + mDepthStencilFormat(config->depthStencilFormat), + mSwapChain(nullptr), + mSwapIntervalDirty(true), + mWindowSubclassed(false), + mNativeWindow(window), + mWidth(width), + mHeight(height), + mSwapInterval(1), + mShareHandle(reinterpret_cast(shareHandle)) +{ + subclassWindow(); +} + +SurfaceD3D::~SurfaceD3D() +{ + unsubclassWindow(); + releaseSwapChain(); +} + +void SurfaceD3D::releaseSwapChain() +{ + SafeDelete(mSwapChain); +} + +egl::Error SurfaceD3D::initialize() +{ + if (mNativeWindow.getNativeWindow()) + { + if (!mNativeWindow.initialize()) + { + return egl::Error(EGL_BAD_SURFACE); + } + } + + egl::Error error = resetSwapChain(); + if (error.isError()) + { + return error; + } + + return egl::Error(EGL_SUCCESS); +} + +egl::Error SurfaceD3D::bindTexImage(EGLint) +{ + return egl::Error(EGL_SUCCESS); +} + +egl::Error SurfaceD3D::releaseTexImage(EGLint) +{ + return egl::Error(EGL_SUCCESS); +} + +egl::Error SurfaceD3D::resetSwapChain() +{ + ASSERT(!mSwapChain); + + int width; + int height; + + if (!mFixedSize) + { + RECT windowRect; + if (!mNativeWindow.getClientRect(&windowRect)) + { + ASSERT(false); + + return egl::Error(EGL_BAD_SURFACE, "Could not retrieve the window dimensions"); + } + + width = windowRect.right - windowRect.left; + height = windowRect.bottom - windowRect.top; + } + else + { + // non-window surface - size is determined at creation + width = mWidth; + height = mHeight; + } + + mSwapChain = mRenderer->createSwapChain(mNativeWindow, mShareHandle, mRenderTargetFormat, mDepthStencilFormat); + if (!mSwapChain) + { + return egl::Error(EGL_BAD_ALLOC); + } + + egl::Error error = resetSwapChain(width, height); + if (error.isError()) + { + SafeDelete(mSwapChain); + return error; + } + + return egl::Error(EGL_SUCCESS); +} + +egl::Error SurfaceD3D::resizeSwapChain(int backbufferWidth, int backbufferHeight) +{ + ASSERT(backbufferWidth >= 0 && backbufferHeight >= 0); + ASSERT(mSwapChain); + + EGLint status = mSwapChain->resize(std::max(1, backbufferWidth), std::max(1, backbufferHeight)); + + if (status == EGL_CONTEXT_LOST) + { + mDisplay->notifyDeviceLost(); + return egl::Error(status); + } + else if (status != EGL_SUCCESS) + { + return egl::Error(status); + } + + mWidth = backbufferWidth; + mHeight = backbufferHeight; + + return egl::Error(EGL_SUCCESS); +} + +egl::Error SurfaceD3D::resetSwapChain(int backbufferWidth, int backbufferHeight) +{ + ASSERT(backbufferWidth >= 0 && backbufferHeight >= 0); + ASSERT(mSwapChain); + + EGLint status = mSwapChain->reset(std::max(1, backbufferWidth), std::max(1, backbufferHeight), mSwapInterval); + + if (status == EGL_CONTEXT_LOST) + { + mRenderer->notifyDeviceLost(); + return egl::Error(status); + } + else if (status != EGL_SUCCESS) + { + return egl::Error(status); + } + + mWidth = backbufferWidth; + mHeight = backbufferHeight; + mSwapIntervalDirty = false; + + return egl::Error(EGL_SUCCESS); +} + +egl::Error SurfaceD3D::swapRect(EGLint x, EGLint y, EGLint width, EGLint height) +{ + if (!mSwapChain) + { + return egl::Error(EGL_SUCCESS); + } + + if (x + width > mWidth) + { + width = mWidth - x; + } + + if (y + height > mHeight) + { + height = mHeight - y; + } + + if (width == 0 || height == 0) + { + return egl::Error(EGL_SUCCESS); + } + + EGLint status = mSwapChain->swapRect(x, y, width, height); + + if (status == EGL_CONTEXT_LOST) + { + mRenderer->notifyDeviceLost(); + return egl::Error(status); + } + else if (status != EGL_SUCCESS) + { + return egl::Error(status); + } + + checkForOutOfDateSwapChain(); + + return egl::Error(EGL_SUCCESS); +} + +#if !defined(ANGLE_ENABLE_WINDOWS_STORE) +#define kSurfaceProperty _TEXT("Egl::SurfaceOwner") +#define kParentWndProc _TEXT("Egl::SurfaceParentWndProc") + +static LRESULT CALLBACK SurfaceWindowProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) +{ + if (message == WM_SIZE) + { + SurfaceD3D* surf = reinterpret_cast(GetProp(hwnd, kSurfaceProperty)); + if(surf) + { + surf->checkForOutOfDateSwapChain(); + } + } + WNDPROC prevWndFunc = reinterpret_cast(GetProp(hwnd, kParentWndProc)); + return CallWindowProc(prevWndFunc, hwnd, message, wparam, lparam); +} +#endif + +void SurfaceD3D::subclassWindow() +{ +#if !defined(ANGLE_ENABLE_WINDOWS_STORE) + HWND window = mNativeWindow.getNativeWindow(); + if (!window) + { + return; + } + + DWORD processId; + DWORD threadId = GetWindowThreadProcessId(window, &processId); + if (processId != GetCurrentProcessId() || threadId != GetCurrentThreadId()) + { + return; + } + + SetLastError(0); + LONG_PTR oldWndProc = SetWindowLongPtr(window, GWLP_WNDPROC, reinterpret_cast(SurfaceWindowProc)); + if(oldWndProc == 0 && GetLastError() != ERROR_SUCCESS) + { + mWindowSubclassed = false; + return; + } + + SetProp(window, kSurfaceProperty, reinterpret_cast(this)); + SetProp(window, kParentWndProc, reinterpret_cast(oldWndProc)); + mWindowSubclassed = true; +#endif +} + +void SurfaceD3D::unsubclassWindow() +{ + if (!mWindowSubclassed) + { + return; + } + +#if !defined(ANGLE_ENABLE_WINDOWS_STORE) + HWND window = mNativeWindow.getNativeWindow(); + if (!window) + { + return; + } + + // un-subclass + LONG_PTR parentWndFunc = reinterpret_cast(GetProp(window, kParentWndProc)); + + // Check the windowproc is still SurfaceWindowProc. + // If this assert fails, then it is likely the application has subclassed the + // hwnd as well and did not unsubclass before destroying its EGL context. The + // application should be modified to either subclass before initializing the + // EGL context, or to unsubclass before destroying the EGL context. + if(parentWndFunc) + { + LONG_PTR prevWndFunc = SetWindowLongPtr(window, GWLP_WNDPROC, parentWndFunc); + UNUSED_ASSERTION_VARIABLE(prevWndFunc); + ASSERT(prevWndFunc == reinterpret_cast(SurfaceWindowProc)); + } + + RemoveProp(window, kSurfaceProperty); + RemoveProp(window, kParentWndProc); +#endif + mWindowSubclassed = false; +} + +bool SurfaceD3D::checkForOutOfDateSwapChain() +{ + RECT client; + int clientWidth = getWidth(); + int clientHeight = getHeight(); + bool sizeDirty = false; + if (!mFixedSize && !mNativeWindow.isIconic()) + { + // The window is automatically resized to 150x22 when it's minimized, but the swapchain shouldn't be resized + // because that's not a useful size to render to. + if (!mNativeWindow.getClientRect(&client)) + { + ASSERT(false); + return false; + } + + // Grow the buffer now, if the window has grown. We need to grow now to avoid losing information. + clientWidth = client.right - client.left; + clientHeight = client.bottom - client.top; + sizeDirty = clientWidth != getWidth() || clientHeight != getHeight(); + } + + bool wasDirty = (mSwapIntervalDirty || sizeDirty); + + if (mSwapIntervalDirty) + { + resetSwapChain(clientWidth, clientHeight); + } + else if (sizeDirty) + { + resizeSwapChain(clientWidth, clientHeight); + } + + return wasDirty; +} + +egl::Error SurfaceD3D::swap() +{ + return swapRect(0, 0, mWidth, mHeight); +} + +egl::Error SurfaceD3D::postSubBuffer(EGLint x, EGLint y, EGLint width, EGLint height) +{ + return swapRect(x, y, width, height); +} + +rx::SwapChainD3D *SurfaceD3D::getSwapChain() const +{ + return mSwapChain; +} + +void SurfaceD3D::setSwapInterval(EGLint interval) +{ + if (mSwapInterval == interval) + { + return; + } + + mSwapInterval = interval; + mSwapIntervalDirty = true; +} + +EGLint SurfaceD3D::getWidth() const +{ + return mWidth; +} + +EGLint SurfaceD3D::getHeight() const +{ + return mHeight; +} + +EGLint SurfaceD3D::isPostSubBufferSupported() const +{ + // post sub buffer is always possible on D3D surfaces + return EGL_TRUE; +} + +egl::Error SurfaceD3D::querySurfacePointerANGLE(EGLint attribute, void **value) +{ + ASSERT(attribute == EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE || attribute == EGL_DEVICE_EXT); + if (attribute == EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE) + *value = mSwapChain->getShareHandle(); + else if (attribute == EGL_DEVICE_EXT) + *value = mSwapChain->getDevice(); + return egl::Error(EGL_SUCCESS); +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/SurfaceD3D.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/SurfaceD3D.h new file mode 100644 index 0000000000..070b7cdbc4 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/SurfaceD3D.h @@ -0,0 +1,92 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// SurfaceD3D.h: D3D implementation of an EGL surface + +#ifndef LIBANGLE_RENDERER_D3D_SURFACED3D_H_ +#define LIBANGLE_RENDERER_D3D_SURFACED3D_H_ + +#include "libANGLE/renderer/SurfaceImpl.h" +#include "libANGLE/renderer/d3d/d3d11/NativeWindow.h" + +namespace egl +{ +class Surface; +} + +namespace rx +{ +class SwapChainD3D; +class RendererD3D; + +class SurfaceD3D : public SurfaceImpl +{ + public: + static SurfaceD3D *createFromWindow(RendererD3D *renderer, egl::Display *display, const egl::Config *config, + EGLNativeWindowType window, EGLint fixedSize, EGLint width, EGLint height); + static SurfaceD3D *createOffscreen(RendererD3D *renderer, egl::Display *display, const egl::Config *config, + EGLClientBuffer shareHandle, EGLint width, EGLint height); + ~SurfaceD3D() override; + void releaseSwapChain(); + + egl::Error initialize() override; + + egl::Error swap() override; + egl::Error postSubBuffer(EGLint x, EGLint y, EGLint width, EGLint height) override; + egl::Error querySurfacePointerANGLE(EGLint attribute, void **value) override; + egl::Error bindTexImage(EGLint buffer) override; + egl::Error releaseTexImage(EGLint buffer) override; + void setSwapInterval(EGLint interval) override; + + EGLint getWidth() const override; + EGLint getHeight() const override; + + EGLint isPostSubBufferSupported() const override; + + // D3D implementations + SwapChainD3D *getSwapChain() const; + + egl::Error resetSwapChain(); + + // Returns true if swapchain changed due to resize or interval update + bool checkForOutOfDateSwapChain(); + + private: + SurfaceD3D(RendererD3D *renderer, egl::Display *display, const egl::Config *config, EGLint width, EGLint height, + EGLint fixedSize, EGLClientBuffer shareHandle, EGLNativeWindowType window); + + egl::Error swapRect(EGLint x, EGLint y, EGLint width, EGLint height); + egl::Error resetSwapChain(int backbufferWidth, int backbufferHeight); + egl::Error resizeSwapChain(int backbufferWidth, int backbufferHeight); + + void subclassWindow(); + void unsubclassWindow(); + + RendererD3D *mRenderer; + egl::Display *mDisplay; + + bool mFixedSize; + + GLenum mRenderTargetFormat; + GLenum mDepthStencilFormat; + + SwapChainD3D *mSwapChain; + bool mSwapIntervalDirty; + bool mWindowSubclassed; // Indicates whether we successfully subclassed mWindow for WM_RESIZE hooking + + NativeWindow mNativeWindow; // Handler for the Window that the surface is created for. + EGLint mWidth; + EGLint mHeight; + + EGLint mSwapInterval; + + HANDLE mShareHandle; +}; + + +} + +#endif // LIBANGLE_RENDERER_D3D_SURFACED3D_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/SwapChainD3D.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/SwapChainD3D.h new file mode 100644 index 0000000000..da36e52ea7 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/SwapChainD3D.h @@ -0,0 +1,63 @@ +// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// SwapChainD3D.h: Defines a back-end specific class that hides the details of the +// implementation-specific swapchain. + +#ifndef LIBANGLE_RENDERER_D3D_SWAPCHAIND3D_H_ +#define LIBANGLE_RENDERER_D3D_SWAPCHAIND3D_H_ + +#include +#include + +#include "common/angleutils.h" +#include "common/platform.h" + +// TODO: move out of D3D11 +#include "libANGLE/renderer/d3d/d3d11/NativeWindow.h" + +#if !defined(ANGLE_FORCE_VSYNC_OFF) +#define ANGLE_FORCE_VSYNC_OFF 0 +#endif + +namespace rx +{ +class RenderTargetD3D; + +class SwapChainD3D : angle::NonCopyable +{ + public: + SwapChainD3D(rx::NativeWindow nativeWindow, HANDLE shareHandle, GLenum backBufferFormat, GLenum depthBufferFormat) + : mNativeWindow(nativeWindow), mShareHandle(shareHandle), mBackBufferFormat(backBufferFormat), mDepthBufferFormat(depthBufferFormat) + { + } + + virtual ~SwapChainD3D() {}; + + virtual EGLint resize(EGLint backbufferWidth, EGLint backbufferSize) = 0; + virtual EGLint reset(EGLint backbufferWidth, EGLint backbufferHeight, EGLint swapInterval) = 0; + virtual EGLint swapRect(EGLint x, EGLint y, EGLint width, EGLint height) = 0; + virtual void recreate() = 0; + virtual void *getDevice() { return NULL; } + + virtual RenderTargetD3D *getColorRenderTarget() = 0; + virtual RenderTargetD3D *getDepthStencilRenderTarget() = 0; + + GLenum GetBackBufferInternalFormat() const { return mBackBufferFormat; } + GLenum GetDepthBufferInternalFormat() const { return mDepthBufferFormat; } + + HANDLE getShareHandle() { return mShareHandle; } + + protected: + rx::NativeWindow mNativeWindow; // Handler for the Window that the surface is created for. + const GLenum mBackBufferFormat; + const GLenum mDepthBufferFormat; + + HANDLE mShareHandle; +}; + +} +#endif // LIBANGLE_RENDERER_D3D_SWAPCHAIND3D_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/TextureD3D.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/TextureD3D.cpp new file mode 100644 index 0000000000..78b03f2283 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/TextureD3D.cpp @@ -0,0 +1,2916 @@ +// +// Copyright 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// TextureD3D.cpp: Implementations of the Texture interfaces shared betweeen the D3D backends. + +#include "libANGLE/renderer/d3d/TextureD3D.h" + +#include "common/mathutil.h" +#include "common/utilities.h" +#include "libANGLE/Buffer.h" +#include "libANGLE/Config.h" +#include "libANGLE/Framebuffer.h" +#include "libANGLE/Surface.h" +#include "libANGLE/Texture.h" +#include "libANGLE/formatutils.h" +#include "libANGLE/renderer/BufferImpl.h" +#include "libANGLE/renderer/d3d/BufferD3D.h" +#include "libANGLE/renderer/d3d/ImageD3D.h" +#include "libANGLE/renderer/d3d/RendererD3D.h" +#include "libANGLE/renderer/d3d/RenderTargetD3D.h" +#include "libANGLE/renderer/d3d/SurfaceD3D.h" +#include "libANGLE/renderer/d3d/TextureStorage.h" + +namespace rx +{ + +namespace +{ + +gl::Error GetUnpackPointer(const gl::PixelUnpackState &unpack, const uint8_t *pixels, + ptrdiff_t layerOffset, const uint8_t **pointerOut) +{ + if (unpack.pixelBuffer.id() != 0) + { + // Do a CPU readback here, if we have an unpack buffer bound and the fast GPU path is not supported + gl::Buffer *pixelBuffer = unpack.pixelBuffer.get(); + ptrdiff_t offset = reinterpret_cast(pixels); + + // TODO: this is the only place outside of renderer that asks for a buffers raw data. + // This functionality should be moved into renderer and the getData method of BufferImpl removed. + BufferD3D *bufferD3D = GetImplAs(pixelBuffer); + ASSERT(bufferD3D); + const uint8_t *bufferData = NULL; + gl::Error error = bufferD3D->getData(&bufferData); + if (error.isError()) + { + return error; + } + + *pointerOut = bufferData + offset; + } + else + { + *pointerOut = pixels; + } + + // Offset the pointer for 2D array layer (if it's valid) + if (*pointerOut != nullptr) + { + *pointerOut += layerOffset; + } + + return gl::Error(GL_NO_ERROR); +} + +bool IsRenderTargetUsage(GLenum usage) +{ + return (usage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE); +} + +} + +TextureD3D::TextureD3D(RendererD3D *renderer) + : mRenderer(renderer), + mUsage(GL_NONE), + mDirtyImages(true), + mImmutable(false), + mTexStorage(NULL) +{ +} + +TextureD3D::~TextureD3D() +{ +} + +gl::Error TextureD3D::getNativeTexture(TextureStorage **outStorage) +{ + // ensure the underlying texture is created + gl::Error error = initializeStorage(false); + if (error.isError()) + { + return error; + } + + if (mTexStorage) + { + error = updateStorage(); + if (error.isError()) + { + return error; + } + } + + ASSERT(outStorage); + + *outStorage = mTexStorage; + return gl::Error(GL_NO_ERROR); +} + +GLint TextureD3D::getBaseLevelWidth() const +{ + const ImageD3D *baseImage = getBaseLevelImage(); + return (baseImage ? baseImage->getWidth() : 0); +} + +GLint TextureD3D::getBaseLevelHeight() const +{ + const ImageD3D *baseImage = getBaseLevelImage(); + return (baseImage ? baseImage->getHeight() : 0); +} + +GLint TextureD3D::getBaseLevelDepth() const +{ + const ImageD3D *baseImage = getBaseLevelImage(); + return (baseImage ? baseImage->getDepth() : 0); +} + +// Note: "base level image" is loosely defined to be any image from the base level, +// where in the base of 2D array textures and cube maps there are several. Don't use +// the base level image for anything except querying texture format and size. +GLenum TextureD3D::getBaseLevelInternalFormat() const +{ + const ImageD3D *baseImage = getBaseLevelImage(); + return (baseImage ? baseImage->getInternalFormat() : GL_NONE); +} + +bool TextureD3D::shouldUseSetData(const ImageD3D *image) const +{ + if (!mRenderer->getWorkarounds().setDataFasterThanImageUpload) + { + return false; + } + + gl::InternalFormat internalFormat = gl::GetInternalFormatInfo(image->getInternalFormat()); + + // We can only handle full updates for depth-stencil textures, so to avoid complications + // disable them entirely. + if (internalFormat.depthBits > 0 || internalFormat.stencilBits > 0) + { + return false; + } + + // TODO(jmadill): Handle compressed internal formats + return (mTexStorage && !internalFormat.compressed); +} + +gl::Error TextureD3D::setImage(const gl::ImageIndex &index, GLenum type, + const gl::PixelUnpackState &unpack, const uint8_t *pixels, + ptrdiff_t layerOffset) +{ + if (unpack.skipRows != 0 || unpack.skipPixels != 0 || unpack.imageHeight != 0 || unpack.skipImages != 0) + { + UNIMPLEMENTED(); + return gl::Error(GL_INVALID_OPERATION, "unimplemented pixel store state"); + } + + ImageD3D *image = getImage(index); + ASSERT(image); + + // No-op + if (image->getWidth() == 0 || image->getHeight() == 0 || image->getDepth() == 0) + { + return gl::Error(GL_NO_ERROR); + } + + // We no longer need the "GLenum format" parameter to TexImage to determine what data format "pixels" contains. + // From our image internal format we know how many channels to expect, and "type" gives the format of pixel's components. + const uint8_t *pixelData = NULL; + gl::Error error = GetUnpackPointer(unpack, pixels, layerOffset, &pixelData); + if (error.isError()) + { + return error; + } + + if (pixelData != NULL) + { + if (shouldUseSetData(image)) + { + error = mTexStorage->setData(index, image, NULL, type, unpack, pixelData); + } + else + { + gl::Box fullImageArea(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth()); + error = image->loadData(fullImageArea, unpack, type, pixelData); + } + + if (error.isError()) + { + return error; + } + + mDirtyImages = true; + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureD3D::subImage(const gl::ImageIndex &index, const gl::Box &area, GLenum format, GLenum type, + const gl::PixelUnpackState &unpack, const uint8_t *pixels, ptrdiff_t layerOffset) +{ + // CPU readback & copy where direct GPU copy is not supported + const uint8_t *pixelData = NULL; + gl::Error error = GetUnpackPointer(unpack, pixels, layerOffset, &pixelData); + if (error.isError()) + { + return error; + } + + if (pixelData != NULL) + { + ImageD3D *image = getImage(index); + ASSERT(image); + + if (shouldUseSetData(image)) + { + return mTexStorage->setData(index, image, &area, type, unpack, pixelData); + } + + error = image->loadData(area, unpack, type, pixelData); + if (error.isError()) + { + return error; + } + + error = commitRegion(index, area); + if (error.isError()) + { + return error; + } + + mDirtyImages = true; + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureD3D::setCompressedImage(const gl::ImageIndex &index, const gl::PixelUnpackState &unpack, + const uint8_t *pixels, ptrdiff_t layerOffset) +{ + if (unpack.skipRows != 0 || unpack.skipPixels != 0 || unpack.imageHeight != 0 || unpack.skipImages != 0) + { + UNIMPLEMENTED(); + return gl::Error(GL_INVALID_OPERATION, "unimplemented pixel store state"); + } + + // We no longer need the "GLenum format" parameter to TexImage to determine what data format "pixels" contains. + // From our image internal format we know how many channels to expect, and "type" gives the format of pixel's components. + const uint8_t *pixelData = NULL; + gl::Error error = GetUnpackPointer(unpack, pixels, layerOffset, &pixelData); + if (error.isError()) + { + return error; + } + + if (pixelData != NULL) + { + ImageD3D *image = getImage(index); + ASSERT(image); + + gl::Box fullImageArea(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth()); + error = image->loadCompressedData(fullImageArea, pixelData); + if (error.isError()) + { + return error; + } + + mDirtyImages = true; + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureD3D::subImageCompressed(const gl::ImageIndex &index, const gl::Box &area, GLenum format, + const gl::PixelUnpackState &unpack, const uint8_t *pixels, + ptrdiff_t layerOffset) +{ + if (unpack.skipRows != 0 || unpack.skipPixels != 0 || unpack.imageHeight != 0 || unpack.skipImages != 0) + { + UNIMPLEMENTED(); + return gl::Error(GL_INVALID_OPERATION, "unimplemented pixel store state"); + } + + const uint8_t *pixelData = NULL; + gl::Error error = GetUnpackPointer(unpack, pixels, layerOffset, &pixelData); + if (error.isError()) + { + return error; + } + + if (pixelData != NULL) + { + ImageD3D *image = getImage(index); + ASSERT(image); + + error = image->loadCompressedData(area, pixelData); + if (error.isError()) + { + return error; + } + + mDirtyImages = true; + } + + return gl::Error(GL_NO_ERROR); +} + +bool TextureD3D::isFastUnpackable(const gl::PixelUnpackState &unpack, GLenum sizedInternalFormat) +{ + return unpack.pixelBuffer.id() != 0 && mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat); +} + +gl::Error TextureD3D::fastUnpackPixels(const gl::PixelUnpackState &unpack, const uint8_t *pixels, const gl::Box &destArea, + GLenum sizedInternalFormat, GLenum type, RenderTargetD3D *destRenderTarget) +{ + // No-op + if (destArea.width <= 0 && destArea.height <= 0 && destArea.depth <= 0) + { + return gl::Error(GL_NO_ERROR); + } + + // In order to perform the fast copy through the shader, we must have the right format, and be able + // to create a render target. + ASSERT(mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat)); + + uintptr_t offset = reinterpret_cast(pixels); + + gl::Error error = mRenderer->fastCopyBufferToTexture(unpack, offset, destRenderTarget, sizedInternalFormat, type, destArea); + if (error.isError()) + { + return error; + } + + return gl::Error(GL_NO_ERROR); +} + +GLint TextureD3D::creationLevels(GLsizei width, GLsizei height, GLsizei depth) const +{ + if ((gl::isPow2(width) && gl::isPow2(height) && gl::isPow2(depth)) || mRenderer->getRendererExtensions().textureNPOT) + { + // Maximum number of levels + return gl::log2(std::max(std::max(width, height), depth)) + 1; + } + else + { + // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps. + return 1; + } +} + +int TextureD3D::mipLevels() const +{ + return gl::log2(std::max(std::max(getBaseLevelWidth(), getBaseLevelHeight()), getBaseLevelDepth())) + 1; +} + +TextureStorage *TextureD3D::getStorage() +{ + ASSERT(mTexStorage); + return mTexStorage; +} + +ImageD3D *TextureD3D::getBaseLevelImage() const +{ + return getImage(getImageIndex(0, 0)); +} + +gl::Error TextureD3D::generateMipmaps() +{ + GLint mipCount = mipLevels(); + + if (mipCount == 1) + { + return gl::Error(GL_NO_ERROR); // no-op + } + + if (mTexStorage && mRenderer->getWorkarounds().zeroMaxLodWorkaround) + { + // Switch to using the mipmapped texture. + TextureStorage *textureStorage = NULL; + gl::Error error = getNativeTexture(&textureStorage); + if (error.isError()) + { + return error; + } + + error = textureStorage->useLevelZeroWorkaroundTexture(false); + if (error.isError()) + { + return error; + } + } + + // Set up proper mipmap chain in our Image array. + initMipmapsImages(); + + // We know that all layers have the same dimension, for the texture to be complete + GLint layerCount = static_cast(getLayerCount(0)); + + // When making mipmaps with the setData workaround enabled, the texture storage has + // the image data already. For non-render-target storage, we have to pull it out into + // an image layer. + if (mRenderer->getWorkarounds().setDataFasterThanImageUpload && mTexStorage) + { + if (!mTexStorage->isRenderTarget()) + { + // Copy from the storage mip 0 to Image mip 0 + for (GLint layer = 0; layer < layerCount; ++layer) + { + gl::ImageIndex srcIndex = getImageIndex(0, layer); + + ImageD3D *image = getImage(srcIndex); + gl::Box area(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth()); + gl::Offset offset(0, 0, 0); + gl::Error error = image->copy(offset, area, srcIndex, mTexStorage); + if (error.isError()) + { + return error; + } + } + } + else + { + gl::Error error = updateStorage(); + if (error.isError()) + { + return error; + } + } + } + + // TODO: Decouple this from zeroMaxLodWorkaround. This is a 9_3 restriction, unrelated to zeroMaxLodWorkaround. + // The restriction is because Feature Level 9_3 can't create SRVs on individual levels of the texture. + // As a result, even if the storage is a rendertarget, we can't use the GPU to generate the mipmaps without further work. + // The D3D9 renderer works around this by copying each level of the texture into its own single-layer GPU texture (in Blit9::boxFilter). + // Feature Level 9_3 could do something similar, or it could continue to use CPU-side mipmap generation, or something else. + bool renderableStorage = (mTexStorage && mTexStorage->isRenderTarget() && !(mRenderer->getWorkarounds().zeroMaxLodWorkaround)); + + for (GLint layer = 0; layer < layerCount; ++layer) + { + for (GLint mip = 1; mip < mipCount; ++mip) + { + ASSERT(getLayerCount(mip) == layerCount); + + gl::ImageIndex sourceIndex = getImageIndex(mip - 1, layer); + gl::ImageIndex destIndex = getImageIndex(mip, layer); + + if (renderableStorage) + { + // GPU-side mipmapping + gl::Error error = mTexStorage->generateMipmap(sourceIndex, destIndex); + if (error.isError()) + { + return error; + } + } + else + { + // CPU-side mipmapping + gl::Error error = mRenderer->generateMipmap(getImage(destIndex), getImage(sourceIndex)); + if (error.isError()) + { + return error; + } + } + } + } + + if (mTexStorage) + { + updateStorage(); + } + + return gl::Error(GL_NO_ERROR); +} + +bool TextureD3D::isBaseImageZeroSize() const +{ + ImageD3D *baseImage = getBaseLevelImage(); + + if (!baseImage || baseImage->getWidth() <= 0) + { + return true; + } + + if (!gl::IsCubeMapTextureTarget(baseImage->getTarget()) && baseImage->getHeight() <= 0) + { + return true; + } + + if (baseImage->getTarget() == GL_TEXTURE_3D && baseImage->getDepth() <= 0) + { + return true; + } + + if (baseImage->getTarget() == GL_TEXTURE_2D_ARRAY && getLayerCount(0) <= 0) + { + return true; + } + + return false; +} + +gl::Error TextureD3D::ensureRenderTarget() +{ + gl::Error error = initializeStorage(true); + if (error.isError()) + { + return error; + } + + if (!isBaseImageZeroSize()) + { + ASSERT(mTexStorage); + if (!mTexStorage->isRenderTarget()) + { + TextureStorage *newRenderTargetStorage = NULL; + error = createCompleteStorage(true, &newRenderTargetStorage); + if (error.isError()) + { + return error; + } + + error = mTexStorage->copyToStorage(newRenderTargetStorage); + if (error.isError()) + { + SafeDelete(newRenderTargetStorage); + return error; + } + + error = setCompleteTexStorage(newRenderTargetStorage); + if (error.isError()) + { + SafeDelete(newRenderTargetStorage); + return error; + } + } + } + + return gl::Error(GL_NO_ERROR); +} + +bool TextureD3D::canCreateRenderTargetForImage(const gl::ImageIndex &index) const +{ + ImageD3D *image = getImage(index); + bool levelsComplete = (isImageComplete(index) && isImageComplete(getImageIndex(0, 0))); + return (image->isRenderableFormat() && levelsComplete); +} + +gl::Error TextureD3D::commitRegion(const gl::ImageIndex &index, const gl::Box ®ion) +{ + if (mTexStorage) + { + ASSERT(isValidIndex(index)); + ImageD3D *image = getImage(index); + gl::Error error = image->copyToStorage(mTexStorage, index, region); + if (error.isError()) + { + return error; + } + + image->markClean(); + } + + return gl::Error(GL_NO_ERROR); +} + +TextureD3D_2D::TextureD3D_2D(RendererD3D *renderer) + : TextureD3D(renderer) +{ + for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i) + { + mImageArray[i] = renderer->createImage(); + } +} + +TextureD3D_2D::~TextureD3D_2D() +{ + // Delete the Images before the TextureStorage. + // Images might be relying on the TextureStorage for some of their data. + // If TextureStorage is deleted before the Images, then their data will be wastefully copied back from the GPU before we delete the Images. + for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i) + { + delete mImageArray[i]; + } + + SafeDelete(mTexStorage); +} + +ImageD3D *TextureD3D_2D::getImage(int level, int layer) const +{ + ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); + ASSERT(layer == 0); + return mImageArray[level]; +} + +ImageD3D *TextureD3D_2D::getImage(const gl::ImageIndex &index) const +{ + ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); + ASSERT(!index.hasLayer()); + ASSERT(index.type == GL_TEXTURE_2D); + return mImageArray[index.mipIndex]; +} + +GLsizei TextureD3D_2D::getLayerCount(int level) const +{ + ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); + return 1; +} + +GLsizei TextureD3D_2D::getWidth(GLint level) const +{ + if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) + return mImageArray[level]->getWidth(); + else + return 0; +} + +GLsizei TextureD3D_2D::getHeight(GLint level) const +{ + if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) + return mImageArray[level]->getHeight(); + else + return 0; +} + +GLenum TextureD3D_2D::getInternalFormat(GLint level) const +{ + if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) + return mImageArray[level]->getInternalFormat(); + else + return GL_NONE; +} + +bool TextureD3D_2D::isDepth(GLint level) const +{ + return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0; +} + +gl::Error TextureD3D_2D::setImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size, GLenum format, GLenum type, + const gl::PixelUnpackState &unpack, const uint8_t *pixels) +{ + ASSERT(target == GL_TEXTURE_2D && size.depth == 1); + + GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type); + + bool fastUnpacked = false; + + redefineImage(level, sizedInternalFormat, size); + + gl::ImageIndex index = gl::ImageIndex::Make2D(level); + + // Attempt a fast gpu copy of the pixel data to the surface + if (isFastUnpackable(unpack, sizedInternalFormat) && isLevelComplete(level)) + { + // Will try to create RT storage if it does not exist + RenderTargetD3D *destRenderTarget = NULL; + gl::Error error = getRenderTarget(index, &destRenderTarget); + if (error.isError()) + { + return error; + } + + gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), 1); + + error = fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget); + if (error.isError()) + { + return error; + } + + // Ensure we don't overwrite our newly initialized data + mImageArray[level]->markClean(); + + fastUnpacked = true; + } + + if (!fastUnpacked) + { + gl::Error error = TextureD3D::setImage(index, type, unpack, pixels, 0); + if (error.isError()) + { + return error; + } + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureD3D_2D::setSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format, GLenum type, + const gl::PixelUnpackState &unpack, const uint8_t *pixels) +{ + ASSERT(target == GL_TEXTURE_2D && area.depth == 1 && area.z == 0); + + if (unpack.skipRows != 0 || unpack.skipPixels != 0 || unpack.imageHeight != 0 || unpack.skipImages != 0) + { + UNIMPLEMENTED(); + return gl::Error(GL_INVALID_OPERATION, "unimplemented pixel store state"); + } + + gl::ImageIndex index = gl::ImageIndex::Make2D(level); + if (isFastUnpackable(unpack, getInternalFormat(level)) && isLevelComplete(level)) + { + RenderTargetD3D *renderTarget = NULL; + gl::Error error = getRenderTarget(index, &renderTarget); + if (error.isError()) + { + return error; + } + + ASSERT(!mImageArray[level]->isDirty()); + + return fastUnpackPixels(unpack, pixels, area, getInternalFormat(level), type, renderTarget); + } + else + { + return TextureD3D::subImage(index, area, format, type, unpack, pixels, 0); + } +} + + +gl::Error TextureD3D_2D::setCompressedImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size, + const gl::PixelUnpackState &unpack, const uint8_t *pixels) +{ + ASSERT(target == GL_TEXTURE_2D && size.depth == 1); + + // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly + redefineImage(level, internalFormat, size); + + return TextureD3D::setCompressedImage(gl::ImageIndex::Make2D(level), unpack, pixels, 0); +} + +gl::Error TextureD3D_2D::setCompressedSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format, + const gl::PixelUnpackState &unpack, const uint8_t *pixels) +{ + ASSERT(target == GL_TEXTURE_2D && area.depth == 1 && area.z == 0); + + gl::ImageIndex index = gl::ImageIndex::Make2D(level); + gl::Error error = TextureD3D::subImageCompressed(index, area, format, unpack, pixels, 0); + if (error.isError()) + { + return error; + } + + return commitRegion(index, area); +} + +gl::Error TextureD3D_2D::copyImage(GLenum target, size_t level, const gl::Rectangle &sourceArea, GLenum internalFormat, + const gl::Framebuffer *source) +{ + ASSERT(target == GL_TEXTURE_2D); + + GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, GL_UNSIGNED_BYTE); + redefineImage(level, sizedInternalFormat, gl::Extents(sourceArea.width, sourceArea.height, 1)); + + gl::ImageIndex index = gl::ImageIndex::Make2D(level); + gl::Offset destOffset(0, 0, 0); + + // If the zero max LOD workaround is active, then we can't sample from individual layers of the framebuffer in shaders, + // so we should use the non-rendering copy path. + if (!canCreateRenderTargetForImage(index) || mRenderer->getWorkarounds().zeroMaxLodWorkaround) + { + gl::Error error = mImageArray[level]->copy(destOffset, sourceArea, source); + if (error.isError()) + { + return error; + } + + mDirtyImages = true; + } + else + { + gl::Error error = ensureRenderTarget(); + if (error.isError()) + { + return error; + } + + mImageArray[level]->markClean(); + + if (sourceArea.width != 0 && sourceArea.height != 0 && isValidLevel(level)) + { + error = mRenderer->copyImage2D(source, sourceArea, internalFormat, destOffset, mTexStorage, level); + if (error.isError()) + { + return error; + } + } + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureD3D_2D::copySubImage(GLenum target, size_t level, const gl::Offset &destOffset, const gl::Rectangle &sourceArea, + const gl::Framebuffer *source) +{ + ASSERT(target == GL_TEXTURE_2D && destOffset.z == 0); + + // can only make our texture storage to a render target if level 0 is defined (with a width & height) and + // the current level we're copying to is defined (with appropriate format, width & height) + + gl::ImageIndex index = gl::ImageIndex::Make2D(level); + + // If the zero max LOD workaround is active, then we can't sample from individual layers of the framebuffer in shaders, + // so we should use the non-rendering copy path. + if (!canCreateRenderTargetForImage(index) || mRenderer->getWorkarounds().zeroMaxLodWorkaround) + { + gl::Error error = mImageArray[level]->copy(destOffset, sourceArea, source); + if (error.isError()) + { + return error; + } + + mDirtyImages = true; + } + else + { + gl::Error error = ensureRenderTarget(); + if (error.isError()) + { + return error; + } + + if (isValidLevel(level)) + { + error = updateStorageLevel(level); + if (error.isError()) + { + return error; + } + + error = mRenderer->copyImage2D(source, sourceArea, + gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format, + destOffset, mTexStorage, level); + if (error.isError()) + { + return error; + } + } + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureD3D_2D::setStorage(GLenum target, size_t levels, GLenum internalFormat, const gl::Extents &size) +{ + ASSERT(GL_TEXTURE_2D && size.depth == 1); + + for (size_t level = 0; level < levels; level++) + { + gl::Extents levelSize(std::max(1, size.width >> level), + std::max(1, size.height >> level), + 1); + mImageArray[level]->redefine(GL_TEXTURE_2D, internalFormat, levelSize, true); + } + + for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) + { + mImageArray[level]->redefine(GL_TEXTURE_2D, GL_NONE, gl::Extents(0, 0, 0), true); + } + + // TODO(geofflang): Verify storage creation had no errors + bool renderTarget = IsRenderTargetUsage(mUsage); + TextureStorage *storage = mRenderer->createTextureStorage2D(internalFormat, renderTarget, size.width, size.height, levels, false); + + gl::Error error = setCompleteTexStorage(storage); + if (error.isError()) + { + SafeDelete(storage); + return error; + } + + error = updateStorage(); + + if (error.isError()) + { + return error; + } + + mImmutable = true; + + return gl::Error(GL_NO_ERROR); +} + +void TextureD3D_2D::bindTexImage(egl::Surface *surface) +{ + GLenum internalformat = surface->getConfig()->renderTargetFormat; + + gl::Extents size(surface->getWidth(), surface->getHeight(), 1); + mImageArray[0]->redefine(GL_TEXTURE_2D, internalformat, size, true); + + if (mTexStorage) + { + SafeDelete(mTexStorage); + } + + SurfaceD3D *surfaceD3D = GetImplAs(surface); + ASSERT(surfaceD3D); + + mTexStorage = mRenderer->createTextureStorage2D(surfaceD3D->getSwapChain()); + + mDirtyImages = true; +} + +void TextureD3D_2D::releaseTexImage() +{ + if (mTexStorage) + { + SafeDelete(mTexStorage); + } + + for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) + { + mImageArray[i]->redefine(GL_TEXTURE_2D, GL_NONE, gl::Extents(0, 0, 0), true); + } +} + +void TextureD3D_2D::initMipmapsImages() +{ + // Purge array levels 1 through q and reset them to represent the generated mipmap levels. + int levelCount = mipLevels(); + for (int level = 1; level < levelCount; level++) + { + gl::Extents levelSize(std::max(getBaseLevelWidth() >> level, 1), + std::max(getBaseLevelHeight() >> level, 1), + 1); + + redefineImage(level, getBaseLevelInternalFormat(), levelSize); + } +} + +unsigned int TextureD3D_2D::getRenderTargetSerial(const gl::ImageIndex &index) +{ + ASSERT(!index.hasLayer()); + return (!ensureRenderTarget().isError() ? mTexStorage->getRenderTargetSerial(index) : 0); +} + +gl::Error TextureD3D_2D::getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT) +{ + ASSERT(!index.hasLayer()); + + // ensure the underlying texture is created + gl::Error error = ensureRenderTarget(); + if (error.isError()) + { + return error; + } + + error = updateStorageLevel(index.mipIndex); + if (error.isError()) + { + return error; + } + + return mTexStorage->getRenderTarget(index, outRT); +} + +bool TextureD3D_2D::isValidLevel(int level) const +{ + return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : false); +} + +bool TextureD3D_2D::isLevelComplete(int level) const +{ + if (isImmutable()) + { + return true; + } + + const ImageD3D *baseImage = getBaseLevelImage(); + + GLsizei width = baseImage->getWidth(); + GLsizei height = baseImage->getHeight(); + + if (width <= 0 || height <= 0) + { + return false; + } + + // The base image level is complete if the width and height are positive + if (level == 0) + { + return true; + } + + ASSERT(level >= 1 && level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL); + ImageD3D *image = mImageArray[level]; + + if (image->getInternalFormat() != baseImage->getInternalFormat()) + { + return false; + } + + if (image->getWidth() != std::max(1, width >> level)) + { + return false; + } + + if (image->getHeight() != std::max(1, height >> level)) + { + return false; + } + + return true; +} + +bool TextureD3D_2D::isImageComplete(const gl::ImageIndex &index) const +{ + return isLevelComplete(index.mipIndex); +} + +// Constructs a native texture resource from the texture images +gl::Error TextureD3D_2D::initializeStorage(bool renderTarget) +{ + // Only initialize the first time this texture is used as a render target or shader resource + if (mTexStorage) + { + return gl::Error(GL_NO_ERROR); + } + + // do not attempt to create storage for nonexistant data + if (!isLevelComplete(0)) + { + return gl::Error(GL_NO_ERROR); + } + + bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage)); + + TextureStorage *storage = NULL; + gl::Error error = createCompleteStorage(createRenderTarget, &storage); + if (error.isError()) + { + return error; + } + + error = setCompleteTexStorage(storage); + if (error.isError()) + { + SafeDelete(storage); + return error; + } + + ASSERT(mTexStorage); + + // flush image data to the storage + error = updateStorage(); + if (error.isError()) + { + return error; + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureD3D_2D::createCompleteStorage(bool renderTarget, TextureStorage **outTexStorage) const +{ + GLsizei width = getBaseLevelWidth(); + GLsizei height = getBaseLevelHeight(); + GLenum internalFormat = getBaseLevelInternalFormat(); + + ASSERT(width > 0 && height > 0); + + // use existing storage level count, when previously specified by TexStorage*D + GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1)); + + bool hintLevelZeroOnly = false; + if (mRenderer->getWorkarounds().zeroMaxLodWorkaround) + { + // If any of the CPU images (levels >= 1) are dirty, then the textureStorage2D should use the mipped texture to begin with. + // Otherwise, it should use the level-zero-only texture. + hintLevelZeroOnly = true; + for (int level = 1; level < levels && hintLevelZeroOnly; level++) + { + hintLevelZeroOnly = !(mImageArray[level]->isDirty() && isLevelComplete(level)); + } + } + + // TODO(geofflang): Determine if the texture creation succeeded + *outTexStorage = mRenderer->createTextureStorage2D(internalFormat, renderTarget, width, height, levels, hintLevelZeroOnly); + + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureD3D_2D::setCompleteTexStorage(TextureStorage *newCompleteTexStorage) +{ + if (newCompleteTexStorage && newCompleteTexStorage->isManaged()) + { + for (int level = 0; level < newCompleteTexStorage->getLevelCount(); level++) + { + gl::Error error = mImageArray[level]->setManagedSurface2D(newCompleteTexStorage, level); + if (error.isError()) + { + return error; + } + } + } + + SafeDelete(mTexStorage); + mTexStorage = newCompleteTexStorage; + + mDirtyImages = true; + + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureD3D_2D::updateStorage() +{ + ASSERT(mTexStorage != NULL); + GLint storageLevels = mTexStorage->getLevelCount(); + for (int level = 0; level < storageLevels; level++) + { + if (mImageArray[level]->isDirty() && isLevelComplete(level)) + { + gl::Error error = updateStorageLevel(level); + if (error.isError()) + { + return error; + } + } + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureD3D_2D::updateStorageLevel(int level) +{ + ASSERT(level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL); + ASSERT(isLevelComplete(level)); + + if (mImageArray[level]->isDirty()) + { + gl::ImageIndex index = gl::ImageIndex::Make2D(level); + gl::Box region(0, 0, 0, getWidth(level), getHeight(level), 1); + gl::Error error = commitRegion(index, region); + if (error.isError()) + { + return error; + } + } + + return gl::Error(GL_NO_ERROR); +} + +void TextureD3D_2D::redefineImage(GLint level, GLenum internalformat, const gl::Extents &size) +{ + ASSERT(size.depth == 1); + + // If there currently is a corresponding storage texture image, it has these parameters + const int storageWidth = std::max(1, getBaseLevelWidth() >> level); + const int storageHeight = std::max(1, getBaseLevelHeight() >> level); + const GLenum storageFormat = getBaseLevelInternalFormat(); + + mImageArray[level]->redefine(GL_TEXTURE_2D, internalformat, size, false); + + if (mTexStorage) + { + const int storageLevels = mTexStorage->getLevelCount(); + + if ((level >= storageLevels && storageLevels != 0) || + size.width != storageWidth || + size.height != storageHeight || + internalformat != storageFormat) // Discard mismatched storage + { + for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) + { + mImageArray[i]->markDirty(); + } + + SafeDelete(mTexStorage); + mDirtyImages = true; + } + } +} + +gl::ImageIndexIterator TextureD3D_2D::imageIterator() const +{ + return gl::ImageIndexIterator::Make2D(0, mTexStorage->getLevelCount()); +} + +gl::ImageIndex TextureD3D_2D::getImageIndex(GLint mip, GLint /*layer*/) const +{ + // "layer" does not apply to 2D Textures. + return gl::ImageIndex::Make2D(mip); +} + +bool TextureD3D_2D::isValidIndex(const gl::ImageIndex &index) const +{ + return (mTexStorage && index.type == GL_TEXTURE_2D && + index.mipIndex >= 0 && index.mipIndex < mTexStorage->getLevelCount()); +} + +TextureD3D_Cube::TextureD3D_Cube(RendererD3D *renderer) + : TextureD3D(renderer) +{ + for (int i = 0; i < 6; i++) + { + for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j) + { + mImageArray[i][j] = renderer->createImage(); + } + } +} + +TextureD3D_Cube::~TextureD3D_Cube() +{ + // Delete the Images before the TextureStorage. + // Images might be relying on the TextureStorage for some of their data. + // If TextureStorage is deleted before the Images, then their data will be wastefully copied back from the GPU before we delete the Images. + for (int i = 0; i < 6; i++) + { + for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j) + { + SafeDelete(mImageArray[i][j]); + } + } + + SafeDelete(mTexStorage); +} + +ImageD3D *TextureD3D_Cube::getImage(int level, int layer) const +{ + ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); + ASSERT(layer >= 0 && layer < 6); + return mImageArray[layer][level]; +} + +ImageD3D *TextureD3D_Cube::getImage(const gl::ImageIndex &index) const +{ + ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); + ASSERT(index.layerIndex >= 0 && index.layerIndex < 6); + return mImageArray[index.layerIndex][index.mipIndex]; +} + +GLsizei TextureD3D_Cube::getLayerCount(int level) const +{ + ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); + return 6; +} + +GLenum TextureD3D_Cube::getInternalFormat(GLint level, GLint layer) const +{ + if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) + return mImageArray[layer][level]->getInternalFormat(); + else + return GL_NONE; +} + +bool TextureD3D_Cube::isDepth(GLint level, GLint layer) const +{ + return gl::GetInternalFormatInfo(getInternalFormat(level, layer)).depthBits > 0; +} + +gl::Error TextureD3D_Cube::setImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size, GLenum format, GLenum type, + const gl::PixelUnpackState &unpack, const uint8_t *pixels) +{ + ASSERT(size.depth == 1); + + GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type); + gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level); + + redefineImage(index.layerIndex, level, sizedInternalFormat, size); + + return TextureD3D::setImage(index, type, unpack, pixels, 0); +} + +gl::Error TextureD3D_Cube::setSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format, GLenum type, + const gl::PixelUnpackState &unpack, const uint8_t *pixels) +{ + ASSERT(area.depth == 1 && area.z == 0); + + gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level); + return TextureD3D::subImage(index, area, format, type, unpack, pixels, 0); +} + +gl::Error TextureD3D_Cube::setCompressedImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size, + const gl::PixelUnpackState &unpack, const uint8_t *pixels) +{ + ASSERT(size.depth == 1); + + // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly + size_t faceIndex = gl::CubeMapTextureTargetToLayerIndex(target); + + redefineImage(faceIndex, level, internalFormat, size); + + gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level); + return TextureD3D::setCompressedImage(index, unpack, pixels, 0); +} + +gl::Error TextureD3D_Cube::setCompressedSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format, + const gl::PixelUnpackState &unpack, const uint8_t *pixels) +{ + ASSERT(area.depth == 1 && area.z == 0); + + gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level); + + gl::Error error = TextureD3D::subImageCompressed(index, area, format, unpack, pixels, 0); + if (error.isError()) + { + return error; + } + + return commitRegion(index, area); +} + +gl::Error TextureD3D_Cube::copyImage(GLenum target, size_t level, const gl::Rectangle &sourceArea, GLenum internalFormat, + const gl::Framebuffer *source) +{ + size_t faceIndex = gl::CubeMapTextureTargetToLayerIndex(target); + GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, GL_UNSIGNED_BYTE); + + gl::Extents size(sourceArea.width, sourceArea.height, 1); + redefineImage(faceIndex, level, sizedInternalFormat, size); + + gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level); + gl::Offset destOffset(0, 0, 0); + + // If the zero max LOD workaround is active, then we can't sample from individual layers of the framebuffer in shaders, + // so we should use the non-rendering copy path. + if (!canCreateRenderTargetForImage(index) || mRenderer->getWorkarounds().zeroMaxLodWorkaround) + { + gl::Error error = mImageArray[faceIndex][level]->copy(destOffset, sourceArea, source); + if (error.isError()) + { + return error; + } + + mDirtyImages = true; + } + else + { + gl::Error error = ensureRenderTarget(); + if (error.isError()) + { + return error; + } + + mImageArray[faceIndex][level]->markClean(); + + ASSERT(size.width == size.height); + + if (size.width > 0 && isValidFaceLevel(faceIndex, level)) + { + error = mRenderer->copyImageCube(source, sourceArea, internalFormat, destOffset, mTexStorage, target, level); + if (error.isError()) + { + return error; + } + } + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureD3D_Cube::copySubImage(GLenum target, size_t level, const gl::Offset &destOffset, const gl::Rectangle &sourceArea, + const gl::Framebuffer *source) +{ + size_t faceIndex = gl::CubeMapTextureTargetToLayerIndex(target); + + gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level); + + // If the zero max LOD workaround is active, then we can't sample from individual layers of the framebuffer in shaders, + // so we should use the non-rendering copy path. + if (!canCreateRenderTargetForImage(index) || mRenderer->getWorkarounds().zeroMaxLodWorkaround) + { + gl::Error error = mImageArray[faceIndex][level]->copy(destOffset, sourceArea, source); + if (error.isError()) + { + return error; + } + + mDirtyImages = true; + } + else + { + gl::Error error = ensureRenderTarget(); + if (error.isError()) + { + return error; + } + + if (isValidFaceLevel(faceIndex, level)) + { + error = updateStorageFaceLevel(faceIndex, level); + if (error.isError()) + { + return error; + } + + error = mRenderer->copyImageCube(source, sourceArea, gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format, + destOffset, mTexStorage, target, level); + if (error.isError()) + { + return error; + } + } + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureD3D_Cube::setStorage(GLenum target, size_t levels, GLenum internalFormat, const gl::Extents &size) +{ + ASSERT(size.width == size.height); + ASSERT(size.depth == 1); + + for (size_t level = 0; level < levels; level++) + { + GLsizei mipSize = std::max(1, size.width >> level); + for (int faceIndex = 0; faceIndex < 6; faceIndex++) + { + mImageArray[faceIndex][level]->redefine(GL_TEXTURE_CUBE_MAP, internalFormat, gl::Extents(mipSize, mipSize, 1), true); + } + } + + for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) + { + for (int faceIndex = 0; faceIndex < 6; faceIndex++) + { + mImageArray[faceIndex][level]->redefine(GL_TEXTURE_CUBE_MAP, GL_NONE, gl::Extents(0, 0, 0), true); + } + } + + // TODO(geofflang): Verify storage creation had no errors + bool renderTarget = IsRenderTargetUsage(mUsage); + + TextureStorage *storage = mRenderer->createTextureStorageCube(internalFormat, renderTarget, size.width, levels, false); + + gl::Error error = setCompleteTexStorage(storage); + if (error.isError()) + { + SafeDelete(storage); + return error; + } + + error = updateStorage(); + + if (error.isError()) + { + return error; + } + + mImmutable = true; + + return gl::Error(GL_NO_ERROR); +} + +// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81. +bool TextureD3D_Cube::isCubeComplete() const +{ + int baseWidth = getBaseLevelWidth(); + int baseHeight = getBaseLevelHeight(); + GLenum baseFormat = getBaseLevelInternalFormat(); + + if (baseWidth <= 0 || baseWidth != baseHeight) + { + return false; + } + + for (int faceIndex = 1; faceIndex < 6; faceIndex++) + { + const ImageD3D &faceBaseImage = *mImageArray[faceIndex][0]; + + if (faceBaseImage.getWidth() != baseWidth || + faceBaseImage.getHeight() != baseHeight || + faceBaseImage.getInternalFormat() != baseFormat ) + { + return false; + } + } + + return true; +} + +void TextureD3D_Cube::bindTexImage(egl::Surface *surface) +{ + UNREACHABLE(); +} + +void TextureD3D_Cube::releaseTexImage() +{ + UNREACHABLE(); +} + + +void TextureD3D_Cube::initMipmapsImages() +{ + // Purge array levels 1 through q and reset them to represent the generated mipmap levels. + int levelCount = mipLevels(); + for (int faceIndex = 0; faceIndex < 6; faceIndex++) + { + for (int level = 1; level < levelCount; level++) + { + int faceLevelSize = (std::max(mImageArray[faceIndex][0]->getWidth() >> level, 1)); + redefineImage(faceIndex, level, mImageArray[faceIndex][0]->getInternalFormat(), + gl::Extents(faceLevelSize, faceLevelSize, 1)); + } + } +} + +unsigned int TextureD3D_Cube::getRenderTargetSerial(const gl::ImageIndex &index) +{ + return (!ensureRenderTarget().isError() ? mTexStorage->getRenderTargetSerial(index) : 0); +} + +gl::Error TextureD3D_Cube::getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT) +{ + ASSERT(gl::IsCubeMapTextureTarget(index.type)); + + // ensure the underlying texture is created + gl::Error error = ensureRenderTarget(); + if (error.isError()) + { + return error; + } + + error = updateStorageFaceLevel(index.layerIndex, index.mipIndex); + if (error.isError()) + { + return error; + } + + return mTexStorage->getRenderTarget(index, outRT); +} + +gl::Error TextureD3D_Cube::initializeStorage(bool renderTarget) +{ + // Only initialize the first time this texture is used as a render target or shader resource + if (mTexStorage) + { + return gl::Error(GL_NO_ERROR); + } + + // do not attempt to create storage for nonexistant data + if (!isFaceLevelComplete(0, 0)) + { + return gl::Error(GL_NO_ERROR); + } + + bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage)); + + TextureStorage *storage = NULL; + gl::Error error = createCompleteStorage(createRenderTarget, &storage); + if (error.isError()) + { + return error; + } + + error = setCompleteTexStorage(storage); + if (error.isError()) + { + SafeDelete(storage); + return error; + } + + ASSERT(mTexStorage); + + // flush image data to the storage + error = updateStorage(); + if (error.isError()) + { + return error; + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureD3D_Cube::createCompleteStorage(bool renderTarget, TextureStorage **outTexStorage) const +{ + GLsizei size = getBaseLevelWidth(); + + ASSERT(size > 0); + + // use existing storage level count, when previously specified by TexStorage*D + GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(size, size, 1)); + + bool hintLevelZeroOnly = false; + if (mRenderer->getWorkarounds().zeroMaxLodWorkaround) + { + // If any of the CPU images (levels >= 1) are dirty, then the textureStorage should use the mipped texture to begin with. + // Otherwise, it should use the level-zero-only texture. + hintLevelZeroOnly = true; + for (int faceIndex = 0; faceIndex < 6 && hintLevelZeroOnly; faceIndex++) + { + for (int level = 1; level < levels && hintLevelZeroOnly; level++) + { + hintLevelZeroOnly = !(mImageArray[faceIndex][level]->isDirty() && isFaceLevelComplete(faceIndex, level)); + } + } + } + + // TODO (geofflang): detect if storage creation succeeded + *outTexStorage = mRenderer->createTextureStorageCube(getBaseLevelInternalFormat(), renderTarget, size, levels, hintLevelZeroOnly); + + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureD3D_Cube::setCompleteTexStorage(TextureStorage *newCompleteTexStorage) +{ + if (newCompleteTexStorage && newCompleteTexStorage->isManaged()) + { + for (int faceIndex = 0; faceIndex < 6; faceIndex++) + { + for (int level = 0; level < newCompleteTexStorage->getLevelCount(); level++) + { + gl::Error error = mImageArray[faceIndex][level]->setManagedSurfaceCube(newCompleteTexStorage, faceIndex, level); + if (error.isError()) + { + return error; + } + } + } + } + + SafeDelete(mTexStorage); + mTexStorage = newCompleteTexStorage; + + mDirtyImages = true; + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureD3D_Cube::updateStorage() +{ + ASSERT(mTexStorage != NULL); + GLint storageLevels = mTexStorage->getLevelCount(); + for (int face = 0; face < 6; face++) + { + for (int level = 0; level < storageLevels; level++) + { + if (mImageArray[face][level]->isDirty() && isFaceLevelComplete(face, level)) + { + gl::Error error = updateStorageFaceLevel(face, level); + if (error.isError()) + { + return error; + } + } + } + } + + return gl::Error(GL_NO_ERROR); +} + +bool TextureD3D_Cube::isValidFaceLevel(int faceIndex, int level) const +{ + return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0); +} + +bool TextureD3D_Cube::isFaceLevelComplete(int faceIndex, int level) const +{ + ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL); + + if (isImmutable()) + { + return true; + } + + int baseSize = getBaseLevelWidth(); + + if (baseSize <= 0) + { + return false; + } + + // "isCubeComplete" checks for base level completeness and we must call that + // to determine if any face at level 0 is complete. We omit that check here + // to avoid re-checking cube-completeness for every face at level 0. + if (level == 0) + { + return true; + } + + // Check that non-zero levels are consistent with the base level. + const ImageD3D *faceLevelImage = mImageArray[faceIndex][level]; + + if (faceLevelImage->getInternalFormat() != getBaseLevelInternalFormat()) + { + return false; + } + + if (faceLevelImage->getWidth() != std::max(1, baseSize >> level)) + { + return false; + } + + return true; +} + +bool TextureD3D_Cube::isImageComplete(const gl::ImageIndex &index) const +{ + return isFaceLevelComplete(index.layerIndex, index.mipIndex); +} + +gl::Error TextureD3D_Cube::updateStorageFaceLevel(int faceIndex, int level) +{ + ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL); + ImageD3D *image = mImageArray[faceIndex][level]; + + if (image->isDirty()) + { + GLenum faceTarget = gl::LayerIndexToCubeMapTextureTarget(faceIndex); + gl::ImageIndex index = gl::ImageIndex::MakeCube(faceTarget, level); + gl::Box region(0, 0, 0, image->getWidth(), image->getHeight(), 1); + gl::Error error = commitRegion(index, region); + if (error.isError()) + { + return error; + } + } + + return gl::Error(GL_NO_ERROR); +} + +void TextureD3D_Cube::redefineImage(int faceIndex, GLint level, GLenum internalformat, const gl::Extents &size) +{ + // If there currently is a corresponding storage texture image, it has these parameters + const int storageWidth = std::max(1, getBaseLevelWidth() >> level); + const int storageHeight = std::max(1, getBaseLevelHeight() >> level); + const GLenum storageFormat = getBaseLevelInternalFormat(); + + mImageArray[faceIndex][level]->redefine(GL_TEXTURE_CUBE_MAP, internalformat, size, false); + + if (mTexStorage) + { + const int storageLevels = mTexStorage->getLevelCount(); + + if ((level >= storageLevels && storageLevels != 0) || + size.width != storageWidth || + size.height != storageHeight || + internalformat != storageFormat) // Discard mismatched storage + { + for (int dirtyLevel = 0; dirtyLevel < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; dirtyLevel++) + { + for (int dirtyFace = 0; dirtyFace < 6; dirtyFace++) + { + mImageArray[dirtyFace][dirtyLevel]->markDirty(); + } + } + + SafeDelete(mTexStorage); + + mDirtyImages = true; + } + } +} + +gl::ImageIndexIterator TextureD3D_Cube::imageIterator() const +{ + return gl::ImageIndexIterator::MakeCube(0, mTexStorage->getLevelCount()); +} + +gl::ImageIndex TextureD3D_Cube::getImageIndex(GLint mip, GLint layer) const +{ + // The "layer" of the image index corresponds to the cube face + return gl::ImageIndex::MakeCube(gl::LayerIndexToCubeMapTextureTarget(layer), mip); +} + +bool TextureD3D_Cube::isValidIndex(const gl::ImageIndex &index) const +{ + return (mTexStorage && gl::IsCubeMapTextureTarget(index.type) && + index.mipIndex >= 0 && index.mipIndex < mTexStorage->getLevelCount()); +} + +TextureD3D_3D::TextureD3D_3D(RendererD3D *renderer) + : TextureD3D(renderer) +{ + for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i) + { + mImageArray[i] = renderer->createImage(); + } +} + +TextureD3D_3D::~TextureD3D_3D() +{ + // Delete the Images before the TextureStorage. + // Images might be relying on the TextureStorage for some of their data. + // If TextureStorage is deleted before the Images, then their data will be wastefully copied back from the GPU before we delete the Images. + for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i) + { + delete mImageArray[i]; + } + + SafeDelete(mTexStorage); +} + +ImageD3D *TextureD3D_3D::getImage(int level, int layer) const +{ + ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); + ASSERT(layer == 0); + return mImageArray[level]; +} + +ImageD3D *TextureD3D_3D::getImage(const gl::ImageIndex &index) const +{ + ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); + ASSERT(!index.hasLayer()); + ASSERT(index.type == GL_TEXTURE_3D); + return mImageArray[index.mipIndex]; +} + +GLsizei TextureD3D_3D::getLayerCount(int level) const +{ + ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); + return 1; +} + +GLsizei TextureD3D_3D::getWidth(GLint level) const +{ + if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) + return mImageArray[level]->getWidth(); + else + return 0; +} + +GLsizei TextureD3D_3D::getHeight(GLint level) const +{ + if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) + return mImageArray[level]->getHeight(); + else + return 0; +} + +GLsizei TextureD3D_3D::getDepth(GLint level) const +{ + if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) + return mImageArray[level]->getDepth(); + else + return 0; +} + +GLenum TextureD3D_3D::getInternalFormat(GLint level) const +{ + if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) + return mImageArray[level]->getInternalFormat(); + else + return GL_NONE; +} + +bool TextureD3D_3D::isDepth(GLint level) const +{ + return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0; +} + +gl::Error TextureD3D_3D::setImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size, GLenum format, GLenum type, + const gl::PixelUnpackState &unpack, const uint8_t *pixels) +{ + ASSERT(target == GL_TEXTURE_3D); + GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type); + + redefineImage(level, sizedInternalFormat, size); + + bool fastUnpacked = false; + + gl::ImageIndex index = gl::ImageIndex::Make3D(level); + + // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer + if (isFastUnpackable(unpack, sizedInternalFormat) && !size.empty()) + { + // Will try to create RT storage if it does not exist + RenderTargetD3D *destRenderTarget = NULL; + gl::Error error = getRenderTarget(index, &destRenderTarget); + if (error.isError()) + { + return error; + } + + gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), getDepth(level)); + + error = fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget); + if (error.isError()) + { + return error; + } + + // Ensure we don't overwrite our newly initialized data + mImageArray[level]->markClean(); + + fastUnpacked = true; + } + + if (!fastUnpacked) + { + gl::Error error = TextureD3D::setImage(index, type, unpack, pixels, 0); + if (error.isError()) + { + return error; + } + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureD3D_3D::setSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format, GLenum type, + const gl::PixelUnpackState &unpack, const uint8_t *pixels) +{ + ASSERT(target == GL_TEXTURE_3D); + + gl::ImageIndex index = gl::ImageIndex::Make3D(level); + + // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer + if (isFastUnpackable(unpack, getInternalFormat(level))) + { + RenderTargetD3D *destRenderTarget = NULL; + gl::Error error = getRenderTarget(index, &destRenderTarget); + if (error.isError()) + { + return error; + } + + ASSERT(!mImageArray[level]->isDirty()); + + return fastUnpackPixels(unpack, pixels, area, getInternalFormat(level), type, destRenderTarget); + } + else + { + return TextureD3D::subImage(index, area, format, type, unpack, pixels, 0); + } +} + +gl::Error TextureD3D_3D::setCompressedImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size, + const gl::PixelUnpackState &unpack, const uint8_t *pixels) +{ + ASSERT(target == GL_TEXTURE_3D); + + // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly + redefineImage(level, internalFormat, size); + + gl::ImageIndex index = gl::ImageIndex::Make3D(level); + return TextureD3D::setCompressedImage(index, unpack, pixels, 0); +} + +gl::Error TextureD3D_3D::setCompressedSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format, + const gl::PixelUnpackState &unpack, const uint8_t *pixels) +{ + ASSERT(target == GL_TEXTURE_3D); + + gl::ImageIndex index = gl::ImageIndex::Make3D(level); + gl::Error error = TextureD3D::subImageCompressed(index, area, format, unpack, pixels, 0); + if (error.isError()) + { + return error; + } + + return commitRegion(index, area); +} + +gl::Error TextureD3D_3D::copyImage(GLenum target, size_t level, const gl::Rectangle &sourceArea, GLenum internalFormat, + const gl::Framebuffer *source) +{ + UNIMPLEMENTED(); + return gl::Error(GL_INVALID_OPERATION, "Copying 3D textures is unimplemented."); +} + +gl::Error TextureD3D_3D::copySubImage(GLenum target, size_t level, const gl::Offset &destOffset, const gl::Rectangle &sourceArea, + const gl::Framebuffer *source) +{ + ASSERT(target == GL_TEXTURE_3D); + + gl::ImageIndex index = gl::ImageIndex::Make3D(level); + + if (canCreateRenderTargetForImage(index)) + { + gl::Error error = mImageArray[level]->copy(destOffset, sourceArea, source); + if (error.isError()) + { + return error; + } + + mDirtyImages = true; + } + else + { + gl::Error error = ensureRenderTarget(); + if (error.isError()) + { + return error; + } + + if (isValidLevel(level)) + { + error = updateStorageLevel(level); + if (error.isError()) + { + return error; + } + + error = mRenderer->copyImage3D(source, sourceArea, + gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format, + destOffset, mTexStorage, level); + if (error.isError()) + { + return error; + } + } + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureD3D_3D::setStorage(GLenum target, size_t levels, GLenum internalFormat, const gl::Extents &size) +{ + ASSERT(target == GL_TEXTURE_3D); + + for (size_t level = 0; level < levels; level++) + { + gl::Extents levelSize(std::max(1, size.width >> level), + std::max(1, size.height >> level), + std::max(1, size.depth >> level)); + mImageArray[level]->redefine(GL_TEXTURE_3D, internalFormat, levelSize, true); + } + + for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) + { + mImageArray[level]->redefine(GL_TEXTURE_3D, GL_NONE, gl::Extents(0, 0, 0), true); + } + + // TODO(geofflang): Verify storage creation had no errors + bool renderTarget = IsRenderTargetUsage(mUsage); + TextureStorage *storage = mRenderer->createTextureStorage3D(internalFormat, renderTarget, size.width, size.height, size.depth, levels); + + gl::Error error = setCompleteTexStorage(storage); + if (error.isError()) + { + SafeDelete(storage); + return error; + } + + error = updateStorage(); + + if (error.isError()) + { + return error; + } + + mImmutable = true; + + return gl::Error(GL_NO_ERROR); +} + +void TextureD3D_3D::bindTexImage(egl::Surface *surface) +{ + UNREACHABLE(); +} + +void TextureD3D_3D::releaseTexImage() +{ + UNREACHABLE(); +} + + +void TextureD3D_3D::initMipmapsImages() +{ + // Purge array levels 1 through q and reset them to represent the generated mipmap levels. + int levelCount = mipLevels(); + for (int level = 1; level < levelCount; level++) + { + gl::Extents levelSize(std::max(getBaseLevelWidth() >> level, 1), + std::max(getBaseLevelHeight() >> level, 1), + std::max(getBaseLevelDepth() >> level, 1)); + redefineImage(level, getBaseLevelInternalFormat(), levelSize); + } +} + +unsigned int TextureD3D_3D::getRenderTargetSerial(const gl::ImageIndex &index) +{ + return (!ensureRenderTarget().isError() ? mTexStorage->getRenderTargetSerial(index) : 0); +} + +gl::Error TextureD3D_3D::getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT) +{ + // ensure the underlying texture is created + gl::Error error = ensureRenderTarget(); + if (error.isError()) + { + return error; + } + + if (index.hasLayer()) + { + error = updateStorage(); + if (error.isError()) + { + return error; + } + } + else + { + error = updateStorageLevel(index.mipIndex); + if (error.isError()) + { + return error; + } + } + + return mTexStorage->getRenderTarget(index, outRT); +} + +gl::Error TextureD3D_3D::initializeStorage(bool renderTarget) +{ + // Only initialize the first time this texture is used as a render target or shader resource + if (mTexStorage) + { + return gl::Error(GL_NO_ERROR); + } + + // do not attempt to create storage for nonexistant data + if (!isLevelComplete(0)) + { + return gl::Error(GL_NO_ERROR); + } + + bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage)); + + TextureStorage *storage = NULL; + gl::Error error = createCompleteStorage(createRenderTarget, &storage); + if (error.isError()) + { + return error; + } + + error = setCompleteTexStorage(storage); + if (error.isError()) + { + SafeDelete(storage); + return error; + } + + ASSERT(mTexStorage); + + // flush image data to the storage + error = updateStorage(); + if (error.isError()) + { + return error; + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureD3D_3D::createCompleteStorage(bool renderTarget, TextureStorage **outStorage) const +{ + GLsizei width = getBaseLevelWidth(); + GLsizei height = getBaseLevelHeight(); + GLsizei depth = getBaseLevelDepth(); + GLenum internalFormat = getBaseLevelInternalFormat(); + + ASSERT(width > 0 && height > 0 && depth > 0); + + // use existing storage level count, when previously specified by TexStorage*D + GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, depth)); + + // TODO: Verify creation of the storage succeeded + *outStorage = mRenderer->createTextureStorage3D(internalFormat, renderTarget, width, height, depth, levels); + + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureD3D_3D::setCompleteTexStorage(TextureStorage *newCompleteTexStorage) +{ + SafeDelete(mTexStorage); + mTexStorage = newCompleteTexStorage; + mDirtyImages = true; + + // We do not support managed 3D storage, as that is D3D9/ES2-only + ASSERT(!mTexStorage->isManaged()); + + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureD3D_3D::updateStorage() +{ + ASSERT(mTexStorage != NULL); + GLint storageLevels = mTexStorage->getLevelCount(); + for (int level = 0; level < storageLevels; level++) + { + if (mImageArray[level]->isDirty() && isLevelComplete(level)) + { + gl::Error error = updateStorageLevel(level); + if (error.isError()) + { + return error; + } + } + } + + return gl::Error(GL_NO_ERROR); +} + +bool TextureD3D_3D::isValidLevel(int level) const +{ + return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0); +} + +bool TextureD3D_3D::isLevelComplete(int level) const +{ + ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL); + + if (isImmutable()) + { + return true; + } + + GLsizei width = getBaseLevelWidth(); + GLsizei height = getBaseLevelHeight(); + GLsizei depth = getBaseLevelDepth(); + + if (width <= 0 || height <= 0 || depth <= 0) + { + return false; + } + + if (level == 0) + { + return true; + } + + ImageD3D *levelImage = mImageArray[level]; + + if (levelImage->getInternalFormat() != getBaseLevelInternalFormat()) + { + return false; + } + + if (levelImage->getWidth() != std::max(1, width >> level)) + { + return false; + } + + if (levelImage->getHeight() != std::max(1, height >> level)) + { + return false; + } + + if (levelImage->getDepth() != std::max(1, depth >> level)) + { + return false; + } + + return true; +} + +bool TextureD3D_3D::isImageComplete(const gl::ImageIndex &index) const +{ + return isLevelComplete(index.mipIndex); +} + +gl::Error TextureD3D_3D::updateStorageLevel(int level) +{ + ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL); + ASSERT(isLevelComplete(level)); + + if (mImageArray[level]->isDirty()) + { + gl::ImageIndex index = gl::ImageIndex::Make3D(level); + gl::Box region(0, 0, 0, getWidth(level), getHeight(level), getDepth(level)); + gl::Error error = commitRegion(index, region); + if (error.isError()) + { + return error; + } + } + + return gl::Error(GL_NO_ERROR); +} + +void TextureD3D_3D::redefineImage(GLint level, GLenum internalformat, const gl::Extents &size) +{ + // If there currently is a corresponding storage texture image, it has these parameters + const int storageWidth = std::max(1, getBaseLevelWidth() >> level); + const int storageHeight = std::max(1, getBaseLevelHeight() >> level); + const int storageDepth = std::max(1, getBaseLevelDepth() >> level); + const GLenum storageFormat = getBaseLevelInternalFormat(); + + mImageArray[level]->redefine(GL_TEXTURE_3D, internalformat, size, false); + + if (mTexStorage) + { + const int storageLevels = mTexStorage->getLevelCount(); + + if ((level >= storageLevels && storageLevels != 0) || + size.width != storageWidth || + size.height != storageHeight || + size.depth != storageDepth || + internalformat != storageFormat) // Discard mismatched storage + { + for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) + { + mImageArray[i]->markDirty(); + } + + SafeDelete(mTexStorage); + mDirtyImages = true; + } + } +} + +gl::ImageIndexIterator TextureD3D_3D::imageIterator() const +{ + return gl::ImageIndexIterator::Make3D(0, mTexStorage->getLevelCount(), + gl::ImageIndex::ENTIRE_LEVEL, gl::ImageIndex::ENTIRE_LEVEL); +} + +gl::ImageIndex TextureD3D_3D::getImageIndex(GLint mip, GLint /*layer*/) const +{ + // The "layer" here does not apply to 3D images. We use one Image per mip. + return gl::ImageIndex::Make3D(mip); +} + +bool TextureD3D_3D::isValidIndex(const gl::ImageIndex &index) const +{ + return (mTexStorage && index.type == GL_TEXTURE_3D && + index.mipIndex >= 0 && index.mipIndex < mTexStorage->getLevelCount()); +} + +TextureD3D_2DArray::TextureD3D_2DArray(RendererD3D *renderer) + : TextureD3D(renderer) +{ + for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level) + { + mLayerCounts[level] = 0; + mImageArray[level] = NULL; + } +} + +TextureD3D_2DArray::~TextureD3D_2DArray() +{ + // Delete the Images before the TextureStorage. + // Images might be relying on the TextureStorage for some of their data. + // If TextureStorage is deleted before the Images, then their data will be wastefully copied back from the GPU before we delete the Images. + deleteImages(); + SafeDelete(mTexStorage); +} + +ImageD3D *TextureD3D_2DArray::getImage(int level, int layer) const +{ + ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); + ASSERT((layer == 0 && mLayerCounts[level] == 0) || + layer < mLayerCounts[level]); + return (mImageArray[level] ? mImageArray[level][layer] : NULL); +} + +ImageD3D *TextureD3D_2DArray::getImage(const gl::ImageIndex &index) const +{ + ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); + ASSERT((index.layerIndex == 0 && mLayerCounts[index.mipIndex] == 0) || + index.layerIndex < mLayerCounts[index.mipIndex]); + ASSERT(index.type == GL_TEXTURE_2D_ARRAY); + return (mImageArray[index.mipIndex] ? mImageArray[index.mipIndex][index.layerIndex] : NULL); +} + +GLsizei TextureD3D_2DArray::getLayerCount(int level) const +{ + ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); + return mLayerCounts[level]; +} + +GLsizei TextureD3D_2DArray::getWidth(GLint level) const +{ + return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getWidth() : 0; +} + +GLsizei TextureD3D_2DArray::getHeight(GLint level) const +{ + return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getHeight() : 0; +} + +GLenum TextureD3D_2DArray::getInternalFormat(GLint level) const +{ + return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getInternalFormat() : GL_NONE; +} + +bool TextureD3D_2DArray::isDepth(GLint level) const +{ + return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0; +} + +gl::Error TextureD3D_2DArray::setImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size, GLenum format, GLenum type, + const gl::PixelUnpackState &unpack, const uint8_t *pixels) +{ + ASSERT(target == GL_TEXTURE_2D_ARRAY); + + GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type); + + redefineImage(level, sizedInternalFormat, size); + + const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(sizedInternalFormat); + GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, size.width, size.height, unpack.alignment, unpack.rowLength); + + for (int i = 0; i < size.depth; i++) + { + const ptrdiff_t layerOffset = (inputDepthPitch * i); + gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, i); + gl::Error error = TextureD3D::setImage(index, type, unpack, pixels, layerOffset); + if (error.isError()) + { + return error; + } + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureD3D_2DArray::setSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format, GLenum type, + const gl::PixelUnpackState &unpack, const uint8_t *pixels) +{ + ASSERT(target == GL_TEXTURE_2D_ARRAY); + + const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(getInternalFormat(level)); + GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, area.width, area.height, unpack.alignment, unpack.rowLength); + + for (int i = 0; i < area.depth; i++) + { + int layer = area.z + i; + const ptrdiff_t layerOffset = (inputDepthPitch * i); + + gl::Box layerArea(area.x, area.y, 0, area.width, area.height, 1); + + gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer); + gl::Error error = TextureD3D::subImage(index, layerArea, format, type, unpack, pixels, layerOffset); + if (error.isError()) + { + return error; + } + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureD3D_2DArray::setCompressedImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size, + const gl::PixelUnpackState &unpack, const uint8_t *pixels) +{ + ASSERT(target == GL_TEXTURE_2D_ARRAY); + + // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly + redefineImage(level, internalFormat, size); + + const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat); + GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, size.width, size.height, 1, 0); + + for (int i = 0; i < size.depth; i++) + { + const ptrdiff_t layerOffset = (inputDepthPitch * i); + + gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, i); + gl::Error error = TextureD3D::setCompressedImage(index, unpack, pixels, layerOffset); + if (error.isError()) + { + return error; + } + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureD3D_2DArray::setCompressedSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format, + const gl::PixelUnpackState &unpack, const uint8_t *pixels) +{ + ASSERT(target == GL_TEXTURE_2D_ARRAY); + + const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format); + GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, area.width, area.height, 1, 0); + + for (int i = 0; i < area.depth; i++) + { + int layer = area.z + i; + const ptrdiff_t layerOffset = (inputDepthPitch * i); + + gl::Box layerArea(area.x, area.y, 0, area.width, area.height, 1); + + gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer); + gl::Error error = TextureD3D::subImageCompressed(index, layerArea, format, unpack, pixels, layerOffset); + if (error.isError()) + { + return error; + } + + error = commitRegion(index, layerArea); + if (error.isError()) + { + return error; + } + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureD3D_2DArray::copyImage(GLenum target, size_t level, const gl::Rectangle &sourceArea, GLenum internalFormat, + const gl::Framebuffer *source) +{ + UNIMPLEMENTED(); + return gl::Error(GL_INVALID_OPERATION, "Copying 2D array textures is unimplemented."); +} + +gl::Error TextureD3D_2DArray::copySubImage(GLenum target, size_t level, const gl::Offset &destOffset, const gl::Rectangle &sourceArea, + const gl::Framebuffer *source) +{ + ASSERT(target == GL_TEXTURE_2D_ARRAY); + + gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, destOffset.z); + + if (canCreateRenderTargetForImage(index)) + { + gl::Offset destLayerOffset(destOffset.x, destOffset.y, 0); + gl::Error error = mImageArray[level][destOffset.z]->copy(destLayerOffset, sourceArea, source); + if (error.isError()) + { + return error; + } + + mDirtyImages = true; + } + else + { + gl::Error error = ensureRenderTarget(); + if (error.isError()) + { + return error; + } + + if (isValidLevel(level)) + { + error = updateStorageLevel(level); + if (error.isError()) + { + return error; + } + + error = mRenderer->copyImage2DArray(source, sourceArea, gl::GetInternalFormatInfo(getInternalFormat(0)).format, + destOffset, mTexStorage, level); + if (error.isError()) + { + return error; + } + } + } + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureD3D_2DArray::setStorage(GLenum target, size_t levels, GLenum internalFormat, const gl::Extents &size) +{ + ASSERT(target == GL_TEXTURE_2D_ARRAY); + + deleteImages(); + + for (size_t level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) + { + gl::Extents levelLayerSize(std::max(1, size.width >> level), + std::max(1, size.height >> level), + 1); + + mLayerCounts[level] = (level < levels ? size.depth : 0); + + if (mLayerCounts[level] > 0) + { + // Create new images for this level + mImageArray[level] = new ImageD3D*[mLayerCounts[level]]; + + for (int layer = 0; layer < mLayerCounts[level]; layer++) + { + mImageArray[level][layer] = mRenderer->createImage(); + mImageArray[level][layer]->redefine(GL_TEXTURE_2D_ARRAY, internalFormat, levelLayerSize, true); + } + } + } + + // TODO(geofflang): Verify storage creation had no errors + bool renderTarget = IsRenderTargetUsage(mUsage); + TextureStorage *storage = mRenderer->createTextureStorage2DArray(internalFormat, renderTarget, size.width, size.height, size.depth, levels); + + gl::Error error = setCompleteTexStorage(storage); + if (error.isError()) + { + SafeDelete(storage); + return error; + } + + error = updateStorage(); + + if (error.isError()) + { + return error; + } + + mImmutable = true; + + return gl::Error(GL_NO_ERROR); +} + +void TextureD3D_2DArray::bindTexImage(egl::Surface *surface) +{ + UNREACHABLE(); +} + +void TextureD3D_2DArray::releaseTexImage() +{ + UNREACHABLE(); +} + + +void TextureD3D_2DArray::initMipmapsImages() +{ + int baseWidth = getBaseLevelWidth(); + int baseHeight = getBaseLevelHeight(); + int baseDepth = getLayerCount(0); + GLenum baseFormat = getBaseLevelInternalFormat(); + + // Purge array levels 1 through q and reset them to represent the generated mipmap levels. + int levelCount = mipLevels(); + for (int level = 1; level < levelCount; level++) + { + gl::Extents levelLayerSize(std::max(baseWidth >> level, 1), + std::max(baseHeight >> level, 1), + baseDepth); + redefineImage(level, baseFormat, levelLayerSize); + } +} + +unsigned int TextureD3D_2DArray::getRenderTargetSerial(const gl::ImageIndex &index) +{ + return (!ensureRenderTarget().isError() ? mTexStorage->getRenderTargetSerial(index) : 0); +} + +gl::Error TextureD3D_2DArray::getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT) +{ + // ensure the underlying texture is created + gl::Error error = ensureRenderTarget(); + if (error.isError()) + { + return error; + } + + error = updateStorageLevel(index.mipIndex); + if (error.isError()) + { + return error; + } + + return mTexStorage->getRenderTarget(index, outRT); +} + +gl::Error TextureD3D_2DArray::initializeStorage(bool renderTarget) +{ + // Only initialize the first time this texture is used as a render target or shader resource + if (mTexStorage) + { + return gl::Error(GL_NO_ERROR); + } + + // do not attempt to create storage for nonexistant data + if (!isLevelComplete(0)) + { + return gl::Error(GL_NO_ERROR); + } + + bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage)); + + TextureStorage *storage = NULL; + gl::Error error = createCompleteStorage(createRenderTarget, &storage); + if (error.isError()) + { + return error; + } + + error = setCompleteTexStorage(storage); + if (error.isError()) + { + SafeDelete(storage); + return error; + } + + ASSERT(mTexStorage); + + // flush image data to the storage + error = updateStorage(); + if (error.isError()) + { + return error; + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureD3D_2DArray::createCompleteStorage(bool renderTarget, TextureStorage **outStorage) const +{ + GLsizei width = getBaseLevelWidth(); + GLsizei height = getBaseLevelHeight(); + GLsizei depth = getLayerCount(0); + GLenum internalFormat = getBaseLevelInternalFormat(); + + ASSERT(width > 0 && height > 0 && depth > 0); + + // use existing storage level count, when previously specified by TexStorage*D + GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1)); + + // TODO(geofflang): Verify storage creation succeeds + *outStorage = mRenderer->createTextureStorage2DArray(internalFormat, renderTarget, width, height, depth, levels); + + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureD3D_2DArray::setCompleteTexStorage(TextureStorage *newCompleteTexStorage) +{ + SafeDelete(mTexStorage); + mTexStorage = newCompleteTexStorage; + mDirtyImages = true; + + // We do not support managed 2D array storage, as managed storage is ES2/D3D9 only + ASSERT(!mTexStorage->isManaged()); + + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureD3D_2DArray::updateStorage() +{ + ASSERT(mTexStorage != NULL); + GLint storageLevels = mTexStorage->getLevelCount(); + for (int level = 0; level < storageLevels; level++) + { + if (isLevelComplete(level)) + { + gl::Error error = updateStorageLevel(level); + if (error.isError()) + { + return error; + } + } + } + + return gl::Error(GL_NO_ERROR); +} + +bool TextureD3D_2DArray::isValidLevel(int level) const +{ + return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0); +} + +bool TextureD3D_2DArray::isLevelComplete(int level) const +{ + ASSERT(level >= 0 && level < (int)ArraySize(mImageArray)); + + if (isImmutable()) + { + return true; + } + + GLsizei width = getBaseLevelWidth(); + GLsizei height = getBaseLevelHeight(); + GLsizei layers = getLayerCount(0); + + if (width <= 0 || height <= 0 || layers <= 0) + { + return false; + } + + if (level == 0) + { + return true; + } + + if (getInternalFormat(level) != getInternalFormat(0)) + { + return false; + } + + if (getWidth(level) != std::max(1, width >> level)) + { + return false; + } + + if (getHeight(level) != std::max(1, height >> level)) + { + return false; + } + + if (getLayerCount(level) != layers) + { + return false; + } + + return true; +} + +bool TextureD3D_2DArray::isImageComplete(const gl::ImageIndex &index) const +{ + return isLevelComplete(index.mipIndex); +} + +gl::Error TextureD3D_2DArray::updateStorageLevel(int level) +{ + ASSERT(level >= 0 && level < (int)ArraySize(mLayerCounts)); + ASSERT(isLevelComplete(level)); + + for (int layer = 0; layer < mLayerCounts[level]; layer++) + { + ASSERT(mImageArray[level] != NULL && mImageArray[level][layer] != NULL); + if (mImageArray[level][layer]->isDirty()) + { + gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer); + gl::Box region(0, 0, 0, getWidth(level), getHeight(level), 1); + gl::Error error = commitRegion(index, region); + if (error.isError()) + { + return error; + } + } + } + + return gl::Error(GL_NO_ERROR); +} + +void TextureD3D_2DArray::deleteImages() +{ + for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level) + { + for (int layer = 0; layer < mLayerCounts[level]; ++layer) + { + delete mImageArray[level][layer]; + } + delete[] mImageArray[level]; + mImageArray[level] = NULL; + mLayerCounts[level] = 0; + } +} + +void TextureD3D_2DArray::redefineImage(GLint level, GLenum internalformat, const gl::Extents &size) +{ + // If there currently is a corresponding storage texture image, it has these parameters + const int storageWidth = std::max(1, getBaseLevelWidth() >> level); + const int storageHeight = std::max(1, getBaseLevelHeight() >> level); + const int storageDepth = getLayerCount(0); + const GLenum storageFormat = getBaseLevelInternalFormat(); + + for (int layer = 0; layer < mLayerCounts[level]; layer++) + { + delete mImageArray[level][layer]; + } + delete[] mImageArray[level]; + mImageArray[level] = NULL; + mLayerCounts[level] = size.depth; + + if (size.depth > 0) + { + mImageArray[level] = new ImageD3D*[size.depth](); + + for (int layer = 0; layer < mLayerCounts[level]; layer++) + { + mImageArray[level][layer] = mRenderer->createImage(); + mImageArray[level][layer]->redefine(GL_TEXTURE_2D_ARRAY, internalformat, + gl::Extents(size.width, size.height, 1), false); + } + } + + if (mTexStorage) + { + const int storageLevels = mTexStorage->getLevelCount(); + + if ((level >= storageLevels && storageLevels != 0) || + size.width != storageWidth || + size.height != storageHeight || + size.depth != storageDepth || + internalformat != storageFormat) // Discard mismatched storage + { + for (int dirtyLevel = 0; dirtyLevel < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; dirtyLevel++) + { + for (int dirtyLayer = 0; dirtyLayer < mLayerCounts[dirtyLevel]; dirtyLayer++) + { + mImageArray[dirtyLevel][dirtyLayer]->markDirty(); + } + } + + delete mTexStorage; + mTexStorage = NULL; + mDirtyImages = true; + } + } +} + +gl::ImageIndexIterator TextureD3D_2DArray::imageIterator() const +{ + return gl::ImageIndexIterator::Make2DArray(0, mTexStorage->getLevelCount(), mLayerCounts); +} + +gl::ImageIndex TextureD3D_2DArray::getImageIndex(GLint mip, GLint layer) const +{ + return gl::ImageIndex::Make2DArray(mip, layer); +} + +bool TextureD3D_2DArray::isValidIndex(const gl::ImageIndex &index) const +{ + // Check for having a storage and the right type of index + if (!mTexStorage || index.type != GL_TEXTURE_2D_ARRAY) + { + return false; + } + + // Check the mip index + if (index.mipIndex < 0 || index.mipIndex >= mTexStorage->getLevelCount()) + { + return false; + } + + // Check the layer index + return (!index.hasLayer() || (index.layerIndex >= 0 && index.layerIndex < mLayerCounts[index.mipIndex])); +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/TextureD3D.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/TextureD3D.h new file mode 100644 index 0000000000..d94be49a08 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/TextureD3D.h @@ -0,0 +1,364 @@ +// +// Copyright 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// TextureD3D.h: Implementations of the Texture interfaces shared betweeen the D3D backends. + +#ifndef LIBANGLE_RENDERER_D3D_TEXTURED3D_H_ +#define LIBANGLE_RENDERER_D3D_TEXTURED3D_H_ + +#include "libANGLE/renderer/TextureImpl.h" +#include "libANGLE/angletypes.h" +#include "libANGLE/Constants.h" + +namespace gl +{ +class Framebuffer; +} + +namespace rx +{ + +class ImageD3D; +class ImageD3D; +class RendererD3D; +class RenderTargetD3D; +class TextureStorage; + +class TextureD3D : public TextureImpl +{ + public: + TextureD3D(RendererD3D *renderer); + virtual ~TextureD3D(); + + gl::Error getNativeTexture(TextureStorage **outStorage); + + virtual void setUsage(GLenum usage) { mUsage = usage; } + bool hasDirtyImages() const { return mDirtyImages; } + void resetDirty() { mDirtyImages = false; } + + virtual ImageD3D *getImage(const gl::ImageIndex &index) const = 0; + virtual GLsizei getLayerCount(int level) const = 0; + + GLint getBaseLevelWidth() const; + GLint getBaseLevelHeight() const; + GLint getBaseLevelDepth() const; + GLenum getBaseLevelInternalFormat() const; + + bool isImmutable() const { return mImmutable; } + + virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT) = 0; + virtual unsigned int getRenderTargetSerial(const gl::ImageIndex &index) = 0; + + // Returns an iterator over all "Images" for this particular Texture. + virtual gl::ImageIndexIterator imageIterator() const = 0; + + // Returns an ImageIndex for a particular "Image". 3D Textures do not have images for + // slices of their depth texures, so 3D textures ignore the layer parameter. + virtual gl::ImageIndex getImageIndex(GLint mip, GLint layer) const = 0; + virtual bool isValidIndex(const gl::ImageIndex &index) const = 0; + + virtual gl::Error generateMipmaps(); + TextureStorage *getStorage(); + ImageD3D *getBaseLevelImage() const; + + protected: + gl::Error setImage(const gl::ImageIndex &index, GLenum type, + const gl::PixelUnpackState &unpack, const uint8_t *pixels, + ptrdiff_t layerOffset); + gl::Error subImage(const gl::ImageIndex &index, const gl::Box &area, GLenum format, GLenum type, + const gl::PixelUnpackState &unpack, const uint8_t *pixels, ptrdiff_t layerOffset); + gl::Error setCompressedImage(const gl::ImageIndex &index, const gl::PixelUnpackState &unpack, + const uint8_t *pixels, ptrdiff_t layerOffset); + gl::Error subImageCompressed(const gl::ImageIndex &index, const gl::Box &area, GLenum format, + const gl::PixelUnpackState &unpack, const uint8_t *pixels, ptrdiff_t layerOffset); + bool isFastUnpackable(const gl::PixelUnpackState &unpack, GLenum sizedInternalFormat); + gl::Error fastUnpackPixels(const gl::PixelUnpackState &unpack, const uint8_t *pixels, const gl::Box &destArea, + GLenum sizedInternalFormat, GLenum type, RenderTargetD3D *destRenderTarget); + + GLint creationLevels(GLsizei width, GLsizei height, GLsizei depth) const; + int mipLevels() const; + virtual void initMipmapsImages() = 0; + bool isBaseImageZeroSize() const; + virtual bool isImageComplete(const gl::ImageIndex &index) const = 0; + + bool canCreateRenderTargetForImage(const gl::ImageIndex &index) const; + virtual gl::Error ensureRenderTarget(); + + virtual gl::Error createCompleteStorage(bool renderTarget, TextureStorage **outTexStorage) const = 0; + virtual gl::Error setCompleteTexStorage(TextureStorage *newCompleteTexStorage) = 0; + gl::Error commitRegion(const gl::ImageIndex &index, const gl::Box ®ion); + + RendererD3D *mRenderer; + + GLenum mUsage; + + bool mDirtyImages; + + bool mImmutable; + TextureStorage *mTexStorage; + + private: + virtual gl::Error initializeStorage(bool renderTarget) = 0; + + virtual gl::Error updateStorage() = 0; + + bool shouldUseSetData(const ImageD3D *image) const; +}; + +class TextureD3D_2D : public TextureD3D +{ + public: + TextureD3D_2D(RendererD3D *renderer); + virtual ~TextureD3D_2D(); + + virtual ImageD3D *getImage(int level, int layer) const; + virtual ImageD3D *getImage(const gl::ImageIndex &index) const; + virtual GLsizei getLayerCount(int level) const; + + GLsizei getWidth(GLint level) const; + GLsizei getHeight(GLint level) const; + GLenum getInternalFormat(GLint level) const; + bool isDepth(GLint level) const; + + gl::Error setImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size, GLenum format, GLenum type, + const gl::PixelUnpackState &unpack, const uint8_t *pixels) override; + gl::Error setSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format, GLenum type, + const gl::PixelUnpackState &unpack, const uint8_t *pixels) override; + + gl::Error setCompressedImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size, + const gl::PixelUnpackState &unpack, const uint8_t *pixels) override; + gl::Error setCompressedSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format, + const gl::PixelUnpackState &unpack, const uint8_t *pixels) override; + + gl::Error copyImage(GLenum target, size_t level, const gl::Rectangle &sourceArea, GLenum internalFormat, + const gl::Framebuffer *source) override; + gl::Error copySubImage(GLenum target, size_t level, const gl::Offset &destOffset, const gl::Rectangle &sourceArea, + const gl::Framebuffer *source) override; + + gl::Error setStorage(GLenum target, size_t levels, GLenum internalFormat, const gl::Extents &size) override; + + virtual void bindTexImage(egl::Surface *surface); + virtual void releaseTexImage(); + + virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT); + virtual unsigned int getRenderTargetSerial(const gl::ImageIndex &index); + + virtual gl::ImageIndexIterator imageIterator() const; + virtual gl::ImageIndex getImageIndex(GLint mip, GLint layer) const; + virtual bool isValidIndex(const gl::ImageIndex &index) const; + + private: + virtual gl::Error initializeStorage(bool renderTarget); + virtual gl::Error createCompleteStorage(bool renderTarget, TextureStorage **outTexStorage) const; + virtual gl::Error setCompleteTexStorage(TextureStorage *newCompleteTexStorage); + + virtual gl::Error updateStorage(); + virtual void initMipmapsImages(); + + bool isValidLevel(int level) const; + bool isLevelComplete(int level) const; + virtual bool isImageComplete(const gl::ImageIndex &index) const; + + gl::Error updateStorageLevel(int level); + + void redefineImage(GLint level, GLenum internalformat, const gl::Extents &size); + + ImageD3D *mImageArray[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; +}; + +class TextureD3D_Cube : public TextureD3D +{ + public: + TextureD3D_Cube(RendererD3D *renderer); + virtual ~TextureD3D_Cube(); + + virtual ImageD3D *getImage(int level, int layer) const; + virtual ImageD3D *getImage(const gl::ImageIndex &index) const; + virtual GLsizei getLayerCount(int level) const; + + virtual bool hasDirtyImages() const { return mDirtyImages; } + virtual void resetDirty() { mDirtyImages = false; } + virtual void setUsage(GLenum usage) { mUsage = usage; } + + GLenum getInternalFormat(GLint level, GLint layer) const; + bool isDepth(GLint level, GLint layer) const; + + gl::Error setImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size, GLenum format, GLenum type, + const gl::PixelUnpackState &unpack, const uint8_t *pixels) override; + gl::Error setSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format, GLenum type, + const gl::PixelUnpackState &unpack, const uint8_t *pixels) override; + + gl::Error setCompressedImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size, + const gl::PixelUnpackState &unpack, const uint8_t *pixels) override; + gl::Error setCompressedSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format, + const gl::PixelUnpackState &unpack, const uint8_t *pixels) override; + + gl::Error copyImage(GLenum target, size_t level, const gl::Rectangle &sourceArea, GLenum internalFormat, + const gl::Framebuffer *source) override; + gl::Error copySubImage(GLenum target, size_t level, const gl::Offset &destOffset, const gl::Rectangle &sourceArea, + const gl::Framebuffer *source) override; + + gl::Error setStorage(GLenum target, size_t levels, GLenum internalFormat, const gl::Extents &size) override; + + virtual void bindTexImage(egl::Surface *surface); + virtual void releaseTexImage(); + + virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT); + virtual unsigned int getRenderTargetSerial(const gl::ImageIndex &index); + + virtual gl::ImageIndexIterator imageIterator() const; + virtual gl::ImageIndex getImageIndex(GLint mip, GLint layer) const; + virtual bool isValidIndex(const gl::ImageIndex &index) const; + + private: + virtual gl::Error initializeStorage(bool renderTarget); + virtual gl::Error createCompleteStorage(bool renderTarget, TextureStorage **outTexStorage) const; + virtual gl::Error setCompleteTexStorage(TextureStorage *newCompleteTexStorage); + + virtual gl::Error updateStorage(); + virtual void initMipmapsImages(); + + bool isValidFaceLevel(int faceIndex, int level) const; + bool isFaceLevelComplete(int faceIndex, int level) const; + bool isCubeComplete() const; + virtual bool isImageComplete(const gl::ImageIndex &index) const; + gl::Error updateStorageFaceLevel(int faceIndex, int level); + + void redefineImage(int faceIndex, GLint level, GLenum internalformat, const gl::Extents &size); + + ImageD3D *mImageArray[6][gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; +}; + +class TextureD3D_3D : public TextureD3D +{ + public: + TextureD3D_3D(RendererD3D *renderer); + virtual ~TextureD3D_3D(); + + virtual ImageD3D *getImage(int level, int layer) const; + virtual ImageD3D *getImage(const gl::ImageIndex &index) const; + virtual GLsizei getLayerCount(int level) const; + + GLsizei getWidth(GLint level) const; + GLsizei getHeight(GLint level) const; + GLsizei getDepth(GLint level) const; + GLenum getInternalFormat(GLint level) const; + bool isDepth(GLint level) const; + + gl::Error setImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size, GLenum format, GLenum type, + const gl::PixelUnpackState &unpack, const uint8_t *pixels) override; + gl::Error setSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format, GLenum type, + const gl::PixelUnpackState &unpack, const uint8_t *pixels) override; + + gl::Error setCompressedImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size, + const gl::PixelUnpackState &unpack, const uint8_t *pixels) override; + gl::Error setCompressedSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format, + const gl::PixelUnpackState &unpack, const uint8_t *pixels) override; + + gl::Error copyImage(GLenum target, size_t level, const gl::Rectangle &sourceArea, GLenum internalFormat, + const gl::Framebuffer *source) override; + gl::Error copySubImage(GLenum target, size_t level, const gl::Offset &destOffset, const gl::Rectangle &sourceArea, + const gl::Framebuffer *source) override; + + gl::Error setStorage(GLenum target, size_t levels, GLenum internalFormat, const gl::Extents &size) override; + + virtual void bindTexImage(egl::Surface *surface); + virtual void releaseTexImage(); + + virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT); + virtual unsigned int getRenderTargetSerial(const gl::ImageIndex &index); + + virtual gl::ImageIndexIterator imageIterator() const; + virtual gl::ImageIndex getImageIndex(GLint mip, GLint layer) const; + virtual bool isValidIndex(const gl::ImageIndex &index) const; + + private: + virtual gl::Error initializeStorage(bool renderTarget); + virtual gl::Error createCompleteStorage(bool renderTarget, TextureStorage **outStorage) const; + virtual gl::Error setCompleteTexStorage(TextureStorage *newCompleteTexStorage); + + virtual gl::Error updateStorage(); + virtual void initMipmapsImages(); + + bool isValidLevel(int level) const; + bool isLevelComplete(int level) const; + virtual bool isImageComplete(const gl::ImageIndex &index) const; + gl::Error updateStorageLevel(int level); + + void redefineImage(GLint level, GLenum internalformat, const gl::Extents &size); + + ImageD3D *mImageArray[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; +}; + +class TextureD3D_2DArray : public TextureD3D +{ + public: + TextureD3D_2DArray(RendererD3D *renderer); + virtual ~TextureD3D_2DArray(); + + virtual ImageD3D *getImage(int level, int layer) const; + virtual ImageD3D *getImage(const gl::ImageIndex &index) const; + virtual GLsizei getLayerCount(int level) const; + + GLsizei getWidth(GLint level) const; + GLsizei getHeight(GLint level) const; + GLenum getInternalFormat(GLint level) const; + bool isDepth(GLint level) const; + + gl::Error setImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size, GLenum format, GLenum type, + const gl::PixelUnpackState &unpack, const uint8_t *pixels) override; + gl::Error setSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format, GLenum type, + const gl::PixelUnpackState &unpack, const uint8_t *pixels) override; + + gl::Error setCompressedImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size, + const gl::PixelUnpackState &unpack, const uint8_t *pixels) override; + gl::Error setCompressedSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format, + const gl::PixelUnpackState &unpack, const uint8_t *pixels) override; + + gl::Error copyImage(GLenum target, size_t level, const gl::Rectangle &sourceArea, GLenum internalFormat, + const gl::Framebuffer *source) override; + gl::Error copySubImage(GLenum target, size_t level, const gl::Offset &destOffset, const gl::Rectangle &sourceArea, + const gl::Framebuffer *source) override; + + gl::Error setStorage(GLenum target, size_t levels, GLenum internalFormat, const gl::Extents &size) override; + + virtual void bindTexImage(egl::Surface *surface); + virtual void releaseTexImage(); + + virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT); + virtual unsigned int getRenderTargetSerial(const gl::ImageIndex &index); + + virtual gl::ImageIndexIterator imageIterator() const; + virtual gl::ImageIndex getImageIndex(GLint mip, GLint layer) const; + virtual bool isValidIndex(const gl::ImageIndex &index) const; + + private: + virtual gl::Error initializeStorage(bool renderTarget); + virtual gl::Error createCompleteStorage(bool renderTarget, TextureStorage **outStorage) const; + virtual gl::Error setCompleteTexStorage(TextureStorage *newCompleteTexStorage); + + virtual gl::Error updateStorage(); + virtual void initMipmapsImages(); + + bool isValidLevel(int level) const; + bool isLevelComplete(int level) const; + virtual bool isImageComplete(const gl::ImageIndex &index) const; + gl::Error updateStorageLevel(int level); + + void deleteImages(); + void redefineImage(GLint level, GLenum internalformat, const gl::Extents &size); + + // Storing images as an array of single depth textures since D3D11 treats each array level of a + // Texture2D object as a separate subresource. Each layer would have to be looped over + // to update all the texture layers since they cannot all be updated at once and it makes the most + // sense for the Image class to not have to worry about layer subresource as well as mip subresources. + GLsizei mLayerCounts[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; + ImageD3D **mImageArray[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_TEXTURED3D_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/TextureStorage.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/TextureStorage.cpp new file mode 100644 index 0000000000..abb83a14d5 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/TextureStorage.cpp @@ -0,0 +1,39 @@ +// +// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// TextureStorage.cpp: Shared members of abstract rx::TextureStorage class. + +#include "libANGLE/renderer/d3d/TextureStorage.h" +#include "libANGLE/renderer/d3d/TextureD3D.h" +#include "libANGLE/renderer/d3d/RenderTargetD3D.h" +#include "libANGLE/renderer/Renderer.h" +#include "libANGLE/Renderbuffer.h" +#include "libANGLE/Texture.h" + +#include "common/debug.h" +#include "common/mathutil.h" + +namespace rx +{ + +TextureStorage::TextureStorage() + : mFirstRenderTargetSerial(0), + mRenderTargetSerialsLayerStride(0) +{} + +void TextureStorage::initializeSerials(unsigned int rtSerialsToReserve, unsigned int rtSerialsLayerStride) +{ + mFirstRenderTargetSerial = RenderTargetD3D::issueSerials(rtSerialsToReserve); + mRenderTargetSerialsLayerStride = rtSerialsLayerStride; +} + +unsigned int TextureStorage::getRenderTargetSerial(const gl::ImageIndex &index) const +{ + unsigned int layerOffset = (index.hasLayer() ? (static_cast(index.layerIndex) * mRenderTargetSerialsLayerStride) : 0); + return mFirstRenderTargetSerial + static_cast(index.mipIndex) + layerOffset; +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/TextureStorage.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/TextureStorage.h new file mode 100644 index 0000000000..ae2d42ca8a --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/TextureStorage.h @@ -0,0 +1,67 @@ +// +// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// TextureStorage.h: Defines the abstract rx::TextureStorage class. + +#ifndef LIBANGLE_RENDERER_D3D_TEXTURESTORAGE_H_ +#define LIBANGLE_RENDERER_D3D_TEXTURESTORAGE_H_ + +#include "libANGLE/Error.h" + +#include "common/debug.h" +#include "libANGLE/Error.h" + +#include +#include + +namespace gl +{ +struct ImageIndex; +struct Box; +struct PixelUnpackState; +} + +namespace rx +{ +class SwapChainD3D; +class RenderTargetD3D; +class ImageD3D; + +class TextureStorage : angle::NonCopyable +{ + public: + TextureStorage(); + virtual ~TextureStorage() {}; + + virtual int getTopLevel() const = 0; + virtual bool isRenderTarget() const = 0; + virtual bool isManaged() const = 0; + virtual int getLevelCount() const = 0; + + virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT) = 0; + virtual gl::Error generateMipmap(const gl::ImageIndex &sourceIndex, const gl::ImageIndex &destIndex) = 0; + + virtual gl::Error copyToStorage(TextureStorage *destStorage) = 0; + virtual gl::Error setData(const gl::ImageIndex &index, ImageD3D *image, const gl::Box *destBox, GLenum type, + const gl::PixelUnpackState &unpack, const uint8_t *pixelData) = 0; + + unsigned int getRenderTargetSerial(const gl::ImageIndex &index) const; + unsigned int getTextureSerial() const; + + // This is a no-op for most implementations of TextureStorage. Some (e.g. TextureStorage11_2D) might override it. + virtual gl::Error useLevelZeroWorkaroundTexture(bool useLevelZeroTexture) { return gl::Error(GL_NO_ERROR); } + + protected: + void initializeSerials(unsigned int rtSerialsToReserve, unsigned int rtSerialsLayerStride); + + private: + unsigned int mFirstRenderTargetSerial; + unsigned int mRenderTargetSerialsLayerStride; +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_TEXTURESTORAGE_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/TransformFeedbackD3D.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/TransformFeedbackD3D.cpp new file mode 100644 index 0000000000..5c0bfdcd5b --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/TransformFeedbackD3D.cpp @@ -0,0 +1,38 @@ +// +// Copyright 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// TransformFeedbackD3D.cpp is a no-op implementation for both the D3D9 and D3D11 renderers. + +#include "libANGLE/renderer/d3d/TransformFeedbackD3D.h" + +namespace rx +{ + +TransformFeedbackD3D::TransformFeedbackD3D() +{ +} + +TransformFeedbackD3D::~TransformFeedbackD3D() +{ +} + +void TransformFeedbackD3D::begin(GLenum primitiveMode) +{ +} + +void TransformFeedbackD3D::end() +{ +} + +void TransformFeedbackD3D::pause() +{ +} + +void TransformFeedbackD3D::resume() +{ +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/TransformFeedbackD3D.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/TransformFeedbackD3D.h new file mode 100644 index 0000000000..6b255b4a2b --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/TransformFeedbackD3D.h @@ -0,0 +1,32 @@ +// +// Copyright 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// TransformFeedbackD3D.h: Implements the abstract rx::TransformFeedbackImpl class. + +#ifndef LIBANGLE_RENDERER_D3D_TRANSFORMFEEDBACKD3D_H_ +#define LIBANGLE_RENDERER_D3D_TRANSFORMFEEDBACKD3D_H_ + +#include "libANGLE/renderer/TransformFeedbackImpl.h" +#include "libANGLE/angletypes.h" + +namespace rx +{ + +class TransformFeedbackD3D : public TransformFeedbackImpl +{ + public: + TransformFeedbackD3D(); + virtual ~TransformFeedbackD3D(); + + virtual void begin(GLenum primitiveMode); + virtual void end(); + virtual void pause(); + virtual void resume(); +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_TRANSFORMFEEDBACKD3D_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/VertexBuffer.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/VertexBuffer.cpp new file mode 100644 index 0000000000..19bd548fce --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/VertexBuffer.cpp @@ -0,0 +1,311 @@ +// +// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// VertexBuffer.cpp: Defines the abstract VertexBuffer class and VertexBufferInterface +// class with derivations, classes that perform graphics API agnostic vertex buffer operations. + +#include "libANGLE/renderer/d3d/VertexBuffer.h" +#include "libANGLE/renderer/d3d/BufferD3D.h" +#include "libANGLE/renderer/d3d/RendererD3D.h" +#include "libANGLE/VertexAttribute.h" + +#include "common/mathutil.h" + +namespace rx +{ + +unsigned int VertexBuffer::mNextSerial = 1; + +VertexBuffer::VertexBuffer() +{ + updateSerial(); +} + +VertexBuffer::~VertexBuffer() +{ +} + +void VertexBuffer::updateSerial() +{ + mSerial = mNextSerial++; +} + +unsigned int VertexBuffer::getSerial() const +{ + return mSerial; +} + +VertexBufferInterface::VertexBufferInterface(BufferFactoryD3D *factory, bool dynamic) + : mFactory(factory) +{ + mDynamic = dynamic; + mWritePosition = 0; + mReservedSpace = 0; + + mVertexBuffer = factory->createVertexBuffer(); +} + +VertexBufferInterface::~VertexBufferInterface() +{ + delete mVertexBuffer; +} + +unsigned int VertexBufferInterface::getSerial() const +{ + return mVertexBuffer->getSerial(); +} + +unsigned int VertexBufferInterface::getBufferSize() const +{ + return mVertexBuffer->getBufferSize(); +} + +gl::Error VertexBufferInterface::setBufferSize(unsigned int size) +{ + if (mVertexBuffer->getBufferSize() == 0) + { + return mVertexBuffer->initialize(size, mDynamic); + } + else + { + return mVertexBuffer->setBufferSize(size); + } +} + +unsigned int VertexBufferInterface::getWritePosition() const +{ + return mWritePosition; +} + +void VertexBufferInterface::setWritePosition(unsigned int writePosition) +{ + mWritePosition = writePosition; +} + +gl::Error VertexBufferInterface::discard() +{ + return mVertexBuffer->discard(); +} + +gl::Error VertexBufferInterface::storeVertexAttributes(const gl::VertexAttribute &attrib, const gl::VertexAttribCurrentValueData ¤tValue, + GLint start, GLsizei count, GLsizei instances, unsigned int *outStreamOffset) +{ + gl::Error error(GL_NO_ERROR); + + unsigned int spaceRequired; + error = mVertexBuffer->getSpaceRequired(attrib, count, instances, &spaceRequired); + if (error.isError()) + { + return error; + } + + if (mWritePosition + spaceRequired < mWritePosition) + { + return gl::Error(GL_OUT_OF_MEMORY, "Internal error, new vertex buffer write position would overflow."); + } + + error = reserveSpace(mReservedSpace); + if (error.isError()) + { + return error; + } + mReservedSpace = 0; + + error = mVertexBuffer->storeVertexAttributes(attrib, currentValue, start, count, instances, mWritePosition); + if (error.isError()) + { + return error; + } + + if (outStreamOffset) + { + *outStreamOffset = mWritePosition; + } + + mWritePosition += spaceRequired; + + // Align to 16-byte boundary + mWritePosition = roundUp(mWritePosition, 16u); + + return gl::Error(GL_NO_ERROR); +} + +gl::Error VertexBufferInterface::reserveVertexSpace(const gl::VertexAttribute &attrib, GLsizei count, GLsizei instances) +{ + gl::Error error(GL_NO_ERROR); + + unsigned int requiredSpace; + error = mVertexBuffer->getSpaceRequired(attrib, count, instances, &requiredSpace); + if (error.isError()) + { + return error; + } + + // Protect against integer overflow + if (mReservedSpace + requiredSpace < mReservedSpace) + { + return gl::Error(GL_OUT_OF_MEMORY, "Unable to reserve %u extra bytes in internal vertex buffer, " + "it would result in an overflow.", requiredSpace); + } + + mReservedSpace += requiredSpace; + + // Align to 16-byte boundary + mReservedSpace = roundUp(mReservedSpace, 16u); + + return gl::Error(GL_NO_ERROR); +} + +VertexBuffer* VertexBufferInterface::getVertexBuffer() const +{ + return mVertexBuffer; +} + +bool VertexBufferInterface::directStoragePossible(const gl::VertexAttribute &attrib, + const gl::VertexAttribCurrentValueData ¤tValue) const +{ + gl::Buffer *buffer = attrib.buffer.get(); + BufferD3D *storage = buffer ? GetImplAs(buffer) : NULL; + + if (!storage || !storage->supportsDirectBinding()) + { + return false; + } + + // Alignment restrictions: In D3D, vertex data must be aligned to + // the format stride, or to a 4-byte boundary, whichever is smaller. + // (Undocumented, and experimentally confirmed) + size_t alignment = 4; + bool requiresConversion = false; + + if (attrib.type != GL_FLOAT) + { + gl::VertexFormat vertexFormat(attrib, currentValue.Type); + + unsigned int outputElementSize; + getVertexBuffer()->getSpaceRequired(attrib, 1, 0, &outputElementSize); + alignment = std::min(outputElementSize, 4); + + // TODO(jmadill): add VertexFormatCaps + requiresConversion = (mFactory->getVertexConversionType(vertexFormat) & VERTEX_CONVERT_CPU) != 0; + } + + bool isAligned = (static_cast(ComputeVertexAttributeStride(attrib)) % alignment == 0) && + (static_cast(attrib.offset) % alignment == 0); + + return !requiresConversion && isAligned; +} + +StreamingVertexBufferInterface::StreamingVertexBufferInterface(BufferFactoryD3D *factory, std::size_t initialSize) + : VertexBufferInterface(factory, true) +{ + setBufferSize(initialSize); +} + +StreamingVertexBufferInterface::~StreamingVertexBufferInterface() +{ +} + +gl::Error StreamingVertexBufferInterface::reserveSpace(unsigned int size) +{ + unsigned int curBufferSize = getBufferSize(); + if (size > curBufferSize) + { + gl::Error error = setBufferSize(std::max(size, 3 * curBufferSize / 2)); + if (error.isError()) + { + return error; + } + setWritePosition(0); + } + else if (getWritePosition() + size > curBufferSize) + { + gl::Error error = discard(); + if (error.isError()) + { + return error; + } + setWritePosition(0); + } + + return gl::Error(GL_NO_ERROR); +} + +StaticVertexBufferInterface::StaticVertexBufferInterface(BufferFactoryD3D *factory) + : VertexBufferInterface(factory, false) +{ +} + +StaticVertexBufferInterface::~StaticVertexBufferInterface() +{ +} + +bool StaticVertexBufferInterface::lookupAttribute(const gl::VertexAttribute &attrib, unsigned int *outStreamOffset) +{ + for (unsigned int element = 0; element < mCache.size(); element++) + { + if (mCache[element].type == attrib.type && + mCache[element].size == attrib.size && + mCache[element].stride == ComputeVertexAttributeStride(attrib) && + mCache[element].normalized == attrib.normalized && + mCache[element].pureInteger == attrib.pureInteger) + { + size_t offset = (static_cast(attrib.offset) % ComputeVertexAttributeStride(attrib)); + if (mCache[element].attributeOffset == offset) + { + if (outStreamOffset) + { + *outStreamOffset = mCache[element].streamOffset; + } + return true; + } + } + } + + return false; +} + +gl::Error StaticVertexBufferInterface::reserveSpace(unsigned int size) +{ + unsigned int curSize = getBufferSize(); + if (curSize == 0) + { + return setBufferSize(size); + } + else if (curSize >= size) + { + return gl::Error(GL_NO_ERROR); + } + else + { + UNREACHABLE(); + return gl::Error(GL_INVALID_OPERATION, "Internal error, Static vertex buffers can't be resized."); + } +} + +gl::Error StaticVertexBufferInterface::storeVertexAttributes(const gl::VertexAttribute &attrib, const gl::VertexAttribCurrentValueData ¤tValue, + GLint start, GLsizei count, GLsizei instances, unsigned int *outStreamOffset) +{ + unsigned int streamOffset; + gl::Error error = VertexBufferInterface::storeVertexAttributes(attrib, currentValue, start, count, instances, &streamOffset); + if (error.isError()) + { + return error; + } + + size_t attributeOffset = static_cast(attrib.offset) % ComputeVertexAttributeStride(attrib); + VertexElement element = { attrib.type, attrib.size, static_cast(ComputeVertexAttributeStride(attrib)), attrib.normalized, attrib.pureInteger, attributeOffset, streamOffset }; + mCache.push_back(element); + + if (outStreamOffset) + { + *outStreamOffset = streamOffset; + } + + return gl::Error(GL_NO_ERROR); +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/VertexBuffer.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/VertexBuffer.h new file mode 100644 index 0000000000..5cb03fe3a1 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/VertexBuffer.h @@ -0,0 +1,143 @@ +// +// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// VertexBuffer.h: Defines the abstract VertexBuffer class and VertexBufferInterface +// class with derivations, classes that perform graphics API agnostic vertex buffer operations. + +#ifndef LIBANGLE_RENDERER_D3D_VERTEXBUFFER_H_ +#define LIBANGLE_RENDERER_D3D_VERTEXBUFFER_H_ + +#include "common/angleutils.h" +#include "libANGLE/Error.h" + +#include + +#include +#include + +namespace gl +{ +struct VertexAttribute; +struct VertexAttribCurrentValueData; +} + +namespace rx +{ +class BufferFactoryD3D; + +class VertexBuffer : angle::NonCopyable +{ + public: + VertexBuffer(); + virtual ~VertexBuffer(); + + virtual gl::Error initialize(unsigned int size, bool dynamicUsage) = 0; + + virtual gl::Error storeVertexAttributes(const gl::VertexAttribute &attrib, const gl::VertexAttribCurrentValueData ¤tValue, + GLint start, GLsizei count, GLsizei instances, unsigned int offset) = 0; + virtual gl::Error getSpaceRequired(const gl::VertexAttribute &attrib, GLsizei count, GLsizei instances, + unsigned int *outSpaceRequired) const = 0; + + virtual unsigned int getBufferSize() const = 0; + virtual gl::Error setBufferSize(unsigned int size) = 0; + virtual gl::Error discard() = 0; + + unsigned int getSerial() const; + + // This may be overridden (e.g. by VertexBuffer11) if necessary. + virtual void hintUnmapResource() { }; + + protected: + void updateSerial(); + + private: + unsigned int mSerial; + static unsigned int mNextSerial; +}; + +class VertexBufferInterface : angle::NonCopyable +{ + public: + VertexBufferInterface(BufferFactoryD3D *factory, bool dynamic); + virtual ~VertexBufferInterface(); + + gl::Error reserveVertexSpace(const gl::VertexAttribute &attribute, GLsizei count, GLsizei instances); + + unsigned int getBufferSize() const; + + unsigned int getSerial() const; + + virtual gl::Error storeVertexAttributes(const gl::VertexAttribute &attrib, const gl::VertexAttribCurrentValueData ¤tValue, + GLint start, GLsizei count, GLsizei instances, unsigned int *outStreamOffset); + + bool directStoragePossible(const gl::VertexAttribute &attrib, + const gl::VertexAttribCurrentValueData ¤tValue) const; + + VertexBuffer* getVertexBuffer() const; + + protected: + virtual gl::Error reserveSpace(unsigned int size) = 0; + + unsigned int getWritePosition() const; + void setWritePosition(unsigned int writePosition); + + gl::Error discard(); + + gl::Error setBufferSize(unsigned int size); + + private: + BufferFactoryD3D *const mFactory; + + VertexBuffer* mVertexBuffer; + + unsigned int mWritePosition; + unsigned int mReservedSpace; + bool mDynamic; +}; + +class StreamingVertexBufferInterface : public VertexBufferInterface +{ + public: + StreamingVertexBufferInterface(BufferFactoryD3D *factory, std::size_t initialSize); + ~StreamingVertexBufferInterface(); + + protected: + gl::Error reserveSpace(unsigned int size); +}; + +class StaticVertexBufferInterface : public VertexBufferInterface +{ + public: + explicit StaticVertexBufferInterface(BufferFactoryD3D *factory); + ~StaticVertexBufferInterface(); + + gl::Error storeVertexAttributes(const gl::VertexAttribute &attrib, const gl::VertexAttribCurrentValueData ¤tValue, + GLint start, GLsizei count, GLsizei instances, unsigned int *outStreamOffset); + + bool lookupAttribute(const gl::VertexAttribute &attribute, unsigned int* outStreamFffset); + + protected: + gl::Error reserveSpace(unsigned int size); + + private: + struct VertexElement + { + GLenum type; + GLuint size; + GLuint stride; + bool normalized; + bool pureInteger; + size_t attributeOffset; + + unsigned int streamOffset; + }; + + std::vector mCache; +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_VERTEXBUFFER_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/VertexDataManager.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/VertexDataManager.cpp new file mode 100644 index 0000000000..cb70b9e4ef --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/VertexDataManager.cpp @@ -0,0 +1,396 @@ +// +// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// VertexDataManager.h: Defines the VertexDataManager, a class that +// runs the Buffer translation process. + +#include "libANGLE/renderer/d3d/VertexDataManager.h" + +#include "libANGLE/Buffer.h" +#include "libANGLE/Program.h" +#include "libANGLE/State.h" +#include "libANGLE/VertexAttribute.h" +#include "libANGLE/VertexArray.h" +#include "libANGLE/renderer/d3d/BufferD3D.h" +#include "libANGLE/renderer/d3d/VertexBuffer.h" + +namespace +{ + enum { INITIAL_STREAM_BUFFER_SIZE = 1024*1024 }; + // This has to be at least 4k or else it fails on ATI cards. + enum { CONSTANT_VERTEX_BUFFER_SIZE = 4096 }; +} + +namespace rx +{ + +static int ElementsInBuffer(const gl::VertexAttribute &attrib, unsigned int size) +{ + // Size cannot be larger than a GLsizei + if (size > static_cast(std::numeric_limits::max())) + { + size = static_cast(std::numeric_limits::max()); + } + + GLsizei stride = ComputeVertexAttributeStride(attrib); + return (size - attrib.offset % stride + (stride - ComputeVertexAttributeTypeSize(attrib))) / stride; +} + +static int StreamingBufferElementCount(const gl::VertexAttribute &attrib, int vertexDrawCount, int instanceDrawCount) +{ + // For instanced rendering, we draw "instanceDrawCount" sets of "vertexDrawCount" vertices. + // + // A vertex attribute with a positive divisor loads one instanced vertex for every set of + // non-instanced vertices, and the instanced vertex index advances once every "mDivisor" instances. + if (instanceDrawCount > 0 && attrib.divisor > 0) + { + // When instanceDrawCount is not a multiple attrib.divisor, the division must round up. + // For instance, with 5 non-instanced vertices and a divisor equal to 3, we need 2 instanced vertices. + return (instanceDrawCount + attrib.divisor - 1) / attrib.divisor; + } + + return vertexDrawCount; +} + +VertexDataManager::VertexDataManager(BufferFactoryD3D *factory) + : mFactory(factory) +{ + for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) + { + mCurrentValue[i].FloatValues[0] = std::numeric_limits::quiet_NaN(); + mCurrentValue[i].FloatValues[1] = std::numeric_limits::quiet_NaN(); + mCurrentValue[i].FloatValues[2] = std::numeric_limits::quiet_NaN(); + mCurrentValue[i].FloatValues[3] = std::numeric_limits::quiet_NaN(); + mCurrentValue[i].Type = GL_FLOAT; + mCurrentValueBuffer[i] = NULL; + mCurrentValueOffsets[i] = 0; + } + + mStreamingBuffer = new StreamingVertexBufferInterface(factory, INITIAL_STREAM_BUFFER_SIZE); + + if (!mStreamingBuffer) + { + ERR("Failed to allocate the streaming vertex buffer."); + } +} + +VertexDataManager::~VertexDataManager() +{ + delete mStreamingBuffer; + + for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) + { + delete mCurrentValueBuffer[i]; + } +} + +void VertexDataManager::hintUnmapAllResources(const std::vector &vertexAttributes) +{ + mStreamingBuffer->getVertexBuffer()->hintUnmapResource(); + + for (size_t i = 0; i < vertexAttributes.size(); i++) + { + const gl::VertexAttribute &attrib = vertexAttributes[i]; + if (attrib.enabled) + { + gl::Buffer *buffer = attrib.buffer.get(); + BufferD3D *storage = buffer ? GetImplAs(buffer) : NULL; + StaticVertexBufferInterface *staticBuffer = storage ? storage->getStaticVertexBuffer() : NULL; + + if (staticBuffer) + { + staticBuffer->getVertexBuffer()->hintUnmapResource(); + } + } + } + + for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) + { + if (mCurrentValueBuffer[i] != NULL) + { + mCurrentValueBuffer[i]->getVertexBuffer()->hintUnmapResource(); + } + } +} + +gl::Error VertexDataManager::prepareVertexData(const gl::State &state, GLint start, GLsizei count, + TranslatedAttribute *translated, GLsizei instances) +{ + if (!mStreamingBuffer) + { + return gl::Error(GL_OUT_OF_MEMORY, "Internal streaming vertex buffer is unexpectedly NULL."); + } + + const gl::VertexArray *vertexArray = state.getVertexArray(); + const std::vector &vertexAttributes = vertexArray->getVertexAttributes(); + + // Invalidate static buffers that don't contain matching attributes + for (int attributeIndex = 0; attributeIndex < gl::MAX_VERTEX_ATTRIBS; attributeIndex++) + { + translated[attributeIndex].active = (state.getProgram()->getSemanticIndex(attributeIndex) != -1); + if (translated[attributeIndex].active && vertexAttributes[attributeIndex].enabled) + { + invalidateMatchingStaticData(vertexAttributes[attributeIndex], state.getVertexAttribCurrentValue(attributeIndex)); + } + } + + // Reserve the required space in the buffers + for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) + { + if (translated[i].active && vertexAttributes[i].enabled) + { + gl::Error error = reserveSpaceForAttrib(vertexAttributes[i], state.getVertexAttribCurrentValue(i), count, instances); + if (error.isError()) + { + return error; + } + } + } + + // Perform the vertex data translations + for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) + { + const gl::VertexAttribute &curAttrib = vertexAttributes[i]; + if (translated[i].active) + { + if (curAttrib.enabled) + { + gl::Error error = storeAttribute(curAttrib, state.getVertexAttribCurrentValue(i), + &translated[i], start, count, instances); + + if (error.isError()) + { + hintUnmapAllResources(vertexAttributes); + return error; + } + } + else + { + if (!mCurrentValueBuffer[i]) + { + mCurrentValueBuffer[i] = new StreamingVertexBufferInterface(mFactory, CONSTANT_VERTEX_BUFFER_SIZE); + } + + gl::Error error = storeCurrentValue(curAttrib, state.getVertexAttribCurrentValue(i), &translated[i], + &mCurrentValue[i], &mCurrentValueOffsets[i], + mCurrentValueBuffer[i]); + if (error.isError()) + { + hintUnmapAllResources(vertexAttributes); + return error; + } + } + } + } + + // Hint to unmap all the resources + hintUnmapAllResources(vertexAttributes); + + for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) + { + const gl::VertexAttribute &curAttrib = vertexAttributes[i]; + if (translated[i].active && curAttrib.enabled) + { + gl::Buffer *buffer = curAttrib.buffer.get(); + + if (buffer) + { + BufferD3D *bufferImpl = GetImplAs(buffer); + bufferImpl->promoteStaticUsage(count * ComputeVertexAttributeTypeSize(curAttrib)); + } + } + } + + return gl::Error(GL_NO_ERROR); +} + +void VertexDataManager::invalidateMatchingStaticData(const gl::VertexAttribute &attrib, + const gl::VertexAttribCurrentValueData ¤tValue) const +{ + gl::Buffer *buffer = attrib.buffer.get(); + + if (buffer) + { + BufferD3D *bufferImpl = GetImplAs(buffer); + StaticVertexBufferInterface *staticBuffer = bufferImpl->getStaticVertexBuffer(); + + if (staticBuffer && + staticBuffer->getBufferSize() > 0 && + !staticBuffer->lookupAttribute(attrib, NULL) && + !staticBuffer->directStoragePossible(attrib, currentValue)) + { + bufferImpl->invalidateStaticData(); + } + } +} + +gl::Error VertexDataManager::reserveSpaceForAttrib(const gl::VertexAttribute &attrib, + const gl::VertexAttribCurrentValueData ¤tValue, + GLsizei count, + GLsizei instances) const +{ + gl::Buffer *buffer = attrib.buffer.get(); + BufferD3D *bufferImpl = buffer ? GetImplAs(buffer) : NULL; + StaticVertexBufferInterface *staticBuffer = bufferImpl ? bufferImpl->getStaticVertexBuffer() : NULL; + VertexBufferInterface *vertexBuffer = staticBuffer ? staticBuffer : static_cast(mStreamingBuffer); + + if (!vertexBuffer->directStoragePossible(attrib, currentValue)) + { + if (staticBuffer) + { + if (staticBuffer->getBufferSize() == 0) + { + int totalCount = ElementsInBuffer(attrib, bufferImpl->getSize()); + gl::Error error = staticBuffer->reserveVertexSpace(attrib, totalCount, 0); + if (error.isError()) + { + return error; + } + } + } + else + { + int totalCount = StreamingBufferElementCount(attrib, count, instances); + ASSERT(!bufferImpl || ElementsInBuffer(attrib, bufferImpl->getSize()) >= totalCount); + + gl::Error error = mStreamingBuffer->reserveVertexSpace(attrib, totalCount, instances); + if (error.isError()) + { + return error; + } + } + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error VertexDataManager::storeAttribute(const gl::VertexAttribute &attrib, + const gl::VertexAttribCurrentValueData ¤tValue, + TranslatedAttribute *translated, + GLint start, + GLsizei count, + GLsizei instances) +{ + gl::Buffer *buffer = attrib.buffer.get(); + ASSERT(buffer || attrib.pointer); + + BufferD3D *storage = buffer ? GetImplAs(buffer) : NULL; + StaticVertexBufferInterface *staticBuffer = storage ? storage->getStaticVertexBuffer() : NULL; + VertexBufferInterface *vertexBuffer = staticBuffer ? staticBuffer : static_cast(mStreamingBuffer); + bool directStorage = vertexBuffer->directStoragePossible(attrib, currentValue); + + unsigned int streamOffset = 0; + unsigned int outputElementSize = 0; + + // Instanced vertices do not apply the 'start' offset + GLint firstVertexIndex = (instances > 0 && attrib.divisor > 0 ? 0 : start); + + if (directStorage) + { + outputElementSize = ComputeVertexAttributeStride(attrib); + streamOffset = attrib.offset + outputElementSize * firstVertexIndex; + } + else if (staticBuffer) + { + gl::Error error = staticBuffer->getVertexBuffer()->getSpaceRequired(attrib, 1, 0, &outputElementSize); + if (error.isError()) + { + return error; + } + + if (!staticBuffer->lookupAttribute(attrib, &streamOffset)) + { + // Convert the entire buffer + int totalCount = ElementsInBuffer(attrib, storage->getSize()); + int startIndex = attrib.offset / ComputeVertexAttributeStride(attrib); + + error = staticBuffer->storeVertexAttributes(attrib, currentValue, -startIndex, totalCount, + 0, &streamOffset); + if (error.isError()) + { + return error; + } + } + + unsigned int firstElementOffset = (attrib.offset / ComputeVertexAttributeStride(attrib)) * outputElementSize; + unsigned int startOffset = (instances == 0 || attrib.divisor == 0) ? firstVertexIndex * outputElementSize : 0; + if (streamOffset + firstElementOffset + startOffset < streamOffset) + { + return gl::Error(GL_OUT_OF_MEMORY); + } + + streamOffset += firstElementOffset + startOffset; + } + else + { + int totalCount = StreamingBufferElementCount(attrib, count, instances); + gl::Error error = mStreamingBuffer->getVertexBuffer()->getSpaceRequired(attrib, 1, 0, &outputElementSize); + if (error.isError()) + { + return error; + } + + error = mStreamingBuffer->storeVertexAttributes(attrib, currentValue, firstVertexIndex, + totalCount, instances, &streamOffset); + if (error.isError()) + { + return error; + } + } + + translated->storage = directStorage ? storage : NULL; + translated->vertexBuffer = vertexBuffer->getVertexBuffer(); + translated->serial = directStorage ? storage->getSerial() : vertexBuffer->getSerial(); + translated->divisor = attrib.divisor; + + translated->attribute = &attrib; + translated->currentValueType = currentValue.Type; + translated->stride = outputElementSize; + translated->offset = streamOffset; + + return gl::Error(GL_NO_ERROR); +} + +gl::Error VertexDataManager::storeCurrentValue(const gl::VertexAttribute &attrib, + const gl::VertexAttribCurrentValueData ¤tValue, + TranslatedAttribute *translated, + gl::VertexAttribCurrentValueData *cachedValue, + size_t *cachedOffset, + StreamingVertexBufferInterface *buffer) +{ + if (*cachedValue != currentValue) + { + gl::Error error = buffer->reserveVertexSpace(attrib, 1, 0); + if (error.isError()) + { + return error; + } + + unsigned int streamOffset; + error = buffer->storeVertexAttributes(attrib, currentValue, 0, 1, 0, &streamOffset); + if (error.isError()) + { + return error; + } + + *cachedValue = currentValue; + *cachedOffset = streamOffset; + } + + translated->storage = NULL; + translated->vertexBuffer = buffer->getVertexBuffer(); + translated->serial = buffer->getSerial(); + translated->divisor = 0; + + translated->attribute = &attrib; + translated->currentValueType = currentValue.Type; + translated->stride = 0; + translated->offset = *cachedOffset; + + return gl::Error(GL_NO_ERROR); +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/VertexDataManager.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/VertexDataManager.h new file mode 100644 index 0000000000..898ed340b8 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/VertexDataManager.h @@ -0,0 +1,95 @@ +// +// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// VertexDataManager.h: Defines the VertexDataManager, a class that +// runs the Buffer translation process. + +#ifndef LIBANGLE_RENDERER_D3D_VERTEXDATAMANAGER_H_ +#define LIBANGLE_RENDERER_D3D_VERTEXDATAMANAGER_H_ + +#include "libANGLE/Constants.h" +#include "libANGLE/VertexAttribute.h" +#include "common/angleutils.h" + +namespace gl +{ +class State; +struct VertexAttribute; +struct VertexAttribCurrentValueData; +} + +namespace rx +{ +class BufferD3D; +class BufferFactoryD3D; +class StreamingVertexBufferInterface; +class VertexBuffer; + +struct TranslatedAttribute +{ + TranslatedAttribute() : active(false), attribute(NULL), currentValueType(GL_NONE), + offset(0), stride(0), vertexBuffer(NULL), storage(NULL), + serial(0), divisor(0) {}; + bool active; + + const gl::VertexAttribute *attribute; + GLenum currentValueType; + unsigned int offset; + unsigned int stride; // 0 means not to advance the read pointer at all + + VertexBuffer *vertexBuffer; + BufferD3D *storage; + unsigned int serial; + unsigned int divisor; +}; + +class VertexDataManager : angle::NonCopyable +{ + public: + VertexDataManager(BufferFactoryD3D *factory); + virtual ~VertexDataManager(); + + gl::Error prepareVertexData(const gl::State &state, GLint start, GLsizei count, + TranslatedAttribute *outAttribs, GLsizei instances); + + private: + gl::Error reserveSpaceForAttrib(const gl::VertexAttribute &attrib, + const gl::VertexAttribCurrentValueData ¤tValue, + GLsizei count, + GLsizei instances) const; + + void invalidateMatchingStaticData(const gl::VertexAttribute &attrib, + const gl::VertexAttribCurrentValueData ¤tValue) const; + + gl::Error storeAttribute(const gl::VertexAttribute &attrib, + const gl::VertexAttribCurrentValueData ¤tValue, + TranslatedAttribute *translated, + GLint start, + GLsizei count, + GLsizei instances); + + gl::Error storeCurrentValue(const gl::VertexAttribute &attrib, + const gl::VertexAttribCurrentValueData ¤tValue, + TranslatedAttribute *translated, + gl::VertexAttribCurrentValueData *cachedValue, + size_t *cachedOffset, + StreamingVertexBufferInterface *buffer); + + void hintUnmapAllResources(const std::vector &vertexAttributes); + + BufferFactoryD3D *const mFactory; + + StreamingVertexBufferInterface *mStreamingBuffer; + + gl::VertexAttribCurrentValueData mCurrentValue[gl::MAX_VERTEX_ATTRIBS]; + + StreamingVertexBufferInterface *mCurrentValueBuffer[gl::MAX_VERTEX_ATTRIBS]; + std::size_t mCurrentValueOffsets[gl::MAX_VERTEX_ATTRIBS]; +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_VERTEXDATAMANAGER_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/copyimage.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/copyimage.cpp new file mode 100644 index 0000000000..b1798454ca --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/copyimage.cpp @@ -0,0 +1,22 @@ +// +// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// copyimage.cpp: Defines image copying functions + +#include "libANGLE/renderer/d3d/copyimage.h" + +namespace rx +{ + +void CopyBGRA8ToRGBA8(const uint8_t *source, uint8_t *dest) +{ + uint32_t argb = *reinterpret_cast(source); + *reinterpret_cast(dest) = (argb & 0xFF00FF00) | // Keep alpha and green + (argb & 0x00FF0000) >> 16 | // Move red to blue + (argb & 0x000000FF) << 16; // Move blue to red +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/copyimage.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/copyimage.h new file mode 100644 index 0000000000..189654ca39 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/copyimage.h @@ -0,0 +1,35 @@ +// +// Copyright (c) 2013-2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// copyimage.h: Defines image copying functions + +#ifndef LIBANGLE_RENDERER_D3D_COPYIMAGE_H_ +#define LIBANGLE_RENDERER_D3D_COPYIMAGE_H_ + +#include "common/mathutil.h" +#include "libANGLE/angletypes.h" + +#include + +namespace rx +{ + +template +void ReadColor(const uint8_t *source, uint8_t *dest); + +template +void WriteColor(const uint8_t *source, uint8_t *dest); + +template +void CopyPixel(const uint8_t *source, uint8_t *dest); + +void CopyBGRA8ToRGBA8(const uint8_t *source, uint8_t *dest); + +} + +#include "copyimage.inl" + +#endif // LIBANGLE_RENDERER_D3D_COPYIMAGE_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/copyimage.inl b/src/3rdparty/angle/src/libANGLE/renderer/d3d/copyimage.inl new file mode 100644 index 0000000000..0498cf7750 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/copyimage.inl @@ -0,0 +1,32 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// copyimage.inl: Defines image copying functions + +namespace rx +{ + +template +inline void ReadColor(const uint8_t *source, uint8_t *dest) +{ + sourceType::readColor(reinterpret_cast*>(dest), reinterpret_cast(source)); +} + +template +inline void WriteColor(const uint8_t *source, uint8_t *dest) +{ + destType::writeColor(reinterpret_cast(dest), reinterpret_cast*>(source)); +} + +template +inline void CopyPixel(const uint8_t *source, uint8_t *dest) +{ + colorDataType temp; + ReadColor(source, &temp); + WriteColor(&temp, dest); +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Blit11.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Blit11.cpp new file mode 100644 index 0000000000..e38b61709f --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Blit11.cpp @@ -0,0 +1,1059 @@ +// +// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Blit11.cpp: Texture copy utility class. + +#include "libANGLE/renderer/d3d/d3d11/Blit11.h" + +#include + +#include "libANGLE/renderer/d3d/d3d11/Renderer11.h" +#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h" +#include "libANGLE/renderer/d3d/d3d11/formatutils11.h" +#include "libANGLE/formatutils.h" + +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthrough2d11vs.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughdepth2d11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrgba2d11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrgba2dui11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrgba2di11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrgb2d11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrgb2dui11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrgb2di11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrg2d11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrg2dui11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrg2di11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughr2d11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughr2dui11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughr2di11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughlum2d11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughlumalpha2d11ps.h" + +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthrough3d11vs.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthrough3d11gs.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrgba3d11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrgba3dui11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrgba3di11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrgb3d11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrgb3dui11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrgb3di11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrg3d11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrg3dui11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrg3di11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughr3d11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughr3dui11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughr3di11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughlum3d11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughlumalpha3d11ps.h" + +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/swizzlef2dps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/swizzlei2dps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/swizzleui2dps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/swizzlef3dps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/swizzlei3dps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/swizzleui3dps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/swizzlef2darrayps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/swizzlei2darrayps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/swizzleui2darrayps.h" + +namespace rx +{ + +static DXGI_FORMAT GetTextureFormat(ID3D11Resource *resource) +{ + ID3D11Texture2D *texture = d3d11::DynamicCastComObject(resource); + if (!texture) + { + return DXGI_FORMAT_UNKNOWN; + } + + D3D11_TEXTURE2D_DESC desc; + texture->GetDesc(&desc); + + SafeRelease(texture); + + return desc.Format; +} + +static ID3D11Resource *CreateStagingTexture(ID3D11Device *device, ID3D11DeviceContext *context, + ID3D11Resource *source, unsigned int subresource, + const gl::Extents &size, unsigned int cpuAccessFlags) +{ + D3D11_TEXTURE2D_DESC stagingDesc; + stagingDesc.Width = size.width; + stagingDesc.Height = size.height; + stagingDesc.MipLevels = 1; + stagingDesc.ArraySize = 1; + stagingDesc.Format = GetTextureFormat(source); + stagingDesc.SampleDesc.Count = 1; + stagingDesc.SampleDesc.Quality = 0; + stagingDesc.Usage = D3D11_USAGE_STAGING; + stagingDesc.CPUAccessFlags = cpuAccessFlags; + stagingDesc.MiscFlags = 0; + stagingDesc.BindFlags = 0; + + ID3D11Texture2D *stagingTexture = NULL; + HRESULT result = device->CreateTexture2D(&stagingDesc, NULL, &stagingTexture); + if (FAILED(result)) + { + ERR("Failed to create staging texture for depth stencil blit. HRESULT: 0x%X.", result); + return NULL; + } + + context->CopySubresourceRegion(stagingTexture, 0, 0, 0, 0, source, subresource, NULL); + + return stagingTexture; +} + +inline static void GenerateVertexCoords(const gl::Box &sourceArea, const gl::Extents &sourceSize, + const gl::Box &destArea, const gl::Extents &destSize, + float *x1, float *y1, float *x2, float *y2, + float *u1, float *v1, float *u2, float *v2) +{ + *x1 = (destArea.x / float(destSize.width)) * 2.0f - 1.0f; + *y1 = ((destSize.height - destArea.y - destArea.height) / float(destSize.height)) * 2.0f - 1.0f; + *x2 = ((destArea.x + destArea.width) / float(destSize.width)) * 2.0f - 1.0f; + *y2 = ((destSize.height - destArea.y) / float(destSize.height)) * 2.0f - 1.0f; + + *u1 = sourceArea.x / float(sourceSize.width); + *v1 = sourceArea.y / float(sourceSize.height); + *u2 = (sourceArea.x + sourceArea.width) / float(sourceSize.width); + *v2 = (sourceArea.y + sourceArea.height) / float(sourceSize.height); +} + +static void Write2DVertices(const gl::Box &sourceArea, const gl::Extents &sourceSize, + const gl::Box &destArea, const gl::Extents &destSize, + void *outVertices, unsigned int *outStride, unsigned int *outVertexCount, + D3D11_PRIMITIVE_TOPOLOGY *outTopology) +{ + float x1, y1, x2, y2, u1, v1, u2, v2; + GenerateVertexCoords(sourceArea, sourceSize, destArea, destSize, &x1, &y1, &x2, &y2, &u1, &v1, &u2, &v2); + + d3d11::PositionTexCoordVertex *vertices = static_cast(outVertices); + + d3d11::SetPositionTexCoordVertex(&vertices[0], x1, y1, u1, v2); + d3d11::SetPositionTexCoordVertex(&vertices[1], x1, y2, u1, v1); + d3d11::SetPositionTexCoordVertex(&vertices[2], x2, y1, u2, v2); + d3d11::SetPositionTexCoordVertex(&vertices[3], x2, y2, u2, v1); + + *outStride = sizeof(d3d11::PositionTexCoordVertex); + *outVertexCount = 4; + *outTopology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP; +} + +static void Write3DVertices(const gl::Box &sourceArea, const gl::Extents &sourceSize, + const gl::Box &destArea, const gl::Extents &destSize, + void *outVertices, unsigned int *outStride, unsigned int *outVertexCount, + D3D11_PRIMITIVE_TOPOLOGY *outTopology) +{ + ASSERT(sourceSize.depth > 0 && destSize.depth > 0); + + float x1, y1, x2, y2, u1, v1, u2, v2; + GenerateVertexCoords(sourceArea, sourceSize, destArea, destSize, &x1, &y1, &x2, &y2, &u1, &v1, &u2, &v2); + + d3d11::PositionLayerTexCoord3DVertex *vertices = static_cast(outVertices); + + for (int i = 0; i < destSize.depth; i++) + { + float readDepth = (float)i / std::max(destSize.depth - 1, 1); + + d3d11::SetPositionLayerTexCoord3DVertex(&vertices[i * 6 + 0], x1, y1, i, u1, v2, readDepth); + d3d11::SetPositionLayerTexCoord3DVertex(&vertices[i * 6 + 1], x1, y2, i, u1, v1, readDepth); + d3d11::SetPositionLayerTexCoord3DVertex(&vertices[i * 6 + 2], x2, y1, i, u2, v2, readDepth); + + d3d11::SetPositionLayerTexCoord3DVertex(&vertices[i * 6 + 3], x1, y2, i, u1, v1, readDepth); + d3d11::SetPositionLayerTexCoord3DVertex(&vertices[i * 6 + 4], x2, y2, i, u2, v1, readDepth); + d3d11::SetPositionLayerTexCoord3DVertex(&vertices[i * 6 + 5], x2, y1, i, u2, v2, readDepth); + } + + *outStride = sizeof(d3d11::PositionLayerTexCoord3DVertex); + *outVertexCount = destSize.depth * 6; + *outTopology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST; +} + +Blit11::Blit11(Renderer11 *renderer) + : mRenderer(renderer), mBlitShaderMap(compareBlitParameters), mSwizzleShaderMap(compareSwizzleParameters), + mVertexBuffer(NULL), mPointSampler(NULL), mLinearSampler(NULL), mScissorEnabledRasterizerState(NULL), + mScissorDisabledRasterizerState(NULL), mDepthStencilState(NULL), + mQuad2DIL(NULL), mQuad2DVS(NULL), mDepthPS(NULL), + mQuad3DIL(NULL), mQuad3DVS(NULL), mQuad3DGS(NULL), + mSwizzleCB(NULL) +{ + HRESULT result; + ID3D11Device *device = mRenderer->getDevice(); + + D3D11_BUFFER_DESC vbDesc; + vbDesc.ByteWidth = std::max(sizeof(d3d11::PositionLayerTexCoord3DVertex), sizeof(d3d11::PositionTexCoordVertex)) * + 6 * renderer->getRendererCaps().max3DTextureSize; + vbDesc.Usage = D3D11_USAGE_DYNAMIC; + vbDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; + vbDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + vbDesc.MiscFlags = 0; + vbDesc.StructureByteStride = 0; + + result = device->CreateBuffer(&vbDesc, NULL, &mVertexBuffer); + ASSERT(SUCCEEDED(result)); + d3d11::SetDebugName(mVertexBuffer, "Blit11 vertex buffer"); + + D3D11_SAMPLER_DESC pointSamplerDesc; + pointSamplerDesc.Filter = D3D11_FILTER_MIN_MAG_POINT_MIP_LINEAR; + pointSamplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP; + pointSamplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP; + pointSamplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP; + pointSamplerDesc.MipLODBias = 0.0f; + pointSamplerDesc.MaxAnisotropy = 0; + pointSamplerDesc.ComparisonFunc = D3D11_COMPARISON_NEVER; + pointSamplerDesc.BorderColor[0] = 0.0f; + pointSamplerDesc.BorderColor[1] = 0.0f; + pointSamplerDesc.BorderColor[2] = 0.0f; + pointSamplerDesc.BorderColor[3] = 0.0f; + pointSamplerDesc.MinLOD = 0.0f; + pointSamplerDesc.MaxLOD = FLT_MAX; + + result = device->CreateSamplerState(&pointSamplerDesc, &mPointSampler); + ASSERT(SUCCEEDED(result)); + d3d11::SetDebugName(mPointSampler, "Blit11 point sampler"); + + D3D11_SAMPLER_DESC linearSamplerDesc; + linearSamplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR; + linearSamplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP; + linearSamplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP; + linearSamplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP; + linearSamplerDesc.MipLODBias = 0.0f; + linearSamplerDesc.MaxAnisotropy = 0; + linearSamplerDesc.ComparisonFunc = D3D11_COMPARISON_NEVER; + linearSamplerDesc.BorderColor[0] = 0.0f; + linearSamplerDesc.BorderColor[1] = 0.0f; + linearSamplerDesc.BorderColor[2] = 0.0f; + linearSamplerDesc.BorderColor[3] = 0.0f; + linearSamplerDesc.MinLOD = 0.0f; + linearSamplerDesc.MaxLOD = FLT_MAX; + + result = device->CreateSamplerState(&linearSamplerDesc, &mLinearSampler); + ASSERT(SUCCEEDED(result)); + d3d11::SetDebugName(mLinearSampler, "Blit11 linear sampler"); + + // Use a rasterizer state that will not cull so that inverted quads will not be culled + D3D11_RASTERIZER_DESC rasterDesc; + rasterDesc.FillMode = D3D11_FILL_SOLID; + rasterDesc.CullMode = D3D11_CULL_NONE; + rasterDesc.FrontCounterClockwise = FALSE; + rasterDesc.DepthBias = 0; + rasterDesc.SlopeScaledDepthBias = 0.0f; + rasterDesc.DepthBiasClamp = 0.0f; + rasterDesc.DepthClipEnable = TRUE; + rasterDesc.MultisampleEnable = FALSE; + rasterDesc.AntialiasedLineEnable = FALSE; + + rasterDesc.ScissorEnable = TRUE; + result = device->CreateRasterizerState(&rasterDesc, &mScissorEnabledRasterizerState); + ASSERT(SUCCEEDED(result)); + d3d11::SetDebugName(mScissorEnabledRasterizerState, "Blit11 scissoring rasterizer state"); + + rasterDesc.ScissorEnable = FALSE; + result = device->CreateRasterizerState(&rasterDesc, &mScissorDisabledRasterizerState); + ASSERT(SUCCEEDED(result)); + d3d11::SetDebugName(mScissorDisabledRasterizerState, "Blit11 no scissoring rasterizer state"); + + D3D11_DEPTH_STENCIL_DESC depthStencilDesc; + depthStencilDesc.DepthEnable = true; + depthStencilDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL; + depthStencilDesc.DepthFunc = D3D11_COMPARISON_ALWAYS; + depthStencilDesc.StencilEnable = FALSE; + depthStencilDesc.StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK; + depthStencilDesc.StencilWriteMask = D3D11_DEFAULT_STENCIL_WRITE_MASK; + depthStencilDesc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP; + depthStencilDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP; + depthStencilDesc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP; + depthStencilDesc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS; + depthStencilDesc.BackFace.StencilFailOp = D3D11_STENCIL_OP_KEEP; + depthStencilDesc.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP; + depthStencilDesc.BackFace.StencilPassOp = D3D11_STENCIL_OP_KEEP; + depthStencilDesc.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS; + + result = device->CreateDepthStencilState(&depthStencilDesc, &mDepthStencilState); + ASSERT(SUCCEEDED(result)); + d3d11::SetDebugName(mDepthStencilState, "Blit11 depth stencil state"); + + D3D11_INPUT_ELEMENT_DESC quad2DLayout[] = + { + { "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, + { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 8, D3D11_INPUT_PER_VERTEX_DATA, 0 }, + }; + + result = device->CreateInputLayout(quad2DLayout, ArraySize(quad2DLayout), g_VS_Passthrough2D, ArraySize(g_VS_Passthrough2D), &mQuad2DIL); + ASSERT(SUCCEEDED(result)); + d3d11::SetDebugName(mQuad2DIL, "Blit11 2D input layout"); + + result = device->CreateVertexShader(g_VS_Passthrough2D, ArraySize(g_VS_Passthrough2D), NULL, &mQuad2DVS); + ASSERT(SUCCEEDED(result)); + d3d11::SetDebugName(mQuad2DVS, "Blit11 2D vertex shader"); + + if (renderer->isES3Capable()) + { + result = device->CreatePixelShader(g_PS_PassthroughDepth2D, ArraySize(g_PS_PassthroughDepth2D), NULL, &mDepthPS); + ASSERT(SUCCEEDED(result)); + d3d11::SetDebugName(mDepthPS, "Blit11 2D depth pixel shader"); + + D3D11_INPUT_ELEMENT_DESC quad3DLayout[] = + { + { "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, + { "LAYER", 0, DXGI_FORMAT_R32_UINT, 0, 8, D3D11_INPUT_PER_VERTEX_DATA, 0 }, + { "TEXCOORD", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 }, + }; + + result = device->CreateInputLayout(quad3DLayout, ArraySize(quad3DLayout), g_VS_Passthrough3D, ArraySize(g_VS_Passthrough3D), &mQuad3DIL); + ASSERT(SUCCEEDED(result)); + d3d11::SetDebugName(mQuad3DIL, "Blit11 3D input layout"); + + result = device->CreateVertexShader(g_VS_Passthrough3D, ArraySize(g_VS_Passthrough3D), NULL, &mQuad3DVS); + ASSERT(SUCCEEDED(result)); + d3d11::SetDebugName(mQuad3DVS, "Blit11 3D vertex shader"); + + result = device->CreateGeometryShader(g_GS_Passthrough3D, ArraySize(g_GS_Passthrough3D), NULL, &mQuad3DGS); + ASSERT(SUCCEEDED(result)); + d3d11::SetDebugName(mQuad3DGS, "Renderer11 copy 3D texture geometry shader"); + } + + buildShaderMap(); + + D3D11_BUFFER_DESC swizzleBufferDesc; + swizzleBufferDesc.ByteWidth = sizeof(unsigned int) * 4; + swizzleBufferDesc.Usage = D3D11_USAGE_DYNAMIC; + swizzleBufferDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; + swizzleBufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + swizzleBufferDesc.MiscFlags = 0; + swizzleBufferDesc.StructureByteStride = 0; + + result = device->CreateBuffer(&swizzleBufferDesc, NULL, &mSwizzleCB); + ASSERT(SUCCEEDED(result)); + d3d11::SetDebugName(mSwizzleCB, "Blit11 swizzle constant buffer"); +} + +Blit11::~Blit11() +{ + SafeRelease(mVertexBuffer); + SafeRelease(mPointSampler); + SafeRelease(mLinearSampler); + SafeRelease(mScissorEnabledRasterizerState); + SafeRelease(mScissorDisabledRasterizerState); + SafeRelease(mDepthStencilState); + + SafeRelease(mQuad2DIL); + SafeRelease(mQuad2DVS); + SafeRelease(mDepthPS); + + SafeRelease(mQuad3DIL); + SafeRelease(mQuad3DVS); + SafeRelease(mQuad3DGS); + + SafeRelease(mSwizzleCB); + + clearShaderMap(); +} + +static inline unsigned int GetSwizzleIndex(GLenum swizzle) +{ + unsigned int colorIndex = 0; + + switch (swizzle) + { + case GL_RED: colorIndex = 0; break; + case GL_GREEN: colorIndex = 1; break; + case GL_BLUE: colorIndex = 2; break; + case GL_ALPHA: colorIndex = 3; break; + case GL_ZERO: colorIndex = 4; break; + case GL_ONE: colorIndex = 5; break; + default: UNREACHABLE(); break; + } + + return colorIndex; +} + +gl::Error Blit11::swizzleTexture(ID3D11ShaderResourceView *source, ID3D11RenderTargetView *dest, const gl::Extents &size, + GLenum swizzleRed, GLenum swizzleGreen, GLenum swizzleBlue, GLenum swizzleAlpha) +{ + HRESULT result; + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); + + D3D11_SHADER_RESOURCE_VIEW_DESC sourceSRVDesc; + source->GetDesc(&sourceSRVDesc); + + const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(sourceSRVDesc.Format); + const gl::InternalFormat &sourceFormatInfo = gl::GetInternalFormatInfo(dxgiFormatInfo.internalFormat); + + GLenum shaderType = GL_NONE; + switch (sourceFormatInfo.componentType) + { + case GL_UNSIGNED_NORMALIZED: + case GL_SIGNED_NORMALIZED: + case GL_FLOAT: + shaderType = GL_FLOAT; + break; + case GL_INT: + shaderType = GL_INT; + break; + case GL_UNSIGNED_INT: + shaderType = GL_UNSIGNED_INT; + break; + default: + UNREACHABLE(); + break; + } + + SwizzleParameters parameters = { 0 }; + parameters.mDestinationType = shaderType; + parameters.mViewDimension = sourceSRVDesc.ViewDimension; + + SwizzleShaderMap::const_iterator i = mSwizzleShaderMap.find(parameters); + if (i == mSwizzleShaderMap.end()) + { + UNREACHABLE(); + return gl::Error(GL_INVALID_OPERATION, "Internal error, missing swizzle shader."); + } + + const Shader &shader = i->second; + + // Set vertices + D3D11_MAPPED_SUBRESOURCE mappedResource; + result = deviceContext->Map(mVertexBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to map internal vertex buffer for swizzle, HRESULT: 0x%X.", result); + } + + UINT stride = 0; + UINT startIdx = 0; + UINT drawCount = 0; + D3D11_PRIMITIVE_TOPOLOGY topology; + + gl::Box area(0, 0, 0, size.width, size.height, size.depth); + shader.mVertexWriteFunction(area, size, area, size, mappedResource.pData, &stride, &drawCount, &topology); + + deviceContext->Unmap(mVertexBuffer, 0); + + // Set constant buffer + result = deviceContext->Map(mSwizzleCB, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to map internal constant buffer for swizzle, HRESULT: 0x%X.", result); + } + + unsigned int *swizzleIndices = reinterpret_cast(mappedResource.pData); + swizzleIndices[0] = GetSwizzleIndex(swizzleRed); + swizzleIndices[1] = GetSwizzleIndex(swizzleGreen); + swizzleIndices[2] = GetSwizzleIndex(swizzleBlue); + swizzleIndices[3] = GetSwizzleIndex(swizzleAlpha); + + deviceContext->Unmap(mSwizzleCB, 0); + + // Apply vertex buffer + deviceContext->IASetVertexBuffers(0, 1, &mVertexBuffer, &stride, &startIdx); + + // Apply constant buffer + deviceContext->PSSetConstantBuffers(0, 1, &mSwizzleCB); + + // Apply state + deviceContext->OMSetBlendState(NULL, NULL, 0xFFFFFFF); + deviceContext->OMSetDepthStencilState(NULL, 0xFFFFFFFF); + deviceContext->RSSetState(mScissorDisabledRasterizerState); + + // Apply shaders + deviceContext->IASetInputLayout(shader.mInputLayout); + deviceContext->IASetPrimitiveTopology(topology); + deviceContext->VSSetShader(shader.mVertexShader, NULL, 0); + + deviceContext->PSSetShader(shader.mPixelShader, NULL, 0); + deviceContext->GSSetShader(shader.mGeometryShader, NULL, 0); + + // Unset the currently bound shader resource to avoid conflicts + mRenderer->setShaderResource(gl::SAMPLER_PIXEL, 0, NULL); + + // Apply render target + mRenderer->setOneTimeRenderTarget(dest); + + // Set the viewport + D3D11_VIEWPORT viewport; + viewport.TopLeftX = 0; + viewport.TopLeftY = 0; + viewport.Width = size.width; + viewport.Height = size.height; + viewport.MinDepth = 0.0f; + viewport.MaxDepth = 1.0f; + deviceContext->RSSetViewports(1, &viewport); + + // Apply textures + mRenderer->setShaderResource(gl::SAMPLER_PIXEL, 0, source); + + // Apply samplers + deviceContext->PSSetSamplers(0, 1, &mPointSampler); + + // Draw the quad + deviceContext->Draw(drawCount, 0); + + // Unbind textures and render targets and vertex buffer + mRenderer->setShaderResource(gl::SAMPLER_PIXEL, 0, NULL); + + mRenderer->unapplyRenderTargets(); + + UINT zero = 0; + ID3D11Buffer *const nullBuffer = NULL; + deviceContext->IASetVertexBuffers(0, 1, &nullBuffer, &zero, &zero); + + mRenderer->markAllStateDirty(); + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Blit11::copyTexture(ID3D11ShaderResourceView *source, const gl::Box &sourceArea, const gl::Extents &sourceSize, + ID3D11RenderTargetView *dest, const gl::Box &destArea, const gl::Extents &destSize, + const gl::Rectangle *scissor, GLenum destFormat, GLenum filter) +{ + HRESULT result; + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); + + // Determine if the source format is a signed integer format, the destFormat will already + // be GL_XXXX_INTEGER but it does not tell us if it is signed or unsigned. + D3D11_SHADER_RESOURCE_VIEW_DESC sourceSRVDesc; + source->GetDesc(&sourceSRVDesc); + + const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(sourceSRVDesc.Format); + const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(dxgiFormatInfo.internalFormat); + + BlitParameters parameters = { 0 }; + parameters.mDestinationFormat = destFormat; + parameters.mSignedInteger = (internalFormatInfo.componentType == GL_INT); + parameters.m3DBlit = sourceSRVDesc.ViewDimension == D3D11_SRV_DIMENSION_TEXTURE3D; + + BlitShaderMap::const_iterator i = mBlitShaderMap.find(parameters); + if (i == mBlitShaderMap.end()) + { + UNREACHABLE(); + return gl::Error(GL_OUT_OF_MEMORY, "Could not find appropriate shader for internal texture blit."); + } + + const Shader& shader = i->second; + + // Set vertices + D3D11_MAPPED_SUBRESOURCE mappedResource; + result = deviceContext->Map(mVertexBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to map internal vertex buffer for texture copy, HRESULT: 0x%X.", result); + } + + UINT stride = 0; + UINT startIdx = 0; + UINT drawCount = 0; + D3D11_PRIMITIVE_TOPOLOGY topology; + + shader.mVertexWriteFunction(sourceArea, sourceSize, destArea, destSize, mappedResource.pData, + &stride, &drawCount, &topology); + + deviceContext->Unmap(mVertexBuffer, 0); + + // Apply vertex buffer + deviceContext->IASetVertexBuffers(0, 1, &mVertexBuffer, &stride, &startIdx); + + // Apply state + deviceContext->OMSetBlendState(NULL, NULL, 0xFFFFFFF); + deviceContext->OMSetDepthStencilState(NULL, 0xFFFFFFFF); + + if (scissor) + { + D3D11_RECT scissorRect; + scissorRect.left = scissor->x; + scissorRect.right = scissor->x + scissor->width; + scissorRect.top = scissor->y; + scissorRect.bottom = scissor->y + scissor->height; + + deviceContext->RSSetScissorRects(1, &scissorRect); + deviceContext->RSSetState(mScissorEnabledRasterizerState); + } + else + { + deviceContext->RSSetState(mScissorDisabledRasterizerState); + } + + // Apply shaders + deviceContext->IASetInputLayout(shader.mInputLayout); + deviceContext->IASetPrimitiveTopology(topology); + deviceContext->VSSetShader(shader.mVertexShader, NULL, 0); + + deviceContext->PSSetShader(shader.mPixelShader, NULL, 0); + deviceContext->GSSetShader(shader.mGeometryShader, NULL, 0); + + // Unset the currently bound shader resource to avoid conflicts + mRenderer->setShaderResource(gl::SAMPLER_PIXEL, 0, NULL); + + // Apply render target + mRenderer->setOneTimeRenderTarget(dest); + + // Set the viewport + D3D11_VIEWPORT viewport; + viewport.TopLeftX = 0; + viewport.TopLeftY = 0; + viewport.Width = destSize.width; + viewport.Height = destSize.height; + viewport.MinDepth = 0.0f; + viewport.MaxDepth = 1.0f; + deviceContext->RSSetViewports(1, &viewport); + + // Apply textures + mRenderer->setShaderResource(gl::SAMPLER_PIXEL, 0, source); + + // Apply samplers + ID3D11SamplerState *sampler = NULL; + switch (filter) + { + case GL_NEAREST: sampler = mPointSampler; break; + case GL_LINEAR: sampler = mLinearSampler; break; + + default: + UNREACHABLE(); + return gl::Error(GL_OUT_OF_MEMORY, "Internal error, unknown blit filter mode."); + } + deviceContext->PSSetSamplers(0, 1, &sampler); + + // Draw the quad + deviceContext->Draw(drawCount, 0); + + // Unbind textures and render targets and vertex buffer + mRenderer->setShaderResource(gl::SAMPLER_PIXEL, 0, NULL); + + mRenderer->unapplyRenderTargets(); + + UINT zero = 0; + ID3D11Buffer *const nullBuffer = NULL; + deviceContext->IASetVertexBuffers(0, 1, &nullBuffer, &zero, &zero); + + mRenderer->markAllStateDirty(); + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Blit11::copyStencil(ID3D11Resource *source, unsigned int sourceSubresource, const gl::Box &sourceArea, const gl::Extents &sourceSize, + ID3D11Resource *dest, unsigned int destSubresource, const gl::Box &destArea, const gl::Extents &destSize, + const gl::Rectangle *scissor) +{ + return copyDepthStencil(source, sourceSubresource, sourceArea, sourceSize, + dest, destSubresource, destArea, destSize, + scissor, true); +} + +gl::Error Blit11::copyDepth(ID3D11ShaderResourceView *source, const gl::Box &sourceArea, const gl::Extents &sourceSize, + ID3D11DepthStencilView *dest, const gl::Box &destArea, const gl::Extents &destSize, + const gl::Rectangle *scissor) +{ + HRESULT result; + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); + + // Set vertices + D3D11_MAPPED_SUBRESOURCE mappedResource; + result = deviceContext->Map(mVertexBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to map internal vertex buffer for texture copy, HRESULT: 0x%X.", result); + } + + UINT stride = 0; + UINT startIdx = 0; + UINT drawCount = 0; + D3D11_PRIMITIVE_TOPOLOGY topology; + + Write2DVertices(sourceArea, sourceSize, destArea, destSize, mappedResource.pData, + &stride, &drawCount, &topology); + + deviceContext->Unmap(mVertexBuffer, 0); + + // Apply vertex buffer + deviceContext->IASetVertexBuffers(0, 1, &mVertexBuffer, &stride, &startIdx); + + // Apply state + deviceContext->OMSetBlendState(NULL, NULL, 0xFFFFFFF); + deviceContext->OMSetDepthStencilState(mDepthStencilState, 0xFFFFFFFF); + + if (scissor) + { + D3D11_RECT scissorRect; + scissorRect.left = scissor->x; + scissorRect.right = scissor->x + scissor->width; + scissorRect.top = scissor->y; + scissorRect.bottom = scissor->y + scissor->height; + + deviceContext->RSSetScissorRects(1, &scissorRect); + deviceContext->RSSetState(mScissorEnabledRasterizerState); + } + else + { + deviceContext->RSSetState(mScissorDisabledRasterizerState); + } + + // Apply shaders + deviceContext->IASetInputLayout(mQuad2DIL); + deviceContext->IASetPrimitiveTopology(topology); + deviceContext->VSSetShader(mQuad2DVS, NULL, 0); + + deviceContext->PSSetShader(mDepthPS, NULL, 0); + deviceContext->GSSetShader(NULL, NULL, 0); + + // Unset the currently bound shader resource to avoid conflicts + mRenderer->setShaderResource(gl::SAMPLER_PIXEL, 0, NULL); + + // Apply render target + deviceContext->OMSetRenderTargets(0, NULL, dest); + + // Set the viewport + D3D11_VIEWPORT viewport; + viewport.TopLeftX = 0; + viewport.TopLeftY = 0; + viewport.Width = destSize.width; + viewport.Height = destSize.height; + viewport.MinDepth = 0.0f; + viewport.MaxDepth = 1.0f; + deviceContext->RSSetViewports(1, &viewport); + + // Apply textures + mRenderer->setShaderResource(gl::SAMPLER_PIXEL, 0, source); + + // Apply samplers + deviceContext->PSSetSamplers(0, 1, &mPointSampler); + + // Draw the quad + deviceContext->Draw(drawCount, 0); + + // Unbind textures and render targets and vertex buffer + mRenderer->setShaderResource(gl::SAMPLER_PIXEL, 0, NULL); + + mRenderer->unapplyRenderTargets(); + + UINT zero = 0; + ID3D11Buffer *const nullBuffer = NULL; + deviceContext->IASetVertexBuffers(0, 1, &nullBuffer, &zero, &zero); + + mRenderer->markAllStateDirty(); + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Blit11::copyDepthStencil(ID3D11Resource *source, unsigned int sourceSubresource, const gl::Box &sourceArea, const gl::Extents &sourceSize, + ID3D11Resource *dest, unsigned int destSubresource, const gl::Box &destArea, const gl::Extents &destSize, + const gl::Rectangle *scissor) +{ + return copyDepthStencil(source, sourceSubresource, sourceArea, sourceSize, + dest, destSubresource, destArea, destSize, + scissor, false); +} + +gl::Error Blit11::copyDepthStencil(ID3D11Resource *source, unsigned int sourceSubresource, const gl::Box &sourceArea, const gl::Extents &sourceSize, + ID3D11Resource *dest, unsigned int destSubresource, const gl::Box &destArea, const gl::Extents &destSize, + const gl::Rectangle *scissor, bool stencilOnly) +{ + ID3D11Device *device = mRenderer->getDevice(); + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); + + ID3D11Resource *sourceStaging = CreateStagingTexture(device, deviceContext, source, sourceSubresource, sourceSize, D3D11_CPU_ACCESS_READ); + // HACK: Create the destination staging buffer as a read/write texture so ID3D11DevicContext::UpdateSubresource can be called + // using it's mapped data as a source + ID3D11Resource *destStaging = CreateStagingTexture(device, deviceContext, dest, destSubresource, destSize, D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE); + + if (!sourceStaging || !destStaging) + { + SafeRelease(sourceStaging); + SafeRelease(destStaging); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal staging textures for depth stencil blit."); + } + + DXGI_FORMAT format = GetTextureFormat(source); + ASSERT(format == GetTextureFormat(dest)); + + const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(format); + unsigned int pixelSize = dxgiFormatInfo.pixelBytes; + unsigned int copyOffset = 0; + unsigned int copySize = pixelSize; + if (stencilOnly) + { + copyOffset = dxgiFormatInfo.depthBits / 8; + copySize = dxgiFormatInfo.stencilBits / 8; + + // It would be expensive to have non-byte sized stencil sizes since it would + // require reading from the destination, currently there aren't any though. + ASSERT(dxgiFormatInfo.stencilBits % 8 == 0 && + dxgiFormatInfo.depthBits % 8 == 0); + } + + D3D11_MAPPED_SUBRESOURCE sourceMapping; + HRESULT result = deviceContext->Map(sourceStaging, 0, D3D11_MAP_READ, 0, &sourceMapping); + if (FAILED(result)) + { + SafeRelease(sourceStaging); + SafeRelease(destStaging); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to map internal source staging texture for depth stencil blit, HRESULT: 0x%X.", result); + } + + D3D11_MAPPED_SUBRESOURCE destMapping; + result = deviceContext->Map(destStaging, 0, D3D11_MAP_WRITE, 0, &destMapping); + if (FAILED(result)) + { + deviceContext->Unmap(sourceStaging, 0); + SafeRelease(sourceStaging); + SafeRelease(destStaging); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to map internal destination staging texture for depth stencil blit, HRESULT: 0x%X.", result); + } + + gl::Rectangle clippedDestArea(destArea.x, destArea.y, destArea.width, destArea.height); + + // Clip dest area to the destination size + gl::ClipRectangle(clippedDestArea, gl::Rectangle(0, 0, destSize.width, destSize.height), &clippedDestArea); + + // Clip dest area to the scissor + if (scissor) + { + gl::ClipRectangle(clippedDestArea, *scissor, &clippedDestArea); + } + + // Determine if entire rows can be copied at once instead of each individual pixel, requires that there is + // no out of bounds lookups required, the entire pixel is copied and no stretching + bool wholeRowCopy = sourceArea.width == clippedDestArea.width && + sourceArea.x >= 0 && sourceArea.x + sourceArea.width <= sourceSize.width && + copySize == pixelSize; + + for (int y = clippedDestArea.y; y < clippedDestArea.y + clippedDestArea.height; y++) + { + float yPerc = static_cast(y - destArea.y) / (destArea.height - 1); + + // Interpolate using the original source rectangle to determine which row to sample from while clamping to the edges + unsigned int readRow = gl::clamp(sourceArea.y + floor(yPerc * (sourceArea.height - 1) + 0.5f), 0, sourceSize.height - 1); + unsigned int writeRow = y; + + if (wholeRowCopy) + { + void *sourceRow = reinterpret_cast(sourceMapping.pData) + + readRow * sourceMapping.RowPitch + + sourceArea.x * pixelSize; + + void *destRow = reinterpret_cast(destMapping.pData) + + writeRow * destMapping.RowPitch + + destArea.x * pixelSize; + + memcpy(destRow, sourceRow, pixelSize * destArea.width); + } + else + { + for (int x = clippedDestArea.x; x < clippedDestArea.x + clippedDestArea.width; x++) + { + float xPerc = static_cast(x - destArea.x) / (destArea.width - 1); + + // Interpolate the original source rectangle to determine which column to sample from while clamping to the edges + unsigned int readColumn = gl::clamp(sourceArea.x + floor(xPerc * (sourceArea.width - 1) + 0.5f), 0, sourceSize.width - 1); + unsigned int writeColumn = x; + + void *sourcePixel = reinterpret_cast(sourceMapping.pData) + + readRow * sourceMapping.RowPitch + + readColumn * pixelSize + + copyOffset; + + void *destPixel = reinterpret_cast(destMapping.pData) + + writeRow * destMapping.RowPitch + + writeColumn * pixelSize + + copyOffset; + + memcpy(destPixel, sourcePixel, copySize); + } + } + } + + // HACK: Use ID3D11DevicContext::UpdateSubresource which causes an extra copy compared to ID3D11DevicContext::CopySubresourceRegion + // according to MSDN. + deviceContext->UpdateSubresource(dest, destSubresource, NULL, destMapping.pData, destMapping.RowPitch, destMapping.DepthPitch); + + deviceContext->Unmap(sourceStaging, 0); + deviceContext->Unmap(destStaging, 0); + + // TODO: Determine why this call to ID3D11DevicContext::CopySubresourceRegion causes a TDR timeout on some + // systems when called repeatedly. + // deviceContext->CopySubresourceRegion(dest, destSubresource, 0, 0, 0, destStaging, 0, NULL); + + SafeRelease(sourceStaging); + SafeRelease(destStaging); + + return gl::Error(GL_NO_ERROR); +} + +bool Blit11::compareBlitParameters(const Blit11::BlitParameters &a, const Blit11::BlitParameters &b) +{ + return memcmp(&a, &b, sizeof(Blit11::BlitParameters)) < 0; +} + +bool Blit11::compareSwizzleParameters(const SwizzleParameters &a, const SwizzleParameters &b) +{ + return memcmp(&a, &b, sizeof(Blit11::SwizzleParameters)) < 0; +} + +void Blit11::add2DBlitShaderToMap(GLenum destFormat, bool signedInteger, ID3D11PixelShader *ps) +{ + BlitParameters params = { 0 }; + params.mDestinationFormat = destFormat; + params.mSignedInteger = signedInteger; + params.m3DBlit = false; + + ASSERT(mBlitShaderMap.find(params) == mBlitShaderMap.end()); + ASSERT(ps); + + Shader shader; + shader.mVertexWriteFunction = Write2DVertices; + shader.mInputLayout = mQuad2DIL; + shader.mVertexShader = mQuad2DVS; + shader.mGeometryShader = NULL; + shader.mPixelShader = ps; + + mBlitShaderMap[params] = shader; +} + +void Blit11::add3DBlitShaderToMap(GLenum destFormat, bool signedInteger, ID3D11PixelShader *ps) +{ + BlitParameters params = { 0 }; + params.mDestinationFormat = destFormat; + params.mSignedInteger = signedInteger; + params.m3DBlit = true; + + ASSERT(mBlitShaderMap.find(params) == mBlitShaderMap.end()); + ASSERT(ps); + + Shader shader; + shader.mVertexWriteFunction = Write3DVertices; + shader.mInputLayout = mQuad3DIL; + shader.mVertexShader = mQuad3DVS; + shader.mGeometryShader = mQuad3DGS; + shader.mPixelShader = ps; + + mBlitShaderMap[params] = shader; +} + +void Blit11::addSwizzleShaderToMap(GLenum destType, D3D11_SRV_DIMENSION viewDimension, ID3D11PixelShader *ps) +{ + SwizzleParameters params = { 0 }; + params.mDestinationType = destType; + params.mViewDimension = viewDimension; + + ASSERT(mSwizzleShaderMap.find(params) == mSwizzleShaderMap.end()); + ASSERT(ps); + + Shader shader; + switch (viewDimension) + { + case D3D_SRV_DIMENSION_TEXTURE2D: + shader.mVertexWriteFunction = Write2DVertices; + shader.mInputLayout = mQuad2DIL; + shader.mVertexShader = mQuad2DVS; + shader.mGeometryShader = NULL; + break; + + case D3D_SRV_DIMENSION_TEXTURE3D: + case D3D_SRV_DIMENSION_TEXTURE2DARRAY: + case D3D_SRV_DIMENSION_TEXTURECUBE: + shader.mVertexWriteFunction = Write3DVertices; + shader.mInputLayout = mQuad3DIL; + shader.mVertexShader = mQuad3DVS; + shader.mGeometryShader = mQuad3DGS; + break; + + default: + UNREACHABLE(); + break; + } + shader.mPixelShader = ps; + + mSwizzleShaderMap[params] = shader; +} + +void Blit11::buildShaderMap() +{ + ID3D11Device *device = mRenderer->getDevice(); + + // 2D shaders (OpenGL ES 2+) + add2DBlitShaderToMap(GL_RGBA, false, d3d11::CompilePS(device, g_PS_PassthroughRGBA2D, "Blit11 2D RGBA pixel shader" )); + add2DBlitShaderToMap(GL_BGRA_EXT, false, d3d11::CompilePS(device, g_PS_PassthroughRGBA2D, "Blit11 2D BGRA pixel shader" )); + add2DBlitShaderToMap(GL_RGB, false, d3d11::CompilePS(device, g_PS_PassthroughRGB2D, "Blit11 2D RGB pixel shader" )); + add2DBlitShaderToMap(GL_RG, false, d3d11::CompilePS(device, g_PS_PassthroughRG2D, "Blit11 2D RG pixel shader" )); + add2DBlitShaderToMap(GL_RED, false, d3d11::CompilePS(device, g_PS_PassthroughR2D, "Blit11 2D R pixel shader" )); + add2DBlitShaderToMap(GL_ALPHA, false, d3d11::CompilePS(device, g_PS_PassthroughRGBA2D, "Blit11 2D alpha pixel shader" )); + add2DBlitShaderToMap(GL_LUMINANCE, false, d3d11::CompilePS(device, g_PS_PassthroughLum2D, "Blit11 2D lum pixel shader" )); + add2DBlitShaderToMap(GL_LUMINANCE_ALPHA, false, d3d11::CompilePS(device, g_PS_PassthroughLumAlpha2D, "Blit11 2D luminance alpha pixel shader")); + + // 2D shaders (OpenGL ES 3+) + if (mRenderer->isES3Capable()) + { + add2DBlitShaderToMap(GL_RGBA_INTEGER, false, d3d11::CompilePS(device, g_PS_PassthroughRGBA2DUI, "Blit11 2D RGBA UI pixel shader" )); + add2DBlitShaderToMap(GL_RGBA_INTEGER, true, d3d11::CompilePS(device, g_PS_PassthroughRGBA2DI, "Blit11 2D RGBA I pixel shader" )); + add2DBlitShaderToMap(GL_RGB_INTEGER, false, d3d11::CompilePS(device, g_PS_PassthroughRGB2DUI, "Blit11 2D RGB UI pixel shader" )); + add2DBlitShaderToMap(GL_RGB_INTEGER, true, d3d11::CompilePS(device, g_PS_PassthroughRGB2DI, "Blit11 2D RGB I pixel shader" )); + add2DBlitShaderToMap(GL_RG_INTEGER, false, d3d11::CompilePS(device, g_PS_PassthroughRG2DUI, "Blit11 2D RG UI pixel shader" )); + add2DBlitShaderToMap(GL_RG_INTEGER, true, d3d11::CompilePS(device, g_PS_PassthroughRG2DI, "Blit11 2D RG I pixel shader" )); + add2DBlitShaderToMap(GL_RED_INTEGER, false, d3d11::CompilePS(device, g_PS_PassthroughR2DUI, "Blit11 2D R UI pixel shader" )); + add2DBlitShaderToMap(GL_RED_INTEGER, true, d3d11::CompilePS(device, g_PS_PassthroughR2DI, "Blit11 2D R I pixel shader" )); + } + + // 3D shaders (OpenGL ES 3+) + if (mRenderer->isES3Capable()) + { + add3DBlitShaderToMap(GL_RGBA, false, d3d11::CompilePS(device, g_PS_PassthroughRGBA3D, "Blit11 3D RGBA pixel shader" )); + add3DBlitShaderToMap(GL_RGBA_INTEGER, false, d3d11::CompilePS(device, g_PS_PassthroughRGBA3DUI, "Blit11 3D UI RGBA pixel shader" )); + add3DBlitShaderToMap(GL_RGBA_INTEGER, true, d3d11::CompilePS(device, g_PS_PassthroughRGBA3DI, "Blit11 3D I RGBA pixel shader" )); + add3DBlitShaderToMap(GL_BGRA_EXT, false, d3d11::CompilePS(device, g_PS_PassthroughRGBA3D, "Blit11 3D BGRA pixel shader" )); + add3DBlitShaderToMap(GL_RGB, false, d3d11::CompilePS(device, g_PS_PassthroughRGB3D, "Blit11 3D RGB pixel shader" )); + add3DBlitShaderToMap(GL_RGB_INTEGER, false, d3d11::CompilePS(device, g_PS_PassthroughRGB3DUI, "Blit11 3D RGB UI pixel shader" )); + add3DBlitShaderToMap(GL_RGB_INTEGER, true, d3d11::CompilePS(device, g_PS_PassthroughRGB3DI, "Blit11 3D RGB I pixel shader" )); + add3DBlitShaderToMap(GL_RG, false, d3d11::CompilePS(device, g_PS_PassthroughRG3D, "Blit11 3D RG pixel shader" )); + add3DBlitShaderToMap(GL_RG_INTEGER, false, d3d11::CompilePS(device, g_PS_PassthroughRG3DUI, "Blit11 3D RG UI pixel shader" )); + add3DBlitShaderToMap(GL_RG_INTEGER, true, d3d11::CompilePS(device, g_PS_PassthroughRG3DI, "Blit11 3D RG I pixel shader" )); + add3DBlitShaderToMap(GL_RED, false, d3d11::CompilePS(device, g_PS_PassthroughR3D, "Blit11 3D R pixel shader" )); + add3DBlitShaderToMap(GL_RED_INTEGER, false, d3d11::CompilePS(device, g_PS_PassthroughR3DUI, "Blit11 3D R UI pixel shader" )); + add3DBlitShaderToMap(GL_RED_INTEGER, true, d3d11::CompilePS(device, g_PS_PassthroughR3DI, "Blit11 3D R I pixel shader" )); + add3DBlitShaderToMap(GL_ALPHA, false, d3d11::CompilePS(device, g_PS_PassthroughRGBA3D, "Blit11 3D alpha pixel shader" )); + add3DBlitShaderToMap(GL_LUMINANCE, false, d3d11::CompilePS(device, g_PS_PassthroughLum3D, "Blit11 3D luminance pixel shader" )); + add3DBlitShaderToMap(GL_LUMINANCE_ALPHA, false, d3d11::CompilePS(device, g_PS_PassthroughLumAlpha3D, "Blit11 3D luminance alpha pixel shader")); + } + + // Swizzling shaders (OpenGL ES 3+) + if (mRenderer->isES3Capable()) + { + addSwizzleShaderToMap(GL_FLOAT, D3D_SRV_DIMENSION_TEXTURE2D, d3d11::CompilePS(device, g_PS_SwizzleF2D, "Blit11 2D F swizzle pixel shader" )); + addSwizzleShaderToMap(GL_UNSIGNED_INT, D3D_SRV_DIMENSION_TEXTURE2D, d3d11::CompilePS(device, g_PS_SwizzleUI2D, "Blit11 2D UI swizzle pixel shader")); + addSwizzleShaderToMap(GL_INT, D3D_SRV_DIMENSION_TEXTURE2D, d3d11::CompilePS(device, g_PS_SwizzleI2D, "Blit11 2D I swizzle pixel shader" )); + + addSwizzleShaderToMap(GL_FLOAT, D3D_SRV_DIMENSION_TEXTURECUBE, d3d11::CompilePS(device, g_PS_SwizzleF2DArray, "Blit11 2D Cube F swizzle pixel shader" )); + addSwizzleShaderToMap(GL_UNSIGNED_INT, D3D_SRV_DIMENSION_TEXTURECUBE, d3d11::CompilePS(device, g_PS_SwizzleUI2DArray, "Blit11 2D Cube UI swizzle pixel shader")); + addSwizzleShaderToMap(GL_INT, D3D_SRV_DIMENSION_TEXTURECUBE, d3d11::CompilePS(device, g_PS_SwizzleI2DArray, "Blit11 2D Cube I swizzle pixel shader" )); + + addSwizzleShaderToMap(GL_FLOAT, D3D_SRV_DIMENSION_TEXTURE3D, d3d11::CompilePS(device, g_PS_SwizzleF3D, "Blit11 3D F swizzle pixel shader" )); + addSwizzleShaderToMap(GL_UNSIGNED_INT, D3D_SRV_DIMENSION_TEXTURE3D, d3d11::CompilePS(device, g_PS_SwizzleUI3D, "Blit11 3D UI swizzle pixel shader")); + addSwizzleShaderToMap(GL_INT, D3D_SRV_DIMENSION_TEXTURE3D, d3d11::CompilePS(device, g_PS_SwizzleI3D, "Blit11 3D I swizzle pixel shader" )); + + addSwizzleShaderToMap(GL_FLOAT, D3D_SRV_DIMENSION_TEXTURE2DARRAY, d3d11::CompilePS(device, g_PS_SwizzleF2DArray, "Blit11 2D Array F swizzle pixel shader" )); + addSwizzleShaderToMap(GL_UNSIGNED_INT, D3D_SRV_DIMENSION_TEXTURE2DARRAY, d3d11::CompilePS(device, g_PS_SwizzleUI2DArray, "Blit11 2D Array UI swizzle pixel shader")); + addSwizzleShaderToMap(GL_INT, D3D_SRV_DIMENSION_TEXTURE2DARRAY, d3d11::CompilePS(device, g_PS_SwizzleI2DArray, "Blit11 2D Array I swizzle pixel shader" )); + } +} + +void Blit11::clearShaderMap() +{ + for (BlitShaderMap::iterator i = mBlitShaderMap.begin(); i != mBlitShaderMap.end(); ++i) + { + Shader &shader = i->second; + SafeRelease(shader.mPixelShader); + } + mBlitShaderMap.clear(); + + for (SwizzleShaderMap::iterator i = mSwizzleShaderMap.begin(); i != mSwizzleShaderMap.end(); ++i) + { + Shader &shader = i->second; + SafeRelease(shader.mPixelShader); + } + mSwizzleShaderMap.clear(); +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Blit11.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Blit11.h new file mode 100644 index 0000000000..d3a8c2c8a3 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Blit11.h @@ -0,0 +1,121 @@ +// +// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Blit11.cpp: Texture copy utility class. + +#ifndef LIBANGLE_RENDERER_D3D_D3D11_BLIT11_H_ +#define LIBANGLE_RENDERER_D3D_D3D11_BLIT11_H_ + +#include "common/angleutils.h" +#include "libANGLE/angletypes.h" +#include "libANGLE/Error.h" + +#include + +namespace rx +{ +class Renderer11; + +class Blit11 : angle::NonCopyable +{ + public: + explicit Blit11(Renderer11 *renderer); + ~Blit11(); + + gl::Error swizzleTexture(ID3D11ShaderResourceView *source, ID3D11RenderTargetView *dest, const gl::Extents &size, + GLenum swizzleRed, GLenum swizzleGreen, GLenum swizzleBlue, GLenum swizzleAlpha); + + gl::Error copyTexture(ID3D11ShaderResourceView *source, const gl::Box &sourceArea, const gl::Extents &sourceSize, + ID3D11RenderTargetView *dest, const gl::Box &destArea, const gl::Extents &destSize, + const gl::Rectangle *scissor, GLenum destFormat, GLenum filter); + + gl::Error copyStencil(ID3D11Resource *source, unsigned int sourceSubresource, const gl::Box &sourceArea, const gl::Extents &sourceSize, + ID3D11Resource *dest, unsigned int destSubresource, const gl::Box &destArea, const gl::Extents &destSize, + const gl::Rectangle *scissor); + + gl::Error copyDepth(ID3D11ShaderResourceView *source, const gl::Box &sourceArea, const gl::Extents &sourceSize, + ID3D11DepthStencilView *dest, const gl::Box &destArea, const gl::Extents &destSize, + const gl::Rectangle *scissor); + + gl::Error copyDepthStencil(ID3D11Resource *source, unsigned int sourceSubresource, const gl::Box &sourceArea, const gl::Extents &sourceSize, + ID3D11Resource *dest, unsigned int destSubresource, const gl::Box &destArea, const gl::Extents &destSize, + const gl::Rectangle *scissor); + + private: + Renderer11 *mRenderer; + + struct BlitParameters + { + GLenum mDestinationFormat; + bool mSignedInteger; + bool m3DBlit; + }; + + gl::Error copyDepthStencil(ID3D11Resource *source, unsigned int sourceSubresource, const gl::Box &sourceArea, const gl::Extents &sourceSize, + ID3D11Resource *dest, unsigned int destSubresource, const gl::Box &destArea, const gl::Extents &destSize, + const gl::Rectangle *scissor, bool stencilOnly); + + static bool compareBlitParameters(const BlitParameters &a, const BlitParameters &b); + + typedef void (*WriteVertexFunction)(const gl::Box &sourceArea, const gl::Extents &sourceSize, + const gl::Box &destArea, const gl::Extents &destSize, + void *outVertices, unsigned int *outStride, unsigned int *outVertexCount, + D3D11_PRIMITIVE_TOPOLOGY *outTopology); + + struct Shader + { + WriteVertexFunction mVertexWriteFunction; + ID3D11InputLayout *mInputLayout; + ID3D11VertexShader *mVertexShader; + ID3D11GeometryShader *mGeometryShader; + ID3D11PixelShader *mPixelShader; + }; + + typedef bool (*BlitParametersComparisonFunction)(const BlitParameters&, const BlitParameters &); + typedef std::map BlitShaderMap; + BlitShaderMap mBlitShaderMap; + + void add2DBlitShaderToMap(GLenum destFormat, bool signedInteger, ID3D11PixelShader *ps); + void add3DBlitShaderToMap(GLenum destFormat, bool signedInteger, ID3D11PixelShader *ps); + + struct SwizzleParameters + { + GLenum mDestinationType; + D3D11_SRV_DIMENSION mViewDimension; + }; + + static bool compareSwizzleParameters(const SwizzleParameters &a, const SwizzleParameters &b); + + typedef bool (*SwizzleParametersComparisonFunction)(const SwizzleParameters&, const SwizzleParameters &); + typedef std::map SwizzleShaderMap; + SwizzleShaderMap mSwizzleShaderMap; + + void addSwizzleShaderToMap(GLenum destType, D3D11_SRV_DIMENSION viewDimension, ID3D11PixelShader *ps); + + void buildShaderMap(); + void clearShaderMap(); + + ID3D11Buffer *mVertexBuffer; + ID3D11SamplerState *mPointSampler; + ID3D11SamplerState *mLinearSampler; + ID3D11RasterizerState *mScissorEnabledRasterizerState; + ID3D11RasterizerState *mScissorDisabledRasterizerState; + ID3D11DepthStencilState *mDepthStencilState; + + ID3D11InputLayout *mQuad2DIL; + ID3D11VertexShader *mQuad2DVS; + ID3D11PixelShader *mDepthPS; + + ID3D11InputLayout *mQuad3DIL; + ID3D11VertexShader *mQuad3DVS; + ID3D11GeometryShader *mQuad3DGS; + + ID3D11Buffer *mSwizzleCB; +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_D3D11_BLIT11_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Buffer11.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Buffer11.cpp new file mode 100644 index 0000000000..d56b0ea7ad --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Buffer11.cpp @@ -0,0 +1,1070 @@ +// +// Copyright 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Buffer11.cpp Defines the Buffer11 class. + +#include "libANGLE/renderer/d3d/d3d11/Buffer11.h" + +#include "common/MemoryBuffer.h" +#include "libANGLE/renderer/d3d/d3d11/Renderer11.h" +#include "libANGLE/renderer/d3d/d3d11/formatutils11.h" + +#if defined(ANGLE_MINGW32_COMPAT) +typedef enum D3D11_MAP_FLAG { + D3D11_MAP_FLAG_DO_NOT_WAIT = 0x100000 +} D3D11_MAP_FLAG; +#endif + +namespace rx +{ + +PackPixelsParams::PackPixelsParams() + : format(GL_NONE), + type(GL_NONE), + outputPitch(0), + packBuffer(NULL), + offset(0) +{} + +PackPixelsParams::PackPixelsParams(const gl::Rectangle &areaIn, GLenum formatIn, GLenum typeIn, GLuint outputPitchIn, + const gl::PixelPackState &packIn, ptrdiff_t offsetIn) + : area(areaIn), + format(formatIn), + type(typeIn), + outputPitch(outputPitchIn), + packBuffer(packIn.pixelBuffer.get()), + pack(packIn.alignment, packIn.reverseRowOrder), + offset(offsetIn) +{} + +namespace gl_d3d11 +{ + +D3D11_MAP GetD3DMapTypeFromBits(GLbitfield access) +{ + bool readBit = ((access & GL_MAP_READ_BIT) != 0); + bool writeBit = ((access & GL_MAP_WRITE_BIT) != 0); + + ASSERT(readBit || writeBit); + + // Note : we ignore the discard bit, because in D3D11, staging buffers + // don't accept the map-discard flag (discard only works for DYNAMIC usage) + + if (readBit && !writeBit) + { + return D3D11_MAP_READ; + } + else if (writeBit && !readBit) + { + return D3D11_MAP_WRITE; + } + else if (writeBit && readBit) + { + return D3D11_MAP_READ_WRITE; + } + else + { + UNREACHABLE(); + return D3D11_MAP_READ; + } +} + +} + +// Each instance of Buffer11::BufferStorage is specialized for a class of D3D binding points +// - vertex/transform feedback buffers +// - index buffers +// - pixel unpack buffers +// - uniform buffers +class Buffer11::BufferStorage : angle::NonCopyable +{ + public: + virtual ~BufferStorage() {} + + DataRevision getDataRevision() const { return mRevision; } + BufferUsage getUsage() const { return mUsage; } + size_t getSize() const { return mBufferSize; } + void setDataRevision(DataRevision rev) { mRevision = rev; } + + virtual bool isMappable() const = 0; + + virtual bool copyFromStorage(BufferStorage *source, size_t sourceOffset, + size_t size, size_t destOffset) = 0; + virtual gl::Error resize(size_t size, bool preserveData) = 0; + + virtual uint8_t *map(size_t offset, size_t length, GLbitfield access) = 0; + virtual void unmap() = 0; + + gl::Error setData(const uint8_t *data, size_t offset, size_t size); + + protected: + BufferStorage(Renderer11 *renderer, BufferUsage usage); + + Renderer11 *mRenderer; + DataRevision mRevision; + const BufferUsage mUsage; + size_t mBufferSize; +}; + +// A native buffer storage represents an underlying D3D11 buffer for a particular +// type of storage. +class Buffer11::NativeStorage : public Buffer11::BufferStorage +{ + public: + NativeStorage(Renderer11 *renderer, BufferUsage usage); + ~NativeStorage() override; + + bool isMappable() const override { return mUsage == BUFFER_USAGE_STAGING; } + + ID3D11Buffer *getNativeStorage() const { return mNativeStorage; } + + bool copyFromStorage(BufferStorage *source, size_t sourceOffset, + size_t size, size_t destOffset) override; + gl::Error resize(size_t size, bool preserveData) override; + + uint8_t *map(size_t offset, size_t length, GLbitfield access) override; + void unmap() override; + + private: + static void fillBufferDesc(D3D11_BUFFER_DESC* bufferDesc, Renderer11 *renderer, BufferUsage usage, unsigned int bufferSize); + + ID3D11Buffer *mNativeStorage; +}; + +// Pack storage represents internal storage for pack buffers. We implement pack buffers +// as CPU memory, tied to a staging texture, for asynchronous texture readback. +class Buffer11::PackStorage : public Buffer11::BufferStorage +{ + public: + explicit PackStorage(Renderer11 *renderer); + ~PackStorage() override; + + bool isMappable() const override { return true; } + + bool copyFromStorage(BufferStorage *source, size_t sourceOffset, + size_t size, size_t destOffset) override; + gl::Error resize(size_t size, bool preserveData) override; + + uint8_t *map(size_t offset, size_t length, GLbitfield access) override; + void unmap() override; + + gl::Error packPixels(ID3D11Texture2D *srcTexure, UINT srcSubresource, const PackPixelsParams ¶ms); + + private: + gl::Error flushQueuedPackCommand(); + + ID3D11Texture2D *mStagingTexture; + DXGI_FORMAT mTextureFormat; + gl::Extents mTextureSize; + MemoryBuffer mMemoryBuffer; + PackPixelsParams *mQueuedPackCommand; + PackPixelsParams mPackParams; + bool mDataModified; +}; + +// System memory storage stores a CPU memory buffer with our buffer data. +// For dynamic data, it's much faster to update the CPU memory buffer than +// it is to update a D3D staging buffer and read it back later. +class Buffer11::SystemMemoryStorage : public Buffer11::BufferStorage +{ + public: + explicit SystemMemoryStorage(Renderer11 *renderer); + ~SystemMemoryStorage() override {} + + bool isMappable() const override { return true; } + + bool copyFromStorage(BufferStorage *source, size_t sourceOffset, + size_t size, size_t destOffset) override; + gl::Error resize(size_t size, bool preserveData) override; + + uint8_t *map(size_t offset, size_t length, GLbitfield access) override; + void unmap() override; + + MemoryBuffer *getSystemCopy() { return &mSystemCopy; } + + protected: + MemoryBuffer mSystemCopy; +}; + +Buffer11::Buffer11(Renderer11 *renderer) + : BufferD3D(renderer), + mRenderer(renderer), + mSize(0), + mMappedStorage(NULL), + mReadUsageCount(0), + mHasSystemMemoryStorage(false) +{} + +Buffer11::~Buffer11() +{ + for (auto it = mBufferStorages.begin(); it != mBufferStorages.end(); it++) + { + SafeDelete(it->second); + } +} + +Buffer11 *Buffer11::makeBuffer11(BufferImpl *buffer) +{ + ASSERT(HAS_DYNAMIC_TYPE(Buffer11*, buffer)); + return static_cast(buffer); +} + +gl::Error Buffer11::setData(const void *data, size_t size, GLenum usage) +{ + gl::Error error = setSubData(data, size, 0); + if (error.isError()) + { + return error; + } + + if (usage == GL_STATIC_DRAW) + { + initializeStaticData(); + } + + return error; +} + +gl::Error Buffer11::getData(const uint8_t **outData) +{ + SystemMemoryStorage *systemMemoryStorage = nullptr; + gl::Error error = getSystemMemoryStorage(&systemMemoryStorage); + + if (error.isError()) + { + *outData = nullptr; + return error; + } + + mReadUsageCount = 0; + + ASSERT(systemMemoryStorage->getSize() >= mSize); + + *outData = systemMemoryStorage->getSystemCopy()->data(); + return gl::Error(GL_NO_ERROR); +} + +gl::Error Buffer11::getSystemMemoryStorage(SystemMemoryStorage **storageOut) +{ + BufferStorage *memStorageUntyped = getBufferStorage(BUFFER_USAGE_SYSTEM_MEMORY); + + if (memStorageUntyped == nullptr) + { + // TODO(jmadill): convert all to errors + return gl::Error(GL_OUT_OF_MEMORY); + } + + *storageOut = GetAs(memStorageUntyped); + return gl::Error(GL_NO_ERROR); +} + +gl::Error Buffer11::setSubData(const void *data, size_t size, size_t offset) +{ + size_t requiredSize = size + offset; + + if (data && size > 0) + { + // Use system memory storage for dynamic buffers. + + BufferStorage *writeBuffer = nullptr; + if (supportsDirectBinding()) + { + writeBuffer = getStagingStorage(); + + if (!writeBuffer) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate internal buffer."); + } + } + else + { + SystemMemoryStorage *systemMemoryStorage = nullptr; + gl::Error error = getSystemMemoryStorage(&systemMemoryStorage); + if (error.isError()) + { + return error; + } + + writeBuffer = systemMemoryStorage; + } + + ASSERT(writeBuffer); + + // Explicitly resize the staging buffer, preserving data if the new data will not + // completely fill the buffer + if (writeBuffer->getSize() < requiredSize) + { + bool preserveData = (offset > 0); + gl::Error error = writeBuffer->resize(requiredSize, preserveData); + if (error.isError()) + { + return error; + } + } + + writeBuffer->setData(static_cast(data), offset, size); + writeBuffer->setDataRevision(writeBuffer->getDataRevision() + 1); + } + + mSize = std::max(mSize, requiredSize); + invalidateStaticData(); + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Buffer11::copySubData(BufferImpl* source, GLintptr sourceOffset, GLintptr destOffset, GLsizeiptr size) +{ + Buffer11 *sourceBuffer = makeBuffer11(source); + ASSERT(sourceBuffer != NULL); + + BufferStorage *copyDest = getLatestBufferStorage(); + if (!copyDest) + { + copyDest = getStagingStorage(); + } + + BufferStorage *copySource = sourceBuffer->getLatestBufferStorage(); + + if (!copySource || !copyDest) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate internal staging buffer."); + } + + // If copying to/from a pixel pack buffer, we must have a staging or + // pack buffer partner, because other native buffers can't be mapped + if (copyDest->getUsage() == BUFFER_USAGE_PIXEL_PACK && !copySource->isMappable()) + { + copySource = sourceBuffer->getStagingStorage(); + } + else if (copySource->getUsage() == BUFFER_USAGE_PIXEL_PACK && !copyDest->isMappable()) + { + copyDest = getStagingStorage(); + } + + // D3D11 does not allow overlapped copies until 11.1, and only if the + // device supports D3D11_FEATURE_DATA_D3D11_OPTIONS::CopyWithOverlap + // Get around this via a different source buffer + if (copySource == copyDest) + { + if (copySource->getUsage() == BUFFER_USAGE_STAGING) + { + copySource = getBufferStorage(BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK); + } + else + { + copySource = getStagingStorage(); + } + } + + copyDest->copyFromStorage(copySource, sourceOffset, size, destOffset); + copyDest->setDataRevision(copyDest->getDataRevision() + 1); + + mSize = std::max(mSize, destOffset + size); + invalidateStaticData(); + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Buffer11::map(size_t offset, size_t length, GLbitfield access, GLvoid **mapPtr) +{ + ASSERT(!mMappedStorage); + + BufferStorage *latestStorage = getLatestBufferStorage(); + if (latestStorage && + (latestStorage->getUsage() == BUFFER_USAGE_PIXEL_PACK || + latestStorage->getUsage() == BUFFER_USAGE_STAGING)) + { + // Latest storage is mappable. + mMappedStorage = latestStorage; + } + else + { + // Fall back to using the staging buffer if the latest storage does + // not exist or is not CPU-accessible. + mMappedStorage = getStagingStorage(); + } + + if (!mMappedStorage) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate mappable internal buffer."); + } + + if ((access & GL_MAP_WRITE_BIT) > 0) + { + // Update the data revision immediately, since the data might be changed at any time + mMappedStorage->setDataRevision(mMappedStorage->getDataRevision() + 1); + } + + uint8_t *mappedBuffer = mMappedStorage->map(offset, length, access); + if (!mappedBuffer) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to map internal buffer."); + } + + *mapPtr = static_cast(mappedBuffer); + return gl::Error(GL_NO_ERROR); +} + +gl::Error Buffer11::unmap() +{ + ASSERT(mMappedStorage); + mMappedStorage->unmap(); + mMappedStorage = NULL; + return gl::Error(GL_NO_ERROR); +} + +void Buffer11::markTransformFeedbackUsage() +{ + BufferStorage *transformFeedbackStorage = getBufferStorage(BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK); + + if (transformFeedbackStorage) + { + transformFeedbackStorage->setDataRevision(transformFeedbackStorage->getDataRevision() + 1); + } + + invalidateStaticData(); +} + +void Buffer11::markBufferUsage() +{ + mReadUsageCount++; + + // Free the system memory storage if we decide it isn't being used very often. + const unsigned int usageLimit = 5; + + if (mReadUsageCount > usageLimit && mHasSystemMemoryStorage) + { + auto systemMemoryStorageIt = mBufferStorages.find(BUFFER_USAGE_SYSTEM_MEMORY); + ASSERT(systemMemoryStorageIt != mBufferStorages.end()); + + SafeDelete(systemMemoryStorageIt->second); + mBufferStorages.erase(systemMemoryStorageIt); + mHasSystemMemoryStorage = false; + } +} + +ID3D11Buffer *Buffer11::getBuffer(BufferUsage usage) +{ + markBufferUsage(); + + BufferStorage *bufferStorage = getBufferStorage(usage); + + if (!bufferStorage) + { + // Storage out-of-memory + return NULL; + } + + ASSERT(HAS_DYNAMIC_TYPE(NativeStorage*, bufferStorage)); + + return static_cast(bufferStorage)->getNativeStorage(); +} + +ID3D11ShaderResourceView *Buffer11::getSRV(DXGI_FORMAT srvFormat) +{ + BufferStorage *storage = getBufferStorage(BUFFER_USAGE_PIXEL_UNPACK); + + if (!storage) + { + // Storage out-of-memory + return NULL; + } + + ASSERT(HAS_DYNAMIC_TYPE(NativeStorage*, storage)); + ID3D11Buffer *buffer = static_cast(storage)->getNativeStorage(); + + auto bufferSRVIt = mBufferResourceViews.find(srvFormat); + + if (bufferSRVIt != mBufferResourceViews.end()) + { + if (bufferSRVIt->second.first == buffer) + { + return bufferSRVIt->second.second; + } + else + { + // The underlying buffer has changed since the SRV was created: recreate the SRV. + SafeRelease(bufferSRVIt->second.second); + } + } + + ID3D11Device *device = mRenderer->getDevice(); + ID3D11ShaderResourceView *bufferSRV = NULL; + + const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(srvFormat); + + D3D11_SHADER_RESOURCE_VIEW_DESC bufferSRVDesc; + bufferSRVDesc.Buffer.ElementOffset = 0; + bufferSRVDesc.Buffer.ElementWidth = mSize / dxgiFormatInfo.pixelBytes; + bufferSRVDesc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER; + bufferSRVDesc.Format = srvFormat; + + HRESULT result = device->CreateShaderResourceView(buffer, &bufferSRVDesc, &bufferSRV); + UNUSED_ASSERTION_VARIABLE(result); + ASSERT(SUCCEEDED(result)); + + mBufferResourceViews[srvFormat] = BufferSRVPair(buffer, bufferSRV); + + return bufferSRV; +} + +gl::Error Buffer11::packPixels(ID3D11Texture2D *srcTexture, UINT srcSubresource, const PackPixelsParams ¶ms) +{ + PackStorage *packStorage = getPackStorage(); + BufferStorage *latestStorage = getLatestBufferStorage(); + + if (packStorage) + { + gl::Error error = packStorage->packPixels(srcTexture, srcSubresource, params); + if (error.isError()) + { + return error; + } + packStorage->setDataRevision(latestStorage ? latestStorage->getDataRevision() + 1 : 1); + } + + return gl::Error(GL_NO_ERROR); +} + +Buffer11::BufferStorage *Buffer11::getBufferStorage(BufferUsage usage) +{ + BufferStorage *newStorage = NULL; + auto directBufferIt = mBufferStorages.find(usage); + if (directBufferIt != mBufferStorages.end()) + { + newStorage = directBufferIt->second; + } + + if (!newStorage) + { + if (usage == BUFFER_USAGE_PIXEL_PACK) + { + newStorage = new PackStorage(mRenderer); + } + else if (usage == BUFFER_USAGE_SYSTEM_MEMORY) + { + newStorage = new SystemMemoryStorage(mRenderer); + mHasSystemMemoryStorage = true; + } + else + { + // buffer is not allocated, create it + newStorage = new NativeStorage(mRenderer, usage); + } + + mBufferStorages.insert(std::make_pair(usage, newStorage)); + } + + // resize buffer + if (newStorage->getSize() < mSize) + { + if (newStorage->resize(mSize, true).isError()) + { + // Out of memory error + return NULL; + } + } + + BufferStorage *latestBuffer = getLatestBufferStorage(); + if (latestBuffer && latestBuffer->getDataRevision() > newStorage->getDataRevision()) + { + // Copy through a staging buffer if we're copying from or to a non-staging, mappable + // buffer storage. This is because we can't map a GPU buffer, and copy CPU + // data directly. If we're already using a staging buffer we're fine. + if (latestBuffer->getUsage() != BUFFER_USAGE_STAGING && + newStorage->getUsage() != BUFFER_USAGE_STAGING && + (!latestBuffer->isMappable() || !newStorage->isMappable())) + { + NativeStorage *stagingBuffer = getStagingStorage(); + + stagingBuffer->copyFromStorage(latestBuffer, 0, latestBuffer->getSize(), 0); + stagingBuffer->setDataRevision(latestBuffer->getDataRevision()); + + latestBuffer = stagingBuffer; + } + + // if copyFromStorage returns true, the D3D buffer has been recreated + // and we should update our serial + if (newStorage->copyFromStorage(latestBuffer, 0, latestBuffer->getSize(), 0)) + { + updateSerial(); + } + newStorage->setDataRevision(latestBuffer->getDataRevision()); + } + + return newStorage; +} + +Buffer11::BufferStorage *Buffer11::getLatestBufferStorage() const +{ + // Even though we iterate over all the direct buffers, it is expected that only + // 1 or 2 will be present. + BufferStorage *latestStorage = NULL; + DataRevision latestRevision = 0; + for (auto it = mBufferStorages.begin(); it != mBufferStorages.end(); it++) + { + BufferStorage *storage = it->second; + if (!latestStorage || storage->getDataRevision() > latestRevision) + { + latestStorage = storage; + latestRevision = storage->getDataRevision(); + } + } + + // resize buffer + if (latestStorage && latestStorage->getSize() < mSize) + { + if (latestStorage->resize(mSize, true).isError()) + { + // Out of memory error + return NULL; + } + } + + return latestStorage; +} + +Buffer11::NativeStorage *Buffer11::getStagingStorage() +{ + BufferStorage *stagingStorage = getBufferStorage(BUFFER_USAGE_STAGING); + + if (!stagingStorage) + { + // Out-of-memory + return NULL; + } + + ASSERT(HAS_DYNAMIC_TYPE(NativeStorage*, stagingStorage)); + return static_cast(stagingStorage); +} + +Buffer11::PackStorage *Buffer11::getPackStorage() +{ + BufferStorage *packStorage = getBufferStorage(BUFFER_USAGE_PIXEL_PACK); + + if (!packStorage) + { + // Out-of-memory + return NULL; + } + + ASSERT(HAS_DYNAMIC_TYPE(PackStorage*, packStorage)); + return static_cast(packStorage); +} + +bool Buffer11::supportsDirectBinding() const +{ + // Do not support direct buffers for dynamic data. The streaming buffer + // offers better performance for data which changes every frame. + // Check for absence of static buffer interfaces to detect dynamic data. + return (mStaticVertexBuffer && mStaticIndexBuffer); +} + +Buffer11::BufferStorage::BufferStorage(Renderer11 *renderer, BufferUsage usage) + : mRenderer(renderer), + mUsage(usage), + mRevision(0), + mBufferSize(0) +{ +} + +gl::Error Buffer11::BufferStorage::setData(const uint8_t *data, size_t offset, size_t size) +{ + ASSERT(isMappable()); + + uint8_t *writePointer = map(offset, size, GL_MAP_WRITE_BIT); + if (!writePointer) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to map internal buffer."); + } + + memcpy(writePointer, data, size); + + unmap(); + + return gl::Error(GL_NO_ERROR); +} + +Buffer11::NativeStorage::NativeStorage(Renderer11 *renderer, BufferUsage usage) + : BufferStorage(renderer, usage), + mNativeStorage(NULL) +{ +} + +Buffer11::NativeStorage::~NativeStorage() +{ + SafeRelease(mNativeStorage); +} + +// Returns true if it recreates the direct buffer +bool Buffer11::NativeStorage::copyFromStorage(BufferStorage *source, size_t sourceOffset, + size_t size, size_t destOffset) +{ + ID3D11DeviceContext *context = mRenderer->getDeviceContext(); + + size_t requiredSize = sourceOffset + size; + bool createBuffer = !mNativeStorage || mBufferSize < requiredSize; + + // (Re)initialize D3D buffer if needed + if (createBuffer) + { + bool preserveData = (destOffset > 0); + resize(source->getSize(), preserveData); + } + + if (source->getUsage() == BUFFER_USAGE_PIXEL_PACK || + source->getUsage() == BUFFER_USAGE_SYSTEM_MEMORY) + { + ASSERT(source->isMappable()); + + uint8_t *sourcePointer = source->map(sourceOffset, size, GL_MAP_READ_BIT); + + D3D11_MAPPED_SUBRESOURCE mappedResource; + HRESULT hr = context->Map(mNativeStorage, 0, D3D11_MAP_WRITE, 0, &mappedResource); + UNUSED_ASSERTION_VARIABLE(hr); + ASSERT(SUCCEEDED(hr)); + + uint8_t *destPointer = static_cast(mappedResource.pData) + destOffset; + + // Offset bounds are validated at the API layer + ASSERT(sourceOffset + size <= destOffset + mBufferSize); + memcpy(destPointer, sourcePointer, size); + + context->Unmap(mNativeStorage, 0); + source->unmap(); + } + else + { + ASSERT(HAS_DYNAMIC_TYPE(NativeStorage*, source)); + + D3D11_BOX srcBox; + srcBox.left = sourceOffset; + srcBox.right = sourceOffset + size; + srcBox.top = 0; + srcBox.bottom = 1; + srcBox.front = 0; + srcBox.back = 1; + + ASSERT(HAS_DYNAMIC_TYPE(NativeStorage*, source)); + ID3D11Buffer *sourceBuffer = static_cast(source)->getNativeStorage(); + + context->CopySubresourceRegion(mNativeStorage, 0, destOffset, 0, 0, sourceBuffer, 0, &srcBox); + } + + return createBuffer; +} + +gl::Error Buffer11::NativeStorage::resize(size_t size, bool preserveData) +{ + ID3D11Device *device = mRenderer->getDevice(); + ID3D11DeviceContext *context = mRenderer->getDeviceContext(); + + D3D11_BUFFER_DESC bufferDesc; + fillBufferDesc(&bufferDesc, mRenderer, mUsage, size); + + ID3D11Buffer *newBuffer; + HRESULT result = device->CreateBuffer(&bufferDesc, NULL, &newBuffer); + + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal buffer, result: 0x%X.", result); + } + + if (mNativeStorage && preserveData) + { + // We don't call resize if the buffer is big enough already. + ASSERT(mBufferSize <= size); + + D3D11_BOX srcBox; + srcBox.left = 0; + srcBox.right = mBufferSize; + srcBox.top = 0; + srcBox.bottom = 1; + srcBox.front = 0; + srcBox.back = 1; + + context->CopySubresourceRegion(newBuffer, 0, 0, 0, 0, mNativeStorage, 0, &srcBox); + } + + // No longer need the old buffer + SafeRelease(mNativeStorage); + mNativeStorage = newBuffer; + + mBufferSize = bufferDesc.ByteWidth; + + return gl::Error(GL_NO_ERROR); +} + +void Buffer11::NativeStorage::fillBufferDesc(D3D11_BUFFER_DESC* bufferDesc, Renderer11 *renderer, + BufferUsage usage, unsigned int bufferSize) +{ + bufferDesc->ByteWidth = bufferSize; + bufferDesc->MiscFlags = 0; + bufferDesc->StructureByteStride = 0; + + switch (usage) + { + case BUFFER_USAGE_STAGING: + bufferDesc->Usage = D3D11_USAGE_STAGING; + bufferDesc->BindFlags = 0; + bufferDesc->CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE; + break; + + case BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK: + bufferDesc->Usage = D3D11_USAGE_DEFAULT; + bufferDesc->BindFlags = D3D11_BIND_VERTEX_BUFFER; + + if (renderer->isES3Capable()) + { + bufferDesc->BindFlags |= D3D11_BIND_STREAM_OUTPUT; + } + + bufferDesc->CPUAccessFlags = 0; + break; + + case BUFFER_USAGE_INDEX: + bufferDesc->Usage = D3D11_USAGE_DEFAULT; + bufferDesc->BindFlags = D3D11_BIND_INDEX_BUFFER; + bufferDesc->CPUAccessFlags = 0; + break; + + case BUFFER_USAGE_PIXEL_UNPACK: + bufferDesc->Usage = D3D11_USAGE_DEFAULT; + bufferDesc->BindFlags = D3D11_BIND_SHADER_RESOURCE; + bufferDesc->CPUAccessFlags = 0; + break; + + case BUFFER_USAGE_UNIFORM: + bufferDesc->Usage = D3D11_USAGE_DYNAMIC; + bufferDesc->BindFlags = D3D11_BIND_CONSTANT_BUFFER; + bufferDesc->CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + + // Constant buffers must be of a limited size, and aligned to 16 byte boundaries + // For our purposes we ignore any buffer data past the maximum constant buffer size + bufferDesc->ByteWidth = roundUp(bufferDesc->ByteWidth, 16u); + bufferDesc->ByteWidth = std::min(bufferDesc->ByteWidth, renderer->getRendererCaps().maxUniformBlockSize); + break; + + default: + UNREACHABLE(); + } +} + +uint8_t *Buffer11::NativeStorage::map(size_t offset, size_t length, GLbitfield access) +{ + ASSERT(mUsage == BUFFER_USAGE_STAGING); + + D3D11_MAPPED_SUBRESOURCE mappedResource; + ID3D11DeviceContext *context = mRenderer->getDeviceContext(); + D3D11_MAP d3dMapType = gl_d3d11::GetD3DMapTypeFromBits(access); + UINT d3dMapFlag = ((access & GL_MAP_UNSYNCHRONIZED_BIT) != 0 ? D3D11_MAP_FLAG_DO_NOT_WAIT : 0); + + HRESULT result = context->Map(mNativeStorage, 0, d3dMapType, d3dMapFlag, &mappedResource); + UNUSED_ASSERTION_VARIABLE(result); + ASSERT(SUCCEEDED(result)); + + return static_cast(mappedResource.pData) + offset; +} + +void Buffer11::NativeStorage::unmap() +{ + ASSERT(mUsage == BUFFER_USAGE_STAGING); + ID3D11DeviceContext *context = mRenderer->getDeviceContext(); + context->Unmap(mNativeStorage, 0); +} + +Buffer11::PackStorage::PackStorage(Renderer11 *renderer) + : BufferStorage(renderer, BUFFER_USAGE_PIXEL_PACK), + mStagingTexture(NULL), + mTextureFormat(DXGI_FORMAT_UNKNOWN), + mQueuedPackCommand(NULL), + mDataModified(false) +{ +} + +Buffer11::PackStorage::~PackStorage() +{ + SafeRelease(mStagingTexture); + SafeDelete(mQueuedPackCommand); +} + +bool Buffer11::PackStorage::copyFromStorage(BufferStorage *source, size_t sourceOffset, + size_t size, size_t destOffset) +{ + // We copy through a staging buffer when drawing with a pack buffer, + // or for other cases where we access the pack buffer + UNREACHABLE(); + return false; +} + +gl::Error Buffer11::PackStorage::resize(size_t size, bool preserveData) +{ + if (size != mBufferSize) + { + if (!mMemoryBuffer.resize(size)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to resize internal buffer storage."); + } + mBufferSize = size; + } + + return gl::Error(GL_NO_ERROR); +} + +uint8_t *Buffer11::PackStorage::map(size_t offset, size_t length, GLbitfield access) +{ + ASSERT(offset + length <= getSize()); + // TODO: fast path + // We might be able to optimize out one or more memcpy calls by detecting when + // and if D3D packs the staging texture memory identically to how we would fill + // the pack buffer according to the current pack state. + + gl::Error error = flushQueuedPackCommand(); + if (error.isError()) + { + return NULL; + } + + mDataModified = (mDataModified || (access & GL_MAP_WRITE_BIT) != 0); + + return mMemoryBuffer.data() + offset; +} + +void Buffer11::PackStorage::unmap() +{ + // No-op +} + +gl::Error Buffer11::PackStorage::packPixels(ID3D11Texture2D *srcTexure, UINT srcSubresource, const PackPixelsParams ¶ms) +{ + gl::Error error = flushQueuedPackCommand(); + if (error.isError()) + { + return error; + } + + mQueuedPackCommand = new PackPixelsParams(params); + + D3D11_TEXTURE2D_DESC textureDesc; + srcTexure->GetDesc(&textureDesc); + + if (mStagingTexture != NULL && + (mTextureFormat != textureDesc.Format || + mTextureSize.width != params.area.width || + mTextureSize.height != params.area.height)) + { + SafeRelease(mStagingTexture); + mTextureSize.width = 0; + mTextureSize.height = 0; + mTextureFormat = DXGI_FORMAT_UNKNOWN; + } + + if (mStagingTexture == NULL) + { + ID3D11Device *device = mRenderer->getDevice(); + HRESULT hr; + + mTextureSize.width = params.area.width; + mTextureSize.height = params.area.height; + mTextureFormat = textureDesc.Format; + + D3D11_TEXTURE2D_DESC stagingDesc; + stagingDesc.Width = params.area.width; + stagingDesc.Height = params.area.height; + stagingDesc.MipLevels = 1; + stagingDesc.ArraySize = 1; + stagingDesc.Format = mTextureFormat; + 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; + + hr = device->CreateTexture2D(&stagingDesc, NULL, &mStagingTexture); + if (FAILED(hr)) + { + ASSERT(hr == E_OUTOFMEMORY); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate internal staging texture."); + } + } + + // ReadPixels from multisampled FBOs isn't supported in current GL + ASSERT(textureDesc.SampleDesc.Count <= 1); + + ID3D11DeviceContext *immediateContext = mRenderer->getDeviceContext(); + D3D11_BOX srcBox; + srcBox.left = params.area.x; + srcBox.right = params.area.x + params.area.width; + srcBox.top = params.area.y; + srcBox.bottom = params.area.y + params.area.height; + srcBox.front = 0; + srcBox.back = 1; + + // Asynchronous copy + immediateContext->CopySubresourceRegion(mStagingTexture, 0, 0, 0, 0, srcTexure, srcSubresource, &srcBox); + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Buffer11::PackStorage::flushQueuedPackCommand() +{ + ASSERT(mMemoryBuffer.size() > 0); + + if (mQueuedPackCommand) + { + gl::Error error = mRenderer->packPixels(mStagingTexture, *mQueuedPackCommand, mMemoryBuffer.data()); + SafeDelete(mQueuedPackCommand); + if (error.isError()) + { + return error; + } + } + + return gl::Error(GL_NO_ERROR); +} + +Buffer11::SystemMemoryStorage::SystemMemoryStorage(Renderer11 *renderer) + : Buffer11::BufferStorage(renderer, BUFFER_USAGE_SYSTEM_MEMORY) +{} + +bool Buffer11::SystemMemoryStorage::copyFromStorage(BufferStorage *source, size_t sourceOffset, + size_t size, size_t destOffset) +{ + ASSERT(source->isMappable()); + const uint8_t *sourceData = source->map(sourceOffset, size, GL_MAP_READ_BIT); + ASSERT(destOffset + size <= mSystemCopy.size()); + memcpy(mSystemCopy.data() + destOffset, sourceData, size); + source->unmap(); + return true; +} + +gl::Error Buffer11::SystemMemoryStorage::resize(size_t size, bool preserveData) +{ + if (mSystemCopy.size() < size) + { + if (!mSystemCopy.resize(size)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to resize SystemMemoryStorage"); + } + mBufferSize = size; + } + + return gl::Error(GL_NO_ERROR); +} + +uint8_t *Buffer11::SystemMemoryStorage::map(size_t offset, size_t length, GLbitfield access) +{ + ASSERT(!mSystemCopy.empty() && offset + length <= mSystemCopy.size()); + return mSystemCopy.data() + offset; +} + +void Buffer11::SystemMemoryStorage::unmap() +{ + // No-op +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Buffer11.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Buffer11.h new file mode 100644 index 0000000000..39bafe880e --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Buffer11.h @@ -0,0 +1,103 @@ +// +// Copyright 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Buffer11.h: Defines the rx::Buffer11 class which implements rx::BufferImpl via rx::BufferD3D. + +#ifndef LIBANGLE_RENDERER_D3D_D3D11_BUFFER11_H_ +#define LIBANGLE_RENDERER_D3D_D3D11_BUFFER11_H_ + +#include "libANGLE/angletypes.h" +#include "libANGLE/renderer/d3d/BufferD3D.h" + +namespace rx +{ +class Renderer11; + +enum BufferUsage +{ + BUFFER_USAGE_STAGING, + BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK, + BUFFER_USAGE_INDEX, + BUFFER_USAGE_PIXEL_UNPACK, + BUFFER_USAGE_PIXEL_PACK, + BUFFER_USAGE_UNIFORM, + BUFFER_USAGE_SYSTEM_MEMORY, +}; + +struct PackPixelsParams +{ + PackPixelsParams(); + PackPixelsParams(const gl::Rectangle &area, GLenum format, GLenum type, GLuint outputPitch, + const gl::PixelPackState &pack, ptrdiff_t offset); + + gl::Rectangle area; + GLenum format; + GLenum type; + GLuint outputPitch; + gl::Buffer *packBuffer; + gl::PixelPackState pack; + ptrdiff_t offset; +}; + +typedef size_t DataRevision; + +class Buffer11 : public BufferD3D +{ + public: + Buffer11(Renderer11 *renderer); + virtual ~Buffer11(); + + static Buffer11 *makeBuffer11(BufferImpl *buffer); + + ID3D11Buffer *getBuffer(BufferUsage usage); + ID3D11ShaderResourceView *getSRV(DXGI_FORMAT srvFormat); + bool isMapped() const { return mMappedStorage != NULL; } + gl::Error packPixels(ID3D11Texture2D *srcTexure, UINT srcSubresource, const PackPixelsParams ¶ms); + + // BufferD3D implementation + virtual size_t getSize() const { return mSize; } + virtual bool supportsDirectBinding() const; + + // BufferImpl implementation + virtual gl::Error setData(const void* data, size_t size, GLenum usage); + gl::Error getData(const uint8_t **outData) override; + virtual gl::Error setSubData(const void* data, size_t size, size_t offset); + virtual gl::Error copySubData(BufferImpl* source, GLintptr sourceOffset, GLintptr destOffset, GLsizeiptr size); + virtual gl::Error map(size_t offset, size_t length, GLbitfield access, GLvoid **mapPtr); + virtual gl::Error unmap(); + virtual void markTransformFeedbackUsage(); + + private: + class BufferStorage; + class NativeStorage; + class PackStorage; + class SystemMemoryStorage; + + Renderer11 *mRenderer; + size_t mSize; + + BufferStorage *mMappedStorage; + + std::map mBufferStorages; + + typedef std::pair BufferSRVPair; + std::map mBufferResourceViews; + + unsigned int mReadUsageCount; + bool mHasSystemMemoryStorage; + + void markBufferUsage(); + NativeStorage *getStagingStorage(); + PackStorage *getPackStorage(); + gl::Error getSystemMemoryStorage(SystemMemoryStorage **storageOut); + + BufferStorage *getBufferStorage(BufferUsage usage); + BufferStorage *getLatestBufferStorage() const; +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_D3D11_BUFFER11_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Clear11.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Clear11.cpp new file mode 100644 index 0000000000..057c3bed42 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Clear11.cpp @@ -0,0 +1,614 @@ +// +// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Clear11.cpp: Framebuffer clear utility class. + +#include "libANGLE/renderer/d3d/d3d11/Clear11.h" + +#include + +#include "libANGLE/FramebufferAttachment.h" +#include "libANGLE/formatutils.h" +#include "libANGLE/renderer/d3d/FramebufferD3D.h" +#include "libANGLE/renderer/d3d/d3d11/Renderer11.h" +#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h" +#include "libANGLE/renderer/d3d/d3d11/RenderTarget11.h" +#include "libANGLE/renderer/d3d/d3d11/formatutils11.h" + +// Precompiled shaders +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearfloat11vs.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearfloat11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearfloat11_fl9ps.h" + +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearuint11vs.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearuint11ps.h" + +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearsint11vs.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearsint11ps.h" + +namespace rx +{ + +template +static void ApplyVertices(const gl::Extents &framebufferSize, const gl::Rectangle *scissor, const gl::Color &color, float depth, void *buffer) +{ + d3d11::PositionDepthColorVertex *vertices = reinterpret_cast*>(buffer); + + float depthClear = gl::clamp01(depth); + float left = -1.0f; + float right = 1.0f; + float top = -1.0f; + float bottom = 1.0f; + + // Clip the quad coordinates to the scissor if needed + if (scissor != NULL) + { + left = std::max(left, (scissor->x / float(framebufferSize.width)) * 2.0f - 1.0f); + right = std::min(right, ((scissor->x + scissor->width) / float(framebufferSize.width)) * 2.0f - 1.0f); + top = std::max(top, ((framebufferSize.height - scissor->y - scissor->height) / float(framebufferSize.height)) * 2.0f - 1.0f); + bottom = std::min(bottom, ((framebufferSize.height - scissor->y) / float(framebufferSize.height)) * 2.0f - 1.0f); + } + + d3d11::SetPositionDepthColorVertex(vertices + 0, left, bottom, depthClear, color); + d3d11::SetPositionDepthColorVertex(vertices + 1, left, top, depthClear, color); + d3d11::SetPositionDepthColorVertex(vertices + 2, right, bottom, depthClear, color); + d3d11::SetPositionDepthColorVertex(vertices + 3, right, top, depthClear, color); +} + +template +Clear11::ClearShader Clear11::CreateClearShader(ID3D11Device *device, DXGI_FORMAT colorType, const BYTE (&vsByteCode)[vsSize], const BYTE (&psByteCode)[psSize]) +{ + HRESULT result; + + ClearShader shader = { 0 }; + + D3D11_INPUT_ELEMENT_DESC quadLayout[] = + { + { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, + { "COLOR", 0, colorType, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 }, + }; + + result = device->CreateInputLayout(quadLayout, ArraySize(quadLayout), vsByteCode, vsSize, &shader.inputLayout); + ASSERT(SUCCEEDED(result)); + + result = device->CreateVertexShader(vsByteCode, vsSize, NULL, &shader.vertexShader); + ASSERT(SUCCEEDED(result)); + + result = device->CreatePixelShader(psByteCode, psSize, NULL, &shader.pixelShader); + ASSERT(SUCCEEDED(result)); + + return shader; +} + +Clear11::Clear11(Renderer11 *renderer) + : mRenderer(renderer), mClearBlendStates(StructLessThan), mClearDepthStencilStates(StructLessThan), + mVertexBuffer(NULL), mRasterizerState(NULL), mSupportsClearView(false) +{ + HRESULT result; + ID3D11Device *device = renderer->getDevice(); + + D3D11_BUFFER_DESC vbDesc; + vbDesc.ByteWidth = sizeof(d3d11::PositionDepthColorVertex) * 4; + vbDesc.Usage = D3D11_USAGE_DYNAMIC; + vbDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; + vbDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + vbDesc.MiscFlags = 0; + vbDesc.StructureByteStride = 0; + + result = device->CreateBuffer(&vbDesc, NULL, &mVertexBuffer); + ASSERT(SUCCEEDED(result)); + d3d11::SetDebugName(mVertexBuffer, "Clear11 masked clear vertex buffer"); + + D3D11_RASTERIZER_DESC rsDesc; + rsDesc.FillMode = D3D11_FILL_SOLID; + rsDesc.CullMode = D3D11_CULL_NONE; + rsDesc.FrontCounterClockwise = FALSE; + rsDesc.DepthBias = 0; + rsDesc.DepthBiasClamp = 0.0f; + rsDesc.SlopeScaledDepthBias = 0.0f; + rsDesc.DepthClipEnable = TRUE; + rsDesc.ScissorEnable = FALSE; + rsDesc.MultisampleEnable = FALSE; + rsDesc.AntialiasedLineEnable = FALSE; + + result = device->CreateRasterizerState(&rsDesc, &mRasterizerState); + ASSERT(SUCCEEDED(result)); + d3d11::SetDebugName(mRasterizerState, "Clear11 masked clear rasterizer state"); + + if (renderer->getFeatureLevel() <= D3D_FEATURE_LEVEL_9_3) + { + mFloatClearShader = CreateClearShader(device, DXGI_FORMAT_R32G32B32A32_FLOAT, g_VS_ClearFloat, g_PS_ClearFloat_FL9); + } + else + { + mFloatClearShader = CreateClearShader(device, DXGI_FORMAT_R32G32B32A32_FLOAT, g_VS_ClearFloat, g_PS_ClearFloat); + } + + if (renderer->isES3Capable()) + { + mUintClearShader = CreateClearShader(device, DXGI_FORMAT_R32G32B32A32_UINT, g_VS_ClearUint, g_PS_ClearUint ); + mIntClearShader = CreateClearShader(device, DXGI_FORMAT_R32G32B32A32_SINT, g_VS_ClearSint, g_PS_ClearSint ); + } + +#if defined(ANGLE_ENABLE_D3D11_1) + if (renderer->getDeviceContext1IfSupported()) + { + D3D11_FEATURE_DATA_D3D11_OPTIONS d3d11Options; + device->CheckFeatureSupport(D3D11_FEATURE_D3D11_OPTIONS, &d3d11Options, sizeof(D3D11_FEATURE_DATA_D3D11_OPTIONS)); + mSupportsClearView = (d3d11Options.ClearView != FALSE); + } +#endif +} + +Clear11::~Clear11() +{ + for (ClearBlendStateMap::iterator i = mClearBlendStates.begin(); i != mClearBlendStates.end(); i++) + { + SafeRelease(i->second); + } + mClearBlendStates.clear(); + + SafeRelease(mFloatClearShader.inputLayout); + SafeRelease(mFloatClearShader.vertexShader); + SafeRelease(mFloatClearShader.pixelShader); + + if (mRenderer->isES3Capable()) + { + SafeRelease(mUintClearShader.inputLayout); + SafeRelease(mUintClearShader.vertexShader); + SafeRelease(mUintClearShader.pixelShader); + + SafeRelease(mIntClearShader.inputLayout); + SafeRelease(mIntClearShader.vertexShader); + SafeRelease(mIntClearShader.pixelShader); + } + + for (ClearDepthStencilStateMap::iterator i = mClearDepthStencilStates.begin(); i != mClearDepthStencilStates.end(); i++) + { + SafeRelease(i->second); + } + mClearDepthStencilStates.clear(); + + SafeRelease(mVertexBuffer); + SafeRelease(mRasterizerState); +} + +gl::Error Clear11::clearFramebuffer(const ClearParameters &clearParams, const gl::Framebuffer::Data &fboData) +{ + const auto &colorAttachments = fboData.mColorAttachments; + const auto &drawBufferStates = fboData.mDrawBufferStates; + const auto *depthAttachment = fboData.mDepthAttachment; + const auto *stencilAttachment = fboData.mStencilAttachment; + + ASSERT(colorAttachments.size() == drawBufferStates.size()); + + // Iterate over the color buffers which require clearing and determine if they can be + // cleared with ID3D11DeviceContext::ClearRenderTargetView or ID3D11DeviceContext1::ClearView. + // This requires: + // 1) The render target is being cleared to a float value (will be cast to integer when clearing integer + // render targets as expected but does not work the other way around) + // 2) The format of the render target has no color channels that are currently masked out. + // Clear the easy-to-clear buffers on the spot and accumulate the ones that require special work. + // + // If these conditions are met, and: + // - No scissored clear is needed, then clear using ID3D11DeviceContext::ClearRenderTargetView. + // - A scissored clear is needed then clear using ID3D11DeviceContext1::ClearView if available. + // Otherwise draw a quad. + // + // Also determine if the depth stencil can be cleared with ID3D11DeviceContext::ClearDepthStencilView + // by checking if the stencil write mask covers the entire stencil. + // + // To clear the remaining buffers, quads must be drawn containing an int, uint or float vertex color + // attribute. + + gl::Extents framebufferSize; + + auto iter = std::find_if(colorAttachments.begin(), colorAttachments.end(), [](const gl::FramebufferAttachment *attachment) { return attachment != nullptr; }); + if (iter != colorAttachments.end()) + { + framebufferSize.width = (*iter)->getWidth(); + framebufferSize.height = (*iter)->getHeight(); + framebufferSize.depth = 1; + } + else if (depthAttachment != nullptr) + { + framebufferSize.width = depthAttachment->getWidth(); + framebufferSize.height = depthAttachment->getHeight(); + framebufferSize.depth = 1; + } + else if (stencilAttachment != nullptr) + { + framebufferSize.width = stencilAttachment->getWidth(); + framebufferSize.height = stencilAttachment->getHeight(); + framebufferSize.depth = 1; + } + else + { + UNREACHABLE(); + return gl::Error(GL_INVALID_OPERATION); + } + + if (clearParams.scissorEnabled && (clearParams.scissor.x >= framebufferSize.width || + clearParams.scissor.y >= framebufferSize.height || + clearParams.scissor.x + clearParams.scissor.width <= 0 || + clearParams.scissor.y + clearParams.scissor.height <= 0)) + { + // Scissor is enabled and the scissor rectangle is outside the renderbuffer + return gl::Error(GL_NO_ERROR); + } + + bool needScissoredClear = clearParams.scissorEnabled && (clearParams.scissor.x > 0 || clearParams.scissor.y > 0 || + clearParams.scissor.x + clearParams.scissor.width < framebufferSize.width || + clearParams.scissor.y + clearParams.scissor.height < framebufferSize.height); + + std::vector maskedClearRenderTargets; + RenderTarget11* maskedClearDepthStencil = NULL; + + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); + ID3D11DeviceContext1 *deviceContext1 = mRenderer->getDeviceContext1IfSupported(); + + for (size_t colorAttachment = 0; colorAttachment < colorAttachments.size(); colorAttachment++) + { + if (clearParams.clearColor[colorAttachment] && + colorAttachments[colorAttachment] != nullptr && + drawBufferStates[colorAttachment] != GL_NONE) + { + const gl::FramebufferAttachment *attachment = colorAttachments[colorAttachment]; + + RenderTarget11 *renderTarget = NULL; + gl::Error error = d3d11::GetAttachmentRenderTarget(attachment, &renderTarget); + if (error.isError()) + { + return error; + } + + const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(attachment->getInternalFormat()); + + if (clearParams.colorClearType == GL_FLOAT && + !(formatInfo.componentType == GL_FLOAT || formatInfo.componentType == GL_UNSIGNED_NORMALIZED || formatInfo.componentType == GL_SIGNED_NORMALIZED)) + { + ERR("It is undefined behaviour to clear a render buffer which is not normalized fixed point or floating-" + "point to floating point values (color attachment %u has internal format 0x%X).", colorAttachment, + attachment->getInternalFormat()); + } + + if ((formatInfo.redBits == 0 || !clearParams.colorMaskRed) && + (formatInfo.greenBits == 0 || !clearParams.colorMaskGreen) && + (formatInfo.blueBits == 0 || !clearParams.colorMaskBlue) && + (formatInfo.alphaBits == 0 || !clearParams.colorMaskAlpha)) + { + // Every channel either does not exist in the render target or is masked out + continue; + } + else if ((!mSupportsClearView && needScissoredClear) || clearParams.colorClearType != GL_FLOAT || + (formatInfo.redBits > 0 && !clearParams.colorMaskRed) || + (formatInfo.greenBits > 0 && !clearParams.colorMaskGreen) || + (formatInfo.blueBits > 0 && !clearParams.colorMaskBlue) || + (formatInfo.alphaBits > 0 && !clearParams.colorMaskAlpha)) + { + // A masked clear is required, or a scissored clear is required and ID3D11DeviceContext1::ClearView is unavailable + MaskedRenderTarget maskAndRt; + bool clearColor = clearParams.clearColor[colorAttachment]; + maskAndRt.colorMask[0] = (clearColor && clearParams.colorMaskRed); + maskAndRt.colorMask[1] = (clearColor && clearParams.colorMaskGreen); + maskAndRt.colorMask[2] = (clearColor && clearParams.colorMaskBlue); + maskAndRt.colorMask[3] = (clearColor && clearParams.colorMaskAlpha); + maskAndRt.renderTarget = renderTarget; + maskedClearRenderTargets.push_back(maskAndRt); + } + else + { + // ID3D11DeviceContext::ClearRenderTargetView or ID3D11DeviceContext1::ClearView is possible + + ID3D11RenderTargetView *framebufferRTV = renderTarget->getRenderTargetView(); + if (!framebufferRTV) + { + return gl::Error(GL_OUT_OF_MEMORY, "Internal render target view pointer unexpectedly null."); + } + + const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(renderTarget->getDXGIFormat()); + + // Check if the actual format has a channel that the internal format does not and set them to the + // default values + const float clearValues[4] = + { + ((formatInfo.redBits == 0 && dxgiFormatInfo.redBits > 0) ? 0.0f : clearParams.colorFClearValue.red), + ((formatInfo.greenBits == 0 && dxgiFormatInfo.greenBits > 0) ? 0.0f : clearParams.colorFClearValue.green), + ((formatInfo.blueBits == 0 && dxgiFormatInfo.blueBits > 0) ? 0.0f : clearParams.colorFClearValue.blue), + ((formatInfo.alphaBits == 0 && dxgiFormatInfo.alphaBits > 0) ? 1.0f : clearParams.colorFClearValue.alpha), + }; + + if (needScissoredClear) + { +#if defined(ANGLE_ENABLE_D3D11_1) + // We shouldn't reach here if deviceContext1 is unavailable. + ASSERT(deviceContext1); + + D3D11_RECT rect; + rect.left = clearParams.scissor.x; + rect.right = clearParams.scissor.x + clearParams.scissor.width; + rect.top = clearParams.scissor.y; + rect.bottom = clearParams.scissor.y + clearParams.scissor.height; + + deviceContext1->ClearView(framebufferRTV, clearValues, &rect, 1); +#endif + } + else + { + deviceContext->ClearRenderTargetView(framebufferRTV, clearValues); + } + } + } + } + + if (clearParams.clearDepth || clearParams.clearStencil) + { + const gl::FramebufferAttachment *attachment = (depthAttachment != nullptr) ? depthAttachment : stencilAttachment; + ASSERT(attachment != nullptr); + + RenderTarget11 *renderTarget = NULL; + gl::Error error = d3d11::GetAttachmentRenderTarget(attachment, &renderTarget); + if (error.isError()) + { + return error; + } + + const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(renderTarget->getDXGIFormat()); + + unsigned int stencilUnmasked = (stencilAttachment != nullptr) ? (1 << dxgiFormatInfo.stencilBits) - 1 : 0; + bool needMaskedStencilClear = clearParams.clearStencil && (clearParams.stencilWriteMask & stencilUnmasked) != stencilUnmasked; + + if (needScissoredClear || needMaskedStencilClear) + { + maskedClearDepthStencil = renderTarget; + } + else + { + ID3D11DepthStencilView *framebufferDSV = renderTarget->getDepthStencilView(); + if (!framebufferDSV) + { + return gl::Error(GL_OUT_OF_MEMORY, "Internal depth stencil view pointer unexpectedly null."); + } + + UINT clearFlags = (clearParams.clearDepth ? D3D11_CLEAR_DEPTH : 0) | + (clearParams.clearStencil ? D3D11_CLEAR_STENCIL : 0); + FLOAT depthClear = gl::clamp01(clearParams.depthClearValue); + UINT8 stencilClear = clearParams.stencilClearValue & 0xFF; + + deviceContext->ClearDepthStencilView(framebufferDSV, clearFlags, depthClear, stencilClear); + } + } + + if (maskedClearRenderTargets.size() > 0 || maskedClearDepthStencil) + { + // To clear the render targets and depth stencil in one pass: + // + // Render a quad clipped to the scissor rectangle which draws the clear color and a blend + // state that will perform the required color masking. + // + // The quad's depth is equal to the depth clear value with a depth stencil state that + // will enable or disable depth test/writes if the depth buffer should be cleared or not. + // + // The rasterizer state's stencil is set to always pass or fail based on if the stencil + // should be cleared or not with a stencil write mask of the stencil clear value. + // + // ====================================================================================== + // + // Luckily, the gl spec (ES 3.0.2 pg 183) states that the results of clearing a render- + // buffer that is not normalized fixed point or floating point with floating point values + // are undefined so we can just write floats to them and D3D11 will bit cast them to + // integers. + // + // Also, we don't have to worry about attempting to clear a normalized fixed/floating point + // buffer with integer values because there is no gl API call which would allow it, + // glClearBuffer* calls only clear a single renderbuffer at a time which is verified to + // be a compatible clear type. + + // Bind all the render targets which need clearing + ASSERT(maskedClearRenderTargets.size() <= mRenderer->getRendererCaps().maxDrawBuffers); + std::vector rtvs(maskedClearRenderTargets.size()); + for (unsigned int i = 0; i < maskedClearRenderTargets.size(); i++) + { + RenderTarget11 *renderTarget = maskedClearRenderTargets[i].renderTarget; + ID3D11RenderTargetView *rtv = renderTarget->getRenderTargetView(); + if (!rtv) + { + return gl::Error(GL_OUT_OF_MEMORY, "Internal render target view pointer unexpectedly null."); + } + + rtvs[i] = rtv; + } + ID3D11DepthStencilView *dsv = maskedClearDepthStencil ? maskedClearDepthStencil->getDepthStencilView() : NULL; + + ID3D11BlendState *blendState = getBlendState(maskedClearRenderTargets); + const FLOAT blendFactors[4] = { 1.0f, 1.0f, 1.0f, 1.0f }; + const UINT sampleMask = 0xFFFFFFFF; + + ID3D11DepthStencilState *dsState = getDepthStencilState(clearParams); + const UINT stencilClear = clearParams.stencilClearValue & 0xFF; + + // Set the vertices + UINT vertexStride = 0; + const UINT startIdx = 0; + const ClearShader* shader = NULL; + D3D11_MAPPED_SUBRESOURCE mappedResource; + HRESULT result = deviceContext->Map(mVertexBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to map internal masked clear vertex buffer, HRESULT: 0x%X.", result); + } + + const gl::Rectangle *scissorPtr = clearParams.scissorEnabled ? &clearParams.scissor : NULL; + switch (clearParams.colorClearType) + { + case GL_FLOAT: + ApplyVertices(framebufferSize, scissorPtr, clearParams.colorFClearValue, clearParams.depthClearValue, mappedResource.pData); + vertexStride = sizeof(d3d11::PositionDepthColorVertex); + shader = &mFloatClearShader; + break; + + case GL_UNSIGNED_INT: + ApplyVertices(framebufferSize, scissorPtr, clearParams.colorUIClearValue, clearParams.depthClearValue, mappedResource.pData); + vertexStride = sizeof(d3d11::PositionDepthColorVertex); + shader = &mUintClearShader; + break; + + case GL_INT: + ApplyVertices(framebufferSize, scissorPtr, clearParams.colorIClearValue, clearParams.depthClearValue, mappedResource.pData); + vertexStride = sizeof(d3d11::PositionDepthColorVertex); + shader = &mIntClearShader; + break; + + default: + UNREACHABLE(); + break; + } + + deviceContext->Unmap(mVertexBuffer, 0); + + // Set the viewport to be the same size as the framebuffer + D3D11_VIEWPORT viewport; + viewport.TopLeftX = 0; + viewport.TopLeftY = 0; + viewport.Width = framebufferSize.width; + viewport.Height = framebufferSize.height; + viewport.MinDepth = 0; + viewport.MaxDepth = 1; + deviceContext->RSSetViewports(1, &viewport); + + // Apply state + deviceContext->OMSetBlendState(blendState, blendFactors, sampleMask); + deviceContext->OMSetDepthStencilState(dsState, stencilClear); + deviceContext->RSSetState(mRasterizerState); + + // Apply shaders + deviceContext->IASetInputLayout(shader->inputLayout); + deviceContext->VSSetShader(shader->vertexShader, NULL, 0); + deviceContext->PSSetShader(shader->pixelShader, NULL, 0); + deviceContext->GSSetShader(NULL, NULL, 0); + + // Apply vertex buffer + deviceContext->IASetVertexBuffers(0, 1, &mVertexBuffer, &vertexStride, &startIdx); + deviceContext->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); + + // Apply render targets + deviceContext->OMSetRenderTargets(rtvs.size(), (rtvs.empty() ? NULL : &rtvs[0]), dsv); + + // Draw the clear quad + deviceContext->Draw(4, 0); + + // Clean up + mRenderer->markAllStateDirty(); + } + + return gl::Error(GL_NO_ERROR); +} + +ID3D11BlendState *Clear11::getBlendState(const std::vector& rts) +{ + ClearBlendInfo blendKey = { 0 }; + for (unsigned int i = 0; i < D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; i++) + { + if (i < rts.size()) + { + RenderTarget11 *rt = rts[i].renderTarget; + const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(rt->getInternalFormat()); + + blendKey.maskChannels[i][0] = (rts[i].colorMask[0] && formatInfo.redBits > 0); + blendKey.maskChannels[i][1] = (rts[i].colorMask[1] && formatInfo.greenBits > 0); + blendKey.maskChannels[i][2] = (rts[i].colorMask[2] && formatInfo.blueBits > 0); + blendKey.maskChannels[i][3] = (rts[i].colorMask[3] && formatInfo.alphaBits > 0); + } + else + { + blendKey.maskChannels[i][0] = false; + blendKey.maskChannels[i][1] = false; + blendKey.maskChannels[i][2] = false; + blendKey.maskChannels[i][3] = false; + } + } + + ClearBlendStateMap::const_iterator i = mClearBlendStates.find(blendKey); + if (i != mClearBlendStates.end()) + { + return i->second; + } + else + { + D3D11_BLEND_DESC blendDesc = { 0 }; + blendDesc.AlphaToCoverageEnable = FALSE; + blendDesc.IndependentBlendEnable = (rts.size() > 1) ? TRUE : FALSE; + + for (unsigned int j = 0; j < D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; j++) + { + blendDesc.RenderTarget[j].BlendEnable = FALSE; + blendDesc.RenderTarget[j].RenderTargetWriteMask = gl_d3d11::ConvertColorMask(blendKey.maskChannels[j][0], + blendKey.maskChannels[j][1], + blendKey.maskChannels[j][2], + blendKey.maskChannels[j][3]); + } + + ID3D11Device *device = mRenderer->getDevice(); + ID3D11BlendState* blendState = NULL; + HRESULT result = device->CreateBlendState(&blendDesc, &blendState); + if (FAILED(result) || !blendState) + { + ERR("Unable to create a ID3D11BlendState, HRESULT: 0x%X.", result); + return NULL; + } + + mClearBlendStates[blendKey] = blendState; + + return blendState; + } +} + +ID3D11DepthStencilState *Clear11::getDepthStencilState(const ClearParameters &clearParams) +{ + ClearDepthStencilInfo dsKey = { 0 }; + dsKey.clearDepth = clearParams.clearDepth; + dsKey.clearStencil = clearParams.clearStencil; + dsKey.stencilWriteMask = clearParams.stencilWriteMask & 0xFF; + + ClearDepthStencilStateMap::const_iterator i = mClearDepthStencilStates.find(dsKey); + if (i != mClearDepthStencilStates.end()) + { + return i->second; + } + else + { + D3D11_DEPTH_STENCIL_DESC dsDesc = { 0 }; + dsDesc.DepthEnable = dsKey.clearDepth ? TRUE : FALSE; + dsDesc.DepthWriteMask = dsKey.clearDepth ? D3D11_DEPTH_WRITE_MASK_ALL : D3D11_DEPTH_WRITE_MASK_ZERO; + dsDesc.DepthFunc = D3D11_COMPARISON_ALWAYS; + dsDesc.StencilEnable = dsKey.clearStencil ? TRUE : FALSE; + dsDesc.StencilReadMask = 0; + dsDesc.StencilWriteMask = dsKey.stencilWriteMask; + dsDesc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_REPLACE; + dsDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_REPLACE; + dsDesc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_REPLACE; + dsDesc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS; + dsDesc.BackFace.StencilFailOp = D3D11_STENCIL_OP_REPLACE; + dsDesc.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_REPLACE; + dsDesc.BackFace.StencilPassOp = D3D11_STENCIL_OP_REPLACE; + dsDesc.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS; + + ID3D11Device *device = mRenderer->getDevice(); + ID3D11DepthStencilState* dsState = NULL; + HRESULT result = device->CreateDepthStencilState(&dsDesc, &dsState); + if (FAILED(result) || !dsState) + { + ERR("Unable to create a ID3D11DepthStencilState, HRESULT: 0x%X.", result); + return NULL; + } + + mClearDepthStencilStates[dsKey] = dsState; + + return dsState; + } +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Clear11.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Clear11.h new file mode 100644 index 0000000000..4797ca1aa0 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Clear11.h @@ -0,0 +1,86 @@ +// +// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Clear11.h: Framebuffer clear utility class. + +#ifndef LIBANGLE_RENDERER_D3D_D3D11_CLEAR11_H_ +#define LIBANGLE_RENDERER_D3D_D3D11_CLEAR11_H_ + +#include +#include + +#include "libANGLE/angletypes.h" +#include "libANGLE/Error.h" +#include "libANGLE/Framebuffer.h" + +namespace rx +{ +class Renderer11; +class RenderTarget11; +struct ClearParameters; + +class Clear11 : angle::NonCopyable +{ + public: + explicit Clear11(Renderer11 *renderer); + ~Clear11(); + + // Clears the framebuffer with the supplied clear parameters, assumes that the framebuffer is currently applied. + gl::Error clearFramebuffer(const ClearParameters &clearParams, const gl::Framebuffer::Data &fboData); + + private: + struct MaskedRenderTarget + { + bool colorMask[4]; + RenderTarget11 *renderTarget; + }; + + ID3D11BlendState *getBlendState(const std::vector &rts); + ID3D11DepthStencilState *getDepthStencilState(const ClearParameters &clearParams); + + struct ClearShader + { + ID3D11InputLayout *inputLayout; + ID3D11VertexShader *vertexShader; + ID3D11PixelShader *pixelShader; + }; + + template + static ClearShader CreateClearShader(ID3D11Device *device, DXGI_FORMAT colorType, const BYTE(&vsByteCode)[vsSize], const BYTE(&psByteCode)[psSize]); + + Renderer11 *mRenderer; + + struct ClearBlendInfo + { + bool maskChannels[D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT][4]; + }; + typedef bool(*ClearBlendInfoComparisonFunction)(const ClearBlendInfo&, const ClearBlendInfo &); + typedef std::map ClearBlendStateMap; + ClearBlendStateMap mClearBlendStates; + + ClearShader mFloatClearShader; + ClearShader mUintClearShader; + ClearShader mIntClearShader; + + struct ClearDepthStencilInfo + { + bool clearDepth; + bool clearStencil; + UINT8 stencilWriteMask; + }; + typedef bool (*ClearDepthStencilInfoComparisonFunction)(const ClearDepthStencilInfo&, const ClearDepthStencilInfo &); + typedef std::map ClearDepthStencilStateMap; + ClearDepthStencilStateMap mClearDepthStencilStates; + + ID3D11Buffer *mVertexBuffer; + ID3D11RasterizerState *mRasterizerState; + + bool mSupportsClearView; +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_D3D11_CLEAR11_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/DebugAnnotator11.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/DebugAnnotator11.cpp new file mode 100644 index 0000000000..f1fe2bb2c7 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/DebugAnnotator11.cpp @@ -0,0 +1,119 @@ +// +// Copyright 2015 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// DebugAnnotator11.cpp: D3D11 helpers for adding trace annotations. +// + +#include "libANGLE/renderer/d3d/d3d11/DebugAnnotator11.h" + +#include "common/debug.h" +#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h" + +namespace rx +{ + +DebugAnnotator11::DebugAnnotator11() + : mInitialized(false), + mD3d11Module(nullptr), + mUserDefinedAnnotation(nullptr) +{ + // D3D11 devices can't be created during DllMain. + // We defer device creation until the object is actually used. +} + +DebugAnnotator11::~DebugAnnotator11() +{ + if (mInitialized) + { +#if defined(ANGLE_ENABLE_D3D11_1) + SafeRelease(mUserDefinedAnnotation); +#endif + +#if !defined(ANGLE_ENABLE_WINDOWS_STORE) + FreeLibrary(mD3d11Module); +#endif // !ANGLE_ENABLE_WINDOWS_STORE + } +} + +void DebugAnnotator11::beginEvent(const std::wstring &eventName) +{ + initializeDevice(); + +#if defined(ANGLE_ENABLE_D3D11_1) + mUserDefinedAnnotation->BeginEvent(eventName.c_str()); +#endif +} + +void DebugAnnotator11::endEvent() +{ + initializeDevice(); + +#if defined(ANGLE_ENABLE_D3D11_1) + mUserDefinedAnnotation->EndEvent(); +#endif +} + +void DebugAnnotator11::setMarker(const std::wstring &markerName) +{ + initializeDevice(); + +#if defined(ANGLE_ENABLE_D3D11_1) + mUserDefinedAnnotation->SetMarker(markerName.c_str()); +#endif +} + +bool DebugAnnotator11::getStatus() +{ + // ID3DUserDefinedAnnotation::GetStatus doesn't work with the Graphics Diagnostics tools in Visual Studio 2013. + +#if defined(_DEBUG) && defined(ANGLE_ENABLE_WINDOWS_STORE) && (WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP) + // In the Windows Store, we can use IDXGraphicsAnalysis. The call to GetDebugInterface1 only succeeds if the app is under capture. + // This should only be called in DEBUG mode. + // If an app links against DXGIGetDebugInterface1 in release mode then it will fail Windows Store ingestion checks. + IDXGraphicsAnalysis *graphicsAnalysis; + DXGIGetDebugInterface1(0, IID_PPV_ARGS(&graphicsAnalysis)); + bool underCapture = (graphicsAnalysis != nullptr); + SafeRelease(graphicsAnalysis); + return underCapture; +#endif // _DEBUG && !ANGLE_ENABLE_WINDOWS_STORE + + // Otherwise, we have to return true here. + return true; +} + +void DebugAnnotator11::initializeDevice() +{ + if (!mInitialized) + { +#if !defined(ANGLE_ENABLE_WINDOWS_STORE) + mD3d11Module = LoadLibrary(TEXT("d3d11.dll")); + ASSERT(mD3d11Module); + + PFN_D3D11_CREATE_DEVICE D3D11CreateDevice = (PFN_D3D11_CREATE_DEVICE)GetProcAddress(mD3d11Module, "D3D11CreateDevice"); + ASSERT(D3D11CreateDevice != nullptr); +#endif // !ANGLE_ENABLE_WINDOWS_STORE + + ID3D11Device *device = nullptr; + ID3D11DeviceContext *context = nullptr; + + HRESULT hr = E_FAIL; + + // Create a D3D_DRIVER_TYPE_NULL device, which is much cheaper than other types of device. + hr = D3D11CreateDevice(NULL, D3D_DRIVER_TYPE_NULL, nullptr, 0, nullptr, 0, D3D11_SDK_VERSION, &device, nullptr, &context); + ASSERT(SUCCEEDED(hr)); + +#if defined(ANGLE_ENABLE_D3D11_1) + mUserDefinedAnnotation = d3d11::DynamicCastComObject(context); + ASSERT(mUserDefinedAnnotation != nullptr); +#endif + + SafeRelease(device); + SafeRelease(context); + + mInitialized = true; + } +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/DebugAnnotator11.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/DebugAnnotator11.h new file mode 100644 index 0000000000..3df62b015c --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/DebugAnnotator11.h @@ -0,0 +1,39 @@ +// +// Copyright 2015 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// DebugAnnotator11.h: D3D11 helpers for adding trace annotations. +// + +#ifndef LIBANGLE_RENDERER_D3D_D3D11_DEBUGANNOTATOR11_H_ +#define LIBANGLE_RENDERER_D3D_D3D11_DEBUGANNOTATOR11_H_ + +#include "common/debug.h" + +struct ID3DUserDefinedAnnotation; + +namespace rx +{ + +class DebugAnnotator11 : public gl::DebugAnnotator +{ + public: + DebugAnnotator11(); + ~DebugAnnotator11() override; + void beginEvent(const std::wstring &eventName) override; + void endEvent() override; + void setMarker(const std::wstring &markerName) override; + bool getStatus() override; + + private: + void initializeDevice(); + + bool mInitialized; + HMODULE mD3d11Module; + ID3DUserDefinedAnnotation *mUserDefinedAnnotation; +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_D3D11_DEBUGANNOTATOR11_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Fence11.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Fence11.cpp new file mode 100644 index 0000000000..8552bc2beb --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Fence11.cpp @@ -0,0 +1,231 @@ +// +// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Fence11.cpp: Defines the rx::FenceNV11 and rx::FenceSync11 classes which implement rx::FenceNVImpl and rx::FenceSyncImpl. + +#include "libANGLE/renderer/d3d/d3d11/Fence11.h" +#include "libANGLE/renderer/d3d/d3d11/Renderer11.h" + +#include "common/utilities.h" + +namespace rx +{ + +// +// Template helpers for set and test operations. +// + +template +gl::Error FenceSetHelper(FenceClass *fence) +{ + if (!fence->mQuery) + { + D3D11_QUERY_DESC queryDesc; + queryDesc.Query = D3D11_QUERY_EVENT; + queryDesc.MiscFlags = 0; + + HRESULT result = fence->mRenderer->getDevice()->CreateQuery(&queryDesc, &fence->mQuery); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create event query, result: 0x%X.", result); + } + } + + fence->mRenderer->getDeviceContext()->End(fence->mQuery); + return gl::Error(GL_NO_ERROR); +} + +template +gl::Error FenceTestHelper(FenceClass *fence, bool flushCommandBuffer, GLboolean *outFinished) +{ + ASSERT(fence->mQuery); + + UINT getDataFlags = (flushCommandBuffer ? 0 : D3D11_ASYNC_GETDATA_DONOTFLUSH); + HRESULT result = fence->mRenderer->getDeviceContext()->GetData(fence->mQuery, NULL, 0, getDataFlags); + + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to get query data, result: 0x%X.", result); + } + else if (fence->mRenderer->isDeviceLost()) + { + return gl::Error(GL_OUT_OF_MEMORY, "Device was lost while querying result of an event query."); + } + + ASSERT(result == S_OK || result == S_FALSE); + *outFinished = ((result == S_OK) ? GL_TRUE : GL_FALSE); + return gl::Error(GL_NO_ERROR); +} + +// +// FenceNV11 +// + +FenceNV11::FenceNV11(Renderer11 *renderer) + : FenceNVImpl(), + mRenderer(renderer), + mQuery(NULL) +{ +} + +FenceNV11::~FenceNV11() +{ + SafeRelease(mQuery); +} + +gl::Error FenceNV11::set() +{ + return FenceSetHelper(this); +} + +gl::Error FenceNV11::test(bool flushCommandBuffer, GLboolean *outFinished) +{ + return FenceTestHelper(this, flushCommandBuffer, outFinished); +} + +gl::Error FenceNV11::finishFence(GLboolean *outFinished) +{ + ASSERT(outFinished); + + while (*outFinished != GL_TRUE) + { + gl::Error error = test(true, outFinished); + if (error.isError()) + { + return error; + } + + ScheduleYield(); + } + + return gl::Error(GL_NO_ERROR); +} + +// +// FenceSync11 +// + +// Important note on accurate timers in Windows: +// +// QueryPerformanceCounter has a few major issues, including being 10x as expensive to call +// as timeGetTime on laptops and "jumping" during certain hardware events. +// +// See the comments at the top of the Chromium source file "chromium/src/base/time/time_win.cc" +// https://code.google.com/p/chromium/codesearch#chromium/src/base/time/time_win.cc +// +// We still opt to use QPC. In the present and moving forward, most newer systems will not suffer +// from buggy implementations. + +FenceSync11::FenceSync11(Renderer11 *renderer) + : FenceSyncImpl(), + mRenderer(renderer), + mQuery(NULL) +{ + LARGE_INTEGER counterFreqency = { 0 }; + BOOL success = QueryPerformanceFrequency(&counterFreqency); + UNUSED_ASSERTION_VARIABLE(success); + ASSERT(success); + + mCounterFrequency = counterFreqency.QuadPart; +} + +FenceSync11::~FenceSync11() +{ + SafeRelease(mQuery); +} + +gl::Error FenceSync11::set() +{ + return FenceSetHelper(this); +} + +gl::Error FenceSync11::clientWait(GLbitfield flags, GLuint64 timeout, GLenum *outResult) +{ + ASSERT(outResult); + + bool flushCommandBuffer = ((flags & GL_SYNC_FLUSH_COMMANDS_BIT) != 0); + + GLboolean result = GL_FALSE; + gl::Error error = FenceTestHelper(this, flushCommandBuffer, &result); + if (error.isError()) + { + *outResult = GL_WAIT_FAILED; + return error; + } + + if (result == GL_TRUE) + { + *outResult = GL_ALREADY_SIGNALED; + return gl::Error(GL_NO_ERROR); + } + + if (timeout == 0) + { + *outResult = GL_TIMEOUT_EXPIRED; + return gl::Error(GL_NO_ERROR); + } + + LARGE_INTEGER currentCounter = { 0 }; + BOOL success = QueryPerformanceCounter(¤tCounter); + UNUSED_ASSERTION_VARIABLE(success); + ASSERT(success); + + LONGLONG timeoutInSeconds = static_cast(timeout) * static_cast(1000000ll); + LONGLONG endCounter = currentCounter.QuadPart + mCounterFrequency * timeoutInSeconds; + + while (currentCounter.QuadPart < endCounter && !result) + { + ScheduleYield(); + success = QueryPerformanceCounter(¤tCounter); + UNUSED_ASSERTION_VARIABLE(success); + ASSERT(success); + + error = FenceTestHelper(this, flushCommandBuffer, &result); + if (error.isError()) + { + *outResult = GL_WAIT_FAILED; + return error; + } + } + + if (currentCounter.QuadPart >= endCounter) + { + *outResult = GL_TIMEOUT_EXPIRED; + } + else + { + *outResult = GL_CONDITION_SATISFIED; + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error FenceSync11::serverWait(GLbitfield flags, GLuint64 timeout) +{ + // Because our API is currently designed to be called from a single thread, we don't need to do + // extra work for a server-side fence. GPU commands issued after the fence is created will always + // be processed after the fence is signaled. + return gl::Error(GL_NO_ERROR); +} + +gl::Error FenceSync11::getStatus(GLint *outResult) +{ + GLboolean result = GL_FALSE; + gl::Error error = FenceTestHelper(this, false, &result); + if (error.isError()) + { + // The spec does not specify any way to report errors during the status test (e.g. device lost) + // so we report the fence is unblocked in case of error or signaled. + *outResult = GL_SIGNALED; + + return error; + } + + *outResult = (result ? GL_SIGNALED : GL_UNSIGNALED); + return gl::Error(GL_NO_ERROR); +} + +} // namespace rx diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Fence11.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Fence11.h new file mode 100644 index 0000000000..2d87f43e76 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Fence11.h @@ -0,0 +1,59 @@ +// +// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Fence11.h: Defines the rx::FenceNV11 and rx::FenceSync11 classes which implement rx::FenceNVImpl and rx::FenceSyncImpl. + +#ifndef LIBANGLE_RENDERER_D3D_D3D11_FENCE11_H_ +#define LIBANGLE_RENDERER_D3D_D3D11_FENCE11_H_ + +#include "libANGLE/renderer/FenceNVImpl.h" +#include "libANGLE/renderer/FenceSyncImpl.h" + +namespace rx +{ +class Renderer11; + +class FenceNV11 : public FenceNVImpl +{ + public: + explicit FenceNV11(Renderer11 *renderer); + virtual ~FenceNV11(); + + gl::Error set(); + gl::Error test(bool flushCommandBuffer, GLboolean *outFinished); + gl::Error finishFence(GLboolean *outFinished); + + private: + template friend gl::Error FenceSetHelper(T *fence); + template friend gl::Error FenceTestHelper(T *fence, bool flushCommandBuffer, GLboolean *outFinished); + + Renderer11 *mRenderer; + ID3D11Query *mQuery; +}; + +class FenceSync11 : public FenceSyncImpl +{ + public: + explicit FenceSync11(Renderer11 *renderer); + virtual ~FenceSync11(); + + gl::Error set(); + gl::Error clientWait(GLbitfield flags, GLuint64 timeout, GLenum *outResult); + gl::Error serverWait(GLbitfield flags, GLuint64 timeout); + gl::Error getStatus(GLint *outResult); + + private: + template friend gl::Error FenceSetHelper(T *fence); + template friend gl::Error FenceTestHelper(T *fence, bool flushCommandBuffer, GLboolean *outFinished); + + Renderer11 *mRenderer; + ID3D11Query *mQuery; + LONGLONG mCounterFrequency; +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_D3D11_FENCE11_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Framebuffer11.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Framebuffer11.cpp new file mode 100644 index 0000000000..da01f320c0 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Framebuffer11.cpp @@ -0,0 +1,270 @@ +// +// Copyright 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Framebuffer11.cpp: Implements the Framebuffer11 class. + +#include "libANGLE/renderer/d3d/d3d11/Framebuffer11.h" + +#include "common/debug.h" +#include "libANGLE/renderer/d3d/d3d11/Buffer11.h" +#include "libANGLE/renderer/d3d/d3d11/Clear11.h" +#include "libANGLE/renderer/d3d/d3d11/TextureStorage11.h" +#include "libANGLE/renderer/d3d/d3d11/Renderer11.h" +#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h" +#include "libANGLE/renderer/d3d/d3d11/RenderTarget11.h" +#include "libANGLE/renderer/d3d/d3d11/formatutils11.h" +#include "libANGLE/renderer/d3d/TextureD3D.h" +#include "libANGLE/Framebuffer.h" +#include "libANGLE/FramebufferAttachment.h" +#include "libANGLE/Texture.h" + +namespace rx +{ + +Framebuffer11::Framebuffer11(const gl::Framebuffer::Data &data, Renderer11 *renderer) + : FramebufferD3D(data, renderer), + mRenderer(renderer) +{ + ASSERT(mRenderer != nullptr); +} + +Framebuffer11::~Framebuffer11() +{ +} + +static gl::Error InvalidateAttachmentSwizzles(const gl::FramebufferAttachment *attachment) +{ + if (attachment && attachment->type() == GL_TEXTURE) + { + gl::Texture *texture = attachment->getTexture(); + + TextureD3D *textureD3D = GetImplAs(texture); + + TextureStorage *texStorage = NULL; + gl::Error error = textureD3D->getNativeTexture(&texStorage); + if (error.isError()) + { + return error; + } + + if (texStorage) + { + TextureStorage11 *texStorage11 = TextureStorage11::makeTextureStorage11(texStorage); + ASSERT(texStorage11); + + texStorage11->invalidateSwizzleCacheLevel(attachment->mipLevel()); + } + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Framebuffer11::invalidateSwizzles() const +{ + for (auto it = mData.mColorAttachments.cbegin(); it != mData.mColorAttachments.cend(); ++it) + { + gl::FramebufferAttachment *colorAttachment = *it; + gl::Error error = InvalidateAttachmentSwizzles(colorAttachment); + if (error.isError()) + { + return error; + } + } + + gl::Error error = InvalidateAttachmentSwizzles(mData.mDepthAttachment); + if (error.isError()) + { + return error; + } + + error = InvalidateAttachmentSwizzles(mData.mStencilAttachment); + if (error.isError()) + { + return error; + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Framebuffer11::clear(const gl::State &state, const ClearParameters &clearParams) +{ + Clear11 *clearer = mRenderer->getClearer(); + gl::Error error = clearer->clearFramebuffer(clearParams, mData); + if (error.isError()) + { + return error; + } + + error = invalidateSwizzles(); + if (error.isError()) + { + return error; + } + + return gl::Error(GL_NO_ERROR); +} + +static gl::Error getRenderTargetResource(const gl::FramebufferAttachment *colorbuffer, unsigned int *subresourceIndexOut, + ID3D11Texture2D **texture2DOut) +{ + ASSERT(colorbuffer); + + RenderTarget11 *renderTarget = NULL; + gl::Error error = d3d11::GetAttachmentRenderTarget(colorbuffer, &renderTarget); + if (error.isError()) + { + return error; + } + + ID3D11Resource *renderTargetResource = renderTarget->getTexture(); + ASSERT(renderTargetResource); + + *subresourceIndexOut = renderTarget->getSubresourceIndex(); + *texture2DOut = d3d11::DynamicCastComObject(renderTargetResource); + + if (!(*texture2DOut)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to query the ID3D11Texture2D from a RenderTarget"); + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Framebuffer11::readPixels(const gl::Rectangle &area, GLenum format, GLenum type, size_t outputPitch, const gl::PixelPackState &pack, uint8_t *pixels) const +{ + ID3D11Texture2D *colorBufferTexture = NULL; + unsigned int subresourceIndex = 0; + + const gl::FramebufferAttachment *colorbuffer = mData.getReadAttachment(); + ASSERT(colorbuffer); + + gl::Error error = getRenderTargetResource(colorbuffer, &subresourceIndex, &colorBufferTexture); + if (error.isError()) + { + return error; + } + + gl::Buffer *packBuffer = pack.pixelBuffer.get(); + if (packBuffer != NULL) + { + Buffer11 *packBufferStorage = Buffer11::makeBuffer11(packBuffer->getImplementation()); + PackPixelsParams packParams(area, format, type, outputPitch, pack, reinterpret_cast(pixels)); + + error = packBufferStorage->packPixels(colorBufferTexture, subresourceIndex, packParams); + if (error.isError()) + { + SafeRelease(colorBufferTexture); + return error; + } + + packBuffer->getIndexRangeCache()->clear(); + } + else + { + error = mRenderer->readTextureData(colorBufferTexture, subresourceIndex, area, format, type, outputPitch, pack, pixels); + if (error.isError()) + { + SafeRelease(colorBufferTexture); + return error; + } + } + + SafeRelease(colorBufferTexture); + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Framebuffer11::blit(const gl::Rectangle &sourceArea, const gl::Rectangle &destArea, const gl::Rectangle *scissor, + bool blitRenderTarget, bool blitDepth, bool blitStencil, GLenum filter, + const gl::Framebuffer *sourceFramebuffer) +{ + if (blitRenderTarget) + { + const gl::FramebufferAttachment *readBuffer = sourceFramebuffer->getReadColorbuffer(); + ASSERT(readBuffer); + + RenderTargetD3D *readRenderTarget = NULL; + gl::Error error = GetAttachmentRenderTarget(readBuffer, &readRenderTarget); + if (error.isError()) + { + return error; + } + ASSERT(readRenderTarget); + + for (size_t colorAttachment = 0; colorAttachment < mData.mColorAttachments.size(); colorAttachment++) + { + if (mData.mColorAttachments[colorAttachment] != nullptr && + mData.mDrawBufferStates[colorAttachment] != GL_NONE) + { + const gl::FramebufferAttachment *drawBuffer = mData.mColorAttachments[colorAttachment]; + + RenderTargetD3D *drawRenderTarget = NULL; + error = GetAttachmentRenderTarget(drawBuffer, &drawRenderTarget); + if (error.isError()) + { + return error; + } + ASSERT(drawRenderTarget); + + error = mRenderer->blitRenderbufferRect(sourceArea, destArea, readRenderTarget, drawRenderTarget, + filter, scissor, blitRenderTarget, false, false); + if (error.isError()) + { + return error; + } + } + } + } + + if (blitDepth || blitStencil) + { + gl::FramebufferAttachment *readBuffer = sourceFramebuffer->getDepthOrStencilbuffer(); + ASSERT(readBuffer); + + RenderTargetD3D *readRenderTarget = NULL; + gl::Error error = GetAttachmentRenderTarget(readBuffer, &readRenderTarget); + if (error.isError()) + { + return error; + } + ASSERT(readRenderTarget); + + const gl::FramebufferAttachment *drawBuffer = mData.getDepthOrStencilAttachment(); + ASSERT(drawBuffer); + + RenderTargetD3D *drawRenderTarget = NULL; + error = GetAttachmentRenderTarget(drawBuffer, &drawRenderTarget); + if (error.isError()) + { + return error; + } + ASSERT(drawRenderTarget); + + error = mRenderer->blitRenderbufferRect(sourceArea, destArea, readRenderTarget, drawRenderTarget, filter, scissor, + false, blitDepth, blitStencil); + if (error.isError()) + { + return error; + } + } + + gl::Error error = invalidateSwizzles(); + if (error.isError()) + { + return error; + } + + return gl::Error(GL_NO_ERROR); +} + +GLenum Framebuffer11::getRenderTargetImplementationFormat(RenderTargetD3D *renderTarget) const +{ + RenderTarget11 *renderTarget11 = RenderTarget11::makeRenderTarget11(renderTarget); + const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(renderTarget11->getDXGIFormat()); + return dxgiFormatInfo.internalFormat; +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Framebuffer11.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Framebuffer11.h new file mode 100644 index 0000000000..07fa480fa2 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Framebuffer11.h @@ -0,0 +1,45 @@ +// +// Copyright 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Framebuffer11.h: Defines the Framebuffer11 class. + +#ifndef LIBANGLE_RENDERER_D3D_D3D11_FRAMBUFFER11_H_ +#define LIBANGLE_RENDERER_D3D_D3D11_FRAMBUFFER11_H_ + +#include "libANGLE/renderer/d3d/FramebufferD3D.h" + +namespace rx +{ +class Renderer11; + +class Framebuffer11 : public FramebufferD3D +{ + public: + Framebuffer11(const gl::Framebuffer::Data &data, Renderer11 *renderer); + virtual ~Framebuffer11(); + + // Invalidate the cached swizzles of all bound texture attachments. + gl::Error invalidateSwizzles() const; + + private: + gl::Error clear(const gl::State &state, const ClearParameters &clearParams) override; + + gl::Error readPixels(const gl::Rectangle &area, GLenum format, GLenum type, size_t outputPitch, + const gl::PixelPackState &pack, uint8_t *pixels) const override; + + gl::Error blit(const gl::Rectangle &sourceArea, const gl::Rectangle &destArea, const gl::Rectangle *scissor, + bool blitRenderTarget, bool blitDepth, bool blitStencil, GLenum filter, + const gl::Framebuffer *sourceFramebuffer) override; + + + GLenum getRenderTargetImplementationFormat(RenderTargetD3D *renderTarget) const override; + + Renderer11 *const mRenderer; +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_D3D11_FRAMBUFFER11_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Image11.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Image11.cpp new file mode 100644 index 0000000000..956b78b5a6 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Image11.cpp @@ -0,0 +1,664 @@ +// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Image11.h: Implements the rx::Image11 class, which acts as the interface to +// the actual underlying resources of a Texture + +#include "libANGLE/renderer/d3d/d3d11/Renderer11.h" +#include "libANGLE/renderer/d3d/d3d11/Image11.h" +#include "libANGLE/renderer/d3d/d3d11/RenderTarget11.h" +#include "libANGLE/renderer/d3d/d3d11/TextureStorage11.h" +#include "libANGLE/renderer/d3d/d3d11/formatutils11.h" +#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h" +#include "libANGLE/Framebuffer.h" +#include "libANGLE/FramebufferAttachment.h" +#include "libANGLE/formatutils.h" + +#include "common/utilities.h" + +namespace rx +{ + +Image11::Image11(Renderer11 *renderer) + : mRenderer(renderer), + mDXGIFormat(DXGI_FORMAT_UNKNOWN), + mStagingTexture(NULL), + mStagingSubresource(0), + mRecoverFromStorage(false), + mAssociatedStorage(NULL), + mAssociatedImageIndex(gl::ImageIndex::MakeInvalid()), + mRecoveredFromStorageCount(0) +{ + // mRenderer should remain unchanged during the lifetime of the Image11 object. + // This lets us safely use mRenderer (and its Feature Level) in Image11's methods. + mFeatureLevel = renderer->getFeatureLevel(); +} + +Image11::~Image11() +{ + disassociateStorage(); + releaseStagingTexture(); +} + +Image11 *Image11::makeImage11(ImageD3D *img) +{ + ASSERT(HAS_DYNAMIC_TYPE(Image11*, img)); + return static_cast(img); +} + +gl::Error Image11::generateMipmap(Image11 *dest, Image11 *src) +{ + ASSERT(src->getDXGIFormat() == dest->getDXGIFormat()); + ASSERT(src->getWidth() == 1 || src->getWidth() / 2 == dest->getWidth()); + ASSERT(src->getHeight() == 1 || src->getHeight() / 2 == dest->getHeight()); + + const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(src->getDXGIFormat()); + ASSERT(dxgiFormatInfo.mipGenerationFunction != NULL); + + D3D11_MAPPED_SUBRESOURCE destMapped; + gl::Error error = dest->map(D3D11_MAP_WRITE, &destMapped); + if (error.isError()) + { + return error; + } + + D3D11_MAPPED_SUBRESOURCE srcMapped; + error = src->map(D3D11_MAP_READ, &srcMapped); + if (error.isError()) + { + dest->unmap(); + return error; + } + + const uint8_t *sourceData = reinterpret_cast(srcMapped.pData); + uint8_t *destData = reinterpret_cast(destMapped.pData); + + dxgiFormatInfo.mipGenerationFunction(src->getWidth(), src->getHeight(), src->getDepth(), + sourceData, srcMapped.RowPitch, srcMapped.DepthPitch, + destData, destMapped.RowPitch, destMapped.DepthPitch); + + dest->unmap(); + src->unmap(); + + dest->markDirty(); + + return gl::Error(GL_NO_ERROR); +} + +bool Image11::isDirty() const +{ + // If mDirty is true + // AND mStagingTexture doesn't exist AND mStagingTexture doesn't need to be recovered from TextureStorage + // AND the texture doesn't require init data (i.e. a blank new texture will suffice) + // then isDirty should still return false. + if (mDirty && !mStagingTexture && !mRecoverFromStorage && !(d3d11::GetTextureFormatInfo(mInternalFormat, mFeatureLevel).dataInitializerFunction != NULL)) + { + return false; + } + + return mDirty; +} + +gl::Error Image11::copyToStorage(TextureStorage *storage, const gl::ImageIndex &index, const gl::Box ®ion) +{ + TextureStorage11 *storage11 = TextureStorage11::makeTextureStorage11(storage); + + // If an app's behavior results in an Image11 copying its data to/from to a TextureStorage multiple times, + // then we should just keep the staging texture around to prevent the copying from impacting perf. + // We allow the Image11 to copy its data to/from TextureStorage once. + // This accounts for an app making a late call to glGenerateMipmap. + bool attemptToReleaseStagingTexture = (mRecoveredFromStorageCount < 2); + + if (attemptToReleaseStagingTexture) + { + // If another image is relying on this Storage for its data, then we must let it recover its data before we overwrite it. + gl::Error error = storage11->releaseAssociatedImage(index, this); + if (error.isError()) + { + return error; + } + } + + ID3D11Resource *stagingTexture = NULL; + unsigned int stagingSubresourceIndex = 0; + gl::Error error = getStagingTexture(&stagingTexture, &stagingSubresourceIndex); + if (error.isError()) + { + return error; + } + + error = storage11->updateSubresourceLevel(stagingTexture, stagingSubresourceIndex, index, region); + if (error.isError()) + { + return error; + } + + // Once the image data has been copied into the Storage, we can release it locally. + if (attemptToReleaseStagingTexture) + { + storage11->associateImage(this, index); + releaseStagingTexture(); + mRecoverFromStorage = true; + mAssociatedStorage = storage11; + mAssociatedImageIndex = index; + } + + return gl::Error(GL_NO_ERROR); +} + +bool Image11::isAssociatedStorageValid(TextureStorage11* textureStorage) const +{ + return (mAssociatedStorage == textureStorage); +} + +gl::Error Image11::recoverFromAssociatedStorage() +{ + if (mRecoverFromStorage) + { + gl::Error error = createStagingTexture(); + if (error.isError()) + { + return error; + } + + bool textureStorageCorrect = mAssociatedStorage->isAssociatedImageValid(mAssociatedImageIndex, this); + + // This means that the cached TextureStorage has been modified after this Image11 released its copy of its data. + // This should not have happened. The TextureStorage should have told this Image11 to recover its data before it was overwritten. + ASSERT(textureStorageCorrect); + + if (textureStorageCorrect) + { + // CopySubResource from the Storage to the Staging texture + gl::Box region(0, 0, 0, mWidth, mHeight, mDepth); + error = mAssociatedStorage->copySubresourceLevel(mStagingTexture, mStagingSubresource, mAssociatedImageIndex, region); + if (error.isError()) + { + return error; + } + + mRecoveredFromStorageCount += 1; + } + + // Reset all the recovery parameters, even if the texture storage association is broken. + disassociateStorage(); + } + + return gl::Error(GL_NO_ERROR); +} + +void Image11::disassociateStorage() +{ + if (mRecoverFromStorage) + { + // Make the texturestorage release the Image11 too + mAssociatedStorage->disassociateImage(mAssociatedImageIndex, this); + + mRecoverFromStorage = false; + mAssociatedStorage = NULL; + mAssociatedImageIndex = gl::ImageIndex::MakeInvalid(); + } +} + +bool Image11::redefine(GLenum target, GLenum internalformat, const gl::Extents &size, bool forceRelease) +{ + if (mWidth != size.width || + mHeight != size.height || + mInternalFormat != internalformat || + forceRelease) + { + // End the association with the TextureStorage, since that data will be out of date. + // Also reset mRecoveredFromStorageCount since this Image is getting completely redefined. + disassociateStorage(); + mRecoveredFromStorageCount = 0; + + mWidth = size.width; + mHeight = size.height; + mDepth = size.depth; + mInternalFormat = internalformat; + mTarget = target; + + // compute the d3d format that will be used + const d3d11::TextureFormat &formatInfo = d3d11::GetTextureFormatInfo(internalformat, mFeatureLevel); + mDXGIFormat = formatInfo.texFormat; + mRenderable = (formatInfo.rtvFormat != DXGI_FORMAT_UNKNOWN); + + releaseStagingTexture(); + mDirty = (formatInfo.dataInitializerFunction != NULL); + + return true; + } + + return false; +} + +DXGI_FORMAT Image11::getDXGIFormat() const +{ + // this should only happen if the image hasn't been redefined first + // which would be a bug by the caller + ASSERT(mDXGIFormat != DXGI_FORMAT_UNKNOWN); + + return mDXGIFormat; +} + +// Store the pixel rectangle designated by xoffset,yoffset,width,height with pixels stored as format/type at input +// into the target pixel rectangle. +gl::Error Image11::loadData(const gl::Box &area, const gl::PixelUnpackState &unpack, GLenum type, const void *input) +{ + const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(mInternalFormat); + GLsizei inputRowPitch = formatInfo.computeRowPitch(type, area.width, unpack.alignment, unpack.rowLength); + GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, area.width, area.height, unpack.alignment, unpack.rowLength); + + const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(mDXGIFormat); + GLuint outputPixelSize = dxgiFormatInfo.pixelBytes; + + const d3d11::TextureFormat &d3dFormatInfo = d3d11::GetTextureFormatInfo(mInternalFormat, mFeatureLevel); + LoadImageFunction loadFunction = d3dFormatInfo.loadFunctions.at(type); + + D3D11_MAPPED_SUBRESOURCE mappedImage; + gl::Error error = map(D3D11_MAP_WRITE, &mappedImage); + if (error.isError()) + { + return error; + } + + uint8_t *offsetMappedData = (reinterpret_cast(mappedImage.pData) + (area.y * mappedImage.RowPitch + area.x * outputPixelSize + area.z * mappedImage.DepthPitch)); + loadFunction(area.width, area.height, area.depth, + reinterpret_cast(input), inputRowPitch, inputDepthPitch, + offsetMappedData, mappedImage.RowPitch, mappedImage.DepthPitch); + + unmap(); + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Image11::loadCompressedData(const gl::Box &area, const void *input) +{ + const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(mInternalFormat); + GLsizei inputRowPitch = formatInfo.computeRowPitch(GL_UNSIGNED_BYTE, area.width, 1, 0); + GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, area.width, area.height, 1, 0); + + const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(mDXGIFormat); + GLuint outputPixelSize = dxgiFormatInfo.pixelBytes; + GLuint outputBlockWidth = dxgiFormatInfo.blockWidth; + GLuint outputBlockHeight = dxgiFormatInfo.blockHeight; + + ASSERT(area.x % outputBlockWidth == 0); + ASSERT(area.y % outputBlockHeight == 0); + + const d3d11::TextureFormat &d3dFormatInfo = d3d11::GetTextureFormatInfo(mInternalFormat, mFeatureLevel); + LoadImageFunction loadFunction = d3dFormatInfo.loadFunctions.at(GL_UNSIGNED_BYTE); + + D3D11_MAPPED_SUBRESOURCE mappedImage; + gl::Error error = map(D3D11_MAP_WRITE, &mappedImage); + if (error.isError()) + { + return error; + } + + uint8_t* offsetMappedData = reinterpret_cast(mappedImage.pData) + ((area.y / outputBlockHeight) * mappedImage.RowPitch + + (area.x / outputBlockWidth) * outputPixelSize + + area.z * mappedImage.DepthPitch); + + loadFunction(area.width, area.height, area.depth, + reinterpret_cast(input), inputRowPitch, inputDepthPitch, + offsetMappedData, mappedImage.RowPitch, mappedImage.DepthPitch); + + unmap(); + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Image11::copy(const gl::Offset &destOffset, const gl::Rectangle &sourceArea, RenderTargetD3D *source) +{ + RenderTarget11 *sourceRenderTarget = RenderTarget11::makeRenderTarget11(source); + ASSERT(sourceRenderTarget->getTexture()); + + ID3D11Resource *resource = sourceRenderTarget->getTexture(); + UINT subresourceIndex = sourceRenderTarget->getSubresourceIndex(); + + gl::Box sourceBox(sourceArea.x, sourceArea.y, 0, sourceArea.width, sourceArea.height, 1); + gl::Error error = copy(destOffset, sourceBox, resource, subresourceIndex); + + SafeRelease(resource); + + return error; +} + +gl::Error Image11::copy(const gl::Offset &destOffset, const gl::Box &sourceArea, const gl::ImageIndex &sourceIndex, TextureStorage *source) +{ + TextureStorage11 *sourceStorage11 = TextureStorage11::makeTextureStorage11(source); + + UINT subresourceIndex = sourceStorage11->getSubresourceIndex(sourceIndex); + ID3D11Resource *resource = NULL; + gl::Error error = sourceStorage11->getResource(&resource); + if (error.isError()) + { + return error; + } + + error = copy(destOffset, sourceArea, resource, subresourceIndex); + + SafeRelease(resource); + + return error; +} + +gl::Error Image11::copy(const gl::Offset &destOffset, const gl::Box &sourceArea, ID3D11Resource *source, UINT sourceSubResource) +{ + D3D11_RESOURCE_DIMENSION dim; + source->GetType(&dim); + + DXGI_FORMAT format = DXGI_FORMAT_UNKNOWN; + gl::Extents extents; + UINT sampleCount = 0; + + ID3D11Texture2D *source2D = NULL; + + if (dim == D3D11_RESOURCE_DIMENSION_TEXTURE2D) + { + D3D11_TEXTURE2D_DESC textureDesc2D; + source2D = d3d11::DynamicCastComObject(source); + ASSERT(source2D); + source2D->GetDesc(&textureDesc2D); + + format = textureDesc2D.Format; + extents = gl::Extents(textureDesc2D.Width, textureDesc2D.Height, 1); + sampleCount = textureDesc2D.SampleDesc.Count; + } + else if (dim == D3D11_RESOURCE_DIMENSION_TEXTURE3D) + { + D3D11_TEXTURE3D_DESC textureDesc3D; + ID3D11Texture3D *source3D = d3d11::DynamicCastComObject(source); + ASSERT(source3D); + source3D->GetDesc(&textureDesc3D); + + format = textureDesc3D.Format; + extents = gl::Extents(textureDesc3D.Width, textureDesc3D.Height, textureDesc3D.Depth); + sampleCount = 1; + } + else + { + UNREACHABLE(); + } + + if (format == mDXGIFormat) + { + // No conversion needed-- use copyback fastpath + ID3D11Resource *stagingTexture = NULL; + unsigned int stagingSubresourceIndex = 0; + gl::Error error = getStagingTexture(&stagingTexture, &stagingSubresourceIndex); + if (error.isError()) + { + return error; + } + + ID3D11Device *device = mRenderer->getDevice(); + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); + + UINT subresourceAfterResolve = sourceSubResource; + + ID3D11Resource *srcTex = NULL; + + bool needResolve = (dim == D3D11_RESOURCE_DIMENSION_TEXTURE2D && sampleCount > 1); + + if (needResolve) + { + D3D11_TEXTURE2D_DESC resolveDesc; + resolveDesc.Width = extents.width; + resolveDesc.Height = extents.height; + resolveDesc.MipLevels = 1; + resolveDesc.ArraySize = 1; + resolveDesc.Format = format; + resolveDesc.SampleDesc.Count = 1; + resolveDesc.SampleDesc.Quality = 0; + resolveDesc.Usage = D3D11_USAGE_DEFAULT; + resolveDesc.BindFlags = 0; + resolveDesc.CPUAccessFlags = 0; + resolveDesc.MiscFlags = 0; + + ID3D11Texture2D *srcTex2D = NULL; + HRESULT result = device->CreateTexture2D(&resolveDesc, NULL, &srcTex2D); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create resolve texture for Image11::copy, HRESULT: 0x%X.", result); + } + srcTex = srcTex2D; + + deviceContext->ResolveSubresource(srcTex, 0, source, sourceSubResource, format); + subresourceAfterResolve = 0; + } + else + { + srcTex = source; + } + + D3D11_BOX srcBox; + srcBox.left = sourceArea.x; + srcBox.right = sourceArea.x + sourceArea.width; + srcBox.top = sourceArea.y; + srcBox.bottom = sourceArea.y + sourceArea.height; + srcBox.front = sourceArea.z; + srcBox.back = sourceArea.z + sourceArea.depth; + + deviceContext->CopySubresourceRegion(stagingTexture, stagingSubresourceIndex, destOffset.x, destOffset.y, + destOffset.z, srcTex, subresourceAfterResolve, &srcBox); + + if (needResolve) + { + SafeRelease(srcTex); + } + } + else + { + // This format requires conversion, so we must copy the texture to staging and manually convert via readPixels + D3D11_MAPPED_SUBRESOURCE mappedImage; + gl::Error error = map(D3D11_MAP_WRITE, &mappedImage); + if (error.isError()) + { + return error; + } + + // determine the offset coordinate into the destination buffer + const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(mDXGIFormat); + GLsizei rowOffset = dxgiFormatInfo.pixelBytes * destOffset.x; + uint8_t *dataOffset = static_cast(mappedImage.pData) + mappedImage.RowPitch * destOffset.y + rowOffset + destOffset.z * mappedImage.DepthPitch; + + const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(mInternalFormat); + + // Currently in ANGLE, the source data may only need to be converted if the source is the current framebuffer + // and OpenGL ES framebuffers must be 2D textures therefore we should not need to convert 3D textures between different formats. + ASSERT(dim == D3D11_RESOURCE_DIMENSION_TEXTURE2D); + ASSERT(sourceArea.z == 0 && sourceArea.depth == 1); + gl::Rectangle sourceRect(sourceArea.x, sourceArea.y, sourceArea.width, sourceArea.height); + error = mRenderer->readTextureData(source2D, sourceSubResource, sourceRect, formatInfo.format, formatInfo.type, mappedImage.RowPitch, gl::PixelPackState(), dataOffset); + + unmap(); + + if (error.isError()) + { + return error; + } + } + + mDirty = true; + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Image11::getStagingTexture(ID3D11Resource **outStagingTexture, unsigned int *outSubresourceIndex) +{ + gl::Error error = createStagingTexture(); + if (error.isError()) + { + return error; + } + + *outStagingTexture = mStagingTexture; + *outSubresourceIndex = mStagingSubresource; + return gl::Error(GL_NO_ERROR); +} + +void Image11::releaseStagingTexture() +{ + SafeRelease(mStagingTexture); +} + +gl::Error Image11::createStagingTexture() +{ + if (mStagingTexture) + { + return gl::Error(GL_NO_ERROR); + } + + ASSERT(mWidth > 0 && mHeight > 0 && mDepth > 0); + + const DXGI_FORMAT dxgiFormat = getDXGIFormat(); + + ID3D11Device *device = mRenderer->getDevice(); + HRESULT result; + + int lodOffset = 1; + GLsizei width = mWidth; + GLsizei height = mHeight; + + // adjust size if needed for compressed textures + d3d11::MakeValidSize(false, dxgiFormat, &width, &height, &lodOffset); + + if (mTarget == GL_TEXTURE_3D) + { + ID3D11Texture3D *newTexture = NULL; + + D3D11_TEXTURE3D_DESC desc; + desc.Width = width; + desc.Height = height; + desc.Depth = mDepth; + desc.MipLevels = lodOffset + 1; + desc.Format = dxgiFormat; + desc.Usage = D3D11_USAGE_STAGING; + desc.BindFlags = 0; + desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE; + desc.MiscFlags = 0; + + if (d3d11::GetTextureFormatInfo(mInternalFormat, mFeatureLevel).dataInitializerFunction != NULL) + { + std::vector initialData; + std::vector< std::vector > textureData; + d3d11::GenerateInitialTextureData(mInternalFormat, mFeatureLevel, width, height, mDepth, + lodOffset + 1, &initialData, &textureData); + + result = device->CreateTexture3D(&desc, initialData.data(), &newTexture); + } + else + { + result = device->CreateTexture3D(&desc, NULL, &newTexture); + } + + if (FAILED(result)) + { + ASSERT(result == E_OUTOFMEMORY); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create staging texture, result: 0x%X.", result); + } + + mStagingTexture = newTexture; + mStagingSubresource = D3D11CalcSubresource(lodOffset, 0, lodOffset + 1); + } + else if (mTarget == GL_TEXTURE_2D || mTarget == GL_TEXTURE_2D_ARRAY || mTarget == GL_TEXTURE_CUBE_MAP) + { + ID3D11Texture2D *newTexture = NULL; + + D3D11_TEXTURE2D_DESC desc; + desc.Width = width; + desc.Height = height; + desc.MipLevels = lodOffset + 1; + desc.ArraySize = 1; + desc.Format = dxgiFormat; + desc.SampleDesc.Count = 1; + desc.SampleDesc.Quality = 0; + desc.Usage = D3D11_USAGE_STAGING; + desc.BindFlags = 0; + desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE; + desc.MiscFlags = 0; + + if (d3d11::GetTextureFormatInfo(mInternalFormat, mFeatureLevel).dataInitializerFunction != NULL) + { + std::vector initialData; + std::vector< std::vector > textureData; + d3d11::GenerateInitialTextureData(mInternalFormat, mFeatureLevel, width, height, 1, + lodOffset + 1, &initialData, &textureData); + + result = device->CreateTexture2D(&desc, initialData.data(), &newTexture); + } + else + { + result = device->CreateTexture2D(&desc, NULL, &newTexture); + } + + if (FAILED(result)) + { + ASSERT(result == E_OUTOFMEMORY); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create staging texture, result: 0x%X.", result); + } + + mStagingTexture = newTexture; + mStagingSubresource = D3D11CalcSubresource(lodOffset, 0, lodOffset + 1); + } + else + { + UNREACHABLE(); + } + + mDirty = false; + return gl::Error(GL_NO_ERROR); +} + +gl::Error Image11::map(D3D11_MAP mapType, D3D11_MAPPED_SUBRESOURCE *map) +{ + // We must recover from the TextureStorage if necessary, even for D3D11_MAP_WRITE. + gl::Error error = recoverFromAssociatedStorage(); + if (error.isError()) + { + return error; + } + + ID3D11Resource *stagingTexture = NULL; + unsigned int subresourceIndex = 0; + error = getStagingTexture(&stagingTexture, &subresourceIndex); + if (error.isError()) + { + return error; + } + + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); + + ASSERT(mStagingTexture); + HRESULT result = deviceContext->Map(stagingTexture, subresourceIndex, mapType, 0, map); + + // this can fail if the device is removed (from TDR) + if (d3d11::isDeviceLostError(result)) + { + mRenderer->notifyDeviceLost(); + } + else if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to map staging texture, result: 0x%X.", result); + } + + mDirty = true; + + return gl::Error(GL_NO_ERROR); +} + +void Image11::unmap() +{ + if (mStagingTexture) + { + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); + deviceContext->Unmap(mStagingTexture, mStagingSubresource); + } +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Image11.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Image11.h new file mode 100644 index 0000000000..5734f73b15 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Image11.h @@ -0,0 +1,84 @@ +// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Image11.h: Defines the rx::Image11 class, which acts as the interface to +// the actual underlying resources of a Texture + +#ifndef LIBANGLE_RENDERER_D3D_D3D11_IMAGE11_H_ +#define LIBANGLE_RENDERER_D3D_D3D11_IMAGE11_H_ + +#include "libANGLE/renderer/d3d/ImageD3D.h" +#include "libANGLE/ImageIndex.h" + +#include "common/debug.h" + +namespace gl +{ +class Framebuffer; +} + +namespace rx +{ +class Renderer11; +class TextureStorage11; + +class Image11 : public ImageD3D +{ + public: + Image11(Renderer11 *renderer); + virtual ~Image11(); + + static Image11 *makeImage11(ImageD3D *img); + + static gl::Error generateMipmap(Image11 *dest, Image11 *src); + + virtual bool isDirty() const; + + virtual gl::Error copyToStorage(TextureStorage *storage, const gl::ImageIndex &index, const gl::Box ®ion); + + bool redefine(GLenum target, GLenum internalformat, const gl::Extents &size, bool forceRelease) override; + + DXGI_FORMAT getDXGIFormat() const; + + virtual gl::Error loadData(const gl::Box &area, const gl::PixelUnpackState &unpack, GLenum type, const void *input); + virtual gl::Error loadCompressedData(const gl::Box &area, const void *input); + + virtual gl::Error copy(const gl::Offset &destOffset, const gl::Rectangle &sourceArea, RenderTargetD3D *source); + virtual gl::Error copy(const gl::Offset &destOffset, const gl::Box &sourceArea, + const gl::ImageIndex &sourceIndex, TextureStorage *source); + + gl::Error recoverFromAssociatedStorage(); + bool isAssociatedStorageValid(TextureStorage11* textureStorage) const; + void disassociateStorage(); + + protected: + gl::Error map(D3D11_MAP mapType, D3D11_MAPPED_SUBRESOURCE *map); + void unmap(); + + private: + gl::Error copyToStorageImpl(TextureStorage11 *storage11, const gl::ImageIndex &index, const gl::Box ®ion); + gl::Error copy(const gl::Offset &destOffset, const gl::Box &sourceArea, ID3D11Resource *source, UINT sourceSubResource); + + gl::Error getStagingTexture(ID3D11Resource **outStagingTexture, unsigned int *outSubresourceIndex); + gl::Error createStagingTexture(); + void releaseStagingTexture(); + + Renderer11 *mRenderer; + D3D_FEATURE_LEVEL mFeatureLevel; + + DXGI_FORMAT mDXGIFormat; + ID3D11Resource *mStagingTexture; + unsigned int mStagingSubresource; + + bool mRecoverFromStorage; + TextureStorage11 *mAssociatedStorage; + gl::ImageIndex mAssociatedImageIndex; + unsigned int mRecoveredFromStorageCount; +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_D3D11_IMAGE11_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/IndexBuffer11.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/IndexBuffer11.cpp new file mode 100644 index 0000000000..99c199f2b9 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/IndexBuffer11.cpp @@ -0,0 +1,162 @@ +// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// IndexBuffer11.cpp: Defines the D3D11 IndexBuffer implementation. + +#include "libANGLE/renderer/d3d/d3d11/IndexBuffer11.h" +#include "libANGLE/renderer/d3d/d3d11/Renderer11.h" + +namespace rx +{ + +IndexBuffer11::IndexBuffer11(Renderer11 *const renderer) : mRenderer(renderer) +{ + mBuffer = NULL; + mBufferSize = 0; + mDynamicUsage = false; +} + +IndexBuffer11::~IndexBuffer11() +{ + SafeRelease(mBuffer); +} + +gl::Error IndexBuffer11::initialize(unsigned int bufferSize, GLenum indexType, bool dynamic) +{ + SafeRelease(mBuffer); + + updateSerial(); + + if (bufferSize > 0) + { + ID3D11Device* dxDevice = mRenderer->getDevice(); + + D3D11_BUFFER_DESC bufferDesc; + bufferDesc.ByteWidth = bufferSize; + bufferDesc.Usage = D3D11_USAGE_DYNAMIC; + bufferDesc.BindFlags = D3D11_BIND_INDEX_BUFFER; + bufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + bufferDesc.MiscFlags = 0; + bufferDesc.StructureByteStride = 0; + + HRESULT result = dxDevice->CreateBuffer(&bufferDesc, NULL, &mBuffer); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate internal index buffer of size, %lu.", bufferSize); + } + } + + mBufferSize = bufferSize; + mIndexType = indexType; + mDynamicUsage = dynamic; + + return gl::Error(GL_NO_ERROR); +} + +IndexBuffer11 *IndexBuffer11::makeIndexBuffer11(IndexBuffer *indexBuffer) +{ + ASSERT(HAS_DYNAMIC_TYPE(IndexBuffer11*, indexBuffer)); + return static_cast(indexBuffer); +} + +gl::Error IndexBuffer11::mapBuffer(unsigned int offset, unsigned int size, void** outMappedMemory) +{ + if (!mBuffer) + { + return gl::Error(GL_OUT_OF_MEMORY, "Internal index buffer is not initialized."); + } + + // Check for integer overflows and out-out-bounds map requests + if (offset + size < offset || offset + size > mBufferSize) + { + return gl::Error(GL_OUT_OF_MEMORY, "Index buffer map range is not inside the buffer."); + } + + ID3D11DeviceContext *dxContext = mRenderer->getDeviceContext(); + + D3D11_MAPPED_SUBRESOURCE mappedResource; + HRESULT result = dxContext->Map(mBuffer, 0, D3D11_MAP_WRITE_NO_OVERWRITE, 0, &mappedResource); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to map internal index buffer, HRESULT: 0x%08x.", result); + } + + *outMappedMemory = reinterpret_cast(mappedResource.pData) + offset; + return gl::Error(GL_NO_ERROR); +} + +gl::Error IndexBuffer11::unmapBuffer() +{ + if (!mBuffer) + { + return gl::Error(GL_OUT_OF_MEMORY, "Internal index buffer is not initialized."); + } + + ID3D11DeviceContext *dxContext = mRenderer->getDeviceContext(); + dxContext->Unmap(mBuffer, 0); + return gl::Error(GL_NO_ERROR); +} + +GLenum IndexBuffer11::getIndexType() const +{ + return mIndexType; +} + +unsigned int IndexBuffer11::getBufferSize() const +{ + return mBufferSize; +} + +gl::Error IndexBuffer11::setSize(unsigned int bufferSize, GLenum indexType) +{ + if (bufferSize > mBufferSize || indexType != mIndexType) + { + return initialize(bufferSize, indexType, mDynamicUsage); + } + else + { + return gl::Error(GL_NO_ERROR); + } +} + +gl::Error IndexBuffer11::discard() +{ + if (!mBuffer) + { + return gl::Error(GL_OUT_OF_MEMORY, "Internal index buffer is not initialized."); + } + + ID3D11DeviceContext *dxContext = mRenderer->getDeviceContext(); + + D3D11_MAPPED_SUBRESOURCE mappedResource; + HRESULT result = dxContext->Map(mBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to map internal index buffer, HRESULT: 0x%08x.", result); + } + + dxContext->Unmap(mBuffer, 0); + + return gl::Error(GL_NO_ERROR); +} + +DXGI_FORMAT IndexBuffer11::getIndexFormat() const +{ + switch (mIndexType) + { + case GL_UNSIGNED_BYTE: return DXGI_FORMAT_R16_UINT; + case GL_UNSIGNED_SHORT: return DXGI_FORMAT_R16_UINT; + case GL_UNSIGNED_INT: return DXGI_FORMAT_R32_UINT; + default: UNREACHABLE(); return DXGI_FORMAT_UNKNOWN; + } +} + +ID3D11Buffer *IndexBuffer11::getBuffer() const +{ + return mBuffer; +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/IndexBuffer11.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/IndexBuffer11.h new file mode 100644 index 0000000000..eadd03eb76 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/IndexBuffer11.h @@ -0,0 +1,51 @@ +// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// IndexBuffer11.h: Defines the D3D11 IndexBuffer implementation. + +#ifndef LIBANGLE_RENDERER_D3D_D3D11_INDEXBUFFER11_H_ +#define LIBANGLE_RENDERER_D3D_D3D11_INDEXBUFFER11_H_ + +#include "libANGLE/renderer/d3d/IndexBuffer.h" + +namespace rx +{ +class Renderer11; + +class IndexBuffer11 : public IndexBuffer +{ + public: + explicit IndexBuffer11(Renderer11 *const renderer); + virtual ~IndexBuffer11(); + + virtual gl::Error initialize(unsigned int bufferSize, GLenum indexType, bool dynamic); + + static IndexBuffer11 *makeIndexBuffer11(IndexBuffer *indexBuffer); + + virtual gl::Error mapBuffer(unsigned int offset, unsigned int size, void** outMappedMemory); + virtual gl::Error unmapBuffer(); + + virtual GLenum getIndexType() const; + virtual unsigned int getBufferSize() const; + virtual gl::Error setSize(unsigned int bufferSize, GLenum indexType); + + virtual gl::Error discard(); + + DXGI_FORMAT getIndexFormat() const; + ID3D11Buffer *getBuffer() const; + + private: + Renderer11 *const mRenderer; + + ID3D11Buffer *mBuffer; + unsigned int mBufferSize; + GLenum mIndexType; + bool mDynamicUsage; +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_D3D11_INDEXBUFFER11_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/InputLayoutCache.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/InputLayoutCache.cpp new file mode 100644 index 0000000000..242c09d6ce --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/InputLayoutCache.cpp @@ -0,0 +1,430 @@ +// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// InputLayoutCache.cpp: Defines InputLayoutCache, a class that builds and caches +// D3D11 input layouts. + +#include "libANGLE/renderer/d3d/d3d11/InputLayoutCache.h" +#include "libANGLE/renderer/d3d/d3d11/VertexBuffer11.h" +#include "libANGLE/renderer/d3d/d3d11/Buffer11.h" +#include "libANGLE/renderer/d3d/d3d11/ShaderExecutable11.h" +#include "libANGLE/renderer/d3d/d3d11/formatutils11.h" +#include "libANGLE/renderer/d3d/ProgramD3D.h" +#include "libANGLE/renderer/d3d/VertexDataManager.h" +#include "libANGLE/Program.h" +#include "libANGLE/VertexAttribute.h" + +#include "third_party/murmurhash/MurmurHash3.h" + +namespace rx +{ + +static void GetInputLayout(const TranslatedAttribute translatedAttributes[gl::MAX_VERTEX_ATTRIBS], + gl::VertexFormat inputLayout[gl::MAX_VERTEX_ATTRIBS]) +{ + for (unsigned int attributeIndex = 0; attributeIndex < gl::MAX_VERTEX_ATTRIBS; attributeIndex++) + { + const TranslatedAttribute &translatedAttribute = translatedAttributes[attributeIndex]; + + if (translatedAttributes[attributeIndex].active) + { + inputLayout[attributeIndex] = gl::VertexFormat(*translatedAttribute.attribute, + translatedAttribute.currentValueType); + } + } +} + +const unsigned int InputLayoutCache::kMaxInputLayouts = 1024; + +InputLayoutCache::InputLayoutCache() : mInputLayoutMap(kMaxInputLayouts, hashInputLayout, compareInputLayouts) +{ + mCounter = 0; + mDevice = NULL; + mDeviceContext = NULL; + mCurrentIL = NULL; + for (unsigned int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) + { + mCurrentBuffers[i] = NULL; + mCurrentVertexStrides[i] = static_cast(-1); + mCurrentVertexOffsets[i] = static_cast(-1); + } + mPointSpriteVertexBuffer = NULL; + mPointSpriteIndexBuffer = NULL; +} + +InputLayoutCache::~InputLayoutCache() +{ + clear(); +} + +void InputLayoutCache::initialize(ID3D11Device *device, ID3D11DeviceContext *context) +{ + clear(); + mDevice = device; + mDeviceContext = context; + mFeatureLevel = device->GetFeatureLevel(); +} + +void InputLayoutCache::clear() +{ + for (InputLayoutMap::iterator i = mInputLayoutMap.begin(); i != mInputLayoutMap.end(); i++) + { + SafeRelease(i->second.inputLayout); + } + mInputLayoutMap.clear(); + SafeRelease(mPointSpriteVertexBuffer); + SafeRelease(mPointSpriteIndexBuffer); + markDirty(); +} + +void InputLayoutCache::markDirty() +{ + mCurrentIL = NULL; + for (unsigned int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) + { + mCurrentBuffers[i] = NULL; + mCurrentVertexStrides[i] = static_cast(-1); + mCurrentVertexOffsets[i] = static_cast(-1); + } +} + +gl::Error InputLayoutCache::applyVertexBuffers(TranslatedAttribute attributes[gl::MAX_VERTEX_ATTRIBS], + GLenum mode, gl::Program *program) +{ + ProgramD3D *programD3D = GetImplAs(program); + + int sortedSemanticIndices[gl::MAX_VERTEX_ATTRIBS]; + programD3D->sortAttributesByLayout(attributes, sortedSemanticIndices); + bool programUsesInstancedPointSprites = programD3D->usesPointSize() && programD3D->usesInstancedPointSpriteEmulation(); + bool instancedPointSpritesActive = programUsesInstancedPointSprites && (mode == GL_POINTS); + + if (!mDevice || !mDeviceContext) + { + return gl::Error(GL_OUT_OF_MEMORY, "Internal input layout cache is not initialized."); + } + + InputLayoutKey ilKey = { 0 }; + + static const char* semanticName = "TEXCOORD"; + + unsigned int firstIndexedElement = gl::MAX_VERTEX_ATTRIBS; + unsigned int firstInstancedElement = gl::MAX_VERTEX_ATTRIBS; + unsigned int nextAvailableInputSlot = 0; + + for (unsigned int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) + { + if (attributes[i].active) + { + D3D11_INPUT_CLASSIFICATION inputClass = attributes[i].divisor > 0 ? D3D11_INPUT_PER_INSTANCE_DATA : D3D11_INPUT_PER_VERTEX_DATA; + // If rendering points and instanced pointsprite emulation is being used, the inputClass is required to be configured as per instance data + inputClass = instancedPointSpritesActive ? D3D11_INPUT_PER_INSTANCE_DATA : inputClass; + + gl::VertexFormat vertexFormat(*attributes[i].attribute, attributes[i].currentValueType); + const d3d11::VertexFormat &vertexFormatInfo = d3d11::GetVertexFormatInfo(vertexFormat, mFeatureLevel); + + // Record the type of the associated vertex shader vector in our key + // This will prevent mismatched vertex shaders from using the same input layout + GLint attributeSize; + program->getActiveAttribute(ilKey.elementCount, 0, NULL, &attributeSize, &ilKey.elements[ilKey.elementCount].glslElementType, NULL); + + ilKey.elements[ilKey.elementCount].desc.SemanticName = semanticName; + ilKey.elements[ilKey.elementCount].desc.SemanticIndex = sortedSemanticIndices[i]; + ilKey.elements[ilKey.elementCount].desc.Format = vertexFormatInfo.nativeFormat; + ilKey.elements[ilKey.elementCount].desc.InputSlot = i; + ilKey.elements[ilKey.elementCount].desc.AlignedByteOffset = 0; + ilKey.elements[ilKey.elementCount].desc.InputSlotClass = inputClass; + ilKey.elements[ilKey.elementCount].desc.InstanceDataStepRate = instancedPointSpritesActive ? 1 : attributes[i].divisor; + + if (inputClass == D3D11_INPUT_PER_VERTEX_DATA && firstIndexedElement == gl::MAX_VERTEX_ATTRIBS) + { + firstIndexedElement = ilKey.elementCount; + } + else if (inputClass == D3D11_INPUT_PER_INSTANCE_DATA && firstInstancedElement == gl::MAX_VERTEX_ATTRIBS) + { + firstInstancedElement = ilKey.elementCount; + } + + ilKey.elementCount++; + nextAvailableInputSlot = i + 1; + } + } + + // Instanced PointSprite emulation requires additional entries in the + // inputlayout to support the vertices that make up the pointsprite quad. + // We do this even if mode != GL_POINTS, since the shader signature has these inputs, and the input layout must match the shader + if (programUsesInstancedPointSprites) + { + ilKey.elements[ilKey.elementCount].desc.SemanticName = "SPRITEPOSITION"; + ilKey.elements[ilKey.elementCount].desc.SemanticIndex = 0; + ilKey.elements[ilKey.elementCount].desc.Format = DXGI_FORMAT_R32G32B32_FLOAT; + ilKey.elements[ilKey.elementCount].desc.InputSlot = nextAvailableInputSlot; + ilKey.elements[ilKey.elementCount].desc.AlignedByteOffset = 0; + ilKey.elements[ilKey.elementCount].desc.InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA; + ilKey.elements[ilKey.elementCount].desc.InstanceDataStepRate = 0; + + // The new elements are D3D11_INPUT_PER_VERTEX_DATA data so the indexed element + // tracking must be applied. This ensures that the instancing specific + // buffer swapping logic continues to work. + if (firstIndexedElement == gl::MAX_VERTEX_ATTRIBS) + { + firstIndexedElement = ilKey.elementCount; + } + + ilKey.elementCount++; + + ilKey.elements[ilKey.elementCount].desc.SemanticName = "SPRITETEXCOORD"; + ilKey.elements[ilKey.elementCount].desc.SemanticIndex = 0; + ilKey.elements[ilKey.elementCount].desc.Format = DXGI_FORMAT_R32G32_FLOAT; + ilKey.elements[ilKey.elementCount].desc.InputSlot = nextAvailableInputSlot; + ilKey.elements[ilKey.elementCount].desc.AlignedByteOffset = sizeof(float) * 3; + ilKey.elements[ilKey.elementCount].desc.InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA; + ilKey.elements[ilKey.elementCount].desc.InstanceDataStepRate = 0; + + ilKey.elementCount++; + } + + // On 9_3, we must ensure that slot 0 contains non-instanced data. + // If slot 0 currently contains instanced data then we swap it with a non-instanced element. + // Note that instancing is only available on 9_3 via ANGLE_instanced_arrays, since 9_3 doesn't support OpenGL ES 3.0. + // As per the spec for ANGLE_instanced_arrays, not all attributes can be instanced simultaneously, so a non-instanced element must exist. + ASSERT(!(mFeatureLevel <= D3D_FEATURE_LEVEL_9_3 && firstIndexedElement == gl::MAX_VERTEX_ATTRIBS)); + bool moveFirstIndexedIntoSlotZero = mFeatureLevel <= D3D_FEATURE_LEVEL_9_3 && firstInstancedElement == 0 && firstIndexedElement != gl::MAX_VERTEX_ATTRIBS; + + if (moveFirstIndexedIntoSlotZero) + { + ilKey.elements[firstInstancedElement].desc.InputSlot = ilKey.elements[firstIndexedElement].desc.InputSlot; + ilKey.elements[firstIndexedElement].desc.InputSlot = 0; + + // Instanced PointSprite emulation uses multiple layout entries across a single vertex buffer. + // If an index swap is performed, we need to ensure that all elements get the proper InputSlot. + if (programUsesInstancedPointSprites) + { + ilKey.elements[firstIndexedElement + 1].desc.InputSlot = 0; + } + } + + ID3D11InputLayout *inputLayout = NULL; + + InputLayoutMap::iterator keyIter = mInputLayoutMap.find(ilKey); + if (keyIter != mInputLayoutMap.end()) + { + inputLayout = keyIter->second.inputLayout; + keyIter->second.lastUsedTime = mCounter++; + } + else + { + gl::VertexFormat shaderInputLayout[gl::MAX_VERTEX_ATTRIBS]; + GetInputLayout(attributes, shaderInputLayout); + + ShaderExecutableD3D *shader = NULL; + gl::Error error = programD3D->getVertexExecutableForInputLayout(shaderInputLayout, &shader, nullptr); + if (error.isError()) + { + return error; + } + + ShaderExecutableD3D *shader11 = ShaderExecutable11::makeShaderExecutable11(shader); + + D3D11_INPUT_ELEMENT_DESC descs[gl::MAX_VERTEX_ATTRIBS]; + for (unsigned int j = 0; j < ilKey.elementCount; ++j) + { + descs[j] = ilKey.elements[j].desc; + } + + HRESULT result = mDevice->CreateInputLayout(descs, ilKey.elementCount, shader11->getFunction(), shader11->getLength(), &inputLayout); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal input layout, HRESULT: 0x%08x", result); + } + + if (mInputLayoutMap.size() >= kMaxInputLayouts) + { + TRACE("Overflowed the limit of %u input layouts, removing the least recently used " + "to make room.", kMaxInputLayouts); + + InputLayoutMap::iterator leastRecentlyUsed = mInputLayoutMap.begin(); + for (InputLayoutMap::iterator i = mInputLayoutMap.begin(); i != mInputLayoutMap.end(); i++) + { + if (i->second.lastUsedTime < leastRecentlyUsed->second.lastUsedTime) + { + leastRecentlyUsed = i; + } + } + SafeRelease(leastRecentlyUsed->second.inputLayout); + mInputLayoutMap.erase(leastRecentlyUsed); + } + + InputLayoutCounterPair inputCounterPair; + inputCounterPair.inputLayout = inputLayout; + inputCounterPair.lastUsedTime = mCounter++; + + mInputLayoutMap.insert(std::make_pair(ilKey, inputCounterPair)); + } + + if (inputLayout != mCurrentIL) + { + mDeviceContext->IASetInputLayout(inputLayout); + mCurrentIL = inputLayout; + } + + bool dirtyBuffers = false; + size_t minDiff = gl::MAX_VERTEX_ATTRIBS; + size_t maxDiff = 0; + unsigned int nextAvailableIndex = 0; + + for (unsigned int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) + { + ID3D11Buffer *buffer = NULL; + + if (attributes[i].active) + { + VertexBuffer11 *vertexBuffer = VertexBuffer11::makeVertexBuffer11(attributes[i].vertexBuffer); + Buffer11 *bufferStorage = attributes[i].storage ? Buffer11::makeBuffer11(attributes[i].storage) : NULL; + + buffer = bufferStorage ? bufferStorage->getBuffer(BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK) + : vertexBuffer->getBuffer(); + } + + UINT vertexStride = attributes[i].stride; + UINT vertexOffset = attributes[i].offset; + + if (buffer != mCurrentBuffers[i] || vertexStride != mCurrentVertexStrides[i] || + vertexOffset != mCurrentVertexOffsets[i]) + { + dirtyBuffers = true; + minDiff = std::min(minDiff, static_cast(i)); + maxDiff = std::max(maxDiff, static_cast(i)); + + mCurrentBuffers[i] = buffer; + mCurrentVertexStrides[i] = vertexStride; + mCurrentVertexOffsets[i] = vertexOffset; + + // If a non null ID3D11Buffer is being assigned to mCurrentBuffers, + // then the next available index needs to be tracked to ensure + // that any instanced pointsprite emulation buffers will be properly packed. + if (buffer) + { + nextAvailableIndex = i + 1; + } + } + } + + // Instanced PointSprite emulation requires two additional ID3D11Buffers. + // A vertex buffer needs to be created and added to the list of current buffers, + // strides and offsets collections. This buffer contains the vertices for a single + // PointSprite quad. + // An index buffer also needs to be created and applied because rendering instanced + // data on D3D11 FL9_3 requires DrawIndexedInstanced() to be used. + if (instancedPointSpritesActive) + { + HRESULT result = S_OK; + const UINT pointSpriteVertexStride = sizeof(float) * 5; + + if (!mPointSpriteVertexBuffer) + { + static const float pointSpriteVertices[] = + { + // Position // TexCoord + -1.0f, -1.0f, 0.0f, 0.0f, 1.0f, + -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, + 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, + 1.0f, -1.0f, 0.0f, 1.0f, 1.0f, + -1.0f, -1.0f, 0.0f, 0.0f, 1.0f, + 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, + }; + + D3D11_SUBRESOURCE_DATA vertexBufferData = { pointSpriteVertices, 0, 0 }; + D3D11_BUFFER_DESC vertexBufferDesc; + vertexBufferDesc.ByteWidth = sizeof(pointSpriteVertices); + vertexBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; + vertexBufferDesc.Usage = D3D11_USAGE_IMMUTABLE; + vertexBufferDesc.CPUAccessFlags = 0; + vertexBufferDesc.MiscFlags = 0; + vertexBufferDesc.StructureByteStride = 0; + + result = mDevice->CreateBuffer(&vertexBufferDesc, &vertexBufferData, &mPointSpriteVertexBuffer); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create instanced pointsprite emulation vertex buffer, HRESULT: 0x%08x", result); + } + } + + mCurrentBuffers[nextAvailableIndex] = mPointSpriteVertexBuffer; + mCurrentVertexStrides[nextAvailableIndex] = pointSpriteVertexStride; + mCurrentVertexOffsets[nextAvailableIndex] = 0; + + if (!mPointSpriteIndexBuffer) + { + // Create an index buffer and set it for pointsprite rendering + static const unsigned short pointSpriteIndices[] = + { + 0, 1, 2, 3, 4, 5, + }; + + D3D11_SUBRESOURCE_DATA indexBufferData = { pointSpriteIndices, 0, 0 }; + D3D11_BUFFER_DESC indexBufferDesc; + indexBufferDesc.ByteWidth = sizeof(pointSpriteIndices); + indexBufferDesc.BindFlags = D3D11_BIND_INDEX_BUFFER; + indexBufferDesc.Usage = D3D11_USAGE_IMMUTABLE; + indexBufferDesc.CPUAccessFlags = 0; + indexBufferDesc.MiscFlags = 0; + indexBufferDesc.StructureByteStride = 0; + + result = mDevice->CreateBuffer(&indexBufferDesc, &indexBufferData, &mPointSpriteIndexBuffer); + if (FAILED(result)) + { + SafeRelease(mPointSpriteVertexBuffer); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create instanced pointsprite emulation index buffer, HRESULT: 0x%08x", result); + } + } + + // The index buffer is applied here because Instanced PointSprite emulation uses + // the a non-indexed rendering path in ANGLE (DrawArrays). This means that applyIndexBuffer() + // on the renderer will not be called and setting this buffer here ensures that the rendering + // path will contain the correct index buffers. + mDeviceContext->IASetIndexBuffer(mPointSpriteIndexBuffer, DXGI_FORMAT_R16_UINT, 0); + } + + if (moveFirstIndexedIntoSlotZero) + { + // In this case, we swapped the slots of the first instanced element and the first indexed element, to ensure + // that the first slot contains non-instanced data (required by Feature Level 9_3). + // We must also swap the corresponding buffers sent to IASetVertexBuffers so that the correct data is sent to each slot. + std::swap(mCurrentBuffers[firstIndexedElement], mCurrentBuffers[firstInstancedElement]); + std::swap(mCurrentVertexStrides[firstIndexedElement], mCurrentVertexStrides[firstInstancedElement]); + std::swap(mCurrentVertexOffsets[firstIndexedElement], mCurrentVertexOffsets[firstInstancedElement]); + } + + if (dirtyBuffers) + { + ASSERT(minDiff <= maxDiff && maxDiff < gl::MAX_VERTEX_ATTRIBS); + mDeviceContext->IASetVertexBuffers(minDiff, maxDiff - minDiff + 1, mCurrentBuffers + minDiff, + mCurrentVertexStrides + minDiff, mCurrentVertexOffsets + minDiff); + } + + return gl::Error(GL_NO_ERROR); +} + +std::size_t InputLayoutCache::hashInputLayout(const InputLayoutKey &inputLayout) +{ + static const unsigned int seed = 0xDEADBEEF; + + std::size_t hash = 0; + MurmurHash3_x86_32(inputLayout.begin(), inputLayout.end() - inputLayout.begin(), seed, &hash); + return hash; +} + +bool InputLayoutCache::compareInputLayouts(const InputLayoutKey &a, const InputLayoutKey &b) +{ + if (a.elementCount != b.elementCount) + { + return false; + } + + return std::equal(a.begin(), a.end(), b.begin()); +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/InputLayoutCache.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/InputLayoutCache.h new file mode 100644 index 0000000000..2c94c57595 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/InputLayoutCache.h @@ -0,0 +1,103 @@ +// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// InputLayoutCache.h: Defines InputLayoutCache, a class that builds and caches +// D3D11 input layouts. + +#ifndef LIBANGLE_RENDERER_D3D_D3D11_INPUTLAYOUTCACHE_H_ +#define LIBANGLE_RENDERER_D3D_D3D11_INPUTLAYOUTCACHE_H_ + +#include "libANGLE/Constants.h" +#include "libANGLE/Error.h" +#include "common/angleutils.h" + +#include + +#include +#include + +namespace gl +{ +class Program; +} + +namespace rx +{ +struct TranslatedAttribute; + +class InputLayoutCache : angle::NonCopyable +{ + public: + InputLayoutCache(); + virtual ~InputLayoutCache(); + + void initialize(ID3D11Device *device, ID3D11DeviceContext *context); + void clear(); + void markDirty(); + + gl::Error applyVertexBuffers(TranslatedAttribute attributes[gl::MAX_VERTEX_ATTRIBS], + GLenum mode, gl::Program *program); + + private: + struct InputLayoutElement + { + D3D11_INPUT_ELEMENT_DESC desc; + GLenum glslElementType; + }; + + struct InputLayoutKey + { + unsigned int elementCount; + InputLayoutElement elements[gl::MAX_VERTEX_ATTRIBS]; + + const char *begin() const + { + return reinterpret_cast(&elementCount); + } + + const char *end() const + { + return reinterpret_cast(&elements[elementCount]); + } + }; + + struct InputLayoutCounterPair + { + ID3D11InputLayout *inputLayout; + unsigned long long lastUsedTime; + }; + + ID3D11InputLayout *mCurrentIL; + ID3D11Buffer *mCurrentBuffers[gl::MAX_VERTEX_ATTRIBS]; + UINT mCurrentVertexStrides[gl::MAX_VERTEX_ATTRIBS]; + UINT mCurrentVertexOffsets[gl::MAX_VERTEX_ATTRIBS]; + + ID3D11Buffer *mPointSpriteVertexBuffer; + ID3D11Buffer *mPointSpriteIndexBuffer; + + static std::size_t hashInputLayout(const InputLayoutKey &inputLayout); + static bool compareInputLayouts(const InputLayoutKey &a, const InputLayoutKey &b); + + typedef std::size_t (*InputLayoutHashFunction)(const InputLayoutKey &); + typedef bool (*InputLayoutEqualityFunction)(const InputLayoutKey &, const InputLayoutKey &); + typedef std::unordered_map InputLayoutMap; + InputLayoutMap mInputLayoutMap; + + static const unsigned int kMaxInputLayouts; + + unsigned long long mCounter; + + ID3D11Device *mDevice; + ID3D11DeviceContext *mDeviceContext; + D3D_FEATURE_LEVEL mFeatureLevel; +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_D3D11_INPUTLAYOUTCACHE_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/NativeWindow.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/NativeWindow.h new file mode 100644 index 0000000000..81b9ea748d --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/NativeWindow.h @@ -0,0 +1,80 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// NativeWindow.h: Defines NativeWindow, a class for managing and +// performing operations on an EGLNativeWindowType. +// It is used for HWND (Desktop Windows) and IInspectable objects +//(Windows Store Applications). + +#ifndef LIBANGLE_RENDERER_D3D_D3D11_NATIVEWINDOW_H_ +#define LIBANGLE_RENDERER_D3D_D3D11_NATIVEWINDOW_H_ + +#include "common/debug.h" +#include "common/platform.h" + +#include + +// DXGISwapChain and DXGIFactory are typedef'd to specific required +// types. The HWND NativeWindow implementation requires IDXGISwapChain +// and IDXGIFactory and the Windows Store NativeWindow +// implementation requires IDXGISwapChain1 and IDXGIFactory2. +#if defined(ANGLE_ENABLE_WINDOWS_STORE) +typedef IDXGISwapChain1 DXGISwapChain; +typedef IDXGIFactory2 DXGIFactory; + +#include +#include +#include +#include + +namespace rx +{ +class InspectableNativeWindow; +} + +using namespace Microsoft::WRL; +using namespace Microsoft::WRL::Wrappers; + +#else +typedef IDXGISwapChain DXGISwapChain; +typedef IDXGIFactory DXGIFactory; +#endif + +namespace rx +{ + +class NativeWindow +{ + public: + enum RotationFlags { RotateNone = 0, RotateLeft = 1, RotateRight = 2 }; + explicit NativeWindow(EGLNativeWindowType window); + + bool initialize(); + bool getClientRect(LPRECT rect); + bool isIconic(); +#if defined(ANGLE_ENABLE_WINDOWS_STORE) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) + RotationFlags rotationFlags() const; +#endif + static bool isValidNativeWindow(EGLNativeWindowType window); + + HRESULT createSwapChain(ID3D11Device* device, DXGIFactory* factory, + DXGI_FORMAT format, UINT width, UINT height, + DXGISwapChain** swapChain); + + inline EGLNativeWindowType getNativeWindow() const { return mWindow; } + + private: + EGLNativeWindowType mWindow; + +#if defined(ANGLE_ENABLE_WINDOWS_STORE) + std::shared_ptr mImpl; +#endif + +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_D3D11_NATIVEWINDOW_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/PixelTransfer11.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/PixelTransfer11.cpp new file mode 100644 index 0000000000..5fd5237d90 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/PixelTransfer11.cpp @@ -0,0 +1,302 @@ +// +// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// PixelTransfer11.cpp: +// Implementation for buffer-to-texture and texture-to-buffer copies. +// Used to implement pixel transfers from unpack and to pack buffers. +// + +#include "libANGLE/renderer/d3d/d3d11/PixelTransfer11.h" +#include "libANGLE/renderer/d3d/d3d11/Renderer11.h" +#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h" +#include "libANGLE/renderer/d3d/d3d11/formatutils11.h" +#include "libANGLE/renderer/d3d/d3d11/Buffer11.h" +#include "libANGLE/renderer/d3d/d3d11/TextureStorage11.h" +#include "libANGLE/renderer/d3d/d3d11/RenderTarget11.h" +#include "libANGLE/formatutils.h" +#include "libANGLE/Texture.h" +#include "libANGLE/Buffer.h" +#include "libANGLE/Context.h" + +// Precompiled shaders +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/buffertotexture11_vs.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/buffertotexture11_gs.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/buffertotexture11_ps_4f.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/buffertotexture11_ps_4i.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/buffertotexture11_ps_4ui.h" + +namespace rx +{ + +PixelTransfer11::PixelTransfer11(Renderer11 *renderer) + : mRenderer(renderer), + mResourcesLoaded(false), + mBufferToTextureVS(NULL), + mBufferToTextureGS(NULL), + mParamsConstantBuffer(NULL), + mCopyRasterizerState(NULL), + mCopyDepthStencilState(NULL) +{ +} + +PixelTransfer11::~PixelTransfer11() +{ + for (auto shaderMapIt = mBufferToTexturePSMap.begin(); shaderMapIt != mBufferToTexturePSMap.end(); shaderMapIt++) + { + SafeRelease(shaderMapIt->second); + } + + mBufferToTexturePSMap.clear(); + + SafeRelease(mBufferToTextureVS); + SafeRelease(mBufferToTextureGS); + SafeRelease(mParamsConstantBuffer); + SafeRelease(mCopyRasterizerState); + SafeRelease(mCopyDepthStencilState); +} + +gl::Error PixelTransfer11::loadResources() +{ + if (mResourcesLoaded) + { + return gl::Error(GL_NO_ERROR); + } + + HRESULT result = S_OK; + ID3D11Device *device = mRenderer->getDevice(); + + D3D11_RASTERIZER_DESC rasterDesc; + rasterDesc.FillMode = D3D11_FILL_SOLID; + rasterDesc.CullMode = D3D11_CULL_NONE; + rasterDesc.FrontCounterClockwise = FALSE; + rasterDesc.DepthBias = 0; + rasterDesc.SlopeScaledDepthBias = 0.0f; + rasterDesc.DepthBiasClamp = 0.0f; + rasterDesc.DepthClipEnable = TRUE; + rasterDesc.ScissorEnable = FALSE; + rasterDesc.MultisampleEnable = FALSE; + rasterDesc.AntialiasedLineEnable = FALSE; + + result = device->CreateRasterizerState(&rasterDesc, &mCopyRasterizerState); + ASSERT(SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal pixel transfer rasterizer state, result: 0x%X.", result); + } + + D3D11_DEPTH_STENCIL_DESC depthStencilDesc; + depthStencilDesc.DepthEnable = true; + depthStencilDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL; + depthStencilDesc.DepthFunc = D3D11_COMPARISON_ALWAYS; + depthStencilDesc.StencilEnable = FALSE; + depthStencilDesc.StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK; + depthStencilDesc.StencilWriteMask = D3D11_DEFAULT_STENCIL_WRITE_MASK; + depthStencilDesc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP; + depthStencilDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP; + depthStencilDesc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP; + depthStencilDesc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS; + depthStencilDesc.BackFace.StencilFailOp = D3D11_STENCIL_OP_KEEP; + depthStencilDesc.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP; + depthStencilDesc.BackFace.StencilPassOp = D3D11_STENCIL_OP_KEEP; + depthStencilDesc.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS; + + result = device->CreateDepthStencilState(&depthStencilDesc, &mCopyDepthStencilState); + ASSERT(SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal pixel transfer depth stencil state, result: 0x%X.", result); + } + + D3D11_BUFFER_DESC constantBufferDesc = { 0 }; + constantBufferDesc.ByteWidth = roundUp(sizeof(CopyShaderParams), 32u); + constantBufferDesc.Usage = D3D11_USAGE_DYNAMIC; + constantBufferDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; + constantBufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + constantBufferDesc.MiscFlags = 0; + constantBufferDesc.StructureByteStride = 0; + + result = device->CreateBuffer(&constantBufferDesc, NULL, &mParamsConstantBuffer); + ASSERT(SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal pixel transfer constant buffer, result: 0x%X.", result); + } + d3d11::SetDebugName(mParamsConstantBuffer, "PixelTransfer11 constant buffer"); + + // init shaders + mBufferToTextureVS = d3d11::CompileVS(device, g_VS_BufferToTexture, "BufferToTexture VS"); + if (!mBufferToTextureVS) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal buffer to texture vertex shader."); + } + + mBufferToTextureGS = d3d11::CompileGS(device, g_GS_BufferToTexture, "BufferToTexture GS"); + if (!mBufferToTextureGS) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal buffer to texture geometry shader."); + } + + gl::Error error = buildShaderMap(); + if (error.isError()) + { + return error; + } + + StructZero(&mParamsData); + + mResourcesLoaded = true; + + return gl::Error(GL_NO_ERROR); +} + +void PixelTransfer11::setBufferToTextureCopyParams(const gl::Box &destArea, const gl::Extents &destSize, GLenum internalFormat, + const gl::PixelUnpackState &unpack, unsigned int offset, CopyShaderParams *parametersOut) +{ + StructZero(parametersOut); + + float texelCenterX = 0.5f / static_cast(destSize.width - 1); + float texelCenterY = 0.5f / static_cast(destSize.height - 1); + + unsigned int bytesPerPixel = gl::GetInternalFormatInfo(internalFormat).pixelBytes; + unsigned int alignmentBytes = static_cast(unpack.alignment); + unsigned int alignmentPixels = (alignmentBytes <= bytesPerPixel ? 1 : alignmentBytes / bytesPerPixel); + + parametersOut->FirstPixelOffset = offset / bytesPerPixel; + parametersOut->PixelsPerRow = static_cast((unpack.rowLength > 0) ? unpack.rowLength : destArea.width); + parametersOut->RowStride = roundUp(parametersOut->PixelsPerRow, alignmentPixels); + parametersOut->RowsPerSlice = static_cast(destArea.height); + parametersOut->PositionOffset[0] = texelCenterX + (destArea.x / float(destSize.width)) * 2.0f - 1.0f; + parametersOut->PositionOffset[1] = texelCenterY + ((destSize.height - destArea.y - 1) / float(destSize.height)) * 2.0f - 1.0f; + parametersOut->PositionScale[0] = 2.0f / static_cast(destSize.width); + parametersOut->PositionScale[1] = -2.0f / static_cast(destSize.height); + parametersOut->FirstSlice = destArea.z; +} + +gl::Error PixelTransfer11::copyBufferToTexture(const gl::PixelUnpackState &unpack, unsigned int offset, RenderTargetD3D *destRenderTarget, + GLenum destinationFormat, GLenum sourcePixelsType, const gl::Box &destArea) +{ + gl::Error error = loadResources(); + if (error.isError()) + { + return error; + } + + gl::Extents destSize = destRenderTarget->getExtents(); + + ASSERT(destArea.x >= 0 && destArea.x + destArea.width <= destSize.width && + destArea.y >= 0 && destArea.y + destArea.height <= destSize.height && + destArea.z >= 0 && destArea.z + destArea.depth <= destSize.depth ); + + const gl::Buffer &sourceBuffer = *unpack.pixelBuffer.get(); + + ASSERT(mRenderer->supportsFastCopyBufferToTexture(destinationFormat)); + + ID3D11PixelShader *pixelShader = findBufferToTexturePS(destinationFormat); + ASSERT(pixelShader); + + // The SRV must be in the proper read format, which may be different from the destination format + // EG: for half float data, we can load full precision floats with implicit conversion + GLenum unsizedFormat = gl::GetInternalFormatInfo(destinationFormat).format; + GLenum sourceFormat = gl::GetSizedInternalFormat(unsizedFormat, sourcePixelsType); + + const d3d11::TextureFormat &sourceFormatInfo = d3d11::GetTextureFormatInfo(sourceFormat, mRenderer->getFeatureLevel()); + DXGI_FORMAT srvFormat = sourceFormatInfo.srvFormat; + ASSERT(srvFormat != DXGI_FORMAT_UNKNOWN); + Buffer11 *bufferStorage11 = Buffer11::makeBuffer11(sourceBuffer.getImplementation()); + ID3D11ShaderResourceView *bufferSRV = bufferStorage11->getSRV(srvFormat); + ASSERT(bufferSRV != NULL); + + ID3D11RenderTargetView *textureRTV = RenderTarget11::makeRenderTarget11(destRenderTarget)->getRenderTargetView(); + ASSERT(textureRTV != NULL); + + CopyShaderParams shaderParams; + setBufferToTextureCopyParams(destArea, destSize, sourceFormat, unpack, offset, &shaderParams); + + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); + + ID3D11Buffer *nullBuffer = NULL; + UINT zero = 0; + + // Are we doing a 2D or 3D copy? + ID3D11GeometryShader *geometryShader = ((destSize.depth > 1) ? mBufferToTextureGS : NULL); + + deviceContext->VSSetShader(mBufferToTextureVS, NULL, 0); + deviceContext->GSSetShader(geometryShader, NULL, 0); + deviceContext->PSSetShader(pixelShader, NULL, 0); + mRenderer->setShaderResource(gl::SAMPLER_PIXEL, 0, bufferSRV); + deviceContext->IASetInputLayout(NULL); + deviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_POINTLIST); + + deviceContext->IASetVertexBuffers(0, 1, &nullBuffer, &zero, &zero); + deviceContext->OMSetBlendState(NULL, NULL, 0xFFFFFFF); + deviceContext->OMSetDepthStencilState(mCopyDepthStencilState, 0xFFFFFFFF); + deviceContext->RSSetState(mCopyRasterizerState); + + mRenderer->setOneTimeRenderTarget(textureRTV); + + if (!StructEquals(mParamsData, shaderParams)) + { + d3d11::SetBufferData(deviceContext, mParamsConstantBuffer, shaderParams); + mParamsData = shaderParams; + } + + deviceContext->VSSetConstantBuffers(0, 1, &mParamsConstantBuffer); + + // Set the viewport + D3D11_VIEWPORT viewport; + viewport.TopLeftX = 0; + viewport.TopLeftY = 0; + viewport.Width = destSize.width; + viewport.Height = destSize.height; + viewport.MinDepth = 0.0f; + viewport.MaxDepth = 1.0f; + deviceContext->RSSetViewports(1, &viewport); + + UINT numPixels = (destArea.width * destArea.height * destArea.depth); + deviceContext->Draw(numPixels, 0); + + // Unbind textures and render targets and vertex buffer + mRenderer->setShaderResource(gl::SAMPLER_PIXEL, 0, NULL); + deviceContext->VSSetConstantBuffers(0, 1, &nullBuffer); + + mRenderer->markAllStateDirty(); + + return gl::Error(GL_NO_ERROR); +} + +gl::Error PixelTransfer11::buildShaderMap() +{ + ID3D11Device *device = mRenderer->getDevice(); + + mBufferToTexturePSMap[GL_FLOAT] = d3d11::CompilePS(device, g_PS_BufferToTexture_4F, "BufferToTexture RGBA ps"); + mBufferToTexturePSMap[GL_INT] = d3d11::CompilePS(device, g_PS_BufferToTexture_4I, "BufferToTexture RGBA-I ps"); + mBufferToTexturePSMap[GL_UNSIGNED_INT] = d3d11::CompilePS(device, g_PS_BufferToTexture_4UI, "BufferToTexture RGBA-UI ps"); + + // Check that all the shaders were created successfully + for (auto shaderMapIt = mBufferToTexturePSMap.begin(); shaderMapIt != mBufferToTexturePSMap.end(); shaderMapIt++) + { + if (shaderMapIt->second == NULL) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal buffer to texture pixel shader."); + } + } + + return gl::Error(GL_NO_ERROR); +} + +ID3D11PixelShader *PixelTransfer11::findBufferToTexturePS(GLenum internalFormat) const +{ + GLenum componentType = gl::GetInternalFormatInfo(internalFormat).componentType; + if (componentType == GL_SIGNED_NORMALIZED || componentType == GL_UNSIGNED_NORMALIZED) + { + componentType = GL_FLOAT; + } + + auto shaderMapIt = mBufferToTexturePSMap.find(componentType); + return (shaderMapIt == mBufferToTexturePSMap.end() ? NULL : shaderMapIt->second); +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/PixelTransfer11.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/PixelTransfer11.h new file mode 100644 index 0000000000..1672121ec7 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/PixelTransfer11.h @@ -0,0 +1,89 @@ +// +// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// PixelTransfer11.h: +// Buffer-to-Texture and Texture-to-Buffer data transfers. +// Used to implement pixel unpack and pixel pack buffers in ES3. + +#ifndef LIBANGLE_RENDERER_D3D_D3D11_PIXELTRANSFER11_H_ +#define LIBANGLE_RENDERER_D3D_D3D11_PIXELTRANSFER11_H_ + +#include "libANGLE/Error.h" + +#include "common/platform.h" + +#include + +#include + +namespace gl +{ + +class Buffer; +struct Box; +struct Extents; +struct PixelUnpackState; + +} + +namespace rx +{ +class Renderer11; +class RenderTargetD3D; + +class PixelTransfer11 +{ + public: + explicit PixelTransfer11(Renderer11 *renderer); + ~PixelTransfer11(); + + // unpack: the source buffer is stored in the unpack state, and buffer strides + // offset: the start of the data within the unpack buffer + // destRenderTarget: individual slice/layer of a target texture + // destinationFormat/sourcePixelsType: determines shaders + shader parameters + // destArea: the sub-section of destRenderTarget to copy to + gl::Error copyBufferToTexture(const gl::PixelUnpackState &unpack, unsigned int offset, RenderTargetD3D *destRenderTarget, + GLenum destinationFormat, GLenum sourcePixelsType, const gl::Box &destArea); + + private: + + struct CopyShaderParams + { + unsigned int FirstPixelOffset; + unsigned int PixelsPerRow; + unsigned int RowStride; + unsigned int RowsPerSlice; + float PositionOffset[2]; + float PositionScale[2]; + int TexLocationOffset[2]; + int TexLocationScale[2]; + unsigned int FirstSlice; + }; + + static void setBufferToTextureCopyParams(const gl::Box &destArea, const gl::Extents &destSize, GLenum internalFormat, + const gl::PixelUnpackState &unpack, unsigned int offset, CopyShaderParams *parametersOut); + + gl::Error loadResources(); + gl::Error buildShaderMap(); + ID3D11PixelShader *findBufferToTexturePS(GLenum internalFormat) const; + + Renderer11 *mRenderer; + + bool mResourcesLoaded; + std::map mBufferToTexturePSMap; + ID3D11VertexShader *mBufferToTextureVS; + ID3D11GeometryShader *mBufferToTextureGS; + ID3D11Buffer *mParamsConstantBuffer; + CopyShaderParams mParamsData; + + ID3D11RasterizerState *mCopyRasterizerState; + ID3D11DepthStencilState *mCopyDepthStencilState; + +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_D3D11_PIXELTRANSFER11_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Query11.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Query11.cpp new file mode 100644 index 0000000000..4979ff51a9 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Query11.cpp @@ -0,0 +1,164 @@ +// +// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Query11.cpp: Defines the rx::Query11 class which implements rx::QueryImpl. + +#include "libANGLE/renderer/d3d/d3d11/Query11.h" +#include "libANGLE/renderer/d3d/d3d11/Renderer11.h" +#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h" +#include "common/utilities.h" + +#include + +#if defined(ANGLE_MINGW32_COMPAT) +typedef struct D3D11_QUERY_DATA_SO_STATISTICS { + UINT64 NumPrimitivesWritten; + UINT64 PrimitivesStorageNeeded; +} D3D11_QUERY_DATA_SO_STATISTICS; +#endif + +namespace rx +{ + +Query11::Query11(Renderer11 *renderer, GLenum type) + : QueryImpl(type), + mResult(0), + mQueryFinished(false), + mRenderer(renderer), + mQuery(NULL) +{ +} + +Query11::~Query11() +{ + SafeRelease(mQuery); +} + +gl::Error Query11::begin() +{ + if (mQuery == NULL) + { + D3D11_QUERY_DESC queryDesc; + queryDesc.Query = gl_d3d11::ConvertQueryType(getType()); + queryDesc.MiscFlags = 0; + + HRESULT result = mRenderer->getDevice()->CreateQuery(&queryDesc, &mQuery); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Internal query creation failed, result: 0x%X.", result); + } + } + + mRenderer->getDeviceContext()->Begin(mQuery); + return gl::Error(GL_NO_ERROR); +} + +gl::Error Query11::end() +{ + ASSERT(mQuery); + mRenderer->getDeviceContext()->End(mQuery); + + mQueryFinished = false; + mResult = GL_FALSE; + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Query11::getResult(GLuint *params) +{ + while (!mQueryFinished) + { + gl::Error error = testQuery(); + if (error.isError()) + { + return error; + } + + if (!mQueryFinished) + { + ScheduleYield(); + } + } + + ASSERT(mQueryFinished); + *params = mResult; + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Query11::isResultAvailable(GLuint *available) +{ + gl::Error error = testQuery(); + if (error.isError()) + { + return error; + } + + *available = (mQueryFinished ? GL_TRUE : GL_FALSE); + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Query11::testQuery() +{ + if (!mQueryFinished) + { + ASSERT(mQuery); + + ID3D11DeviceContext *context = mRenderer->getDeviceContext(); + switch (getType()) + { + case GL_ANY_SAMPLES_PASSED_EXT: + case GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT: + { + UINT64 numPixels = 0; + HRESULT result = context->GetData(mQuery, &numPixels, sizeof(numPixels), 0); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to get the data of an internal query, result: 0x%X.", result); + } + + if (result == S_OK) + { + mQueryFinished = true; + mResult = (numPixels > 0) ? GL_TRUE : GL_FALSE; + } + } + break; + + case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN: + { + D3D11_QUERY_DATA_SO_STATISTICS soStats = { 0 }; + HRESULT result = context->GetData(mQuery, &soStats, sizeof(soStats), 0); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to get the data of an internal query, result: 0x%X.", result); + } + + if (result == S_OK) + { + mQueryFinished = true; + mResult = static_cast(soStats.NumPrimitivesWritten); + } + } + break; + + default: + UNREACHABLE(); + break; + } + + if (!mQueryFinished && mRenderer->testDeviceLost()) + { + mRenderer->notifyDeviceLost(); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to test get query result, device is lost."); + } + } + + return gl::Error(GL_NO_ERROR); +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Query11.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Query11.h new file mode 100644 index 0000000000..bd53fed250 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Query11.h @@ -0,0 +1,42 @@ +// +// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Query11.h: Defines the rx::Query11 class which implements rx::QueryImpl. + +#ifndef LIBANGLE_RENDERER_D3D_D3D11_QUERY11_H_ +#define LIBANGLE_RENDERER_D3D_D3D11_QUERY11_H_ + +#include "libANGLE/renderer/QueryImpl.h" + +namespace rx +{ +class Renderer11; + +class Query11 : public QueryImpl +{ + public: + Query11(Renderer11 *renderer, GLenum type); + virtual ~Query11(); + + virtual gl::Error begin(); + virtual gl::Error end(); + virtual gl::Error getResult(GLuint *params); + virtual gl::Error isResultAvailable(GLuint *available); + + private: + gl::Error testQuery(); + + GLuint mResult; + + bool mQueryFinished; + + Renderer11 *mRenderer; + ID3D11Query *mQuery; +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_D3D11_QUERY11_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/RenderStateCache.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/RenderStateCache.cpp new file mode 100644 index 0000000000..4990e6bc6e --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/RenderStateCache.cpp @@ -0,0 +1,452 @@ +// +// Copyright (c) 2012-2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// RenderStateCache.cpp: Defines rx::RenderStateCache, a cache of Direct3D render +// state objects. + +#include "libANGLE/renderer/d3d/d3d11/RenderStateCache.h" + +#include + +#include "common/debug.h" +#include "libANGLE/Framebuffer.h" +#include "libANGLE/FramebufferAttachment.h" +#include "libANGLE/renderer/d3d/FramebufferD3D.h" +#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h" +#include "libANGLE/renderer/d3d/d3d11/Renderer11.h" +#include "third_party/murmurhash/MurmurHash3.h" + +namespace rx +{ + +template +static void ClearStateMap(mapType &map) +{ + for (typename mapType::iterator i = map.begin(); i != map.end(); i++) + { + SafeRelease(i->second.first); + } + map.clear(); +} + +// MSDN's documentation of ID3D11Device::CreateBlendState, ID3D11Device::CreateRasterizerState, +// ID3D11Device::CreateDepthStencilState and ID3D11Device::CreateSamplerState claims the maximum +// number of unique states of each type an application can create is 4096 +const unsigned int RenderStateCache::kMaxBlendStates = 4096; +const unsigned int RenderStateCache::kMaxRasterizerStates = 4096; +const unsigned int RenderStateCache::kMaxDepthStencilStates = 4096; +const unsigned int RenderStateCache::kMaxSamplerStates = 4096; + +RenderStateCache::RenderStateCache(Renderer11 *renderer) + : mRenderer(renderer), + mDevice(NULL), + mCounter(0), + mBlendStateCache(kMaxBlendStates, hashBlendState, compareBlendStates), + mRasterizerStateCache(kMaxRasterizerStates, hashRasterizerState, compareRasterizerStates), + mDepthStencilStateCache(kMaxDepthStencilStates, hashDepthStencilState, compareDepthStencilStates), + mSamplerStateCache(kMaxSamplerStates, hashSamplerState, compareSamplerStates) +{ +} + +RenderStateCache::~RenderStateCache() +{ + clear(); +} + +void RenderStateCache::initialize(ID3D11Device *device) +{ + clear(); + mDevice = device; +} + +void RenderStateCache::clear() +{ + ClearStateMap(mBlendStateCache); + ClearStateMap(mRasterizerStateCache); + ClearStateMap(mDepthStencilStateCache); + ClearStateMap(mSamplerStateCache); +} + +std::size_t RenderStateCache::hashBlendState(const BlendStateKey &blendState) +{ + static const unsigned int seed = 0xABCDEF98; + + std::size_t hash = 0; + MurmurHash3_x86_32(&blendState, sizeof(gl::BlendState), seed, &hash); + return hash; +} + +bool RenderStateCache::compareBlendStates(const BlendStateKey &a, const BlendStateKey &b) +{ + return memcmp(&a, &b, sizeof(BlendStateKey)) == 0; +} + +gl::Error RenderStateCache::getBlendState(const gl::Framebuffer *framebuffer, const gl::BlendState &blendState, + ID3D11BlendState **outBlendState) +{ + if (!mDevice) + { + return gl::Error(GL_OUT_OF_MEMORY, "Internal error, RenderStateCache is not initialized."); + } + + bool mrt = false; + + const FramebufferD3D *framebufferD3D = GetImplAs(framebuffer); + const gl::AttachmentList &colorbuffers = framebufferD3D->getColorAttachmentsForRender(mRenderer->getWorkarounds()); + + BlendStateKey key = { 0 }; + key.blendState = blendState; + for (size_t colorAttachment = 0; colorAttachment < colorbuffers.size(); ++colorAttachment) + { + const gl::FramebufferAttachment *attachment = colorbuffers[colorAttachment]; + + auto rtChannels = key.rtChannels[colorAttachment]; + + if (attachment) + { + if (colorAttachment > 0) + { + mrt = true; + } + + rtChannels[0] = attachment->getRedSize() > 0; + rtChannels[1] = attachment->getGreenSize() > 0; + rtChannels[2] = attachment->getBlueSize() > 0; + rtChannels[3] = attachment->getAlphaSize() > 0; + } + } + + BlendStateMap::iterator keyIter = mBlendStateCache.find(key); + if (keyIter != mBlendStateCache.end()) + { + BlendStateCounterPair &state = keyIter->second; + state.second = mCounter++; + *outBlendState = state.first; + return gl::Error(GL_NO_ERROR); + } + else + { + if (mBlendStateCache.size() >= kMaxBlendStates) + { + TRACE("Overflowed the limit of %u blend states, removing the least recently used " + "to make room.", kMaxBlendStates); + + BlendStateMap::iterator leastRecentlyUsed = mBlendStateCache.begin(); + for (BlendStateMap::iterator i = mBlendStateCache.begin(); i != mBlendStateCache.end(); i++) + { + if (i->second.second < leastRecentlyUsed->second.second) + { + leastRecentlyUsed = i; + } + } + SafeRelease(leastRecentlyUsed->second.first); + mBlendStateCache.erase(leastRecentlyUsed); + } + + // Create a new blend state and insert it into the cache + D3D11_BLEND_DESC blendDesc = { 0 }; + blendDesc.AlphaToCoverageEnable = blendState.sampleAlphaToCoverage; + blendDesc.IndependentBlendEnable = mrt ? TRUE : FALSE; + + for (unsigned int i = 0; i < D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; i++) + { + D3D11_RENDER_TARGET_BLEND_DESC &rtBlend = blendDesc.RenderTarget[i]; + + rtBlend.BlendEnable = blendState.blend; + if (blendState.blend) + { + rtBlend.SrcBlend = gl_d3d11::ConvertBlendFunc(blendState.sourceBlendRGB, false); + rtBlend.DestBlend = gl_d3d11::ConvertBlendFunc(blendState.destBlendRGB, false); + rtBlend.BlendOp = gl_d3d11::ConvertBlendOp(blendState.blendEquationRGB); + + rtBlend.SrcBlendAlpha = gl_d3d11::ConvertBlendFunc(blendState.sourceBlendAlpha, true); + rtBlend.DestBlendAlpha = gl_d3d11::ConvertBlendFunc(blendState.destBlendAlpha, true); + rtBlend.BlendOpAlpha = gl_d3d11::ConvertBlendOp(blendState.blendEquationAlpha); + } + + rtBlend.RenderTargetWriteMask = gl_d3d11::ConvertColorMask(key.rtChannels[i][0] && blendState.colorMaskRed, + key.rtChannels[i][1] && blendState.colorMaskGreen, + key.rtChannels[i][2] && blendState.colorMaskBlue, + key.rtChannels[i][3] && blendState.colorMaskAlpha); + } + + ID3D11BlendState *dx11BlendState = NULL; + HRESULT result = mDevice->CreateBlendState(&blendDesc, &dx11BlendState); + if (FAILED(result) || !dx11BlendState) + { + return gl::Error(GL_OUT_OF_MEMORY, "Unable to create a ID3D11BlendState, HRESULT: 0x%X.", result); + } + + mBlendStateCache.insert(std::make_pair(key, std::make_pair(dx11BlendState, mCounter++))); + + *outBlendState = dx11BlendState; + return gl::Error(GL_NO_ERROR); + } +} + +std::size_t RenderStateCache::hashRasterizerState(const RasterizerStateKey &rasterState) +{ + static const unsigned int seed = 0xABCDEF98; + + std::size_t hash = 0; + MurmurHash3_x86_32(&rasterState, sizeof(RasterizerStateKey), seed, &hash); + return hash; +} + +bool RenderStateCache::compareRasterizerStates(const RasterizerStateKey &a, const RasterizerStateKey &b) +{ + return memcmp(&a, &b, sizeof(RasterizerStateKey)) == 0; +} + +gl::Error RenderStateCache::getRasterizerState(const gl::RasterizerState &rasterState, bool scissorEnabled, + ID3D11RasterizerState **outRasterizerState) +{ + if (!mDevice) + { + return gl::Error(GL_OUT_OF_MEMORY, "Internal error, RenderStateCache is not initialized."); + } + + RasterizerStateKey key = { 0 }; + key.rasterizerState = rasterState; + key.scissorEnabled = scissorEnabled; + + RasterizerStateMap::iterator keyIter = mRasterizerStateCache.find(key); + if (keyIter != mRasterizerStateCache.end()) + { + RasterizerStateCounterPair &state = keyIter->second; + state.second = mCounter++; + *outRasterizerState = state.first; + return gl::Error(GL_NO_ERROR); + } + else + { + if (mRasterizerStateCache.size() >= kMaxRasterizerStates) + { + TRACE("Overflowed the limit of %u rasterizer states, removing the least recently used " + "to make room.", kMaxRasterizerStates); + + RasterizerStateMap::iterator leastRecentlyUsed = mRasterizerStateCache.begin(); + for (RasterizerStateMap::iterator i = mRasterizerStateCache.begin(); i != mRasterizerStateCache.end(); i++) + { + if (i->second.second < leastRecentlyUsed->second.second) + { + leastRecentlyUsed = i; + } + } + SafeRelease(leastRecentlyUsed->second.first); + mRasterizerStateCache.erase(leastRecentlyUsed); + } + + D3D11_CULL_MODE cullMode = gl_d3d11::ConvertCullMode(rasterState.cullFace, rasterState.cullMode); + + // Disable culling if drawing points + if (rasterState.pointDrawMode) + { + cullMode = D3D11_CULL_NONE; + } + + D3D11_RASTERIZER_DESC rasterDesc; + rasterDesc.FillMode = D3D11_FILL_SOLID; + rasterDesc.CullMode = cullMode; + rasterDesc.FrontCounterClockwise = (rasterState.frontFace == GL_CCW) ? FALSE: TRUE; + rasterDesc.DepthBiasClamp = 0.0f; // MSDN documentation of DepthBiasClamp implies a value of zero will preform no clamping, must be tested though. + rasterDesc.DepthClipEnable = TRUE; + rasterDesc.ScissorEnable = scissorEnabled ? TRUE : FALSE; + rasterDesc.MultisampleEnable = rasterState.multiSample; + rasterDesc.AntialiasedLineEnable = FALSE; + + if (rasterState.polygonOffsetFill) + { + rasterDesc.SlopeScaledDepthBias = rasterState.polygonOffsetFactor; + rasterDesc.DepthBias = (INT)rasterState.polygonOffsetUnits; + } + else + { + rasterDesc.SlopeScaledDepthBias = 0.0f; + rasterDesc.DepthBias = 0; + } + + ID3D11RasterizerState *dx11RasterizerState = NULL; + HRESULT result = mDevice->CreateRasterizerState(&rasterDesc, &dx11RasterizerState); + if (FAILED(result) || !dx11RasterizerState) + { + return gl::Error(GL_OUT_OF_MEMORY, "Unable to create a ID3D11RasterizerState, HRESULT: 0x%X.", result); + } + + mRasterizerStateCache.insert(std::make_pair(key, std::make_pair(dx11RasterizerState, mCounter++))); + + *outRasterizerState = dx11RasterizerState; + return gl::Error(GL_NO_ERROR); + } +} + +std::size_t RenderStateCache::hashDepthStencilState(const gl::DepthStencilState &dsState) +{ + static const unsigned int seed = 0xABCDEF98; + + std::size_t hash = 0; + MurmurHash3_x86_32(&dsState, sizeof(gl::DepthStencilState), seed, &hash); + return hash; +} + +bool RenderStateCache::compareDepthStencilStates(const gl::DepthStencilState &a, const gl::DepthStencilState &b) +{ + return memcmp(&a, &b, sizeof(gl::DepthStencilState)) == 0; +} + +gl::Error RenderStateCache::getDepthStencilState(const gl::DepthStencilState &dsState, ID3D11DepthStencilState **outDSState) +{ + if (!mDevice) + { + return gl::Error(GL_OUT_OF_MEMORY, "Internal error, RenderStateCache is not initialized."); + } + + DepthStencilStateMap::iterator keyIter = mDepthStencilStateCache.find(dsState); + if (keyIter != mDepthStencilStateCache.end()) + { + DepthStencilStateCounterPair &state = keyIter->second; + state.second = mCounter++; + *outDSState = state.first; + return gl::Error(GL_NO_ERROR); + } + else + { + if (mDepthStencilStateCache.size() >= kMaxDepthStencilStates) + { + TRACE("Overflowed the limit of %u depth stencil states, removing the least recently used " + "to make room.", kMaxDepthStencilStates); + + DepthStencilStateMap::iterator leastRecentlyUsed = mDepthStencilStateCache.begin(); + for (DepthStencilStateMap::iterator i = mDepthStencilStateCache.begin(); i != mDepthStencilStateCache.end(); i++) + { + if (i->second.second < leastRecentlyUsed->second.second) + { + leastRecentlyUsed = i; + } + } + SafeRelease(leastRecentlyUsed->second.first); + mDepthStencilStateCache.erase(leastRecentlyUsed); + } + + D3D11_DEPTH_STENCIL_DESC dsDesc = { 0 }; + dsDesc.DepthEnable = dsState.depthTest ? TRUE : FALSE; + dsDesc.DepthWriteMask = gl_d3d11::ConvertDepthMask(dsState.depthMask); + dsDesc.DepthFunc = gl_d3d11::ConvertComparison(dsState.depthFunc); + dsDesc.StencilEnable = dsState.stencilTest ? TRUE : FALSE; + dsDesc.StencilReadMask = gl_d3d11::ConvertStencilMask(dsState.stencilMask); + dsDesc.StencilWriteMask = gl_d3d11::ConvertStencilMask(dsState.stencilWritemask); + dsDesc.FrontFace.StencilFailOp = gl_d3d11::ConvertStencilOp(dsState.stencilFail); + dsDesc.FrontFace.StencilDepthFailOp = gl_d3d11::ConvertStencilOp(dsState.stencilPassDepthFail); + dsDesc.FrontFace.StencilPassOp = gl_d3d11::ConvertStencilOp(dsState.stencilPassDepthPass); + dsDesc.FrontFace.StencilFunc = gl_d3d11::ConvertComparison(dsState.stencilFunc); + dsDesc.BackFace.StencilFailOp = gl_d3d11::ConvertStencilOp(dsState.stencilBackFail); + dsDesc.BackFace.StencilDepthFailOp = gl_d3d11::ConvertStencilOp(dsState.stencilBackPassDepthFail); + dsDesc.BackFace.StencilPassOp = gl_d3d11::ConvertStencilOp(dsState.stencilBackPassDepthPass); + dsDesc.BackFace.StencilFunc = gl_d3d11::ConvertComparison(dsState.stencilBackFunc); + + ID3D11DepthStencilState *dx11DepthStencilState = NULL; + HRESULT result = mDevice->CreateDepthStencilState(&dsDesc, &dx11DepthStencilState); + if (FAILED(result) || !dx11DepthStencilState) + { + return gl::Error(GL_OUT_OF_MEMORY, "Unable to create a ID3D11DepthStencilState, HRESULT: 0x%X.", result); + } + + mDepthStencilStateCache.insert(std::make_pair(dsState, std::make_pair(dx11DepthStencilState, mCounter++))); + + *outDSState = dx11DepthStencilState; + return gl::Error(GL_NO_ERROR); + } +} + +std::size_t RenderStateCache::hashSamplerState(const gl::SamplerState &samplerState) +{ + static const unsigned int seed = 0xABCDEF98; + + std::size_t hash = 0; + MurmurHash3_x86_32(&samplerState, sizeof(gl::SamplerState), seed, &hash); + return hash; +} + +bool RenderStateCache::compareSamplerStates(const gl::SamplerState &a, const gl::SamplerState &b) +{ + return memcmp(&a, &b, sizeof(gl::SamplerState)) == 0; +} + +gl::Error RenderStateCache::getSamplerState(const gl::SamplerState &samplerState, ID3D11SamplerState **outSamplerState) +{ + if (!mDevice) + { + return gl::Error(GL_OUT_OF_MEMORY, "Internal error, RenderStateCache is not initialized."); + } + + SamplerStateMap::iterator keyIter = mSamplerStateCache.find(samplerState); + if (keyIter != mSamplerStateCache.end()) + { + SamplerStateCounterPair &state = keyIter->second; + state.second = mCounter++; + *outSamplerState = state.first; + return gl::Error(GL_NO_ERROR); + } + else + { + if (mSamplerStateCache.size() >= kMaxSamplerStates) + { + TRACE("Overflowed the limit of %u sampler states, removing the least recently used " + "to make room.", kMaxSamplerStates); + + SamplerStateMap::iterator leastRecentlyUsed = mSamplerStateCache.begin(); + for (SamplerStateMap::iterator i = mSamplerStateCache.begin(); i != mSamplerStateCache.end(); i++) + { + if (i->second.second < leastRecentlyUsed->second.second) + { + leastRecentlyUsed = i; + } + } + SafeRelease(leastRecentlyUsed->second.first); + mSamplerStateCache.erase(leastRecentlyUsed); + } + + D3D11_SAMPLER_DESC samplerDesc; + samplerDesc.Filter = gl_d3d11::ConvertFilter(samplerState.minFilter, samplerState.magFilter, + samplerState.maxAnisotropy, samplerState.compareMode); + samplerDesc.AddressU = gl_d3d11::ConvertTextureWrap(samplerState.wrapS); + samplerDesc.AddressV = gl_d3d11::ConvertTextureWrap(samplerState.wrapT); + samplerDesc.AddressW = gl_d3d11::ConvertTextureWrap(samplerState.wrapR); + samplerDesc.MipLODBias = 0; + samplerDesc.MaxAnisotropy = samplerState.maxAnisotropy; + samplerDesc.ComparisonFunc = gl_d3d11::ConvertComparison(samplerState.compareFunc); + samplerDesc.BorderColor[0] = 0.0f; + samplerDesc.BorderColor[1] = 0.0f; + samplerDesc.BorderColor[2] = 0.0f; + samplerDesc.BorderColor[3] = 0.0f; + samplerDesc.MinLOD = samplerState.minLod; + samplerDesc.MaxLOD = samplerState.maxLod; + + if (mRenderer->getFeatureLevel() <= D3D_FEATURE_LEVEL_9_3) + { + // Check that maxLOD is nearly FLT_MAX (1000.0f is the default), since 9_3 doesn't support anything other than FLT_MAX. + // Note that Feature Level 9_* only supports GL ES 2.0, so the consumer of ANGLE can't modify the Max LOD themselves. + ASSERT(samplerState.maxLod >= 999.9f); + + // Now just set MaxLOD to FLT_MAX. Other parts of the renderer (e.g. the non-zero max LOD workaround) should take account of this. + samplerDesc.MaxLOD = FLT_MAX; + } + + ID3D11SamplerState *dx11SamplerState = NULL; + HRESULT result = mDevice->CreateSamplerState(&samplerDesc, &dx11SamplerState); + if (FAILED(result) || !dx11SamplerState) + { + return gl::Error(GL_OUT_OF_MEMORY, "Unable to create a ID3D11SamplerState, HRESULT: 0x%X.", result); + } + + mSamplerStateCache.insert(std::make_pair(samplerState, std::make_pair(dx11SamplerState, mCounter++))); + + *outSamplerState = dx11SamplerState; + return gl::Error(GL_NO_ERROR); + } +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/RenderStateCache.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/RenderStateCache.h new file mode 100644 index 0000000000..0099b94a04 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/RenderStateCache.h @@ -0,0 +1,111 @@ +// +// Copyright (c) 2012-2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// RenderStateCache.h: Defines rx::RenderStateCache, a cache of Direct3D render +// state objects. + +#ifndef LIBANGLE_RENDERER_D3D_D3D11_RENDERSTATECACHE_H_ +#define LIBANGLE_RENDERER_D3D_D3D11_RENDERSTATECACHE_H_ + +#include "libANGLE/angletypes.h" +#include "libANGLE/Error.h" +#include "common/angleutils.h" + +#include + +namespace gl +{ +class Framebuffer; +} + +namespace rx +{ +class Renderer11; + +class RenderStateCache : angle::NonCopyable +{ + public: + RenderStateCache(Renderer11 *renderer); + virtual ~RenderStateCache(); + + void initialize(ID3D11Device *device); + void clear(); + + gl::Error getBlendState(const gl::Framebuffer *framebuffer, const gl::BlendState &blendState, ID3D11BlendState **outBlendState); + gl::Error getRasterizerState(const gl::RasterizerState &rasterState, bool scissorEnabled, ID3D11RasterizerState **outRasterizerState); + gl::Error getDepthStencilState(const gl::DepthStencilState &dsState, ID3D11DepthStencilState **outDSState); + gl::Error getSamplerState(const gl::SamplerState &samplerState, ID3D11SamplerState **outSamplerState); + + private: + Renderer11 *mRenderer; + unsigned long long mCounter; + + // Blend state cache + struct BlendStateKey + { + gl::BlendState blendState; + bool rtChannels[D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT][4]; + }; + static std::size_t hashBlendState(const BlendStateKey &blendState); + static bool compareBlendStates(const BlendStateKey &a, const BlendStateKey &b); + static const unsigned int kMaxBlendStates; + + typedef std::size_t (*BlendStateHashFunction)(const BlendStateKey &); + typedef bool (*BlendStateEqualityFunction)(const BlendStateKey &, const BlendStateKey &); + typedef std::pair BlendStateCounterPair; + typedef std::unordered_map BlendStateMap; + BlendStateMap mBlendStateCache; + + // Rasterizer state cache + struct RasterizerStateKey + { + gl::RasterizerState rasterizerState; + bool scissorEnabled; + }; + static std::size_t hashRasterizerState(const RasterizerStateKey &rasterState); + static bool compareRasterizerStates(const RasterizerStateKey &a, const RasterizerStateKey &b); + static const unsigned int kMaxRasterizerStates; + + typedef std::size_t (*RasterizerStateHashFunction)(const RasterizerStateKey &); + typedef bool (*RasterizerStateEqualityFunction)(const RasterizerStateKey &, const RasterizerStateKey &); + typedef std::pair RasterizerStateCounterPair; + typedef std::unordered_map RasterizerStateMap; + RasterizerStateMap mRasterizerStateCache; + + // Depth stencil state cache + static std::size_t hashDepthStencilState(const gl::DepthStencilState &dsState); + static bool compareDepthStencilStates(const gl::DepthStencilState &a, const gl::DepthStencilState &b); + static const unsigned int kMaxDepthStencilStates; + + typedef std::size_t (*DepthStencilStateHashFunction)(const gl::DepthStencilState &); + typedef bool (*DepthStencilStateEqualityFunction)(const gl::DepthStencilState &, const gl::DepthStencilState &); + typedef std::pair DepthStencilStateCounterPair; + typedef std::unordered_map DepthStencilStateMap; + DepthStencilStateMap mDepthStencilStateCache; + + // Sample state cache + static std::size_t hashSamplerState(const gl::SamplerState &samplerState); + static bool compareSamplerStates(const gl::SamplerState &a, const gl::SamplerState &b); + static const unsigned int kMaxSamplerStates; + + typedef std::size_t (*SamplerStateHashFunction)(const gl::SamplerState &); + typedef bool (*SamplerStateEqualityFunction)(const gl::SamplerState &, const gl::SamplerState &); + typedef std::pair SamplerStateCounterPair; + typedef std::unordered_map SamplerStateMap; + SamplerStateMap mSamplerStateCache; + + ID3D11Device *mDevice; +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_D3D11_RENDERSTATECACHE_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/RenderTarget11.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/RenderTarget11.cpp new file mode 100644 index 0000000000..ecd9e13c90 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/RenderTarget11.cpp @@ -0,0 +1,394 @@ +// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// RenderTarget11.cpp: Implements a DX11-specific wrapper for ID3D11View pointers +// retained by Renderbuffers. + +#include "libANGLE/renderer/d3d/d3d11/RenderTarget11.h" +#include "libANGLE/renderer/d3d/d3d11/Renderer11.h" +#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h" +#include "libANGLE/renderer/d3d/d3d11/SwapChain11.h" +#include "libANGLE/renderer/d3d/d3d11/formatutils11.h" + +namespace rx +{ + +static bool getTextureProperties(ID3D11Resource *resource, unsigned int *mipLevels, unsigned int *samples) +{ + ID3D11Texture1D *texture1D = d3d11::DynamicCastComObject(resource); + if (texture1D) + { + D3D11_TEXTURE1D_DESC texDesc; + texture1D->GetDesc(&texDesc); + SafeRelease(texture1D); + + *mipLevels = texDesc.MipLevels; + *samples = 0; + + return true; + } + + ID3D11Texture2D *texture2D = d3d11::DynamicCastComObject(resource); + if (texture2D) + { + D3D11_TEXTURE2D_DESC texDesc; + texture2D->GetDesc(&texDesc); + SafeRelease(texture2D); + + *mipLevels = texDesc.MipLevels; + *samples = texDesc.SampleDesc.Count > 1 ? texDesc.SampleDesc.Count : 0; + + return true; + } + + ID3D11Texture3D *texture3D = d3d11::DynamicCastComObject(resource); + if (texture3D) + { + D3D11_TEXTURE3D_DESC texDesc; + texture3D->GetDesc(&texDesc); + SafeRelease(texture3D); + + *mipLevels = texDesc.MipLevels; + *samples = 0; + + return true; + } + + return false; +} + +static unsigned int getRTVSubresourceIndex(ID3D11Resource *resource, ID3D11RenderTargetView *view) +{ + D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; + view->GetDesc(&rtvDesc); + + unsigned int mipSlice = 0; + unsigned int arraySlice = 0; + + switch (rtvDesc.ViewDimension) + { + case D3D11_RTV_DIMENSION_TEXTURE1D: + mipSlice = rtvDesc.Texture1D.MipSlice; + arraySlice = 0; + break; + + case D3D11_RTV_DIMENSION_TEXTURE1DARRAY: + mipSlice = rtvDesc.Texture1DArray.MipSlice; + arraySlice = rtvDesc.Texture1DArray.FirstArraySlice; + break; + + case D3D11_RTV_DIMENSION_TEXTURE2D: + mipSlice = rtvDesc.Texture2D.MipSlice; + arraySlice = 0; + break; + + case D3D11_RTV_DIMENSION_TEXTURE2DARRAY: + mipSlice = rtvDesc.Texture2DArray.MipSlice; + arraySlice = rtvDesc.Texture2DArray.FirstArraySlice; + break; + + case D3D11_RTV_DIMENSION_TEXTURE2DMS: + mipSlice = 0; + arraySlice = 0; + break; + + case D3D11_RTV_DIMENSION_TEXTURE2DMSARRAY: + mipSlice = 0; + arraySlice = rtvDesc.Texture2DMSArray.FirstArraySlice; + break; + + case D3D11_RTV_DIMENSION_TEXTURE3D: + mipSlice = rtvDesc.Texture3D.MipSlice; + arraySlice = 0; + break; + + case D3D11_RTV_DIMENSION_UNKNOWN: + case D3D11_RTV_DIMENSION_BUFFER: + UNIMPLEMENTED(); + break; + + default: + UNREACHABLE(); + break; + } + + unsigned int mipLevels, samples; + getTextureProperties(resource, &mipLevels, &samples); + + return D3D11CalcSubresource(mipSlice, arraySlice, mipLevels); +} + +static unsigned int getDSVSubresourceIndex(ID3D11Resource *resource, ID3D11DepthStencilView *view) +{ + D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc; + view->GetDesc(&dsvDesc); + + unsigned int mipSlice = 0; + unsigned int arraySlice = 0; + + switch (dsvDesc.ViewDimension) + { + case D3D11_DSV_DIMENSION_TEXTURE1D: + mipSlice = dsvDesc.Texture1D.MipSlice; + arraySlice = 0; + break; + + case D3D11_DSV_DIMENSION_TEXTURE1DARRAY: + mipSlice = dsvDesc.Texture1DArray.MipSlice; + arraySlice = dsvDesc.Texture1DArray.FirstArraySlice; + break; + + case D3D11_DSV_DIMENSION_TEXTURE2D: + mipSlice = dsvDesc.Texture2D.MipSlice; + arraySlice = 0; + break; + + case D3D11_DSV_DIMENSION_TEXTURE2DARRAY: + mipSlice = dsvDesc.Texture2DArray.MipSlice; + arraySlice = dsvDesc.Texture2DArray.FirstArraySlice; + break; + + case D3D11_DSV_DIMENSION_TEXTURE2DMS: + mipSlice = 0; + arraySlice = 0; + break; + + case D3D11_DSV_DIMENSION_TEXTURE2DMSARRAY: + mipSlice = 0; + arraySlice = dsvDesc.Texture2DMSArray.FirstArraySlice; + break; + + case D3D11_DSV_DIMENSION_UNKNOWN: + UNIMPLEMENTED(); + break; + + default: + UNREACHABLE(); + break; + } + + unsigned int mipLevels, samples; + getTextureProperties(resource, &mipLevels, &samples); + + return D3D11CalcSubresource(mipSlice, arraySlice, mipLevels); +} + +RenderTarget11 *RenderTarget11::makeRenderTarget11(RenderTargetD3D *target) +{ + ASSERT(HAS_DYNAMIC_TYPE(RenderTarget11*, target)); + return static_cast(target); +} + +TextureRenderTarget11::TextureRenderTarget11(ID3D11RenderTargetView *rtv, ID3D11Resource *resource, ID3D11ShaderResourceView *srv, + GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLsizei samples) + : mWidth(width), + mHeight(height), + mDepth(depth), + mInternalFormat(internalFormat), + mDXGIFormat(DXGI_FORMAT_UNKNOWN), + mSamples(samples), + mSubresourceIndex(0), + mTexture(resource), + mRenderTarget(rtv), + mDepthStencil(NULL), + mShaderResource(srv) +{ + if (mTexture) + { + mTexture->AddRef(); + } + + if (mRenderTarget) + { + mRenderTarget->AddRef(); + } + + if (mShaderResource) + { + mShaderResource->AddRef(); + } + + if (mRenderTarget && mTexture) + { + mSubresourceIndex = getRTVSubresourceIndex(mTexture, mRenderTarget); + + D3D11_RENDER_TARGET_VIEW_DESC desc; + mRenderTarget->GetDesc(&desc); + mDXGIFormat = desc.Format; + } +} + +TextureRenderTarget11::TextureRenderTarget11(ID3D11DepthStencilView *dsv, ID3D11Resource *resource, ID3D11ShaderResourceView *srv, + GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLsizei samples) + : mWidth(width), + mHeight(height), + mDepth(depth), + mInternalFormat(internalFormat), + mDXGIFormat(DXGI_FORMAT_UNKNOWN), + mSamples(samples), + mSubresourceIndex(0), + mTexture(resource), + mRenderTarget(NULL), + mDepthStencil(dsv), + mShaderResource(srv) +{ + if (mTexture) + { + mTexture->AddRef(); + } + + if (mDepthStencil) + { + mDepthStencil->AddRef(); + } + + if (mShaderResource) + { + mShaderResource->AddRef(); + } + + if (mDepthStencil && mTexture) + { + mSubresourceIndex = getDSVSubresourceIndex(mTexture, mDepthStencil); + + D3D11_DEPTH_STENCIL_VIEW_DESC desc; + mDepthStencil->GetDesc(&desc); + mDXGIFormat = desc.Format; + } +} + +TextureRenderTarget11::~TextureRenderTarget11() +{ + SafeRelease(mTexture); + SafeRelease(mRenderTarget); + SafeRelease(mDepthStencil); + SafeRelease(mShaderResource); +} + +ID3D11Resource *TextureRenderTarget11::getTexture() const +{ + return mTexture; +} + +ID3D11RenderTargetView *TextureRenderTarget11::getRenderTargetView() const +{ + return mRenderTarget; +} + +ID3D11DepthStencilView *TextureRenderTarget11::getDepthStencilView() const +{ + return mDepthStencil; +} + +ID3D11ShaderResourceView *TextureRenderTarget11::getShaderResourceView() const +{ + return mShaderResource; +} + +GLsizei TextureRenderTarget11::getWidth() const +{ + return mWidth; +} + +GLsizei TextureRenderTarget11::getHeight() const +{ + return mHeight; +} + +GLsizei TextureRenderTarget11::getDepth() const +{ + return mDepth; +} + +GLenum TextureRenderTarget11::getInternalFormat() const +{ + return mInternalFormat; +} + +GLsizei TextureRenderTarget11::getSamples() const +{ + return mSamples; +} + +unsigned int TextureRenderTarget11::getSubresourceIndex() const +{ + return mSubresourceIndex; +} + +DXGI_FORMAT TextureRenderTarget11::getDXGIFormat() const +{ + return mDXGIFormat; +} + +SurfaceRenderTarget11::SurfaceRenderTarget11(SwapChain11 *swapChain, Renderer11 *renderer, bool depth) + : mSwapChain(swapChain), + mRenderer(renderer), + mDepth(depth) +{ + ASSERT(mSwapChain); +} + +SurfaceRenderTarget11::~SurfaceRenderTarget11() +{ +} + +GLsizei SurfaceRenderTarget11::getWidth() const +{ + return mSwapChain->getWidth(); +} + +GLsizei SurfaceRenderTarget11::getHeight() const +{ + return mSwapChain->getHeight(); +} + +GLsizei SurfaceRenderTarget11::getDepth() const +{ + return 1; +} + +GLenum SurfaceRenderTarget11::getInternalFormat() const +{ + return (mDepth ? mSwapChain->GetDepthBufferInternalFormat() : mSwapChain->GetBackBufferInternalFormat()); +} + +GLsizei SurfaceRenderTarget11::getSamples() const +{ + // Our EGL surfaces do not support multisampling. + return 0; +} + +ID3D11Resource *SurfaceRenderTarget11::getTexture() const +{ + return (mDepth ? mSwapChain->getDepthStencilTexture() : mSwapChain->getOffscreenTexture()); +} + +ID3D11RenderTargetView *SurfaceRenderTarget11::getRenderTargetView() const +{ + return (mDepth ? NULL : mSwapChain->getRenderTarget()); +} + +ID3D11DepthStencilView *SurfaceRenderTarget11::getDepthStencilView() const +{ + return (mDepth ? mSwapChain->getDepthStencil() : NULL); +} + +ID3D11ShaderResourceView *SurfaceRenderTarget11::getShaderResourceView() const +{ + return (mDepth ? mSwapChain->getDepthStencilShaderResource() : mSwapChain->getRenderTargetShaderResource()); +} + +unsigned int SurfaceRenderTarget11::getSubresourceIndex() const +{ + return 0; +} + +DXGI_FORMAT SurfaceRenderTarget11::getDXGIFormat() const +{ + return d3d11::GetTextureFormatInfo(getInternalFormat(), mRenderer->getFeatureLevel()).texFormat; +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/RenderTarget11.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/RenderTarget11.h new file mode 100644 index 0000000000..4472a56175 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/RenderTarget11.h @@ -0,0 +1,110 @@ +// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// RenderTarget11.h: Defines a DX11-specific wrapper for ID3D11View pointers +// retained by Renderbuffers. + +#ifndef LIBANGLE_RENDERER_D3D_D3D11_RENDERTARGET11_H_ +#define LIBANGLE_RENDERER_D3D_D3D11_RENDERTARGET11_H_ + +#include "libANGLE/renderer/d3d/RenderTargetD3D.h" + +namespace rx +{ +class SwapChain11; +class Renderer11; + +class RenderTarget11 : public RenderTargetD3D +{ + public: + RenderTarget11() { } + virtual ~RenderTarget11() { } + + static RenderTarget11 *makeRenderTarget11(RenderTargetD3D *renderTarget); + + virtual ID3D11Resource *getTexture() const = 0; + virtual ID3D11RenderTargetView *getRenderTargetView() const = 0; + virtual ID3D11DepthStencilView *getDepthStencilView() const = 0; + virtual ID3D11ShaderResourceView *getShaderResourceView() const = 0; + + virtual unsigned int getSubresourceIndex() const = 0; + + virtual DXGI_FORMAT getDXGIFormat() const = 0; + + private: + D3D_FEATURE_LEVEL mFeatureLevel; +}; + +class TextureRenderTarget11 : public RenderTarget11 +{ + public: + // TextureRenderTarget11 takes ownership of any D3D11 resources it is given and will AddRef them + TextureRenderTarget11(ID3D11RenderTargetView *rtv, ID3D11Resource *resource, ID3D11ShaderResourceView *srv, + GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLsizei samples); + TextureRenderTarget11(ID3D11DepthStencilView *dsv, ID3D11Resource *resource, ID3D11ShaderResourceView *srv, + GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLsizei samples); + virtual ~TextureRenderTarget11(); + + GLsizei getWidth() const override; + GLsizei getHeight() const override; + GLsizei getDepth() const override; + GLenum getInternalFormat() const override; + GLsizei getSamples() const override; + + ID3D11Resource *getTexture() const override; + ID3D11RenderTargetView *getRenderTargetView() const override; + ID3D11DepthStencilView *getDepthStencilView() const override; + ID3D11ShaderResourceView *getShaderResourceView() const override; + + unsigned int getSubresourceIndex() const override; + + DXGI_FORMAT getDXGIFormat() const override; + + private: + GLsizei mWidth; + GLsizei mHeight; + GLsizei mDepth; + GLenum mInternalFormat; + DXGI_FORMAT mDXGIFormat; + GLsizei mSamples; + + unsigned int mSubresourceIndex; + ID3D11Resource *mTexture; + ID3D11RenderTargetView *mRenderTarget; + ID3D11DepthStencilView *mDepthStencil; + ID3D11ShaderResourceView *mShaderResource; +}; + +class SurfaceRenderTarget11 : public RenderTarget11 +{ + public: + SurfaceRenderTarget11(SwapChain11 *swapChain, Renderer11 *renderer, bool depth); + virtual ~SurfaceRenderTarget11(); + + GLsizei getWidth() const override; + GLsizei getHeight() const override; + GLsizei getDepth() const override; + GLenum getInternalFormat() const override; + GLsizei getSamples() const override; + + ID3D11Resource *getTexture() const override; + ID3D11RenderTargetView *getRenderTargetView() const override; + ID3D11DepthStencilView *getDepthStencilView() const override; + ID3D11ShaderResourceView *getShaderResourceView() const override; + + unsigned int getSubresourceIndex() const override; + + DXGI_FORMAT getDXGIFormat() const override; + + private: + SwapChain11 *mSwapChain; + Renderer11 *mRenderer; + bool mDepth; +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_D3D11_RENDERTARGET11_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp new file mode 100644 index 0000000000..5291a3a086 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp @@ -0,0 +1,3585 @@ +// +// Copyright (c) 2012-2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Renderer11.cpp: Implements a back-end specific class for the D3D11 renderer. + +#include "libANGLE/renderer/d3d/d3d11/Renderer11.h" + +#include "common/utilities.h" +#include "common/tls.h" +#include "libANGLE/Buffer.h" +#include "libANGLE/Display.h" +#include "libANGLE/Framebuffer.h" +#include "libANGLE/FramebufferAttachment.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/Fence11.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/RenderTarget11.h" +#include "libANGLE/renderer/d3d/d3d11/ShaderExecutable11.h" +#include "libANGLE/renderer/d3d/d3d11/SwapChain11.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 +#include + +// 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. +#ifndef ANGLE_SKIP_DXGI_1_2_CHECK +#define ANGLE_SKIP_DXGI_1_2_CHECK 0 +#endif + +#ifdef _DEBUG +// this flag enables suppressing some spurious warnings that pop up in certain WebGL samples +// and conformance tests. to enable all warnings, remove this define. +#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 +{ + +namespace +{ + +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(-1); + +static bool ImageIndexConflictsWithSRV(const gl::ImageIndex *index, D3D11_SHADER_RESOURCE_VIEW_DESC desc) +{ + unsigned mipLevel = index->mipIndex; + unsigned layerIndex = index->layerIndex; + GLenum type = index->type; + + switch (desc.ViewDimension) + { + case D3D11_SRV_DIMENSION_TEXTURE2D: + { + unsigned maxSrvMip = desc.Texture2D.MipLevels + desc.Texture2D.MostDetailedMip; + maxSrvMip = (desc.Texture2D.MipLevels == -1) ? INT_MAX : maxSrvMip; + + unsigned mipMin = index->mipIndex; + unsigned mipMax = (layerIndex == -1) ? INT_MAX : layerIndex; + + return type == GL_TEXTURE_2D && RangeUI(mipMin, mipMax).intersects(RangeUI(desc.Texture2D.MostDetailedMip, maxSrvMip)); + } + + case D3D11_SRV_DIMENSION_TEXTURE2DARRAY: + { + unsigned maxSrvMip = desc.Texture2DArray.MipLevels + desc.Texture2DArray.MostDetailedMip; + maxSrvMip = (desc.Texture2DArray.MipLevels == -1) ? INT_MAX : maxSrvMip; + + unsigned maxSlice = desc.Texture2DArray.FirstArraySlice + desc.Texture2DArray.ArraySize; + + // 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; + } + + case D3D11_SRV_DIMENSION_TEXTURECUBE: + { + 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; + } + + case D3D11_SRV_DIMENSION_TEXTURE3D: + { + 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; + } + default: + // We only handle the cases corresponding to valid image indexes + UNIMPLEMENTED(); + } + + return false; +} + +// Does *not* increment the resource ref count!! +ID3D11Resource *GetViewResource(ID3D11View *view) +{ + ID3D11Resource *resource = NULL; + ASSERT(view); + view->GetResource(&resource); + resource->Release(); + return resource; +} + +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 = 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 = rx::roundUp(size, static_cast(256)) / 16; + + // 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 +} + +} + +Renderer11::Renderer11(egl::Display *display) + : RendererD3D(display), + mStateCache(this) +{ + // Initialize global annotator + gl::InitializeDebugAnnotations(&mAnnotator); + + mVertexDataManager = NULL; + mIndexDataManager = NULL; + + mLineLoopIB = NULL; + mTriangleFanIB = NULL; + + mBlit = NULL; + mPixelTransfer = NULL; + + mClear = NULL; + + mTrim = NULL; + + mSyncQuery = NULL; + + mSupportsConstantBufferOffsets = false; + + mD3d11Module = NULL; + mDxgiModule = NULL; + + mDevice = NULL; + mDeviceContext = NULL; + mDeviceContext1 = NULL; + mDxgiAdapter = NULL; + mDxgiFactory = NULL; + + mDriverConstantBufferVS = NULL; + mDriverConstantBufferPS = NULL; + + mAppliedVertexShader = NULL; + mAppliedGeometryShader = NULL; + mAppliedPixelShader = NULL; + + mAppliedNumXFBBindings = static_cast(-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); + + if (requestedMajorVersion == EGL_DONT_CARE || requestedMajorVersion >= 11) + { + if (requestedMinorVersion == EGL_DONT_CARE || requestedMinorVersion >= 0) + { + mAvailableFeatureLevels.push_back(D3D_FEATURE_LEVEL_11_0); + } + } + + if (requestedMajorVersion == EGL_DONT_CARE || requestedMajorVersion >= 10) + { + 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) +#else + if (requestedMajorVersion == 9 && requestedMinorVersion == 3) +#endif + { + mAvailableFeatureLevels.push_back(D3D_FEATURE_LEVEL_9_3); + } + + 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: + mDriverType = D3D_DRIVER_TYPE_WARP; + break; + + case EGL_PLATFORM_ANGLE_DEVICE_TYPE_REFERENCE_ANGLE: + mDriverType = D3D_DRIVER_TYPE_REFERENCE; + break; + + case EGL_PLATFORM_ANGLE_DEVICE_TYPE_NULL_ANGLE: + mDriverType = D3D_DRIVER_TYPE_NULL; + break; + + default: + UNREACHABLE(); + } +} + +Renderer11::~Renderer11() +{ + release(); + + gl::UninitializeDebugAnnotations(); +} + +Renderer11 *Renderer11::makeRenderer11(Renderer *renderer) +{ + ASSERT(HAS_DYNAMIC_TYPE(Renderer11*, renderer)); + return static_cast(renderer); +} + +#ifndef __d3d11_1_h__ +#define D3D11_MESSAGE_ID_DEVICE_DRAW_RENDERTARGETVIEW_NOT_SET ((D3D11_MESSAGE_ID)3146081) +#endif + +egl::Error Renderer11::initialize() +{ + if (!mCompiler.initialize()) + { + return egl::Error(EGL_NOT_INITIALIZED, + D3D11_INIT_COMPILER_ERROR, + "Failed to initialize compiler."); + } + +#if !defined(ANGLE_ENABLE_WINDOWS_STORE) + mDxgiModule = LoadLibrary(TEXT("dxgi.dll")); + mD3d11Module = LoadLibrary(TEXT("d3d11.dll")); + + if (mD3d11Module == NULL || mDxgiModule == NULL) + { + 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"); + + if (D3D11CreateDevice == NULL) + { + return egl::Error(EGL_NOT_INITIALIZED, + D3D11_INIT_MISSING_DEP, + "Could not retrieve D3D11CreateDevice address."); + } +#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)) +#endif + { + result = D3D11CreateDevice(NULL, + mDriverType, + NULL, + 0, + mAvailableFeatureLevels.data(), + mAvailableFeatureLevels.size(), + D3D11_SDK_VERSION, + &mDevice, + &mFeatureLevel, + &mDeviceContext); + + if (result == E_INVALIDARG) + { + // Cleanup done by destructor through glDestroyRenderer + return egl::Error(EGL_NOT_INITIALIZED, + D3D11_INIT_CREATEDEVICE_INVALIDARG, + "Could not create D3D11 device."); + } + + if (!mDevice || FAILED(result)) + { + // Cleanup done by destructor through glDestroyRenderer + return egl::Error(EGL_NOT_INITIALIZED, + D3D11_INIT_CREATEDEVICE_ERROR, + "Could not create D3D11 device."); + } + } + +#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; + } + + 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 + + // 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(mDeviceContext); +#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 query DXGI device."); + } + + result = dxgiDevice->GetParent(__uuidof(IDXGIAdapter), (void**)&mDxgiAdapter); + + if (FAILED(result)) + { + return egl::Error(EGL_NOT_INITIALIZED, + D3D11_INIT_OTHER_ERROR, + "Could not retrieve DXGI adapter"); + } + + SafeRelease(dxgiDevice); + +#if defined(ANGLE_ENABLE_D3D11_1) + IDXGIAdapter2 *dxgiAdapter2 = d3d11::DynamicCastComObject(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 (mFeatureLevel <= D3D_FEATURE_LEVEL_9_3 && dxgiAdapter2 != NULL) + { + DXGI_ADAPTER_DESC2 adapterDesc2 = {0}; + dxgiAdapter2->GetDesc2(&adapterDesc2); + + // 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); + } + + SafeRelease(dxgiAdapter2); +#endif + + memset(mDescription, 0, sizeof(mDescription)); + wcstombs(mDescription, mAdapterDescription.Description, sizeof(mDescription) - 1); + + result = mDxgiAdapter->GetParent(__uuidof(IDXGIFactory), (void**)&mDxgiFactory); + + if (!mDxgiFactory || FAILED(result)) + { + return egl::Error(EGL_NOT_INITIALIZED, + D3D11_INIT_OTHER_ERROR, + "Could not create DXGI factory."); + } + + // 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 (SUCCEEDED(result)) + { + D3D11_MESSAGE_ID hideMessages[] = + { + D3D11_MESSAGE_ID_DEVICE_DRAW_RENDERTARGETVIEW_NOT_SET + }; + + D3D11_INFO_QUEUE_FILTER filter = {0}; + filter.DenyList.NumIDs = ArraySize(hideMessages); + filter.DenyList.pIDList = hideMessages; + + infoQueue->AddStorageFilterEntries(&filter); + SafeRelease(infoQueue); + } +#endif + + initializeDevice(); + + return egl::Error(EGL_SUCCESS); +} + +// do any one-time device initialization +// NOTE: this is also needed after a device lost/reset +// to reset the scene status and ensure the default states are reset. +void Renderer11::initializeDevice() +{ + mStateCache.initialize(mDevice); + mInputLayoutCache.initialize(mDevice, mDeviceContext); + + ASSERT(!mVertexDataManager && !mIndexDataManager); + mVertexDataManager = new VertexDataManager(this); + mIndexDataManager = new IndexDataManager(this, getRendererClass()); + + ASSERT(!mBlit); + mBlit = new Blit11(this); + + ASSERT(!mClear); + mClear = new Clear11(this); + + const auto &attributes = mDisplay->getAttributeMap(); + // If automatic trim is enabled, DXGIDevice3::Trim( ) is called for the application + // automatically when an application is suspended by the OS. This feature is currently + // only supported for Windows Store applications. + EGLint enableAutoTrim = attributes.get(EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE, EGL_FALSE); + + if (enableAutoTrim == EGL_TRUE) + { + ASSERT(!mTrim); + mTrim = new Trim11(this); + } + + ASSERT(!mPixelTransfer); + mPixelTransfer = new PixelTransfer11(this); + + 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 + + mForceSetVertexSamplerStates.resize(rendererCaps.maxVertexTextureImageUnits); + mCurVertexSamplerStates.resize(rendererCaps.maxVertexTextureImageUnits); + + mForceSetPixelSamplerStates.resize(rendererCaps.maxTextureImageUnits); + mCurPixelSamplerStates.resize(rendererCaps.maxTextureImageUnits); + + mCurVertexSRVs.resize(rendererCaps.maxVertexTextureImageUnits); + mCurPixelSRVs.resize(rendererCaps.maxTextureImageUnits); + + markAllStateDirty(); +} + +egl::ConfigSet Renderer11::generateConfigs() const +{ + static const GLenum colorBufferFormats[] = + { + GL_BGRA8_EXT, + GL_RGBA8_OES, + }; + + static const GLenum depthStencilBufferFormats[] = + { + GL_NONE, + GL_DEPTH24_STENCIL8_OES, + GL_DEPTH_COMPONENT16, + }; + + const gl::Caps &rendererCaps = getRendererCaps(); + const gl::TextureCapsMap &rendererTextureCaps = getRendererTextureCaps(); + + egl::ConfigSet configs; + for (size_t formatIndex = 0; formatIndex < ArraySize(colorBufferFormats); formatIndex++) + { + GLenum colorBufferInternalFormat = colorBufferFormats[formatIndex]; + const gl::TextureCaps &colorBufferFormatCaps = rendererTextureCaps.get(colorBufferInternalFormat); + if (colorBufferFormatCaps.renderable) + { + for (size_t depthStencilIndex = 0; depthStencilIndex < ArraySize(depthStencilBufferFormats); depthStencilIndex++) + { + 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(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); + } + } + } + } + + ASSERT(configs.size() > 0); + return configs; +} + +gl::Error Renderer11::flush() +{ + mDeviceContext->Flush(); + return gl::Error(GL_NO_ERROR); +} + +gl::Error Renderer11::finish() +{ + HRESULT result; + + if (!mSyncQuery) + { + D3D11_QUERY_DESC queryDesc; + queryDesc.Query = D3D11_QUERY_EVENT; + queryDesc.MiscFlags = 0; + + result = mDevice->CreateQuery(&queryDesc, &mSyncQuery); + ASSERT(SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create event query, result: 0x%X.", result); + } + } + + mDeviceContext->End(mSyncQuery); + mDeviceContext->Flush(); + + do + { + result = mDeviceContext->GetData(mSyncQuery, NULL, 0, D3D11_ASYNC_GETDATA_DONOTFLUSH); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to get event query data, result: 0x%X.", result); + } + + // Keep polling, but allow other threads to do something useful first + ScheduleYield(); + + if (testDeviceLost()) + { + mDisplay->notifyDeviceLost(); + return gl::Error(GL_OUT_OF_MEMORY, "Device was lost while waiting for sync."); + } + } + while (result == S_FALSE); + + return gl::Error(GL_NO_ERROR); +} + +SwapChainD3D *Renderer11::createSwapChain(NativeWindow nativeWindow, HANDLE shareHandle, GLenum backBufferFormat, GLenum depthBufferFormat) +{ + return new SwapChain11(this, nativeWindow, shareHandle, backBufferFormat, depthBufferFormat); +} + +gl::Error Renderer11::generateSwizzle(gl::Texture *texture) +{ + if (texture) + { + TextureD3D *textureD3D = GetImplAs(texture); + ASSERT(textureD3D); + + TextureStorage *texStorage = nullptr; + gl::Error error = textureD3D->getNativeTexture(&texStorage); + if (error.isError()) + { + return error; + } + + if (texStorage) + { + TextureStorage11 *storage11 = TextureStorage11::makeTextureStorage11(texStorage); + error = storage11->generateSwizzles(texture->getSamplerState().swizzleRed, + texture->getSamplerState().swizzleGreen, + texture->getSamplerState().swizzleBlue, + texture->getSamplerState().swizzleAlpha); + if (error.isError()) + { + return error; + } + } + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Renderer11::setSamplerState(gl::SamplerType type, int index, gl::Texture *texture, const gl::SamplerState &samplerStateParam) +{ + // Make sure to add the level offset for our tiny compressed texture workaround + TextureD3D *textureD3D = GetImplAs(texture); + gl::SamplerState samplerStateInternal = samplerStateParam; + + TextureStorage *storage = nullptr; + gl::Error error = textureD3D->getNativeTexture(&storage); + if (error.isError()) + { + return error; + } + + // Storage should exist, texture should be complete + ASSERT(storage); + + samplerStateInternal.baseLevel += storage->getTopLevel(); + + if (type == gl::SAMPLER_PIXEL) + { + ASSERT(static_cast(index) < getRendererCaps().maxTextureImageUnits); + + if (mForceSetPixelSamplerStates[index] || memcmp(&samplerStateInternal, &mCurPixelSamplerStates[index], sizeof(gl::SamplerState)) != 0) + { + ID3D11SamplerState *dxSamplerState = NULL; + error = mStateCache.getSamplerState(samplerStateInternal, &dxSamplerState); + if (error.isError()) + { + return error; + } + + ASSERT(dxSamplerState != NULL); + mDeviceContext->PSSetSamplers(index, 1, &dxSamplerState); + + mCurPixelSamplerStates[index] = samplerStateInternal; + } + + mForceSetPixelSamplerStates[index] = false; + } + else if (type == gl::SAMPLER_VERTEX) + { + ASSERT(static_cast(index) < getRendererCaps().maxVertexTextureImageUnits); + + if (mForceSetVertexSamplerStates[index] || memcmp(&samplerStateInternal, &mCurVertexSamplerStates[index], sizeof(gl::SamplerState)) != 0) + { + ID3D11SamplerState *dxSamplerState = NULL; + error = mStateCache.getSamplerState(samplerStateInternal, &dxSamplerState); + if (error.isError()) + { + return error; + } + + ASSERT(dxSamplerState != NULL); + mDeviceContext->VSSetSamplers(index, 1, &dxSamplerState); + + mCurVertexSamplerStates[index] = samplerStateInternal; + } + + mForceSetVertexSamplerStates[index] = false; + } + else UNREACHABLE(); + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Renderer11::setTexture(gl::SamplerType type, int index, gl::Texture *texture) +{ + ID3D11ShaderResourceView *textureSRV = NULL; + + if (texture) + { + TextureD3D *textureImpl = GetImplAs(texture); + + TextureStorage *texStorage = nullptr; + gl::Error error = textureImpl->getNativeTexture(&texStorage); + if (error.isError()) + { + return error; + } + + // Texture should be complete and have a storage + ASSERT(texStorage); + + TextureStorage11 *storage11 = TextureStorage11::makeTextureStorage11(texStorage); + + // Make sure to add the level offset for our tiny compressed texture workaround + gl::SamplerState samplerState = texture->getSamplerState(); + samplerState.baseLevel += storage11->getTopLevel(); + + error = storage11->getSRV(samplerState, &textureSRV); + if (error.isError()) + { + return error; + } + + // If we get NULL back from getSRV here, something went wrong in the texture class and we're unexpectedly + // missing the shader resource view + ASSERT(textureSRV != NULL); + + textureImpl->resetDirty(); + } + + ASSERT((type == gl::SAMPLER_PIXEL && static_cast(index) < getRendererCaps().maxTextureImageUnits) || + (type == gl::SAMPLER_VERTEX && static_cast(index) < getRendererCaps().maxVertexTextureImageUnits)); + + setShaderResource(type, index, textureSRV); + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Renderer11::setUniformBuffers(const gl::Data &data, + const GLint vertexUniformBuffers[], + const GLint fragmentUniformBuffers[]) +{ + for (unsigned int uniformBufferIndex = 0; uniformBufferIndex < data.caps->maxVertexUniformBlocks; uniformBufferIndex++) + { + GLint binding = vertexUniformBuffers[uniformBufferIndex]; + + if (binding == -1) + { + continue; + } + + gl::Buffer *uniformBuffer = data.state->getIndexedUniformBuffer(binding); + GLintptr uniformBufferOffset = data.state->getIndexedUniformBufferOffset(binding); + GLsizeiptr uniformBufferSize = data.state->getIndexedUniformBufferSize(binding); + + if (uniformBuffer) + { + Buffer11 *bufferStorage = Buffer11::makeBuffer11(uniformBuffer->getImplementation()); + ID3D11Buffer *constantBuffer = bufferStorage->getBuffer(BUFFER_USAGE_UNIFORM); + + if (!constantBuffer) + { + return gl::Error(GL_OUT_OF_MEMORY); + } + + if (mCurrentConstantBufferVS[uniformBufferIndex] != bufferStorage->getSerial() || + mCurrentConstantBufferVSOffset[uniformBufferIndex] != uniformBufferOffset || + mCurrentConstantBufferVSSize[uniformBufferIndex] != uniformBufferSize) + { +#if defined(ANGLE_ENABLE_D3D11_1) + if (mSupportsConstantBufferOffsets && uniformBufferSize != 0) + { + UINT firstConstant = 0, numConstants = 0; + CalculateConstantBufferParams(uniformBufferOffset, uniformBufferSize, &firstConstant, &numConstants); + mDeviceContext1->VSSetConstantBuffers1(getReservedVertexUniformBuffers() + uniformBufferIndex, + 1, &constantBuffer, &firstConstant, &numConstants); + } + else +#endif + { + ASSERT(uniformBufferOffset == 0); + mDeviceContext->VSSetConstantBuffers(getReservedVertexUniformBuffers() + uniformBufferIndex, + 1, &constantBuffer); + } + + mCurrentConstantBufferVS[uniformBufferIndex] = bufferStorage->getSerial(); + mCurrentConstantBufferVSOffset[uniformBufferIndex] = uniformBufferOffset; + mCurrentConstantBufferVSSize[uniformBufferIndex] = uniformBufferSize; + } + } + } + + for (unsigned int uniformBufferIndex = 0; uniformBufferIndex < data.caps->maxFragmentUniformBlocks; uniformBufferIndex++) + { + GLint binding = fragmentUniformBuffers[uniformBufferIndex]; + + if (binding == -1) + { + continue; + } + + gl::Buffer *uniformBuffer = data.state->getIndexedUniformBuffer(binding); + GLintptr uniformBufferOffset = data.state->getIndexedUniformBufferOffset(binding); + GLsizeiptr uniformBufferSize = data.state->getIndexedUniformBufferSize(binding); + + if (uniformBuffer) + { + Buffer11 *bufferStorage = Buffer11::makeBuffer11(uniformBuffer->getImplementation()); + ID3D11Buffer *constantBuffer = bufferStorage->getBuffer(BUFFER_USAGE_UNIFORM); + + if (!constantBuffer) + { + return gl::Error(GL_OUT_OF_MEMORY); + } + + if (mCurrentConstantBufferPS[uniformBufferIndex] != bufferStorage->getSerial() || + mCurrentConstantBufferPSOffset[uniformBufferIndex] != uniformBufferOffset || + mCurrentConstantBufferPSSize[uniformBufferIndex] != uniformBufferSize) + { +#if defined(ANGLE_ENABLE_D3D11_1) + if (mSupportsConstantBufferOffsets && uniformBufferSize != 0) + { + UINT firstConstant = 0, numConstants = 0; + CalculateConstantBufferParams(uniformBufferOffset, uniformBufferSize, &firstConstant, &numConstants); + mDeviceContext1->PSSetConstantBuffers1(getReservedFragmentUniformBuffers() + uniformBufferIndex, + 1, &constantBuffer, &firstConstant, &numConstants); + } + else +#endif + { + ASSERT(uniformBufferOffset == 0); + mDeviceContext->PSSetConstantBuffers(getReservedFragmentUniformBuffers() + uniformBufferIndex, + 1, &constantBuffer); + } + + mCurrentConstantBufferPS[uniformBufferIndex] = bufferStorage->getSerial(); + mCurrentConstantBufferPSOffset[uniformBufferIndex] = uniformBufferOffset; + mCurrentConstantBufferPSSize[uniformBufferIndex] = uniformBufferSize; + } + } + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Renderer11::setRasterizerState(const gl::RasterizerState &rasterState) +{ + if (mForceSetRasterState || memcmp(&rasterState, &mCurRasterState, sizeof(gl::RasterizerState)) != 0) + { + ID3D11RasterizerState *dxRasterState = NULL; + gl::Error error = mStateCache.getRasterizerState(rasterState, mScissorEnabled, &dxRasterState); + if (error.isError()) + { + return error; + } + + mDeviceContext->RSSetState(dxRasterState); + + mCurRasterState = rasterState; + } + + mForceSetRasterState = false; + + return gl::Error(GL_NO_ERROR); +} + +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; + } + + mForceSetBlendState = false; + + 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) + { + 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(stencilRef, 0xFFu); + + mDeviceContext->OMSetDepthStencilState(dxDepthStencilState, dxStencilRef); + + mCurDepthStencilState = depthStencilState; + mCurStencilRef = stencilRef; + mCurStencilBackRef = stencilBackRef; + } + + 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) + { + 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; + } + + mForceSetScissor = false; +} + +void Renderer11::setViewport(const gl::Rectangle &viewport, float zNear, float zFar, GLenum drawMode, GLenum frontFace, + bool ignoreViewport) +{ + 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(caps.maxViewportWidth); + int dxMaxViewportBoundsY = static_cast(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(dxViewportTopLeftX); + dxViewport.TopLeftY = static_cast(dxViewportTopLeftY); + dxViewport.Width = static_cast(dxViewportWidth); + dxViewport.Height = static_cast(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((actualViewport.width - dxViewportWidth) + 2 * (actualViewport.x - dxViewportTopLeftX)) / dxViewport.Width; + mVertexConstants.viewAdjust[1] = static_cast((actualViewport.height - dxViewportHeight) + 2 * (actualViewport.y - dxViewportTopLeftY)) / dxViewport.Height; + mVertexConstants.viewAdjust[2] = static_cast(actualViewport.width) / dxViewport.Width; + mVertexConstants.viewAdjust[3] = static_cast(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; +} + +bool Renderer11::applyPrimitiveType(GLenum mode, GLsizei count, bool usesPointSize) +{ + D3D11_PRIMITIVE_TOPOLOGY primitiveTopology = D3D_PRIMITIVE_TOPOLOGY_UNDEFINED; + + GLsizei minCount = 0; + + switch (mode) + { + case GL_POINTS: primitiveTopology = D3D11_PRIMITIVE_TOPOLOGY_POINTLIST; minCount = 1; break; + case GL_LINES: primitiveTopology = D3D_PRIMITIVE_TOPOLOGY_LINELIST; minCount = 2; break; + case GL_LINE_LOOP: primitiveTopology = D3D_PRIMITIVE_TOPOLOGY_LINESTRIP; minCount = 2; break; + case GL_LINE_STRIP: primitiveTopology = D3D_PRIMITIVE_TOPOLOGY_LINESTRIP; minCount = 2; break; + case GL_TRIANGLES: primitiveTopology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST; minCount = 3; break; + case GL_TRIANGLE_STRIP: primitiveTopology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP; minCount = 3; break; + // emulate fans via rewriting index buffer + case GL_TRIANGLE_FAN: primitiveTopology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST; minCount = 3; break; + default: + UNREACHABLE(); + return false; + } + + // If instanced pointsprite emulation is being used and If gl_PointSize is used in the shader, + // GL_POINTS mode is expected to render pointsprites. + // Instanced PointSprite emulation requires that the topology to be D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST. + if (mode == GL_POINTS && usesPointSize && getWorkarounds().useInstancedPointSpriteEmulation) + { + primitiveTopology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST; + } + + if (primitiveTopology != mCurrentPrimitiveTopology) + { + mDeviceContext->IASetPrimitiveTopology(primitiveTopology); + mCurrentPrimitiveTopology = primitiveTopology; + } + + return count >= minCount; +} + +void Renderer11::unsetConflictingSRVs(gl::SamplerType samplerType, uintptr_t resource, const gl::ImageIndex *index) +{ + 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(resourceIndex), NULL); + } + } +} + +gl::Error Renderer11::applyRenderTarget(const gl::Framebuffer *framebuffer) +{ + // 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(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(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(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(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(framebufferRTVs[rtIndex]); + } + mAppliedDSV = reinterpret_cast(framebufferDSV); + mRenderTargetDescInitialized = true; + mDepthStencilInitialized = true; + } + + const Framebuffer11 *framebuffer11 = GetImplAs(framebuffer); + gl::Error error = framebuffer11->invalidateSwizzles(); + 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()) + { + return error; + } + + return mInputLayoutCache.applyVertexBuffers(attributes, mode, state.getProgram()); +} + +gl::Error Renderer11::applyIndexBuffer(const GLvoid *indices, gl::Buffer *elementArrayBuffer, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo) +{ + gl::Error error = mIndexDataManager->prepareIndexData(type, count, elementArrayBuffer, indices, indexInfo); + if (error.isError()) + { + return error; + } + + ID3D11Buffer *buffer = NULL; + DXGI_FORMAT bufferFormat = (indexInfo->indexType == GL_UNSIGNED_INT) ? DXGI_FORMAT_R32_UINT : DXGI_FORMAT_R16_UINT; + + if (indexInfo->storage) + { + Buffer11 *storage = Buffer11::makeBuffer11(indexInfo->storage); + buffer = storage->getBuffer(BUFFER_USAGE_INDEX); + } + else + { + IndexBuffer11* indexBuffer = IndexBuffer11::makeIndexBuffer11(indexInfo->indexBuffer); + buffer = indexBuffer->getBuffer(); + } + + if (buffer != mAppliedIB || bufferFormat != mAppliedIBFormat || indexInfo->startOffset != mAppliedIBOffset) + { + mDeviceContext->IASetIndexBuffer(buffer, bufferFormat, indexInfo->startOffset); + + mAppliedIB = buffer; + mAppliedIBFormat = bufferFormat; + mAppliedIBOffset = indexInfo->startOffset; + } + + return gl::Error(GL_NO_ERROR); +} + +void Renderer11::applyTransformFeedbackBuffers(const gl::State &state) +{ + size_t numXFBBindings = 0; + bool requiresUpdate = false; + + if (state.isTransformFeedbackActiveUnpaused()) + { + numXFBBindings = state.getTransformFeedbackBufferIndexRange(); + 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); + ID3D11Buffer *d3dBuffer = NULL; + if (curXFBBuffer) + { + Buffer11 *storage = Buffer11::makeBuffer11(curXFBBuffer->getImplementation()); + 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]) + { + requiresUpdate = true; + } + } + } + + if (requiresUpdate || numXFBBindings != mAppliedNumXFBBindings) + { + for (size_t i = 0; i < numXFBBindings; ++i) + { + gl::Buffer *curXFBBuffer = state.getIndexedTransformFeedbackBuffer(i); + GLintptr curXFBOffset = state.getIndexedTransformFeedbackBufferOffset(i); + + if (curXFBBuffer) + { + Buffer11 *storage = Buffer11::makeBuffer11(curXFBBuffer->getImplementation()); + ID3D11Buffer *d3dBuffer = storage->getBuffer(BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK); + + mCurrentD3DOffsets[i] = (mAppliedTFBuffers[i] != d3dBuffer || mAppliedTFOffsets[i] != curXFBOffset) ? + static_cast(curXFBOffset) : -1; + mAppliedTFBuffers[i] = d3dBuffer; + } + else + { + mAppliedTFBuffers[i] = NULL; + mCurrentD3DOffsets[i] = 0; + } + mAppliedTFOffsets[i] = curXFBOffset; + } + + mAppliedNumXFBBindings = numXFBBindings; + + mDeviceContext->SOSetTargets(numXFBBindings, mAppliedTFBuffers, mCurrentD3DOffsets); + } +} + +gl::Error Renderer11::drawArrays(const gl::Data &data, GLenum mode, GLsizei count, GLsizei instances, bool usesPointSize) +{ + 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. + + mDeviceContext->PSSetShader(NULL, NULL, 0); + + if (instances > 0) + { + mDeviceContext->DrawInstanced(count, instances, 0, 0); + } + else + { + mDeviceContext->Draw(count, 0); + } + + ProgramD3D *programD3D = GetImplAs(data.state->getProgram()); + + rx::ShaderExecutableD3D *pixelExe = NULL; + 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) + { + ID3D11PixelShader *pixelShader = ShaderExecutable11::makeShaderExecutable11(pixelExe)->getPixelShader(); + ASSERT(reinterpret_cast(pixelShader) == mAppliedPixelShader); + mDeviceContext->PSSetShader(pixelShader, NULL, 0); + + // Retrieve the point sprite geometry shader + rx::ShaderExecutableD3D *geometryExe = programD3D->getGeometryExecutable(); + ID3D11GeometryShader *geometryShader = (geometryExe ? ShaderExecutable11::makeShaderExecutable11(geometryExe)->getGeometryShader() : NULL); + mAppliedGeometryShader = reinterpret_cast(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) + { + return drawTriangleFan(count, GL_NONE, NULL, 0, NULL, instances); + } + else if (instances > 0) + { + mDeviceContext->DrawInstanced(count, instances, 0, 0); + return gl::Error(GL_NO_ERROR); + } + else + { + // 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); + } + 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) +{ + int minIndex = static_cast(indexInfo.indexRange.start); + + if (mode == GL_LINE_LOOP) + { + return drawLineLoop(count, type, indices, minIndex, elementArrayBuffer); + } + else if (mode == GL_TRIANGLE_FAN) + { + return drawTriangleFan(count, type, indices, minIndex, elementArrayBuffer, instances); + } + else if (instances > 0) + { + mDeviceContext->DrawIndexedInstanced(count, instances, 0, -minIndex, 0); + return gl::Error(GL_NO_ERROR); + } + else + { + mDeviceContext->DrawIndexed(count, 0, -minIndex); + return gl::Error(GL_NO_ERROR); + } +} + +gl::Error Renderer11::drawLineLoop(GLsizei count, GLenum type, const GLvoid *indices, int minIndex, gl::Buffer *elementArrayBuffer) +{ + // Get the raw indices for an indexed draw + if (type != GL_NONE && elementArrayBuffer) + { + BufferD3D *storage = GetImplAs(elementArrayBuffer); + intptr_t offset = reinterpret_cast(indices); + + const uint8_t *bufferData = NULL; + gl::Error error = storage->getData(&bufferData); + if (error.isError()) + { + return error; + } + + indices = bufferData + offset; + } + + if (!mLineLoopIB) + { + mLineLoopIB = new StreamingIndexBufferInterface(this); + gl::Error error = mLineLoopIB->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_INT); + if (error.isError()) + { + SafeDelete(mLineLoopIB); + return error; + } + } + + // Checked by Renderer11::applyPrimitiveType + ASSERT(count >= 0); + + if (static_cast(count) + 1 > (std::numeric_limits::max() / sizeof(unsigned int))) + { + 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(count) + 1) * sizeof(unsigned int); + gl::Error error = mLineLoopIB->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_INT); + if (error.isError()) + { + return error; + } + + void* mappedMemory = NULL; + unsigned int offset; + error = mLineLoopIB->mapBuffer(spaceNeeded, &mappedMemory, &offset); + if (error.isError()) + { + return error; + } + + unsigned int *data = reinterpret_cast(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(indices)[i]; + } + data[count] = static_cast(indices)[0]; + break; + case GL_UNSIGNED_SHORT: + for (int i = 0; i < count; i++) + { + data[i] = static_cast(indices)[i]; + } + data[count] = static_cast(indices)[0]; + break; + case GL_UNSIGNED_INT: + for (int i = 0; i < count; i++) + { + data[i] = static_cast(indices)[i]; + } + data[count] = static_cast(indices)[0]; + break; + default: UNREACHABLE(); + } + + error = mLineLoopIB->unmapBuffer(); + if (error.isError()) + { + return error; + } + + IndexBuffer11 *indexBuffer = IndexBuffer11::makeIndexBuffer11(mLineLoopIB->getIndexBuffer()); + ID3D11Buffer *d3dIndexBuffer = indexBuffer->getBuffer(); + DXGI_FORMAT indexFormat = indexBuffer->getIndexFormat(); + + if (mAppliedIB != d3dIndexBuffer || mAppliedIBFormat != indexFormat || mAppliedIBOffset != indexBufferOffset) + { + mDeviceContext->IASetIndexBuffer(d3dIndexBuffer, indexFormat, indexBufferOffset); + mAppliedIB = d3dIndexBuffer; + mAppliedIBFormat = indexFormat; + mAppliedIBOffset = indexBufferOffset; + } + + mDeviceContext->DrawIndexed(count + 1, 0, -minIndex); + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Renderer11::drawTriangleFan(GLsizei count, GLenum type, const GLvoid *indices, int minIndex, gl::Buffer *elementArrayBuffer, int instances) +{ + // Get the raw indices for an indexed draw + if (type != GL_NONE && elementArrayBuffer) + { + BufferD3D *storage = GetImplAs(elementArrayBuffer); + intptr_t offset = reinterpret_cast(indices); + + const uint8_t *bufferData = NULL; + gl::Error error = storage->getData(&bufferData); + if (error.isError()) + { + return error; + } + + indices = bufferData + offset; + } + + if (!mTriangleFanIB) + { + mTriangleFanIB = new StreamingIndexBufferInterface(this); + gl::Error error = mTriangleFanIB->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_INT); + if (error.isError()) + { + SafeDelete(mTriangleFanIB); + return error; + } + } + + // Checked by Renderer11::applyPrimitiveType + ASSERT(count >= 3); + + const unsigned int numTris = count - 2; + + if (numTris > (std::numeric_limits::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); + gl::Error error = mTriangleFanIB->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_INT); + if (error.isError()) + { + return error; + } + + void* mappedMemory = NULL; + unsigned int offset; + error = mTriangleFanIB->mapBuffer(spaceNeeded, &mappedMemory, &offset); + if (error.isError()) + { + return error; + } + + unsigned int *data = reinterpret_cast(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(indices)[0]; + data[i*3 + 1] = static_cast(indices)[i + 1]; + data[i*3 + 2] = static_cast(indices)[i + 2]; + } + break; + case GL_UNSIGNED_SHORT: + for (unsigned int i = 0; i < numTris; i++) + { + data[i*3 + 0] = static_cast(indices)[0]; + data[i*3 + 1] = static_cast(indices)[i + 1]; + data[i*3 + 2] = static_cast(indices)[i + 2]; + } + break; + case GL_UNSIGNED_INT: + for (unsigned int i = 0; i < numTris; i++) + { + data[i*3 + 0] = static_cast(indices)[0]; + data[i*3 + 1] = static_cast(indices)[i + 1]; + data[i*3 + 2] = static_cast(indices)[i + 2]; + } + break; + default: UNREACHABLE(); + } + + error = mTriangleFanIB->unmapBuffer(); + if (error.isError()) + { + return error; + } + + IndexBuffer11 *indexBuffer = IndexBuffer11::makeIndexBuffer11(mTriangleFanIB->getIndexBuffer()); + ID3D11Buffer *d3dIndexBuffer = indexBuffer->getBuffer(); + DXGI_FORMAT indexFormat = indexBuffer->getIndexFormat(); + + if (mAppliedIB != d3dIndexBuffer || mAppliedIBFormat != indexFormat || mAppliedIBOffset != indexBufferOffset) + { + mDeviceContext->IASetIndexBuffer(d3dIndexBuffer, indexFormat, indexBufferOffset); + mAppliedIB = d3dIndexBuffer; + mAppliedIBFormat = indexFormat; + mAppliedIBOffset = indexBufferOffset; + } + + if (instances > 0) + { + mDeviceContext->DrawIndexedInstanced(numTris * 3, instances, 0, -minIndex, 0); + } + else + { + mDeviceContext->DrawIndexed(numTris * 3, 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) +{ + ProgramD3D *programD3D = GetImplAs(program); + + ShaderExecutableD3D *vertexExe = NULL; + gl::Error error = programD3D->getVertexExecutableForInputLayout(inputLayout, &vertexExe, nullptr); + if (error.isError()) + { + return error; + } + + ShaderExecutableD3D *pixelExe = NULL; + error = programD3D->getPixelExecutableForFramebuffer(framebuffer, &pixelExe); + if (error.isError()) + { + return error; + } + + ShaderExecutableD3D *geometryExe = programD3D->getGeometryExecutable(); + + ID3D11VertexShader *vertexShader = (vertexExe ? ShaderExecutable11::makeShaderExecutable11(vertexExe)->getVertexShader() : NULL); + + ID3D11PixelShader *pixelShader = NULL; + // Skip pixel shader if we're doing rasterizer discard. + if (!rasterizerDiscard) + { + pixelShader = (pixelExe ? ShaderExecutable11::makeShaderExecutable11(pixelExe)->getPixelShader() : NULL); + } + + ID3D11GeometryShader *geometryShader = NULL; + if (transformFeedbackActive) + { + geometryShader = (vertexExe ? ShaderExecutable11::makeShaderExecutable11(vertexExe)->getStreamOutShader() : NULL); + } + else if (mCurRasterState.pointDrawMode) + { + geometryShader = (geometryExe ? ShaderExecutable11::makeShaderExecutable11(geometryExe)->getGeometryShader() : NULL); + } + + bool dirtyUniforms = false; + + if (reinterpret_cast(vertexShader) != mAppliedVertexShader) + { + mDeviceContext->VSSetShader(vertexShader, NULL, 0); + mAppliedVertexShader = reinterpret_cast(vertexShader); + dirtyUniforms = true; + } + + if (reinterpret_cast(geometryShader) != mAppliedGeometryShader) + { + mDeviceContext->GSSetShader(geometryShader, NULL, 0); + mAppliedGeometryShader = reinterpret_cast(geometryShader); + dirtyUniforms = true; + } + + if (reinterpret_cast(pixelShader) != mAppliedPixelShader) + { + mDeviceContext->PSSetShader(pixelShader, NULL, 0); + mAppliedPixelShader = reinterpret_cast(pixelShader); + dirtyUniforms = true; + } + + if (dirtyUniforms) + { + programD3D->dirtyAllUniforms(); + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Renderer11::applyUniforms(const ProgramImpl &program, const std::vector &uniformArray) +{ + unsigned int totalRegisterCountVS = 0; + unsigned int totalRegisterCountPS = 0; + + bool vertexUniformsDirty = false; + bool pixelUniformsDirty = false; + + for (size_t uniformIndex = 0; uniformIndex < uniformArray.size(); uniformIndex++) + { + const gl::LinkedUniform &uniform = *uniformArray[uniformIndex]; + + if (uniform.isReferencedByVertexShader() && !uniform.isSampler()) + { + totalRegisterCountVS += uniform.registerCount; + vertexUniformsDirty = (vertexUniformsDirty || uniform.dirty); + } + + if (uniform.isReferencedByFragmentShader() && !uniform.isSampler()) + { + totalRegisterCountPS += uniform.registerCount; + pixelUniformsDirty = (pixelUniformsDirty || uniform.dirty); + } + } + + const ProgramD3D *programD3D = GetAs(&program); + const UniformStorage11 *vertexUniformStorage = UniformStorage11::makeUniformStorage11(&programD3D->getVertexUniformStorage()); + const UniformStorage11 *fragmentUniformStorage = UniformStorage11::makeUniformStorage11(&programD3D->getFragmentUniformStorage()); + ASSERT(vertexUniformStorage); + ASSERT(fragmentUniformStorage); + + ID3D11Buffer *vertexConstantBuffer = vertexUniformStorage->getConstantBuffer(); + ID3D11Buffer *pixelConstantBuffer = fragmentUniformStorage->getConstantBuffer(); + + float (*mapVS)[4] = NULL; + float (*mapPS)[4] = NULL; + + if (totalRegisterCountVS > 0 && vertexUniformsDirty) + { + D3D11_MAPPED_SUBRESOURCE map = {0}; + HRESULT result = mDeviceContext->Map(vertexConstantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &map); + UNUSED_ASSERTION_VARIABLE(result); + ASSERT(SUCCEEDED(result)); + mapVS = (float(*)[4])map.pData; + } + + if (totalRegisterCountPS > 0 && pixelUniformsDirty) + { + D3D11_MAPPED_SUBRESOURCE map = {0}; + HRESULT result = mDeviceContext->Map(pixelConstantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &map); + UNUSED_ASSERTION_VARIABLE(result); + ASSERT(SUCCEEDED(result)); + mapPS = (float(*)[4])map.pData; + } + + for (size_t uniformIndex = 0; uniformIndex < uniformArray.size(); uniformIndex++) + { + gl::LinkedUniform *uniform = uniformArray[uniformIndex]; + + if (!uniform->isSampler()) + { + 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. + + 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 (mapVS) + { + mDeviceContext->Unmap(vertexConstantBuffer, 0); + } + + if (mapPS) + { + mDeviceContext->Unmap(pixelConstantBuffer, 0); + } + + if (mCurrentVertexConstantBuffer != vertexConstantBuffer) + { + mDeviceContext->VSSetConstantBuffers(0, 1, &vertexConstantBuffer); + mCurrentVertexConstantBuffer = vertexConstantBuffer; + } + + if (mCurrentPixelConstantBuffer != pixelConstantBuffer) + { + mDeviceContext->PSSetConstantBuffers(0, 1, &pixelConstantBuffer); + mCurrentPixelConstantBuffer = pixelConstantBuffer; + } + + // Driver uniforms + if (!mDriverConstantBufferVS) + { + D3D11_BUFFER_DESC constantBufferDescription = {0}; + constantBufferDescription.ByteWidth = sizeof(dx_VertexConstants); + constantBufferDescription.Usage = D3D11_USAGE_DEFAULT; + constantBufferDescription.BindFlags = D3D11_BIND_CONSTANT_BUFFER; + constantBufferDescription.CPUAccessFlags = 0; + constantBufferDescription.MiscFlags = 0; + constantBufferDescription.StructureByteStride = 0; + + HRESULT result = mDevice->CreateBuffer(&constantBufferDescription, NULL, &mDriverConstantBufferVS); + UNUSED_ASSERTION_VARIABLE(result); + ASSERT(SUCCEEDED(result)); + + mDeviceContext->VSSetConstantBuffers(1, 1, &mDriverConstantBufferVS); + } + + if (!mDriverConstantBufferPS) + { + D3D11_BUFFER_DESC constantBufferDescription = {0}; + constantBufferDescription.ByteWidth = sizeof(dx_PixelConstants); + constantBufferDescription.Usage = D3D11_USAGE_DEFAULT; + constantBufferDescription.BindFlags = D3D11_BIND_CONSTANT_BUFFER; + constantBufferDescription.CPUAccessFlags = 0; + constantBufferDescription.MiscFlags = 0; + constantBufferDescription.StructureByteStride = 0; + + HRESULT result = mDevice->CreateBuffer(&constantBufferDescription, NULL, &mDriverConstantBufferPS); + UNUSED_ASSERTION_VARIABLE(result); + ASSERT(SUCCEEDED(result)); + + mDeviceContext->PSSetConstantBuffers(1, 1, &mDriverConstantBufferPS); + } + + if (memcmp(&mVertexConstants, &mAppliedVertexConstants, sizeof(dx_VertexConstants)) != 0) + { + mDeviceContext->UpdateSubresource(mDriverConstantBufferVS, 0, NULL, &mVertexConstants, 16, 0); + memcpy(&mAppliedVertexConstants, &mVertexConstants, sizeof(dx_VertexConstants)); + } + + if (memcmp(&mPixelConstants, &mAppliedPixelConstants, sizeof(dx_PixelConstants)) != 0) + { + mDeviceContext->UpdateSubresource(mDriverConstantBufferPS, 0, NULL, &mPixelConstants, 16, 0); + memcpy(&mAppliedPixelConstants, &mPixelConstants, sizeof(dx_PixelConstants)); + } + + // GSSetConstantBuffers triggers device removal on 9_3, so we should only call it if necessary + if (programD3D->usesGeometryShader()) + { + // needed for the point sprite geometry shader + if (mCurrentGeometryConstantBuffer != mDriverConstantBufferPS) + { + mDeviceContext->GSSetConstantBuffers(0, 1, &mDriverConstantBufferPS); + mCurrentGeometryConstantBuffer = mDriverConstantBufferPS; + } + } + + return gl::Error(GL_NO_ERROR); +} + +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()); + + 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; + + mAppliedIB = NULL; + mAppliedIBFormat = DXGI_FORMAT_UNKNOWN; + mAppliedIBOffset = 0; + + mAppliedVertexShader = DirtyPointer; + mAppliedGeometryShader = DirtyPointer; + mAppliedPixelShader = DirtyPointer; + + mAppliedNumXFBBindings = static_cast(-1); + + for (size_t i = 0; i < gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS; i++) + { + mAppliedTFBuffers[i] = NULL; + mAppliedTFOffsets[i] = 0; + } + + memset(&mAppliedVertexConstants, 0, sizeof(dx_VertexConstants)); + memset(&mAppliedPixelConstants, 0, sizeof(dx_PixelConstants)); + + mInputLayoutCache.markDirty(); + + for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS; i++) + { + mCurrentConstantBufferVS[i] = static_cast(-1); + mCurrentConstantBufferVSOffset[i] = 0; + mCurrentConstantBufferVSSize[i] = 0; + mCurrentConstantBufferPS[i] = static_cast(-1); + mCurrentConstantBufferPSOffset[i] = 0; + mCurrentConstantBufferPSSize[i] = 0; + } + + mCurrentVertexConstantBuffer = NULL; + mCurrentPixelConstantBuffer = NULL; + mCurrentGeometryConstantBuffer = NULL; + + mCurrentPrimitiveTopology = D3D_PRIMITIVE_TOPOLOGY_UNDEFINED; +} + +void Renderer11::releaseDeviceResources() +{ + mStateCache.clear(); + mInputLayoutCache.clear(); + + SafeDelete(mVertexDataManager); + SafeDelete(mIndexDataManager); + SafeDelete(mLineLoopIB); + SafeDelete(mTriangleFanIB); + SafeDelete(mBlit); + SafeDelete(mClear); + SafeDelete(mTrim); + SafeDelete(mPixelTransfer); + + SafeRelease(mDriverConstantBufferVS); + SafeRelease(mDriverConstantBufferPS); + SafeRelease(mSyncQuery); +} + +// set notify to true to broadcast a message to all contexts of the device loss +bool Renderer11::testDeviceLost() +{ + bool isLost = false; + + // GetRemovedReason is used to test if the device is removed + HRESULT result = mDevice->GetDeviceRemovedReason(); + isLost = d3d11::isDeviceLostError(result); + + if (isLost) + { + // Log error if this is a new device lost event + if (mDeviceLost == false) + { + ERR("The D3D11 device was removed: 0x%08X", result); + } + + // ensure we note the device loss -- + // we'll probably get this done again by notifyDeviceLost + // but best to remember it! + // Note that we don't want to clear the device loss status here + // -- this needs to be done by resetDevice + mDeviceLost = true; + } + + return isLost; +} + +bool Renderer11::testDeviceResettable() +{ + // determine if the device is resettable by creating a dummy device + PFN_D3D11_CREATE_DEVICE D3D11CreateDevice = (PFN_D3D11_CREATE_DEVICE)GetProcAddress(mD3d11Module, "D3D11CreateDevice"); + + if (D3D11CreateDevice == NULL) + { + return false; + } + + ID3D11Device* dummyDevice; + D3D_FEATURE_LEVEL dummyFeatureLevel; + ID3D11DeviceContext* dummyContext; + + HRESULT result = D3D11CreateDevice(NULL, + mDriverType, + NULL, + #if defined(_DEBUG) + D3D11_CREATE_DEVICE_DEBUG, + #else + 0, + #endif + mAvailableFeatureLevels.data(), + mAvailableFeatureLevels.size(), + D3D11_SDK_VERSION, + &dummyDevice, + &dummyFeatureLevel, + &dummyContext); + + if (!mDevice || FAILED(result)) + { + return false; + } + + SafeRelease(dummyContext); + SafeRelease(dummyDevice); + + return true; +} + +void Renderer11::release() +{ + RendererD3D::cleanup(); + + releaseDeviceResources(); + + SafeRelease(mDxgiFactory); + SafeRelease(mDxgiAdapter); + +#if defined(ANGLE_ENABLE_D3D11_1) + SafeRelease(mDeviceContext1); +#endif + + if (mDeviceContext) + { + mDeviceContext->ClearState(); + mDeviceContext->Flush(); + SafeRelease(mDeviceContext); + } + + SafeRelease(mDevice); + + if (mD3d11Module) + { + FreeLibrary(mD3d11Module); + mD3d11Module = NULL; + } + + if (mDxgiModule) + { + FreeLibrary(mDxgiModule); + mDxgiModule = NULL; + } + + mCompiler.release(); +} + +bool Renderer11::resetDevice() +{ + // recreate everything + release(); + egl::Error result = initialize(); + + if (result.isError()) + { + ERR("Could not reinitialize D3D11 device: %08X", result.getCode()); + return false; + } + + mDeviceLost = false; + + return true; +} + +VendorID Renderer11::getVendorId() const +{ + return static_cast(mAdapterDescription.VendorId); +} + +std::string Renderer11::getRendererDescription() const +{ + std::ostringstream rendererString; + + rendererString << mDescription; + rendererString << " Direct3D11"; + + rendererString << " vs_" << getMajorShaderModel() << "_" << getMinorShaderModel() << getShaderModelSuffix(); + rendererString << " ps_" << getMajorShaderModel() << "_" << getMinorShaderModel() << getShaderModelSuffix(); + + return rendererString.str(); +} + +GUID 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; +} + +unsigned int Renderer11::getReservedVertexUniformVectors() const +{ + return 0; // Driver uniforms are stored in a separate constant buffer +} + +unsigned int Renderer11::getReservedFragmentUniformVectors() const +{ + return 0; // Driver uniforms are stored in a separate constant buffer +} + +unsigned int Renderer11::getReservedVertexUniformBuffers() const +{ + // we reserve one buffer for the application uniforms, and one for driver uniforms + return 2; +} + +unsigned int Renderer11::getReservedFragmentUniformBuffers() const +{ + // we reserve one buffer for the application uniforms, and one for driver uniforms + return 2; +} + +bool Renderer11::getShareHandleSupport() const +{ + // We only currently support share handles with BGRA surfaces, because + // chrome needs BGRA. Once chrome fixes this, we should always support them. + // PIX doesn't seem to support using share handles, so disable them. + // 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 +} + +bool Renderer11::getPostSubBufferSupport() const +{ + // D3D11 does not support present with dirty rectangles until D3D11.1 and DXGI 1.2. + return false; +} + +int Renderer11::getMajorShaderModel() const +{ + switch (mFeatureLevel) + { + 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 + case D3D_FEATURE_LEVEL_10_0: return D3D10_SHADER_MAJOR_VERSION; // 4 + case D3D_FEATURE_LEVEL_9_3: return D3D10_SHADER_MAJOR_VERSION; // 4 + default: UNREACHABLE(); return 0; + } +} + +int Renderer11::getMinorShaderModel() const +{ + switch (mFeatureLevel) + { + 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 + case D3D_FEATURE_LEVEL_10_0: return D3D10_SHADER_MINOR_VERSION; // 0 + case D3D_FEATURE_LEVEL_9_3: return D3D10_SHADER_MINOR_VERSION; // 0 + default: UNREACHABLE(); return 0; + } +} + +std::string Renderer11::getShaderModelSuffix() const +{ + switch (mFeatureLevel) + { + case D3D_FEATURE_LEVEL_11_0: return ""; + case D3D_FEATURE_LEVEL_10_1: return ""; + case D3D_FEATURE_LEVEL_10_0: return ""; + case D3D_FEATURE_LEVEL_9_3: return "_level_9_3"; + default: UNREACHABLE(); return ""; + } +} + +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(); + ASSERT(colorbuffer); + + RenderTarget11 *sourceRenderTarget = NULL; + gl::Error error = d3d11::GetAttachmentRenderTarget(colorbuffer, &sourceRenderTarget); + if (error.isError()) + { + return error; + } + ASSERT(sourceRenderTarget); + + ID3D11ShaderResourceView *source = sourceRenderTarget->getShaderResourceView(); + ASSERT(source); + + TextureStorage11_2D *storage11 = TextureStorage11_2D::makeTextureStorage11_2D(storage); + ASSERT(storage11); + + gl::ImageIndex index = gl::ImageIndex::Make2D(level); + RenderTargetD3D *destRenderTarget = NULL; + error = storage11->getRenderTarget(index, &destRenderTarget); + if (error.isError()) + { + return error; + } + ASSERT(destRenderTarget); + + ID3D11RenderTargetView *dest = RenderTarget11::makeRenderTarget11(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); + + 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); + if (error.isError()) + { + return error; + } + + storage11->invalidateSwizzleCacheLevel(level); + + return gl::Error(GL_NO_ERROR); +} + +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(); + ASSERT(colorbuffer); + + RenderTarget11 *sourceRenderTarget = NULL; + gl::Error error = d3d11::GetAttachmentRenderTarget(colorbuffer, &sourceRenderTarget); + if (error.isError()) + { + return error; + } + ASSERT(sourceRenderTarget); + + ID3D11ShaderResourceView *source = sourceRenderTarget->getShaderResourceView(); + ASSERT(source); + + TextureStorage11_Cube *storage11 = TextureStorage11_Cube::makeTextureStorage11_Cube(storage); + ASSERT(storage11); + + gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level); + RenderTargetD3D *destRenderTarget = NULL; + error = storage11->getRenderTarget(index, &destRenderTarget); + if (error.isError()) + { + return error; + } + ASSERT(destRenderTarget); + + ID3D11RenderTargetView *dest = RenderTarget11::makeRenderTarget11(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); + + 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); + if (error.isError()) + { + return error; + } + + storage11->invalidateSwizzleCacheLevel(level); + + return gl::Error(GL_NO_ERROR); +} + +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(); + ASSERT(colorbuffer); + + RenderTarget11 *sourceRenderTarget = NULL; + gl::Error error = d3d11::GetAttachmentRenderTarget(colorbuffer, &sourceRenderTarget); + if (error.isError()) + { + return error; + } + ASSERT(sourceRenderTarget); + + ID3D11ShaderResourceView *source = sourceRenderTarget->getShaderResourceView(); + ASSERT(source); + + TextureStorage11_3D *storage11 = TextureStorage11_3D::makeTextureStorage11_3D(storage); + ASSERT(storage11); + + gl::ImageIndex index = gl::ImageIndex::Make3D(level, destOffset.z); + RenderTargetD3D *destRenderTarget = NULL; + error = storage11->getRenderTarget(index, &destRenderTarget); + if (error.isError()) + { + return error; + } + ASSERT(destRenderTarget); + + ID3D11RenderTargetView *dest = RenderTarget11::makeRenderTarget11(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); + + 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); + if (error.isError()) + { + return error; + } + + storage11->invalidateSwizzleCacheLevel(level); + + return gl::Error(GL_NO_ERROR); +} + +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(); + ASSERT(colorbuffer); + + RenderTarget11 *sourceRenderTarget = NULL; + gl::Error error = d3d11::GetAttachmentRenderTarget(colorbuffer, &sourceRenderTarget); + if (error.isError()) + { + return error; + } + ASSERT(sourceRenderTarget); + + ID3D11ShaderResourceView *source = sourceRenderTarget->getShaderResourceView(); + ASSERT(source); + + TextureStorage11_2DArray *storage11 = TextureStorage11_2DArray::makeTextureStorage11_2DArray(storage); + ASSERT(storage11); + + gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, destOffset.z); + RenderTargetD3D *destRenderTarget = NULL; + error = storage11->getRenderTarget(index, &destRenderTarget); + if (error.isError()) + { + return error; + } + ASSERT(destRenderTarget); + + ID3D11RenderTargetView *dest = RenderTarget11::makeRenderTarget11(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); + + 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); + if (error.isError()) + { + return error; + } + + storage11->invalidateSwizzleCacheLevel(level); + + return gl::Error(GL_NO_ERROR); +} + +void Renderer11::unapplyRenderTargets() +{ + setOneTimeRenderTarget(NULL); +} + +// When finished with this rendertarget, markAllStateDirty must be called. +void Renderer11::setOneTimeRenderTarget(ID3D11RenderTargetView *renderTargetView) +{ + ID3D11RenderTargetView *rtvArray[gl::IMPLEMENTATION_MAX_DRAW_BUFFERS] = {NULL}; + + rtvArray[0] = renderTargetView; + + mDeviceContext->OMSetRenderTargets(getRendererCaps().maxDrawBuffers, rtvArray, NULL); + + // Do not preserve the serial for this one-time-use render target + for (size_t rtIndex = 0; rtIndex < ArraySize(mAppliedRTVs); rtIndex++) + { + mAppliedRTVs[rtIndex] = DirtyPointer; + } + mAppliedDSV = DirtyPointer; +} + +gl::Error Renderer11::createRenderTarget(int width, int height, GLenum format, GLsizei samples, RenderTargetD3D **outRT) +{ + const d3d11::TextureFormat &formatInfo = d3d11::GetTextureFormatInfo(format, mFeatureLevel); + + const gl::TextureCaps &textureCaps = getRendererTextureCaps().get(format); + GLuint supportedSamples = textureCaps.getNearestSamples(samples); + + if (width > 0 && height > 0) + { + // Create texture resource + D3D11_TEXTURE2D_DESC desc; + desc.Width = width; + desc.Height = height; + desc.MipLevels = 1; + desc.ArraySize = 1; + desc.Format = formatInfo.texFormat; + desc.SampleDesc.Count = (supportedSamples == 0) ? 1 : supportedSamples; + desc.SampleDesc.Quality = 0; + desc.Usage = D3D11_USAGE_DEFAULT; + desc.CPUAccessFlags = 0; + desc.MiscFlags = 0; + + // If a rendertarget or depthstencil format exists for this texture format, + // we'll flag it to allow binding that way. Shader resource views are a little + // more complicated. + bool bindRTV = false, bindDSV = false, bindSRV = false; + bindRTV = (formatInfo.rtvFormat != DXGI_FORMAT_UNKNOWN); + bindDSV = (formatInfo.dsvFormat != DXGI_FORMAT_UNKNOWN); + if (formatInfo.srvFormat != DXGI_FORMAT_UNKNOWN) + { + // Multisample targets flagged for binding as depth stencil cannot also be + // flagged for binding as SRV, so make certain not to add the SRV flag for + // these targets. + bindSRV = !(formatInfo.dsvFormat != DXGI_FORMAT_UNKNOWN && desc.SampleDesc.Count > 1); + } + + desc.BindFlags = (bindRTV ? D3D11_BIND_RENDER_TARGET : 0) | + (bindDSV ? D3D11_BIND_DEPTH_STENCIL : 0) | + (bindSRV ? D3D11_BIND_SHADER_RESOURCE : 0); + + // The format must be either an RTV or a DSV + ASSERT(bindRTV != bindDSV); + + ID3D11Texture2D *texture = NULL; + HRESULT result = mDevice->CreateTexture2D(&desc, NULL, &texture); + if (FAILED(result)) + { + ASSERT(result == E_OUTOFMEMORY); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create render target texture, result: 0x%X.", result); + } + + ID3D11ShaderResourceView *srv = NULL; + if (bindSRV) + { + D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; + srvDesc.Format = formatInfo.srvFormat; + srvDesc.ViewDimension = (supportedSamples == 0) ? D3D11_SRV_DIMENSION_TEXTURE2D : D3D11_SRV_DIMENSION_TEXTURE2DMS; + srvDesc.Texture2D.MostDetailedMip = 0; + srvDesc.Texture2D.MipLevels = 1; + + result = mDevice->CreateShaderResourceView(texture, &srvDesc, &srv); + if (FAILED(result)) + { + ASSERT(result == E_OUTOFMEMORY); + SafeRelease(texture); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create render target shader resource view, result: 0x%X.", result); + } + } + + if (bindDSV) + { + D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc; + dsvDesc.Format = formatInfo.dsvFormat; + dsvDesc.ViewDimension = (supportedSamples == 0) ? D3D11_DSV_DIMENSION_TEXTURE2D : D3D11_DSV_DIMENSION_TEXTURE2DMS; + dsvDesc.Texture2D.MipSlice = 0; + dsvDesc.Flags = 0; + + ID3D11DepthStencilView *dsv = NULL; + result = mDevice->CreateDepthStencilView(texture, &dsvDesc, &dsv); + if (FAILED(result)) + { + ASSERT(result == E_OUTOFMEMORY); + SafeRelease(texture); + SafeRelease(srv); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create render target depth stencil view, result: 0x%X.", result); + } + + *outRT = new TextureRenderTarget11(dsv, texture, srv, format, width, height, 1, supportedSamples); + + SafeRelease(dsv); + } + else if (bindRTV) + { + D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; + rtvDesc.Format = formatInfo.rtvFormat; + rtvDesc.ViewDimension = (supportedSamples == 0) ? D3D11_RTV_DIMENSION_TEXTURE2D : D3D11_RTV_DIMENSION_TEXTURE2DMS; + rtvDesc.Texture2D.MipSlice = 0; + + ID3D11RenderTargetView *rtv = NULL; + result = mDevice->CreateRenderTargetView(texture, &rtvDesc, &rtv); + if (FAILED(result)) + { + ASSERT(result == E_OUTOFMEMORY); + SafeRelease(texture); + SafeRelease(srv); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create render target render target view, result: 0x%X.", result); + } + + if (formatInfo.dataInitializerFunction != NULL) + { + const float clearValues[4] = { 0.0f, 0.0f, 0.0f, 1.0f }; + mDeviceContext->ClearRenderTargetView(rtv, clearValues); + } + + *outRT = new TextureRenderTarget11(rtv, texture, srv, format, width, height, 1, supportedSamples); + + SafeRelease(rtv); + } + else + { + UNREACHABLE(); + } + + SafeRelease(texture); + SafeRelease(srv); + } + else + { + *outRT = new TextureRenderTarget11(reinterpret_cast(NULL), NULL, NULL, format, width, height, 1, supportedSamples); + } + + return gl::Error(GL_NO_ERROR); +} + +FramebufferImpl *Renderer11::createDefaultFramebuffer(const gl::Framebuffer::Data &data) +{ + return createFramebuffer(data); +} + +FramebufferImpl *Renderer11::createFramebuffer(const gl::Framebuffer::Data &data) +{ + return new Framebuffer11(data, this); +} + +CompilerImpl *Renderer11::createCompiler(const gl::Data &data) +{ + return new CompilerD3D(data, SH_HLSL11_OUTPUT); +} + +ShaderImpl *Renderer11::createShader(GLenum type) +{ + return new ShaderD3D(type); +} + +ProgramImpl *Renderer11::createProgram() +{ + return new ProgramD3D(this); +} + +gl::Error Renderer11::loadExecutable(const void *function, size_t length, ShaderType type, + const std::vector &transformFeedbackVaryings, + bool separatedOutputBuffers, ShaderExecutableD3D **outExecutable) +{ + switch (type) + { + case SHADER_VERTEX: + { + ID3D11VertexShader *vertexShader = NULL; + ID3D11GeometryShader *streamOutShader = NULL; + + HRESULT result = mDevice->CreateVertexShader(function, length, NULL, &vertexShader); + ASSERT(SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create vertex shader, result: 0x%X.", result); + } + + if (transformFeedbackVaryings.size() > 0) + { + std::vector soDeclaration; + for (size_t i = 0; i < transformFeedbackVaryings.size(); i++) + { + 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); + } + } + + result = mDevice->CreateGeometryShaderWithStreamOutput(function, length, soDeclaration.data(), soDeclaration.size(), + NULL, 0, 0, NULL, &streamOutShader); + ASSERT(SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create steam output shader, result: 0x%X.", result); + } + } + + *outExecutable = new ShaderExecutable11(function, length, vertexShader, streamOutShader); + } + break; + case SHADER_PIXEL: + { + ID3D11PixelShader *pixelShader = NULL; + + HRESULT result = mDevice->CreatePixelShader(function, length, NULL, &pixelShader); + ASSERT(SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create pixel shader, result: 0x%X.", result); + } + + *outExecutable = new ShaderExecutable11(function, length, pixelShader); + } + break; + case SHADER_GEOMETRY: + { + ID3D11GeometryShader *geometryShader = NULL; + + HRESULT result = mDevice->CreateGeometryShader(function, length, NULL, &geometryShader); + ASSERT(SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create geometry shader, result: 0x%X.", result); + } + + *outExecutable = new ShaderExecutable11(function, length, geometryShader); + } + break; + default: + UNREACHABLE(); + return gl::Error(GL_INVALID_OPERATION); + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Renderer11::compileToExecutable(gl::InfoLog &infoLog, const std::string &shaderHLSL, ShaderType type, + const std::vector &transformFeedbackVaryings, + bool separatedOutputBuffers, const D3DCompilerWorkarounds &workarounds, + ShaderExecutableD3D **outExectuable) +{ + const char *profileType = NULL; + switch (type) + { + case SHADER_VERTEX: + profileType = "vs"; + break; + case SHADER_PIXEL: + profileType = "ps"; + break; + case SHADER_GEOMETRY: + profileType = "gs"; + break; + default: + UNREACHABLE(); + return gl::Error(GL_INVALID_OPERATION); + } + + std::string profile = FormatString("%s_%d_%d%s", profileType, getMajorShaderModel(), getMinorShaderModel(), getShaderModelSuffix().c_str()); + + UINT flags = D3DCOMPILE_OPTIMIZATION_LEVEL2; + + if (gl::DebugAnnotationsActive()) + { +#ifndef NDEBUG + flags = D3DCOMPILE_SKIP_OPTIMIZATION; +#endif + + flags |= D3DCOMPILE_DEBUG; + } + + if (workarounds.enableIEEEStrictness) + flags |= D3DCOMPILE_IEEE_STRICTNESS; + + // Sometimes D3DCompile will fail with the default compilation flags for complicated shaders when it would otherwise pass with alternative options. + // Try the default flags first and if compilation fails, try some alternatives. + std::vector configs; + configs.push_back(CompileConfig(flags, "default" )); + configs.push_back(CompileConfig(flags | D3DCOMPILE_SKIP_VALIDATION, "skip validation" )); + configs.push_back(CompileConfig(flags | D3DCOMPILE_SKIP_OPTIMIZATION, "skip optimization")); + + D3D_SHADER_MACRO loopMacros[] = { {"ANGLE_ENABLE_LOOP_FLATTEN", "1"}, {0, 0} }; + + ID3DBlob *binary = NULL; + std::string debugInfo; + gl::Error error = mCompiler.compileToBinary(infoLog, shaderHLSL, profile, configs, loopMacros, &binary, &debugInfo); + if (error.isError()) + { + return error; + } + + // It's possible that binary is NULL if the compiler failed in all configurations. Set the executable to NULL + // and return GL_NO_ERROR to signify that there was a link error but the internal state is still OK. + if (!binary) + { + *outExectuable = NULL; + return gl::Error(GL_NO_ERROR); + } + + error = loadExecutable(binary->GetBufferPointer(), binary->GetBufferSize(), type, + transformFeedbackVaryings, separatedOutputBuffers, outExectuable); + + SafeRelease(binary); + if (error.isError()) + { + return error; + } + + if (!debugInfo.empty()) + { + (*outExectuable)->appendDebugInfo(debugInfo); + } + + return gl::Error(GL_NO_ERROR); +} + +UniformStorageD3D *Renderer11::createUniformStorage(size_t storageSize) +{ + return new UniformStorage11(this, storageSize); +} + +VertexBuffer *Renderer11::createVertexBuffer() +{ + return new VertexBuffer11(this); +} + +IndexBuffer *Renderer11::createIndexBuffer() +{ + return new IndexBuffer11(this); +} + +BufferImpl *Renderer11::createBuffer() +{ + return new Buffer11(this); +} + +VertexArrayImpl *Renderer11::createVertexArray() +{ + return new VertexArray11(this); +} + +QueryImpl *Renderer11::createQuery(GLenum type) +{ + return new Query11(this, type); +} + +FenceNVImpl *Renderer11::createFenceNV() +{ + return new FenceNV11(this); +} + +FenceSyncImpl *Renderer11::createFenceSync() +{ + return new FenceSync11(this); +} + +TransformFeedbackImpl* Renderer11::createTransformFeedback() +{ + return new TransformFeedbackD3D(); +} + +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::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(d3d11FormatInfo.texFormat); + + // sRGB formats do not work with D3D11 buffer SRVs + if (internalFormatInfo.colorEncoding == GL_SRGB) + { + return false; + } + + // We cannot support direct copies to non-color-renderable formats + if (d3d11FormatInfo.rtvFormat == DXGI_FORMAT_UNKNOWN) + { + return false; + } + + // We skip all 3-channel formats since sometimes format support is missing + if (internalFormatInfo.componentCount == 3) + { + return false; + } + + // We don't support formats which we can't represent without conversion + if (dxgiFormatInfo.internalFormat != internalFormat) + { + return false; + } + + return true; +} + +gl::Error Renderer11::fastCopyBufferToTexture(const gl::PixelUnpackState &unpack, unsigned int offset, RenderTargetD3D *destRenderTarget, + GLenum destinationFormat, GLenum sourcePixelsType, const gl::Box &destArea) +{ + ASSERT(supportsFastCopyBufferToTexture(destinationFormat)); + return mPixelTransfer->copyBufferToTexture(unpack, offset, destRenderTarget, destinationFormat, sourcePixelsType, destArea); +} + +ImageD3D *Renderer11::createImage() +{ + return new Image11(this); +} + +gl::Error Renderer11::generateMipmap(ImageD3D *dest, ImageD3D *src) +{ + Image11 *dest11 = Image11::makeImage11(dest); + Image11 *src11 = Image11::makeImage11(src); + return Image11::generateMipmap(dest11, src11); +} + +TextureStorage *Renderer11::createTextureStorage2D(SwapChainD3D *swapChain) +{ + SwapChain11 *swapChain11 = SwapChain11::makeSwapChain11(swapChain); + return new TextureStorage11_2D(this, swapChain11); +} + +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); +} + +TextureStorage *Renderer11::createTextureStorageCube(GLenum internalformat, bool renderTarget, int size, int levels, bool hintLevelZeroOnly) +{ + return new TextureStorage11_Cube(this, internalformat, renderTarget, size, levels, hintLevelZeroOnly); +} + +TextureStorage *Renderer11::createTextureStorage3D(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth, int levels) +{ + return new TextureStorage11_3D(this, internalformat, renderTarget, width, height, depth, levels); +} + +TextureStorage *Renderer11::createTextureStorage2DArray(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth, int levels) +{ + return new TextureStorage11_2DArray(this, internalformat, renderTarget, width, height, depth, levels); +} + +TextureImpl *Renderer11::createTexture(GLenum target) +{ + switch(target) + { + case GL_TEXTURE_2D: return new TextureD3D_2D(this); + case GL_TEXTURE_CUBE_MAP: return new TextureD3D_Cube(this); + case GL_TEXTURE_3D: return new TextureD3D_3D(this); + case GL_TEXTURE_2D_ARRAY: return new TextureD3D_2DArray(this); + default: + UNREACHABLE(); + } + + return NULL; +} + +RenderbufferImpl *Renderer11::createRenderbuffer() +{ + RenderbufferD3D *renderbuffer = new RenderbufferD3D(this); + 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) +{ + ASSERT(area.width >= 0); + ASSERT(area.height >= 0); + + D3D11_TEXTURE2D_DESC textureDesc; + texture->GetDesc(&textureDesc); + + // 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(textureDesc.Width)); + safeArea.y = gl::clamp(area.y, 0, static_cast(textureDesc.Height)); + safeArea.width = gl::clamp(area.width + std::min(area.x, 0), 0, + static_cast(textureDesc.Width) - safeArea.x); + safeArea.height = gl::clamp(area.height + std::min(area.y, 0), 0, + static_cast(textureDesc.Height) - safeArea.y); + + ASSERT(safeArea.x >= 0 && safeArea.y >= 0); + ASSERT(safeArea.x + safeArea.width <= static_cast(textureDesc.Width)); + ASSERT(safeArea.y + safeArea.height <= static_cast(textureDesc.Height)); + + if (safeArea.width == 0 || safeArea.height == 0) + { + // no work to do + 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)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal staging texture for ReadPixels, HRESULT: 0x%X.", result); + } + + ID3D11Texture2D* srcTex = NULL; + if (textureDesc.SampleDesc.Count > 1) + { + D3D11_TEXTURE2D_DESC resolveDesc; + resolveDesc.Width = textureDesc.Width; + resolveDesc.Height = textureDesc.Height; + resolveDesc.MipLevels = 1; + resolveDesc.ArraySize = 1; + resolveDesc.Format = textureDesc.Format; + resolveDesc.SampleDesc.Count = 1; + resolveDesc.SampleDesc.Quality = 0; + resolveDesc.Usage = D3D11_USAGE_DEFAULT; + resolveDesc.BindFlags = 0; + resolveDesc.CPUAccessFlags = 0; + resolveDesc.MiscFlags = 0; + + result = mDevice->CreateTexture2D(&resolveDesc, NULL, &srcTex); + if (FAILED(result)) + { + SafeRelease(stagingTex); + return gl::Error(GL_OUT_OF_MEMORY, "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(); + } + + D3D11_BOX srcBox; + srcBox.left = static_cast(safeArea.x); + srcBox.right = static_cast(safeArea.x + safeArea.width); + srcBox.top = static_cast(safeArea.y); + srcBox.bottom = static_cast(safeArea.y + safeArea.height); + srcBox.front = 0; + srcBox.back = 1; + + mDeviceContext->CopySubresourceRegion(stagingTex, 0, 0, 0, 0, srcTex, subResource, &srcBox); + + SafeRelease(srcTex); + + PackPixelsParams packParams(safeArea, format, type, outputPitch, pack, 0); + gl::Error error = packPixels(stagingTex, packParams, pixels); + + SafeRelease(stagingTex); + + return error; +} + +gl::Error Renderer11::packPixels(ID3D11Texture2D *readTexture, const PackPixelsParams ¶ms, uint8_t *pixelsOut) +{ + D3D11_TEXTURE2D_DESC textureDesc; + readTexture->GetDesc(&textureDesc); + + D3D11_MAPPED_SUBRESOURCE mapping; + HRESULT hr = mDeviceContext->Map(readTexture, 0, D3D11_MAP_READ, 0, &mapping); + if (FAILED(hr)) + { + ASSERT(hr == E_OUTOFMEMORY); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to map internal texture for reading, result: 0x%X.", hr); + } + + uint8_t *source; + int inputPitch; + if (params.pack.reverseRowOrder) + { + source = static_cast(mapping.pData) + mapping.RowPitch * (params.area.height - 1); + inputPitch = -static_cast(mapping.RowPitch); + } + else + { + source = static_cast(mapping.pData); + inputPitch = static_cast(mapping.RowPitch); + } + + const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(textureDesc.Format); + const gl::InternalFormat &sourceFormatInfo = gl::GetInternalFormatInfo(dxgiFormatInfo.internalFormat); + if (sourceFormatInfo.format == params.format && sourceFormatInfo.type == params.type) + { + uint8_t *dest = pixelsOut + params.offset; + for (int y = 0; y < params.area.height; y++) + { + memcpy(dest + y * params.outputPitch, source + y * inputPitch, params.area.width * sourceFormatInfo.pixelBytes); + } + } + else + { + const d3d11::DXGIFormat &sourceDXGIFormatInfo = d3d11::GetDXGIFormatInfo(textureDesc.Format); + ColorCopyFunction fastCopyFunc = sourceDXGIFormatInfo.getFastCopyFunction(params.format, params.type); + + GLenum sizedDestInternalFormat = gl::GetSizedInternalFormat(params.format, params.type); + const gl::InternalFormat &destFormatInfo = gl::GetInternalFormatInfo(sizedDestInternalFormat); + + if (fastCopyFunc) + { + // Fast copy is possible through some special function + for (int y = 0; y < params.area.height; y++) + { + for (int x = 0; x < params.area.width; x++) + { + uint8_t *dest = pixelsOut + params.offset + y * params.outputPitch + x * destFormatInfo.pixelBytes; + const uint8_t *src = source + y * inputPitch + x * sourceFormatInfo.pixelBytes; + + fastCopyFunc(src, dest); + } + } + } + else + { + ColorReadFunction colorReadFunction = sourceDXGIFormatInfo.colorReadFunction; + ColorWriteFunction colorWriteFunction = GetColorWriteFunction(params.format, params.type); + + uint8_t temp[16]; // Maximum size of any Color type used. + static_assert(sizeof(temp) >= sizeof(gl::ColorF) && + sizeof(temp) >= sizeof(gl::ColorUI) && + sizeof(temp) >= sizeof(gl::ColorI), + "Unexpected size of gl::Color struct."); + + for (int y = 0; y < params.area.height; y++) + { + for (int x = 0; x < params.area.width; x++) + { + uint8_t *dest = pixelsOut + params.offset + y * params.outputPitch + x * destFormatInfo.pixelBytes; + const uint8_t *src = source + y * inputPitch + x * sourceFormatInfo.pixelBytes; + + // readFunc and writeFunc will be using the same type of color, CopyTexImage + // will not allow the copy otherwise. + colorReadFunction(src, temp); + colorWriteFunction(temp, dest); + } + } + } + } + + mDeviceContext->Unmap(readTexture, 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) +{ + // 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); + if (!drawRenderTarget) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to retrieve the internal draw render target from the draw framebuffer."); + } + + ID3D11Resource *drawTexture = drawRenderTarget11->getTexture(); + unsigned int drawSubresource = drawRenderTarget11->getSubresourceIndex(); + ID3D11RenderTargetView *drawRTV = drawRenderTarget11->getRenderTargetView(); + ID3D11DepthStencilView *drawDSV = drawRenderTarget11->getDepthStencilView(); + + RenderTarget11 *readRenderTarget11 = RenderTarget11::makeRenderTarget11(readRenderTarget); + if (!readRenderTarget) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to retrieve the internal read render target from the read framebuffer."); + } + + ID3D11Resource *readTexture = NULL; + ID3D11ShaderResourceView *readSRV = NULL; + unsigned int readSubresource = 0; + if (readRenderTarget->getSamples() > 0) + { + ID3D11Resource *unresolvedResource = readRenderTarget11->getTexture(); + ID3D11Texture2D *unresolvedTexture = d3d11::DynamicCastComObject(unresolvedResource); + + if (unresolvedTexture) + { + readTexture = resolveMultisampledTexture(unresolvedTexture, readRenderTarget11->getSubresourceIndex()); + readSubresource = 0; + + SafeRelease(unresolvedTexture); + + HRESULT hresult = mDevice->CreateShaderResourceView(readTexture, NULL, &readSRV); + if (FAILED(hresult)) + { + SafeRelease(readTexture); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create shader resource view to resolve multisampled framebuffer."); + } + } + } + else + { + readTexture = readRenderTarget11->getTexture(); + readTexture->AddRef(); + readSubresource = readRenderTarget11->getSubresourceIndex(); + readSRV = readRenderTarget11->getShaderResourceView(); + readSRV->AddRef(); + } + + if (!readTexture || !readSRV) + { + SafeRelease(readTexture); + SafeRelease(readSRV); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to retrieve the internal read render target view from the read render target."); + } + + gl::Extents readSize(readRenderTarget->getWidth(), readRenderTarget->getHeight(), 1); + gl::Extents drawSize(drawRenderTarget->getWidth(), drawRenderTarget->getHeight(), 1); + + 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; + + bool stretchRequired = readRect.width != drawRect.width || readRect.height != drawRect.height; + + bool flipRequired = readRect.width < 0 || readRect.height < 0 || drawRect.width < 0 || drawRect.height < 0; + + bool outOfBounds = readRect.x < 0 || readRect.x + readRect.width > readSize.width || + readRect.y < 0 || readRect.y + readRect.height > readSize.height || + 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)) + { + UINT dstX = drawRect.x; + UINT dstY = drawRect.y; + + D3D11_BOX readBox; + readBox.left = readRect.x; + readBox.right = readRect.x + readRect.width; + readBox.top = readRect.y; + readBox.bottom = readRect.y + readRect.height; + readBox.front = 0; + readBox.back = 1; + + if (scissorNeeded) + { + // drawRect is guaranteed to have positive width and height because stretchRequired is false. + ASSERT(drawRect.width >= 0 || drawRect.height >= 0); + + if (drawRect.x < scissor->x) + { + dstX = scissor->x; + readBox.left += (scissor->x - drawRect.x); + } + if (drawRect.y < scissor->y) + { + dstY = scissor->y; + readBox.top += (scissor->y - drawRect.y); + } + if (drawRect.x + drawRect.width > scissor->x + scissor->width) + { + readBox.right -= ((drawRect.x + drawRect.width) - (scissor->x + scissor->width)); + } + if (drawRect.y + drawRect.height > scissor->y + scissor->height) + { + readBox.bottom -= ((drawRect.y + drawRect.height) - (scissor->y + scissor->height)); + } + } + + // D3D11 needs depth-stencil CopySubresourceRegions to have a NULL pSrcBox + // We also require complete framebuffer copies for depth-stencil blit. + D3D11_BOX *pSrcBox = wholeBufferCopy ? NULL : &readBox; + + mDeviceContext->CopySubresourceRegion(drawTexture, drawSubresource, dstX, dstY, 0, + readTexture, readSubresource, pSrcBox); + result = gl::Error(GL_NO_ERROR); + } + else + { + gl::Box readArea(readRect.x, readRect.y, 0, readRect.width, readRect.height, 1); + gl::Box drawArea(drawRect.x, drawRect.y, 0, drawRect.width, drawRect.height, 1); + + if (depthBlit && stencilBlit) + { + result = mBlit->copyDepthStencil(readTexture, readSubresource, readArea, readSize, + drawTexture, drawSubresource, drawArea, drawSize, + scissor); + } + else if (depthBlit) + { + result = mBlit->copyDepth(readSRV, readArea, readSize, drawDSV, drawArea, drawSize, + scissor); + } + else if (stencilBlit) + { + result = mBlit->copyStencil(readTexture, readSubresource, readArea, readSize, + drawTexture, drawSubresource, drawArea, drawSize, + scissor); + } + else + { + GLenum format = gl::GetInternalFormatInfo(drawRenderTarget->getInternalFormat()).format; + result = mBlit->copyTexture(readSRV, readArea, readSize, drawRTV, drawArea, drawSize, + scissor, format, filter); + } + } + + SafeRelease(readTexture); + SafeRelease(readSRV); + + return result; +} + +bool Renderer11::isES3Capable() const +{ + return (d3d11_gl::GetMaximumClientVersion(mFeatureLevel) > 2); +}; + +ID3D11Texture2D *Renderer11::resolveMultisampledTexture(ID3D11Texture2D *source, unsigned int subresource) +{ + D3D11_TEXTURE2D_DESC textureDesc; + source->GetDesc(&textureDesc); + + if (textureDesc.SampleDesc.Count > 1) + { + D3D11_TEXTURE2D_DESC resolveDesc; + resolveDesc.Width = textureDesc.Width; + resolveDesc.Height = textureDesc.Height; + resolveDesc.MipLevels = 1; + resolveDesc.ArraySize = 1; + resolveDesc.Format = textureDesc.Format; + resolveDesc.SampleDesc.Count = 1; + resolveDesc.SampleDesc.Quality = 0; + resolveDesc.Usage = textureDesc.Usage; + resolveDesc.BindFlags = textureDesc.BindFlags; + resolveDesc.CPUAccessFlags = 0; + resolveDesc.MiscFlags = 0; + + ID3D11Texture2D *resolveTexture = NULL; + HRESULT result = mDevice->CreateTexture2D(&resolveDesc, NULL, &resolveTexture); + if (FAILED(result)) + { + ERR("Failed to create a multisample resolve texture, HRESULT: 0x%X.", result); + return NULL; + } + + mDeviceContext->ResolveSubresource(resolveTexture, 0, source, subresource, textureDesc.Format); + return resolveTexture; + } + else + { + source->AddRef(); + return source; + } +} + +bool Renderer11::getLUID(LUID *adapterLuid) const +{ + adapterLuid->HighPart = 0; + adapterLuid->LowPart = 0; + + if (!mDxgiAdapter) + { + return false; + } + + DXGI_ADAPTER_DESC adapterDesc; + if (FAILED(mDxgiAdapter->GetDesc(&adapterDesc))) + { + return false; + } + + *adapterLuid = adapterDesc.AdapterLuid; + return true; +} + +VertexConversionType Renderer11::getVertexConversionType(const gl::VertexFormat &vertexFormat) const +{ + return d3d11::GetVertexFormatInfo(vertexFormat, mFeatureLevel).conversionType; +} + +GLenum Renderer11::getVertexComponentType(const gl::VertexFormat &vertexFormat) const +{ + return d3d11::GetDXGIFormatInfo(d3d11::GetVertexFormatInfo(vertexFormat, mFeatureLevel).nativeFormat).componentType; +} + +void Renderer11::generateCaps(gl::Caps *outCaps, gl::TextureCapsMap *outTextureCaps, gl::Extensions *outExtensions) const +{ + d3d11_gl::GenerateCaps(mDevice, mDeviceContext, outCaps, outTextureCaps, outExtensions); +} + +Workarounds Renderer11::generateWorkarounds() const +{ + return d3d11::GenerateWorkarounds(mFeatureLevel); +} + +void Renderer11::setShaderResource(gl::SamplerType shaderType, UINT resourceSlot, ID3D11ShaderResourceView *srv) +{ + auto ¤tSRVs = (shaderType == gl::SAMPLER_VERTEX ? mCurVertexSRVs : mCurPixelSRVs); + + ASSERT(static_cast(resourceSlot) < currentSRVs.size()); + auto &record = currentSRVs[resourceSlot]; + + if (record.srv != reinterpret_cast(srv)) + { + if (shaderType == gl::SAMPLER_VERTEX) + { + mDeviceContext->VSSetShaderResources(resourceSlot, 1, &srv); + } + else + { + mDeviceContext->PSSetShaderResources(resourceSlot, 1, &srv); + } + + record.srv = reinterpret_cast(srv); + if (srv) + { + record.resource = reinterpret_cast(GetViewResource(srv)); + srv->GetDesc(&record.desc); + } + else + { + record.resource = 0; + } + } +} +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Renderer11.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Renderer11.h new file mode 100644 index 0000000000..cc7d6c237b --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Renderer11.h @@ -0,0 +1,400 @@ +// +// Copyright (c) 2012-2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Renderer11.h: Defines a back-end specific class for the D3D11 renderer. + +#ifndef LIBANGLE_RENDERER_D3D_D3D11_RENDERER11_H_ +#define LIBANGLE_RENDERER_D3D_D3D11_RENDERER11_H_ + +#include "common/angleutils.h" +#include "common/mathutil.h" +#include "libANGLE/AttributeMap.h" +#include "libANGLE/angletypes.h" +#include "libANGLE/renderer/d3d/HLSLCompiler.h" +#include "libANGLE/renderer/d3d/RendererD3D.h" +#include "libANGLE/renderer/d3d/RenderTargetD3D.h" +#include "libANGLE/renderer/d3d/d3d11/DebugAnnotator11.h" +#include "libANGLE/renderer/d3d/d3d11/InputLayoutCache.h" +#include "libANGLE/renderer/d3d/d3d11/RenderStateCache.h" + +struct ID3D11DeviceContext1; + +namespace gl +{ +class FramebufferAttachment; +struct ImageIndex; +} + +namespace rx +{ + +class VertexDataManager; +class IndexDataManager; +class StreamingIndexBufferInterface; +class Blit11; +class Clear11; +class PixelTransfer11; +class RenderTarget11; +class Trim11; +struct PackPixelsParams; + +enum +{ + MAX_VERTEX_UNIFORM_VECTORS_D3D11 = 1024, + MAX_FRAGMENT_UNIFORM_VECTORS_D3D11 = 1024 +}; + +// Possible reasons RendererD3D initialize can fail +enum D3D11InitError +{ + // The renderer loaded successfully + D3D11_INIT_SUCCESS = 0, + // Failed to load the ANGLE & D3D compiler libraries + D3D11_INIT_COMPILER_ERROR, + // Failed to load a necessary DLL (non-compiler) + D3D11_INIT_MISSING_DEP, + // CreateDevice returned E_INVALIDARG + D3D11_INIT_CREATEDEVICE_INVALIDARG, + // CreateDevice failed with an error other than invalid arg + D3D11_INIT_CREATEDEVICE_ERROR, + // DXGI 1.2 required but not found + D3D11_INIT_INCOMPATIBLE_DXGI, + // Other initialization error + D3D11_INIT_OTHER_ERROR, + NUM_D3D11_INIT_ERRORS +}; + +class Renderer11 : public RendererD3D +{ + public: + explicit Renderer11(egl::Display *display); + virtual ~Renderer11(); + + static Renderer11 *makeRenderer11(Renderer *renderer); + + egl::Error initialize() override; + virtual bool resetDevice(); + + egl::ConfigSet generateConfigs() const override; + + gl::Error flush() override; + gl::Error finish() override; + + virtual SwapChainD3D *createSwapChain(NativeWindow nativeWindow, HANDLE shareHandle, GLenum backBufferFormat, GLenum depthBufferFormat); + + virtual gl::Error generateSwizzle(gl::Texture *texture); + virtual gl::Error setSamplerState(gl::SamplerType type, int index, gl::Texture *texture, const gl::SamplerState &sampler); + virtual gl::Error setTexture(gl::SamplerType type, int index, gl::Texture *texture); + + gl::Error setUniformBuffers(const gl::Data &data, + const GLint vertexUniformBuffers[], + const GLint fragmentUniformBuffers[]) override; + + virtual gl::Error setRasterizerState(const gl::RasterizerState &rasterState); + gl::Error setBlendState(const gl::Framebuffer *framebuffer, const gl::BlendState &blendState, const gl::ColorF &blendColor, + unsigned int sampleMask) override; + virtual gl::Error setDepthStencilState(const gl::DepthStencilState &depthStencilState, int stencilRef, + int stencilBackRef, bool frontFaceCCW); + + virtual void setScissorRectangle(const gl::Rectangle &scissor, bool enabled); + virtual void setViewport(const gl::Rectangle &viewport, float zNear, float zFar, GLenum drawMode, GLenum frontFace, + bool ignoreViewport); + + virtual bool applyPrimitiveType(GLenum mode, GLsizei count, bool usesPointSize); + gl::Error applyRenderTarget(const gl::Framebuffer *frameBuffer) override; + virtual gl::Error applyShaders(gl::Program *program, const gl::VertexFormat inputLayout[], const gl::Framebuffer *framebuffer, + bool rasterizerDiscard, bool transformFeedbackActive); + + virtual gl::Error applyUniforms(const ProgramImpl &program, const std::vector &uniformArray); + virtual gl::Error applyVertexBuffer(const gl::State &state, GLenum mode, GLint first, GLsizei count, GLsizei instances); + virtual gl::Error applyIndexBuffer(const GLvoid *indices, gl::Buffer *elementArrayBuffer, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo); + void applyTransformFeedbackBuffers(const gl::State &state) override; + + gl::Error drawArrays(const gl::Data &data, GLenum mode, GLsizei count, GLsizei instances, bool usesPointSize) override; + virtual gl::Error drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, + gl::Buffer *elementArrayBuffer, const TranslatedIndexData &indexInfo, GLsizei instances); + + virtual void markAllStateDirty(); + + // lost device + bool testDeviceLost() override; + bool testDeviceResettable() override; + + VendorID getVendorId() const override; + std::string getRendererDescription() const override; + GUID getAdapterIdentifier() const override; + + virtual unsigned int getReservedVertexUniformVectors() const; + virtual unsigned int getReservedFragmentUniformVectors() const; + virtual unsigned int getReservedVertexUniformBuffers() const; + virtual unsigned int getReservedFragmentUniformBuffers() const; + virtual bool getShareHandleSupport() const; + virtual bool getPostSubBufferSupport() const; + + virtual int getMajorShaderModel() const; + int getMinorShaderModel() const override; + std::string getShaderModelSuffix() const override; + + // Pixel operations + virtual gl::Error copyImage2D(const gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, + const gl::Offset &destOffset, TextureStorage *storage, GLint level); + virtual gl::Error copyImageCube(const gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, + const gl::Offset &destOffset, TextureStorage *storage, GLenum target, GLint level); + virtual gl::Error copyImage3D(const gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, + const gl::Offset &destOffset, TextureStorage *storage, GLint level); + virtual gl::Error copyImage2DArray(const gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, + const gl::Offset &destOffset, TextureStorage *storage, GLint level); + + // RenderTarget creation + virtual gl::Error createRenderTarget(int width, int height, GLenum format, GLsizei samples, RenderTargetD3D **outRT); + + // Framebuffer creation + FramebufferImpl *createDefaultFramebuffer(const gl::Framebuffer::Data &data) override; + FramebufferImpl *createFramebuffer(const gl::Framebuffer::Data &data) override; + + // Shader creation + virtual CompilerImpl *createCompiler(const gl::Data &data); + virtual ShaderImpl *createShader(GLenum type); + virtual ProgramImpl *createProgram(); + + // Shader operations + virtual gl::Error loadExecutable(const void *function, size_t length, ShaderType type, + const std::vector &transformFeedbackVaryings, + bool separatedOutputBuffers, ShaderExecutableD3D **outExecutable); + virtual gl::Error compileToExecutable(gl::InfoLog &infoLog, const std::string &shaderHLSL, ShaderType type, + const std::vector &transformFeedbackVaryings, + bool separatedOutputBuffers, const D3DCompilerWorkarounds &workarounds, + ShaderExecutableD3D **outExectuable); + virtual UniformStorageD3D *createUniformStorage(size_t storageSize); + + // Image operations + virtual ImageD3D *createImage(); + gl::Error generateMipmap(ImageD3D *dest, ImageD3D *source) override; + virtual TextureStorage *createTextureStorage2D(SwapChainD3D *swapChain); + virtual TextureStorage *createTextureStorage2D(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels, bool hintLevelZeroOnly); + virtual TextureStorage *createTextureStorageCube(GLenum internalformat, bool renderTarget, int size, int levels, bool hintLevelZeroOnly); + virtual TextureStorage *createTextureStorage3D(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth, int levels); + virtual TextureStorage *createTextureStorage2DArray(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth, int levels); + + // Texture creation + virtual TextureImpl *createTexture(GLenum target); + + // Renderbuffer creation + virtual RenderbufferImpl *createRenderbuffer(); + + // Buffer creation + virtual BufferImpl *createBuffer(); + virtual VertexBuffer *createVertexBuffer(); + virtual IndexBuffer *createIndexBuffer(); + + // Vertex Array creation + virtual VertexArrayImpl *createVertexArray(); + + // Query and Fence creation + virtual QueryImpl *createQuery(GLenum type); + virtual FenceNVImpl *createFenceNV(); + virtual FenceSyncImpl *createFenceSync(); + + // Transform Feedback creation + virtual TransformFeedbackImpl* createTransformFeedback(); + + // D3D11-renderer specific methods + ID3D11Device *getDevice() { return mDevice; } + ID3D11DeviceContext *getDeviceContext() { return mDeviceContext; }; + ID3D11DeviceContext1 *getDeviceContext1IfSupported() { return mDeviceContext1; }; + DXGIFactory *getDxgiFactory() { return mDxgiFactory; }; + + Blit11 *getBlitter() { return mBlit; } + Clear11 *getClearer() { return mClear; } + + // Buffer-to-texture and Texture-to-buffer copies + virtual bool supportsFastCopyBufferToTexture(GLenum internalFormat) const; + virtual gl::Error fastCopyBufferToTexture(const gl::PixelUnpackState &unpack, unsigned int offset, RenderTargetD3D *destRenderTarget, + GLenum destinationFormat, GLenum sourcePixelsType, const gl::Box &destArea); + + void unapplyRenderTargets(); + void setOneTimeRenderTarget(ID3D11RenderTargetView *renderTargetView); + gl::Error packPixels(ID3D11Texture2D *readTexture, const PackPixelsParams ¶ms, uint8_t *pixelsOut); + + bool getLUID(LUID *adapterLuid) const override; + virtual VertexConversionType getVertexConversionType(const gl::VertexFormat &vertexFormat) const; + virtual GLenum getVertexComponentType(const gl::VertexFormat &vertexFormat) const; + + gl::Error readTextureData(ID3D11Texture2D *texture, unsigned int subResource, const gl::Rectangle &area, GLenum format, + GLenum type, GLuint outputPitch, const gl::PixelPackState &pack, uint8_t *pixels); + + void setShaderResource(gl::SamplerType shaderType, UINT resourceSlot, ID3D11ShaderResourceView *srv); + + gl::Error 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); + + bool isES3Capable() const; + D3D_FEATURE_LEVEL getFeatureLevel() const { return mFeatureLevel; }; + + RendererClass getRendererClass() const override { return RENDERER_D3D11; } + + private: + void generateCaps(gl::Caps *outCaps, gl::TextureCapsMap *outTextureCaps, gl::Extensions *outExtensions) const override; + Workarounds generateWorkarounds() const override; + + gl::Error drawLineLoop(GLsizei count, GLenum type, const GLvoid *indices, int minIndex, gl::Buffer *elementArrayBuffer); + gl::Error drawTriangleFan(GLsizei count, GLenum type, const GLvoid *indices, int minIndex, gl::Buffer *elementArrayBuffer, int instances); + + ID3D11Texture2D *resolveMultisampledTexture(ID3D11Texture2D *source, unsigned int subresource); + void unsetConflictingSRVs(gl::SamplerType shaderType, uintptr_t resource, const gl::ImageIndex *index); + + HMODULE mD3d11Module; + HMODULE mDxgiModule; + std::vector mAvailableFeatureLevels; + D3D_DRIVER_TYPE mDriverType; + + HLSLCompiler mCompiler; + + void initializeDevice(); + void releaseDeviceResources(); + void release(); + + RenderStateCache mStateCache; + + // current render target states + uintptr_t mAppliedRTVs[gl::IMPLEMENTATION_MAX_DRAW_BUFFERS]; + uintptr_t mAppliedDSV; + bool mDepthStencilInitialized; + bool mRenderTargetDescInitialized; + + struct RenderTargetDesc + { + size_t width; + size_t height; + DXGI_FORMAT format; + }; + RenderTargetDesc mRenderTargetDesc; + + // Currently applied sampler states + std::vector mForceSetVertexSamplerStates; + std::vector mCurVertexSamplerStates; + + std::vector mForceSetPixelSamplerStates; + std::vector mCurPixelSamplerStates; + + // Currently applied textures + struct SRVRecord + { + uintptr_t srv; + uintptr_t resource; + D3D11_SHADER_RESOURCE_VIEW_DESC desc; + }; + std::vector mCurVertexSRVs; + std::vector mCurPixelSRVs; + + // Currently applied blend state + bool mForceSetBlendState; + gl::BlendState mCurBlendState; + gl::ColorF mCurBlendColor; + unsigned int mCurSampleMask; + + // Currently applied rasterizer state + bool mForceSetRasterState; + gl::RasterizerState mCurRasterState; + + // Currently applied depth stencil state + bool mForceSetDepthStencilState; + gl::DepthStencilState mCurDepthStencilState; + int mCurStencilRef; + int mCurStencilBackRef; + + // Currently applied scissor rectangle + bool mForceSetScissor; + bool mScissorEnabled; + gl::Rectangle mCurScissor; + + // Currently applied viewport + bool mForceSetViewport; + gl::Rectangle mCurViewport; + float mCurNear; + float mCurFar; + + // Currently applied primitive topology + D3D11_PRIMITIVE_TOPOLOGY mCurrentPrimitiveTopology; + + // Currently applied index buffer + ID3D11Buffer *mAppliedIB; + DXGI_FORMAT mAppliedIBFormat; + unsigned int mAppliedIBOffset; + + // Currently applied transform feedback buffers + size_t mAppliedNumXFBBindings; + ID3D11Buffer *mAppliedTFBuffers[gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS]; // Tracks the current D3D buffers + // in use for streamout + GLintptr mAppliedTFOffsets[gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS]; // Tracks the current GL-specified + // buffer offsets to transform feedback + // buffers + UINT mCurrentD3DOffsets[gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS]; // Tracks the D3D buffer offsets, + // which may differ from GLs, due + // to different append behavior + + // Currently applied shaders + uintptr_t mAppliedVertexShader; + uintptr_t mAppliedGeometryShader; + uintptr_t mAppliedPixelShader; + + dx_VertexConstants mVertexConstants; + dx_VertexConstants mAppliedVertexConstants; + ID3D11Buffer *mDriverConstantBufferVS; + ID3D11Buffer *mCurrentVertexConstantBuffer; + unsigned int mCurrentConstantBufferVS[gl::IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS]; + GLintptr mCurrentConstantBufferVSOffset[gl::IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS]; + GLsizeiptr mCurrentConstantBufferVSSize[gl::IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS]; + + dx_PixelConstants mPixelConstants; + dx_PixelConstants mAppliedPixelConstants; + ID3D11Buffer *mDriverConstantBufferPS; + ID3D11Buffer *mCurrentPixelConstantBuffer; + unsigned int mCurrentConstantBufferPS[gl::IMPLEMENTATION_MAX_FRAGMENT_SHADER_UNIFORM_BUFFERS]; + GLintptr mCurrentConstantBufferPSOffset[gl::IMPLEMENTATION_MAX_FRAGMENT_SHADER_UNIFORM_BUFFERS]; + GLsizeiptr mCurrentConstantBufferPSSize[gl::IMPLEMENTATION_MAX_FRAGMENT_SHADER_UNIFORM_BUFFERS]; + + ID3D11Buffer *mCurrentGeometryConstantBuffer; + + // Vertex, index and input layouts + VertexDataManager *mVertexDataManager; + IndexDataManager *mIndexDataManager; + InputLayoutCache mInputLayoutCache; + + StreamingIndexBufferInterface *mLineLoopIB; + StreamingIndexBufferInterface *mTriangleFanIB; + + // Texture copy resources + Blit11 *mBlit; + PixelTransfer11 *mPixelTransfer; + + // Masked clear resources + Clear11 *mClear; + + // Perform trim for D3D resources + Trim11 *mTrim; + + // Sync query + ID3D11Query *mSyncQuery; + + // Constant buffer offset support + bool mSupportsConstantBufferOffsets; + + ID3D11Device *mDevice; + D3D_FEATURE_LEVEL mFeatureLevel; + ID3D11DeviceContext *mDeviceContext; + ID3D11DeviceContext1 *mDeviceContext1; + IDXGIAdapter *mDxgiAdapter; + DXGI_ADAPTER_DESC mAdapterDescription; + char mDescription[128]; + DXGIFactory *mDxgiFactory; + + DebugAnnotator11 mAnnotator; +}; + +} +#endif // LIBANGLE_RENDERER_D3D_D3D11_RENDERER11_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/ShaderExecutable11.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/ShaderExecutable11.cpp new file mode 100644 index 0000000000..7e64c3183d --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/ShaderExecutable11.cpp @@ -0,0 +1,110 @@ +// +// Copyright (c) 2012-2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// ShaderExecutable11.cpp: Implements a D3D11-specific class to contain shader +// executable implementation details. + +#include "libANGLE/renderer/d3d/d3d11/ShaderExecutable11.h" +#include "libANGLE/renderer/d3d/d3d11/Renderer11.h" + +namespace rx +{ + +ShaderExecutable11::ShaderExecutable11(const void *function, size_t length, ID3D11PixelShader *executable) + : ShaderExecutableD3D(function, length) +{ + mPixelExecutable = executable; + mVertexExecutable = NULL; + mGeometryExecutable = NULL; + mStreamOutExecutable = NULL; +} + +ShaderExecutable11::ShaderExecutable11(const void *function, size_t length, ID3D11VertexShader *executable, ID3D11GeometryShader *streamOut) + : ShaderExecutableD3D(function, length) +{ + mVertexExecutable = executable; + mPixelExecutable = NULL; + mGeometryExecutable = NULL; + mStreamOutExecutable = streamOut; +} + +ShaderExecutable11::ShaderExecutable11(const void *function, size_t length, ID3D11GeometryShader *executable) + : ShaderExecutableD3D(function, length) +{ + mGeometryExecutable = executable; + mVertexExecutable = NULL; + mPixelExecutable = NULL; + mStreamOutExecutable = NULL; +} + +ShaderExecutable11::~ShaderExecutable11() +{ + SafeRelease(mVertexExecutable); + SafeRelease(mPixelExecutable); + SafeRelease(mGeometryExecutable); + SafeRelease(mStreamOutExecutable); +} + +ShaderExecutable11 *ShaderExecutable11::makeShaderExecutable11(ShaderExecutableD3D *executable) +{ + ASSERT(HAS_DYNAMIC_TYPE(ShaderExecutable11*, executable)); + return static_cast(executable); +} + +ID3D11VertexShader *ShaderExecutable11::getVertexShader() const +{ + return mVertexExecutable; +} + +ID3D11PixelShader *ShaderExecutable11::getPixelShader() const +{ + return mPixelExecutable; +} + +ID3D11GeometryShader *ShaderExecutable11::getGeometryShader() const +{ + return mGeometryExecutable; +} + +ID3D11GeometryShader *ShaderExecutable11::getStreamOutShader() const +{ + return mStreamOutExecutable; +} + +UniformStorage11::UniformStorage11(Renderer11 *renderer, size_t initialSize) + : UniformStorageD3D(initialSize), + mConstantBuffer(NULL) +{ + ID3D11Device *d3d11Device = renderer->getDevice(); + + if (initialSize > 0) + { + D3D11_BUFFER_DESC constantBufferDescription = {0}; + constantBufferDescription.ByteWidth = initialSize; + constantBufferDescription.Usage = D3D11_USAGE_DYNAMIC; + constantBufferDescription.BindFlags = D3D11_BIND_CONSTANT_BUFFER; + constantBufferDescription.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + constantBufferDescription.MiscFlags = 0; + constantBufferDescription.StructureByteStride = 0; + + HRESULT result = d3d11Device->CreateBuffer(&constantBufferDescription, NULL, &mConstantBuffer); + UNUSED_ASSERTION_VARIABLE(result); + ASSERT(SUCCEEDED(result)); + } +} + +UniformStorage11::~UniformStorage11() +{ + SafeRelease(mConstantBuffer); +} + +const UniformStorage11 *UniformStorage11::makeUniformStorage11(const UniformStorageD3D *uniformStorage) +{ + ASSERT(HAS_DYNAMIC_TYPE(const UniformStorage11*, uniformStorage)); + return static_cast(uniformStorage); +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/ShaderExecutable11.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/ShaderExecutable11.h new file mode 100644 index 0000000000..02558ee4dc --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/ShaderExecutable11.h @@ -0,0 +1,59 @@ +// +// Copyright (c) 2012-2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// ShaderExecutable11.h: Defines a D3D11-specific class to contain shader +// executable implementation details. + +#ifndef LIBANGLE_RENDERER_D3D_D3D11_SHADEREXECUTABLE11_H_ +#define LIBANGLE_RENDERER_D3D_D3D11_SHADEREXECUTABLE11_H_ + +#include "libANGLE/renderer/d3d/ShaderExecutableD3D.h" + +namespace rx +{ +class Renderer11; +class UniformStorage11; + +class ShaderExecutable11 : public ShaderExecutableD3D +{ + public: + ShaderExecutable11(const void *function, size_t length, ID3D11PixelShader *executable); + ShaderExecutable11(const void *function, size_t length, ID3D11VertexShader *executable, ID3D11GeometryShader *streamOut); + ShaderExecutable11(const void *function, size_t length, ID3D11GeometryShader *executable); + + virtual ~ShaderExecutable11(); + + static ShaderExecutable11 *makeShaderExecutable11(ShaderExecutableD3D *executable); + + ID3D11PixelShader *getPixelShader() const; + ID3D11VertexShader *getVertexShader() const; + ID3D11GeometryShader *getGeometryShader() const; + ID3D11GeometryShader *getStreamOutShader() const; + + private: + ID3D11PixelShader *mPixelExecutable; + ID3D11VertexShader *mVertexExecutable; + ID3D11GeometryShader *mGeometryExecutable; + ID3D11GeometryShader *mStreamOutExecutable; +}; + +class UniformStorage11 : public UniformStorageD3D +{ + public: + UniformStorage11(Renderer11 *renderer, size_t initialSize); + virtual ~UniformStorage11(); + + static const UniformStorage11 *makeUniformStorage11(const UniformStorageD3D *uniformStorage); + + ID3D11Buffer *getConstantBuffer() const { return mConstantBuffer; } + + private: + ID3D11Buffer *mConstantBuffer; +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_D3D11_SHADEREXECUTABLE11_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/SwapChain11.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/SwapChain11.cpp new file mode 100644 index 0000000000..298f3ccbd2 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/SwapChain11.cpp @@ -0,0 +1,711 @@ +// +// Copyright (c) 2012-2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// SwapChain11.cpp: Implements a back-end specific class for the D3D11 swap chain. + +#include "libANGLE/renderer/d3d/d3d11/SwapChain11.h" +#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h" +#include "libANGLE/renderer/d3d/d3d11/formatutils11.h" +#include "libANGLE/renderer/d3d/d3d11/Renderer11.h" +#include "libANGLE/renderer/d3d/d3d11/NativeWindow.h" +#include "libANGLE/features.h" + +// Precompiled shaders +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthrough2d11vs.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrgba2d11ps.h" + + +namespace rx +{ + +SwapChain11::SwapChain11(Renderer11 *renderer, NativeWindow nativeWindow, HANDLE shareHandle, + GLenum backBufferFormat, GLenum depthBufferFormat) + : mRenderer(renderer), + SwapChainD3D(nativeWindow, shareHandle, backBufferFormat, depthBufferFormat), + mColorRenderTarget(this, renderer, false), + mDepthStencilRenderTarget(this, renderer, true) +{ + mSwapChain = NULL; + mBackBufferTexture = NULL; + mBackBufferRTView = NULL; + mOffscreenTexture = NULL; + mOffscreenRTView = NULL; + mOffscreenSRView = NULL; + mDepthStencilTexture = NULL; + mDepthStencilDSView = NULL; + mDepthStencilSRView = NULL; + mQuadVB = NULL; + mPassThroughSampler = NULL; + mPassThroughIL = NULL; + mPassThroughVS = NULL; + mPassThroughPS = NULL; + mWidth = -1; + mHeight = -1; + mSwapInterval = 0; + mAppCreatedShareHandle = mShareHandle != NULL; + mPassThroughResourcesInit = false; +} + +SwapChain11::~SwapChain11() +{ + release(); +} + +void SwapChain11::release() +{ + SafeRelease(mSwapChain); + SafeRelease(mBackBufferTexture); + SafeRelease(mBackBufferRTView); + SafeRelease(mOffscreenTexture); + SafeRelease(mOffscreenRTView); + SafeRelease(mOffscreenSRView); + SafeRelease(mDepthStencilTexture); + SafeRelease(mDepthStencilDSView); + SafeRelease(mDepthStencilSRView); + SafeRelease(mQuadVB); + SafeRelease(mPassThroughSampler); + SafeRelease(mPassThroughIL); + SafeRelease(mPassThroughVS); + SafeRelease(mPassThroughPS); + + if (!mAppCreatedShareHandle) + { + mShareHandle = NULL; + } +} + +void SwapChain11::releaseOffscreenTexture() +{ + SafeRelease(mOffscreenTexture); + SafeRelease(mOffscreenRTView); + SafeRelease(mOffscreenSRView); + SafeRelease(mDepthStencilTexture); + SafeRelease(mDepthStencilDSView); + SafeRelease(mDepthStencilSRView); +} + +EGLint SwapChain11::resetOffscreenTexture(int backbufferWidth, int backbufferHeight) +{ + ID3D11Device *device = mRenderer->getDevice(); + + ASSERT(device != NULL); + + // D3D11 does not allow zero size textures + ASSERT(backbufferWidth >= 1); + ASSERT(backbufferHeight >= 1); + + // Preserve the render target content + ID3D11Texture2D *previousOffscreenTexture = mOffscreenTexture; + if (previousOffscreenTexture) + { + previousOffscreenTexture->AddRef(); + } + const int previousWidth = mWidth; + const int previousHeight = mHeight; + + releaseOffscreenTexture(); + + const d3d11::TextureFormat &backbufferFormatInfo = d3d11::GetTextureFormatInfo(mBackBufferFormat, mRenderer->getFeatureLevel()); + + // If the app passed in a share handle, open the resource + // See EGL_ANGLE_d3d_share_handle_client_buffer + if (mAppCreatedShareHandle) + { + ID3D11Resource *tempResource11; + HRESULT result = device->OpenSharedResource(mShareHandle, __uuidof(ID3D11Resource), (void**)&tempResource11); + + if (FAILED(result)) + { + ERR("Failed to open the swap chain pbuffer share handle: %08lX", result); + release(); + return EGL_BAD_PARAMETER; + } + + result = tempResource11->QueryInterface(__uuidof(ID3D11Texture2D), (void**)&mOffscreenTexture); + SafeRelease(tempResource11); + + if (FAILED(result)) + { + ERR("Failed to query texture2d interface in pbuffer share handle: %08lX", result); + release(); + return EGL_BAD_PARAMETER; + } + + // Validate offscreen texture parameters + D3D11_TEXTURE2D_DESC offscreenTextureDesc = {0}; + mOffscreenTexture->GetDesc(&offscreenTextureDesc); + + if (offscreenTextureDesc.Width != (UINT)backbufferWidth || + offscreenTextureDesc.Height != (UINT)backbufferHeight || + offscreenTextureDesc.Format != backbufferFormatInfo.texFormat || + offscreenTextureDesc.MipLevels != 1 || + offscreenTextureDesc.ArraySize != 1) + { + ERR("Invalid texture parameters in the shared offscreen texture pbuffer"); + release(); + return EGL_BAD_PARAMETER; + } + } + else + { + const bool useSharedResource = !mNativeWindow.getNativeWindow() && mRenderer->getShareHandleSupport(); + + D3D11_TEXTURE2D_DESC offscreenTextureDesc = {0}; +#if defined(ANGLE_ENABLE_WINDOWS_STORE) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) + const int textureLength = std::max(backbufferWidth, backbufferHeight); + offscreenTextureDesc.Width = textureLength; + offscreenTextureDesc.Height = textureLength; +#else + offscreenTextureDesc.Width = backbufferWidth; + offscreenTextureDesc.Height = backbufferHeight; +#endif + offscreenTextureDesc.Format = backbufferFormatInfo.texFormat; + offscreenTextureDesc.MipLevels = 1; + offscreenTextureDesc.ArraySize = 1; + offscreenTextureDesc.SampleDesc.Count = 1; + offscreenTextureDesc.SampleDesc.Quality = 0; + offscreenTextureDesc.Usage = D3D11_USAGE_DEFAULT; + offscreenTextureDesc.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE; + offscreenTextureDesc.CPUAccessFlags = 0; + offscreenTextureDesc.MiscFlags = useSharedResource ? D3D11_RESOURCE_MISC_SHARED : 0; + + HRESULT result = device->CreateTexture2D(&offscreenTextureDesc, NULL, &mOffscreenTexture); + + if (FAILED(result)) + { + ERR("Could not create offscreen texture: %08lX", result); + release(); + + if (d3d11::isDeviceLostError(result)) + { + return EGL_CONTEXT_LOST; + } + else + { + return EGL_BAD_ALLOC; + } + } + + d3d11::SetDebugName(mOffscreenTexture, "Offscreen back buffer texture"); + + // EGL_ANGLE_surface_d3d_texture_2d_share_handle requires that we store a share handle for the client + if (useSharedResource) + { + IDXGIResource *offscreenTextureResource = NULL; + result = mOffscreenTexture->QueryInterface(__uuidof(IDXGIResource), (void**)&offscreenTextureResource); + + // Fall back to no share handle on failure + if (FAILED(result)) + { + ERR("Could not query offscreen texture resource: %08lX", result); + } + else + { + result = offscreenTextureResource->GetSharedHandle(&mShareHandle); + SafeRelease(offscreenTextureResource); + + if (FAILED(result)) + { + mShareHandle = NULL; + ERR("Could not get offscreen texture shared handle: %08lX", result); + } + } + } + } + + + D3D11_RENDER_TARGET_VIEW_DESC offscreenRTVDesc; + offscreenRTVDesc.Format = backbufferFormatInfo.rtvFormat; + offscreenRTVDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; + offscreenRTVDesc.Texture2D.MipSlice = 0; + + HRESULT result = device->CreateRenderTargetView(mOffscreenTexture, &offscreenRTVDesc, &mOffscreenRTView); + ASSERT(SUCCEEDED(result)); + d3d11::SetDebugName(mOffscreenRTView, "Offscreen back buffer render target"); + + D3D11_SHADER_RESOURCE_VIEW_DESC offscreenSRVDesc; + offscreenSRVDesc.Format = backbufferFormatInfo.srvFormat; + offscreenSRVDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; + offscreenSRVDesc.Texture2D.MostDetailedMip = 0; + offscreenSRVDesc.Texture2D.MipLevels = static_cast(-1); + + result = device->CreateShaderResourceView(mOffscreenTexture, &offscreenSRVDesc, &mOffscreenSRView); + ASSERT(SUCCEEDED(result)); + d3d11::SetDebugName(mOffscreenSRView, "Offscreen back buffer shader resource"); + + const d3d11::TextureFormat &depthBufferFormatInfo = d3d11::GetTextureFormatInfo(mDepthBufferFormat, mRenderer->getFeatureLevel()); + + if (mDepthBufferFormat != GL_NONE) + { + D3D11_TEXTURE2D_DESC depthStencilTextureDesc; +#if defined(ANGLE_ENABLE_WINDOWS_STORE) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) + const int textureLength = std::max(backbufferWidth, backbufferHeight); + depthStencilTextureDesc.Width = textureLength; + depthStencilTextureDesc.Height = textureLength; +#else + depthStencilTextureDesc.Width = backbufferWidth; + depthStencilTextureDesc.Height = backbufferHeight; +#endif + depthStencilTextureDesc.Format = depthBufferFormatInfo.texFormat; + depthStencilTextureDesc.MipLevels = 1; + depthStencilTextureDesc.ArraySize = 1; + depthStencilTextureDesc.SampleDesc.Count = 1; + depthStencilTextureDesc.SampleDesc.Quality = 0; + depthStencilTextureDesc.Usage = D3D11_USAGE_DEFAULT; + depthStencilTextureDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL; + + if (depthBufferFormatInfo.srvFormat != DXGI_FORMAT_UNKNOWN) + { + depthStencilTextureDesc.BindFlags |= D3D11_BIND_SHADER_RESOURCE; + } + + depthStencilTextureDesc.CPUAccessFlags = 0; + depthStencilTextureDesc.MiscFlags = 0; + + result = device->CreateTexture2D(&depthStencilTextureDesc, NULL, &mDepthStencilTexture); + if (FAILED(result)) + { + ERR("Could not create depthstencil surface for new swap chain: 0x%08X", result); + release(); + + if (d3d11::isDeviceLostError(result)) + { + return EGL_CONTEXT_LOST; + } + else + { + return EGL_BAD_ALLOC; + } + } + d3d11::SetDebugName(mDepthStencilTexture, "Offscreen depth stencil texture"); + + D3D11_DEPTH_STENCIL_VIEW_DESC depthStencilDesc; + depthStencilDesc.Format = depthBufferFormatInfo.dsvFormat; + depthStencilDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D; + depthStencilDesc.Flags = 0; + depthStencilDesc.Texture2D.MipSlice = 0; + + result = device->CreateDepthStencilView(mDepthStencilTexture, &depthStencilDesc, &mDepthStencilDSView); + ASSERT(SUCCEEDED(result)); + d3d11::SetDebugName(mDepthStencilDSView, "Offscreen depth stencil view"); + + if (depthBufferFormatInfo.srvFormat != DXGI_FORMAT_UNKNOWN) + { + D3D11_SHADER_RESOURCE_VIEW_DESC depthStencilSRVDesc; + depthStencilSRVDesc.Format = depthBufferFormatInfo.srvFormat; + depthStencilSRVDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; + depthStencilSRVDesc.Texture2D.MostDetailedMip = 0; + depthStencilSRVDesc.Texture2D.MipLevels = static_cast(-1); + + result = device->CreateShaderResourceView(mDepthStencilTexture, &depthStencilSRVDesc, &mDepthStencilSRView); + ASSERT(SUCCEEDED(result)); + d3d11::SetDebugName(mDepthStencilSRView, "Offscreen depth stencil shader resource"); + } + } + + mWidth = backbufferWidth; + mHeight = backbufferHeight; + + if (previousOffscreenTexture != NULL) + { + D3D11_BOX sourceBox = {0}; + sourceBox.left = 0; + sourceBox.right = std::min(previousWidth, mWidth); + sourceBox.top = std::max(previousHeight - mHeight, 0); + sourceBox.bottom = previousHeight; + sourceBox.front = 0; + sourceBox.back = 1; + + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); + const int yoffset = std::max(mHeight - previousHeight, 0); + deviceContext->CopySubresourceRegion(mOffscreenTexture, 0, 0, yoffset, 0, previousOffscreenTexture, 0, &sourceBox); + + SafeRelease(previousOffscreenTexture); + + if (mSwapChain) + { + swapRect(0, 0, mWidth, mHeight); + } + } + + return EGL_SUCCESS; +} + +EGLint SwapChain11::resize(EGLint backbufferWidth, EGLint backbufferHeight) +{ + ID3D11Device *device = mRenderer->getDevice(); + + if (device == NULL) + { + return EGL_BAD_ACCESS; + } + + // EGL allows creating a surface with 0x0 dimension, however, DXGI does not like 0x0 swapchains + if (backbufferWidth < 1 || backbufferHeight < 1) + { + return EGL_SUCCESS; + } + +#if !defined(ANGLE_ENABLE_WINDOWS_STORE) || (WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP) + // Can only call resize if we have already created our swap buffer and resources + ASSERT(mSwapChain && mBackBufferTexture && mBackBufferRTView); + + SafeRelease(mBackBufferTexture); + SafeRelease(mBackBufferRTView); + + // Resize swap chain + DXGI_SWAP_CHAIN_DESC desc; + mSwapChain->GetDesc(&desc); + const d3d11::TextureFormat &backbufferFormatInfo = d3d11::GetTextureFormatInfo(mBackBufferFormat, mRenderer->getFeatureLevel()); + HRESULT result = mSwapChain->ResizeBuffers(desc.BufferCount, backbufferWidth, backbufferHeight, backbufferFormatInfo.texFormat, 0); + + if (FAILED(result)) + { + ERR("Error resizing swap chain buffers: 0x%08X", result); + release(); + + if (d3d11::isDeviceLostError(result)) + { + return EGL_CONTEXT_LOST; + } + else + { + return EGL_BAD_ALLOC; + } + } + + result = mSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&mBackBufferTexture); + ASSERT(SUCCEEDED(result)); + if (SUCCEEDED(result)) + { + d3d11::SetDebugName(mBackBufferTexture, "Back buffer texture"); + } + + result = device->CreateRenderTargetView(mBackBufferTexture, NULL, &mBackBufferRTView); + ASSERT(SUCCEEDED(result)); + if (SUCCEEDED(result)) + { + d3d11::SetDebugName(mBackBufferRTView, "Back buffer render target"); + } + + return resetOffscreenTexture(backbufferWidth, backbufferHeight); +#else + // Do nothing on Windows Phone apart from updating the internal buffer/width height + mWidth = backbufferWidth; + mHeight = backbufferHeight; + return EGL_SUCCESS; +#endif +} + +EGLint SwapChain11::reset(int backbufferWidth, int backbufferHeight, EGLint swapInterval) +{ + ID3D11Device *device = mRenderer->getDevice(); + + if (device == NULL) + { + return EGL_BAD_ACCESS; + } + + // Release specific resources to free up memory for the new render target, while the + // old render target still exists for the purpose of preserving its contents. + SafeRelease(mSwapChain); + SafeRelease(mBackBufferTexture); + SafeRelease(mBackBufferRTView); + + mSwapInterval = static_cast(swapInterval); + if (mSwapInterval > 4) + { + // IDXGISwapChain::Present documentation states that valid sync intervals are in the [0,4] range + return EGL_BAD_PARAMETER; + } + + // EGL allows creating a surface with 0x0 dimension, however, DXGI does not like 0x0 swapchains + if (backbufferWidth < 1 || backbufferHeight < 1) + { + releaseOffscreenTexture(); + return EGL_SUCCESS; + } + + if (mNativeWindow.getNativeWindow()) + { + const d3d11::TextureFormat &backbufferFormatInfo = d3d11::GetTextureFormatInfo(mBackBufferFormat, mRenderer->getFeatureLevel()); + + HRESULT result = mNativeWindow.createSwapChain(device, mRenderer->getDxgiFactory(), + backbufferFormatInfo.texFormat, + backbufferWidth, backbufferHeight, &mSwapChain); + + if (FAILED(result)) + { + ERR("Could not create additional swap chains or offscreen surfaces: %08lX", result); + release(); + + if (d3d11::isDeviceLostError(result)) + { + return EGL_CONTEXT_LOST; + } + else + { + return EGL_BAD_ALLOC; + } + } + + result = mSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&mBackBufferTexture); + ASSERT(SUCCEEDED(result)); + d3d11::SetDebugName(mBackBufferTexture, "Back buffer texture"); + + result = device->CreateRenderTargetView(mBackBufferTexture, NULL, &mBackBufferRTView); + ASSERT(SUCCEEDED(result)); + d3d11::SetDebugName(mBackBufferRTView, "Back buffer render target"); + } + + // If we are resizing the swap chain, we don't wish to recreate all the static resources + if (!mPassThroughResourcesInit) + { + mPassThroughResourcesInit = true; + initPassThroughResources(); + } + + return resetOffscreenTexture(backbufferWidth, backbufferHeight); +} + +void SwapChain11::initPassThroughResources() +{ + ID3D11Device *device = mRenderer->getDevice(); + + ASSERT(device != NULL); + + // Make sure our resources are all not allocated, when we create + ASSERT(mQuadVB == NULL && mPassThroughSampler == NULL); + ASSERT(mPassThroughIL == NULL && mPassThroughVS == NULL && mPassThroughPS == NULL); + + D3D11_BUFFER_DESC vbDesc; + vbDesc.ByteWidth = sizeof(d3d11::PositionTexCoordVertex) * 4; + vbDesc.Usage = D3D11_USAGE_DYNAMIC; + vbDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; + vbDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + vbDesc.MiscFlags = 0; + vbDesc.StructureByteStride = 0; + + HRESULT result = device->CreateBuffer(&vbDesc, NULL, &mQuadVB); + ASSERT(SUCCEEDED(result)); + d3d11::SetDebugName(mQuadVB, "Swap chain quad vertex buffer"); + + D3D11_SAMPLER_DESC samplerDesc; + samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT; + samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP; + samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP; + samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP; + samplerDesc.MipLODBias = 0.0f; + samplerDesc.MaxAnisotropy = 0; + samplerDesc.ComparisonFunc = D3D11_COMPARISON_NEVER; + samplerDesc.BorderColor[0] = 0.0f; + samplerDesc.BorderColor[1] = 0.0f; + samplerDesc.BorderColor[2] = 0.0f; + samplerDesc.BorderColor[3] = 0.0f; + samplerDesc.MinLOD = 0; + samplerDesc.MaxLOD = D3D11_FLOAT32_MAX; + + result = device->CreateSamplerState(&samplerDesc, &mPassThroughSampler); + ASSERT(SUCCEEDED(result)); + d3d11::SetDebugName(mPassThroughSampler, "Swap chain pass through sampler"); + + D3D11_INPUT_ELEMENT_DESC quadLayout[] = + { + { "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, + { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 8, D3D11_INPUT_PER_VERTEX_DATA, 0 }, + }; + + result = device->CreateInputLayout(quadLayout, 2, g_VS_Passthrough2D, sizeof(g_VS_Passthrough2D), &mPassThroughIL); + ASSERT(SUCCEEDED(result)); + d3d11::SetDebugName(mPassThroughIL, "Swap chain pass through layout"); + + result = device->CreateVertexShader(g_VS_Passthrough2D, sizeof(g_VS_Passthrough2D), NULL, &mPassThroughVS); + ASSERT(SUCCEEDED(result)); + d3d11::SetDebugName(mPassThroughVS, "Swap chain pass through vertex shader"); + + result = device->CreatePixelShader(g_PS_PassthroughRGBA2D, sizeof(g_PS_PassthroughRGBA2D), NULL, &mPassThroughPS); + ASSERT(SUCCEEDED(result)); + d3d11::SetDebugName(mPassThroughPS, "Swap chain pass through pixel shader"); +} + +// parameters should be validated/clamped by caller +EGLint SwapChain11::swapRect(EGLint x, EGLint y, EGLint width, EGLint height) +{ + if (!mSwapChain) + { + return EGL_SUCCESS; + } + + ID3D11Device *device = mRenderer->getDevice(); + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); + + // Set vertices + D3D11_MAPPED_SUBRESOURCE mappedResource; + HRESULT result = deviceContext->Map(mQuadVB, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); + if (FAILED(result)) + { + return EGL_BAD_ACCESS; + } + + d3d11::PositionTexCoordVertex *vertices = static_cast(mappedResource.pData); + + // Create a quad in homogeneous coordinates + float x1 = (x / float(mWidth)) * 2.0f - 1.0f; + float y1 = (y / float(mHeight)) * 2.0f - 1.0f; + float x2 = ((x + width) / float(mWidth)) * 2.0f - 1.0f; + float y2 = ((y + height) / float(mHeight)) * 2.0f - 1.0f; + +#if defined(ANGLE_ENABLE_WINDOWS_STORE) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) + const float dim = std::max(mWidth, mHeight); + float u1 = x / dim; + float v1 = y / dim; + float u2 = (x + width) / dim; + float v2 = (y + height) / dim; + + const NativeWindow::RotationFlags flags = mNativeWindow.rotationFlags(); + const bool rotateL = flags == NativeWindow::RotateLeft; + const bool rotateR = flags == NativeWindow::RotateRight; + d3d11::SetPositionTexCoordVertex(&vertices[0], x1, y1, rotateL ? u2 : u1, rotateR ? v2 : v1); + d3d11::SetPositionTexCoordVertex(&vertices[1], x1, y2, rotateR ? u2 : u1, rotateL ? v1 : v2); + d3d11::SetPositionTexCoordVertex(&vertices[2], x2, y1, rotateR ? u1 : u2, rotateL ? v2 : v1); + d3d11::SetPositionTexCoordVertex(&vertices[3], x2, y2, rotateL ? u1 : u2, rotateR ? v1 : v2); +#else + float u1 = x / float(mWidth); + float v1 = y / float(mHeight); + float u2 = (x + width) / float(mWidth); + float v2 = (y + height) / float(mHeight); + + d3d11::SetPositionTexCoordVertex(&vertices[0], x1, y1, u1, v1); + d3d11::SetPositionTexCoordVertex(&vertices[1], x1, y2, u1, v2); + d3d11::SetPositionTexCoordVertex(&vertices[2], x2, y1, u2, v1); + d3d11::SetPositionTexCoordVertex(&vertices[3], x2, y2, u2, v2); +#endif + + deviceContext->Unmap(mQuadVB, 0); + + static UINT stride = sizeof(d3d11::PositionTexCoordVertex); + static UINT startIdx = 0; + deviceContext->IASetVertexBuffers(0, 1, &mQuadVB, &stride, &startIdx); + + // Apply state + deviceContext->OMSetDepthStencilState(NULL, 0xFFFFFFFF); + + static const float blendFactor[4] = { 1.0f, 1.0f, 1.0f, 1.0f }; + deviceContext->OMSetBlendState(NULL, blendFactor, 0xFFFFFFF); + + deviceContext->RSSetState(NULL); + + // Apply shaders + deviceContext->IASetInputLayout(mPassThroughIL); + deviceContext->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); + deviceContext->VSSetShader(mPassThroughVS, NULL, 0); + deviceContext->PSSetShader(mPassThroughPS, NULL, 0); + deviceContext->GSSetShader(NULL, NULL, 0); + + // Apply render targets + mRenderer->setOneTimeRenderTarget(mBackBufferRTView); + + // Set the viewport + D3D11_VIEWPORT viewport; + viewport.TopLeftX = 0; + viewport.TopLeftY = 0; +#if defined(ANGLE_ENABLE_WINDOWS_STORE) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) + viewport.Width = (rotateL || rotateR) ? mHeight : mWidth; + viewport.Height = (rotateL || rotateR) ? mWidth : mHeight; +#else + viewport.Width = mWidth; + viewport.Height = mHeight; +#endif + viewport.MinDepth = 0.0f; + viewport.MaxDepth = 1.0f; + deviceContext->RSSetViewports(1, &viewport); + + // Apply textures + mRenderer->setShaderResource(gl::SAMPLER_PIXEL, 0, mOffscreenSRView); + deviceContext->PSSetSamplers(0, 1, &mPassThroughSampler); + + // Draw + deviceContext->Draw(4, 0); + +#if ANGLE_VSYNC == ANGLE_DISABLED + result = mSwapChain->Present(0, 0); +#else + result = mSwapChain->Present(mSwapInterval, 0); +#endif + + if (result == DXGI_ERROR_DEVICE_REMOVED) + { + HRESULT removedReason = device->GetDeviceRemovedReason(); + UNUSED_TRACE_VARIABLE(removedReason); + ERR("Present failed: the D3D11 device was removed: 0x%08X", removedReason); + return EGL_CONTEXT_LOST; + } + else if (result == DXGI_ERROR_DEVICE_RESET) + { + ERR("Present failed: the D3D11 device was reset from a bad command."); + return EGL_CONTEXT_LOST; + } + else if (FAILED(result)) + { + ERR("Present failed with error code 0x%08X", result); + } + + // Unbind + mRenderer->setShaderResource(gl::SAMPLER_PIXEL, 0, NULL); + + mRenderer->unapplyRenderTargets(); + mRenderer->markAllStateDirty(); + + return EGL_SUCCESS; +} + +ID3D11Texture2D *SwapChain11::getOffscreenTexture() +{ + return mOffscreenTexture; +} + +ID3D11RenderTargetView *SwapChain11::getRenderTarget() +{ + return mOffscreenRTView; +} + +ID3D11ShaderResourceView *SwapChain11::getRenderTargetShaderResource() +{ + return mOffscreenSRView; +} + +ID3D11DepthStencilView *SwapChain11::getDepthStencil() +{ + return mDepthStencilDSView; +} + +ID3D11ShaderResourceView * SwapChain11::getDepthStencilShaderResource() +{ + return mDepthStencilSRView; +} + +ID3D11Texture2D *SwapChain11::getDepthStencilTexture() +{ + return mDepthStencilTexture; +} + +SwapChain11 *SwapChain11::makeSwapChain11(SwapChainD3D *swapChain) +{ + ASSERT(HAS_DYNAMIC_TYPE(SwapChain11*, swapChain)); + return static_cast(swapChain); +} + +void SwapChain11::recreate() +{ + // possibly should use this method instead of reset +} + +void *rx::SwapChain11::getDevice() +{ + return mRenderer->getDevice(); +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/SwapChain11.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/SwapChain11.h new file mode 100644 index 0000000000..48c808a261 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/SwapChain11.h @@ -0,0 +1,87 @@ +// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// SwapChain11.h: Defines a back-end specific class for the D3D11 swap chain. + +#ifndef LIBANGLE_RENDERER_D3D_D3D11_SWAPCHAIN11_H_ +#define LIBANGLE_RENDERER_D3D_D3D11_SWAPCHAIN11_H_ + +#include "common/angleutils.h" +#include "libANGLE/renderer/d3d/SwapChainD3D.h" +#include "libANGLE/renderer/d3d/d3d11/RenderTarget11.h" + +namespace rx +{ +class Renderer11; + +class SwapChain11 : public SwapChainD3D +{ + public: + SwapChain11(Renderer11 *renderer, NativeWindow nativeWindow, HANDLE shareHandle, + GLenum backBufferFormat, GLenum depthBufferFormat); + virtual ~SwapChain11(); + + EGLint resize(EGLint backbufferWidth, EGLint backbufferHeight); + virtual EGLint reset(EGLint backbufferWidth, EGLint backbufferHeight, EGLint swapInterval); + virtual EGLint swapRect(EGLint x, EGLint y, EGLint width, EGLint height); + virtual void recreate(); + + RenderTargetD3D *getColorRenderTarget() override { return &mColorRenderTarget; } + RenderTargetD3D *getDepthStencilRenderTarget() override { return &mDepthStencilRenderTarget; } + + virtual ID3D11Texture2D *getOffscreenTexture(); + virtual ID3D11RenderTargetView *getRenderTarget(); + virtual ID3D11ShaderResourceView *getRenderTargetShaderResource(); + + virtual ID3D11Texture2D *getDepthStencilTexture(); + virtual ID3D11DepthStencilView *getDepthStencil(); + virtual ID3D11ShaderResourceView *getDepthStencilShaderResource(); + + EGLint getWidth() const { return mWidth; } + EGLint getHeight() const { return mHeight; } + + virtual void *getDevice(); + + static SwapChain11 *makeSwapChain11(SwapChainD3D *swapChain); + + private: + void release(); + void initPassThroughResources(); + void releaseOffscreenTexture(); + EGLint resetOffscreenTexture(int backbufferWidth, int backbufferHeight); + + Renderer11 *mRenderer; + EGLint mHeight; + EGLint mWidth; + bool mAppCreatedShareHandle; + unsigned int mSwapInterval; + bool mPassThroughResourcesInit; + + DXGISwapChain *mSwapChain; + + ID3D11Texture2D *mBackBufferTexture; + ID3D11RenderTargetView *mBackBufferRTView; + + ID3D11Texture2D *mOffscreenTexture; + ID3D11RenderTargetView *mOffscreenRTView; + ID3D11ShaderResourceView *mOffscreenSRView; + + ID3D11Texture2D *mDepthStencilTexture; + ID3D11DepthStencilView *mDepthStencilDSView; + ID3D11ShaderResourceView *mDepthStencilSRView; + + ID3D11Buffer *mQuadVB; + ID3D11SamplerState *mPassThroughSampler; + ID3D11InputLayout *mPassThroughIL; + ID3D11VertexShader *mPassThroughVS; + ID3D11PixelShader *mPassThroughPS; + + SurfaceRenderTarget11 mColorRenderTarget; + SurfaceRenderTarget11 mDepthStencilRenderTarget; +}; + +} +#endif // LIBANGLE_RENDERER_D3D_D3D11_SWAPCHAIN11_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/TextureStorage11.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/TextureStorage11.cpp new file mode 100644 index 0000000000..103e90fed3 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/TextureStorage11.cpp @@ -0,0 +1,2676 @@ +// +// Copyright (c) 2012-2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// TextureStorage11.cpp: Implements the abstract rx::TextureStorage11 class and its concrete derived +// classes TextureStorage11_2D and TextureStorage11_Cube, which act as the interface to the D3D11 texture. + +#include "libANGLE/renderer/d3d/d3d11/TextureStorage11.h" + +#include + +#include "common/MemoryBuffer.h" +#include "common/utilities.h" +#include "libANGLE/ImageIndex.h" +#include "libANGLE/formatutils.h" +#include "libANGLE/renderer/d3d/TextureD3D.h" +#include "libANGLE/renderer/d3d/d3d11/Blit11.h" +#include "libANGLE/renderer/d3d/d3d11/Image11.h" +#include "libANGLE/renderer/d3d/d3d11/RenderTarget11.h" +#include "libANGLE/renderer/d3d/d3d11/Renderer11.h" +#include "libANGLE/renderer/d3d/d3d11/SwapChain11.h" +#include "libANGLE/renderer/d3d/d3d11/formatutils11.h" +#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h" + +namespace rx +{ + +TextureStorage11::SwizzleCacheValue::SwizzleCacheValue() + : swizzleRed(GL_NONE), swizzleGreen(GL_NONE), swizzleBlue(GL_NONE), swizzleAlpha(GL_NONE) +{ +} + +TextureStorage11::SwizzleCacheValue::SwizzleCacheValue(GLenum red, GLenum green, GLenum blue, GLenum alpha) + : swizzleRed(red), swizzleGreen(green), swizzleBlue(blue), swizzleAlpha(alpha) +{ +} + +bool TextureStorage11::SwizzleCacheValue::operator==(const SwizzleCacheValue &other) const +{ + return swizzleRed == other.swizzleRed && + swizzleGreen == other.swizzleGreen && + swizzleBlue == other.swizzleBlue && + swizzleAlpha == other.swizzleAlpha; +} + +bool TextureStorage11::SwizzleCacheValue::operator!=(const SwizzleCacheValue &other) const +{ + return !(*this == other); +} + +TextureStorage11::SRVKey::SRVKey(int baseLevel, int mipLevels, bool swizzle) + : baseLevel(baseLevel), mipLevels(mipLevels), swizzle(swizzle) +{ +} + +bool TextureStorage11::SRVKey::operator<(const SRVKey &rhs) const +{ + return std::tie(baseLevel, mipLevels, swizzle) < std::tie(rhs.baseLevel, rhs.mipLevels, rhs.swizzle); +} + +TextureStorage11::TextureStorage11(Renderer11 *renderer, UINT bindFlags) + : mBindFlags(bindFlags), + mTopLevel(0), + mMipLevels(0), + mInternalFormat(GL_NONE), + mTextureFormat(DXGI_FORMAT_UNKNOWN), + mShaderResourceFormat(DXGI_FORMAT_UNKNOWN), + mRenderTargetFormat(DXGI_FORMAT_UNKNOWN), + mDepthStencilFormat(DXGI_FORMAT_UNKNOWN), + mTextureWidth(0), + mTextureHeight(0), + mTextureDepth(0) +{ + mRenderer = Renderer11::makeRenderer11(renderer); + + for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) + { + mLevelSRVs[i] = NULL; + } +} + +TextureStorage11::~TextureStorage11() +{ + for (unsigned int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) + { + SafeRelease(mLevelSRVs[level]); + } + + for (SRVCache::iterator i = mSrvCache.begin(); i != mSrvCache.end(); i++) + { + SafeRelease(i->second); + } + mSrvCache.clear(); +} + +TextureStorage11 *TextureStorage11::makeTextureStorage11(TextureStorage *storage) +{ + ASSERT(HAS_DYNAMIC_TYPE(TextureStorage11*, storage)); + return static_cast(storage); +} + +DWORD TextureStorage11::GetTextureBindFlags(GLenum internalFormat, D3D_FEATURE_LEVEL featureLevel, bool renderTarget) +{ + UINT bindFlags = 0; + + const d3d11::TextureFormat &formatInfo = d3d11::GetTextureFormatInfo(internalFormat, featureLevel); + if (formatInfo.srvFormat != DXGI_FORMAT_UNKNOWN) + { + bindFlags |= D3D11_BIND_SHADER_RESOURCE; + } + if (formatInfo.dsvFormat != DXGI_FORMAT_UNKNOWN) + { + bindFlags |= D3D11_BIND_DEPTH_STENCIL; + } + if (formatInfo.rtvFormat != DXGI_FORMAT_UNKNOWN && renderTarget) + { + bindFlags |= D3D11_BIND_RENDER_TARGET; + } + + return bindFlags; +} + +UINT TextureStorage11::getBindFlags() const +{ + return mBindFlags; +} + +int TextureStorage11::getTopLevel() const +{ + return mTopLevel; +} + +bool TextureStorage11::isRenderTarget() const +{ + return (mBindFlags & (D3D11_BIND_RENDER_TARGET | D3D11_BIND_DEPTH_STENCIL)) != 0; +} + +bool TextureStorage11::isManaged() const +{ + return false; +} + +int TextureStorage11::getLevelCount() const +{ + return mMipLevels - mTopLevel; +} + +int TextureStorage11::getLevelWidth(int mipLevel) const +{ + return std::max(static_cast(mTextureWidth) >> mipLevel, 1); +} + +int TextureStorage11::getLevelHeight(int mipLevel) const +{ + return std::max(static_cast(mTextureHeight) >> mipLevel, 1); +} + +int TextureStorage11::getLevelDepth(int mipLevel) const +{ + return std::max(static_cast(mTextureDepth) >> mipLevel, 1); +} + +UINT TextureStorage11::getSubresourceIndex(const gl::ImageIndex &index) const +{ + UINT mipSlice = static_cast(index.mipIndex + mTopLevel); + UINT arraySlice = static_cast(index.hasLayer() ? index.layerIndex : 0); + UINT subresource = D3D11CalcSubresource(mipSlice, arraySlice, mMipLevels); + ASSERT(subresource != std::numeric_limits::max()); + return subresource; +} + +gl::Error TextureStorage11::getSRV(const gl::SamplerState &samplerState, ID3D11ShaderResourceView **outSRV) +{ + bool swizzleRequired = samplerState.swizzleRequired(); + bool mipmapping = gl::IsMipmapFiltered(samplerState); + unsigned int mipLevels = mipmapping ? (samplerState.maxLevel - samplerState.baseLevel + 1) : 1; + + // Make sure there's 'mipLevels' mipmap levels below the base level (offset by the top level, which corresponds to GL level 0) + mipLevels = std::min(mipLevels, mMipLevels - mTopLevel - samplerState.baseLevel); + + if (mRenderer->getFeatureLevel() <= D3D_FEATURE_LEVEL_9_3) + { + ASSERT(!swizzleRequired); + ASSERT(mipLevels == 1 || mipLevels == mMipLevels); + } + + if (mRenderer->getWorkarounds().zeroMaxLodWorkaround) + { + // We must ensure that the level zero texture is in sync with mipped texture. + gl::Error error = useLevelZeroWorkaroundTexture(mipLevels == 1); + if (error.isError()) + { + return error; + } + } + + if (swizzleRequired) + { + verifySwizzleExists(samplerState.swizzleRed, samplerState.swizzleGreen, samplerState.swizzleBlue, samplerState.swizzleAlpha); + } + + SRVKey key(samplerState.baseLevel, mipLevels, swizzleRequired); + SRVCache::const_iterator iter = mSrvCache.find(key); + if (iter != mSrvCache.end()) + { + *outSRV = iter->second; + } + else + { + ID3D11Resource *texture = NULL; + if (swizzleRequired) + { + gl::Error error = getSwizzleTexture(&texture); + if (error.isError()) + { + return error; + } + } + else + { + gl::Error error = getResource(&texture); + if (error.isError()) + { + return error; + } + } + + ID3D11ShaderResourceView *srv = NULL; + DXGI_FORMAT format = (swizzleRequired ? mSwizzleShaderResourceFormat : mShaderResourceFormat); + gl::Error error = createSRV(samplerState.baseLevel, mipLevels, format, texture, &srv); + if (error.isError()) + { + return error; + } + + mSrvCache.insert(std::make_pair(key, srv)); + *outSRV = srv; + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureStorage11::getSRVLevel(int mipLevel, ID3D11ShaderResourceView **outSRV) +{ + ASSERT(mipLevel >= 0 && mipLevel < getLevelCount()); + + if (!mLevelSRVs[mipLevel]) + { + ID3D11Resource *resource = NULL; + gl::Error error = getResource(&resource); + if (error.isError()) + { + return error; + } + + error = createSRV(mipLevel, 1, mShaderResourceFormat, resource, &mLevelSRVs[mipLevel]); + if (error.isError()) + { + return error; + } + } + + *outSRV = mLevelSRVs[mipLevel]; + + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureStorage11::generateSwizzles(GLenum swizzleRed, GLenum swizzleGreen, GLenum swizzleBlue, GLenum swizzleAlpha) +{ + SwizzleCacheValue swizzleTarget(swizzleRed, swizzleGreen, swizzleBlue, swizzleAlpha); + for (int level = 0; level < getLevelCount(); level++) + { + // Check if the swizzle for this level is out of date + if (mSwizzleCache[level] != swizzleTarget) + { + // Need to re-render the swizzle for this level + ID3D11ShaderResourceView *sourceSRV = NULL; + gl::Error error = getSRVLevel(level, &sourceSRV); + if (error.isError()) + { + return error; + } + + ID3D11RenderTargetView *destRTV = NULL; + error = getSwizzleRenderTarget(level, &destRTV); + if (error.isError()) + { + return error; + } + + gl::Extents size(getLevelWidth(level), getLevelHeight(level), getLevelDepth(level)); + + Blit11 *blitter = mRenderer->getBlitter(); + + error = blitter->swizzleTexture(sourceSRV, destRTV, size, swizzleRed, swizzleGreen, swizzleBlue, swizzleAlpha); + if (error.isError()) + { + return error; + } + + mSwizzleCache[level] = swizzleTarget; + } + } + + return gl::Error(GL_NO_ERROR); +} + +void TextureStorage11::invalidateSwizzleCacheLevel(int mipLevel) +{ + if (mipLevel >= 0 && static_cast(mipLevel) < ArraySize(mSwizzleCache)) + { + // The default constructor of SwizzleCacheValue has GL_NONE for all channels which is not a + // valid swizzle combination + mSwizzleCache[mipLevel] = SwizzleCacheValue(); + } +} + +void TextureStorage11::invalidateSwizzleCache() +{ + for (unsigned int mipLevel = 0; mipLevel < ArraySize(mSwizzleCache); mipLevel++) + { + invalidateSwizzleCacheLevel(mipLevel); + } +} + +gl::Error TextureStorage11::updateSubresourceLevel(ID3D11Resource *srcTexture, unsigned int sourceSubresource, + const gl::ImageIndex &index, const gl::Box ©Area) +{ + ASSERT(srcTexture); + + GLint level = index.mipIndex; + + invalidateSwizzleCacheLevel(level); + + gl::Extents texSize(getLevelWidth(level), getLevelHeight(level), getLevelDepth(level)); + + bool fullCopy = copyArea.x == 0 && + copyArea.y == 0 && + copyArea.z == 0 && + copyArea.width == texSize.width && + copyArea.height == texSize.height && + copyArea.depth == texSize.depth; + + ID3D11Resource *dstTexture = NULL; + gl::Error error(GL_NO_ERROR); + + // If the zero-LOD workaround is active and we want to update a level greater than zero, then we should + // update the mipmapped texture, even if mapmaps are currently disabled. + if (index.mipIndex > 0 && mRenderer->getWorkarounds().zeroMaxLodWorkaround) + { + error = getMippedResource(&dstTexture); + } + else + { + error = getResource(&dstTexture); + } + + if (error.isError()) + { + return error; + } + + unsigned int dstSubresource = getSubresourceIndex(index); + + ASSERT(dstTexture); + + const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(mTextureFormat); + if (!fullCopy && (dxgiFormatInfo.depthBits > 0 || dxgiFormatInfo.stencilBits > 0)) + { + // CopySubresourceRegion cannot copy partial depth stencils, use the blitter instead + Blit11 *blitter = mRenderer->getBlitter(); + + return blitter->copyDepthStencil(srcTexture, sourceSubresource, copyArea, texSize, + dstTexture, dstSubresource, copyArea, texSize, + NULL); + } + else + { + D3D11_BOX srcBox; + srcBox.left = copyArea.x; + srcBox.top = copyArea.y; + srcBox.right = copyArea.x + roundUp(static_cast(copyArea.width), dxgiFormatInfo.blockWidth); + srcBox.bottom = copyArea.y + roundUp(static_cast(copyArea.height), dxgiFormatInfo.blockHeight); + srcBox.front = copyArea.z; + srcBox.back = copyArea.z + copyArea.depth; + + ID3D11DeviceContext *context = mRenderer->getDeviceContext(); + + context->CopySubresourceRegion(dstTexture, dstSubresource, copyArea.x, copyArea.y, copyArea.z, + srcTexture, sourceSubresource, fullCopy ? NULL : &srcBox); + return gl::Error(GL_NO_ERROR); + } +} + +gl::Error TextureStorage11::copySubresourceLevel(ID3D11Resource* dstTexture, unsigned int dstSubresource, + const gl::ImageIndex &index, const gl::Box ®ion) +{ + ASSERT(dstTexture); + + ID3D11Resource *srcTexture = NULL; + gl::Error error(GL_NO_ERROR); + + // If the zero-LOD workaround is active and we want to update a level greater than zero, then we should + // update the mipmapped texture, even if mapmaps are currently disabled. + if (index.mipIndex > 0 && mRenderer->getWorkarounds().zeroMaxLodWorkaround) + { + error = getMippedResource(&srcTexture); + } + else + { + error = getResource(&srcTexture); + } + + if (error.isError()) + { + return error; + } + + ASSERT(srcTexture); + + unsigned int srcSubresource = getSubresourceIndex(index); + + ID3D11DeviceContext *context = mRenderer->getDeviceContext(); + + // D3D11 can't perform partial CopySubresourceRegion on depth/stencil textures, so pSrcBox should be NULL. + D3D11_BOX srcBox; + D3D11_BOX *pSrcBox = NULL; + if (mRenderer->getFeatureLevel() <= D3D_FEATURE_LEVEL_9_3) + { + // However, D3D10Level9 doesn't always perform CopySubresourceRegion correctly unless the source box + // is specified. This is okay, since we don't perform CopySubresourceRegion on depth/stencil + // textures on 9_3. + ASSERT(d3d11::GetDXGIFormatInfo(mTextureFormat).depthBits == 0); + ASSERT(d3d11::GetDXGIFormatInfo(mTextureFormat).stencilBits == 0); + srcBox.left = region.x; + srcBox.right = region.x + region.width; + srcBox.top = region.y; + srcBox.bottom = region.y + region.height; + srcBox.front = region.z; + srcBox.back = region.z + region.depth; + pSrcBox = &srcBox; + } + + context->CopySubresourceRegion(dstTexture, dstSubresource, region.x, region.y, region.z, + srcTexture, srcSubresource, pSrcBox); + + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureStorage11::generateMipmap(const gl::ImageIndex &sourceIndex, const gl::ImageIndex &destIndex) +{ + ASSERT(sourceIndex.layerIndex == destIndex.layerIndex); + + invalidateSwizzleCacheLevel(destIndex.mipIndex); + + RenderTargetD3D *source = NULL; + gl::Error error = getRenderTarget(sourceIndex, &source); + if (error.isError()) + { + return error; + } + + RenderTargetD3D *dest = NULL; + error = getRenderTarget(destIndex, &dest); + if (error.isError()) + { + return error; + } + + ID3D11ShaderResourceView *sourceSRV = RenderTarget11::makeRenderTarget11(source)->getShaderResourceView(); + ID3D11RenderTargetView *destRTV = RenderTarget11::makeRenderTarget11(dest)->getRenderTargetView(); + + gl::Box sourceArea(0, 0, 0, source->getWidth(), source->getHeight(), source->getDepth()); + gl::Extents sourceSize(source->getWidth(), source->getHeight(), source->getDepth()); + + gl::Box destArea(0, 0, 0, dest->getWidth(), dest->getHeight(), dest->getDepth()); + gl::Extents destSize(dest->getWidth(), dest->getHeight(), dest->getDepth()); + + Blit11 *blitter = mRenderer->getBlitter(); + return blitter->copyTexture(sourceSRV, sourceArea, sourceSize, destRTV, destArea, destSize, NULL, + gl::GetInternalFormatInfo(source->getInternalFormat()).format, GL_LINEAR); +} + +void TextureStorage11::verifySwizzleExists(GLenum swizzleRed, GLenum swizzleGreen, GLenum swizzleBlue, GLenum swizzleAlpha) +{ + SwizzleCacheValue swizzleTarget(swizzleRed, swizzleGreen, swizzleBlue, swizzleAlpha); + for (unsigned int level = 0; level < mMipLevels; level++) + { + ASSERT(mSwizzleCache[level] == swizzleTarget); + } +} + +gl::Error TextureStorage11::copyToStorage(TextureStorage *destStorage) +{ + ASSERT(destStorage); + + ID3D11Resource *sourceResouce = NULL; + gl::Error error = getResource(&sourceResouce); + if (error.isError()) + { + return error; + } + + TextureStorage11 *dest11 = TextureStorage11::makeTextureStorage11(destStorage); + ID3D11Resource *destResource = NULL; + error = dest11->getResource(&destResource); + if (error.isError()) + { + return error; + } + + ID3D11DeviceContext *immediateContext = mRenderer->getDeviceContext(); + immediateContext->CopyResource(destResource, sourceResouce); + + dest11->invalidateSwizzleCache(); + + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureStorage11::setData(const gl::ImageIndex &index, ImageD3D *image, const gl::Box *destBox, GLenum type, + const gl::PixelUnpackState &unpack, const uint8_t *pixelData) +{ + ASSERT(!image->isDirty()); + + ID3D11Resource *resource = NULL; + gl::Error error = getResource(&resource); + if (error.isError()) + { + return error; + } + ASSERT(resource); + + UINT destSubresource = getSubresourceIndex(index); + + const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(image->getInternalFormat()); + + gl::Box levelBox(0, 0, 0, getLevelWidth(index.mipIndex), getLevelHeight(index.mipIndex), getLevelDepth(index.mipIndex)); + bool fullUpdate = (destBox == NULL || *destBox == levelBox); + ASSERT(internalFormatInfo.depthBits == 0 || fullUpdate); + + // TODO(jmadill): Handle compressed formats + // Compressed formats have different load syntax, so we'll have to handle them with slightly + // different logic. Will implemnent this in a follow-up patch, and ensure we do not use SetData + // with compressed formats in the calling logic. + ASSERT(!internalFormatInfo.compressed); + + int width = destBox ? destBox->width : static_cast(image->getWidth()); + int height = destBox ? destBox->height : static_cast(image->getHeight()); + int depth = destBox ? destBox->depth : static_cast(image->getDepth()); + UINT srcRowPitch = internalFormatInfo.computeRowPitch(type, width, unpack.alignment, unpack.rowLength); + UINT srcDepthPitch = internalFormatInfo.computeDepthPitch(type, width, height, unpack.alignment, unpack.rowLength); + + const d3d11::TextureFormat &d3d11Format = d3d11::GetTextureFormatInfo(image->getInternalFormat(), mRenderer->getFeatureLevel()); + const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(d3d11Format.texFormat); + + size_t outputPixelSize = dxgiFormatInfo.pixelBytes; + + UINT bufferRowPitch = outputPixelSize * width; + UINT bufferDepthPitch = bufferRowPitch * height; + + size_t neededSize = bufferDepthPitch * depth; + MemoryBuffer *conversionBuffer = NULL; + error = mRenderer->getScratchMemoryBuffer(neededSize, &conversionBuffer); + if (error.isError()) + { + return error; + } + + // TODO: fast path + LoadImageFunction loadFunction = d3d11Format.loadFunctions.at(type); + loadFunction(width, height, depth, + pixelData, srcRowPitch, srcDepthPitch, + conversionBuffer->data(), bufferRowPitch, bufferDepthPitch); + + ID3D11DeviceContext *immediateContext = mRenderer->getDeviceContext(); + + if (!fullUpdate) + { + ASSERT(destBox); + + D3D11_BOX destD3DBox; + destD3DBox.left = destBox->x; + destD3DBox.right = destBox->x + destBox->width; + destD3DBox.top = destBox->y; + destD3DBox.bottom = destBox->y + destBox->height; + destD3DBox.front = destBox->z; + destD3DBox.back = destBox->z + destBox->depth; + + immediateContext->UpdateSubresource(resource, destSubresource, + &destD3DBox, conversionBuffer->data(), + bufferRowPitch, bufferDepthPitch); + } + else + { + immediateContext->UpdateSubresource(resource, destSubresource, + NULL, conversionBuffer->data(), + bufferRowPitch, bufferDepthPitch); + } + + return gl::Error(GL_NO_ERROR); +} + +TextureStorage11_2D::TextureStorage11_2D(Renderer11 *renderer, SwapChain11 *swapchain) + : TextureStorage11(renderer, D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE), + mTexture(swapchain->getOffscreenTexture()), + mSwizzleTexture(NULL), + mLevelZeroTexture(NULL), + mLevelZeroRenderTarget(NULL), + mUseLevelZeroTexture(false) +{ + mTexture->AddRef(); + + for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) + { + mAssociatedImages[i] = NULL; + mRenderTarget[i] = NULL; + mSwizzleRenderTargets[i] = NULL; + } + + D3D11_TEXTURE2D_DESC texDesc; + mTexture->GetDesc(&texDesc); + mMipLevels = texDesc.MipLevels; + mTextureFormat = texDesc.Format; + mTextureWidth = texDesc.Width; + mTextureHeight = texDesc.Height; + mTextureDepth = 1; + + mInternalFormat = swapchain->GetBackBufferInternalFormat(); + + ID3D11ShaderResourceView *srv = swapchain->getRenderTargetShaderResource(); + D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; + srv->GetDesc(&srvDesc); + mShaderResourceFormat = srvDesc.Format; + + ID3D11RenderTargetView* offscreenRTV = swapchain->getRenderTarget(); + D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; + offscreenRTV->GetDesc(&rtvDesc); + mRenderTargetFormat = rtvDesc.Format; + + const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(mTextureFormat); + const d3d11::TextureFormat &formatInfo = d3d11::GetTextureFormatInfo(dxgiFormatInfo.internalFormat, mRenderer->getFeatureLevel()); + mSwizzleTextureFormat = formatInfo.swizzleTexFormat; + mSwizzleShaderResourceFormat = formatInfo.swizzleSRVFormat; + mSwizzleRenderTargetFormat = formatInfo.swizzleRTVFormat; + + mDepthStencilFormat = DXGI_FORMAT_UNKNOWN; + + initializeSerials(1, 1); +} + +TextureStorage11_2D::TextureStorage11_2D(Renderer11 *renderer, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels, bool hintLevelZeroOnly) + : TextureStorage11(renderer, GetTextureBindFlags(internalformat, renderer->getFeatureLevel(), renderTarget)), + mTexture(NULL), + mSwizzleTexture(NULL), + mLevelZeroTexture(NULL), + mLevelZeroRenderTarget(NULL), + mUseLevelZeroTexture(false) +{ + for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) + { + mAssociatedImages[i] = NULL; + mRenderTarget[i] = NULL; + mSwizzleRenderTargets[i] = NULL; + } + + mInternalFormat = internalformat; + + const d3d11::TextureFormat &formatInfo = d3d11::GetTextureFormatInfo(internalformat, renderer->getFeatureLevel()); + mTextureFormat = formatInfo.texFormat; + mShaderResourceFormat = formatInfo.srvFormat; + mDepthStencilFormat = formatInfo.dsvFormat; + mRenderTargetFormat = formatInfo.rtvFormat; + mSwizzleTextureFormat = formatInfo.swizzleTexFormat; + mSwizzleShaderResourceFormat = formatInfo.swizzleSRVFormat; + mSwizzleRenderTargetFormat = formatInfo.swizzleRTVFormat; + + d3d11::MakeValidSize(false, mTextureFormat, &width, &height, &mTopLevel); + mMipLevels = mTopLevel + levels; + mTextureWidth = width; + mTextureHeight = height; + mTextureDepth = 1; + + if (hintLevelZeroOnly && levels > 1) + { + //The LevelZeroOnly hint should only be true if the zero max LOD workaround is active. + ASSERT(mRenderer->getWorkarounds().zeroMaxLodWorkaround); + mUseLevelZeroTexture = true; + } + + initializeSerials(getLevelCount(), 1); +} + +TextureStorage11_2D::~TextureStorage11_2D() +{ + for (unsigned i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) + { + if (mAssociatedImages[i] != NULL) + { + bool imageAssociationCorrect = mAssociatedImages[i]->isAssociatedStorageValid(this); + ASSERT(imageAssociationCorrect); + + if (imageAssociationCorrect) + { + // We must let the Images recover their data before we delete it from the TextureStorage. + gl::Error error = mAssociatedImages[i]->recoverFromAssociatedStorage(); + if (error.isError()) + { + // TODO: Find a way to report this back to the context + } + } + } + } + + SafeRelease(mTexture); + SafeRelease(mSwizzleTexture); + + SafeRelease(mLevelZeroTexture); + SafeDelete(mLevelZeroRenderTarget); + + for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) + { + SafeDelete(mRenderTarget[i]); + SafeRelease(mSwizzleRenderTargets[i]); + } +} + +TextureStorage11_2D *TextureStorage11_2D::makeTextureStorage11_2D(TextureStorage *storage) +{ + ASSERT(HAS_DYNAMIC_TYPE(TextureStorage11_2D*, storage)); + return static_cast(storage); +} + +gl::Error TextureStorage11_2D::copyToStorage(TextureStorage *destStorage) +{ + ASSERT(destStorage); + + TextureStorage11_2D *dest11 = TextureStorage11_2D::makeTextureStorage11_2D(destStorage); + + if (mRenderer->getWorkarounds().zeroMaxLodWorkaround) + { + ID3D11DeviceContext *immediateContext = mRenderer->getDeviceContext(); + + // If either mTexture or mLevelZeroTexture exist, then we need to copy them into the corresponding textures in destStorage. + if (mTexture) + { + gl::Error error = dest11->useLevelZeroWorkaroundTexture(false); + if (error.isError()) + { + return error; + } + + ID3D11Resource *destResource = NULL; + error = dest11->getResource(&destResource); + if (error.isError()) + { + return error; + } + + immediateContext->CopyResource(destResource, mTexture); + } + + if (mLevelZeroTexture) + { + gl::Error error = dest11->useLevelZeroWorkaroundTexture(true); + if (error.isError()) + { + return error; + } + + ID3D11Resource *destResource = NULL; + error = dest11->getResource(&destResource); + if (error.isError()) + { + return error; + } + + immediateContext->CopyResource(destResource, mLevelZeroTexture); + } + } + else + { + ID3D11Resource *sourceResouce = NULL; + gl::Error error = getResource(&sourceResouce); + if (error.isError()) + { + return error; + } + + ID3D11Resource *destResource = NULL; + error = dest11->getResource(&destResource); + if (error.isError()) + { + return error; + } + + ID3D11DeviceContext *immediateContext = mRenderer->getDeviceContext(); + immediateContext->CopyResource(destResource, sourceResouce); + } + + dest11->invalidateSwizzleCache(); + + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureStorage11_2D::useLevelZeroWorkaroundTexture(bool useLevelZeroTexture) +{ + if (useLevelZeroTexture && mMipLevels > 1) + { + if (!mUseLevelZeroTexture && mTexture) + { + gl::Error error = ensureTextureExists(1); + if (error.isError()) + { + return error; + } + + // Pull data back from the mipped texture if necessary. + ASSERT(mLevelZeroTexture); + ID3D11DeviceContext *context = mRenderer->getDeviceContext(); + context->CopySubresourceRegion(mLevelZeroTexture, 0, 0, 0, 0, mTexture, 0, NULL); + } + + mUseLevelZeroTexture = true; + } + else + { + if (mUseLevelZeroTexture && mLevelZeroTexture) + { + gl::Error error = ensureTextureExists(mMipLevels); + if (error.isError()) + { + return error; + } + + // Pull data back from the level zero texture if necessary. + ASSERT(mTexture); + ID3D11DeviceContext *context = mRenderer->getDeviceContext(); + context->CopySubresourceRegion(mTexture, 0, 0, 0, 0, mLevelZeroTexture, 0, NULL); + } + + mUseLevelZeroTexture = false; + } + + return gl::Error(GL_NO_ERROR); +} + +void TextureStorage11_2D::associateImage(Image11* image, const gl::ImageIndex &index) +{ + GLint level = index.mipIndex; + + ASSERT(0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); + + if (0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) + { + mAssociatedImages[level] = image; + } +} + +bool TextureStorage11_2D::isAssociatedImageValid(const gl::ImageIndex &index, Image11* expectedImage) +{ + GLint level = index.mipIndex; + + if (0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) + { + // This validation check should never return false. It means the Image/TextureStorage association is broken. + bool retValue = (mAssociatedImages[level] == expectedImage); + ASSERT(retValue); + return retValue; + } + + return false; +} + +// disassociateImage allows an Image to end its association with a Storage. +void TextureStorage11_2D::disassociateImage(const gl::ImageIndex &index, Image11* expectedImage) +{ + GLint level = index.mipIndex; + + ASSERT(0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); + + if (0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) + { + ASSERT(mAssociatedImages[level] == expectedImage); + + if (mAssociatedImages[level] == expectedImage) + { + mAssociatedImages[level] = NULL; + } + } +} + +// releaseAssociatedImage prepares the Storage for a new Image association. It lets the old Image recover its data before ending the association. +gl::Error TextureStorage11_2D::releaseAssociatedImage(const gl::ImageIndex &index, Image11* incomingImage) +{ + GLint level = index.mipIndex; + + ASSERT(0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); + + if (0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) + { + // No need to let the old Image recover its data, if it is also the incoming Image. + if (mAssociatedImages[level] != NULL && mAssociatedImages[level] != incomingImage) + { + // Ensure that the Image is still associated with this TextureStorage. This should be true. + bool imageAssociationCorrect = mAssociatedImages[level]->isAssociatedStorageValid(this); + ASSERT(imageAssociationCorrect); + + if (imageAssociationCorrect) + { + // Force the image to recover from storage before its data is overwritten. + // This will reset mAssociatedImages[level] to NULL too. + gl::Error error = mAssociatedImages[level]->recoverFromAssociatedStorage(); + if (error.isError()) + { + return error; + } + } + } + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureStorage11_2D::getResource(ID3D11Resource **outResource) +{ + if (mUseLevelZeroTexture && mMipLevels > 1) + { + gl::Error error = ensureTextureExists(1); + if (error.isError()) + { + return error; + } + + *outResource = mLevelZeroTexture; + return gl::Error(GL_NO_ERROR); + } + else + { + gl::Error error = ensureTextureExists(mMipLevels); + if (error.isError()) + { + return error; + } + + *outResource = mTexture; + return gl::Error(GL_NO_ERROR); + } +} + +gl::Error TextureStorage11_2D::getMippedResource(ID3D11Resource **outResource) +{ + // This shouldn't be called unless the zero max LOD workaround is active. + ASSERT(mRenderer->getWorkarounds().zeroMaxLodWorkaround); + + gl::Error error = ensureTextureExists(mMipLevels); + if (error.isError()) + { + return error; + } + + *outResource = mTexture; + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureStorage11_2D::ensureTextureExists(int mipLevels) +{ + // If mMipLevels = 1 then always use mTexture rather than mLevelZeroTexture. + bool useLevelZeroTexture = mRenderer->getWorkarounds().zeroMaxLodWorkaround ? (mipLevels == 1) && (mMipLevels > 1) : false; + ID3D11Texture2D **outputTexture = useLevelZeroTexture ? &mLevelZeroTexture : &mTexture; + + // if the width or height is not positive this should be treated as an incomplete texture + // we handle that here by skipping the d3d texture creation + if (*outputTexture == NULL && mTextureWidth > 0 && mTextureHeight > 0) + { + ASSERT(mipLevels > 0); + + ID3D11Device *device = mRenderer->getDevice(); + + D3D11_TEXTURE2D_DESC desc; + desc.Width = mTextureWidth; // Compressed texture size constraints? + desc.Height = mTextureHeight; + desc.MipLevels = mipLevels; + desc.ArraySize = 1; + desc.Format = mTextureFormat; + desc.SampleDesc.Count = 1; + desc.SampleDesc.Quality = 0; + desc.Usage = D3D11_USAGE_DEFAULT; + desc.BindFlags = getBindFlags(); + desc.CPUAccessFlags = 0; + desc.MiscFlags = 0; + + HRESULT result = device->CreateTexture2D(&desc, NULL, outputTexture); + + // this can happen from windows TDR + if (d3d11::isDeviceLostError(result)) + { + mRenderer->notifyDeviceLost(); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create 2D texture storage, result: 0x%X.", result); + } + else if (FAILED(result)) + { + ASSERT(result == E_OUTOFMEMORY); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create 2D texture storage, result: 0x%X.", result); + } + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureStorage11_2D::getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT) +{ + ASSERT(!index.hasLayer()); + + int level = index.mipIndex; + ASSERT(level >= 0 && level < getLevelCount()); + + // In GL ES 2.0, the application can only render to level zero of the texture (Section 4.4.3 of the GLES 2.0 spec, page 113 of version 2.0.25). + // Other parts of TextureStorage11_2D could create RTVs on non-zero levels of the texture (e.g. generateMipmap). + // On Feature Level 9_3, this is unlikely to be useful. The renderer can't create SRVs on the individual levels of the texture, + // so methods like generateMipmap can't do anything useful with non-zero-level RTVs. + // Therefore if level > 0 on 9_3 then there's almost certainly something wrong. + ASSERT(!(mRenderer->getFeatureLevel() <= D3D_FEATURE_LEVEL_9_3 && level > 0)); + + if (!mRenderTarget[level]) + { + ID3D11Resource *texture = NULL; + gl::Error error = getResource(&texture); + if (error.isError()) + { + return error; + } + + ID3D11ShaderResourceView *srv = NULL; + error = getSRVLevel(level, &srv); + if (error.isError()) + { + return error; + } + + if (mUseLevelZeroTexture) + { + if (!mLevelZeroRenderTarget) + { + ID3D11Device *device = mRenderer->getDevice(); + + D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; + rtvDesc.Format = mRenderTargetFormat; + rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; + rtvDesc.Texture2D.MipSlice = mTopLevel + level; + + ID3D11RenderTargetView *rtv; + HRESULT result = device->CreateRenderTargetView(mLevelZeroTexture, &rtvDesc, &rtv); + + if (result == E_OUTOFMEMORY) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal render target view for texture storage, result: 0x%X.", result); + } + ASSERT(SUCCEEDED(result)); + + mLevelZeroRenderTarget = new TextureRenderTarget11(rtv, mLevelZeroTexture, NULL, mInternalFormat, getLevelWidth(level), getLevelHeight(level), 1, 0); + + // RenderTarget will take ownership of these resources + SafeRelease(rtv); + } + + ASSERT(outRT); + *outRT = mLevelZeroRenderTarget; + return gl::Error(GL_NO_ERROR); + } + + if (mRenderTargetFormat != DXGI_FORMAT_UNKNOWN) + { + ID3D11Device *device = mRenderer->getDevice(); + + D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; + rtvDesc.Format = mRenderTargetFormat; + rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; + rtvDesc.Texture2D.MipSlice = mTopLevel + level; + + ID3D11RenderTargetView *rtv; + HRESULT result = device->CreateRenderTargetView(texture, &rtvDesc, &rtv); + + ASSERT(result == E_OUTOFMEMORY || SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal render target view for texture storage, result: 0x%X.", result); + } + + mRenderTarget[level] = new TextureRenderTarget11(rtv, texture, srv, mInternalFormat, getLevelWidth(level), getLevelHeight(level), 1, 0); + + // RenderTarget will take ownership of these resources + SafeRelease(rtv); + } + else if (mDepthStencilFormat != DXGI_FORMAT_UNKNOWN) + { + ID3D11Device *device = mRenderer->getDevice(); + + D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc; + dsvDesc.Format = mDepthStencilFormat; + dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D; + dsvDesc.Texture2D.MipSlice = mTopLevel + level; + dsvDesc.Flags = 0; + + ID3D11DepthStencilView *dsv; + HRESULT result = device->CreateDepthStencilView(texture, &dsvDesc, &dsv); + + ASSERT(result == E_OUTOFMEMORY || SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY,"Failed to create internal depth stencil view for texture storage, result: 0x%X.", result); + } + + mRenderTarget[level] = new TextureRenderTarget11(dsv, texture, srv, mInternalFormat, getLevelWidth(level), getLevelHeight(level), 1, 0); + + // RenderTarget will take ownership of these resources + SafeRelease(dsv); + } + else + { + UNREACHABLE(); + } + } + + ASSERT(outRT); + *outRT = mRenderTarget[level]; + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureStorage11_2D::createSRV(int baseLevel, int mipLevels, DXGI_FORMAT format, ID3D11Resource *texture, + ID3D11ShaderResourceView **outSRV) const +{ + ASSERT(outSRV); + + D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; + srvDesc.Format = format; + srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; + srvDesc.Texture2D.MostDetailedMip = mTopLevel + baseLevel; + srvDesc.Texture2D.MipLevels = mipLevels; + + ID3D11Resource *srvTexture = texture; + + if (mRenderer->getWorkarounds().zeroMaxLodWorkaround) + { + ASSERT(mTopLevel == 0); + ASSERT(baseLevel == 0); + // This code also assumes that the incoming texture equals either mLevelZeroTexture or mTexture. + + if (mipLevels == 1 && mMipLevels > 1) + { + // We must use a SRV on the level-zero-only texture. + ASSERT(mLevelZeroTexture != NULL && texture == mLevelZeroTexture); + srvTexture = mLevelZeroTexture; + } + else + { + ASSERT(mipLevels == static_cast(mMipLevels)); + ASSERT(mTexture != NULL && texture == mTexture); + srvTexture = mTexture; + } + } + + ID3D11Device *device = mRenderer->getDevice(); + HRESULT result = device->CreateShaderResourceView(srvTexture, &srvDesc, outSRV); + + ASSERT(result == E_OUTOFMEMORY || SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal texture storage SRV, result: 0x%X.", result); + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureStorage11_2D::getSwizzleTexture(ID3D11Resource **outTexture) +{ + ASSERT(outTexture); + + if (!mSwizzleTexture) + { + ID3D11Device *device = mRenderer->getDevice(); + + D3D11_TEXTURE2D_DESC desc; + desc.Width = mTextureWidth; + desc.Height = mTextureHeight; + desc.MipLevels = mMipLevels; + desc.ArraySize = 1; + desc.Format = mSwizzleTextureFormat; + desc.SampleDesc.Count = 1; + desc.SampleDesc.Quality = 0; + desc.Usage = D3D11_USAGE_DEFAULT; + desc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET; + desc.CPUAccessFlags = 0; + desc.MiscFlags = 0; + + HRESULT result = device->CreateTexture2D(&desc, NULL, &mSwizzleTexture); + + ASSERT(result == E_OUTOFMEMORY || SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal swizzle texture, result: 0x%X.", result); + } + } + + *outTexture = mSwizzleTexture; + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureStorage11_2D::getSwizzleRenderTarget(int mipLevel, ID3D11RenderTargetView **outRTV) +{ + ASSERT(mipLevel >= 0 && mipLevel < getLevelCount()); + ASSERT(outRTV); + + if (!mSwizzleRenderTargets[mipLevel]) + { + ID3D11Resource *swizzleTexture = NULL; + gl::Error error = getSwizzleTexture(&swizzleTexture); + if (error.isError()) + { + return error; + } + + ID3D11Device *device = mRenderer->getDevice(); + + D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; + rtvDesc.Format = mSwizzleRenderTargetFormat; + rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; + rtvDesc.Texture2D.MipSlice = mTopLevel + mipLevel; + + HRESULT result = device->CreateRenderTargetView(mSwizzleTexture, &rtvDesc, &mSwizzleRenderTargets[mipLevel]); + + ASSERT(result == E_OUTOFMEMORY || SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal swizzle render target view, result: 0x%X.", result); + } + } + + *outRTV = mSwizzleRenderTargets[mipLevel]; + return gl::Error(GL_NO_ERROR); +} + +TextureStorage11_Cube::TextureStorage11_Cube(Renderer11 *renderer, GLenum internalformat, bool renderTarget, int size, int levels, bool hintLevelZeroOnly) + : TextureStorage11(renderer, GetTextureBindFlags(internalformat, renderer->getFeatureLevel(), renderTarget)) +{ + mTexture = NULL; + mSwizzleTexture = NULL; + + for (unsigned int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) + { + mSwizzleRenderTargets[level] = NULL; + for (unsigned int face = 0; face < CUBE_FACE_COUNT; face++) + { + mAssociatedImages[face][level] = NULL; + mRenderTarget[face][level] = NULL; + } + } + + mLevelZeroTexture = NULL; + mUseLevelZeroTexture = false; + + for (unsigned int face = 0; face < CUBE_FACE_COUNT; face++) + { + mLevelZeroRenderTarget[face] = NULL; + } + + mInternalFormat = internalformat; + + const d3d11::TextureFormat &formatInfo = d3d11::GetTextureFormatInfo(internalformat, renderer->getFeatureLevel()); + mTextureFormat = formatInfo.texFormat; + mShaderResourceFormat = formatInfo.srvFormat; + mDepthStencilFormat = formatInfo.dsvFormat; + mRenderTargetFormat = formatInfo.rtvFormat; + mSwizzleTextureFormat = formatInfo.swizzleTexFormat; + mSwizzleShaderResourceFormat = formatInfo.swizzleSRVFormat; + mSwizzleRenderTargetFormat = formatInfo.swizzleRTVFormat; + + // adjust size if needed for compressed textures + int height = size; + d3d11::MakeValidSize(false, mTextureFormat, &size, &height, &mTopLevel); + + mMipLevels = mTopLevel + levels; + mTextureWidth = size; + mTextureHeight = size; + mTextureDepth = 1; + + if (hintLevelZeroOnly && levels > 1) + { + //The LevelZeroOnly hint should only be true if the zero max LOD workaround is active. + ASSERT(mRenderer->getWorkarounds().zeroMaxLodWorkaround); + mUseLevelZeroTexture = true; + } + + initializeSerials(getLevelCount() * CUBE_FACE_COUNT, CUBE_FACE_COUNT); +} + +TextureStorage11_Cube::~TextureStorage11_Cube() +{ + for (unsigned int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) + { + for (unsigned int face = 0; face < CUBE_FACE_COUNT; face++) + { + if (mAssociatedImages[face][level] != NULL) + { + bool imageAssociationCorrect = mAssociatedImages[face][level]->isAssociatedStorageValid(this); + ASSERT(imageAssociationCorrect); + + if (imageAssociationCorrect) + { + // We must let the Images recover their data before we delete it from the TextureStorage. + mAssociatedImages[face][level]->recoverFromAssociatedStorage(); + } + } + } + } + + SafeRelease(mTexture); + SafeRelease(mSwizzleTexture); + SafeRelease(mLevelZeroTexture); + + for (unsigned int face = 0; face < CUBE_FACE_COUNT; face++) + { + SafeDelete(mLevelZeroRenderTarget[face]); + } + + for (unsigned int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) + { + SafeRelease(mSwizzleRenderTargets[level]); + for (unsigned int face = 0; face < CUBE_FACE_COUNT; face++) + { + SafeDelete(mRenderTarget[face][level]); + } + } +} + +TextureStorage11_Cube *TextureStorage11_Cube::makeTextureStorage11_Cube(TextureStorage *storage) +{ + ASSERT(HAS_DYNAMIC_TYPE(TextureStorage11_Cube*, storage)); + return static_cast(storage); +} + +UINT TextureStorage11_Cube::getSubresourceIndex(const gl::ImageIndex &index) const +{ + if (mRenderer->getWorkarounds().zeroMaxLodWorkaround && mUseLevelZeroTexture && index.mipIndex == 0) + { + UINT arraySlice = static_cast(index.hasLayer() ? index.layerIndex : 0); + UINT subresource = D3D11CalcSubresource(0, arraySlice, 1); + ASSERT(subresource != std::numeric_limits::max()); + return subresource; + } + else + { + UINT mipSlice = static_cast(index.mipIndex + mTopLevel); + UINT arraySlice = static_cast(index.hasLayer() ? index.layerIndex : 0); + UINT subresource = D3D11CalcSubresource(mipSlice, arraySlice, mMipLevels); + ASSERT(subresource != std::numeric_limits::max()); + return subresource; + } +} + +gl::Error TextureStorage11_Cube::copyToStorage(TextureStorage *destStorage) +{ + ASSERT(destStorage); + + TextureStorage11_Cube *dest11 = TextureStorage11_Cube::makeTextureStorage11_Cube(destStorage); + + if (mRenderer->getWorkarounds().zeroMaxLodWorkaround) + { + ID3D11DeviceContext *immediateContext = mRenderer->getDeviceContext(); + + // If either mTexture or mLevelZeroTexture exist, then we need to copy them into the corresponding textures in destStorage. + if (mTexture) + { + gl::Error error = dest11->useLevelZeroWorkaroundTexture(false); + if (error.isError()) + { + return error; + } + + ID3D11Resource *destResource = NULL; + error = dest11->getResource(&destResource); + if (error.isError()) + { + return error; + } + + immediateContext->CopyResource(destResource, mTexture); + } + + if (mLevelZeroTexture) + { + gl::Error error = dest11->useLevelZeroWorkaroundTexture(true); + if (error.isError()) + { + return error; + } + + ID3D11Resource *destResource = NULL; + error = dest11->getResource(&destResource); + if (error.isError()) + { + return error; + } + + immediateContext->CopyResource(destResource, mLevelZeroTexture); + } + } + else + { + ID3D11Resource *sourceResouce = NULL; + gl::Error error = getResource(&sourceResouce); + if (error.isError()) + { + return error; + } + + ID3D11Resource *destResource = NULL; + error = dest11->getResource(&destResource); + if (error.isError()) + { + return error; + } + + ID3D11DeviceContext *immediateContext = mRenderer->getDeviceContext(); + immediateContext->CopyResource(destResource, sourceResouce); + } + + dest11->invalidateSwizzleCache(); + + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureStorage11_Cube::useLevelZeroWorkaroundTexture(bool useLevelZeroTexture) +{ + if (useLevelZeroTexture && mMipLevels > 1) + { + if (!mUseLevelZeroTexture && mTexture) + { + gl::Error error = ensureTextureExists(1); + if (error.isError()) + { + return error; + } + + // Pull data back from the mipped texture if necessary. + ASSERT(mLevelZeroTexture); + ID3D11DeviceContext *context = mRenderer->getDeviceContext(); + + for (int face = 0; face < 6; face++) + { + context->CopySubresourceRegion(mLevelZeroTexture, D3D11CalcSubresource(0, face, 1), 0, 0, 0, mTexture, face * mMipLevels, NULL); + } + } + + mUseLevelZeroTexture = true; + } + else + { + if (mUseLevelZeroTexture && mLevelZeroTexture) + { + gl::Error error = ensureTextureExists(mMipLevels); + if (error.isError()) + { + return error; + } + + // Pull data back from the level zero texture if necessary. + ASSERT(mTexture); + ID3D11DeviceContext *context = mRenderer->getDeviceContext(); + + for (int face = 0; face < 6; face++) + { + context->CopySubresourceRegion(mTexture, D3D11CalcSubresource(0, face, mMipLevels), 0, 0, 0, mLevelZeroTexture, face, NULL); + } + } + + mUseLevelZeroTexture = false; + } + + return gl::Error(GL_NO_ERROR); +} + +void TextureStorage11_Cube::associateImage(Image11* image, const gl::ImageIndex &index) +{ + GLint level = index.mipIndex; + GLint layerTarget = index.layerIndex; + + ASSERT(0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); + ASSERT(0 <= layerTarget && layerTarget < CUBE_FACE_COUNT); + + if (0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) + { + if (0 <= layerTarget && layerTarget < CUBE_FACE_COUNT) + { + mAssociatedImages[layerTarget][level] = image; + } + } +} + +bool TextureStorage11_Cube::isAssociatedImageValid(const gl::ImageIndex &index, Image11* expectedImage) +{ + GLint level = index.mipIndex; + GLint layerTarget = index.layerIndex; + + if (0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) + { + if (0 <= layerTarget && layerTarget < CUBE_FACE_COUNT) + { + // This validation check should never return false. It means the Image/TextureStorage association is broken. + bool retValue = (mAssociatedImages[layerTarget][level] == expectedImage); + ASSERT(retValue); + return retValue; + } + } + + return false; +} + +// disassociateImage allows an Image to end its association with a Storage. +void TextureStorage11_Cube::disassociateImage(const gl::ImageIndex &index, Image11* expectedImage) +{ + GLint level = index.mipIndex; + GLint layerTarget = index.layerIndex; + + ASSERT(0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); + ASSERT(0 <= layerTarget && layerTarget < CUBE_FACE_COUNT); + + if (0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) + { + if (0 <= layerTarget && layerTarget < CUBE_FACE_COUNT) + { + ASSERT(mAssociatedImages[layerTarget][level] == expectedImage); + + if (mAssociatedImages[layerTarget][level] == expectedImage) + { + mAssociatedImages[layerTarget][level] = NULL; + } + } + } +} + +// releaseAssociatedImage prepares the Storage for a new Image association. It lets the old Image recover its data before ending the association. +gl::Error TextureStorage11_Cube::releaseAssociatedImage(const gl::ImageIndex &index, Image11* incomingImage) +{ + GLint level = index.mipIndex; + GLint layerTarget = index.layerIndex; + + ASSERT(0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); + ASSERT(0 <= layerTarget && layerTarget < CUBE_FACE_COUNT); + + if ((0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)) + { + if (0 <= layerTarget && layerTarget < CUBE_FACE_COUNT) + { + // No need to let the old Image recover its data, if it is also the incoming Image. + if (mAssociatedImages[layerTarget][level] != NULL && mAssociatedImages[layerTarget][level] != incomingImage) + { + // Ensure that the Image is still associated with this TextureStorage. This should be true. + bool imageAssociationCorrect = mAssociatedImages[layerTarget][level]->isAssociatedStorageValid(this); + ASSERT(imageAssociationCorrect); + + if (imageAssociationCorrect) + { + // Force the image to recover from storage before its data is overwritten. + // This will reset mAssociatedImages[level] to NULL too. + gl::Error error = mAssociatedImages[layerTarget][level]->recoverFromAssociatedStorage(); + if (error.isError()) + { + return error; + } + } + } + } + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureStorage11_Cube::getResource(ID3D11Resource **outResource) +{ + if (mUseLevelZeroTexture && mMipLevels > 1) + { + gl::Error error = ensureTextureExists(1); + if (error.isError()) + { + return error; + } + + *outResource = mLevelZeroTexture; + return gl::Error(GL_NO_ERROR); + } + else + { + gl::Error error = ensureTextureExists(mMipLevels); + if (error.isError()) + { + return error; + } + + *outResource = mTexture; + return gl::Error(GL_NO_ERROR); + } +} + +gl::Error TextureStorage11_Cube::getMippedResource(ID3D11Resource **outResource) +{ + // This shouldn't be called unless the zero max LOD workaround is active. + ASSERT(mRenderer->getWorkarounds().zeroMaxLodWorkaround); + + gl::Error error = ensureTextureExists(mMipLevels); + if (error.isError()) + { + return error; + } + + *outResource = mTexture; + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureStorage11_Cube::ensureTextureExists(int mipLevels) +{ + // If mMipLevels = 1 then always use mTexture rather than mLevelZeroTexture. + bool useLevelZeroTexture = mRenderer->getWorkarounds().zeroMaxLodWorkaround ? (mipLevels == 1) && (mMipLevels > 1) : false; + ID3D11Texture2D **outputTexture = useLevelZeroTexture ? &mLevelZeroTexture : &mTexture; + + // if the size is not positive this should be treated as an incomplete texture + // we handle that here by skipping the d3d texture creation + if (*outputTexture == NULL && mTextureWidth > 0 && mTextureHeight > 0) + { + ASSERT(mMipLevels > 0); + + ID3D11Device *device = mRenderer->getDevice(); + + D3D11_TEXTURE2D_DESC desc; + desc.Width = mTextureWidth; + desc.Height = mTextureHeight; + desc.MipLevels = mipLevels; + desc.ArraySize = CUBE_FACE_COUNT; + desc.Format = mTextureFormat; + desc.SampleDesc.Count = 1; + desc.SampleDesc.Quality = 0; + desc.Usage = D3D11_USAGE_DEFAULT; + desc.BindFlags = getBindFlags(); + desc.CPUAccessFlags = 0; + desc.MiscFlags = D3D11_RESOURCE_MISC_TEXTURECUBE; + + HRESULT result = device->CreateTexture2D(&desc, NULL, outputTexture); + + // this can happen from windows TDR + if (d3d11::isDeviceLostError(result)) + { + mRenderer->notifyDeviceLost(); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create cube texture storage, result: 0x%X.", result); + } + else if (FAILED(result)) + { + ASSERT(result == E_OUTOFMEMORY); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create cube texture storage, result: 0x%X.", result); + } + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureStorage11_Cube::getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT) +{ + int faceIndex = index.layerIndex; + int level = index.mipIndex; + + ASSERT(level >= 0 && level < getLevelCount()); + ASSERT(faceIndex >= 0 && faceIndex < CUBE_FACE_COUNT); + + if (!mRenderTarget[faceIndex][level]) + { + ID3D11Device *device = mRenderer->getDevice(); + HRESULT result; + + ID3D11Resource *texture = NULL; + gl::Error error = getResource(&texture); + if (error.isError()) + { + return error; + } + + if (mUseLevelZeroTexture) + { + if (!mLevelZeroRenderTarget[faceIndex]) + { + D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; + rtvDesc.Format = mRenderTargetFormat; + rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY; + rtvDesc.Texture2DArray.MipSlice = mTopLevel + level; + rtvDesc.Texture2DArray.FirstArraySlice = faceIndex; + rtvDesc.Texture2DArray.ArraySize = 1; + + ID3D11RenderTargetView *rtv; + result = device->CreateRenderTargetView(mLevelZeroTexture, &rtvDesc, &rtv); + + if (result == E_OUTOFMEMORY) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal render target view for texture storage, result: 0x%X.", result); + } + ASSERT(SUCCEEDED(result)); + + mLevelZeroRenderTarget[faceIndex] = new TextureRenderTarget11(rtv, mLevelZeroTexture, NULL, mInternalFormat, getLevelWidth(level), getLevelHeight(level), 1, 0); + + // RenderTarget will take ownership of these resources + SafeRelease(rtv); + } + + ASSERT(outRT); + *outRT = mLevelZeroRenderTarget[faceIndex]; + return gl::Error(GL_NO_ERROR); + } + + D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; + srvDesc.Format = mShaderResourceFormat; + srvDesc.Texture2DArray.MostDetailedMip = mTopLevel + level; + srvDesc.Texture2DArray.MipLevels = 1; + srvDesc.Texture2DArray.FirstArraySlice = faceIndex; + srvDesc.Texture2DArray.ArraySize = 1; + + if (mRenderer->getFeatureLevel() <= D3D_FEATURE_LEVEL_9_3) + { + srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBE; + } + else + { + srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY; // Will be used with Texture2D sampler, not TextureCube + } + + ID3D11ShaderResourceView *srv; + result = device->CreateShaderResourceView(texture, &srvDesc, &srv); + + ASSERT(result == E_OUTOFMEMORY || SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal shader resource view for texture storage, result: 0x%X.", result); + } + + if (mRenderTargetFormat != DXGI_FORMAT_UNKNOWN) + { + D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; + rtvDesc.Format = mRenderTargetFormat; + rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY; + rtvDesc.Texture2DArray.MipSlice = mTopLevel + level; + rtvDesc.Texture2DArray.FirstArraySlice = faceIndex; + rtvDesc.Texture2DArray.ArraySize = 1; + + ID3D11RenderTargetView *rtv; + result = device->CreateRenderTargetView(texture, &rtvDesc, &rtv); + + ASSERT(result == E_OUTOFMEMORY || SUCCEEDED(result)); + if (FAILED(result)) + { + SafeRelease(srv); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal render target view for texture storage, result: 0x%X.", result); + } + + mRenderTarget[faceIndex][level] = new TextureRenderTarget11(rtv, texture, srv, mInternalFormat, getLevelWidth(level), getLevelHeight(level), 1, 0); + + // RenderTarget will take ownership of these resources + SafeRelease(rtv); + SafeRelease(srv); + } + else if (mDepthStencilFormat != DXGI_FORMAT_UNKNOWN) + { + D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc; + dsvDesc.Format = mDepthStencilFormat; + dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DARRAY; + dsvDesc.Flags = 0; + dsvDesc.Texture2DArray.MipSlice = mTopLevel + level; + dsvDesc.Texture2DArray.FirstArraySlice = faceIndex; + dsvDesc.Texture2DArray.ArraySize = 1; + + ID3D11DepthStencilView *dsv; + result = device->CreateDepthStencilView(texture, &dsvDesc, &dsv); + + ASSERT(result == E_OUTOFMEMORY || SUCCEEDED(result)); + if (FAILED(result)) + { + SafeRelease(srv); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal depth stencil view for texture storage, result: 0x%X.", result); + } + + mRenderTarget[faceIndex][level] = new TextureRenderTarget11(dsv, texture, srv, mInternalFormat, getLevelWidth(level), getLevelHeight(level), 1, 0); + + // RenderTarget will take ownership of these resources + SafeRelease(dsv); + SafeRelease(srv); + } + else + { + UNREACHABLE(); + } + } + + ASSERT(outRT); + *outRT = mRenderTarget[faceIndex][level]; + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureStorage11_Cube::createSRV(int baseLevel, int mipLevels, DXGI_FORMAT format, ID3D11Resource *texture, + ID3D11ShaderResourceView **outSRV) const +{ + ASSERT(outSRV); + + D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; + srvDesc.Format = format; + + // Unnormalized integer cube maps are not supported by DX11; we emulate them as an array of six 2D textures + const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(format); + if (dxgiFormatInfo.componentType == GL_INT || dxgiFormatInfo.componentType == GL_UNSIGNED_INT) + { + srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY; + srvDesc.Texture2DArray.MostDetailedMip = mTopLevel + baseLevel; + srvDesc.Texture2DArray.MipLevels = 1; + srvDesc.Texture2DArray.FirstArraySlice = 0; + srvDesc.Texture2DArray.ArraySize = CUBE_FACE_COUNT; + } + else + { + srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBE; + srvDesc.TextureCube.MipLevels = mipLevels; + srvDesc.TextureCube.MostDetailedMip = mTopLevel + baseLevel; + } + + ID3D11Resource *srvTexture = texture; + + if (mRenderer->getWorkarounds().zeroMaxLodWorkaround) + { + ASSERT(mTopLevel == 0); + ASSERT(baseLevel == 0); + // This code also assumes that the incoming texture equals either mLevelZeroTexture or mTexture. + + if (mipLevels == 1 && mMipLevels > 1) + { + // We must use a SRV on the level-zero-only texture. + ASSERT(mLevelZeroTexture != NULL && texture == mLevelZeroTexture); + srvTexture = mLevelZeroTexture; + } + else + { + ASSERT(mipLevels == static_cast(mMipLevels)); + ASSERT(mTexture != NULL && texture == mTexture); + srvTexture = mTexture; + } + } + + ID3D11Device *device = mRenderer->getDevice(); + HRESULT result = device->CreateShaderResourceView(srvTexture, &srvDesc, outSRV); + + ASSERT(result == E_OUTOFMEMORY || SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal texture storage SRV, result: 0x%X.", result); + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureStorage11_Cube::getSwizzleTexture(ID3D11Resource **outTexture) +{ + ASSERT(outTexture); + + if (!mSwizzleTexture) + { + ID3D11Device *device = mRenderer->getDevice(); + + D3D11_TEXTURE2D_DESC desc; + desc.Width = mTextureWidth; + desc.Height = mTextureHeight; + desc.MipLevels = mMipLevels; + desc.ArraySize = CUBE_FACE_COUNT; + desc.Format = mSwizzleTextureFormat; + desc.SampleDesc.Count = 1; + desc.SampleDesc.Quality = 0; + desc.Usage = D3D11_USAGE_DEFAULT; + desc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET; + desc.CPUAccessFlags = 0; + desc.MiscFlags = D3D11_RESOURCE_MISC_TEXTURECUBE; + + HRESULT result = device->CreateTexture2D(&desc, NULL, &mSwizzleTexture); + + ASSERT(result == E_OUTOFMEMORY || SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal swizzle texture, result: 0x%X.", result); + } + } + + *outTexture = mSwizzleTexture; + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureStorage11_Cube::getSwizzleRenderTarget(int mipLevel, ID3D11RenderTargetView **outRTV) +{ + ASSERT(mipLevel >= 0 && mipLevel < getLevelCount()); + ASSERT(outRTV); + + if (!mSwizzleRenderTargets[mipLevel]) + { + ID3D11Resource *swizzleTexture = NULL; + gl::Error error = getSwizzleTexture(&swizzleTexture); + if (error.isError()) + { + return error; + } + + ID3D11Device *device = mRenderer->getDevice(); + + D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; + rtvDesc.Format = mSwizzleRenderTargetFormat; + rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY; + rtvDesc.Texture2DArray.MipSlice = mTopLevel + mipLevel; + rtvDesc.Texture2DArray.FirstArraySlice = 0; + rtvDesc.Texture2DArray.ArraySize = CUBE_FACE_COUNT; + + HRESULT result = device->CreateRenderTargetView(mSwizzleTexture, &rtvDesc, &mSwizzleRenderTargets[mipLevel]); + + ASSERT(result == E_OUTOFMEMORY || SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal swizzle render target view, result: 0x%X.", result); + } + } + + *outRTV = mSwizzleRenderTargets[mipLevel]; + return gl::Error(GL_NO_ERROR); +} + +TextureStorage11_3D::TextureStorage11_3D(Renderer11 *renderer, GLenum internalformat, bool renderTarget, + GLsizei width, GLsizei height, GLsizei depth, int levels) + : TextureStorage11(renderer, GetTextureBindFlags(internalformat, renderer->getFeatureLevel(), renderTarget)) +{ + mTexture = NULL; + mSwizzleTexture = NULL; + + for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) + { + mAssociatedImages[i] = NULL; + mLevelRenderTargets[i] = NULL; + mSwizzleRenderTargets[i] = NULL; + } + + mInternalFormat = internalformat; + + const d3d11::TextureFormat &formatInfo = d3d11::GetTextureFormatInfo(internalformat, renderer->getFeatureLevel()); + mTextureFormat = formatInfo.texFormat; + mShaderResourceFormat = formatInfo.srvFormat; + mDepthStencilFormat = formatInfo.dsvFormat; + mRenderTargetFormat = formatInfo.rtvFormat; + mSwizzleTextureFormat = formatInfo.swizzleTexFormat; + mSwizzleShaderResourceFormat = formatInfo.swizzleSRVFormat; + mSwizzleRenderTargetFormat = formatInfo.swizzleRTVFormat; + + // adjust size if needed for compressed textures + d3d11::MakeValidSize(false, mTextureFormat, &width, &height, &mTopLevel); + + mMipLevels = mTopLevel + levels; + mTextureWidth = width; + mTextureHeight = height; + mTextureDepth = depth; + + initializeSerials(getLevelCount() * depth, depth); +} + +TextureStorage11_3D::~TextureStorage11_3D() +{ + for (unsigned i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) + { + if (mAssociatedImages[i] != NULL) + { + bool imageAssociationCorrect = mAssociatedImages[i]->isAssociatedStorageValid(this); + ASSERT(imageAssociationCorrect); + + if (imageAssociationCorrect) + { + // We must let the Images recover their data before we delete it from the TextureStorage. + mAssociatedImages[i]->recoverFromAssociatedStorage(); + } + } + } + + SafeRelease(mTexture); + SafeRelease(mSwizzleTexture); + + for (RenderTargetMap::iterator i = mLevelLayerRenderTargets.begin(); i != mLevelLayerRenderTargets.end(); i++) + { + SafeDelete(i->second); + } + mLevelLayerRenderTargets.clear(); + + for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) + { + SafeDelete(mLevelRenderTargets[i]); + SafeRelease(mSwizzleRenderTargets[i]); + } +} + +TextureStorage11_3D *TextureStorage11_3D::makeTextureStorage11_3D(TextureStorage *storage) +{ + ASSERT(HAS_DYNAMIC_TYPE(TextureStorage11_3D*, storage)); + return static_cast(storage); +} + +void TextureStorage11_3D::associateImage(Image11* image, const gl::ImageIndex &index) +{ + GLint level = index.mipIndex; + + ASSERT(0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); + + if (0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) + { + mAssociatedImages[level] = image; + } +} + +bool TextureStorage11_3D::isAssociatedImageValid(const gl::ImageIndex &index, Image11* expectedImage) +{ + GLint level = index.mipIndex; + + if (0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) + { + // This validation check should never return false. It means the Image/TextureStorage association is broken. + bool retValue = (mAssociatedImages[level] == expectedImage); + ASSERT(retValue); + return retValue; + } + + return false; +} + +// disassociateImage allows an Image to end its association with a Storage. +void TextureStorage11_3D::disassociateImage(const gl::ImageIndex &index, Image11* expectedImage) +{ + GLint level = index.mipIndex; + + ASSERT(0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); + + if (0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) + { + ASSERT(mAssociatedImages[level] == expectedImage); + + if (mAssociatedImages[level] == expectedImage) + { + mAssociatedImages[level] = NULL; + } + } +} + +// releaseAssociatedImage prepares the Storage for a new Image association. It lets the old Image recover its data before ending the association. +gl::Error TextureStorage11_3D::releaseAssociatedImage(const gl::ImageIndex &index, Image11* incomingImage) +{ + GLint level = index.mipIndex; + + ASSERT((0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)); + + if (0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) + { + // No need to let the old Image recover its data, if it is also the incoming Image. + if (mAssociatedImages[level] != NULL && mAssociatedImages[level] != incomingImage) + { + // Ensure that the Image is still associated with this TextureStorage. This should be true. + bool imageAssociationCorrect = mAssociatedImages[level]->isAssociatedStorageValid(this); + ASSERT(imageAssociationCorrect); + + if (imageAssociationCorrect) + { + // Force the image to recover from storage before its data is overwritten. + // This will reset mAssociatedImages[level] to NULL too. + gl::Error error = mAssociatedImages[level]->recoverFromAssociatedStorage(); + if (error.isError()) + { + return error; + } + } + } + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureStorage11_3D::getResource(ID3D11Resource **outResource) +{ + // If the width, height or depth are not positive this should be treated as an incomplete texture + // we handle that here by skipping the d3d texture creation + if (mTexture == NULL && mTextureWidth > 0 && mTextureHeight > 0 && mTextureDepth > 0) + { + ASSERT(mMipLevels > 0); + + ID3D11Device *device = mRenderer->getDevice(); + + D3D11_TEXTURE3D_DESC desc; + desc.Width = mTextureWidth; + desc.Height = mTextureHeight; + desc.Depth = mTextureDepth; + desc.MipLevels = mMipLevels; + desc.Format = mTextureFormat; + desc.Usage = D3D11_USAGE_DEFAULT; + desc.BindFlags = getBindFlags(); + desc.CPUAccessFlags = 0; + desc.MiscFlags = 0; + + HRESULT result = device->CreateTexture3D(&desc, NULL, &mTexture); + + // this can happen from windows TDR + if (d3d11::isDeviceLostError(result)) + { + mRenderer->notifyDeviceLost(); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create 3D texture storage, result: 0x%X.", result); + } + else if (FAILED(result)) + { + ASSERT(result == E_OUTOFMEMORY); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create 3D texture storage, result: 0x%X.", result); + } + } + + *outResource = mTexture; + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureStorage11_3D::createSRV(int baseLevel, int mipLevels, DXGI_FORMAT format, ID3D11Resource *texture, + ID3D11ShaderResourceView **outSRV) const +{ + ASSERT(outSRV); + + D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; + srvDesc.Format = format; + srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE3D; + srvDesc.Texture3D.MostDetailedMip = baseLevel; + srvDesc.Texture3D.MipLevels = mipLevels; + + ID3D11Device *device = mRenderer->getDevice(); + HRESULT result = device->CreateShaderResourceView(texture, &srvDesc, outSRV); + + ASSERT(result == E_OUTOFMEMORY || SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal texture storage SRV, result: 0x%X.", result); + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureStorage11_3D::getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT) +{ + int mipLevel = index.mipIndex; + ASSERT(mipLevel >= 0 && mipLevel < getLevelCount()); + + ASSERT(mRenderTargetFormat != DXGI_FORMAT_UNKNOWN); + + if (!index.hasLayer()) + { + if (!mLevelRenderTargets[mipLevel]) + { + ID3D11Resource *texture = NULL; + gl::Error error = getResource(&texture); + if (error.isError()) + { + return error; + } + + ID3D11ShaderResourceView *srv = NULL; + error = getSRVLevel(mipLevel, &srv); + if (error.isError()) + { + return error; + } + + ID3D11Device *device = mRenderer->getDevice(); + + D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; + rtvDesc.Format = mRenderTargetFormat; + rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE3D; + rtvDesc.Texture3D.MipSlice = mTopLevel + mipLevel; + rtvDesc.Texture3D.FirstWSlice = 0; + rtvDesc.Texture3D.WSize = static_cast(-1); + + ID3D11RenderTargetView *rtv; + HRESULT result = device->CreateRenderTargetView(texture, &rtvDesc, &rtv); + + ASSERT(result == E_OUTOFMEMORY || SUCCEEDED(result)); + if (FAILED(result)) + { + SafeRelease(srv); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal render target view for texture storage, result: 0x%X.", result); + } + + mLevelRenderTargets[mipLevel] = new TextureRenderTarget11(rtv, texture, srv, mInternalFormat, getLevelWidth(mipLevel), getLevelHeight(mipLevel), getLevelDepth(mipLevel), 0); + + // RenderTarget will take ownership of these resources + SafeRelease(rtv); + } + + ASSERT(outRT); + *outRT = mLevelRenderTargets[mipLevel]; + return gl::Error(GL_NO_ERROR); + } + else + { + int layer = index.layerIndex; + + LevelLayerKey key(mipLevel, layer); + if (mLevelLayerRenderTargets.find(key) == mLevelLayerRenderTargets.end()) + { + ID3D11Device *device = mRenderer->getDevice(); + HRESULT result; + + ID3D11Resource *texture = NULL; + gl::Error error = getResource(&texture); + if (error.isError()) + { + return error; + } + + // TODO, what kind of SRV is expected here? + ID3D11ShaderResourceView *srv = NULL; + + D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; + rtvDesc.Format = mRenderTargetFormat; + rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE3D; + rtvDesc.Texture3D.MipSlice = mTopLevel + mipLevel; + rtvDesc.Texture3D.FirstWSlice = layer; + rtvDesc.Texture3D.WSize = 1; + + ID3D11RenderTargetView *rtv; + result = device->CreateRenderTargetView(texture, &rtvDesc, &rtv); + + ASSERT(result == E_OUTOFMEMORY || SUCCEEDED(result)); + if (FAILED(result)) + { + SafeRelease(srv); return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal render target view for texture storage, result: 0x%X.", result); + } + ASSERT(SUCCEEDED(result)); + + mLevelLayerRenderTargets[key] = new TextureRenderTarget11(rtv, texture, srv, mInternalFormat, getLevelWidth(mipLevel), getLevelHeight(mipLevel), 1, 0); + + // RenderTarget will take ownership of these resources + SafeRelease(rtv); + } + + ASSERT(outRT); + *outRT = mLevelLayerRenderTargets[key]; + return gl::Error(GL_NO_ERROR); + } +} + +gl::Error TextureStorage11_3D::getSwizzleTexture(ID3D11Resource **outTexture) +{ + ASSERT(outTexture); + + if (!mSwizzleTexture) + { + ID3D11Device *device = mRenderer->getDevice(); + + D3D11_TEXTURE3D_DESC desc; + desc.Width = mTextureWidth; + desc.Height = mTextureHeight; + desc.Depth = mTextureDepth; + desc.MipLevels = mMipLevels; + desc.Format = mSwizzleTextureFormat; + desc.Usage = D3D11_USAGE_DEFAULT; + desc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET; + desc.CPUAccessFlags = 0; + desc.MiscFlags = 0; + + HRESULT result = device->CreateTexture3D(&desc, NULL, &mSwizzleTexture); + + ASSERT(result == E_OUTOFMEMORY || SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal swizzle texture, result: 0x%X.", result); + } + } + + *outTexture = mSwizzleTexture; + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureStorage11_3D::getSwizzleRenderTarget(int mipLevel, ID3D11RenderTargetView **outRTV) +{ + ASSERT(mipLevel >= 0 && mipLevel < getLevelCount()); + ASSERT(outRTV); + + if (!mSwizzleRenderTargets[mipLevel]) + { + ID3D11Resource *swizzleTexture = NULL; + gl::Error error = getSwizzleTexture(&swizzleTexture); + if (error.isError()) + { + return error; + } + + ID3D11Device *device = mRenderer->getDevice(); + + D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; + rtvDesc.Format = mSwizzleRenderTargetFormat; + rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE3D; + rtvDesc.Texture3D.MipSlice = mTopLevel + mipLevel; + rtvDesc.Texture3D.FirstWSlice = 0; + rtvDesc.Texture3D.WSize = static_cast(-1); + + HRESULT result = device->CreateRenderTargetView(mSwizzleTexture, &rtvDesc, &mSwizzleRenderTargets[mipLevel]); + + ASSERT(result == E_OUTOFMEMORY || SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal swizzle render target view, result: 0x%X.", result); + } + } + + *outRTV = mSwizzleRenderTargets[mipLevel]; + return gl::Error(GL_NO_ERROR); +} + +TextureStorage11_2DArray::TextureStorage11_2DArray(Renderer11 *renderer, GLenum internalformat, bool renderTarget, + GLsizei width, GLsizei height, GLsizei depth, int levels) + : TextureStorage11(renderer, GetTextureBindFlags(internalformat, renderer->getFeatureLevel(), renderTarget)) +{ + mTexture = NULL; + mSwizzleTexture = NULL; + + for (unsigned int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) + { + mSwizzleRenderTargets[level] = NULL; + } + + mInternalFormat = internalformat; + + const d3d11::TextureFormat &formatInfo = d3d11::GetTextureFormatInfo(internalformat, renderer->getFeatureLevel()); + mTextureFormat = formatInfo.texFormat; + mShaderResourceFormat = formatInfo.srvFormat; + mDepthStencilFormat = formatInfo.dsvFormat; + mRenderTargetFormat = formatInfo.rtvFormat; + mSwizzleTextureFormat = formatInfo.swizzleTexFormat; + mSwizzleShaderResourceFormat = formatInfo.swizzleSRVFormat; + mSwizzleRenderTargetFormat = formatInfo.swizzleRTVFormat; + + // adjust size if needed for compressed textures + d3d11::MakeValidSize(false, mTextureFormat, &width, &height, &mTopLevel); + + mMipLevels = mTopLevel + levels; + mTextureWidth = width; + mTextureHeight = height; + mTextureDepth = depth; + + initializeSerials(getLevelCount() * depth, depth); +} + +TextureStorage11_2DArray::~TextureStorage11_2DArray() +{ + for (ImageMap::iterator i = mAssociatedImages.begin(); i != mAssociatedImages.end(); i++) + { + if (i->second) + { + bool imageAssociationCorrect = i->second->isAssociatedStorageValid(this); + ASSERT(imageAssociationCorrect); + + if (imageAssociationCorrect) + { + // We must let the Images recover their data before we delete it from the TextureStorage. + i->second->recoverFromAssociatedStorage(); + } + } + } + mAssociatedImages.clear(); + + SafeRelease(mTexture); + SafeRelease(mSwizzleTexture); + + for (unsigned int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) + { + SafeRelease(mSwizzleRenderTargets[level]); + } + + for (RenderTargetMap::iterator i = mRenderTargets.begin(); i != mRenderTargets.end(); i++) + { + SafeDelete(i->second); + } + mRenderTargets.clear(); +} + +TextureStorage11_2DArray *TextureStorage11_2DArray::makeTextureStorage11_2DArray(TextureStorage *storage) +{ + ASSERT(HAS_DYNAMIC_TYPE(TextureStorage11_2DArray*, storage)); + return static_cast(storage); +} + +void TextureStorage11_2DArray::associateImage(Image11* image, const gl::ImageIndex &index) +{ + GLint level = index.mipIndex; + GLint layerTarget = index.layerIndex; + + ASSERT(0 <= level && level < getLevelCount()); + + if (0 <= level && level < getLevelCount()) + { + LevelLayerKey key(level, layerTarget); + mAssociatedImages[key] = image; + } +} + +bool TextureStorage11_2DArray::isAssociatedImageValid(const gl::ImageIndex &index, Image11* expectedImage) +{ + GLint level = index.mipIndex; + GLint layerTarget = index.layerIndex; + + LevelLayerKey key(level, layerTarget); + + // This validation check should never return false. It means the Image/TextureStorage association is broken. + bool retValue = (mAssociatedImages.find(key) != mAssociatedImages.end() && (mAssociatedImages[key] == expectedImage)); + ASSERT(retValue); + return retValue; +} + +// disassociateImage allows an Image to end its association with a Storage. +void TextureStorage11_2DArray::disassociateImage(const gl::ImageIndex &index, Image11* expectedImage) +{ + GLint level = index.mipIndex; + GLint layerTarget = index.layerIndex; + + LevelLayerKey key(level, layerTarget); + + bool imageAssociationCorrect = (mAssociatedImages.find(key) != mAssociatedImages.end() && (mAssociatedImages[key] == expectedImage)); + ASSERT(imageAssociationCorrect); + + if (imageAssociationCorrect) + { + mAssociatedImages[key] = NULL; + } +} + +// releaseAssociatedImage prepares the Storage for a new Image association. It lets the old Image recover its data before ending the association. +gl::Error TextureStorage11_2DArray::releaseAssociatedImage(const gl::ImageIndex &index, Image11* incomingImage) +{ + GLint level = index.mipIndex; + GLint layerTarget = index.layerIndex; + + LevelLayerKey key(level, layerTarget); + + if (mAssociatedImages.find(key) != mAssociatedImages.end()) + { + if (mAssociatedImages[key] != NULL && mAssociatedImages[key] != incomingImage) + { + // Ensure that the Image is still associated with this TextureStorage. This should be true. + bool imageAssociationCorrect = mAssociatedImages[key]->isAssociatedStorageValid(this); + ASSERT(imageAssociationCorrect); + + if (imageAssociationCorrect) + { + // Force the image to recover from storage before its data is overwritten. + // This will reset mAssociatedImages[level] to NULL too. + gl::Error error = mAssociatedImages[key]->recoverFromAssociatedStorage(); + if (error.isError()) + { + return error; + } + } + } + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureStorage11_2DArray::getResource(ID3D11Resource **outResource) +{ + // if the width, height or depth is not positive this should be treated as an incomplete texture + // we handle that here by skipping the d3d texture creation + if (mTexture == NULL && mTextureWidth > 0 && mTextureHeight > 0 && mTextureDepth > 0) + { + ASSERT(mMipLevels > 0); + + ID3D11Device *device = mRenderer->getDevice(); + + D3D11_TEXTURE2D_DESC desc; + desc.Width = mTextureWidth; + desc.Height = mTextureHeight; + desc.MipLevels = mMipLevels; + desc.ArraySize = mTextureDepth; + desc.Format = mTextureFormat; + desc.SampleDesc.Count = 1; + desc.SampleDesc.Quality = 0; + desc.Usage = D3D11_USAGE_DEFAULT; + desc.BindFlags = getBindFlags(); + desc.CPUAccessFlags = 0; + desc.MiscFlags = 0; + + HRESULT result = device->CreateTexture2D(&desc, NULL, &mTexture); + + // this can happen from windows TDR + if (d3d11::isDeviceLostError(result)) + { + mRenderer->notifyDeviceLost(); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create 2D array texture storage, result: 0x%X.", result); + } + else if (FAILED(result)) + { + ASSERT(result == E_OUTOFMEMORY); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create 2D array texture storage, result: 0x%X.", result); + } + } + + *outResource = mTexture; + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureStorage11_2DArray::createSRV(int baseLevel, int mipLevels, DXGI_FORMAT format, ID3D11Resource *texture, + ID3D11ShaderResourceView **outSRV) const +{ + D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; + srvDesc.Format = format; + srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY; + srvDesc.Texture2DArray.MostDetailedMip = mTopLevel + baseLevel; + srvDesc.Texture2DArray.MipLevels = mipLevels; + srvDesc.Texture2DArray.FirstArraySlice = 0; + srvDesc.Texture2DArray.ArraySize = mTextureDepth; + + ID3D11Device *device = mRenderer->getDevice(); + HRESULT result = device->CreateShaderResourceView(texture, &srvDesc, outSRV); + + ASSERT(result == E_OUTOFMEMORY || SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal texture storage SRV, result: 0x%X.", result); + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureStorage11_2DArray::getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT) +{ + ASSERT(index.hasLayer()); + + int mipLevel = index.mipIndex; + int layer = index.layerIndex; + + ASSERT(mipLevel >= 0 && mipLevel < getLevelCount()); + + LevelLayerKey key(mipLevel, layer); + if (mRenderTargets.find(key) == mRenderTargets.end()) + { + ID3D11Device *device = mRenderer->getDevice(); + HRESULT result; + + ID3D11Resource *texture = NULL; + gl::Error error = getResource(&texture); + if (error.isError()) + { + return error; + } + + D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; + srvDesc.Format = mShaderResourceFormat; + srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY; + srvDesc.Texture2DArray.MostDetailedMip = mTopLevel + mipLevel; + srvDesc.Texture2DArray.MipLevels = 1; + srvDesc.Texture2DArray.FirstArraySlice = layer; + srvDesc.Texture2DArray.ArraySize = 1; + + ID3D11ShaderResourceView *srv; + result = device->CreateShaderResourceView(texture, &srvDesc, &srv); + + ASSERT(result == E_OUTOFMEMORY || SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal shader resource view for texture storage, result: 0x%X.", result); + } + + if (mRenderTargetFormat != DXGI_FORMAT_UNKNOWN) + { + D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; + rtvDesc.Format = mRenderTargetFormat; + rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY; + rtvDesc.Texture2DArray.MipSlice = mTopLevel + mipLevel; + rtvDesc.Texture2DArray.FirstArraySlice = layer; + rtvDesc.Texture2DArray.ArraySize = 1; + + ID3D11RenderTargetView *rtv; + result = device->CreateRenderTargetView(texture, &rtvDesc, &rtv); + + ASSERT(result == E_OUTOFMEMORY || SUCCEEDED(result)); + if (FAILED(result)) + { + SafeRelease(srv); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal render target view for texture storage, result: 0x%X.", result); + } + + mRenderTargets[key] = new TextureRenderTarget11(rtv, texture, srv, mInternalFormat, getLevelWidth(mipLevel), getLevelHeight(mipLevel), 1, 0); + + // RenderTarget will take ownership of these resources + SafeRelease(rtv); + SafeRelease(srv); + } + else + { + UNREACHABLE(); + } + } + + ASSERT(outRT); + *outRT = mRenderTargets[key]; + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureStorage11_2DArray::getSwizzleTexture(ID3D11Resource **outTexture) +{ + if (!mSwizzleTexture) + { + ID3D11Device *device = mRenderer->getDevice(); + + D3D11_TEXTURE2D_DESC desc; + desc.Width = mTextureWidth; + desc.Height = mTextureHeight; + desc.MipLevels = mMipLevels; + desc.ArraySize = mTextureDepth; + desc.Format = mSwizzleTextureFormat; + desc.SampleDesc.Count = 1; + desc.SampleDesc.Quality = 0; + desc.Usage = D3D11_USAGE_DEFAULT; + desc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET; + desc.CPUAccessFlags = 0; + desc.MiscFlags = 0; + + HRESULT result = device->CreateTexture2D(&desc, NULL, &mSwizzleTexture); + + ASSERT(result == E_OUTOFMEMORY || SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal swizzle texture, result: 0x%X.", result); + } + } + + *outTexture = mSwizzleTexture; + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureStorage11_2DArray::getSwizzleRenderTarget(int mipLevel, ID3D11RenderTargetView **outRTV) +{ + ASSERT(mipLevel >= 0 && mipLevel < getLevelCount()); + ASSERT(outRTV); + + if (!mSwizzleRenderTargets[mipLevel]) + { + ID3D11Resource *swizzleTexture = NULL; + gl::Error error = getSwizzleTexture(&swizzleTexture); + if (error.isError()) + { + return error; + } + + ID3D11Device *device = mRenderer->getDevice(); + + D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; + rtvDesc.Format = mSwizzleRenderTargetFormat; + rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY; + rtvDesc.Texture2DArray.MipSlice = mTopLevel + mipLevel; + rtvDesc.Texture2DArray.FirstArraySlice = 0; + rtvDesc.Texture2DArray.ArraySize = mTextureDepth; + + HRESULT result = device->CreateRenderTargetView(mSwizzleTexture, &rtvDesc, &mSwizzleRenderTargets[mipLevel]); + + ASSERT(result == E_OUTOFMEMORY || SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal swizzle render target view, result: 0x%X.", result); + } + } + + *outRTV = mSwizzleRenderTargets[mipLevel]; + return gl::Error(GL_NO_ERROR); +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/TextureStorage11.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/TextureStorage11.h new file mode 100644 index 0000000000..456e2660f9 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/TextureStorage11.h @@ -0,0 +1,326 @@ +// +// Copyright (c) 2012-2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// TextureStorage11.h: Defines the abstract rx::TextureStorage11 class and its concrete derived +// classes TextureStorage11_2D and TextureStorage11_Cube, which act as the interface to the D3D11 texture. + +#ifndef LIBANGLE_RENDERER_D3D_D3D11_TEXTURESTORAGE11_H_ +#define LIBANGLE_RENDERER_D3D_D3D11_TEXTURESTORAGE11_H_ + +#include "libANGLE/Texture.h" +#include "libANGLE/Error.h" +#include "libANGLE/renderer/d3d/TextureStorage.h" + +#include + +namespace gl +{ +struct ImageIndex; +} + +namespace rx +{ +class RenderTargetD3D; +class RenderTarget11; +class Renderer11; +class SwapChain11; +class Image11; + +class TextureStorage11 : public TextureStorage +{ + public: + virtual ~TextureStorage11(); + + static TextureStorage11 *makeTextureStorage11(TextureStorage *storage); + + static DWORD GetTextureBindFlags(GLenum internalFormat, D3D_FEATURE_LEVEL featureLevel, bool renderTarget); + + UINT getBindFlags() const; + + virtual gl::Error getResource(ID3D11Resource **outResource) = 0; + virtual gl::Error getSRV(const gl::SamplerState &samplerState, ID3D11ShaderResourceView **outSRV); + virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT) = 0; + + virtual gl::Error generateMipmap(const gl::ImageIndex &sourceIndex, const gl::ImageIndex &destIndex); + + virtual int getTopLevel() const; + virtual bool isRenderTarget() const; + virtual bool isManaged() const; + virtual int getLevelCount() const; + virtual UINT getSubresourceIndex(const gl::ImageIndex &index) const; + + gl::Error generateSwizzles(GLenum swizzleRed, GLenum swizzleGreen, GLenum swizzleBlue, GLenum swizzleAlpha); + void invalidateSwizzleCacheLevel(int mipLevel); + void invalidateSwizzleCache(); + + gl::Error updateSubresourceLevel(ID3D11Resource *texture, unsigned int sourceSubresource, + const gl::ImageIndex &index, const gl::Box ©Area); + + gl::Error copySubresourceLevel(ID3D11Resource* dstTexture, unsigned int dstSubresource, + const gl::ImageIndex &index, const gl::Box ®ion); + + virtual void associateImage(Image11* image, const gl::ImageIndex &index) = 0; + virtual void disassociateImage(const gl::ImageIndex &index, Image11* expectedImage) = 0; + virtual bool isAssociatedImageValid(const gl::ImageIndex &index, Image11* expectedImage) = 0; + virtual gl::Error releaseAssociatedImage(const gl::ImageIndex &index, Image11* incomingImage) = 0; + + virtual gl::Error copyToStorage(TextureStorage *destStorage); + virtual gl::Error setData(const gl::ImageIndex &index, ImageD3D *image, const gl::Box *destBox, GLenum type, + const gl::PixelUnpackState &unpack, const uint8_t *pixelData); + + protected: + TextureStorage11(Renderer11 *renderer, UINT bindFlags); + int getLevelWidth(int mipLevel) const; + int getLevelHeight(int mipLevel) const; + int getLevelDepth(int mipLevel) const; + + // Some classes (e.g. TextureStorage11_2D) will override getMippedResource. + virtual gl::Error getMippedResource(ID3D11Resource **outResource) { return getResource(outResource); } + + virtual gl::Error getSwizzleTexture(ID3D11Resource **outTexture) = 0; + virtual gl::Error getSwizzleRenderTarget(int mipLevel, ID3D11RenderTargetView **outRTV) = 0; + gl::Error getSRVLevel(int mipLevel, ID3D11ShaderResourceView **outSRV); + + virtual gl::Error createSRV(int baseLevel, int mipLevels, DXGI_FORMAT format, ID3D11Resource *texture, + ID3D11ShaderResourceView **outSRV) const = 0; + + void verifySwizzleExists(GLenum swizzleRed, GLenum swizzleGreen, GLenum swizzleBlue, GLenum swizzleAlpha); + + Renderer11 *mRenderer; + int mTopLevel; + unsigned int mMipLevels; + + GLenum mInternalFormat; + DXGI_FORMAT mTextureFormat; + DXGI_FORMAT mShaderResourceFormat; + DXGI_FORMAT mRenderTargetFormat; + DXGI_FORMAT mDepthStencilFormat; + DXGI_FORMAT mSwizzleTextureFormat; + DXGI_FORMAT mSwizzleShaderResourceFormat; + DXGI_FORMAT mSwizzleRenderTargetFormat; + unsigned int mTextureWidth; + unsigned int mTextureHeight; + unsigned int mTextureDepth; + + struct SwizzleCacheValue + { + GLenum swizzleRed; + GLenum swizzleGreen; + GLenum swizzleBlue; + GLenum swizzleAlpha; + + SwizzleCacheValue(); + SwizzleCacheValue(GLenum red, GLenum green, GLenum blue, GLenum alpha); + + bool operator ==(const SwizzleCacheValue &other) const; + bool operator !=(const SwizzleCacheValue &other) const; + }; + SwizzleCacheValue mSwizzleCache[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; + + private: + const UINT mBindFlags; + + struct SRVKey + { + SRVKey(int baseLevel = 0, int mipLevels = 0, bool swizzle = false); + + bool operator<(const SRVKey &rhs) const; + + int baseLevel; + int mipLevels; + bool swizzle; + }; + typedef std::map SRVCache; + + SRVCache mSrvCache; + ID3D11ShaderResourceView *mLevelSRVs[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; +}; + +class TextureStorage11_2D : public TextureStorage11 +{ + public: + TextureStorage11_2D(Renderer11 *renderer, SwapChain11 *swapchain); + TextureStorage11_2D(Renderer11 *renderer, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels, bool hintLevelZeroOnly = false); + virtual ~TextureStorage11_2D(); + + static TextureStorage11_2D *makeTextureStorage11_2D(TextureStorage *storage); + + virtual gl::Error getResource(ID3D11Resource **outResource); + virtual gl::Error getMippedResource(ID3D11Resource **outResource); + virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT); + + virtual gl::Error copyToStorage(TextureStorage *destStorage); + + virtual void associateImage(Image11* image, const gl::ImageIndex &index); + virtual void disassociateImage(const gl::ImageIndex &index, Image11* expectedImage); + virtual bool isAssociatedImageValid(const gl::ImageIndex &index, Image11* expectedImage); + virtual gl::Error releaseAssociatedImage(const gl::ImageIndex &index, Image11* incomingImage); + + virtual gl::Error useLevelZeroWorkaroundTexture(bool useLevelZeroTexture); + + protected: + virtual gl::Error getSwizzleTexture(ID3D11Resource **outTexture); + virtual gl::Error getSwizzleRenderTarget(int mipLevel, ID3D11RenderTargetView **outRTV); + + gl::Error ensureTextureExists(int mipLevels); + + private: + virtual gl::Error createSRV(int baseLevel, int mipLevels, DXGI_FORMAT format, ID3D11Resource *texture, + ID3D11ShaderResourceView **outSRV) const; + + ID3D11Texture2D *mTexture; + RenderTarget11 *mRenderTarget[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; + + // These are members related to the zero max-LOD workaround. + // D3D11 Feature Level 9_3 can't disable mipmaps on a mipmapped texture (i.e. solely sample from level zero). + // These members are used to work around this limitation. + // Usually only mTexture XOR mLevelZeroTexture will exist. + // For example, if an app creates a texture with only one level, then 9_3 will only create mLevelZeroTexture. + // However, in some scenarios, both textures have to be created. This incurs additional memory overhead. + // One example of this is an application that creates a texture, calls glGenerateMipmap, and then disables mipmaps on the texture. + // A more likely example is an app that creates an empty texture, renders to it, and then calls glGenerateMipmap + // TODO: In this rendering scenario, release the mLevelZeroTexture after mTexture has been created to save memory. + ID3D11Texture2D *mLevelZeroTexture; + RenderTarget11 *mLevelZeroRenderTarget; + bool mUseLevelZeroTexture; + + // Swizzle-related variables + ID3D11Texture2D *mSwizzleTexture; + ID3D11RenderTargetView *mSwizzleRenderTargets[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; + + Image11 *mAssociatedImages[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; +}; + +class TextureStorage11_Cube : public TextureStorage11 +{ + public: + TextureStorage11_Cube(Renderer11 *renderer, GLenum internalformat, bool renderTarget, int size, int levels, bool hintLevelZeroOnly); + virtual ~TextureStorage11_Cube(); + + static TextureStorage11_Cube *makeTextureStorage11_Cube(TextureStorage *storage); + + virtual UINT getSubresourceIndex(const gl::ImageIndex &index) const; + + virtual gl::Error getResource(ID3D11Resource **outResource); + virtual gl::Error getMippedResource(ID3D11Resource **outResource); + virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT); + + virtual gl::Error copyToStorage(TextureStorage *destStorage); + + virtual void associateImage(Image11* image, const gl::ImageIndex &index); + virtual void disassociateImage(const gl::ImageIndex &index, Image11* expectedImage); + virtual bool isAssociatedImageValid(const gl::ImageIndex &index, Image11* expectedImage); + virtual gl::Error releaseAssociatedImage(const gl::ImageIndex &index, Image11* incomingImage); + + virtual gl::Error useLevelZeroWorkaroundTexture(bool useLevelZeroTexture); + + protected: + virtual gl::Error getSwizzleTexture(ID3D11Resource **outTexture); + virtual gl::Error getSwizzleRenderTarget(int mipLevel, ID3D11RenderTargetView **outRTV); + + gl::Error ensureTextureExists(int mipLevels); + + private: + virtual gl::Error createSRV(int baseLevel, int mipLevels, DXGI_FORMAT format, ID3D11Resource *texture, + ID3D11ShaderResourceView **outSRV) const; + + static const size_t CUBE_FACE_COUNT = 6; + + ID3D11Texture2D *mTexture; + RenderTarget11 *mRenderTarget[CUBE_FACE_COUNT][gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; + + // Level-zero workaround members. See TextureStorage11_2D's workaround members for a description. + ID3D11Texture2D *mLevelZeroTexture; + RenderTarget11 *mLevelZeroRenderTarget[CUBE_FACE_COUNT]; + bool mUseLevelZeroTexture; + + ID3D11Texture2D *mSwizzleTexture; + ID3D11RenderTargetView *mSwizzleRenderTargets[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; + + Image11 *mAssociatedImages[CUBE_FACE_COUNT][gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; +}; + +class TextureStorage11_3D : public TextureStorage11 +{ + public: + TextureStorage11_3D(Renderer11 *renderer, GLenum internalformat, bool renderTarget, + GLsizei width, GLsizei height, GLsizei depth, int levels); + virtual ~TextureStorage11_3D(); + + static TextureStorage11_3D *makeTextureStorage11_3D(TextureStorage *storage); + + virtual gl::Error getResource(ID3D11Resource **outResource); + + // Handles both layer and non-layer RTs + virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT); + + virtual void associateImage(Image11* image, const gl::ImageIndex &index); + virtual void disassociateImage(const gl::ImageIndex &index, Image11* expectedImage); + virtual bool isAssociatedImageValid(const gl::ImageIndex &index, Image11* expectedImage); + virtual gl::Error releaseAssociatedImage(const gl::ImageIndex &index, Image11* incomingImage); + + protected: + virtual gl::Error getSwizzleTexture(ID3D11Resource **outTexture); + virtual gl::Error getSwizzleRenderTarget(int mipLevel, ID3D11RenderTargetView **outRTV); + + private: + virtual gl::Error createSRV(int baseLevel, int mipLevels, DXGI_FORMAT format, ID3D11Resource *texture, + ID3D11ShaderResourceView **outSRV) const; + + typedef std::pair LevelLayerKey; + typedef std::map RenderTargetMap; + RenderTargetMap mLevelLayerRenderTargets; + + RenderTarget11 *mLevelRenderTargets[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; + + ID3D11Texture3D *mTexture; + ID3D11Texture3D *mSwizzleTexture; + ID3D11RenderTargetView *mSwizzleRenderTargets[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; + + Image11 *mAssociatedImages[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; +}; + +class TextureStorage11_2DArray : public TextureStorage11 +{ + public: + TextureStorage11_2DArray(Renderer11 *renderer, GLenum internalformat, bool renderTarget, + GLsizei width, GLsizei height, GLsizei depth, int levels); + virtual ~TextureStorage11_2DArray(); + + static TextureStorage11_2DArray *makeTextureStorage11_2DArray(TextureStorage *storage); + + virtual gl::Error getResource(ID3D11Resource **outResource); + virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT); + + virtual void associateImage(Image11* image, const gl::ImageIndex &index); + virtual void disassociateImage(const gl::ImageIndex &index, Image11* expectedImage); + virtual bool isAssociatedImageValid(const gl::ImageIndex &index, Image11* expectedImage); + virtual gl::Error releaseAssociatedImage(const gl::ImageIndex &index, Image11* incomingImage); + + protected: + virtual gl::Error getSwizzleTexture(ID3D11Resource **outTexture); + virtual gl::Error getSwizzleRenderTarget(int mipLevel, ID3D11RenderTargetView **outRTV); + + private: + virtual gl::Error createSRV(int baseLevel, int mipLevels, DXGI_FORMAT format, ID3D11Resource *texture, + ID3D11ShaderResourceView **outSRV) const; + + typedef std::pair LevelLayerKey; + typedef std::map RenderTargetMap; + RenderTargetMap mRenderTargets; + + ID3D11Texture2D *mTexture; + + ID3D11Texture2D *mSwizzleTexture; + ID3D11RenderTargetView *mSwizzleRenderTargets[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; + + typedef std::map ImageMap; + ImageMap mAssociatedImages; +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_D3D11_TEXTURESTORAGE11_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Trim11.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Trim11.cpp new file mode 100644 index 0000000000..213ce31817 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Trim11.cpp @@ -0,0 +1,95 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Trim11.cpp: Trim support utility class. + +#include "libANGLE/renderer/d3d/d3d11/Trim11.h" +#include "libANGLE/renderer/d3d/d3d11/Renderer11.h" +#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h" + +#if defined (ANGLE_ENABLE_WINDOWS_STORE) +using namespace ABI::Windows::Foundation; +using namespace ABI::Windows::ApplicationModel; +using namespace ABI::Windows::ApplicationModel::Core; +#endif + +namespace rx +{ + +Trim11::Trim11(rx::Renderer11 *renderer) + : mRenderer(renderer) +{ + bool result = true; + result = registerForRendererTrimRequest(); + ASSERT(result); +} + +Trim11::~Trim11() +{ + unregisterForRendererTrimRequest(); +} + +void Trim11::trim() +{ + if (!mRenderer) + { + return; + } + +#if defined (ANGLE_ENABLE_WINDOWS_STORE) + ID3D11Device* device = mRenderer->getDevice(); + // IDXGIDevice3 is only supported on Windows 8.1 and Windows Phone 8.1 and above. + IDXGIDevice3 *dxgiDevice3 = d3d11::DynamicCastComObject(device); + if (dxgiDevice3) + { + dxgiDevice3->Trim(); + } + SafeRelease(dxgiDevice3); +#endif +} + +bool Trim11::registerForRendererTrimRequest() +{ +#if defined (ANGLE_ENABLE_WINDOWS_STORE) + ICoreApplication* coreApplication = nullptr; + HRESULT result = GetActivationFactory(HStringReference(RuntimeClass_Windows_ApplicationModel_Core_CoreApplication).Get(), &coreApplication); + if (SUCCEEDED(result)) + { + auto suspendHandler = Callback>( + [this](IInspectable*, ISuspendingEventArgs*) -> HRESULT + { + trim(); + return S_OK; + }); + result = coreApplication->add_Suspending(suspendHandler.Get(), &mApplicationSuspendedEventToken); + } + SafeRelease(coreApplication); + + if (FAILED(result)) + { + return false; + } +#endif + return true; +} + +void Trim11::unregisterForRendererTrimRequest() +{ +#if defined (ANGLE_ENABLE_WINDOWS_STORE) + if (mApplicationSuspendedEventToken.value != 0) + { + ICoreApplication* coreApplication = nullptr; + if (SUCCEEDED(GetActivationFactory(HStringReference(RuntimeClass_Windows_ApplicationModel_Core_CoreApplication).Get(), &coreApplication))) + { + coreApplication->remove_Suspending(mApplicationSuspendedEventToken); + } + mApplicationSuspendedEventToken.value = 0; + SafeRelease(coreApplication); + } +#endif +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Trim11.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Trim11.h new file mode 100644 index 0000000000..f232ad7e8e --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Trim11.h @@ -0,0 +1,43 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Trim11.h: Trim support utility class. + +#ifndef LIBANGLE_RENDERER_D3D_D3D11_TRIM11_H_ +#define LIBANGLE_RENDERER_D3D_D3D11_TRIM11_H_ + +#include "common/angleutils.h" +#include "libANGLE/angletypes.h" +#include "libANGLE/Error.h" + +#if !defined(ANGLE_ENABLE_WINDOWS_STORE) +typedef void* EventRegistrationToken; +#else +#include +#endif + +namespace rx +{ +class Renderer11; + +class Trim11 : angle::NonCopyable +{ + public: + explicit Trim11(Renderer11 *renderer); + ~Trim11(); + + private: + Renderer11 *mRenderer; + EventRegistrationToken mApplicationSuspendedEventToken; + + void trim(); + bool registerForRendererTrimRequest(); + void unregisterForRendererTrimRequest(); +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_D3D11_TRIM11_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/VertexArray11.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/VertexArray11.h new file mode 100644 index 0000000000..78aad7d106 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/VertexArray11.h @@ -0,0 +1,40 @@ +// +// Copyright 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// VertexArray11.h: Defines the rx::VertexArray11 class which implements rx::VertexArrayImpl. + +#ifndef LIBANGLE_RENDERER_D3D_D3D11_VERTEXARRAY11_H_ +#define LIBANGLE_RENDERER_D3D_D3D11_VERTEXARRAY11_H_ + +#include "libANGLE/renderer/VertexArrayImpl.h" +#include "libANGLE/renderer/d3d/d3d11/Renderer11.h" + +namespace rx +{ +class Renderer11; + +class VertexArray11 : public VertexArrayImpl +{ + public: + VertexArray11(Renderer11 *renderer) + : VertexArrayImpl(), + mRenderer(renderer) + { + } + virtual ~VertexArray11() { } + + virtual void setElementArrayBuffer(const gl::Buffer *buffer) { } + virtual void setAttribute(size_t idx, const gl::VertexAttribute &attr) { } + virtual void setAttributeDivisor(size_t idx, GLuint divisor) { } + virtual void enableAttribute(size_t idx, bool enabledState) { } + + private: + Renderer11 *mRenderer; +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_D3D11_VERTEXARRAY11_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/VertexBuffer11.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/VertexBuffer11.cpp new file mode 100644 index 0000000000..adc64cef5e --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/VertexBuffer11.cpp @@ -0,0 +1,244 @@ +// +// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// VertexBuffer11.cpp: Defines the D3D11 VertexBuffer implementation. + +#include "libANGLE/renderer/d3d/d3d11/VertexBuffer11.h" +#include "libANGLE/renderer/d3d/d3d11/Buffer11.h" +#include "libANGLE/renderer/d3d/d3d11/Renderer11.h" +#include "libANGLE/renderer/d3d/d3d11/formatutils11.h" +#include "libANGLE/Buffer.h" +#include "libANGLE/VertexAttribute.h" + +namespace rx +{ + +VertexBuffer11::VertexBuffer11(Renderer11 *const renderer) : mRenderer(renderer) +{ + mBuffer = NULL; + mBufferSize = 0; + mDynamicUsage = false; + mMappedResourceData = NULL; +} + +VertexBuffer11::~VertexBuffer11() +{ + ASSERT(mMappedResourceData == NULL); + SafeRelease(mBuffer); +} + +gl::Error VertexBuffer11::initialize(unsigned int size, bool dynamicUsage) +{ + SafeRelease(mBuffer); + + updateSerial(); + + if (size > 0) + { + ID3D11Device* dxDevice = mRenderer->getDevice(); + + D3D11_BUFFER_DESC bufferDesc; + bufferDesc.ByteWidth = size; + bufferDesc.Usage = D3D11_USAGE_DYNAMIC; + bufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; + bufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + bufferDesc.MiscFlags = 0; + bufferDesc.StructureByteStride = 0; + + HRESULT result = dxDevice->CreateBuffer(&bufferDesc, NULL, &mBuffer); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate internal vertex buffer of size, %lu.", size); + } + } + + mBufferSize = size; + mDynamicUsage = dynamicUsage; + + return gl::Error(GL_NO_ERROR); +} + +VertexBuffer11 *VertexBuffer11::makeVertexBuffer11(VertexBuffer *vetexBuffer) +{ + ASSERT(HAS_DYNAMIC_TYPE(VertexBuffer11*, vetexBuffer)); + return static_cast(vetexBuffer); +} + +gl::Error VertexBuffer11::mapResource() +{ + if (mMappedResourceData == NULL) + { + ID3D11DeviceContext *dxContext = mRenderer->getDeviceContext(); + + D3D11_MAPPED_SUBRESOURCE mappedResource; + + HRESULT result = dxContext->Map(mBuffer, 0, D3D11_MAP_WRITE_NO_OVERWRITE, 0, &mappedResource); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to map internal vertex buffer, HRESULT: 0x%08x.", result); + } + + mMappedResourceData = reinterpret_cast(mappedResource.pData); + } + + return gl::Error(GL_NO_ERROR); +} + +void VertexBuffer11::hintUnmapResource() +{ + if (mMappedResourceData != NULL) + { + ID3D11DeviceContext *dxContext = mRenderer->getDeviceContext(); + dxContext->Unmap(mBuffer, 0); + + mMappedResourceData = NULL; + } +} + +gl::Error VertexBuffer11::storeVertexAttributes(const gl::VertexAttribute &attrib, const gl::VertexAttribCurrentValueData ¤tValue, + GLint start, GLsizei count, GLsizei instances, unsigned int offset) +{ + if (!mBuffer) + { + return gl::Error(GL_OUT_OF_MEMORY, "Internal vertex buffer is not initialized."); + } + + gl::Buffer *buffer = attrib.buffer.get(); + int inputStride = ComputeVertexAttributeStride(attrib); + + // This will map the resource if it isn't already mapped. + gl::Error error = mapResource(); + if (error.isError()) + { + return error; + } + + uint8_t *output = mMappedResourceData + offset; + + const uint8_t *input = NULL; + if (attrib.enabled) + { + if (buffer) + { + BufferD3D *storage = GetImplAs(buffer); + error = storage->getData(&input); + if (error.isError()) + { + return error; + } + input += static_cast(attrib.offset); + } + else + { + input = static_cast(attrib.pointer); + } + } + else + { + input = reinterpret_cast(currentValue.FloatValues); + } + + if (instances == 0 || attrib.divisor == 0) + { + input += inputStride * start; + } + + gl::VertexFormat vertexFormat(attrib, currentValue.Type); + const d3d11::VertexFormat &vertexFormatInfo = d3d11::GetVertexFormatInfo(vertexFormat, mRenderer->getFeatureLevel()); + ASSERT(vertexFormatInfo.copyFunction != NULL); + vertexFormatInfo.copyFunction(input, inputStride, count, output); + + return gl::Error(GL_NO_ERROR); +} + +gl::Error VertexBuffer11::getSpaceRequired(const gl::VertexAttribute &attrib, GLsizei count, + GLsizei instances, unsigned int *outSpaceRequired) const +{ + unsigned int elementCount = 0; + if (attrib.enabled) + { + if (instances == 0 || attrib.divisor == 0) + { + elementCount = count; + } + else + { + // Round up to divisor, if possible + elementCount = UnsignedCeilDivide(static_cast(instances), attrib.divisor); + } + + gl::VertexFormat vertexFormat(attrib); + const d3d11::VertexFormat &vertexFormatInfo = d3d11::GetVertexFormatInfo(vertexFormat, mRenderer->getFeatureLevel()); + const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(vertexFormatInfo.nativeFormat); + unsigned int elementSize = dxgiFormatInfo.pixelBytes; + if (elementSize <= std::numeric_limits::max() / elementCount) + { + if (outSpaceRequired) + { + *outSpaceRequired = elementSize * elementCount; + } + return gl::Error(GL_NO_ERROR); + } + else + { + return gl::Error(GL_OUT_OF_MEMORY, "New vertex buffer size would result in an overflow."); + } + } + else + { + const unsigned int elementSize = 4; + if (outSpaceRequired) + { + *outSpaceRequired = elementSize * 4; + } + return gl::Error(GL_NO_ERROR); + } +} + +unsigned int VertexBuffer11::getBufferSize() const +{ + return mBufferSize; +} + +gl::Error VertexBuffer11::setBufferSize(unsigned int size) +{ + if (size > mBufferSize) + { + return initialize(size, mDynamicUsage); + } + else + { + return gl::Error(GL_NO_ERROR); + } +} + +gl::Error VertexBuffer11::discard() +{ + if (!mBuffer) + { + return gl::Error(GL_OUT_OF_MEMORY, "Internal vertex buffer is not initialized."); + } + + ID3D11DeviceContext *dxContext = mRenderer->getDeviceContext(); + + D3D11_MAPPED_SUBRESOURCE mappedResource; + HRESULT result = dxContext->Map(mBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to map internal buffer for discarding, HRESULT: 0x%08x", result); + } + + dxContext->Unmap(mBuffer, 0); + + return gl::Error(GL_NO_ERROR); +} + +ID3D11Buffer *VertexBuffer11::getBuffer() const +{ + return mBuffer; +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/VertexBuffer11.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/VertexBuffer11.h new file mode 100644 index 0000000000..2450e8955c --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/VertexBuffer11.h @@ -0,0 +1,58 @@ +// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// VertexBuffer11.h: Defines the D3D11 VertexBuffer implementation. + +#ifndef LIBANGLE_RENDERER_D3D_D3D11_VERTEXBUFFER11_H_ +#define LIBANGLE_RENDERER_D3D_D3D11_VERTEXBUFFER11_H_ + +#include + +#include "libANGLE/renderer/d3d/VertexBuffer.h" + +namespace rx +{ +class Renderer11; + +class VertexBuffer11 : public VertexBuffer +{ + public: + explicit VertexBuffer11(Renderer11 *const renderer); + virtual ~VertexBuffer11(); + + virtual gl::Error initialize(unsigned int size, bool dynamicUsage); + + static VertexBuffer11 *makeVertexBuffer11(VertexBuffer *vetexBuffer); + + virtual gl::Error storeVertexAttributes(const gl::VertexAttribute &attrib, const gl::VertexAttribCurrentValueData ¤tValue, + GLint start, GLsizei count, GLsizei instances, unsigned int offset); + + virtual gl::Error getSpaceRequired(const gl::VertexAttribute &attrib, GLsizei count, GLsizei instances, + unsigned int *outSpaceRequired) const; + + virtual unsigned int getBufferSize() const; + virtual gl::Error setBufferSize(unsigned int size); + virtual gl::Error discard(); + + virtual void hintUnmapResource(); + + ID3D11Buffer *getBuffer() const; + + private: + gl::Error mapResource(); + + Renderer11 *const mRenderer; + + ID3D11Buffer *mBuffer; + unsigned int mBufferSize; + bool mDynamicUsage; + + uint8_t *mMappedResourceData; +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_D3D11_VERTEXBUFFER11_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/copyvertex.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/copyvertex.h new file mode 100644 index 0000000000..5501e361f1 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/copyvertex.h @@ -0,0 +1,40 @@ +// +// Copyright (c) 2013-2015 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// copyvertex.h: Defines D3D11 vertex buffer copying and conversion functions + +#ifndef LIBANGLE_RENDERER_D3D_D3D11_COPYVERTEX_H_ +#define LIBANGLE_RENDERER_D3D_D3D11_COPYVERTEX_H_ + +#include "common/mathutil.h" + +namespace rx +{ + +// 'alphaDefaultValueBits' gives the default value for the alpha channel (4th component) +template +inline void CopyNativeVertexData(const uint8_t *input, size_t stride, size_t count, uint8_t *output); + +template +inline void Copy8SintTo16SintVertexData(const uint8_t *input, size_t stride, size_t count, uint8_t *output); + +template +inline void Copy8SnormTo16SnormVertexData(const uint8_t *input, size_t stride, size_t count, uint8_t *output); + +template +inline void Copy32FixedTo32FVertexData(const uint8_t *input, size_t stride, size_t count, uint8_t *output); + +template +inline void CopyTo32FVertexData(const uint8_t *input, size_t stride, size_t count, uint8_t *output); + +template +inline void CopyXYZ10W2ToXYZW32FVertexData(const uint8_t *input, size_t stride, size_t count, uint8_t *output); + +} + +#include "copyvertex.inl" + +#endif // LIBANGLE_RENDERER_D3D_D3D11_COPYVERTEX_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/copyvertex.inl b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/copyvertex.inl new file mode 100644 index 0000000000..60678d7b9f --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/copyvertex.inl @@ -0,0 +1,377 @@ +// +// Copyright (c) 2014-2015 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +namespace rx +{ + +template +inline void CopyNativeVertexData(const uint8_t *input, size_t stride, size_t count, uint8_t *output) +{ + const size_t attribSize = sizeof(T)* inputComponentCount; + + if (attribSize == stride && inputComponentCount == outputComponentCount) + { + memcpy(output, input, count * attribSize); + } + else + { + const T defaultAlphaValue = gl::bitCast(alphaDefaultValueBits); + const size_t lastNonAlphaOutputComponent = std::min(outputComponentCount, 3); + + for (size_t i = 0; i < count; i++) + { + const T *offsetInput = reinterpret_cast(input + (i * stride)); + T *offsetOutput = reinterpret_cast(output) + i * outputComponentCount; + + for (size_t j = 0; j < inputComponentCount; j++) + { + offsetOutput[j] = offsetInput[j]; + } + + for (size_t j = inputComponentCount; j < lastNonAlphaOutputComponent; j++) + { + // Set the remaining G/B channels to 0. + offsetOutput[j] = 0; + } + + if (inputComponentCount < outputComponentCount && outputComponentCount == 4) + { + // Set the remaining alpha channel to the defaultAlphaValue. + offsetOutput[3] = defaultAlphaValue; + } + } + } +} + +template +inline void Copy8SintTo16SintVertexData(const uint8_t *input, size_t stride, size_t count, uint8_t *output) +{ + const size_t lastNonAlphaOutputComponent = std::min(outputComponentCount, 3); + + for (size_t i = 0; i < count; i++) + { + const GLbyte *offsetInput = reinterpret_cast(input + i * stride); + GLshort *offsetOutput = reinterpret_cast(output)+i * outputComponentCount; + + for (size_t j = 0; j < inputComponentCount; j++) + { + offsetOutput[j] = static_cast(offsetInput[j]); + } + + for (size_t j = inputComponentCount; j < lastNonAlphaOutputComponent; j++) + { + // Set remaining G/B channels to 0. + offsetOutput[j] = 0; + } + + if (inputComponentCount < outputComponentCount && outputComponentCount == 4) + { + // On integer formats, we must set the Alpha channel to 1 if it's unused. + offsetOutput[3] = 1; + } + } +} + +template +inline void Copy8SnormTo16SnormVertexData(const uint8_t *input, size_t stride, size_t count, uint8_t *output) +{ + for (size_t i = 0; i < count; i++) + { + const GLbyte *offsetInput = reinterpret_cast(input + i * stride); + GLshort *offsetOutput = reinterpret_cast(output) + i * outputComponentCount; + + for (size_t j = 0; j < inputComponentCount; j++) + { + // The original GLbyte value ranges from -128 to +127 (INT8_MAX). + // When converted to GLshort, the value must be scaled to between -32768 and +32767 (INT16_MAX). + if (offsetInput[j] > 0) + { + offsetOutput[j] = offsetInput[j] << 8 | offsetInput[j] << 1 | ((offsetInput[j] & 0x40) >> 6); + } + else + { + offsetOutput[j] = offsetInput[j] << 8; + } + } + + for (size_t j = inputComponentCount; j < std::min(outputComponentCount, 3); j++) + { + // Set remaining G/B channels to 0. + offsetOutput[j] = 0; + } + + if (inputComponentCount < outputComponentCount && outputComponentCount == 4) + { + // On normalized formats, we must set the Alpha channel to the max value if it's unused. + offsetOutput[3] = INT16_MAX; + } + } +} + +template +inline void Copy32FixedTo32FVertexData(const uint8_t *input, size_t stride, size_t count, uint8_t *output) +{ + static const float divisor = 1.0f / (1 << 16); + + for (size_t i = 0; i < count; i++) + { + const GLfixed* offsetInput = reinterpret_cast(input + (stride * i)); + float* offsetOutput = reinterpret_cast(output) + i * outputComponentCount; + + for (size_t j = 0; j < inputComponentCount; j++) + { + offsetOutput[j] = static_cast(offsetInput[j]) * divisor; + } + + // 4-component output formats would need special padding in the alpha channel. + static_assert(!(inputComponentCount < 4 && outputComponentCount == 4), + "An inputComponentCount less than 4 and an outputComponentCount equal to 4 is not supported."); + + for (size_t j = inputComponentCount; j < outputComponentCount; j++) + { + offsetOutput[j] = 0.0f; + } + } +} + +template +inline void CopyTo32FVertexData(const uint8_t *input, size_t stride, size_t count, uint8_t *output) +{ + typedef std::numeric_limits NL; + + for (size_t i = 0; i < count; i++) + { + const T *offsetInput = reinterpret_cast(input + (stride * i)); + float *offsetOutput = reinterpret_cast(output) + i * outputComponentCount; + + for (size_t j = 0; j < inputComponentCount; j++) + { + if (normalized) + { + if (NL::is_signed) + { + const float divisor = 1.0f / (2 * static_cast(NL::max()) + 1); + offsetOutput[j] = (2 * static_cast(offsetInput[j]) + 1) * divisor; + } + else + { + offsetOutput[j] = static_cast(offsetInput[j]) / NL::max(); + } + } + else + { + offsetOutput[j] = static_cast(offsetInput[j]); + } + } + + // This would require special padding. + static_assert(!(inputComponentCount < 4 && outputComponentCount == 4), + "An inputComponentCount less than 4 and an outputComponentCount equal to 4 is not supported."); + + for (size_t j = inputComponentCount; j < outputComponentCount; j++) + { + offsetOutput[j] = 0.0f; + } + } +} + +namespace priv +{ + +template +static inline void CopyPackedRGB(uint32_t data, uint8_t *output) +{ + const uint32_t rgbSignMask = 0x200; // 1 set at the 9 bit + const uint32_t negativeMask = 0xFFFFFC00; // All bits from 10 to 31 set to 1 + + if (toFloat) + { + GLfloat *floatOutput = reinterpret_cast(output); + if (isSigned) + { + GLfloat finalValue = 0; + if (data & rgbSignMask) + { + int negativeNumber = data | negativeMask; + finalValue = static_cast(negativeNumber); + } + else + { + finalValue = static_cast(data); + } + + if (normalized) + { + const int32_t maxValue = 0x1FF; // 1 set in bits 0 through 8 + const int32_t minValue = 0xFFFFFE01; // Inverse of maxValue + + // A 10-bit two's complement number has the possibility of being minValue - 1 but + // OpenGL's normalization rules dictate that it should be clamped to minValue in this + // case. + if (finalValue < minValue) + { + finalValue = minValue; + } + + const int32_t halfRange = (maxValue - minValue) >> 1; + *floatOutput = ((finalValue - minValue) / halfRange) - 1.0f; + } + else + { + *floatOutput = finalValue; + } + } + else + { + if (normalized) + { + const uint32_t maxValue = 0x3FF; // 1 set in bits 0 through 9 + *floatOutput = static_cast(data) / static_cast(maxValue); + } + else + { + *floatOutput = static_cast(data); + } + } + } + else + { + if (isSigned) + { + GLshort *intOutput = reinterpret_cast(output); + + if (data & rgbSignMask) + { + *intOutput = data | negativeMask; + } + else + { + *intOutput = data; + } + } + else + { + GLushort *uintOutput = reinterpret_cast(output); + *uintOutput = data; + } + } +} + +template +inline void CopyPackedAlpha(uint32_t data, uint8_t *output) +{ + if (toFloat) + { + GLfloat *floatOutput = reinterpret_cast(output); + if (isSigned) + { + if (normalized) + { + switch (data) + { + case 0x0: *floatOutput = 0.0f; break; + case 0x1: *floatOutput = 1.0f; break; + case 0x2: *floatOutput = -1.0f; break; + case 0x3: *floatOutput = -1.0f; break; + default: UNREACHABLE(); + } + } + else + { + switch (data) + { + case 0x0: *floatOutput = 0.0f; break; + case 0x1: *floatOutput = 1.0f; break; + case 0x2: *floatOutput = -2.0f; break; + case 0x3: *floatOutput = -1.0f; break; + default: UNREACHABLE(); + } + } + } + else + { + if (normalized) + { + switch (data) + { + case 0x0: *floatOutput = 0.0f / 3.0f; break; + case 0x1: *floatOutput = 1.0f / 3.0f; break; + case 0x2: *floatOutput = 2.0f / 3.0f; break; + case 0x3: *floatOutput = 3.0f / 3.0f; break; + default: UNREACHABLE(); + } + } + else + { + switch (data) + { + case 0x0: *floatOutput = 0.0f; break; + case 0x1: *floatOutput = 1.0f; break; + case 0x2: *floatOutput = 2.0f; break; + case 0x3: *floatOutput = 3.0f; break; + default: UNREACHABLE(); + } + } + } + } + else + { + if (isSigned) + { + GLshort *intOutput = reinterpret_cast(output); + switch (data) + { + case 0x0: *intOutput = 0; break; + case 0x1: *intOutput = 1; break; + case 0x2: *intOutput = -2; break; + case 0x3: *intOutput = -1; break; + default: UNREACHABLE(); + } + } + else + { + GLushort *uintOutput = reinterpret_cast(output); + switch (data) + { + case 0x0: *uintOutput = 0; break; + case 0x1: *uintOutput = 1; break; + case 0x2: *uintOutput = 2; break; + case 0x3: *uintOutput = 3; break; + default: UNREACHABLE(); + } + } + } +} + +} + +template +inline void CopyXYZ10W2ToXYZW32FVertexData(const uint8_t *input, size_t stride, size_t count, uint8_t *output) +{ + const size_t outputComponentSize = toFloat ? 4 : 2; + const size_t componentCount = 4; + + const uint32_t rgbMask = 0x3FF; // 1 set in bits 0 through 9 + const size_t redShift = 0; // red is bits 0 through 9 + const size_t greenShift = 10; // green is bits 10 through 19 + const size_t blueShift = 20; // blue is bits 20 through 29 + + const uint32_t alphaMask = 0x3; // 1 set in bits 0 and 1 + const size_t alphaShift = 30; // Alpha is the 30 and 31 bits + + for (size_t i = 0; i < count; i++) + { + GLuint packedValue = *reinterpret_cast(input + (i * stride)); + uint8_t *offsetOutput = output + (i * outputComponentSize * componentCount); + + priv::CopyPackedRGB( (packedValue >> redShift) & rgbMask, offsetOutput + (0 * outputComponentSize)); + priv::CopyPackedRGB( (packedValue >> greenShift) & rgbMask, offsetOutput + (1 * outputComponentSize)); + priv::CopyPackedRGB( (packedValue >> blueShift) & rgbMask, offsetOutput + (2 * outputComponentSize)); + priv::CopyPackedAlpha((packedValue >> alphaShift) & alphaMask, offsetOutput + (3 * outputComponentSize)); + } +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/formatutils11.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/formatutils11.cpp new file mode 100644 index 0000000000..2f81d6d608 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/formatutils11.cpp @@ -0,0 +1,1328 @@ +// +// Copyright (c) 2013-2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// formatutils11.cpp: Queries for GL image formats and their translations to D3D11 +// formats. + +#include "libANGLE/renderer/d3d/d3d11/formatutils11.h" + +#include "libANGLE/formatutils.h" +#include "libANGLE/renderer/Renderer.h" +#include "libANGLE/renderer/d3d/copyimage.h" +#include "libANGLE/renderer/d3d/generatemip.h" +#include "libANGLE/renderer/d3d/loadimage.h" +#include "libANGLE/renderer/d3d/d3d11/copyvertex.h" + +namespace rx +{ + +namespace d3d11 +{ + +typedef std::map DXGIToESFormatMap; + +inline void AddDXGIToESEntry(DXGIToESFormatMap *map, DXGI_FORMAT key, GLenum value) +{ + map->insert(std::make_pair(key, value)); +} + +static DXGIToESFormatMap BuildDXGIToESFormatMap() +{ + DXGIToESFormatMap map; + + AddDXGIToESEntry(&map, DXGI_FORMAT_UNKNOWN, GL_NONE); + + AddDXGIToESEntry(&map, DXGI_FORMAT_A8_UNORM, GL_ALPHA8_EXT); + AddDXGIToESEntry(&map, DXGI_FORMAT_R8_UNORM, GL_R8); + AddDXGIToESEntry(&map, DXGI_FORMAT_R8G8_UNORM, GL_RG8); + AddDXGIToESEntry(&map, DXGI_FORMAT_R8G8B8A8_UNORM, GL_RGBA8); + AddDXGIToESEntry(&map, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, GL_SRGB8_ALPHA8); + AddDXGIToESEntry(&map, DXGI_FORMAT_B8G8R8A8_UNORM, GL_BGRA8_EXT); + + AddDXGIToESEntry(&map, DXGI_FORMAT_R8_SNORM, GL_R8_SNORM); + AddDXGIToESEntry(&map, DXGI_FORMAT_R8G8_SNORM, GL_RG8_SNORM); + AddDXGIToESEntry(&map, DXGI_FORMAT_R8G8B8A8_SNORM, GL_RGBA8_SNORM); + + AddDXGIToESEntry(&map, DXGI_FORMAT_R8_UINT, GL_R8UI); + AddDXGIToESEntry(&map, DXGI_FORMAT_R16_UINT, GL_R16UI); + AddDXGIToESEntry(&map, DXGI_FORMAT_R32_UINT, GL_R32UI); + AddDXGIToESEntry(&map, DXGI_FORMAT_R8G8_UINT, GL_RG8UI); + AddDXGIToESEntry(&map, DXGI_FORMAT_R16G16_UINT, GL_RG16UI); + AddDXGIToESEntry(&map, DXGI_FORMAT_R32G32_UINT, GL_RG32UI); + AddDXGIToESEntry(&map, DXGI_FORMAT_R32G32B32_UINT, GL_RGB32UI); + AddDXGIToESEntry(&map, DXGI_FORMAT_R8G8B8A8_UINT, GL_RGBA8UI); + AddDXGIToESEntry(&map, DXGI_FORMAT_R16G16B16A16_UINT, GL_RGBA16UI); + AddDXGIToESEntry(&map, DXGI_FORMAT_R32G32B32A32_UINT, GL_RGBA32UI); + + AddDXGIToESEntry(&map, DXGI_FORMAT_R8_SINT, GL_R8I); + AddDXGIToESEntry(&map, DXGI_FORMAT_R16_SINT, GL_R16I); + AddDXGIToESEntry(&map, DXGI_FORMAT_R32_SINT, GL_R32I); + AddDXGIToESEntry(&map, DXGI_FORMAT_R8G8_SINT, GL_RG8I); + AddDXGIToESEntry(&map, DXGI_FORMAT_R16G16_SINT, GL_RG16I); + AddDXGIToESEntry(&map, DXGI_FORMAT_R32G32_SINT, GL_RG32I); + AddDXGIToESEntry(&map, DXGI_FORMAT_R32G32B32_SINT, GL_RGB32I); + AddDXGIToESEntry(&map, DXGI_FORMAT_R8G8B8A8_SINT, GL_RGBA8I); + AddDXGIToESEntry(&map, DXGI_FORMAT_R16G16B16A16_SINT, GL_RGBA16I); + AddDXGIToESEntry(&map, DXGI_FORMAT_R32G32B32A32_SINT, GL_RGBA32I); + + AddDXGIToESEntry(&map, DXGI_FORMAT_R10G10B10A2_UNORM, GL_RGB10_A2); + AddDXGIToESEntry(&map, DXGI_FORMAT_R10G10B10A2_UINT, GL_RGB10_A2UI); + + AddDXGIToESEntry(&map, DXGI_FORMAT_R16_FLOAT, GL_R16F); + AddDXGIToESEntry(&map, DXGI_FORMAT_R16G16_FLOAT, GL_RG16F); + AddDXGIToESEntry(&map, DXGI_FORMAT_R16G16B16A16_FLOAT, GL_RGBA16F); + + AddDXGIToESEntry(&map, DXGI_FORMAT_R32_FLOAT, GL_R32F); + AddDXGIToESEntry(&map, DXGI_FORMAT_R32G32_FLOAT, GL_RG32F); + AddDXGIToESEntry(&map, DXGI_FORMAT_R32G32B32_FLOAT, GL_RGB32F); + AddDXGIToESEntry(&map, DXGI_FORMAT_R32G32B32A32_FLOAT, GL_RGBA32F); + + AddDXGIToESEntry(&map, DXGI_FORMAT_R9G9B9E5_SHAREDEXP, GL_RGB9_E5); + AddDXGIToESEntry(&map, DXGI_FORMAT_R11G11B10_FLOAT, GL_R11F_G11F_B10F); + + AddDXGIToESEntry(&map, DXGI_FORMAT_R16_TYPELESS, GL_DEPTH_COMPONENT16); + AddDXGIToESEntry(&map, DXGI_FORMAT_R16_UNORM, GL_DEPTH_COMPONENT16); + AddDXGIToESEntry(&map, DXGI_FORMAT_D16_UNORM, GL_DEPTH_COMPONENT16); + AddDXGIToESEntry(&map, DXGI_FORMAT_R24G8_TYPELESS, GL_DEPTH24_STENCIL8_OES); + AddDXGIToESEntry(&map, DXGI_FORMAT_R24_UNORM_X8_TYPELESS, GL_DEPTH24_STENCIL8_OES); + AddDXGIToESEntry(&map, DXGI_FORMAT_D24_UNORM_S8_UINT, GL_DEPTH24_STENCIL8_OES); + AddDXGIToESEntry(&map, DXGI_FORMAT_R32G8X24_TYPELESS, GL_DEPTH32F_STENCIL8); + AddDXGIToESEntry(&map, DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS, GL_DEPTH32F_STENCIL8); + AddDXGIToESEntry(&map, DXGI_FORMAT_D32_FLOAT_S8X24_UINT, GL_DEPTH32F_STENCIL8); + AddDXGIToESEntry(&map, DXGI_FORMAT_R32_TYPELESS, GL_DEPTH_COMPONENT32F); + AddDXGIToESEntry(&map, DXGI_FORMAT_D32_FLOAT, GL_DEPTH_COMPONENT32F); + + AddDXGIToESEntry(&map, DXGI_FORMAT_BC1_UNORM, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT); + AddDXGIToESEntry(&map, DXGI_FORMAT_BC2_UNORM, GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE); + AddDXGIToESEntry(&map, DXGI_FORMAT_BC3_UNORM, GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE); + + return map; +} + +struct D3D11FastCopyFormat +{ + GLenum destFormat; + GLenum destType; + ColorCopyFunction copyFunction; + + D3D11FastCopyFormat(GLenum destFormat, GLenum destType, ColorCopyFunction copyFunction) + : destFormat(destFormat), destType(destType), copyFunction(copyFunction) + { } + + bool operator<(const D3D11FastCopyFormat& other) const + { + return memcmp(this, &other, sizeof(D3D11FastCopyFormat)) < 0; + } +}; + +typedef std::multimap D3D11FastCopyMap; + +static D3D11FastCopyMap BuildFastCopyMap() +{ + D3D11FastCopyMap map; + + map.insert(std::make_pair(DXGI_FORMAT_B8G8R8A8_UNORM, D3D11FastCopyFormat(GL_RGBA, GL_UNSIGNED_BYTE, CopyBGRA8ToRGBA8))); + + return map; +} + +struct DXGIColorFormatInfo +{ + size_t redBits; + size_t greenBits; + size_t blueBits; + + size_t luminanceBits; + + size_t alphaBits; + size_t sharedBits; +}; + +typedef std::map ColorFormatInfoMap; +typedef std::pair ColorFormatInfoPair; + +static inline void InsertDXGIColorFormatInfo(ColorFormatInfoMap *map, DXGI_FORMAT format, size_t redBits, size_t greenBits, + size_t blueBits, size_t alphaBits, size_t sharedBits) +{ + DXGIColorFormatInfo info; + info.redBits = redBits; + info.greenBits = greenBits; + info.blueBits = blueBits; + info.alphaBits = alphaBits; + info.sharedBits = sharedBits; + + map->insert(std::make_pair(format, info)); +} + +static ColorFormatInfoMap BuildColorFormatInfoMap() +{ + ColorFormatInfoMap map; + + // | DXGI format | R | G | B | A | S | + InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_A8_UNORM, 0, 0, 0, 8, 0); + InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R8_UNORM, 8, 0, 0, 0, 0); + InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R8G8_UNORM, 8, 8, 0, 0, 0); + InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R8G8B8A8_UNORM, 8, 8, 8, 8, 0); + InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, 8, 8, 8, 8, 0); + InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_B8G8R8A8_UNORM, 8, 8, 8, 8, 0); + + InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R8_SNORM, 8, 0, 0, 0, 0); + InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R8G8_SNORM, 8, 8, 0, 0, 0); + InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R8G8B8A8_SNORM, 8, 8, 8, 8, 0); + + InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R8_UINT, 8, 0, 0, 0, 0); + InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R16_UINT, 16, 0, 0, 0, 0); + InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R32_UINT, 32, 0, 0, 0, 0); + InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R8G8_UINT, 8, 8, 0, 0, 0); + InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R16G16_UINT, 16, 16, 0, 0, 0); + InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R32G32_UINT, 32, 32, 0, 0, 0); + InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R32G32B32_UINT, 32, 32, 32, 0, 0); + InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R8G8B8A8_UINT, 8, 8, 8, 8, 0); + InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R16G16B16A16_UINT, 16, 16, 16, 16, 0); + InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R32G32B32A32_UINT, 32, 32, 32, 32, 0); + + InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R8_SINT, 8, 0, 0, 0, 0); + InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R16_SINT, 16, 0, 0, 0, 0); + InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R32_SINT, 32, 0, 0, 0, 0); + InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R8G8_SINT, 8, 8, 0, 0, 0); + InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R16G16_SINT, 16, 16, 0, 0, 0); + InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R32G32_SINT, 32, 32, 0, 0, 0); + InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R32G32B32_SINT, 32, 32, 32, 0, 0); + InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R8G8B8A8_SINT, 8, 8, 8, 8, 0); + InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R16G16B16A16_SINT, 16, 16, 16, 16, 0); + InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R32G32B32A32_SINT, 32, 32, 32, 32, 0); + + InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R10G10B10A2_UNORM, 10, 10, 10, 2, 0); + InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R10G10B10A2_UINT, 10, 10, 10, 2, 0); + + InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R16_FLOAT, 16, 0, 0, 0, 0); + InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R16G16_FLOAT, 16, 16, 0, 0, 0); + InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R16G16B16A16_FLOAT, 16, 16, 16, 16, 0); + + InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R32_FLOAT, 32, 0, 0, 0, 0); + InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R32G32_FLOAT, 32, 32, 0, 0, 0); + InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R32G32B32_FLOAT, 32, 32, 32, 0, 0); + InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R32G32B32A32_FLOAT, 32, 32, 32, 32, 0); + + InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R9G9B9E5_SHAREDEXP, 9, 9, 9, 0, 5); + InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R11G11B10_FLOAT, 11, 11, 10, 0, 0); + + return map; +} + +struct DXGIDepthStencilInfo +{ + unsigned int depthBits; + unsigned int depthOffset; + unsigned int stencilBits; + unsigned int stencilOffset; +}; + +typedef std::map DepthStencilInfoMap; +typedef std::pair DepthStencilInfoPair; + +static inline void InsertDXGIDepthStencilInfo(DepthStencilInfoMap *map, DXGI_FORMAT format, unsigned int depthBits, + unsigned int depthOffset, unsigned int stencilBits, unsigned int stencilOffset) +{ + DXGIDepthStencilInfo info; + info.depthBits = depthBits; + info.depthOffset = depthOffset; + info.stencilBits = stencilBits; + info.stencilOffset = stencilOffset; + + map->insert(std::make_pair(format, info)); +} + +static DepthStencilInfoMap BuildDepthStencilInfoMap() +{ + DepthStencilInfoMap map; + + InsertDXGIDepthStencilInfo(&map, DXGI_FORMAT_R16_TYPELESS, 16, 0, 0, 0); + InsertDXGIDepthStencilInfo(&map, DXGI_FORMAT_R16_UNORM, 16, 0, 0, 0); + InsertDXGIDepthStencilInfo(&map, DXGI_FORMAT_D16_UNORM, 16, 0, 0, 0); + + InsertDXGIDepthStencilInfo(&map, DXGI_FORMAT_R24G8_TYPELESS, 24, 0, 8, 24); + InsertDXGIDepthStencilInfo(&map, DXGI_FORMAT_R24_UNORM_X8_TYPELESS, 24, 0, 8, 24); + InsertDXGIDepthStencilInfo(&map, DXGI_FORMAT_D24_UNORM_S8_UINT, 24, 0, 8, 24); + + InsertDXGIDepthStencilInfo(&map, DXGI_FORMAT_R32_TYPELESS, 32, 0, 0, 0); + InsertDXGIDepthStencilInfo(&map, DXGI_FORMAT_R32_FLOAT, 32, 0, 0, 0); + InsertDXGIDepthStencilInfo(&map, DXGI_FORMAT_D32_FLOAT, 32, 0, 0, 0); + + InsertDXGIDepthStencilInfo(&map, DXGI_FORMAT_R32G8X24_TYPELESS, 32, 0, 8, 32); + InsertDXGIDepthStencilInfo(&map, DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS, 32, 0, 8, 32); + InsertDXGIDepthStencilInfo(&map, DXGI_FORMAT_D32_FLOAT_S8X24_UINT, 32, 0, 8, 32); + + return map; +} + +typedef std::map DXGIFormatInfoMap; + +DXGIFormat::DXGIFormat() + : pixelBytes(0), + blockWidth(0), + blockHeight(0), + redBits(0), + greenBits(0), + blueBits(0), + alphaBits(0), + sharedBits(0), + depthBits(0), + depthOffset(0), + stencilBits(0), + stencilOffset(0), + internalFormat(GL_NONE), + componentType(GL_NONE), + mipGenerationFunction(NULL), + colorReadFunction(NULL), + fastCopyFunctions() +{ +} + +ColorCopyFunction DXGIFormat::getFastCopyFunction(GLenum format, GLenum type) const +{ + FastCopyFunctionMap::const_iterator iter = fastCopyFunctions.find(std::make_pair(format, type)); + return (iter != fastCopyFunctions.end()) ? iter->second : NULL; +} + +void AddDXGIFormat(DXGIFormatInfoMap *map, DXGI_FORMAT dxgiFormat, GLuint pixelBits, GLuint blockWidth, GLuint blockHeight, + GLenum componentType, MipGenerationFunction mipFunc, ColorReadFunction readFunc) +{ + DXGIFormat info; + info.pixelBytes = pixelBits / 8; + info.blockWidth = blockWidth; + info.blockHeight = blockHeight; + + static const ColorFormatInfoMap colorInfoMap = BuildColorFormatInfoMap(); + ColorFormatInfoMap::const_iterator colorInfoIter = colorInfoMap.find(dxgiFormat); + if (colorInfoIter != colorInfoMap.end()) + { + const DXGIColorFormatInfo &colorInfo = colorInfoIter->second; + info.redBits = colorInfo.redBits; + info.greenBits = colorInfo.greenBits; + info.blueBits = colorInfo.blueBits; + info.alphaBits = colorInfo.alphaBits; + info.sharedBits = colorInfo.sharedBits; + } + + static const DepthStencilInfoMap dsInfoMap = BuildDepthStencilInfoMap(); + DepthStencilInfoMap::const_iterator dsInfoIter = dsInfoMap.find(dxgiFormat); + if (dsInfoIter != dsInfoMap.end()) + { + const DXGIDepthStencilInfo &dsInfo = dsInfoIter->second; + info.depthBits = dsInfo.depthBits; + info.depthOffset = dsInfo.depthOffset; + info.stencilBits = dsInfo.stencilBits; + info.stencilOffset = dsInfo.stencilOffset; + } + + static const DXGIToESFormatMap dxgiToESMap = BuildDXGIToESFormatMap(); + DXGIToESFormatMap::const_iterator dxgiToESIter = dxgiToESMap.find(dxgiFormat); + info.internalFormat = (dxgiToESIter != dxgiToESMap.end()) ? dxgiToESIter->second : GL_NONE; + + info.componentType = componentType; + + info.mipGenerationFunction = mipFunc; + info.colorReadFunction = readFunc; + + static const D3D11FastCopyMap fastCopyMap = BuildFastCopyMap(); + std::pair fastCopyIter = fastCopyMap.equal_range(dxgiFormat); + for (D3D11FastCopyMap::const_iterator i = fastCopyIter.first; i != fastCopyIter.second; i++) + { + info.fastCopyFunctions.insert(std::make_pair(std::make_pair(i->second.destFormat, i->second.destType), i->second.copyFunction)); + } + + map->insert(std::make_pair(dxgiFormat, info)); +} + +// A map to determine the pixel size and mipmap generation function of a given DXGI format +static DXGIFormatInfoMap BuildDXGIFormatInfoMap() +{ + DXGIFormatInfoMap map; + + // | DXGI format |S |W |H |Component Type | Mip generation function | Color read function + AddDXGIFormat(&map, DXGI_FORMAT_UNKNOWN, 0, 0, 0, GL_NONE, NULL, NULL); + + AddDXGIFormat(&map, DXGI_FORMAT_A8_UNORM, 8, 1, 1, GL_UNSIGNED_NORMALIZED, GenerateMip, ReadColor); + AddDXGIFormat(&map, DXGI_FORMAT_R8_UNORM, 8, 1, 1, GL_UNSIGNED_NORMALIZED, GenerateMip, ReadColor); + AddDXGIFormat(&map, DXGI_FORMAT_R8G8_UNORM, 16, 1, 1, GL_UNSIGNED_NORMALIZED, GenerateMip, ReadColor); + AddDXGIFormat(&map, DXGI_FORMAT_R8G8B8A8_UNORM, 32, 1, 1, GL_UNSIGNED_NORMALIZED, GenerateMip, ReadColor); + AddDXGIFormat(&map, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, 32, 1, 1, GL_UNSIGNED_NORMALIZED, GenerateMip, ReadColor); + AddDXGIFormat(&map, DXGI_FORMAT_B8G8R8A8_UNORM, 32, 1, 1, GL_UNSIGNED_NORMALIZED, GenerateMip, ReadColor); + + AddDXGIFormat(&map, DXGI_FORMAT_R8_SNORM, 8, 1, 1, GL_SIGNED_NORMALIZED, GenerateMip, ReadColor); + AddDXGIFormat(&map, DXGI_FORMAT_R8G8_SNORM, 16, 1, 1, GL_SIGNED_NORMALIZED, GenerateMip, ReadColor); + AddDXGIFormat(&map, DXGI_FORMAT_R8G8B8A8_SNORM, 32, 1, 1, GL_SIGNED_NORMALIZED, GenerateMip, ReadColor); + + AddDXGIFormat(&map, DXGI_FORMAT_R8_UINT, 8, 1, 1, GL_UNSIGNED_INT, GenerateMip, ReadColor); + AddDXGIFormat(&map, DXGI_FORMAT_R16_UINT, 16, 1, 1, GL_UNSIGNED_INT, GenerateMip, ReadColor); + AddDXGIFormat(&map, DXGI_FORMAT_R32_UINT, 32, 1, 1, GL_UNSIGNED_INT, GenerateMip, ReadColor); + AddDXGIFormat(&map, DXGI_FORMAT_R8G8_UINT, 16, 1, 1, GL_UNSIGNED_INT, GenerateMip, ReadColor); + AddDXGIFormat(&map, DXGI_FORMAT_R16G16_UINT, 32, 1, 1, GL_UNSIGNED_INT, GenerateMip, ReadColor); + AddDXGIFormat(&map, DXGI_FORMAT_R32G32_UINT, 64, 1, 1, GL_UNSIGNED_INT, GenerateMip, ReadColor); + AddDXGIFormat(&map, DXGI_FORMAT_R32G32B32_UINT, 96, 1, 1, GL_UNSIGNED_INT, GenerateMip, ReadColor); + AddDXGIFormat(&map, DXGI_FORMAT_R8G8B8A8_UINT, 32, 1, 1, GL_UNSIGNED_INT, GenerateMip, ReadColor); + AddDXGIFormat(&map, DXGI_FORMAT_R16G16B16A16_UINT, 64, 1, 1, GL_UNSIGNED_INT, GenerateMip, ReadColor); + AddDXGIFormat(&map, DXGI_FORMAT_R32G32B32A32_UINT, 128, 1, 1, GL_UNSIGNED_INT, GenerateMip, ReadColor); + + AddDXGIFormat(&map, DXGI_FORMAT_R8_SINT, 8, 1, 1, GL_INT, GenerateMip, ReadColor); + AddDXGIFormat(&map, DXGI_FORMAT_R16_SINT, 16, 1, 1, GL_INT, GenerateMip, ReadColor); + AddDXGIFormat(&map, DXGI_FORMAT_R32_SINT, 32, 1, 1, GL_INT, GenerateMip, ReadColor); + AddDXGIFormat(&map, DXGI_FORMAT_R8G8_SINT, 16, 1, 1, GL_INT, GenerateMip, ReadColor); + AddDXGIFormat(&map, DXGI_FORMAT_R16G16_SINT, 32, 1, 1, GL_INT, GenerateMip, ReadColor); + AddDXGIFormat(&map, DXGI_FORMAT_R32G32_SINT, 64, 1, 1, GL_INT, GenerateMip, ReadColor); + AddDXGIFormat(&map, DXGI_FORMAT_R32G32B32_SINT, 96, 1, 1, GL_INT, GenerateMip, ReadColor); + AddDXGIFormat(&map, DXGI_FORMAT_R8G8B8A8_SINT, 32, 1, 1, GL_INT, GenerateMip, ReadColor); + AddDXGIFormat(&map, DXGI_FORMAT_R16G16B16A16_SINT, 64, 1, 1, GL_INT, GenerateMip, ReadColor); + AddDXGIFormat(&map, DXGI_FORMAT_R32G32B32A32_SINT, 128, 1, 1, GL_INT, GenerateMip, ReadColor); + + AddDXGIFormat(&map, DXGI_FORMAT_R10G10B10A2_UNORM, 32, 1, 1, GL_UNSIGNED_NORMALIZED, GenerateMip, ReadColor); + AddDXGIFormat(&map, DXGI_FORMAT_R10G10B10A2_UINT, 32, 1, 1, GL_UNSIGNED_INT, GenerateMip, ReadColor); + + AddDXGIFormat(&map, DXGI_FORMAT_R16_FLOAT, 16, 1, 1, GL_FLOAT, GenerateMip, ReadColor); + AddDXGIFormat(&map, DXGI_FORMAT_R16G16_FLOAT, 32, 1, 1, GL_FLOAT, GenerateMip, ReadColor); + AddDXGIFormat(&map, DXGI_FORMAT_R16G16B16A16_FLOAT, 64, 1, 1, GL_FLOAT, GenerateMip, ReadColor); + + AddDXGIFormat(&map, DXGI_FORMAT_R32_FLOAT, 32, 1, 1, GL_FLOAT, GenerateMip, ReadColor); + AddDXGIFormat(&map, DXGI_FORMAT_R32G32_FLOAT, 64, 1, 1, GL_FLOAT, GenerateMip, ReadColor); + AddDXGIFormat(&map, DXGI_FORMAT_R32G32B32_FLOAT, 96, 1, 1, GL_FLOAT, NULL, NULL); + AddDXGIFormat(&map, DXGI_FORMAT_R32G32B32A32_FLOAT, 128, 1, 1, GL_FLOAT, GenerateMip, ReadColor); + + AddDXGIFormat(&map, DXGI_FORMAT_R9G9B9E5_SHAREDEXP, 32, 1, 1, GL_FLOAT, GenerateMip, ReadColor); + AddDXGIFormat(&map, DXGI_FORMAT_R11G11B10_FLOAT, 32, 1, 1, GL_FLOAT, GenerateMip, ReadColor); + + AddDXGIFormat(&map, DXGI_FORMAT_R16_TYPELESS, 16, 1, 1, GL_NONE, NULL, NULL); + AddDXGIFormat(&map, DXGI_FORMAT_R16_UNORM, 16, 1, 1, GL_UNSIGNED_NORMALIZED, NULL, NULL); + AddDXGIFormat(&map, DXGI_FORMAT_D16_UNORM, 16, 1, 1, GL_UNSIGNED_NORMALIZED, NULL, NULL); + AddDXGIFormat(&map, DXGI_FORMAT_R24G8_TYPELESS, 32, 1, 1, GL_NONE, NULL, NULL); + AddDXGIFormat(&map, DXGI_FORMAT_R24_UNORM_X8_TYPELESS, 32, 1, 1, GL_NONE, NULL, NULL); + AddDXGIFormat(&map, DXGI_FORMAT_D24_UNORM_S8_UINT, 32, 1, 1, GL_UNSIGNED_INT, NULL, NULL); + AddDXGIFormat(&map, DXGI_FORMAT_R32G8X24_TYPELESS, 64, 1, 1, GL_NONE, NULL, NULL); + AddDXGIFormat(&map, DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS, 64, 1, 1, GL_NONE, NULL, NULL); + AddDXGIFormat(&map, DXGI_FORMAT_D32_FLOAT_S8X24_UINT, 64, 1, 1, GL_UNSIGNED_INT, NULL, NULL); + AddDXGIFormat(&map, DXGI_FORMAT_R32_TYPELESS, 32, 1, 1, GL_NONE, NULL, NULL); + AddDXGIFormat(&map, DXGI_FORMAT_D32_FLOAT, 32, 1, 1, GL_FLOAT, NULL, NULL); + + AddDXGIFormat(&map, DXGI_FORMAT_BC1_UNORM, 64, 4, 4, GL_UNSIGNED_NORMALIZED, NULL, NULL); + AddDXGIFormat(&map, DXGI_FORMAT_BC2_UNORM, 128, 4, 4, GL_UNSIGNED_NORMALIZED, NULL, NULL); + AddDXGIFormat(&map, DXGI_FORMAT_BC3_UNORM, 128, 4, 4, GL_UNSIGNED_NORMALIZED, NULL, NULL); + + // Useful formats for vertex buffers + AddDXGIFormat(&map, DXGI_FORMAT_R16_UNORM, 16, 1, 1, GL_UNSIGNED_NORMALIZED, NULL, NULL); + AddDXGIFormat(&map, DXGI_FORMAT_R16_SNORM, 16, 1, 1, GL_SIGNED_NORMALIZED, NULL, NULL); + AddDXGIFormat(&map, DXGI_FORMAT_R16G16_UNORM, 32, 1, 1, GL_UNSIGNED_NORMALIZED, NULL, NULL); + AddDXGIFormat(&map, DXGI_FORMAT_R16G16_SNORM, 32, 1, 1, GL_SIGNED_NORMALIZED, NULL, NULL); + AddDXGIFormat(&map, DXGI_FORMAT_R16G16B16A16_UNORM, 64, 1, 1, GL_UNSIGNED_NORMALIZED, NULL, NULL); + AddDXGIFormat(&map, DXGI_FORMAT_R16G16B16A16_SNORM, 64, 1, 1, GL_SIGNED_NORMALIZED, NULL, NULL); + + return map; +} + +const DXGIFormat &GetDXGIFormatInfo(DXGI_FORMAT format) +{ + static const DXGIFormatInfoMap infoMap = BuildDXGIFormatInfoMap(); + DXGIFormatInfoMap::const_iterator iter = infoMap.find(format); + if (iter != infoMap.end()) + { + return iter->second; + } + else + { + static DXGIFormat defaultInfo; + return defaultInfo; + } +} + +struct SwizzleSizeType +{ + size_t maxComponentSize; + GLenum componentType; + + SwizzleSizeType() + : maxComponentSize(0), componentType(GL_NONE) + { } + + SwizzleSizeType(size_t maxComponentSize, GLenum componentType) + : maxComponentSize(maxComponentSize), componentType(componentType) + { } + + bool operator<(const SwizzleSizeType& other) const + { + return (maxComponentSize != other.maxComponentSize) ? (maxComponentSize < other.maxComponentSize) + : (componentType < other.componentType); + } +}; + +struct SwizzleFormatInfo +{ + DXGI_FORMAT mTexFormat; + DXGI_FORMAT mSRVFormat; + DXGI_FORMAT mRTVFormat; + + SwizzleFormatInfo() + : mTexFormat(DXGI_FORMAT_UNKNOWN), mSRVFormat(DXGI_FORMAT_UNKNOWN), mRTVFormat(DXGI_FORMAT_UNKNOWN) + { } + + SwizzleFormatInfo(DXGI_FORMAT texFormat, DXGI_FORMAT srvFormat, DXGI_FORMAT rtvFormat) + : mTexFormat(texFormat), mSRVFormat(srvFormat), mRTVFormat(rtvFormat) + { } +}; + +typedef std::map SwizzleInfoMap; +typedef std::pair SwizzleInfoPair; + +static SwizzleInfoMap BuildSwizzleInfoMap() +{ + SwizzleInfoMap map; + + map.insert(SwizzleInfoPair(SwizzleSizeType( 8, GL_UNSIGNED_NORMALIZED), SwizzleFormatInfo(DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM ))); + map.insert(SwizzleInfoPair(SwizzleSizeType(16, GL_UNSIGNED_NORMALIZED), SwizzleFormatInfo(DXGI_FORMAT_R16G16B16A16_UNORM, DXGI_FORMAT_R16G16B16A16_UNORM, DXGI_FORMAT_R16G16B16A16_UNORM))); + map.insert(SwizzleInfoPair(SwizzleSizeType(24, GL_UNSIGNED_NORMALIZED), SwizzleFormatInfo(DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT))); + map.insert(SwizzleInfoPair(SwizzleSizeType(32, GL_UNSIGNED_NORMALIZED), SwizzleFormatInfo(DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT))); + + map.insert(SwizzleInfoPair(SwizzleSizeType( 8, GL_SIGNED_NORMALIZED ), SwizzleFormatInfo(DXGI_FORMAT_R8G8B8A8_SNORM, DXGI_FORMAT_R8G8B8A8_SNORM, DXGI_FORMAT_R8G8B8A8_SNORM ))); + + map.insert(SwizzleInfoPair(SwizzleSizeType(16, GL_FLOAT ), SwizzleFormatInfo(DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_R16G16B16A16_FLOAT))); + map.insert(SwizzleInfoPair(SwizzleSizeType(32, GL_FLOAT ), SwizzleFormatInfo(DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT))); + + map.insert(SwizzleInfoPair(SwizzleSizeType( 8, GL_UNSIGNED_INT ), SwizzleFormatInfo(DXGI_FORMAT_R8G8B8A8_UINT, DXGI_FORMAT_R8G8B8A8_UINT, DXGI_FORMAT_R8G8B8A8_UINT ))); + map.insert(SwizzleInfoPair(SwizzleSizeType(16, GL_UNSIGNED_INT ), SwizzleFormatInfo(DXGI_FORMAT_R16G16B16A16_UINT, DXGI_FORMAT_R16G16B16A16_UINT, DXGI_FORMAT_R16G16B16A16_UINT ))); + map.insert(SwizzleInfoPair(SwizzleSizeType(32, GL_UNSIGNED_INT ), SwizzleFormatInfo(DXGI_FORMAT_R32G32B32A32_UINT, DXGI_FORMAT_R32G32B32A32_UINT, DXGI_FORMAT_R32G32B32A32_UINT ))); + + map.insert(SwizzleInfoPair(SwizzleSizeType( 8, GL_INT ), SwizzleFormatInfo(DXGI_FORMAT_R8G8B8A8_SINT, DXGI_FORMAT_R8G8B8A8_SINT, DXGI_FORMAT_R8G8B8A8_SINT ))); + map.insert(SwizzleInfoPair(SwizzleSizeType(16, GL_INT ), SwizzleFormatInfo(DXGI_FORMAT_R16G16B16A16_SINT, DXGI_FORMAT_R16G16B16A16_SINT, DXGI_FORMAT_R16G16B16A16_SINT ))); + map.insert(SwizzleInfoPair(SwizzleSizeType(32, GL_INT ), SwizzleFormatInfo(DXGI_FORMAT_R32G32B32A32_SINT, DXGI_FORMAT_R32G32B32A32_SINT, DXGI_FORMAT_R32G32B32A32_SINT ))); + + return map; +} + +typedef std::pair InternalFormatInitializerPair; +typedef std::map InternalFormatInitializerMap; + +static InternalFormatInitializerMap BuildInternalFormatInitializerMap() +{ + InternalFormatInitializerMap map; + + map.insert(InternalFormatInitializerPair(GL_RGB8, Initialize4ComponentData )); + map.insert(InternalFormatInitializerPair(GL_RGB565, Initialize4ComponentData )); + map.insert(InternalFormatInitializerPair(GL_SRGB8, Initialize4ComponentData )); + map.insert(InternalFormatInitializerPair(GL_RGB16F, Initialize4ComponentData)); + map.insert(InternalFormatInitializerPair(GL_RGB32F, Initialize4ComponentData)); + map.insert(InternalFormatInitializerPair(GL_RGB8UI, Initialize4ComponentData )); + map.insert(InternalFormatInitializerPair(GL_RGB8I, Initialize4ComponentData )); + map.insert(InternalFormatInitializerPair(GL_RGB16UI, Initialize4ComponentData )); + map.insert(InternalFormatInitializerPair(GL_RGB16I, Initialize4ComponentData )); + map.insert(InternalFormatInitializerPair(GL_RGB32UI, Initialize4ComponentData )); + map.insert(InternalFormatInitializerPair(GL_RGB32I, Initialize4ComponentData )); + + return map; +} + +// ES3 image loading functions vary based on the internal format and data type given, +// this map type determines the loading function from the internal format and type supplied +// to glTex*Image*D and the destination DXGI_FORMAT. Source formats and types are taken from +// Tables 3.2 and 3.3 of the ES 3 spec. +typedef std::pair TypeLoadFunctionPair; +typedef std::map > D3D11LoadFunctionMap; + +static void UnimplementedLoadFunction(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + UNIMPLEMENTED(); +} + +static void UnreachableLoadFunction(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + UNREACHABLE(); +} + +// A helper function to insert data into the D3D11LoadFunctionMap with fewer characters. +static inline void InsertLoadFunction(D3D11LoadFunctionMap *map, GLenum internalFormat, GLenum type, + LoadImageFunction loadFunc) +{ + (*map)[internalFormat].push_back(TypeLoadFunctionPair(type, loadFunc)); +} + +D3D11LoadFunctionMap BuildD3D11_FL9_3_LoadFunctionMap() +{ + D3D11LoadFunctionMap map; + + // From GL_EXT_texture_storage. Also used by GL_ALPHA8 + // On feature level 9_3, A8_UNORM doesn't support mipmaps, so we must use RGBA8 instead + InsertLoadFunction(&map, GL_ALPHA8_EXT, GL_UNSIGNED_BYTE, LoadA8ToRGBA8); + + return map; +} + +D3D11LoadFunctionMap BuildD3D11_FL10_0Plus_LoadFunctionMap() +{ + D3D11LoadFunctionMap map; + + // From GL_EXT_texture_storage. Also used by GL_ALPHA8 + InsertLoadFunction(&map, GL_ALPHA8_EXT, GL_UNSIGNED_BYTE, LoadToNative); + + return map; +} + +D3D11LoadFunctionMap BuildBaseD3D11LoadFunctionMap() +{ + D3D11LoadFunctionMap map; + + // | Internal format | Type | Load function | + InsertLoadFunction(&map, GL_RGBA8, GL_UNSIGNED_BYTE, LoadToNative ); + InsertLoadFunction(&map, GL_RGB5_A1, GL_UNSIGNED_BYTE, LoadToNative ); + InsertLoadFunction(&map, GL_RGBA4, GL_UNSIGNED_BYTE, LoadToNative ); + InsertLoadFunction(&map, GL_SRGB8_ALPHA8, GL_UNSIGNED_BYTE, LoadToNative ); + InsertLoadFunction(&map, GL_RGBA8_SNORM, GL_BYTE, LoadToNative ); + InsertLoadFunction(&map, GL_RGBA4, GL_UNSIGNED_SHORT_4_4_4_4, LoadRGBA4ToRGBA8 ); + InsertLoadFunction(&map, GL_RGB10_A2, GL_UNSIGNED_INT_2_10_10_10_REV, LoadToNative ); + InsertLoadFunction(&map, GL_RGB5_A1, GL_UNSIGNED_SHORT_5_5_5_1, LoadRGB5A1ToRGBA8 ); + InsertLoadFunction(&map, GL_RGB5_A1, GL_UNSIGNED_INT_2_10_10_10_REV, LoadRGB10A2ToRGBA8 ); + InsertLoadFunction(&map, GL_RGBA16F, GL_HALF_FLOAT, LoadToNative ); + InsertLoadFunction(&map, GL_RGBA16F, GL_HALF_FLOAT_OES, LoadToNative ); + InsertLoadFunction(&map, GL_RGBA32F, GL_FLOAT, LoadToNative ); + InsertLoadFunction(&map, GL_RGBA16F, GL_FLOAT, Load32FTo16F<4> ); + InsertLoadFunction(&map, GL_RGBA8UI, GL_UNSIGNED_BYTE, LoadToNative ); + InsertLoadFunction(&map, GL_RGBA8I, GL_BYTE, LoadToNative ); + InsertLoadFunction(&map, GL_RGBA16UI, GL_UNSIGNED_SHORT, LoadToNative ); + InsertLoadFunction(&map, GL_RGBA16I, GL_SHORT, LoadToNative ); + InsertLoadFunction(&map, GL_RGBA32UI, GL_UNSIGNED_INT, LoadToNative ); + InsertLoadFunction(&map, GL_RGBA32I, GL_INT, LoadToNative ); + InsertLoadFunction(&map, GL_RGB10_A2UI, GL_UNSIGNED_INT_2_10_10_10_REV, LoadToNative ); + InsertLoadFunction(&map, GL_RGB8, GL_UNSIGNED_BYTE, LoadToNative3To4 ); + InsertLoadFunction(&map, GL_RGB565, GL_UNSIGNED_BYTE, LoadToNative3To4 ); + InsertLoadFunction(&map, GL_SRGB8, GL_UNSIGNED_BYTE, LoadToNative3To4 ); + InsertLoadFunction(&map, GL_RGB8_SNORM, GL_BYTE, LoadToNative3To4 ); + InsertLoadFunction(&map, GL_RGB565, GL_UNSIGNED_SHORT_5_6_5, LoadR5G6B5ToRGBA8 ); + InsertLoadFunction(&map, GL_R11F_G11F_B10F, GL_UNSIGNED_INT_10F_11F_11F_REV, LoadToNative ); + InsertLoadFunction(&map, GL_RGB9_E5, GL_UNSIGNED_INT_5_9_9_9_REV, LoadToNative ); + InsertLoadFunction(&map, GL_RGB16F, GL_HALF_FLOAT, LoadToNative3To4); + InsertLoadFunction(&map, GL_RGB16F, GL_HALF_FLOAT_OES, LoadToNative3To4); + InsertLoadFunction(&map, GL_R11F_G11F_B10F, GL_HALF_FLOAT, LoadRGB16FToRG11B10F ); + InsertLoadFunction(&map, GL_R11F_G11F_B10F, GL_HALF_FLOAT_OES, LoadRGB16FToRG11B10F ); + InsertLoadFunction(&map, GL_RGB9_E5, GL_HALF_FLOAT, LoadRGB16FToRGB9E5 ); + InsertLoadFunction(&map, GL_RGB9_E5, GL_HALF_FLOAT_OES, LoadRGB16FToRGB9E5 ); + InsertLoadFunction(&map, GL_RGB32F, GL_FLOAT, LoadToNative3To4); + InsertLoadFunction(&map, GL_RGB16F, GL_FLOAT, LoadRGB32FToRGBA16F ); + InsertLoadFunction(&map, GL_R11F_G11F_B10F, GL_FLOAT, LoadRGB32FToRG11B10F ); + InsertLoadFunction(&map, GL_RGB9_E5, GL_FLOAT, LoadRGB32FToRGB9E5 ); + InsertLoadFunction(&map, GL_RGB8UI, GL_UNSIGNED_BYTE, LoadToNative3To4 ); + InsertLoadFunction(&map, GL_RGB8I, GL_BYTE, LoadToNative3To4 ); + InsertLoadFunction(&map, GL_RGB16UI, GL_UNSIGNED_SHORT, LoadToNative3To4 ); + InsertLoadFunction(&map, GL_RGB16I, GL_SHORT, LoadToNative3To4 ); + InsertLoadFunction(&map, GL_RGB32UI, GL_UNSIGNED_INT, LoadToNative3To4 ); + InsertLoadFunction(&map, GL_RGB32I, GL_INT, LoadToNative3To4 ); + InsertLoadFunction(&map, GL_RG8, GL_UNSIGNED_BYTE, LoadToNative ); + InsertLoadFunction(&map, GL_RG8_SNORM, GL_BYTE, LoadToNative ); + InsertLoadFunction(&map, GL_RG16F, GL_HALF_FLOAT, LoadToNative ); + InsertLoadFunction(&map, GL_RG16F, GL_HALF_FLOAT_OES, LoadToNative ); + InsertLoadFunction(&map, GL_RG32F, GL_FLOAT, LoadToNative ); + InsertLoadFunction(&map, GL_RG16F, GL_FLOAT, Load32FTo16F<2> ); + InsertLoadFunction(&map, GL_RG8UI, GL_UNSIGNED_BYTE, LoadToNative ); + InsertLoadFunction(&map, GL_RG8I, GL_BYTE, LoadToNative ); + InsertLoadFunction(&map, GL_RG16UI, GL_UNSIGNED_SHORT, LoadToNative ); + InsertLoadFunction(&map, GL_RG16I, GL_SHORT, LoadToNative ); + InsertLoadFunction(&map, GL_RG32UI, GL_UNSIGNED_INT, LoadToNative ); + InsertLoadFunction(&map, GL_RG32I, GL_INT, LoadToNative ); + InsertLoadFunction(&map, GL_R8, GL_UNSIGNED_BYTE, LoadToNative ); + InsertLoadFunction(&map, GL_R8_SNORM, GL_BYTE, LoadToNative ); + InsertLoadFunction(&map, GL_R16F, GL_HALF_FLOAT, LoadToNative ); + InsertLoadFunction(&map, GL_R16F, GL_HALF_FLOAT_OES, LoadToNative ); + InsertLoadFunction(&map, GL_R32F, GL_FLOAT, LoadToNative ); + InsertLoadFunction(&map, GL_R16F, GL_FLOAT, Load32FTo16F<1> ); + InsertLoadFunction(&map, GL_R8UI, GL_UNSIGNED_BYTE, LoadToNative ); + InsertLoadFunction(&map, GL_R8I, GL_BYTE, LoadToNative ); + InsertLoadFunction(&map, GL_R16UI, GL_UNSIGNED_SHORT, LoadToNative ); + InsertLoadFunction(&map, GL_R16I, GL_SHORT, LoadToNative ); + InsertLoadFunction(&map, GL_R32UI, GL_UNSIGNED_INT, LoadToNative ); + InsertLoadFunction(&map, GL_R32I, GL_INT, LoadToNative ); + InsertLoadFunction(&map, GL_DEPTH_COMPONENT16, GL_UNSIGNED_SHORT, LoadToNative ); + InsertLoadFunction(&map, GL_DEPTH_COMPONENT24, GL_UNSIGNED_INT, LoadR32ToR24G8 ); + InsertLoadFunction(&map, GL_DEPTH_COMPONENT16, GL_UNSIGNED_INT, LoadR32ToR16 ); + InsertLoadFunction(&map, GL_DEPTH_COMPONENT32F, GL_FLOAT, LoadToNative ); + InsertLoadFunction(&map, GL_DEPTH24_STENCIL8, GL_UNSIGNED_INT_24_8, LoadR32ToR24G8 ); + InsertLoadFunction(&map, GL_DEPTH32F_STENCIL8, GL_FLOAT_32_UNSIGNED_INT_24_8_REV, LoadToNative ); + + // Unsized formats + // Load functions are unreachable because they are converted to sized internal formats based on + // the format and type before loading takes place. + InsertLoadFunction(&map, GL_RGBA, GL_UNSIGNED_BYTE, UnreachableLoadFunction ); + InsertLoadFunction(&map, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, UnreachableLoadFunction ); + InsertLoadFunction(&map, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, UnreachableLoadFunction ); + InsertLoadFunction(&map, GL_RGB, GL_UNSIGNED_BYTE, UnreachableLoadFunction ); + InsertLoadFunction(&map, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, UnreachableLoadFunction ); + InsertLoadFunction(&map, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, UnreachableLoadFunction ); + InsertLoadFunction(&map, GL_LUMINANCE, GL_UNSIGNED_BYTE, UnreachableLoadFunction ); + InsertLoadFunction(&map, GL_ALPHA, GL_UNSIGNED_BYTE, UnreachableLoadFunction ); + + // From GL_OES_texture_float + InsertLoadFunction(&map, GL_LUMINANCE_ALPHA, GL_FLOAT, LoadLA32FToRGBA32F ); + InsertLoadFunction(&map, GL_LUMINANCE, GL_FLOAT, LoadL32FToRGBA32F ); + InsertLoadFunction(&map, GL_ALPHA, GL_FLOAT, LoadA32FToRGBA32F ); + + // From GL_OES_texture_half_float + InsertLoadFunction(&map, GL_LUMINANCE_ALPHA, GL_HALF_FLOAT, LoadLA16FToRGBA16F ); + InsertLoadFunction(&map, GL_LUMINANCE_ALPHA, GL_HALF_FLOAT_OES, LoadLA16FToRGBA16F ); + InsertLoadFunction(&map, GL_LUMINANCE, GL_HALF_FLOAT, LoadL16FToRGBA16F ); + InsertLoadFunction(&map, GL_LUMINANCE, GL_HALF_FLOAT_OES, LoadL16FToRGBA16F ); + InsertLoadFunction(&map, GL_ALPHA, GL_HALF_FLOAT, LoadA16FToRGBA16F ); + InsertLoadFunction(&map, GL_ALPHA, GL_HALF_FLOAT_OES, LoadA16FToRGBA16F ); + + // From GL_EXT_texture_storage + // GL_ALPHA8_EXT GL_UNSIGNED_BYTE is in the feature-level-specific load function maps, due to differences between 9_3 and 10_0+ + InsertLoadFunction(&map, GL_LUMINANCE8_EXT, GL_UNSIGNED_BYTE, LoadL8ToRGBA8 ); + InsertLoadFunction(&map, GL_LUMINANCE8_ALPHA8_EXT, GL_UNSIGNED_BYTE, LoadLA8ToRGBA8 ); + InsertLoadFunction(&map, GL_ALPHA32F_EXT, GL_FLOAT, LoadA32FToRGBA32F ); + InsertLoadFunction(&map, GL_LUMINANCE32F_EXT, GL_FLOAT, LoadL32FToRGBA32F ); + InsertLoadFunction(&map, GL_LUMINANCE_ALPHA32F_EXT, GL_FLOAT, LoadLA32FToRGBA32F ); + InsertLoadFunction(&map, GL_ALPHA16F_EXT, GL_HALF_FLOAT, LoadA16FToRGBA16F ); + InsertLoadFunction(&map, GL_ALPHA16F_EXT, GL_HALF_FLOAT_OES, LoadA16FToRGBA16F ); + InsertLoadFunction(&map, GL_LUMINANCE16F_EXT, GL_HALF_FLOAT, LoadL16FToRGBA16F ); + InsertLoadFunction(&map, GL_LUMINANCE16F_EXT, GL_HALF_FLOAT_OES, LoadL16FToRGBA16F ); + InsertLoadFunction(&map, GL_LUMINANCE_ALPHA16F_EXT, GL_HALF_FLOAT, LoadLA16FToRGBA16F ); + InsertLoadFunction(&map, GL_LUMINANCE_ALPHA16F_EXT, GL_HALF_FLOAT_OES, LoadLA16FToRGBA16F ); + + // From GL_ANGLE_depth_texture + InsertLoadFunction(&map, GL_DEPTH_COMPONENT32_OES, GL_UNSIGNED_INT, LoadR32ToR24G8 ); + + // From GL_EXT_texture_format_BGRA8888 + InsertLoadFunction(&map, GL_BGRA8_EXT, GL_UNSIGNED_BYTE, LoadToNative ); + InsertLoadFunction(&map, GL_BGRA4_ANGLEX, GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT, LoadRGBA4ToRGBA8 ); + InsertLoadFunction(&map, GL_BGRA4_ANGLEX, GL_UNSIGNED_BYTE, LoadToNative ); + InsertLoadFunction(&map, GL_BGR5_A1_ANGLEX, GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT, LoadRGB5A1ToRGBA8 ); + InsertLoadFunction(&map, GL_BGR5_A1_ANGLEX, GL_UNSIGNED_BYTE, LoadToNative ); + + // Compressed formats + // From ES 3.0.1 spec, table 3.16 + // | Internal format | Type | Load function | + InsertLoadFunction(&map, GL_COMPRESSED_R11_EAC, GL_UNSIGNED_BYTE, UnimplementedLoadFunction ); + InsertLoadFunction(&map, GL_COMPRESSED_R11_EAC, GL_UNSIGNED_BYTE, UnimplementedLoadFunction ); + InsertLoadFunction(&map, GL_COMPRESSED_SIGNED_R11_EAC, GL_UNSIGNED_BYTE, UnimplementedLoadFunction ); + InsertLoadFunction(&map, GL_COMPRESSED_RG11_EAC, GL_UNSIGNED_BYTE, UnimplementedLoadFunction ); + InsertLoadFunction(&map, GL_COMPRESSED_SIGNED_RG11_EAC, GL_UNSIGNED_BYTE, UnimplementedLoadFunction ); + InsertLoadFunction(&map, GL_COMPRESSED_RGB8_ETC2, GL_UNSIGNED_BYTE, UnimplementedLoadFunction ); + InsertLoadFunction(&map, GL_COMPRESSED_SRGB8_ETC2, GL_UNSIGNED_BYTE, UnimplementedLoadFunction ); + InsertLoadFunction(&map, GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2, GL_UNSIGNED_BYTE, UnimplementedLoadFunction ); + InsertLoadFunction(&map, GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2, GL_UNSIGNED_BYTE, UnimplementedLoadFunction ); + InsertLoadFunction(&map, GL_COMPRESSED_RGBA8_ETC2_EAC, GL_UNSIGNED_BYTE, UnimplementedLoadFunction ); + InsertLoadFunction(&map, GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC, GL_UNSIGNED_BYTE, UnimplementedLoadFunction ); + + // From GL_EXT_texture_compression_dxt1 + InsertLoadFunction(&map, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_UNSIGNED_BYTE, LoadCompressedToNative<4, 4, 8>); + InsertLoadFunction(&map, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, GL_UNSIGNED_BYTE, LoadCompressedToNative<4, 4, 8>); + + // From GL_ANGLE_texture_compression_dxt3 + InsertLoadFunction(&map, GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE, GL_UNSIGNED_BYTE, LoadCompressedToNative<4, 4, 16>); + + // From GL_ANGLE_texture_compression_dxt5 + InsertLoadFunction(&map, GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE, GL_UNSIGNED_BYTE, LoadCompressedToNative<4, 4, 16>); + + return map; +} + +// For sized GL internal formats, there is only one corresponding D3D11 format. This map type allows +// querying for the DXGI texture formats to use for textures, SRVs, RTVs and DSVs given a GL internal +// format. +typedef std::map D3D11ES3FormatMap; + +TextureFormat::TextureFormat() + : texFormat(DXGI_FORMAT_UNKNOWN), + srvFormat(DXGI_FORMAT_UNKNOWN), + rtvFormat(DXGI_FORMAT_UNKNOWN), + dsvFormat(DXGI_FORMAT_UNKNOWN), + renderFormat(DXGI_FORMAT_UNKNOWN), + swizzleTexFormat(DXGI_FORMAT_UNKNOWN), + swizzleSRVFormat(DXGI_FORMAT_UNKNOWN), + swizzleRTVFormat(DXGI_FORMAT_UNKNOWN), + dataInitializerFunction(NULL), + loadFunctions() +{ +} + +static inline void InsertD3D11FormatInfoBase(D3D11ES3FormatMap *formatMap, const D3D11LoadFunctionMap &flLoadFunctions, GLenum internalFormat, DXGI_FORMAT texFormat, + DXGI_FORMAT srvFormat, DXGI_FORMAT rtvFormat, DXGI_FORMAT dsvFormat) +{ + TextureFormat info; + info.texFormat = texFormat; + info.srvFormat = srvFormat; + info.rtvFormat = rtvFormat; + info.dsvFormat = dsvFormat; + + // Given a GL internal format, the renderFormat is the DSV format if it is depth- or stencil-renderable, + // the RTV format if it is color-renderable, and the (nonrenderable) texture format otherwise. + if (dsvFormat != DXGI_FORMAT_UNKNOWN) + { + info.renderFormat = dsvFormat; + } + else if (rtvFormat != DXGI_FORMAT_UNKNOWN) + { + info.renderFormat = rtvFormat; + } + else if (texFormat != DXGI_FORMAT_UNKNOWN) + { + info.renderFormat = texFormat; + } + else + { + info.renderFormat = DXGI_FORMAT_UNKNOWN; + } + + // Compute the swizzle formats + const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat); + if (internalFormat != GL_NONE && formatInfo.pixelBytes > 0) + { + if (formatInfo.componentCount != 4 || texFormat == DXGI_FORMAT_UNKNOWN || + srvFormat == DXGI_FORMAT_UNKNOWN || rtvFormat == DXGI_FORMAT_UNKNOWN) + { + // Get the maximum sized component + unsigned int maxBits = 1; + if (formatInfo.compressed) + { + unsigned int compressedBitsPerBlock = formatInfo.pixelBytes * 8; + unsigned int blockSize = formatInfo.compressedBlockWidth * formatInfo.compressedBlockHeight; + maxBits = std::max(compressedBitsPerBlock / blockSize, maxBits); + } + else + { + maxBits = std::max(maxBits, formatInfo.alphaBits); + maxBits = std::max(maxBits, formatInfo.redBits); + maxBits = std::max(maxBits, formatInfo.greenBits); + maxBits = std::max(maxBits, formatInfo.blueBits); + maxBits = std::max(maxBits, formatInfo.luminanceBits); + maxBits = std::max(maxBits, formatInfo.depthBits); + } + + maxBits = roundUp(maxBits, 8U); + + static const SwizzleInfoMap swizzleMap = BuildSwizzleInfoMap(); + SwizzleInfoMap::const_iterator swizzleIter = swizzleMap.find(SwizzleSizeType(maxBits, formatInfo.componentType)); + ASSERT(swizzleIter != swizzleMap.end()); + + const SwizzleFormatInfo &swizzleInfo = swizzleIter->second; + info.swizzleTexFormat = swizzleInfo.mTexFormat; + info.swizzleSRVFormat = swizzleInfo.mSRVFormat; + info.swizzleRTVFormat = swizzleInfo.mRTVFormat; + } + else + { + // The original texture format is suitable for swizzle operations + info.swizzleTexFormat = texFormat; + info.swizzleSRVFormat = srvFormat; + info.swizzleRTVFormat = rtvFormat; + } + } + else + { + // Not possible to swizzle with this texture format since it is either unsized or GL_NONE + info.swizzleTexFormat = DXGI_FORMAT_UNKNOWN; + info.swizzleSRVFormat = DXGI_FORMAT_UNKNOWN; + info.swizzleRTVFormat = DXGI_FORMAT_UNKNOWN; + } + + // Check if there is an initialization function for this texture format + static const InternalFormatInitializerMap initializerMap = BuildInternalFormatInitializerMap(); + InternalFormatInitializerMap::const_iterator initializerIter = initializerMap.find(internalFormat); + info.dataInitializerFunction = (initializerIter != initializerMap.end()) ? initializerIter->second : NULL; + + // Gather all the load functions for this internal format from the base list + static const D3D11LoadFunctionMap loadFunctions = BuildBaseD3D11LoadFunctionMap(); + D3D11LoadFunctionMap::const_iterator loadFunctionIter = loadFunctions.find(internalFormat); + if (loadFunctionIter != loadFunctions.end()) + { + const std::vector &loadFunctionVector = loadFunctionIter->second; + for (size_t i = 0; i < loadFunctionVector.size(); i++) + { + GLenum type = loadFunctionVector[i].first; + LoadImageFunction function = loadFunctionVector[i].second; + info.loadFunctions.insert(std::make_pair(type, function)); + } + } + + // Gather load functions for this internal format from the feature-level-specific list + D3D11LoadFunctionMap::const_iterator flLoadFunctionIter = flLoadFunctions.find(internalFormat); + if (flLoadFunctionIter != flLoadFunctions.end()) + { + const std::vector &flLoadFunctionVector = flLoadFunctionIter->second; + for (size_t i = 0; i < flLoadFunctionVector.size(); i++) + { + GLenum type = flLoadFunctionVector[i].first; + LoadImageFunction function = flLoadFunctionVector[i].second; + info.loadFunctions.insert(std::make_pair(type, function)); + } + } + + formatMap->insert(std::make_pair(internalFormat, info)); +} + +static inline void InsertD3D11_FL9_3_FormatInfo(D3D11ES3FormatMap *map, GLenum internalFormat, DXGI_FORMAT texFormat, + DXGI_FORMAT srvFormat, DXGI_FORMAT rtvFormat, DXGI_FORMAT dsvFormat) +{ + static const D3D11LoadFunctionMap flLoadFunctions = BuildD3D11_FL9_3_LoadFunctionMap(); + InsertD3D11FormatInfoBase(map, flLoadFunctions, internalFormat, texFormat, srvFormat, rtvFormat, dsvFormat); +} + +static inline void InsertD3D11FormatInfo(D3D11ES3FormatMap *map, GLenum internalFormat, DXGI_FORMAT texFormat, + DXGI_FORMAT srvFormat, DXGI_FORMAT rtvFormat, DXGI_FORMAT dsvFormat) +{ + static const D3D11LoadFunctionMap flLoadFunctions = BuildD3D11_FL10_0Plus_LoadFunctionMap(); + InsertD3D11FormatInfoBase(map, flLoadFunctions, internalFormat, texFormat, srvFormat, rtvFormat, dsvFormat); +} + +static D3D11ES3FormatMap BuildD3D11_FL9_3FormatOverrideMap() +{ + // D3D11 Feature Level 9_3 doesn't support as many texture formats as Feature Level 10_0+. + // In particular, it doesn't support: + // - mipmaps on DXGI_FORMAT_A8_NORM + // - *_TYPELESS formats + // - DXGI_FORMAT_D32_FLOAT_S8X24_UINT or DXGI_FORMAT_D32_FLOAT + + D3D11ES3FormatMap map; + + // | GL internal format | D3D11 texture format | D3D11 SRV format | D3D11 RTV format | D3D11 DSV format + InsertD3D11_FL9_3_FormatInfo(&map, GL_ALPHA, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN); + InsertD3D11_FL9_3_FormatInfo(&map, GL_ALPHA8_EXT, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN); + InsertD3D11_FL9_3_FormatInfo(&map, GL_DEPTH_COMPONENT16, DXGI_FORMAT_D16_UNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_D16_UNORM); + InsertD3D11_FL9_3_FormatInfo(&map, GL_DEPTH_COMPONENT24, DXGI_FORMAT_D24_UNORM_S8_UINT, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_D24_UNORM_S8_UINT); + InsertD3D11_FL9_3_FormatInfo(&map, GL_DEPTH_COMPONENT32F, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN); + InsertD3D11_FL9_3_FormatInfo(&map, GL_DEPTH24_STENCIL8, DXGI_FORMAT_D24_UNORM_S8_UINT, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_D24_UNORM_S8_UINT); + InsertD3D11_FL9_3_FormatInfo(&map, GL_DEPTH32F_STENCIL8, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN); + InsertD3D11_FL9_3_FormatInfo(&map, GL_STENCIL_INDEX8, DXGI_FORMAT_D24_UNORM_S8_UINT, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_D24_UNORM_S8_UINT); + + return map; +} + +static D3D11ES3FormatMap BuildD3D11FormatMap() +{ + D3D11ES3FormatMap map; + + // | GL internal format | D3D11 texture format | D3D11 SRV format | D3D11 RTV format | D3D11 DSV format | + InsertD3D11FormatInfo(&map, GL_NONE, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_R8, DXGI_FORMAT_R8_UNORM, DXGI_FORMAT_R8_UNORM, DXGI_FORMAT_R8_UNORM, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_R8_SNORM, DXGI_FORMAT_R8_SNORM, DXGI_FORMAT_R8_SNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_RG8, DXGI_FORMAT_R8G8_UNORM, DXGI_FORMAT_R8G8_UNORM, DXGI_FORMAT_R8G8_UNORM, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_RG8_SNORM, DXGI_FORMAT_R8G8_SNORM, DXGI_FORMAT_R8G8_SNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_RGB8, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_RGB8_SNORM, DXGI_FORMAT_R8G8B8A8_SNORM, DXGI_FORMAT_R8G8B8A8_SNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_RGB565, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_RGBA4, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_RGB5_A1, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_RGBA8, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_RGBA8_SNORM, DXGI_FORMAT_R8G8B8A8_SNORM, DXGI_FORMAT_R8G8B8A8_SNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_RGB10_A2, DXGI_FORMAT_R10G10B10A2_UNORM, DXGI_FORMAT_R10G10B10A2_UNORM, DXGI_FORMAT_R10G10B10A2_UNORM, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_RGB10_A2UI, DXGI_FORMAT_R10G10B10A2_UINT, DXGI_FORMAT_R10G10B10A2_UINT, DXGI_FORMAT_R10G10B10A2_UINT, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_SRGB8, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_SRGB8_ALPHA8, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_R16F, DXGI_FORMAT_R16_FLOAT, DXGI_FORMAT_R16_FLOAT, DXGI_FORMAT_R16_FLOAT, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_RG16F, DXGI_FORMAT_R16G16_FLOAT, DXGI_FORMAT_R16G16_FLOAT, DXGI_FORMAT_R16G16_FLOAT, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_RGB16F, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_RGBA16F, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_R32F, DXGI_FORMAT_R32_FLOAT, DXGI_FORMAT_R32_FLOAT, DXGI_FORMAT_R32_FLOAT, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_RG32F, DXGI_FORMAT_R32G32_FLOAT, DXGI_FORMAT_R32G32_FLOAT, DXGI_FORMAT_R32G32_FLOAT, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_RGB32F, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_RGBA32F, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_R11F_G11F_B10F, DXGI_FORMAT_R11G11B10_FLOAT, DXGI_FORMAT_R11G11B10_FLOAT, DXGI_FORMAT_R11G11B10_FLOAT, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_RGB9_E5, DXGI_FORMAT_R9G9B9E5_SHAREDEXP, DXGI_FORMAT_R9G9B9E5_SHAREDEXP, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_R8I, DXGI_FORMAT_R8_SINT, DXGI_FORMAT_R8_SINT, DXGI_FORMAT_R8_SINT, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_R8UI, DXGI_FORMAT_R8_UINT, DXGI_FORMAT_R8_UINT, DXGI_FORMAT_R8_UINT, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_R16I, DXGI_FORMAT_R16_SINT, DXGI_FORMAT_R16_SINT, DXGI_FORMAT_R16_SINT, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_R16UI, DXGI_FORMAT_R16_UINT, DXGI_FORMAT_R16_UINT, DXGI_FORMAT_R16_UINT, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_R32I, DXGI_FORMAT_R32_SINT, DXGI_FORMAT_R32_SINT, DXGI_FORMAT_R32_SINT, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_R32UI, DXGI_FORMAT_R32_UINT, DXGI_FORMAT_R32_UINT, DXGI_FORMAT_R32_UINT, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_RG8I, DXGI_FORMAT_R8G8_SINT, DXGI_FORMAT_R8G8_SINT, DXGI_FORMAT_R8G8_SINT, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_RG8UI, DXGI_FORMAT_R8G8_UINT, DXGI_FORMAT_R8G8_UINT, DXGI_FORMAT_R8G8_UINT, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_RG16I, DXGI_FORMAT_R16G16_SINT, DXGI_FORMAT_R16G16_SINT, DXGI_FORMAT_R16G16_SINT, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_RG16UI, DXGI_FORMAT_R16G16_UINT, DXGI_FORMAT_R16G16_UINT, DXGI_FORMAT_R16G16_UINT, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_RG32I, DXGI_FORMAT_R32G32_SINT, DXGI_FORMAT_R32G32_SINT, DXGI_FORMAT_R32G32_SINT, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_RG32UI, DXGI_FORMAT_R32G32_UINT, DXGI_FORMAT_R32G32_UINT, DXGI_FORMAT_R32G32_UINT, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_RGB8I, DXGI_FORMAT_R8G8B8A8_SINT, DXGI_FORMAT_R8G8B8A8_SINT, DXGI_FORMAT_R8G8B8A8_SINT, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_RGB8UI, DXGI_FORMAT_R8G8B8A8_UINT, DXGI_FORMAT_R8G8B8A8_UINT, DXGI_FORMAT_R8G8B8A8_UINT, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_RGB16I, DXGI_FORMAT_R16G16B16A16_SINT, DXGI_FORMAT_R16G16B16A16_SINT, DXGI_FORMAT_R16G16B16A16_SINT, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_RGB16UI, DXGI_FORMAT_R16G16B16A16_UINT, DXGI_FORMAT_R16G16B16A16_UINT, DXGI_FORMAT_R16G16B16A16_UINT, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_RGB32I, DXGI_FORMAT_R32G32B32A32_SINT, DXGI_FORMAT_R32G32B32A32_SINT, DXGI_FORMAT_R32G32B32A32_SINT, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_RGB32UI, DXGI_FORMAT_R32G32B32A32_UINT, DXGI_FORMAT_R32G32B32A32_UINT, DXGI_FORMAT_R32G32B32A32_UINT, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_RGBA8I, DXGI_FORMAT_R8G8B8A8_SINT, DXGI_FORMAT_R8G8B8A8_SINT, DXGI_FORMAT_R8G8B8A8_SINT, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_RGBA8UI, DXGI_FORMAT_R8G8B8A8_UINT, DXGI_FORMAT_R8G8B8A8_UINT, DXGI_FORMAT_R8G8B8A8_UINT, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_RGBA16I, DXGI_FORMAT_R16G16B16A16_SINT, DXGI_FORMAT_R16G16B16A16_SINT, DXGI_FORMAT_R16G16B16A16_SINT, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_RGBA16UI, DXGI_FORMAT_R16G16B16A16_UINT, DXGI_FORMAT_R16G16B16A16_UINT, DXGI_FORMAT_R16G16B16A16_UINT, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_RGBA32I, DXGI_FORMAT_R32G32B32A32_SINT, DXGI_FORMAT_R32G32B32A32_SINT, DXGI_FORMAT_R32G32B32A32_SINT, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_RGBA32UI, DXGI_FORMAT_R32G32B32A32_UINT, DXGI_FORMAT_R32G32B32A32_UINT, DXGI_FORMAT_R32G32B32A32_UINT, DXGI_FORMAT_UNKNOWN); + + // Unsized formats, TODO: Are types of float and half float allowed for the unsized types? Would it change the DXGI format? + InsertD3D11FormatInfo(&map, GL_ALPHA, DXGI_FORMAT_A8_UNORM, DXGI_FORMAT_A8_UNORM, DXGI_FORMAT_A8_UNORM, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_LUMINANCE, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_LUMINANCE_ALPHA, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_RGB, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_RGBA, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_BGRA_EXT, DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_UNKNOWN); + + // From GL_EXT_texture_storage + // | GL internal format | D3D11 texture format | D3D11 SRV format | D3D11 RTV format | D3D11 DSV format | + InsertD3D11FormatInfo(&map, GL_ALPHA8_EXT, DXGI_FORMAT_A8_UNORM, DXGI_FORMAT_A8_UNORM, DXGI_FORMAT_A8_UNORM, DXGI_FORMAT_UNKNOWN ); + InsertD3D11FormatInfo(&map, GL_LUMINANCE8_EXT, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN ); + InsertD3D11FormatInfo(&map, GL_ALPHA32F_EXT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_UNKNOWN ); + InsertD3D11FormatInfo(&map, GL_LUMINANCE32F_EXT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_UNKNOWN ); + InsertD3D11FormatInfo(&map, GL_ALPHA16F_EXT, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_UNKNOWN ); + InsertD3D11FormatInfo(&map, GL_LUMINANCE16F_EXT, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_UNKNOWN ); + InsertD3D11FormatInfo(&map, GL_LUMINANCE8_ALPHA8_EXT, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN ); + InsertD3D11FormatInfo(&map, GL_LUMINANCE_ALPHA32F_EXT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_UNKNOWN ); + InsertD3D11FormatInfo(&map, GL_LUMINANCE_ALPHA16F_EXT, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_UNKNOWN ); + InsertD3D11FormatInfo(&map, GL_BGRA8_EXT, DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_UNKNOWN ); + InsertD3D11FormatInfo(&map, GL_BGRA4_ANGLEX, DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_UNKNOWN ); + InsertD3D11FormatInfo(&map, GL_BGR5_A1_ANGLEX, DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_UNKNOWN ); + + // Depth stencil formats + InsertD3D11FormatInfo(&map, GL_DEPTH_COMPONENT16, DXGI_FORMAT_R16_TYPELESS, DXGI_FORMAT_R16_UNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_D16_UNORM ); + InsertD3D11FormatInfo(&map, GL_DEPTH_COMPONENT24, DXGI_FORMAT_R24G8_TYPELESS, DXGI_FORMAT_R24_UNORM_X8_TYPELESS, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_D24_UNORM_S8_UINT ); + InsertD3D11FormatInfo(&map, GL_DEPTH_COMPONENT32F, DXGI_FORMAT_R32_TYPELESS, DXGI_FORMAT_R32_FLOAT, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_D32_FLOAT ); + InsertD3D11FormatInfo(&map, GL_DEPTH24_STENCIL8, DXGI_FORMAT_R24G8_TYPELESS, DXGI_FORMAT_R24_UNORM_X8_TYPELESS, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_D24_UNORM_S8_UINT ); + InsertD3D11FormatInfo(&map, GL_DEPTH32F_STENCIL8, DXGI_FORMAT_R32G8X24_TYPELESS, DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_D32_FLOAT_S8X24_UINT); + InsertD3D11FormatInfo(&map, GL_STENCIL_INDEX8, DXGI_FORMAT_R24G8_TYPELESS, DXGI_FORMAT_X24_TYPELESS_G8_UINT, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_D24_UNORM_S8_UINT ); + + // From GL_ANGLE_depth_texture + // Since D3D11 doesn't have a D32_UNORM format, use D24S8 which has comparable precision and matches the ES3 format. + InsertD3D11FormatInfo(&map, GL_DEPTH_COMPONENT32_OES, DXGI_FORMAT_R24G8_TYPELESS, DXGI_FORMAT_R24_UNORM_X8_TYPELESS, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_D24_UNORM_S8_UINT); + + // Compressed formats, From ES 3.0.1 spec, table 3.16 + // | GL internal format | D3D11 texture format | D3D11 SRV format | D3D11 RTV format | D3D11 DSV format | + InsertD3D11FormatInfo(&map, GL_COMPRESSED_R11_EAC, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_COMPRESSED_SIGNED_R11_EAC, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_COMPRESSED_RG11_EAC, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_COMPRESSED_SIGNED_RG11_EAC, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_COMPRESSED_RGB8_ETC2, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_COMPRESSED_SRGB8_ETC2, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_COMPRESSED_RGBA8_ETC2_EAC, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN); + + // From GL_EXT_texture_compression_dxt1 + InsertD3D11FormatInfo(&map, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, DXGI_FORMAT_BC1_UNORM, DXGI_FORMAT_BC1_UNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, DXGI_FORMAT_BC1_UNORM, DXGI_FORMAT_BC1_UNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN); + + // From GL_ANGLE_texture_compression_dxt3 + InsertD3D11FormatInfo(&map, GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE, DXGI_FORMAT_BC2_UNORM, DXGI_FORMAT_BC2_UNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN); + + // From GL_ANGLE_texture_compression_dxt5 + InsertD3D11FormatInfo(&map, GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE, DXGI_FORMAT_BC3_UNORM, DXGI_FORMAT_BC3_UNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN); + + return map; +} + +const TextureFormat &GetTextureFormatInfo(GLenum internalFormat, D3D_FEATURE_LEVEL featureLevel) +{ + static const D3D11ES3FormatMap formatMap = BuildD3D11FormatMap(); + static const D3D11ES3FormatMap formatMapFL9_3Override = BuildD3D11_FL9_3FormatOverrideMap(); + + if (featureLevel == D3D_FEATURE_LEVEL_9_3) + { + // First see if the internalFormat has a special map for FL9_3 + D3D11ES3FormatMap::const_iterator fl9_3Iter = formatMapFL9_3Override.find(internalFormat); + if (fl9_3Iter != formatMapFL9_3Override.end()) + { + return fl9_3Iter->second; + } + } + + D3D11ES3FormatMap::const_iterator iter = formatMap.find(internalFormat); + if (iter != formatMap.end()) + { + return iter->second; + } + else + { + static const TextureFormat defaultInfo; + return defaultInfo; + } +} + +typedef std::map D3D11VertexFormatInfoMap; +typedef std::pair D3D11VertexFormatPair; + +VertexFormat::VertexFormat() + : conversionType(VERTEX_CONVERT_NONE), + nativeFormat(DXGI_FORMAT_UNKNOWN), + copyFunction(NULL) +{ +} + +static void AddVertexFormatInfo(D3D11VertexFormatInfoMap *map, GLenum inputType, GLboolean normalized, GLuint componentCount, + VertexConversionType conversionType, DXGI_FORMAT nativeFormat, VertexCopyFunction copyFunction) +{ + gl::VertexFormat inputFormat(inputType, normalized, componentCount, false); + + VertexFormat info; + info.conversionType = conversionType; + info.nativeFormat = nativeFormat; + info.copyFunction = copyFunction; + + map->insert(D3D11VertexFormatPair(inputFormat, info)); +} + +static void AddIntegerVertexFormatInfo(D3D11VertexFormatInfoMap *map, GLenum inputType, GLuint componentCount, + VertexConversionType conversionType, DXGI_FORMAT nativeFormat, VertexCopyFunction copyFunction) +{ + gl::VertexFormat inputFormat(inputType, GL_FALSE, componentCount, true); + + VertexFormat info; + info.conversionType = conversionType; + info.nativeFormat = nativeFormat; + info.copyFunction = copyFunction; + + map->insert(D3D11VertexFormatPair(inputFormat, info)); +} + +static D3D11VertexFormatInfoMap BuildD3D11_FL9_3VertexFormatInfoOverrideMap() +{ + // D3D11 Feature Level 9_3 doesn't support as many formats for vertex buffer resource as Feature Level 10_0+. + // http://msdn.microsoft.com/en-us/library/windows/desktop/ff471324(v=vs.85).aspx + + D3D11VertexFormatInfoMap map; + + // GL_BYTE -- unnormalized + AddVertexFormatInfo(&map, GL_BYTE, GL_FALSE, 1, VERTEX_CONVERT_BOTH, DXGI_FORMAT_R16G16_SINT, &Copy8SintTo16SintVertexData<1, 2>); + AddVertexFormatInfo(&map, GL_BYTE, GL_FALSE, 2, VERTEX_CONVERT_BOTH, DXGI_FORMAT_R16G16_SINT, &Copy8SintTo16SintVertexData<2, 2>); + AddVertexFormatInfo(&map, GL_BYTE, GL_FALSE, 3, VERTEX_CONVERT_BOTH, DXGI_FORMAT_R16G16B16A16_SINT, &Copy8SintTo16SintVertexData<3, 4>); + AddVertexFormatInfo(&map, GL_BYTE, GL_FALSE, 4, VERTEX_CONVERT_BOTH, DXGI_FORMAT_R16G16B16A16_SINT, &Copy8SintTo16SintVertexData<4, 4>); + + // GL_BYTE -- normalized + AddVertexFormatInfo(&map, GL_BYTE, GL_TRUE, 1, VERTEX_CONVERT_CPU, DXGI_FORMAT_R16G16_SNORM, &Copy8SnormTo16SnormVertexData<1, 2>); + AddVertexFormatInfo(&map, GL_BYTE, GL_TRUE, 2, VERTEX_CONVERT_CPU, DXGI_FORMAT_R16G16_SNORM, &Copy8SnormTo16SnormVertexData<2, 2>); + AddVertexFormatInfo(&map, GL_BYTE, GL_TRUE, 3, VERTEX_CONVERT_CPU, DXGI_FORMAT_R16G16B16A16_SNORM, &Copy8SnormTo16SnormVertexData<3, 4>); + AddVertexFormatInfo(&map, GL_BYTE, GL_TRUE, 4, VERTEX_CONVERT_CPU, DXGI_FORMAT_R16G16B16A16_SNORM, &Copy8SnormTo16SnormVertexData<4, 4>); + + // GL_UNSIGNED_BYTE -- unnormalized + AddVertexFormatInfo(&map, GL_UNSIGNED_BYTE, GL_FALSE, 1, VERTEX_CONVERT_BOTH, DXGI_FORMAT_R8G8B8A8_UINT, &CopyNativeVertexData); + AddVertexFormatInfo(&map, GL_UNSIGNED_BYTE, GL_FALSE, 2, VERTEX_CONVERT_BOTH, DXGI_FORMAT_R8G8B8A8_UINT, &CopyNativeVertexData); + // NOTE: 3 and 4 component unnormalized GL_UNSIGNED_BYTE should use the default format table. + + // GL_UNSIGNED_BYTE -- normalized + AddVertexFormatInfo(&map, GL_UNSIGNED_BYTE, GL_TRUE, 1, VERTEX_CONVERT_CPU, DXGI_FORMAT_R8G8B8A8_UNORM, &CopyNativeVertexData); + AddVertexFormatInfo(&map, GL_UNSIGNED_BYTE, GL_TRUE, 2, VERTEX_CONVERT_CPU, DXGI_FORMAT_R8G8B8A8_UNORM, &CopyNativeVertexData); + // NOTE: 3 and 4 component normalized GL_UNSIGNED_BYTE should use the default format table. + + // GL_SHORT -- unnormalized + AddVertexFormatInfo(&map, GL_SHORT, GL_FALSE, 1, VERTEX_CONVERT_BOTH, DXGI_FORMAT_R16G16_SINT, &CopyNativeVertexData); + // NOTE: 2, 3 and 4 component unnormalized GL_SHORT should use the default format table. + + // GL_SHORT -- normalized + AddVertexFormatInfo(&map, GL_SHORT, GL_TRUE, 1, VERTEX_CONVERT_CPU, DXGI_FORMAT_R16G16_SNORM, &CopyNativeVertexData); + // NOTE: 2, 3 and 4 component normalized GL_SHORT should use the default format table. + + // GL_UNSIGNED_SHORT -- unnormalized + AddVertexFormatInfo(&map, GL_UNSIGNED_SHORT, GL_FALSE, 1, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32_FLOAT, &CopyTo32FVertexData); + AddVertexFormatInfo(&map, GL_UNSIGNED_SHORT, GL_FALSE, 2, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32_FLOAT, &CopyTo32FVertexData); + AddVertexFormatInfo(&map, GL_UNSIGNED_SHORT, GL_FALSE, 3, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32_FLOAT, &CopyTo32FVertexData); + AddVertexFormatInfo(&map, GL_UNSIGNED_SHORT, GL_FALSE, 4, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32A32_FLOAT, &CopyTo32FVertexData); + + // GL_UNSIGNED_SHORT -- normalized + AddVertexFormatInfo(&map, GL_UNSIGNED_SHORT, GL_TRUE, 1, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32_FLOAT, &CopyTo32FVertexData); + AddVertexFormatInfo(&map, GL_UNSIGNED_SHORT, GL_TRUE, 2, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32_FLOAT, &CopyTo32FVertexData); + AddVertexFormatInfo(&map, GL_UNSIGNED_SHORT, GL_TRUE, 3, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32_FLOAT, &CopyTo32FVertexData); + AddVertexFormatInfo(&map, GL_UNSIGNED_SHORT, GL_TRUE, 4, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32A32_FLOAT, &CopyTo32FVertexData); + + // GL_FIXED + // TODO: Add test to verify that this works correctly. + AddVertexFormatInfo(&map, GL_FIXED, GL_FALSE, 1, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32_FLOAT, &Copy32FixedTo32FVertexData<1, 2>); + // NOTE: 2, 3 and 4 component GL_FIXED should use the default format table. + + // GL_FLOAT + // TODO: Add test to verify that this works correctly. + AddVertexFormatInfo(&map, GL_FLOAT, GL_FALSE, 1, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32_FLOAT, &CopyNativeVertexData); + // NOTE: 2, 3 and 4 component GL_FLOAT should use the default format table. + + return map; +} + +static D3D11VertexFormatInfoMap BuildD3D11VertexFormatInfoMap() +{ + D3D11VertexFormatInfoMap map; + + // TODO: column legend + + // + // Float formats + // + + // GL_BYTE -- un-normalized + AddVertexFormatInfo(&map, GL_BYTE, GL_FALSE, 1, VERTEX_CONVERT_GPU, DXGI_FORMAT_R8_SINT, &CopyNativeVertexData); + AddVertexFormatInfo(&map, GL_BYTE, GL_FALSE, 2, VERTEX_CONVERT_GPU, DXGI_FORMAT_R8G8_SINT, &CopyNativeVertexData); + AddVertexFormatInfo(&map, GL_BYTE, GL_FALSE, 3, VERTEX_CONVERT_BOTH, DXGI_FORMAT_R8G8B8A8_SINT, &CopyNativeVertexData); + AddVertexFormatInfo(&map, GL_BYTE, GL_FALSE, 4, VERTEX_CONVERT_GPU, DXGI_FORMAT_R8G8B8A8_SINT, &CopyNativeVertexData); + + // GL_BYTE -- normalized + AddVertexFormatInfo(&map, GL_BYTE, GL_TRUE, 1, VERTEX_CONVERT_NONE, DXGI_FORMAT_R8_SNORM, &CopyNativeVertexData); + AddVertexFormatInfo(&map, GL_BYTE, GL_TRUE, 2, VERTEX_CONVERT_NONE, DXGI_FORMAT_R8G8_SNORM, &CopyNativeVertexData); + AddVertexFormatInfo(&map, GL_BYTE, GL_TRUE, 3, VERTEX_CONVERT_CPU, DXGI_FORMAT_R8G8B8A8_SNORM, &CopyNativeVertexData); + AddVertexFormatInfo(&map, GL_BYTE, GL_TRUE, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R8G8B8A8_SNORM, &CopyNativeVertexData); + + // GL_UNSIGNED_BYTE -- un-normalized + AddVertexFormatInfo(&map, GL_UNSIGNED_BYTE, GL_FALSE, 1, VERTEX_CONVERT_GPU, DXGI_FORMAT_R8_UINT, &CopyNativeVertexData); + AddVertexFormatInfo(&map, GL_UNSIGNED_BYTE, GL_FALSE, 2, VERTEX_CONVERT_GPU, DXGI_FORMAT_R8G8_UINT, &CopyNativeVertexData); + AddVertexFormatInfo(&map, GL_UNSIGNED_BYTE, GL_FALSE, 3, VERTEX_CONVERT_BOTH, DXGI_FORMAT_R8G8B8A8_UINT, &CopyNativeVertexData); + AddVertexFormatInfo(&map, GL_UNSIGNED_BYTE, GL_FALSE, 4, VERTEX_CONVERT_GPU, DXGI_FORMAT_R8G8B8A8_UINT, &CopyNativeVertexData); + + // GL_UNSIGNED_BYTE -- normalized + AddVertexFormatInfo(&map, GL_UNSIGNED_BYTE, GL_TRUE, 1, VERTEX_CONVERT_NONE, DXGI_FORMAT_R8_UNORM, &CopyNativeVertexData); + AddVertexFormatInfo(&map, GL_UNSIGNED_BYTE, GL_TRUE, 2, VERTEX_CONVERT_NONE, DXGI_FORMAT_R8G8_UNORM, &CopyNativeVertexData); + AddVertexFormatInfo(&map, GL_UNSIGNED_BYTE, GL_TRUE, 3, VERTEX_CONVERT_CPU, DXGI_FORMAT_R8G8B8A8_UNORM, &CopyNativeVertexData); + AddVertexFormatInfo(&map, GL_UNSIGNED_BYTE, GL_TRUE, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R8G8B8A8_UNORM, &CopyNativeVertexData); + + // GL_SHORT -- un-normalized + AddVertexFormatInfo(&map, GL_SHORT, GL_FALSE, 1, VERTEX_CONVERT_GPU, DXGI_FORMAT_R16_SINT, &CopyNativeVertexData); + AddVertexFormatInfo(&map, GL_SHORT, GL_FALSE, 2, VERTEX_CONVERT_GPU, DXGI_FORMAT_R16G16_SINT, &CopyNativeVertexData); + AddVertexFormatInfo(&map, GL_SHORT, GL_FALSE, 3, VERTEX_CONVERT_BOTH, DXGI_FORMAT_R16G16B16A16_SINT, &CopyNativeVertexData); + AddVertexFormatInfo(&map, GL_SHORT, GL_FALSE, 4, VERTEX_CONVERT_GPU, DXGI_FORMAT_R16G16B16A16_SINT, &CopyNativeVertexData); + + // GL_SHORT -- normalized + AddVertexFormatInfo(&map, GL_SHORT, GL_TRUE, 1, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16_SNORM, &CopyNativeVertexData); + AddVertexFormatInfo(&map, GL_SHORT, GL_TRUE, 2, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16_SNORM, &CopyNativeVertexData); + AddVertexFormatInfo(&map, GL_SHORT, GL_TRUE, 3, VERTEX_CONVERT_CPU, DXGI_FORMAT_R16G16B16A16_SNORM, &CopyNativeVertexData); + AddVertexFormatInfo(&map, GL_SHORT, GL_TRUE, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16B16A16_SNORM, &CopyNativeVertexData); + + // GL_UNSIGNED_SHORT -- un-normalized + AddVertexFormatInfo(&map, GL_UNSIGNED_SHORT, GL_FALSE, 1, VERTEX_CONVERT_GPU, DXGI_FORMAT_R16_UINT, &CopyNativeVertexData); + AddVertexFormatInfo(&map, GL_UNSIGNED_SHORT, GL_FALSE, 2, VERTEX_CONVERT_GPU, DXGI_FORMAT_R16G16_UINT, &CopyNativeVertexData); + AddVertexFormatInfo(&map, GL_UNSIGNED_SHORT, GL_FALSE, 3, VERTEX_CONVERT_BOTH, DXGI_FORMAT_R16G16B16A16_UINT, &CopyNativeVertexData); + AddVertexFormatInfo(&map, GL_UNSIGNED_SHORT, GL_FALSE, 4, VERTEX_CONVERT_GPU, DXGI_FORMAT_R16G16B16A16_UINT, &CopyNativeVertexData); + + // GL_UNSIGNED_SHORT -- normalized + AddVertexFormatInfo(&map, GL_UNSIGNED_SHORT, GL_TRUE, 1, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16_UNORM, &CopyNativeVertexData); + AddVertexFormatInfo(&map, GL_UNSIGNED_SHORT, GL_TRUE, 2, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16_UNORM, &CopyNativeVertexData); + AddVertexFormatInfo(&map, GL_UNSIGNED_SHORT, GL_TRUE, 3, VERTEX_CONVERT_CPU, DXGI_FORMAT_R16G16B16A16_UNORM, &CopyNativeVertexData); + AddVertexFormatInfo(&map, GL_UNSIGNED_SHORT, GL_TRUE, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16B16A16_UNORM, &CopyNativeVertexData); + + // GL_INT -- un-normalized + AddVertexFormatInfo(&map, GL_INT, GL_FALSE, 1, VERTEX_CONVERT_GPU, DXGI_FORMAT_R32_SINT, &CopyNativeVertexData); + AddVertexFormatInfo(&map, GL_INT, GL_FALSE, 2, VERTEX_CONVERT_GPU, DXGI_FORMAT_R32G32_SINT, &CopyNativeVertexData); + AddVertexFormatInfo(&map, GL_INT, GL_FALSE, 3, VERTEX_CONVERT_GPU, DXGI_FORMAT_R32G32B32_SINT, &CopyNativeVertexData); + AddVertexFormatInfo(&map, GL_INT, GL_FALSE, 4, VERTEX_CONVERT_GPU, DXGI_FORMAT_R32G32B32A32_SINT, &CopyNativeVertexData); + + // GL_INT -- normalized + AddVertexFormatInfo(&map, GL_INT, GL_TRUE, 1, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32_FLOAT, &CopyTo32FVertexData); + AddVertexFormatInfo(&map, GL_INT, GL_TRUE, 2, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32_FLOAT, &CopyTo32FVertexData); + AddVertexFormatInfo(&map, GL_INT, GL_TRUE, 3, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32_FLOAT, &CopyTo32FVertexData); + AddVertexFormatInfo(&map, GL_INT, GL_TRUE, 4, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32A32_FLOAT, &CopyTo32FVertexData); + + // GL_UNSIGNED_INT -- un-normalized + AddVertexFormatInfo(&map, GL_UNSIGNED_INT, GL_FALSE, 1, VERTEX_CONVERT_GPU, DXGI_FORMAT_R32_UINT, &CopyNativeVertexData); + AddVertexFormatInfo(&map, GL_UNSIGNED_INT, GL_FALSE, 2, VERTEX_CONVERT_GPU, DXGI_FORMAT_R32G32_UINT, &CopyNativeVertexData); + AddVertexFormatInfo(&map, GL_UNSIGNED_INT, GL_FALSE, 3, VERTEX_CONVERT_GPU, DXGI_FORMAT_R32G32B32_UINT, &CopyNativeVertexData); + AddVertexFormatInfo(&map, GL_UNSIGNED_INT, GL_FALSE, 4, VERTEX_CONVERT_GPU, DXGI_FORMAT_R32G32B32A32_UINT, &CopyNativeVertexData); + + // GL_UNSIGNED_INT -- normalized + AddVertexFormatInfo(&map, GL_UNSIGNED_INT, GL_TRUE, 1, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32_FLOAT, &CopyTo32FVertexData); + AddVertexFormatInfo(&map, GL_UNSIGNED_INT, GL_TRUE, 2, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32_FLOAT, &CopyTo32FVertexData); + AddVertexFormatInfo(&map, GL_UNSIGNED_INT, GL_TRUE, 3, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32_FLOAT, &CopyTo32FVertexData); + AddVertexFormatInfo(&map, GL_UNSIGNED_INT, GL_TRUE, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32B32A32_FLOAT, &CopyTo32FVertexData); + + // GL_FIXED + AddVertexFormatInfo(&map, GL_FIXED, GL_FALSE, 1, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32_FLOAT, &Copy32FixedTo32FVertexData<1, 1>); + AddVertexFormatInfo(&map, GL_FIXED, GL_FALSE, 2, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32_FLOAT, &Copy32FixedTo32FVertexData<2, 2>); + AddVertexFormatInfo(&map, GL_FIXED, GL_FALSE, 3, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32_FLOAT, &Copy32FixedTo32FVertexData<3, 3>); + AddVertexFormatInfo(&map, GL_FIXED, GL_FALSE, 4, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32A32_FLOAT, &Copy32FixedTo32FVertexData<4, 4>); + + // GL_HALF_FLOAT + AddVertexFormatInfo(&map, GL_HALF_FLOAT, GL_FALSE, 1, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16_FLOAT, &CopyNativeVertexData); + AddVertexFormatInfo(&map, GL_HALF_FLOAT, GL_FALSE, 2, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16_FLOAT, &CopyNativeVertexData); + AddVertexFormatInfo(&map, GL_HALF_FLOAT, GL_FALSE, 3, VERTEX_CONVERT_CPU, DXGI_FORMAT_R16G16B16A16_FLOAT, &CopyNativeVertexData); + AddVertexFormatInfo(&map, GL_HALF_FLOAT, GL_FALSE, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16B16A16_FLOAT, &CopyNativeVertexData); + + // GL_FLOAT + AddVertexFormatInfo(&map, GL_FLOAT, GL_FALSE, 1, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32_FLOAT, &CopyNativeVertexData); + AddVertexFormatInfo(&map, GL_FLOAT, GL_FALSE, 2, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32_FLOAT, &CopyNativeVertexData); + AddVertexFormatInfo(&map, GL_FLOAT, GL_FALSE, 3, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32B32_FLOAT, &CopyNativeVertexData); + AddVertexFormatInfo(&map, GL_FLOAT, GL_FALSE, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32B32A32_FLOAT, &CopyNativeVertexData); + + // GL_INT_2_10_10_10_REV + AddVertexFormatInfo(&map, GL_INT_2_10_10_10_REV, GL_FALSE, 4, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32A32_FLOAT, &CopyXYZ10W2ToXYZW32FVertexData); + AddVertexFormatInfo(&map, GL_INT_2_10_10_10_REV, GL_TRUE, 4, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32A32_FLOAT, &CopyXYZ10W2ToXYZW32FVertexData); + + // GL_UNSIGNED_INT_2_10_10_10_REV + AddVertexFormatInfo(&map, GL_UNSIGNED_INT_2_10_10_10_REV, GL_FALSE, 4, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32A32_FLOAT, &CopyXYZ10W2ToXYZW32FVertexData); + AddVertexFormatInfo(&map, GL_UNSIGNED_INT_2_10_10_10_REV, GL_TRUE, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R10G10B10A2_UNORM, &CopyNativeVertexData); + + // + // Integer Formats + // + + // GL_BYTE + AddIntegerVertexFormatInfo(&map, GL_BYTE, 1, VERTEX_CONVERT_NONE, DXGI_FORMAT_R8_SINT, &CopyNativeVertexData); + AddIntegerVertexFormatInfo(&map, GL_BYTE, 2, VERTEX_CONVERT_NONE, DXGI_FORMAT_R8G8_SINT, &CopyNativeVertexData); + AddIntegerVertexFormatInfo(&map, GL_BYTE, 3, VERTEX_CONVERT_CPU, DXGI_FORMAT_R8G8B8A8_SINT, &CopyNativeVertexData); + AddIntegerVertexFormatInfo(&map, GL_BYTE, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R8G8B8A8_SINT, &CopyNativeVertexData); + + // GL_UNSIGNED_BYTE + AddIntegerVertexFormatInfo(&map, GL_UNSIGNED_BYTE, 1, VERTEX_CONVERT_NONE, DXGI_FORMAT_R8_UINT, &CopyNativeVertexData); + AddIntegerVertexFormatInfo(&map, GL_UNSIGNED_BYTE, 2, VERTEX_CONVERT_NONE, DXGI_FORMAT_R8G8_UINT, &CopyNativeVertexData); + AddIntegerVertexFormatInfo(&map, GL_UNSIGNED_BYTE, 3, VERTEX_CONVERT_CPU, DXGI_FORMAT_R8G8B8A8_UINT, &CopyNativeVertexData); + AddIntegerVertexFormatInfo(&map, GL_UNSIGNED_BYTE, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R8G8B8A8_UINT, &CopyNativeVertexData); + + // GL_SHORT + AddIntegerVertexFormatInfo(&map, GL_SHORT, 1, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16_SINT, &CopyNativeVertexData); + AddIntegerVertexFormatInfo(&map, GL_SHORT, 2, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16_SINT, &CopyNativeVertexData); + AddIntegerVertexFormatInfo(&map, GL_SHORT, 3, VERTEX_CONVERT_CPU, DXGI_FORMAT_R16G16B16A16_SINT, &CopyNativeVertexData); + AddIntegerVertexFormatInfo(&map, GL_SHORT, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16B16A16_SINT, &CopyNativeVertexData); + + // GL_UNSIGNED_SHORT + AddIntegerVertexFormatInfo(&map, GL_UNSIGNED_SHORT, 1, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16_UINT, &CopyNativeVertexData); + AddIntegerVertexFormatInfo(&map, GL_UNSIGNED_SHORT, 2, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16_UINT, &CopyNativeVertexData); + AddIntegerVertexFormatInfo(&map, GL_UNSIGNED_SHORT, 3, VERTEX_CONVERT_CPU, DXGI_FORMAT_R16G16B16A16_UINT, &CopyNativeVertexData); + AddIntegerVertexFormatInfo(&map, GL_UNSIGNED_SHORT, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16B16A16_UINT, &CopyNativeVertexData); + + // GL_INT + AddIntegerVertexFormatInfo(&map, GL_INT, 1, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32_SINT, &CopyNativeVertexData); + AddIntegerVertexFormatInfo(&map, GL_INT, 2, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32_SINT, &CopyNativeVertexData); + AddIntegerVertexFormatInfo(&map, GL_INT, 3, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32B32_SINT, &CopyNativeVertexData); + AddIntegerVertexFormatInfo(&map, GL_INT, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32B32A32_SINT, &CopyNativeVertexData); + + // GL_UNSIGNED_INT + AddIntegerVertexFormatInfo(&map, GL_UNSIGNED_INT, 1, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32_SINT, &CopyNativeVertexData); + AddIntegerVertexFormatInfo(&map, GL_UNSIGNED_INT, 2, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32_SINT, &CopyNativeVertexData); + AddIntegerVertexFormatInfo(&map, GL_UNSIGNED_INT, 3, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32B32_SINT, &CopyNativeVertexData); + AddIntegerVertexFormatInfo(&map, GL_UNSIGNED_INT, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32B32A32_SINT, &CopyNativeVertexData); + + // GL_INT_2_10_10_10_REV + AddIntegerVertexFormatInfo(&map, GL_INT_2_10_10_10_REV, 4, VERTEX_CONVERT_CPU, DXGI_FORMAT_R16G16B16A16_SINT, &CopyXYZ10W2ToXYZW32FVertexData); + + // GL_UNSIGNED_INT_2_10_10_10_REV + AddIntegerVertexFormatInfo(&map, GL_UNSIGNED_INT_2_10_10_10_REV, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R10G10B10A2_UINT, &CopyNativeVertexData); + + return map; +} + +const VertexFormat &GetVertexFormatInfo(const gl::VertexFormat &vertexFormat, D3D_FEATURE_LEVEL featureLevel) +{ + static const D3D11VertexFormatInfoMap vertexFormatMap = BuildD3D11VertexFormatInfoMap(); + static const D3D11VertexFormatInfoMap vertexFormatMapFL9_3Override = BuildD3D11_FL9_3VertexFormatInfoOverrideMap(); + + if (featureLevel == D3D_FEATURE_LEVEL_9_3) + { + // First see if the format has a special mapping for FL9_3 + D3D11VertexFormatInfoMap::const_iterator iter = vertexFormatMapFL9_3Override.find(vertexFormat); + if (iter != vertexFormatMapFL9_3Override.end()) + { + return iter->second; + } + } + + D3D11VertexFormatInfoMap::const_iterator iter = vertexFormatMap.find(vertexFormat); + if (iter != vertexFormatMap.end()) + { + return iter->second; + } + else + { + static const VertexFormat defaultInfo; + return defaultInfo; + } +} + +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/formatutils11.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/formatutils11.h new file mode 100644 index 0000000000..33fe29dc39 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/formatutils11.h @@ -0,0 +1,93 @@ +// +// Copyright (c) 2013-2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// formatutils11.h: Queries for GL image formats and their translations to D3D11 +// formats. + +#ifndef LIBANGLE_RENDERER_D3D_D3D11_FORMATUTILS11_H_ +#define LIBANGLE_RENDERER_D3D_D3D11_FORMATUTILS11_H_ + +#include "libANGLE/renderer/d3d/formatutilsD3D.h" +#include "libANGLE/angletypes.h" + +#include "common/platform.h" + +#include + +namespace rx +{ + +namespace d3d11 +{ + +typedef std::map, ColorCopyFunction> FastCopyFunctionMap; + +struct DXGIFormat +{ + DXGIFormat(); + + GLuint pixelBytes; + GLuint blockWidth; + GLuint blockHeight; + + GLuint redBits; + GLuint greenBits; + GLuint blueBits; + GLuint alphaBits; + GLuint sharedBits; + + GLuint depthBits; + GLuint depthOffset; + GLuint stencilBits; + GLuint stencilOffset; + + GLenum internalFormat; + GLenum componentType; + + MipGenerationFunction mipGenerationFunction; + ColorReadFunction colorReadFunction; + + FastCopyFunctionMap fastCopyFunctions; + ColorCopyFunction getFastCopyFunction(GLenum format, GLenum type) const; +}; +const DXGIFormat &GetDXGIFormatInfo(DXGI_FORMAT format); + +struct TextureFormat +{ + TextureFormat(); + + DXGI_FORMAT texFormat; + DXGI_FORMAT srvFormat; + DXGI_FORMAT rtvFormat; + DXGI_FORMAT dsvFormat; + DXGI_FORMAT renderFormat; + + DXGI_FORMAT swizzleTexFormat; + DXGI_FORMAT swizzleSRVFormat; + DXGI_FORMAT swizzleRTVFormat; + + InitializeTextureDataFunction dataInitializerFunction; + + typedef std::map LoadFunctionMap; + LoadFunctionMap loadFunctions; +}; +const TextureFormat &GetTextureFormatInfo(GLenum internalFormat, D3D_FEATURE_LEVEL featureLevel); + +struct VertexFormat +{ + VertexFormat(); + + VertexConversionType conversionType; + DXGI_FORMAT nativeFormat; + VertexCopyFunction copyFunction; +}; +const VertexFormat &GetVertexFormatInfo(const gl::VertexFormat &vertexFormat, D3D_FEATURE_LEVEL featureLevel); + +} + +} + +#endif // LIBANGLE_RENDERER_D3D_D3D11_FORMATUTILS11_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.cpp new file mode 100644 index 0000000000..63085f497f --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.cpp @@ -0,0 +1,1378 @@ +// +// Copyright (c) 2012-2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// renderer11_utils.cpp: Conversion functions and other utility routines +// specific to the D3D11 renderer. + +#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h" +#include "libANGLE/renderer/d3d/d3d11/formatutils11.h" +#include "libANGLE/renderer/d3d/d3d11/RenderTarget11.h" +#include "libANGLE/renderer/d3d/FramebufferD3D.h" +#include "libANGLE/renderer/Workarounds.h" +#include "libANGLE/formatutils.h" +#include "libANGLE/Program.h" +#include "libANGLE/Framebuffer.h" + +#include "common/debug.h" + +#include + +#ifndef D3D_FL9_1_DEFAULT_MAX_ANISOTROPY +# define D3D_FL9_1_DEFAULT_MAX_ANISOTROPY 2 +#endif +#ifndef D3D_FL9_1_SIMULTANEOUS_RENDER_TARGET_COUNT +# define D3D_FL9_1_SIMULTANEOUS_RENDER_TARGET_COUNT 1 +#endif +#ifndef D3D_FL9_3_SIMULTANEOUS_RENDER_TARGET_COUNT +# define D3D_FL9_3_SIMULTANEOUS_RENDER_TARGET_COUNT 4 +#endif +#ifndef D3D_FL9_1_IA_PRIMITIVE_MAX_COUNT +# define D3D_FL9_1_IA_PRIMITIVE_MAX_COUNT 65535 +#endif +#ifndef D3D_FL9_2_IA_PRIMITIVE_MAX_COUNT +# define D3D_FL9_2_IA_PRIMITIVE_MAX_COUNT 1048575 +#endif +#ifndef D3D_FL9_1_REQ_TEXTURECUBE_DIMENSION +# define D3D_FL9_1_REQ_TEXTURECUBE_DIMENSION 512 +#endif +#ifndef D3D_FL9_3_REQ_TEXTURECUBE_DIMENSION +# define D3D_FL9_3_REQ_TEXTURECUBE_DIMENSION 4096 +#endif +#ifndef D3D_FL9_1_REQ_TEXTURE2D_U_OR_V_DIMENSION +# define D3D_FL9_1_REQ_TEXTURE2D_U_OR_V_DIMENSION 2048 +#endif +#ifndef D3D_FL9_1_REQ_TEXTURE3D_U_V_OR_W_DIMENSION +# define D3D_FL9_1_REQ_TEXTURE3D_U_V_OR_W_DIMENSION 256 +#endif +#ifndef D3D_FL9_3_REQ_TEXTURE2D_U_OR_V_DIMENSION +# define D3D_FL9_3_REQ_TEXTURE2D_U_OR_V_DIMENSION 4096 +#endif +#ifndef D3D11_REQ_TEXTURECUBE_DIMENSION +# define D3D11_REQ_TEXTURECUBE_DIMENSION 16384 +#endif +#ifndef D3D11_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION +# define D3D11_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION 2048 +#endif +#ifndef D3D11_REQ_TEXTURE3D_U_V_OR_W_DIMENSION +# define D3D11_REQ_TEXTURE3D_U_V_OR_W_DIMENSION 2048 +#endif +#ifndef D3D11_REQ_DRAWINDEXED_INDEX_COUNT_2_TO_EXP +# define D3D11_REQ_DRAWINDEXED_INDEX_COUNT_2_TO_EXP 32 +#endif +#ifndef D3D11_REQ_DRAW_VERTEX_COUNT_2_TO_EXP +# define D3D11_REQ_DRAW_VERTEX_COUNT_2_TO_EXP 32 +#endif +#ifndef D3D10_1_STANDARD_VERTEX_ELEMENT_COUNT +# define D3D10_1_STANDARD_VERTEX_ELEMENT_COUNT 32 +#endif +#ifndef D3D11_STANDARD_VERTEX_ELEMENT_COUNT +# define D3D11_STANDARD_VERTEX_ELEMENT_COUNT 32 +#endif +#ifndef D3D10_1_SO_BUFFER_SLOT_COUNT +# define D3D10_1_SO_BUFFER_SLOT_COUNT 4 +#endif +#ifndef D3D11_SO_BUFFER_SLOT_COUNT +# define D3D11_SO_BUFFER_SLOT_COUNT 4 +#endif +#ifndef D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT +# define D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT 14 +#endif +#ifndef D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT +# define D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT 16 +#endif +#ifndef D3D11_COMMONSHADER_TEXEL_OFFSET_MAX_NEGATIVE +# define D3D11_COMMONSHADER_TEXEL_OFFSET_MAX_NEGATIVE -8 +#endif +#ifndef D3D11_COMMONSHADER_TEXEL_OFFSET_MAX_POSITIVE +# define D3D11_COMMONSHADER_TEXEL_OFFSET_MAX_POSITIVE 7 +#endif +#ifndef D3D11_REQ_CONSTANT_BUFFER_ELEMENT_COUNT +# define D3D11_REQ_CONSTANT_BUFFER_ELEMENT_COUNT 4096 +#endif +#ifndef D3D11_PS_INPUT_REGISTER_COUNT +# define D3D11_PS_INPUT_REGISTER_COUNT 32 +#endif +#ifndef D3D10_1_VS_OUTPUT_REGISTER_COUNT +# define D3D10_1_VS_OUTPUT_REGISTER_COUNT 32 +#endif +#if defined(ANGLE_MINGW32_COMPAT) +static const IID WKPDID_D3DDebugObjectName = { 0x429b8c22, 0x9188, 0x4b0c, 0x87, 0x42, 0xac, 0xb0, 0xbf, 0x85, 0xc2, 0x00 }; +#endif + +namespace rx +{ + +namespace gl_d3d11 +{ + +D3D11_BLEND ConvertBlendFunc(GLenum glBlend, bool isAlpha) +{ + D3D11_BLEND d3dBlend = D3D11_BLEND_ZERO; + + switch (glBlend) + { + case GL_ZERO: d3dBlend = D3D11_BLEND_ZERO; break; + case GL_ONE: d3dBlend = D3D11_BLEND_ONE; break; + case GL_SRC_COLOR: d3dBlend = (isAlpha ? D3D11_BLEND_SRC_ALPHA : D3D11_BLEND_SRC_COLOR); break; + case GL_ONE_MINUS_SRC_COLOR: d3dBlend = (isAlpha ? D3D11_BLEND_INV_SRC_ALPHA : D3D11_BLEND_INV_SRC_COLOR); break; + case GL_DST_COLOR: d3dBlend = (isAlpha ? D3D11_BLEND_DEST_ALPHA : D3D11_BLEND_DEST_COLOR); break; + case GL_ONE_MINUS_DST_COLOR: d3dBlend = (isAlpha ? D3D11_BLEND_INV_DEST_ALPHA : D3D11_BLEND_INV_DEST_COLOR); break; + case GL_SRC_ALPHA: d3dBlend = D3D11_BLEND_SRC_ALPHA; break; + case GL_ONE_MINUS_SRC_ALPHA: d3dBlend = D3D11_BLEND_INV_SRC_ALPHA; break; + case GL_DST_ALPHA: d3dBlend = D3D11_BLEND_DEST_ALPHA; break; + case GL_ONE_MINUS_DST_ALPHA: d3dBlend = D3D11_BLEND_INV_DEST_ALPHA; break; + case GL_CONSTANT_COLOR: d3dBlend = D3D11_BLEND_BLEND_FACTOR; break; + case GL_ONE_MINUS_CONSTANT_COLOR: d3dBlend = D3D11_BLEND_INV_BLEND_FACTOR; break; + case GL_CONSTANT_ALPHA: d3dBlend = D3D11_BLEND_BLEND_FACTOR; break; + case GL_ONE_MINUS_CONSTANT_ALPHA: d3dBlend = D3D11_BLEND_INV_BLEND_FACTOR; break; + case GL_SRC_ALPHA_SATURATE: d3dBlend = D3D11_BLEND_SRC_ALPHA_SAT; break; + default: UNREACHABLE(); + } + + return d3dBlend; +} + +D3D11_BLEND_OP ConvertBlendOp(GLenum glBlendOp) +{ + D3D11_BLEND_OP d3dBlendOp = D3D11_BLEND_OP_ADD; + + switch (glBlendOp) + { + case GL_FUNC_ADD: d3dBlendOp = D3D11_BLEND_OP_ADD; break; + case GL_FUNC_SUBTRACT: d3dBlendOp = D3D11_BLEND_OP_SUBTRACT; break; + case GL_FUNC_REVERSE_SUBTRACT: d3dBlendOp = D3D11_BLEND_OP_REV_SUBTRACT; break; + case GL_MIN: d3dBlendOp = D3D11_BLEND_OP_MIN; break; + case GL_MAX: d3dBlendOp = D3D11_BLEND_OP_MAX; break; + default: UNREACHABLE(); + } + + return d3dBlendOp; +} + +UINT8 ConvertColorMask(bool red, bool green, bool blue, bool alpha) +{ + UINT8 mask = 0; + if (red) + { + mask |= D3D11_COLOR_WRITE_ENABLE_RED; + } + if (green) + { + mask |= D3D11_COLOR_WRITE_ENABLE_GREEN; + } + if (blue) + { + mask |= D3D11_COLOR_WRITE_ENABLE_BLUE; + } + if (alpha) + { + mask |= D3D11_COLOR_WRITE_ENABLE_ALPHA; + } + return mask; +} + +D3D11_CULL_MODE ConvertCullMode(bool cullEnabled, GLenum cullMode) +{ + D3D11_CULL_MODE cull = D3D11_CULL_NONE; + + if (cullEnabled) + { + switch (cullMode) + { + case GL_FRONT: cull = D3D11_CULL_FRONT; break; + case GL_BACK: cull = D3D11_CULL_BACK; break; + case GL_FRONT_AND_BACK: cull = D3D11_CULL_NONE; break; + default: UNREACHABLE(); + } + } + else + { + cull = D3D11_CULL_NONE; + } + + return cull; +} + +D3D11_COMPARISON_FUNC ConvertComparison(GLenum comparison) +{ + D3D11_COMPARISON_FUNC d3dComp = D3D11_COMPARISON_NEVER; + switch (comparison) + { + case GL_NEVER: d3dComp = D3D11_COMPARISON_NEVER; break; + case GL_ALWAYS: d3dComp = D3D11_COMPARISON_ALWAYS; break; + case GL_LESS: d3dComp = D3D11_COMPARISON_LESS; break; + case GL_LEQUAL: d3dComp = D3D11_COMPARISON_LESS_EQUAL; break; + case GL_EQUAL: d3dComp = D3D11_COMPARISON_EQUAL; break; + case GL_GREATER: d3dComp = D3D11_COMPARISON_GREATER; break; + case GL_GEQUAL: d3dComp = D3D11_COMPARISON_GREATER_EQUAL; break; + case GL_NOTEQUAL: d3dComp = D3D11_COMPARISON_NOT_EQUAL; break; + default: UNREACHABLE(); + } + + return d3dComp; +} + +D3D11_DEPTH_WRITE_MASK ConvertDepthMask(bool depthWriteEnabled) +{ + return depthWriteEnabled ? D3D11_DEPTH_WRITE_MASK_ALL : D3D11_DEPTH_WRITE_MASK_ZERO; +} + +UINT8 ConvertStencilMask(GLuint stencilmask) +{ + return static_cast(stencilmask); +} + +D3D11_STENCIL_OP ConvertStencilOp(GLenum stencilOp) +{ + D3D11_STENCIL_OP d3dStencilOp = D3D11_STENCIL_OP_KEEP; + + switch (stencilOp) + { + case GL_ZERO: d3dStencilOp = D3D11_STENCIL_OP_ZERO; break; + case GL_KEEP: d3dStencilOp = D3D11_STENCIL_OP_KEEP; break; + case GL_REPLACE: d3dStencilOp = D3D11_STENCIL_OP_REPLACE; break; + case GL_INCR: d3dStencilOp = D3D11_STENCIL_OP_INCR_SAT; break; + case GL_DECR: d3dStencilOp = D3D11_STENCIL_OP_DECR_SAT; break; + case GL_INVERT: d3dStencilOp = D3D11_STENCIL_OP_INVERT; break; + case GL_INCR_WRAP: d3dStencilOp = D3D11_STENCIL_OP_INCR; break; + case GL_DECR_WRAP: d3dStencilOp = D3D11_STENCIL_OP_DECR; break; + default: UNREACHABLE(); + } + + return d3dStencilOp; +} + +D3D11_FILTER ConvertFilter(GLenum minFilter, GLenum magFilter, float maxAnisotropy, GLenum comparisonMode) +{ + bool comparison = comparisonMode != GL_NONE; + + if (maxAnisotropy > 1.0f) + { + return D3D11_ENCODE_ANISOTROPIC_FILTER(static_cast(comparison)); + } + else + { + D3D11_FILTER_TYPE dxMin = D3D11_FILTER_TYPE_POINT; + D3D11_FILTER_TYPE dxMip = D3D11_FILTER_TYPE_POINT; + switch (minFilter) + { + case GL_NEAREST: dxMin = D3D11_FILTER_TYPE_POINT; dxMip = D3D11_FILTER_TYPE_POINT; break; + case GL_LINEAR: dxMin = D3D11_FILTER_TYPE_LINEAR; dxMip = D3D11_FILTER_TYPE_POINT; break; + case GL_NEAREST_MIPMAP_NEAREST: dxMin = D3D11_FILTER_TYPE_POINT; dxMip = D3D11_FILTER_TYPE_POINT; break; + case GL_LINEAR_MIPMAP_NEAREST: dxMin = D3D11_FILTER_TYPE_LINEAR; dxMip = D3D11_FILTER_TYPE_POINT; break; + case GL_NEAREST_MIPMAP_LINEAR: dxMin = D3D11_FILTER_TYPE_POINT; dxMip = D3D11_FILTER_TYPE_LINEAR; break; + case GL_LINEAR_MIPMAP_LINEAR: dxMin = D3D11_FILTER_TYPE_LINEAR; dxMip = D3D11_FILTER_TYPE_LINEAR; break; + default: UNREACHABLE(); + } + + D3D11_FILTER_TYPE dxMag = D3D11_FILTER_TYPE_POINT; + switch (magFilter) + { + case GL_NEAREST: dxMag = D3D11_FILTER_TYPE_POINT; break; + case GL_LINEAR: dxMag = D3D11_FILTER_TYPE_LINEAR; break; + default: UNREACHABLE(); + } + + return D3D11_ENCODE_BASIC_FILTER(dxMin, dxMag, dxMip, static_cast(comparison)); + } +} + +D3D11_TEXTURE_ADDRESS_MODE ConvertTextureWrap(GLenum wrap) +{ + switch (wrap) + { + case GL_REPEAT: return D3D11_TEXTURE_ADDRESS_WRAP; + case GL_CLAMP_TO_EDGE: return D3D11_TEXTURE_ADDRESS_CLAMP; + case GL_MIRRORED_REPEAT: return D3D11_TEXTURE_ADDRESS_MIRROR; + default: UNREACHABLE(); + } + + return D3D11_TEXTURE_ADDRESS_WRAP; +} + +D3D11_QUERY ConvertQueryType(GLenum queryType) +{ + switch (queryType) + { + case GL_ANY_SAMPLES_PASSED_EXT: + case GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT: return D3D11_QUERY_OCCLUSION; + case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN: return D3D11_QUERY_SO_STATISTICS; + default: UNREACHABLE(); return D3D11_QUERY_EVENT; + } +} + +} + + +namespace d3d11_gl +{ + +GLint GetMaximumClientVersion(D3D_FEATURE_LEVEL featureLevel) +{ + switch (featureLevel) + { +#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: +#endif + case D3D_FEATURE_LEVEL_11_0: + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: return 3; + + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: return 2; + + default: UNREACHABLE(); return 0; + } +} + +static gl::TextureCaps GenerateTextureFormatCaps(GLint maxClientVersion, GLenum internalFormat, ID3D11Device *device) +{ + gl::TextureCaps textureCaps; + + const d3d11::TextureFormat &formatInfo = d3d11::GetTextureFormatInfo(internalFormat, device->GetFeatureLevel()); + + UINT formatSupport; + if (SUCCEEDED(device->CheckFormatSupport(formatInfo.texFormat, &formatSupport))) + { + const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(internalFormat); + if (internalFormatInfo.depthBits > 0 || internalFormatInfo.stencilBits > 0) + { + textureCaps.texturable = ((formatSupport & D3D11_FORMAT_SUPPORT_TEXTURE2D) != 0); + } + else + { + UINT formatSupportMask = D3D11_FORMAT_SUPPORT_TEXTURE2D | D3D11_FORMAT_SUPPORT_TEXTURECUBE; + if (maxClientVersion > 2) + { + formatSupportMask |= D3D11_FORMAT_SUPPORT_TEXTURE3D; + } + textureCaps.texturable = ((formatSupport & formatSupportMask) == formatSupportMask); + } + } + + if (SUCCEEDED(device->CheckFormatSupport(formatInfo.renderFormat, &formatSupport)) && + ((formatSupport & D3D11_FORMAT_SUPPORT_MULTISAMPLE_RENDERTARGET) != 0)) + { + for (size_t sampleCount = 1; sampleCount <= D3D11_MAX_MULTISAMPLE_SAMPLE_COUNT; sampleCount++) + { + UINT qualityCount = 0; + if (SUCCEEDED(device->CheckMultisampleQualityLevels(formatInfo.renderFormat, sampleCount, &qualityCount)) && + qualityCount > 0) + { + textureCaps.sampleCounts.insert(sampleCount); + } + } + } + + textureCaps.filterable = SUCCEEDED(device->CheckFormatSupport(formatInfo.srvFormat, &formatSupport)) && + ((formatSupport & D3D11_FORMAT_SUPPORT_SHADER_SAMPLE)) != 0; + textureCaps.renderable = (SUCCEEDED(device->CheckFormatSupport(formatInfo.rtvFormat, &formatSupport)) && + ((formatSupport & D3D11_FORMAT_SUPPORT_RENDER_TARGET)) != 0) || + (SUCCEEDED(device->CheckFormatSupport(formatInfo.dsvFormat, &formatSupport)) && + ((formatSupport & D3D11_FORMAT_SUPPORT_DEPTH_STENCIL) != 0)); + + return textureCaps; +} + +static bool GetNPOTTextureSupport(D3D_FEATURE_LEVEL featureLevel) +{ + switch (featureLevel) + { +#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: +#endif + case D3D_FEATURE_LEVEL_11_0: + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: return true; + + // From http://msdn.microsoft.com/en-us/library/windows/desktop/ff476876.aspx + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: return false; + + default: UNREACHABLE(); return false; + } +} + +static float GetMaximumAnisotropy(D3D_FEATURE_LEVEL featureLevel) +{ + switch (featureLevel) + { +#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: +#endif + case D3D_FEATURE_LEVEL_11_0: return D3D11_MAX_MAXANISOTROPY; + + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: return D3D10_MAX_MAXANISOTROPY; + + // From http://msdn.microsoft.com/en-us/library/windows/desktop/ff476876.aspx + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: return 16; + + case D3D_FEATURE_LEVEL_9_1: return D3D_FL9_1_DEFAULT_MAX_ANISOTROPY; + + default: UNREACHABLE(); return 0; + } +} + +static bool GetOcclusionQuerySupport(D3D_FEATURE_LEVEL featureLevel) +{ + switch (featureLevel) + { +#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: +#endif + case D3D_FEATURE_LEVEL_11_0: + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: return true; + + // From http://msdn.microsoft.com/en-us/library/windows/desktop/ff476150.aspx ID3D11Device::CreateQuery + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: return true; + case D3D_FEATURE_LEVEL_9_1: return false; + + default: UNREACHABLE(); return false; + } +} + +static bool GetEventQuerySupport(D3D_FEATURE_LEVEL featureLevel) +{ + // From http://msdn.microsoft.com/en-us/library/windows/desktop/ff476150.aspx ID3D11Device::CreateQuery + + switch (featureLevel) + { +#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: +#endif + case D3D_FEATURE_LEVEL_11_0: + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: return true; + + default: UNREACHABLE(); return false; + } +} + +static bool GetInstancingSupport(D3D_FEATURE_LEVEL featureLevel) +{ + // From http://msdn.microsoft.com/en-us/library/windows/desktop/ff476150.aspx ID3D11Device::CreateInputLayout + + switch (featureLevel) + { +#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: +#endif + case D3D_FEATURE_LEVEL_11_0: + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: return true; + + // Feature Level 9_3 supports instancing, but slot 0 in the input layout must not be instanced. + // D3D9 has a similar restriction, where stream 0 must not be instanced. + // This restriction can be worked around by remapping any non-instanced slot to slot 0. + // This works because HLSL uses shader semantics to match the vertex inputs to the elements in the input layout, rather than the slots. + // Note that we only support instancing via ANGLE_instanced_array on 9_3, since 9_3 doesn't support OpenGL ES 3.0 + case D3D_FEATURE_LEVEL_9_3: return true; + + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: return false; + + default: UNREACHABLE(); return false; + } +} + +static bool GetFramebufferMultisampleSupport(D3D_FEATURE_LEVEL featureLevel) +{ + switch (featureLevel) + { +#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: +#endif + case D3D_FEATURE_LEVEL_11_0: + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: return true; + + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: return false; + + default: UNREACHABLE(); return false; + } +} + +static bool GetFramebufferBlitSupport(D3D_FEATURE_LEVEL featureLevel) +{ + switch (featureLevel) + { +#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: +#endif + case D3D_FEATURE_LEVEL_11_0: + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: return true; + + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: return false; + + default: UNREACHABLE(); return false; + } +} + +static bool GetDerivativeInstructionSupport(D3D_FEATURE_LEVEL featureLevel) +{ + // http://msdn.microsoft.com/en-us/library/windows/desktop/bb509588.aspx states that shader model + // ps_2_x is required for the ddx (and other derivative functions). + + // http://msdn.microsoft.com/en-us/library/windows/desktop/ff476876.aspx states that feature level + // 9.3 supports shader model ps_2_x. + + switch (featureLevel) + { +#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: +#endif + case D3D_FEATURE_LEVEL_11_0: + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: + case D3D_FEATURE_LEVEL_9_3: return true; + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: return false; + + default: UNREACHABLE(); return false; + } +} + +static bool GetShaderTextureLODSupport(D3D_FEATURE_LEVEL featureLevel) +{ + switch (featureLevel) + { +#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: +#endif + case D3D_FEATURE_LEVEL_11_0: + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: return true; + + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: return false; + + default: UNREACHABLE(); return false; + } +} + +static size_t GetMaximumSimultaneousRenderTargets(D3D_FEATURE_LEVEL featureLevel) +{ + // From http://msdn.microsoft.com/en-us/library/windows/desktop/ff476150.aspx ID3D11Device::CreateInputLayout + + switch (featureLevel) + { +#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: +#endif + case D3D_FEATURE_LEVEL_11_0: return D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; + + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: return D3D10_SIMULTANEOUS_RENDER_TARGET_COUNT; + + case D3D_FEATURE_LEVEL_9_3: return D3D_FL9_3_SIMULTANEOUS_RENDER_TARGET_COUNT; + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: return D3D_FL9_1_SIMULTANEOUS_RENDER_TARGET_COUNT; + + default: UNREACHABLE(); return 0; + } +} + +static size_t GetMaximum2DTextureSize(D3D_FEATURE_LEVEL featureLevel) +{ + switch (featureLevel) + { +#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: +#endif + case D3D_FEATURE_LEVEL_11_0: return D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION; + + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: return D3D10_REQ_TEXTURE2D_U_OR_V_DIMENSION; + + case D3D_FEATURE_LEVEL_9_3: return D3D_FL9_3_REQ_TEXTURE2D_U_OR_V_DIMENSION; + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: return D3D_FL9_1_REQ_TEXTURE2D_U_OR_V_DIMENSION; + + default: UNREACHABLE(); return 0; + } +} + +static size_t GetMaximumCubeMapTextureSize(D3D_FEATURE_LEVEL featureLevel) +{ + switch (featureLevel) + { +#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: +#endif + case D3D_FEATURE_LEVEL_11_0: return D3D11_REQ_TEXTURECUBE_DIMENSION; + + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: return D3D10_REQ_TEXTURECUBE_DIMENSION; + + case D3D_FEATURE_LEVEL_9_3: return D3D_FL9_3_REQ_TEXTURECUBE_DIMENSION; + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: return D3D_FL9_1_REQ_TEXTURECUBE_DIMENSION; + + default: UNREACHABLE(); return 0; + } +} + +static size_t GetMaximum2DTextureArraySize(D3D_FEATURE_LEVEL featureLevel) +{ + switch (featureLevel) + { +#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: +#endif + case D3D_FEATURE_LEVEL_11_0: return D3D11_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION; + + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: return D3D10_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION; + + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: return 0; + + default: UNREACHABLE(); return 0; + } +} + +static size_t GetMaximum3DTextureSize(D3D_FEATURE_LEVEL featureLevel) +{ + switch (featureLevel) + { +#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: +#endif + case D3D_FEATURE_LEVEL_11_0: return D3D11_REQ_TEXTURE3D_U_V_OR_W_DIMENSION; + + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: return D3D10_REQ_TEXTURE3D_U_V_OR_W_DIMENSION; + + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: return D3D_FL9_1_REQ_TEXTURE3D_U_V_OR_W_DIMENSION; + + default: UNREACHABLE(); return 0; + } +} + +static size_t GetMaximumViewportSize(D3D_FEATURE_LEVEL featureLevel) +{ + switch (featureLevel) + { +#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: +#endif + case D3D_FEATURE_LEVEL_11_0: return D3D11_VIEWPORT_BOUNDS_MAX; + + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: return D3D10_VIEWPORT_BOUNDS_MAX; + + // No constants for D3D11 Feature Level 9 viewport size limits, use the maximum texture sizes + case D3D_FEATURE_LEVEL_9_3: return D3D_FL9_3_REQ_TEXTURE2D_U_OR_V_DIMENSION; + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: return D3D_FL9_1_REQ_TEXTURE2D_U_OR_V_DIMENSION; + + default: UNREACHABLE(); return 0; + } +} + +static size_t GetMaximumDrawIndexedIndexCount(D3D_FEATURE_LEVEL featureLevel) +{ + // D3D11 allows up to 2^32 elements, but we report max signed int for convenience since that's what's + // returned from glGetInteger + static_assert(D3D11_REQ_DRAWINDEXED_INDEX_COUNT_2_TO_EXP == 32, "Unexpected D3D11 constant value."); + static_assert(D3D10_REQ_DRAWINDEXED_INDEX_COUNT_2_TO_EXP == 32, "Unexpected D3D11 constant value."); + + switch (featureLevel) + { +#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: +#endif + case D3D_FEATURE_LEVEL_11_0: + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: return std::numeric_limits::max(); + + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: return D3D_FL9_2_IA_PRIMITIVE_MAX_COUNT; + case D3D_FEATURE_LEVEL_9_1: return D3D_FL9_1_IA_PRIMITIVE_MAX_COUNT; + + default: UNREACHABLE(); return 0; + } +} + +static size_t GetMaximumDrawVertexCount(D3D_FEATURE_LEVEL featureLevel) +{ + // D3D11 allows up to 2^32 elements, but we report max signed int for convenience since that's what's + // returned from glGetInteger + static_assert(D3D11_REQ_DRAW_VERTEX_COUNT_2_TO_EXP == 32, "Unexpected D3D11 constant value."); + static_assert(D3D10_REQ_DRAW_VERTEX_COUNT_2_TO_EXP == 32, "Unexpected D3D11 constant value."); + + switch (featureLevel) + { +#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: +#endif + case D3D_FEATURE_LEVEL_11_0: + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: return std::numeric_limits::max(); + + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: return D3D_FL9_2_IA_PRIMITIVE_MAX_COUNT; + case D3D_FEATURE_LEVEL_9_1: return D3D_FL9_1_IA_PRIMITIVE_MAX_COUNT; + + default: UNREACHABLE(); return 0; + } +} + +static size_t GetMaximumVertexInputSlots(D3D_FEATURE_LEVEL featureLevel) +{ + switch (featureLevel) + { +#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: +#endif + case D3D_FEATURE_LEVEL_11_0: return D3D11_STANDARD_VERTEX_ELEMENT_COUNT; + + case D3D_FEATURE_LEVEL_10_1: return D3D10_1_STANDARD_VERTEX_ELEMENT_COUNT; + case D3D_FEATURE_LEVEL_10_0: return D3D10_STANDARD_VERTEX_ELEMENT_COUNT; + + // From http://http://msdn.microsoft.com/en-us/library/windows/desktop/ff476876.aspx "Max Input Slots" + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: return 16; + + default: UNREACHABLE(); return 0; + } +} + +static size_t GetMaximumVertexUniformVectors(D3D_FEATURE_LEVEL featureLevel) +{ + // TODO(geofflang): Remove hard-coded limit once the gl-uniform-arrays test can pass + switch (featureLevel) + { +#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: +#endif + case D3D_FEATURE_LEVEL_11_0: return 1024; // D3D11_REQ_CONSTANT_BUFFER_ELEMENT_COUNT; + + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: return 1024; // D3D10_REQ_CONSTANT_BUFFER_ELEMENT_COUNT; + + // From http://msdn.microsoft.com/en-us/library/windows/desktop/ff476149.aspx ID3D11DeviceContext::VSSetConstantBuffers + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: return 255; + + default: UNREACHABLE(); return 0; + } +} + +static size_t GetReservedVertexUniformBuffers() +{ + // Reserve one buffer for the application uniforms, and one for driver uniforms + return 2; +} + +static size_t GetMaximumVertexUniformBlocks(D3D_FEATURE_LEVEL featureLevel) +{ + switch (featureLevel) + { +#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: +#endif + case D3D_FEATURE_LEVEL_11_0: return D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - GetReservedVertexUniformBuffers(); + + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: return D3D10_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - GetReservedVertexUniformBuffers(); + + // Uniform blocks not supported on D3D11 Feature Level 9 + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: return 0; + + default: UNREACHABLE(); return 0; + } +} + +static size_t GetReservedVertexOutputVectors(D3D_FEATURE_LEVEL featureLevel) +{ + // According to The OpenGL ES Shading Language specifications + // (Language Version 1.00 section 10.16, Language Version 3.10 section 12.21) + // built-in special variables (e.g. gl_FragCoord, or gl_PointCoord) + // which are statically used in the shader should be included in the variable packing algorithm. + // Therefore, we should not reserve output vectors for them. + + switch (featureLevel) + { + // We must reserve one output vector for dx_Position. + // We also reserve one for gl_Position, which we unconditionally output on Feature Levels 10_0+, + // even if it's unused in the shader (e.g. for transform feedback). TODO: This could be improved. +#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: +#endif + case D3D_FEATURE_LEVEL_11_0: + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: return 2; + + // Just reserve dx_Position on Feature Level 9, since we don't ever need to output gl_Position. + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: return 1; + + default: UNREACHABLE(); return 0; + } + + return 1; +} + +static size_t GetMaximumVertexOutputVectors(D3D_FEATURE_LEVEL featureLevel) +{ + static_assert(gl::IMPLEMENTATION_MAX_VARYING_VECTORS == D3D11_VS_OUTPUT_REGISTER_COUNT, "Unexpected D3D11 constant value."); + + switch (featureLevel) + { +#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: +#endif + case D3D_FEATURE_LEVEL_11_0: return D3D11_VS_OUTPUT_REGISTER_COUNT - GetReservedVertexOutputVectors(featureLevel); + + case D3D_FEATURE_LEVEL_10_1: return D3D10_1_VS_OUTPUT_REGISTER_COUNT - GetReservedVertexOutputVectors(featureLevel); + case D3D_FEATURE_LEVEL_10_0: return D3D10_VS_OUTPUT_REGISTER_COUNT - GetReservedVertexOutputVectors(featureLevel); + + // Use Shader Model 2.X limits + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: return 8 - GetReservedVertexOutputVectors(featureLevel); + + default: UNREACHABLE(); return 0; + } +} + +static size_t GetMaximumVertexTextureUnits(D3D_FEATURE_LEVEL featureLevel) +{ + switch (featureLevel) + { +#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: +#endif + case D3D_FEATURE_LEVEL_11_0: return D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT; + + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: return D3D10_COMMONSHADER_SAMPLER_SLOT_COUNT; + + // Vertex textures not supported on D3D11 Feature Level 9 according to + // http://msdn.microsoft.com/en-us/library/windows/desktop/ff476149.aspx + // ID3D11DeviceContext::VSSetSamplers and ID3D11DeviceContext::VSSetShaderResources + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: return 0; + + default: UNREACHABLE(); return 0; + } +} + +static size_t GetMaximumPixelUniformVectors(D3D_FEATURE_LEVEL featureLevel) +{ + // TODO(geofflang): Remove hard-coded limit once the gl-uniform-arrays test can pass + switch (featureLevel) + { +#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: +#endif + case D3D_FEATURE_LEVEL_11_0: return 1024; // D3D11_REQ_CONSTANT_BUFFER_ELEMENT_COUNT; + + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: return 1024; // D3D10_REQ_CONSTANT_BUFFER_ELEMENT_COUNT; + + // From http://msdn.microsoft.com/en-us/library/windows/desktop/ff476149.aspx ID3D11DeviceContext::PSSetConstantBuffers + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: return 32; + + default: UNREACHABLE(); return 0; + } +} + +static size_t GetReservedPixelUniformBuffers() +{ + // Reserve one buffer for the application uniforms, and one for driver uniforms + return 2; +} + +static size_t GetMaximumPixelUniformBlocks(D3D_FEATURE_LEVEL featureLevel) +{ + switch (featureLevel) + { +#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: +#endif + case D3D_FEATURE_LEVEL_11_0: return D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - GetReservedPixelUniformBuffers(); + + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: return D3D10_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - GetReservedPixelUniformBuffers(); + + // Uniform blocks not supported on D3D11 Feature Level 9 + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: return 0; + + default: UNREACHABLE(); return 0; + } +} + +static size_t GetMaximumPixelInputVectors(D3D_FEATURE_LEVEL featureLevel) +{ + switch (featureLevel) + { +#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: +#endif + case D3D_FEATURE_LEVEL_11_0: return D3D11_PS_INPUT_REGISTER_COUNT - GetReservedVertexOutputVectors(featureLevel); + + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: return D3D10_PS_INPUT_REGISTER_COUNT - GetReservedVertexOutputVectors(featureLevel); + + // Use Shader Model 2.X limits + case D3D_FEATURE_LEVEL_9_3: return 8 - GetReservedVertexOutputVectors(featureLevel); + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: return 8 - GetReservedVertexOutputVectors(featureLevel); + + default: UNREACHABLE(); return 0; + } +} + +static size_t GetMaximumPixelTextureUnits(D3D_FEATURE_LEVEL featureLevel) +{ + switch (featureLevel) + { +#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: +#endif + case D3D_FEATURE_LEVEL_11_0: return D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT; + + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: return D3D10_COMMONSHADER_SAMPLER_SLOT_COUNT; + + // http://msdn.microsoft.com/en-us/library/windows/desktop/ff476149.aspx ID3D11DeviceContext::PSSetShaderResources + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: return 16; + + default: UNREACHABLE(); return 0; + } +} + +static int GetMinimumTexelOffset(D3D_FEATURE_LEVEL featureLevel) +{ + switch (featureLevel) + { +#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: +#endif + case D3D_FEATURE_LEVEL_11_0: return D3D11_COMMONSHADER_TEXEL_OFFSET_MAX_NEGATIVE; + + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: return D3D10_COMMONSHADER_TEXEL_OFFSET_MAX_NEGATIVE; + + // Sampling functions with offsets are not available below shader model 4.0. + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: return 0; + + default: UNREACHABLE(); return 0; + } +} + +static int GetMaximumTexelOffset(D3D_FEATURE_LEVEL featureLevel) +{ + switch (featureLevel) + { +#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: +#endif + case D3D_FEATURE_LEVEL_11_0: return D3D11_COMMONSHADER_TEXEL_OFFSET_MAX_POSITIVE; + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: return D3D11_COMMONSHADER_TEXEL_OFFSET_MAX_POSITIVE; + + // Sampling functions with offsets are not available below shader model 4.0. + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: return 0; + + default: UNREACHABLE(); return 0; + } +} + +static size_t GetMaximumConstantBufferSize(D3D_FEATURE_LEVEL featureLevel) +{ + // Returns a size_t despite the limit being a GLuint64 because size_t is the maximum size of + // any buffer that could be allocated. + + const size_t bytesPerComponent = 4 * sizeof(float); + + switch (featureLevel) + { +#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: +#endif + case D3D_FEATURE_LEVEL_11_0: return D3D11_REQ_CONSTANT_BUFFER_ELEMENT_COUNT * bytesPerComponent; + + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: return D3D10_REQ_CONSTANT_BUFFER_ELEMENT_COUNT * bytesPerComponent; + + // Limits from http://msdn.microsoft.com/en-us/library/windows/desktop/ff476501.aspx remarks section + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: return 4096 * bytesPerComponent; + + default: UNREACHABLE(); return 0; + } +} + +static size_t GetMaximumStreamOutputBuffers(D3D_FEATURE_LEVEL featureLevel) +{ + switch (featureLevel) + { +#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: +#endif + case D3D_FEATURE_LEVEL_11_0: return D3D11_SO_BUFFER_SLOT_COUNT; + + case D3D_FEATURE_LEVEL_10_1: return D3D10_1_SO_BUFFER_SLOT_COUNT; + case D3D_FEATURE_LEVEL_10_0: return D3D10_SO_BUFFER_SLOT_COUNT; + + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: return 0; + + default: UNREACHABLE(); return 0; + } +} + +static size_t GetMaximumStreamOutputInterleavedComponents(D3D_FEATURE_LEVEL featureLevel) +{ + switch (featureLevel) + { +#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: +#endif + case D3D_FEATURE_LEVEL_11_0: + + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: return GetMaximumVertexOutputVectors(featureLevel) * 4; + + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: return 0; + + default: UNREACHABLE(); return 0; + } +} + +static size_t GetMaximumStreamOutputSeparateComponents(D3D_FEATURE_LEVEL featureLevel) +{ + switch (featureLevel) + { +#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: +#endif + case D3D_FEATURE_LEVEL_11_0: return GetMaximumStreamOutputInterleavedComponents(featureLevel) / + GetMaximumStreamOutputBuffers(featureLevel); + + + // D3D 10 and 10.1 only allow one output per output slot if an output slot other than zero is used. + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: return 4; + + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: return 0; + + default: UNREACHABLE(); return 0; + } +} + +void GenerateCaps(ID3D11Device *device, ID3D11DeviceContext *deviceContext, gl::Caps *caps, gl::TextureCapsMap *textureCapsMap, gl::Extensions *extensions) +{ + D3D_FEATURE_LEVEL featureLevel = device->GetFeatureLevel(); + + GLuint maxSamples = 0; + const gl::FormatSet &allFormats = gl::GetAllSizedInternalFormats(); + for (gl::FormatSet::const_iterator internalFormat = allFormats.begin(); internalFormat != allFormats.end(); ++internalFormat) + { + gl::TextureCaps textureCaps = GenerateTextureFormatCaps(GetMaximumClientVersion(featureLevel), *internalFormat, device); + textureCapsMap->insert(*internalFormat, textureCaps); + + maxSamples = std::max(maxSamples, textureCaps.getMaxSamples()); + + if (gl::GetInternalFormatInfo(*internalFormat).compressed) + { + caps->compressedTextureFormats.push_back(*internalFormat); + } + } + + // GL core feature limits + caps->maxElementIndex = static_cast(std::numeric_limits::max()); + caps->max3DTextureSize = GetMaximum3DTextureSize(featureLevel); + caps->max2DTextureSize = GetMaximum2DTextureSize(featureLevel); + caps->maxCubeMapTextureSize = GetMaximumCubeMapTextureSize(featureLevel); + caps->maxArrayTextureLayers = GetMaximum2DTextureArraySize(featureLevel); + + // Unimplemented, set to minimum required + caps->maxLODBias = 2.0f; + + // No specific limits on render target size, maximum 2D texture size is equivalent + caps->maxRenderbufferSize = caps->max2DTextureSize; + + // Maximum draw buffers and color attachments are the same, max color attachments could eventually be + // increased to 16 + caps->maxDrawBuffers = GetMaximumSimultaneousRenderTargets(featureLevel); + caps->maxColorAttachments = GetMaximumSimultaneousRenderTargets(featureLevel); + + // D3D11 has the same limit for viewport width and height + caps->maxViewportWidth = GetMaximumViewportSize(featureLevel); + caps->maxViewportHeight = caps->maxViewportWidth; + + // Choose a reasonable maximum, enforced in the shader. + caps->minAliasedPointSize = 1.0f; + caps->maxAliasedPointSize = 1024.0f; + + // Wide lines not supported + caps->minAliasedLineWidth = 1.0f; + caps->maxAliasedLineWidth = 1.0f; + + // Primitive count limits + caps->maxElementsIndices = GetMaximumDrawIndexedIndexCount(featureLevel); + caps->maxElementsVertices = GetMaximumDrawVertexCount(featureLevel); + + // Program and shader binary formats (no supported shader binary formats) + caps->programBinaryFormats.push_back(GL_PROGRAM_BINARY_ANGLE); + + caps->vertexHighpFloat.setIEEEFloat(); + caps->vertexMediumpFloat.setIEEEFloat(); + caps->vertexLowpFloat.setIEEEFloat(); + caps->fragmentHighpFloat.setIEEEFloat(); + caps->fragmentMediumpFloat.setIEEEFloat(); + caps->fragmentLowpFloat.setIEEEFloat(); + + // 32-bit integers are natively supported + caps->vertexHighpInt.setTwosComplementInt(32); + caps->vertexMediumpInt.setTwosComplementInt(32); + caps->vertexLowpInt.setTwosComplementInt(32); + caps->fragmentHighpInt.setTwosComplementInt(32); + caps->fragmentMediumpInt.setTwosComplementInt(32); + caps->fragmentLowpInt.setTwosComplementInt(32); + + // We do not wait for server fence objects internally, so report a max timeout of zero. + caps->maxServerWaitTimeout = 0; + + // Vertex shader limits + caps->maxVertexAttributes = GetMaximumVertexInputSlots(featureLevel); + caps->maxVertexUniformComponents = GetMaximumVertexUniformVectors(featureLevel) * 4; + caps->maxVertexUniformVectors = GetMaximumVertexUniformVectors(featureLevel); + caps->maxVertexUniformBlocks = GetMaximumVertexUniformBlocks(featureLevel); + caps->maxVertexOutputComponents = GetMaximumVertexOutputVectors(featureLevel) * 4; + caps->maxVertexTextureImageUnits = GetMaximumVertexTextureUnits(featureLevel); + + // Fragment shader limits + caps->maxFragmentUniformComponents = GetMaximumPixelUniformVectors(featureLevel) * 4; + caps->maxFragmentUniformVectors = GetMaximumPixelUniformVectors(featureLevel); + caps->maxFragmentUniformBlocks = GetMaximumPixelUniformBlocks(featureLevel); + caps->maxFragmentInputComponents = GetMaximumPixelInputVectors(featureLevel) * 4; + caps->maxTextureImageUnits = GetMaximumPixelTextureUnits(featureLevel); + caps->minProgramTexelOffset = GetMinimumTexelOffset(featureLevel); + caps->maxProgramTexelOffset = GetMaximumTexelOffset(featureLevel); + + // Aggregate shader limits + caps->maxUniformBufferBindings = caps->maxVertexUniformBlocks + caps->maxFragmentUniformBlocks; + caps->maxUniformBlockSize = GetMaximumConstantBufferSize(featureLevel); + + // Setting a large alignment forces uniform buffers to bind with zero offset + caps->uniformBufferOffsetAlignment = static_cast(std::numeric_limits::max()); +#if defined(ANGLE_ENABLE_D3D11_1) + ID3D11DeviceContext1 *deviceContext1 = d3d11::DynamicCastComObject(deviceContext); + + if (deviceContext1) + { + D3D11_FEATURE_DATA_D3D11_OPTIONS d3d11Options; + device->CheckFeatureSupport(D3D11_FEATURE_D3D11_OPTIONS, &d3d11Options, sizeof(D3D11_FEATURE_DATA_D3D11_OPTIONS)); + + if (d3d11Options.ConstantBufferOffsetting) + { + // With DirectX 11.1, constant buffer offset and size must be a multiple of 16 constants of 16 bytes each. + // https://msdn.microsoft.com/en-us/library/windows/desktop/hh404649%28v=vs.85%29.aspx + caps->uniformBufferOffsetAlignment = 256; + } + + SafeRelease(deviceContext1); + } +#endif + + caps->maxCombinedUniformBlocks = caps->maxVertexUniformBlocks + caps->maxFragmentUniformBlocks; + caps->maxCombinedVertexUniformComponents = (static_cast(caps->maxVertexUniformBlocks) * static_cast(caps->maxUniformBlockSize / 4)) + + static_cast(caps->maxVertexUniformComponents); + caps->maxCombinedFragmentUniformComponents = (static_cast(caps->maxFragmentUniformBlocks) * static_cast(caps->maxUniformBlockSize / 4)) + + static_cast(caps->maxFragmentUniformComponents); + caps->maxVaryingComponents = GetMaximumVertexOutputVectors(featureLevel) * 4; + caps->maxVaryingVectors = GetMaximumVertexOutputVectors(featureLevel); + caps->maxCombinedTextureImageUnits = caps->maxVertexTextureImageUnits + caps->maxTextureImageUnits; + + // Transform feedback limits + caps->maxTransformFeedbackInterleavedComponents = GetMaximumStreamOutputInterleavedComponents(featureLevel); + caps->maxTransformFeedbackSeparateAttributes = GetMaximumStreamOutputBuffers(featureLevel); + caps->maxTransformFeedbackSeparateComponents = GetMaximumStreamOutputSeparateComponents(featureLevel); + + // GL extension support + extensions->setTextureExtensionSupport(*textureCapsMap); + extensions->elementIndexUint = true; + extensions->packedDepthStencil = true; + extensions->getProgramBinary = true; + extensions->rgb8rgba8 = true; + extensions->readFormatBGRA = true; + extensions->pixelBufferObject = true; + extensions->mapBuffer = true; + extensions->mapBufferRange = true; + extensions->textureNPOT = GetNPOTTextureSupport(featureLevel); + extensions->drawBuffers = GetMaximumSimultaneousRenderTargets(featureLevel) > 1; + extensions->textureStorage = true; + extensions->textureFilterAnisotropic = true; + extensions->maxTextureAnisotropy = GetMaximumAnisotropy(featureLevel); + extensions->occlusionQueryBoolean = GetOcclusionQuerySupport(featureLevel); + extensions->fence = GetEventQuerySupport(featureLevel); + extensions->timerQuery = false; // Unimplemented + extensions->robustness = true; + extensions->blendMinMax = true; + extensions->framebufferBlit = GetFramebufferBlitSupport(featureLevel); + extensions->framebufferMultisample = GetFramebufferMultisampleSupport(featureLevel); + extensions->maxSamples = maxSamples; + extensions->instancedArrays = GetInstancingSupport(featureLevel); + extensions->packReverseRowOrder = true; + extensions->standardDerivatives = GetDerivativeInstructionSupport(featureLevel); + extensions->shaderTextureLOD = GetShaderTextureLODSupport(featureLevel); + extensions->fragDepth = true; + extensions->textureUsage = true; // This could be false since it has no effect in D3D11 + extensions->translatedShaderSource = true; +} + +} + +namespace d3d11 +{ + +void MakeValidSize(bool isImage, DXGI_FORMAT format, GLsizei *requestWidth, GLsizei *requestHeight, int *levelOffset) +{ + const DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(format); + + int upsampleCount = 0; + // Don't expand the size of full textures that are at least (blockWidth x blockHeight) already. + if (isImage || *requestWidth < static_cast(dxgiFormatInfo.blockWidth) || + *requestHeight < static_cast(dxgiFormatInfo.blockHeight)) + { + while (*requestWidth % dxgiFormatInfo.blockWidth != 0 || *requestHeight % dxgiFormatInfo.blockHeight != 0) + { + *requestWidth <<= 1; + *requestHeight <<= 1; + upsampleCount++; + } + } + *levelOffset = upsampleCount; +} + +void GenerateInitialTextureData(GLint internalFormat, D3D_FEATURE_LEVEL featureLevel, GLuint width, GLuint height, GLuint depth, + GLuint mipLevels, std::vector *outSubresourceData, + std::vector< std::vector > *outData) +{ + const d3d11::TextureFormat &d3dFormatInfo = d3d11::GetTextureFormatInfo(internalFormat, featureLevel); + ASSERT(d3dFormatInfo.dataInitializerFunction != NULL); + + const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(d3dFormatInfo.texFormat); + + outSubresourceData->resize(mipLevels); + outData->resize(mipLevels); + + for (unsigned int i = 0; i < mipLevels; i++) + { + unsigned int mipWidth = std::max(width >> i, 1U); + unsigned int mipHeight = std::max(height >> i, 1U); + unsigned int mipDepth = std::max(depth >> i, 1U); + + unsigned int rowWidth = dxgiFormatInfo.pixelBytes * mipWidth; + unsigned int imageSize = rowWidth * height; + + outData->at(i).resize(rowWidth * mipHeight * mipDepth); + d3dFormatInfo.dataInitializerFunction(mipWidth, mipHeight, mipDepth, outData->at(i).data(), rowWidth, imageSize); + + outSubresourceData->at(i).pSysMem = outData->at(i).data(); + outSubresourceData->at(i).SysMemPitch = rowWidth; + outSubresourceData->at(i).SysMemSlicePitch = imageSize; + } +} + +void SetPositionTexCoordVertex(PositionTexCoordVertex* vertex, float x, float y, float u, float v) +{ + vertex->x = x; + vertex->y = y; + vertex->u = u; + vertex->v = v; +} + +void SetPositionLayerTexCoord3DVertex(PositionLayerTexCoord3DVertex* vertex, float x, float y, + unsigned int layer, float u, float v, float s) +{ + vertex->x = x; + vertex->y = y; + vertex->l = layer; + vertex->u = u; + vertex->v = v; + vertex->s = s; +} + +HRESULT SetDebugName(ID3D11DeviceChild *resource, const char *name) +{ +#if defined(_DEBUG) + return resource->SetPrivateData(WKPDID_D3DDebugObjectName, strlen(name), name); +#else + return S_OK; +#endif +} + +gl::Error GetAttachmentRenderTarget(const gl::FramebufferAttachment *attachment, RenderTarget11 **outRT) +{ + RenderTargetD3D *renderTarget = NULL; + gl::Error error = rx::GetAttachmentRenderTarget(attachment, &renderTarget); + if (error.isError()) + { + return error; + } + *outRT = RenderTarget11::makeRenderTarget11(renderTarget); + return gl::Error(GL_NO_ERROR); +} + +Workarounds GenerateWorkarounds(D3D_FEATURE_LEVEL featureLevel) +{ + Workarounds workarounds; + workarounds.mrtPerfWorkaround = true; + workarounds.setDataFasterThanImageUpload = true; + workarounds.zeroMaxLodWorkaround = (featureLevel <= D3D_FEATURE_LEVEL_9_3); + workarounds.useInstancedPointSpriteEmulation = (featureLevel <= D3D_FEATURE_LEVEL_9_3); + return workarounds; +} + +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.h new file mode 100644 index 0000000000..207e6b5404 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.h @@ -0,0 +1,190 @@ +// +// Copyright (c) 2012-2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// renderer11_utils.h: Conversion functions and other utility routines +// specific to the D3D11 renderer. + +#ifndef LIBANGLE_RENDERER_D3D_D3D11_RENDERER11_UTILS_H_ +#define LIBANGLE_RENDERER_D3D_D3D11_RENDERER11_UTILS_H_ + +#include "libANGLE/angletypes.h" +#include "libANGLE/Caps.h" +#include "libANGLE/Error.h" + +#include + +namespace gl +{ +class FramebufferAttachment; +} + +namespace rx +{ +class RenderTarget11; +struct Workarounds; + +namespace gl_d3d11 +{ + +D3D11_BLEND ConvertBlendFunc(GLenum glBlend, bool isAlpha); +D3D11_BLEND_OP ConvertBlendOp(GLenum glBlendOp); +UINT8 ConvertColorMask(bool maskRed, bool maskGreen, bool maskBlue, bool maskAlpha); + +D3D11_CULL_MODE ConvertCullMode(bool cullEnabled, GLenum cullMode); + +D3D11_COMPARISON_FUNC ConvertComparison(GLenum comparison); +D3D11_DEPTH_WRITE_MASK ConvertDepthMask(bool depthWriteEnabled); +UINT8 ConvertStencilMask(GLuint stencilmask); +D3D11_STENCIL_OP ConvertStencilOp(GLenum stencilOp); + +D3D11_FILTER ConvertFilter(GLenum minFilter, GLenum magFilter, float maxAnisotropy, GLenum comparisonMode); +D3D11_TEXTURE_ADDRESS_MODE ConvertTextureWrap(GLenum wrap); + +D3D11_QUERY ConvertQueryType(GLenum queryType); + +} + +namespace d3d11_gl +{ + +GLint GetMaximumClientVersion(D3D_FEATURE_LEVEL featureLevel); +void GenerateCaps(ID3D11Device *device, ID3D11DeviceContext *deviceContext, gl::Caps *caps, gl::TextureCapsMap *textureCapsMap, gl::Extensions *extensions); + +} + +namespace d3d11 +{ + +void MakeValidSize(bool isImage, DXGI_FORMAT format, GLsizei *requestWidth, GLsizei *requestHeight, int *levelOffset); + +void GenerateInitialTextureData(GLint internalFormat, D3D_FEATURE_LEVEL featureLevel, GLuint width, GLuint height, GLuint depth, + GLuint mipLevels, std::vector *outSubresourceData, + std::vector< std::vector > *outData); + +struct PositionTexCoordVertex +{ + float x, y; + float u, v; +}; +void SetPositionTexCoordVertex(PositionTexCoordVertex* vertex, float x, float y, float u, float v); + +struct PositionLayerTexCoord3DVertex +{ + float x, y; + unsigned int l; + float u, v, s; +}; +void SetPositionLayerTexCoord3DVertex(PositionLayerTexCoord3DVertex* vertex, float x, float y, + unsigned int layer, float u, float v, float s); + +template +struct PositionDepthColorVertex +{ + float x, y, z; + T r, g, b, a; +}; + +template +void SetPositionDepthColorVertex(PositionDepthColorVertex* vertex, float x, float y, float z, + const gl::Color &color) +{ + vertex->x = x; + vertex->y = y; + vertex->z = z; + vertex->r = color.red; + vertex->g = color.green; + vertex->b = color.blue; + vertex->a = color.alpha; +} + +HRESULT SetDebugName(ID3D11DeviceChild *resource, const char *name); + +template +outType* DynamicCastComObject(IUnknown* object) +{ + outType *outObject = NULL; + HRESULT result = object->QueryInterface(__uuidof(outType), reinterpret_cast(&outObject)); + if (SUCCEEDED(result)) + { + return outObject; + } + else + { + SafeRelease(outObject); + return NULL; + } +} + +inline bool isDeviceLostError(HRESULT errorCode) +{ + switch (errorCode) + { + case DXGI_ERROR_DEVICE_HUNG: + case DXGI_ERROR_DEVICE_REMOVED: + case DXGI_ERROR_DEVICE_RESET: + case DXGI_ERROR_DRIVER_INTERNAL_ERROR: + case DXGI_ERROR_NOT_CURRENTLY_AVAILABLE: + return true; + default: + return false; + } +} + +template +inline ID3D11VertexShader *CompileVS(ID3D11Device *device, const BYTE (&byteCode)[N], const char *name) +{ + ID3D11VertexShader *vs = NULL; + HRESULT result = device->CreateVertexShader(byteCode, N, NULL, &vs); + UNUSED_ASSERTION_VARIABLE(result); + ASSERT(SUCCEEDED(result)); + SetDebugName(vs, name); + return vs; +} + +template +inline ID3D11GeometryShader *CompileGS(ID3D11Device *device, const BYTE (&byteCode)[N], const char *name) +{ + ID3D11GeometryShader *gs = NULL; + HRESULT result = device->CreateGeometryShader(byteCode, N, NULL, &gs); + UNUSED_ASSERTION_VARIABLE(result); + ASSERT(SUCCEEDED(result)); + SetDebugName(gs, name); + return gs; +} + +template +inline ID3D11PixelShader *CompilePS(ID3D11Device *device, const BYTE (&byteCode)[N], const char *name) +{ + ID3D11PixelShader *ps = NULL; + HRESULT result = device->CreatePixelShader(byteCode, N, NULL, &ps); + UNUSED_ASSERTION_VARIABLE(result); + ASSERT(SUCCEEDED(result)); + SetDebugName(ps, name); + return ps; +} + +// Copy data to small D3D11 buffers, such as for small constant buffers, which use one struct to +// represent an entire buffer. +template +inline void SetBufferData(ID3D11DeviceContext *context, ID3D11Buffer *constantBuffer, const T &value) +{ + D3D11_MAPPED_SUBRESOURCE mappedResource; + context->Map(constantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); + + memcpy(mappedResource.pData, &value, sizeof(T)); + + context->Unmap(constantBuffer, 0); +} + +gl::Error GetAttachmentRenderTarget(const gl::FramebufferAttachment *attachment, RenderTarget11 **outRT); + +Workarounds GenerateWorkarounds(D3D_FEATURE_LEVEL featureLevel); + +} + +} + +#endif // LIBANGLE_RENDERER_D3D_D3D11_RENDERER11_UTILS_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/shaders/BufferToTexture11.hlsl b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/shaders/BufferToTexture11.hlsl new file mode 100644 index 0000000000..c43734f6a3 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/shaders/BufferToTexture11.hlsl @@ -0,0 +1,77 @@ +Buffer Buffer4F : register(t0); +Buffer Buffer4I : register(t0); +Buffer Buffer4UI : register(t0); + +struct VS_OUTPUT +{ + float4 position : SV_Position; + uint index : TEXCOORD0; + uint slice : LAYER; +}; + +struct GS_OUTPUT +{ + float4 position : SV_Position; + uint index : TEXCOORD0; + uint slice : SV_RenderTargetArrayIndex; +}; + +cbuffer BufferCopyParams : register(b0) +{ + uint FirstPixelOffset; + uint PixelsPerRow; + uint RowStride; + uint RowsPerSlice; + float2 PositionOffset; + float2 PositionScale; + int2 TexLocationOffset; + int2 TexLocationScale; + uint FirstSlice; +} + +void ComputePositionAndIndex(uint vertexID, out VS_OUTPUT outVertex) +{ + uint PixelsPerSlice = PixelsPerRow * RowsPerSlice; + uint SliceStride = RowStride * RowsPerSlice; + + uint slice = vertexID / PixelsPerSlice; + uint sliceOffset = slice * PixelsPerSlice; + uint row = (vertexID - sliceOffset) / PixelsPerRow; + uint col = vertexID - sliceOffset - (row * PixelsPerRow); + + float2 coords = float2(float(col), float(row)); + + outVertex.position = float4(PositionOffset + PositionScale * coords, 0.0f, 1.0f); + outVertex.index = FirstPixelOffset + slice * SliceStride + row * RowStride + col; + outVertex.slice = FirstSlice + slice; +} + +void VS_BufferToTexture(in uint vertexID : SV_VertexID, out VS_OUTPUT outVertex) +{ + ComputePositionAndIndex(vertexID, outVertex); +} + +[maxvertexcount(1)] +void GS_BufferToTexture(point VS_OUTPUT inVertex[1], inout PointStream outStream) +{ + GS_OUTPUT outVertex; + outVertex.position = inVertex[0].position; + outVertex.index = inVertex[0].index; + outVertex.slice = inVertex[0].slice; + outStream.Append(outVertex); +} + +float4 PS_BufferToTexture_4F(in float4 inPosition : SV_Position, in uint inIndex : TEXCOORD0) : SV_Target +{ + return Buffer4F.Load(inIndex); +} + +int4 PS_BufferToTexture_4I(in float4 inPosition : SV_Position, in uint inIndex : TEXCOORD0) : SV_Target +{ + return Buffer4I.Load(inIndex); +} + +uint4 PS_BufferToTexture_4UI(in float4 inPosition : SV_Position, in uint inIndex : TEXCOORD0) : SV_Target +{ + return Buffer4UI.Load(inIndex); +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/shaders/Clear11.hlsl b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/shaders/Clear11.hlsl new file mode 100644 index 0000000000..2b3e1ebe4c --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/shaders/Clear11.hlsl @@ -0,0 +1,119 @@ +// Assume we are in SM4+, which has 8 color outputs + +void VS_ClearFloat( in float3 inPosition : POSITION, in float4 inColor : COLOR, + out float4 outPosition : SV_POSITION, out float4 outColor : COLOR) +{ + outPosition = float4(inPosition, 1.0f); + outColor = inColor; +} + +struct PS_OutputFloat +{ + float4 color0 : SV_TARGET0; + float4 color1 : SV_TARGET1; + float4 color2 : SV_TARGET2; + float4 color3 : SV_TARGET3; + float4 color4 : SV_TARGET4; + float4 color5 : SV_TARGET5; + float4 color6 : SV_TARGET6; + float4 color7 : SV_TARGET7; +}; + +PS_OutputFloat PS_ClearFloat(in float4 inPosition : SV_POSITION, in float4 inColor : COLOR) +{ + PS_OutputFloat outColor; + outColor.color0 = inColor; + outColor.color1 = inColor; + outColor.color2 = inColor; + outColor.color3 = inColor; + outColor.color4 = inColor; + outColor.color5 = inColor; + outColor.color6 = inColor; + outColor.color7 = inColor; + return outColor; +} + +struct PS_OutputFloat_FL9 +{ + float4 color0 : SV_TARGET0; + float4 color1 : SV_TARGET1; + float4 color2 : SV_TARGET2; + float4 color3 : SV_TARGET3; +}; + +PS_OutputFloat_FL9 PS_ClearFloat_FL9(in float4 inPosition : SV_POSITION, in float4 inColor : COLOR) +{ + PS_OutputFloat_FL9 outColor; + outColor.color0 = inColor; + outColor.color1 = inColor; + outColor.color2 = inColor; + outColor.color3 = inColor; + return outColor; +} + +void VS_ClearUint( in float3 inPosition : POSITION, in uint4 inColor : COLOR, + out float4 outPosition : SV_POSITION, out uint4 outColor : COLOR) +{ + outPosition = float4(inPosition, 1.0f); + outColor = inColor; +} + +struct PS_OutputUint +{ + uint4 color0 : SV_TARGET0; + uint4 color1 : SV_TARGET1; + uint4 color2 : SV_TARGET2; + uint4 color3 : SV_TARGET3; + uint4 color4 : SV_TARGET4; + uint4 color5 : SV_TARGET5; + uint4 color6 : SV_TARGET6; + uint4 color7 : SV_TARGET7; +}; + +PS_OutputUint PS_ClearUint(in float4 inPosition : SV_POSITION, in uint4 inColor : COLOR) +{ + PS_OutputUint outColor; + outColor.color0 = inColor; + outColor.color1 = inColor; + outColor.color2 = inColor; + outColor.color3 = inColor; + outColor.color4 = inColor; + outColor.color5 = inColor; + outColor.color6 = inColor; + outColor.color7 = inColor; + return outColor; +} + + +void VS_ClearSint( in float3 inPosition : POSITION, in int4 inColor : COLOR, + out float4 outPosition : SV_POSITION, out int4 outColor : COLOR) +{ + outPosition = float4(inPosition, 1.0f); + outColor = inColor; +} + +struct PS_OutputSint +{ + int4 color0 : SV_TARGET0; + int4 color1 : SV_TARGET1; + int4 color2 : SV_TARGET2; + int4 color3 : SV_TARGET3; + int4 color4 : SV_TARGET4; + int4 color5 : SV_TARGET5; + int4 color6 : SV_TARGET6; + int4 color7 : SV_TARGET7; +}; + +PS_OutputSint PS_ClearSint(in float4 inPosition : SV_POSITION, in int4 inColor : COLOR) +{ + PS_OutputSint outColor; + outColor.color0 = inColor; + outColor.color1 = inColor; + outColor.color2 = inColor; + outColor.color3 = inColor; + outColor.color4 = inColor; + outColor.color5 = inColor; + outColor.color6 = inColor; + outColor.color7 = inColor; + return outColor; +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/shaders/Passthrough2D11.hlsl b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/shaders/Passthrough2D11.hlsl new file mode 100644 index 0000000000..8671c39fb7 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/shaders/Passthrough2D11.hlsl @@ -0,0 +1,111 @@ +Texture2D TextureF : register(t0); +Texture2D TextureUI : register(t0); +Texture2D TextureI : register(t0); + +SamplerState Sampler : register(s0); + +void VS_Passthrough2D( in float2 inPosition : POSITION, in float2 inTexCoord : TEXCOORD0, + out float4 outPosition : SV_POSITION, out float2 outTexCoord : TEXCOORD0) +{ + outPosition = float4(inPosition, 0.0f, 1.0f); + outTexCoord = inTexCoord; +} + +float PS_PassthroughDepth2D(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_DEPTH +{ + return TextureF.Sample(Sampler, inTexCoord).r; +} + +float4 PS_PassthroughRGBA2D(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + return TextureF.Sample(Sampler, inTexCoord).rgba; +} + +uint4 PS_PassthroughRGBA2DUI(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + uint2 size; + TextureUI.GetDimensions(size.x, size.y); + + return TextureUI.Load(int3(size * inTexCoord, 0)).rgba; +} + +int4 PS_PassthroughRGBA2DI(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + uint2 size; + TextureI.GetDimensions(size.x, size.y); + + return TextureI.Load(int3(size * inTexCoord, 0)).rgba; +} + +float4 PS_PassthroughRGB2D(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + return float4(TextureF.Sample(Sampler, inTexCoord).rgb, 1.0f); +} + +uint4 PS_PassthroughRGB2DUI(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + uint2 size; + TextureUI.GetDimensions(size.x, size.y); + + return uint4(TextureUI.Load(int3(size * inTexCoord, 0)).rgb, 0); +} + +int4 PS_PassthroughRGB2DI(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + uint2 size; + TextureI.GetDimensions(size.x, size.y); + + return int4(TextureI.Load(int3(size * inTexCoord, 0)).rgb, 0); +} + +float4 PS_PassthroughRG2D(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + return float4(TextureF.Sample(Sampler, inTexCoord).rg, 0.0f, 1.0f); +} + +uint4 PS_PassthroughRG2DUI(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + uint2 size; + TextureUI.GetDimensions(size.x, size.y); + + return uint4(TextureUI.Load(int3(size * inTexCoord, 0)).rg, 0, 0); +} + +int4 PS_PassthroughRG2DI(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + uint2 size; + TextureI.GetDimensions(size.x, size.y); + + return int4(TextureI.Load(int3(size * inTexCoord, 0)).rg, 0, 0); +} + +float4 PS_PassthroughR2D(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + return float4(TextureF.Sample(Sampler, inTexCoord).r, 0.0f, 0.0f, 1.0f); +} + +uint4 PS_PassthroughR2DUI(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + uint2 size; + TextureUI.GetDimensions(size.x, size.y); + + return uint4(TextureUI.Load(int3(size * inTexCoord, 0)).r, 0, 0, 0); +} + +int4 PS_PassthroughR2DI(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + uint2 size; + TextureI.GetDimensions(size.x, size.y); + + return int4(TextureI.Load(int3(size * inTexCoord, 0)).r, 0, 0, 0); +} + +float4 PS_PassthroughLum2D(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + return float4(TextureF.Sample(Sampler, inTexCoord).rrr, 1.0f); +} + +float4 PS_PassthroughLumAlpha2D(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + return TextureF.Sample(Sampler, inTexCoord).rrra; +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/shaders/Passthrough3D11.hlsl b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/shaders/Passthrough3D11.hlsl new file mode 100644 index 0000000000..c23c9032ec --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/shaders/Passthrough3D11.hlsl @@ -0,0 +1,146 @@ +Texture3D TextureF : register(t0); +Texture3D TextureUI : register(t0); +Texture3D TextureI : register(t0); + +SamplerState Sampler : register(s0); + +struct VS_INPUT +{ + float2 Position : POSITION; + uint Layer : LAYER; + float3 TexCoord : TEXCOORD; +}; + +struct VS_OUTPUT +{ + float4 Position : SV_POSITION; + uint Layer : LAYER; + float3 TexCoord : TEXCOORD; +}; + +struct GS_OUTPUT +{ + float4 Position : SV_POSITION; + uint Layer : SV_RENDERTARGETARRAYINDEX; + float3 TexCoord : TEXCOORD; +}; + +VS_OUTPUT VS_Passthrough3D(VS_INPUT input) +{ + VS_OUTPUT output; + + output.Position = float4(input.Position, 0.0f, 1.0f); + output.Layer = input.Layer; + output.TexCoord = input.TexCoord; + + return output; +} + +[maxvertexcount(3)] +void GS_Passthrough3D(triangle VS_OUTPUT input[3], inout TriangleStream outputStream) +{ + GS_OUTPUT output; + + for (int i = 0; i < 3; i++) + { + output.Position = input[i].Position; + output.Layer = input[i].Layer; + output.TexCoord = input[i].TexCoord; + + outputStream.Append(output); + } +} + +float4 PS_PassthroughRGBA3D(GS_OUTPUT input) : SV_TARGET0 +{ + return TextureF.Sample(Sampler, input.TexCoord).rgba; +} + +uint4 PS_PassthroughRGBA3DUI(GS_OUTPUT input) : SV_TARGET0 +{ + uint3 size; + TextureUI.GetDimensions(size.x, size.y, size.z); + + return TextureUI.Load(int4(size * input.TexCoord, 0)).rgba; +} + +int4 PS_PassthroughRGBA3DI(GS_OUTPUT input) : SV_TARGET0 +{ + uint3 size; + TextureI.GetDimensions(size.x, size.y, size.z); + + return TextureI.Load(int4(size * input.TexCoord, 0)).rgba; +} + +float4 PS_PassthroughRGB3D(GS_OUTPUT input) : SV_TARGET0 +{ + return float4(TextureF.Sample(Sampler, input.TexCoord).rgb, 1.0f); +} + +uint4 PS_PassthroughRGB3DUI(GS_OUTPUT input) : SV_TARGET0 +{ + uint3 size; + TextureUI.GetDimensions(size.x, size.y, size.z); + + return uint4(TextureUI.Load(int4(size * input.TexCoord, 0)).rgb, 0); +} + +int4 PS_PassthroughRGB3DI(GS_OUTPUT input) : SV_TARGET0 +{ + uint3 size; + TextureI.GetDimensions(size.x, size.y, size.z); + + return int4(TextureI.Load(int4(size * input.TexCoord, 0)).rgb, 0); +} + +float4 PS_PassthroughRG3D(GS_OUTPUT input) : SV_TARGET0 +{ + return float4(TextureF.Sample(Sampler, input.TexCoord).rg, 0.0f, 1.0f); +} + +uint4 PS_PassthroughRG3DUI(GS_OUTPUT input) : SV_TARGET0 +{ + uint3 size; + TextureUI.GetDimensions(size.x, size.y, size.z); + + return uint4(TextureUI.Load(int4(size * input.TexCoord, 0)).rg, 0, 0); +} + +int4 PS_PassthroughRG3DI(GS_OUTPUT input) : SV_TARGET0 +{ + uint3 size; + TextureI.GetDimensions(size.x, size.y, size.z); + + return int4(TextureI.Load(int4(size * input.TexCoord, 0)).rg, 0, 0); +} + +float4 PS_PassthroughR3D(GS_OUTPUT input) : SV_TARGET0 +{ + return float4(TextureF.Sample(Sampler, input.TexCoord).r, 0.0f, 0.0f, 1.0f); +} + +uint4 PS_PassthroughR3DUI(GS_OUTPUT input) : SV_TARGET0 +{ + uint3 size; + TextureUI.GetDimensions(size.x, size.y, size.z); + + return uint4(TextureUI.Load(int4(size * input.TexCoord, 0)).r, 0, 0, 0); +} + +int4 PS_PassthroughR3DI(GS_OUTPUT input) : SV_TARGET0 +{ + uint3 size; + TextureI.GetDimensions(size.x, size.y, size.z); + + return int4(TextureI.Load(int4(size * input.TexCoord, 0)).r, 0, 0, 0); +} + +float4 PS_PassthroughLum3D(GS_OUTPUT input) : SV_TARGET0 +{ + return float4(TextureF.Sample(Sampler, input.TexCoord).rrr, 1.0f); +} + +float4 PS_PassthroughLumAlpha3D(GS_OUTPUT input) : SV_TARGET0 +{ + return TextureF.Sample(Sampler, input.TexCoord).rrra; +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/shaders/Swizzle11.hlsl b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/shaders/Swizzle11.hlsl new file mode 100644 index 0000000000..505e222137 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/shaders/Swizzle11.hlsl @@ -0,0 +1,99 @@ +Texture2D TextureF2D : register(t0); +Texture2D TextureUI2D : register(t0); +Texture2D TextureI2D : register(t0); + +Texture3D TextureF3D : register(t0); +Texture3D TextureUI3D : register(t0); +Texture3D TextureI3D : register(t0); + +Texture2DArray TextureF2DArray : register(t0); +Texture2DArray TextureUI2DArray : register(t0); +Texture2DArray TextureI2DArray : register(t0); + +SamplerState Sampler : register(s0); + +cbuffer SwizzleProperties : register(b0) +{ + uint4 SwizzleIndices : packoffset(c0); +} + +float4 SwizzleLookup(in float4 sample) +{ + float lookup[6] = { sample[0], sample[1], sample[2], sample[3], 0.0f, 1.0f }; + return float4(lookup[SwizzleIndices[0]], lookup[SwizzleIndices[1]], lookup[SwizzleIndices[2]], lookup[SwizzleIndices[3]]); +} + +int4 SwizzleLookup(in int4 sample) +{ + int lookup[6] = { sample[0], sample[1], sample[2], sample[3], 0.0f, 1.0f }; + return int4(lookup[SwizzleIndices[0]], lookup[SwizzleIndices[1]], lookup[SwizzleIndices[2]], lookup[SwizzleIndices[3]]); +} + +uint4 SwizzleLookup(in uint4 sample) +{ + uint lookup[6] = { sample[0], sample[1], sample[2], sample[3], 0.0f, 1.0f }; + return uint4(lookup[SwizzleIndices[0]], lookup[SwizzleIndices[1]], lookup[SwizzleIndices[2]], lookup[SwizzleIndices[3]]); +} + +float4 PS_SwizzleF2D(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + return SwizzleLookup(TextureF2D.Sample(Sampler, inTexCoord)); +} + +int4 PS_SwizzleI2D(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + uint2 size; + TextureI2D.GetDimensions(size.x, size.y); + + return SwizzleLookup(TextureI2D.Load(int3(size * inTexCoord, 0))); +} + +uint4 PS_SwizzleUI2D(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + uint2 size; + TextureUI2D.GetDimensions(size.x, size.y); + + return SwizzleLookup(TextureUI2D.Load(int3(size * inTexCoord, 0))); +} + +float4 PS_SwizzleF3D(in float4 inPosition : SV_POSITION, in uint inLayer : SV_RENDERTARGETARRAYINDEX, in float3 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + return SwizzleLookup(TextureF3D.Sample(Sampler, inTexCoord)); +} + +int4 PS_SwizzleI3D(in float4 inPosition : SV_POSITION, in uint inLayer : SV_RENDERTARGETARRAYINDEX, in float3 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + uint3 size; + TextureI3D.GetDimensions(size.x, size.y, size.z); + + return SwizzleLookup(TextureI3D.Load(int4(size * inTexCoord, 0))); +} + +uint4 PS_SwizzleUI3D(in float4 inPosition : SV_POSITION, in uint inLayer : SV_RENDERTARGETARRAYINDEX, in float3 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + uint3 size; + TextureUI3D.GetDimensions(size.x, size.y, size.z); + + return SwizzleLookup(TextureUI3D.Load(int4(size * inTexCoord, 0))); +} + +float4 PS_SwizzleF2DArray(in float4 inPosition : SV_POSITION, in uint inLayer : SV_RENDERTARGETARRAYINDEX, in float3 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + return SwizzleLookup(TextureF2DArray.Sample(Sampler, float3(inTexCoord.xy, inLayer))); +} + +int4 PS_SwizzleI2DArray(in float4 inPosition : SV_POSITION, in uint inLayer : SV_RENDERTARGETARRAYINDEX, in float3 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + uint3 size; + TextureI2DArray.GetDimensions(size.x, size.y, size.z); + + return SwizzleLookup(TextureI2DArray.Load(int4(size.xy * inTexCoord.xy, inLayer, 0))); +} + +uint4 PS_SwizzleUI2DArray(in float4 inPosition : SV_POSITION, in uint inLayer : SV_RENDERTARGETARRAYINDEX, in float3 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + uint3 size; + TextureUI2DArray.GetDimensions(size.x, size.y, size.z); + + return SwizzleLookup(TextureUI2DArray.Load(int4(size.xy * inTexCoord.xy, inLayer, 0))); +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/win32/NativeWindow.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/win32/NativeWindow.cpp new file mode 100644 index 0000000000..9d8f0bb96c --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/win32/NativeWindow.cpp @@ -0,0 +1,68 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// NativeWindow.cpp: Handler for managing HWND native window types. + +#include "libANGLE/renderer/d3d/d3d11/NativeWindow.h" + +#include "common/debug.h" + +namespace rx +{ + +NativeWindow::NativeWindow(EGLNativeWindowType window) : mWindow(window) +{ +} + +bool NativeWindow::initialize() +{ + return true; +} + +bool NativeWindow::getClientRect(LPRECT rect) +{ + return GetClientRect(mWindow, rect) == TRUE; +} + +bool NativeWindow::isIconic() +{ + return IsIconic(mWindow) == TRUE; +} + +bool NativeWindow::isValidNativeWindow(EGLNativeWindowType window) +{ + return IsWindow(window) == TRUE; +} + +HRESULT NativeWindow::createSwapChain(ID3D11Device* device, DXGIFactory* factory, + DXGI_FORMAT format, unsigned int width, unsigned int height, + DXGISwapChain** swapChain) +{ + if (device == NULL || factory == NULL || swapChain == NULL || width == 0 || height == 0) + { + return E_INVALIDARG; + } + + DXGI_SWAP_CHAIN_DESC swapChainDesc = { 0 }; + swapChainDesc.BufferCount = 1; + swapChainDesc.BufferDesc.Format = format; + swapChainDesc.BufferDesc.Width = width; + swapChainDesc.BufferDesc.Height = height; + swapChainDesc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED; + swapChainDesc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED; + swapChainDesc.BufferDesc.RefreshRate.Numerator = 0; + swapChainDesc.BufferDesc.RefreshRate.Denominator = 1; + swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_BACK_BUFFER; + swapChainDesc.Flags = 0; + swapChainDesc.OutputWindow = mWindow; + swapChainDesc.SampleDesc.Count = 1; + swapChainDesc.SampleDesc.Quality = 0; + swapChainDesc.Windowed = TRUE; + swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; + + return factory->CreateSwapChain(device, &swapChainDesc, swapChain); +} +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow.cpp new file mode 100644 index 0000000000..350526c867 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow.cpp @@ -0,0 +1,214 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// CoreWindowNativeWindow.cpp: NativeWindow for managing ICoreWindow native window types. + +#include "libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow.h" + +using namespace ABI::Windows::Foundation::Collections; + +namespace rx +{ +CoreWindowNativeWindow::~CoreWindowNativeWindow() +{ + unregisterForSizeChangeEvents(); +} + +bool CoreWindowNativeWindow::initialize(EGLNativeWindowType window, IPropertySet *propertySet) +{ + mOrientationChangedEventToken.value = 0; + ComPtr props = propertySet; + ComPtr win = window; + SIZE swapChainSize = {}; + bool swapChainSizeSpecified = false; + HRESULT result = S_OK; + + // IPropertySet is an optional parameter and can be null. + // If one is specified, cache as an IMap and read the properties + // used for initial host initialization. + if (propertySet) + { + result = props.As(&mPropertyMap); + if (SUCCEEDED(result)) + { + // The EGLRenderSurfaceSizeProperty is optional and may be missing. The IPropertySet + // was prevalidated to contain the EGLNativeWindowType before being passed to + // this host. + result = GetOptionalSizePropertyValue(mPropertyMap, EGLRenderSurfaceSizeProperty, &swapChainSize, &swapChainSizeSpecified); + } + } + + if (SUCCEEDED(result)) + { + result = win.As(&mCoreWindow); + } + + if (SUCCEEDED(result)) + { + // If a swapchain size is specfied, then the automatic resize + // behaviors implemented by the host should be disabled. The swapchain + // will be still be scaled when being rendered to fit the bounds + // of the host. + // Scaling of the swapchain output occurs automatically because if + // the scaling mode setting DXGI_SCALING_STRETCH on the swapchain. + if (swapChainSizeSpecified) + { + mClientRect = { 0, 0, swapChainSize.cx, swapChainSize.cy }; + mSupportsSwapChainResize = false; + } + else + { + result = GetCoreWindowSizeInPixels(mCoreWindow, &mClientRect); + } + } + + if (SUCCEEDED(result)) + { + ComPtr displayInformation; + result = GetActivationFactory(HStringReference(RuntimeClass_Windows_Graphics_Display_DisplayInformation).Get(), &displayInformation); + if (SUCCEEDED(result)) + { + result = displayInformation->GetForCurrentView(&mDisplayInformation); + } + } + + if (SUCCEEDED(result)) + { + mNewClientRect = mClientRect; + mClientRectChanged = false; + return registerForSizeChangeEvents(); + } + + return false; +} + +bool CoreWindowNativeWindow::registerForSizeChangeEvents() +{ + ComPtr sizeChangedHandler; + HRESULT result = Microsoft::WRL::MakeAndInitialize(sizeChangedHandler.ReleaseAndGetAddressOf(), this->shared_from_this()); + if (SUCCEEDED(result)) + { + result = mCoreWindow->add_SizeChanged(sizeChangedHandler.Get(), &mSizeChangedEventToken); + } + +#if defined(ANGLE_ENABLE_WINDOWS_STORE) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) + ComPtr orientationChangedHandler; + result = sizeChangedHandler.As(&orientationChangedHandler); + if (SUCCEEDED(result)) + { + result = mDisplayInformation->add_OrientationChanged(orientationChangedHandler.Get(), &mOrientationChangedEventToken); + } +#endif + + if (SUCCEEDED(result)) + { + return true; + } + + return false; +} + +void CoreWindowNativeWindow::unregisterForSizeChangeEvents() +{ + if (mCoreWindow) + { + (void)mCoreWindow->remove_SizeChanged(mSizeChangedEventToken); + } +#if defined(ANGLE_ENABLE_WINDOWS_STORE) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) + if (mDisplayInformation) + { + (void)mDisplayInformation->remove_OrientationChanged(mOrientationChangedEventToken); + } +#endif + mSizeChangedEventToken.value = 0; + mOrientationChangedEventToken.value = 0; +} + +HRESULT CoreWindowNativeWindow::createSwapChain(ID3D11Device *device, DXGIFactory *factory, DXGI_FORMAT format, unsigned int width, unsigned int height, DXGISwapChain **swapChain) +{ + if (device == NULL || factory == NULL || swapChain == NULL || width == 0 || height == 0) + { + return E_INVALIDARG; + } + + DXGI_SWAP_CHAIN_DESC1 swapChainDesc = { 0 }; + swapChainDesc.Width = width; + swapChainDesc.Height = height; + swapChainDesc.Format = format; + swapChainDesc.Stereo = FALSE; + swapChainDesc.SampleDesc.Count = 1; + swapChainDesc.SampleDesc.Quality = 0; + swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_BACK_BUFFER; + swapChainDesc.BufferCount = 2; + swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; + swapChainDesc.Scaling = DXGI_SCALING_STRETCH; + + *swapChain = nullptr; + + ComPtr newSwapChain; + HRESULT result = factory->CreateSwapChainForCoreWindow(device, mCoreWindow.Get(), &swapChainDesc, nullptr, newSwapChain.ReleaseAndGetAddressOf()); + if (SUCCEEDED(result)) + { + +#if 0 //(WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) // Qt: allow Windows Phone to resize, but don't modify the backing texture in the swap chain. + // Test if swapchain supports resize. On Windows Phone devices, this will return DXGI_ERROR_UNSUPPORTED. On + // other devices DXGI_ERROR_INVALID_CALL should be returned because the combination of flags passed + // (DXGI_SWAP_CHAIN_FLAG_NONPREROTATED | DXGI_SWAP_CHAIN_FLAG_GDI_COMPATIBLE) are invalid flag combinations. + if (newSwapChain->ResizeBuffers(swapChainDesc.BufferCount, swapChainDesc.Width, swapChainDesc.Height, swapChainDesc.Format, DXGI_SWAP_CHAIN_FLAG_NONPREROTATED | DXGI_SWAP_CHAIN_FLAG_GDI_COMPATIBLE) == DXGI_ERROR_UNSUPPORTED) + { + mSupportsSwapChainResize = false; + } +#endif // (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) + + result = newSwapChain.CopyTo(swapChain); + } + + if (SUCCEEDED(result)) + { + // If automatic swapchain resize behaviors have been disabled, then + // unregister for the resize change events. + if (mSupportsSwapChainResize == false) + { + unregisterForSizeChangeEvents(); + } + } + + return result; +} + +HRESULT GetCoreWindowSizeInPixels(const ComPtr& coreWindow, RECT *windowSize) +{ + ABI::Windows::Foundation::Rect bounds; + HRESULT result = coreWindow->get_Bounds(&bounds); + if (SUCCEEDED(result)) + { + *windowSize = { 0, 0, ConvertDipsToPixels(bounds.Width), ConvertDipsToPixels(bounds.Height) }; + } + + return result; +} + +static float GetLogicalDpi() +{ + ComPtr displayProperties; + float dpi = 96.0f; + + if (SUCCEEDED(GetActivationFactory(HStringReference(RuntimeClass_Windows_Graphics_Display_DisplayProperties).Get(), displayProperties.GetAddressOf()))) + { + if (SUCCEEDED(displayProperties->get_LogicalDpi(&dpi))) + { + return dpi; + } + } + return dpi; +} + +long ConvertDipsToPixels(float dips) +{ + static const float dipsPerInch = 96.0f; + return lround((dips * GetLogicalDpi() / dipsPerInch)); +} +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow.h new file mode 100644 index 0000000000..59df9d5a6c --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow.h @@ -0,0 +1,110 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// CoreWindowNativeWindow.h: NativeWindow for managing ICoreWindow native window types. + +#ifndef LIBANGLE_RENDERER_D3D_D3D11_WINRT_COREWINDOWNATIVEWINDOW_H_ +#define LIBANGLE_RENDERER_D3D_D3D11_WINRT_COREWINDOWNATIVEWINDOW_H_ + +#include "libANGLE/renderer/d3d/d3d11/winrt/InspectableNativeWindow.h" + +#include +#include + +typedef ABI::Windows::Foundation::__FITypedEventHandler_2_Windows__CUI__CCore__CCoreWindow_Windows__CUI__CCore__CWindowSizeChangedEventArgs_t IWindowSizeChangedEventHandler; +typedef ABI::Windows::Foundation::__FITypedEventHandler_2_Windows__CGraphics__CDisplay__CDisplayInformation_IInspectable_t IDisplayOrientationEventHandler; + +namespace rx +{ +long ConvertDipsToPixels(float dips); + +class CoreWindowNativeWindow : public InspectableNativeWindow, public std::enable_shared_from_this +{ + public: + ~CoreWindowNativeWindow(); + + bool initialize(EGLNativeWindowType window, IPropertySet *propertySet); + bool registerForSizeChangeEvents(); + void unregisterForSizeChangeEvents(); + HRESULT createSwapChain(ID3D11Device *device, DXGIFactory *factory, DXGI_FORMAT format, unsigned int width, unsigned int height, DXGISwapChain **swapChain); + + private: + ComPtr mCoreWindow; + ComPtr> mPropertyMap; + ComPtr mDisplayInformation; + EventRegistrationToken mOrientationChangedEventToken; +}; + +[uuid(7F924F66-EBAE-40E5-A10B-B8F35E245190)] +class CoreWindowSizeChangedHandler : + public Microsoft::WRL::RuntimeClass, IWindowSizeChangedEventHandler, IDisplayOrientationEventHandler> +{ + public: + CoreWindowSizeChangedHandler() { } + HRESULT RuntimeClassInitialize(std::shared_ptr host) + { + if (!host) + { + return E_INVALIDARG; + } + + mHost = host; + return S_OK; + } + + // IWindowSizeChangedEventHandler + IFACEMETHOD(Invoke)(ABI::Windows::UI::Core::ICoreWindow *sender, ABI::Windows::UI::Core::IWindowSizeChangedEventArgs *sizeChangedEventArgs) + { + std::shared_ptr host = mHost.lock(); + if (host) + { + ABI::Windows::Foundation::Size windowSize; + if (SUCCEEDED(sizeChangedEventArgs->get_Size(&windowSize))) + { + SIZE windowSizeInPixels = { ConvertDipsToPixels(windowSize.Width), ConvertDipsToPixels(windowSize.Height) }; + host->setNewClientSize(windowSizeInPixels); + } + } + + return S_OK; + } + + IFACEMETHOD(Invoke)(ABI::Windows::Graphics::Display::IDisplayInformation *displayInformation, IInspectable *) + { +#if defined(ANGLE_ENABLE_WINDOWS_STORE) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) + NativeWindow::RotationFlags flags = NativeWindow::RotateNone; + ABI::Windows::Graphics::Display::DisplayOrientations orientation; + if (SUCCEEDED(displayInformation->get_CurrentOrientation(&orientation))) + { + switch (orientation) + { + case ABI::Windows::Graphics::Display::DisplayOrientations_Landscape: + flags = NativeWindow::RotateLeft; + break; + case ABI::Windows::Graphics::Display::DisplayOrientations_LandscapeFlipped: + flags = NativeWindow::RotateRight; + break; + default: + break; + } + } + std::shared_ptr host = mHost.lock(); + if (host) + { + host->setRotationFlags(flags); + } +#endif + return S_OK; + } + + private: + std::weak_ptr mHost; +}; + +HRESULT GetCoreWindowSizeInPixels(const ComPtr& coreWindow, RECT *windowSize); +} + +#endif // LIBANGLE_RENDERER_D3D_D3D11_WINRT_COREWINDOWNATIVEWINDOW_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/InspectableNativeWindow.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/InspectableNativeWindow.cpp new file mode 100644 index 0000000000..2bf48c5d94 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/InspectableNativeWindow.cpp @@ -0,0 +1,291 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// InspectableNativeWindow.cpp: NativeWindow base class for managing IInspectable native window types. + +#include "libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow.h" +#include "libANGLE/renderer/d3d/d3d11/winrt/SwapChainPanelNativeWindow.h" + +namespace rx +{ +NativeWindow::NativeWindow(EGLNativeWindowType window) +{ + mWindow = window; +} + +bool NativeWindow::initialize() +{ + // If the native window type is a IPropertySet, extract the + // EGLNativeWindowType (IInspectable) and initialize the + // proper host with this IPropertySet. + ComPtr propertySet; + ComPtr eglNativeWindow; + if (IsEGLConfiguredPropertySet(mWindow, &propertySet, &eglNativeWindow)) + { + // A property set was found and the EGLNativeWindowType was + // retrieved. The mWindow member of the host to must be updated + // to use the EGLNativeWindowType specified in the property set. + // mWindow is treated as a raw pointer not an AddRef'd interface, so + // the old mWindow does not need a Release() before this assignment. + mWindow = eglNativeWindow.Get(); + } + + ComPtr coreWindow; + ComPtr swapChainPanel; + if (IsCoreWindow(mWindow, &coreWindow)) + { + mImpl = std::make_shared(); + if (mImpl) + { + return mImpl->initialize(mWindow, propertySet.Get()); + } + } + else if (IsSwapChainPanel(mWindow, &swapChainPanel)) + { + mImpl = std::make_shared(); + if (mImpl) + { + return mImpl->initialize(mWindow, propertySet.Get()); + } + } + else + { + ERR("Invalid IInspectable EGLNativeWindowType detected. Valid IInspectables include ICoreWindow, ISwapChainPanel and IPropertySet"); + } + + return false; +} + +bool NativeWindow::getClientRect(RECT *rect) +{ + if (mImpl) + { + return mImpl->getClientRect(rect); + } + + return false; +} + +#if defined(ANGLE_ENABLE_WINDOWS_STORE) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) +NativeWindow::RotationFlags NativeWindow::rotationFlags() const +{ + if (mImpl) + { + return mImpl->rotationFlags(); + } + + return NativeWindow::RotateNone; +} +#endif + +bool NativeWindow::isIconic() +{ + return false; +} + +bool NativeWindow::isValidNativeWindow(EGLNativeWindowType window) +{ + return IsValidEGLNativeWindowType(window); +} + +HRESULT NativeWindow::createSwapChain(ID3D11Device *device, DXGIFactory *factory, DXGI_FORMAT format, unsigned int width, unsigned int height, DXGISwapChain **swapChain) +{ + if (mImpl) + { + return mImpl->createSwapChain(device, factory, format, width, height, swapChain); + } + + return E_UNEXPECTED; +} + +bool IsCoreWindow(EGLNativeWindowType window, ComPtr *coreWindow) +{ + if (!window) + { + return false; + } + + ComPtr win = window; + ComPtr coreWin; + if (SUCCEEDED(win.As(&coreWin))) + { + if (coreWindow != nullptr) + { + *coreWindow = coreWin.Detach(); + } + return true; + } + + return false; +} + +bool IsSwapChainPanel(EGLNativeWindowType window, ComPtr *swapChainPanel) +{ + if (!window) + { + return false; + } + + ComPtr win = window; + ComPtr panel; + if (SUCCEEDED(win.As(&panel))) + { + if (swapChainPanel != nullptr) + { + *swapChainPanel = panel.Detach(); + } + return true; + } + + return false; +} + +bool IsEGLConfiguredPropertySet(EGLNativeWindowType window, ABI::Windows::Foundation::Collections::IPropertySet **propertySet, IInspectable **eglNativeWindow) +{ + if (!window) + { + return false; + } + + ComPtr props = window; + ComPtr propSet; + ComPtr nativeWindow; + ComPtr> propMap; + boolean hasEglNativeWindowPropertyKey = false; + + HRESULT result = props.As(&propSet); + if (SUCCEEDED(result)) + { + result = propSet.As(&propMap); + } + + // Look for the presence of the EGLNativeWindowType in the property set + if (SUCCEEDED(result)) + { + result = propMap->HasKey(HStringReference(EGLNativeWindowTypeProperty).Get(), &hasEglNativeWindowPropertyKey); + } + + // If the IPropertySet does not contain the required EglNativeWindowType key, the property set is + // considered invalid. + if (SUCCEEDED(result) && !hasEglNativeWindowPropertyKey) + { + ERR("Could not find EGLNativeWindowTypeProperty in IPropertySet. Valid EGLNativeWindowTypeProperty values include ICoreWindow"); + return false; + } + + // The EglNativeWindowType property exists, so retreive the IInspectable that represents the EGLNativeWindowType + if (SUCCEEDED(result) && hasEglNativeWindowPropertyKey) + { + result = propMap->Lookup(HStringReference(EGLNativeWindowTypeProperty).Get(), &nativeWindow); + } + + if (SUCCEEDED(result)) + { + if (propertySet != nullptr) + { + result = propSet.CopyTo(propertySet); + } + } + + if (SUCCEEDED(result)) + { + if (eglNativeWindow != nullptr) + { + result = nativeWindow.CopyTo(eglNativeWindow); + } + } + + if (SUCCEEDED(result)) + { + return true; + } + + return false; +} + +// A Valid EGLNativeWindowType IInspectable can only be: +// +// ICoreWindow +// IPropertySet +// +// Anything else will be rejected as an invalid IInspectable. +bool IsValidEGLNativeWindowType(EGLNativeWindowType window) +{ + return IsCoreWindow(window) || IsSwapChainPanel(window) || IsEGLConfiguredPropertySet(window); +} + +// Attempts to read an optional SIZE property value that is assumed to be in the form of +// an ABI::Windows::Foundation::Size. This function validates the Size value before returning +// it to the caller. +// +// Possible return values are: +// S_OK, valueExists == true - optional SIZE value was successfully retrieved and validated +// S_OK, valueExists == false - optional SIZE value was not found +// E_INVALIDARG, valueExists = false - optional SIZE value was malformed in the property set. +// * Incorrect property type ( must be PropertyType_Size) +// * Invalid property value (width/height must be > 0) +// Additional errors may be returned from IMap or IPropertyValue +// +HRESULT GetOptionalSizePropertyValue(const ComPtr>& propertyMap, const wchar_t *propertyName, SIZE *value, bool *valueExists) +{ + if (!propertyMap || !propertyName || !value || !valueExists) + { + return false; + } + + // Assume that the value does not exist + *valueExists = false; + *value = { 0, 0 }; + + ComPtr propertyValue; + ABI::Windows::Foundation::PropertyType propertyType = ABI::Windows::Foundation::PropertyType::PropertyType_Empty; + Size sizeValue = { 0, 0 }; + boolean hasKey = false; + + HRESULT result = propertyMap->HasKey(HStringReference(propertyName).Get(), &hasKey); + if (SUCCEEDED(result) && !hasKey) + { + // Value does not exist, so return S_OK and set the exists parameter to false to indicate + // that a the optional property does not exist. + *valueExists = false; + return S_OK; + } + + if (SUCCEEDED(result)) + { + result = propertyMap->Lookup(HStringReference(propertyName).Get(), &propertyValue); + } + + if (SUCCEEDED(result)) + { + result = propertyValue->get_Type(&propertyType); + } + + // Check if the expected Size property is of PropertyType_Size type. + if (SUCCEEDED(result) && propertyType == ABI::Windows::Foundation::PropertyType::PropertyType_Size) + { + if (SUCCEEDED(propertyValue->GetSize(&sizeValue)) && (sizeValue.Width > 0 && sizeValue.Height > 0)) + { + // A valid property value exists + *value = { static_cast(sizeValue.Width), static_cast(sizeValue.Height) }; + *valueExists = true; + result = S_OK; + } + else + { + // An invalid Size property was detected. Width/Height values must > 0 + result = E_INVALIDARG; + } + } + else + { + // An invalid property type was detected. Size property must be of PropertyType_Size + result = E_INVALIDARG; + } + + return result; +} +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/InspectableNativeWindow.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/InspectableNativeWindow.h new file mode 100644 index 0000000000..575bdf8a58 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/InspectableNativeWindow.h @@ -0,0 +1,105 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// InspectableNativeWindow.h: Host specific implementation interface for +// managing IInspectable native window types. + +#ifndef LIBANGLE_RENDERER_D3D_D3D11_WINRT_INSPECTABLENATIVEWINDOW_H_ +#define LIBANGLE_RENDERER_D3D_D3D11_WINRT_INSPECTABLENATIVEWINDOW_H_ + +#include "libANGLE/renderer/d3d/d3d11/NativeWindow.h" + +#include "common/platform.h" + +#include "angle_windowsstore.h" + +#include +#include + +using namespace Microsoft::WRL; +using namespace Microsoft::WRL::Wrappers; +using namespace ABI::Windows::Foundation; +using namespace ABI::Windows::Foundation::Collections; + +namespace rx +{ +class InspectableNativeWindow +{ + public: + InspectableNativeWindow() : + mSupportsSwapChainResize(true), + mRequiresSwapChainScaling(false), + mClientRectChanged(false), + mClientRect({0,0,0,0}), + mNewClientRect({0,0,0,0}), + mRotationFlags(NativeWindow::RotateNone) + { + mSizeChangedEventToken.value = 0; + } + virtual ~InspectableNativeWindow(){} + + virtual bool initialize(EGLNativeWindowType window, IPropertySet *propertySet) = 0; + virtual HRESULT createSwapChain(ID3D11Device *device, DXGIFactory *factory, DXGI_FORMAT format, unsigned int width, unsigned int height, DXGISwapChain **swapChain) = 0; + virtual bool registerForSizeChangeEvents() = 0; + virtual void unregisterForSizeChangeEvents() = 0; + virtual HRESULT scaleSwapChain(const SIZE& newSize) { return S_OK; } + + bool getClientRect(RECT *rect) + { + if (mClientRectChanged && mSupportsSwapChainResize) + { + mClientRect = mNewClientRect; + } + + *rect = mClientRect; + + return true; + } + + void setNewClientSize(const SIZE &newSize) + { + if (mSupportsSwapChainResize && !mRequiresSwapChainScaling) + { + mNewClientRect = { 0, 0, newSize.cx, newSize.cy }; + mClientRectChanged = true; + } + + if (mRequiresSwapChainScaling) + { + scaleSwapChain(newSize); + } + } + + NativeWindow::RotationFlags rotationFlags() const + { + return mRotationFlags; + } + + void setRotationFlags(NativeWindow::RotationFlags flags) + { + mRotationFlags = flags; + } + +protected: + bool mSupportsSwapChainResize; + bool mRequiresSwapChainScaling; + RECT mClientRect; + RECT mNewClientRect; + bool mClientRectChanged; + NativeWindow::RotationFlags mRotationFlags; + + EventRegistrationToken mSizeChangedEventToken; +}; + +bool IsValidEGLNativeWindowType(EGLNativeWindowType window); +bool IsCoreWindow(EGLNativeWindowType window, ComPtr *coreWindow = nullptr); +bool IsSwapChainPanel(EGLNativeWindowType window, ComPtr *swapChainPanel = nullptr); +bool IsEGLConfiguredPropertySet(EGLNativeWindowType window, ABI::Windows::Foundation::Collections::IPropertySet **propertySet = nullptr, IInspectable **inspectable = nullptr); +HRESULT GetOptionalSizePropertyValue(const ComPtr>& propertyMap, const wchar_t *propertyName, SIZE *value, bool *valueExists); + +} + +#endif // LIBANGLE_RENDERER_D3D_D3D11_WINRT_INSPECTABLENATIVEWINDOW_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/SwapChainPanelNativeWindow.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/SwapChainPanelNativeWindow.cpp new file mode 100644 index 0000000000..53899dbb30 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/SwapChainPanelNativeWindow.cpp @@ -0,0 +1,228 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// SwapChainPanelNativeWindow.cpp: NativeWindow for managing ISwapChainPanel native window types. + +#include "libANGLE/renderer/d3d/d3d11/winrt/SwapChainPanelNativeWindow.h" + +#include +#include + +using namespace ABI::Windows::Foundation::Collections; + +namespace rx +{ +SwapChainPanelNativeWindow::~SwapChainPanelNativeWindow() +{ + unregisterForSizeChangeEvents(); +} + +bool SwapChainPanelNativeWindow::initialize(EGLNativeWindowType window, IPropertySet *propertySet) +{ + ComPtr props = propertySet; + ComPtr win = window; + SIZE swapChainSize = {}; + bool swapChainSizeSpecified = false; + HRESULT result = S_OK; + + // IPropertySet is an optional parameter and can be null. + // If one is specified, cache as an IMap and read the properties + // used for initial host initialization. + if (propertySet) + { + result = props.As(&mPropertyMap); + if (SUCCEEDED(result)) + { + // The EGLRenderSurfaceSizeProperty is optional and may be missing. The IPropertySet + // was prevalidated to contain the EGLNativeWindowType before being passed to + // this host. + result = GetOptionalSizePropertyValue(mPropertyMap, EGLRenderSurfaceSizeProperty, &swapChainSize, &swapChainSizeSpecified); + } + } + + if (SUCCEEDED(result)) + { + result = win.As(&mSwapChainPanel); + } + + if (SUCCEEDED(result)) + { + // If a swapchain size is specfied, then the automatic resize + // behaviors implemented by the host should be disabled. The swapchain + // will be still be scaled when being rendered to fit the bounds + // of the host. + // Scaling of the swapchain output needs to be handled by the + // host for swapchain panels even though the scaling mode setting + // DXGI_SCALING_STRETCH is configured on the swapchain. + if (swapChainSizeSpecified) + { + mClientRect = { 0, 0, swapChainSize.cx, swapChainSize.cy }; + + // Enable host swapchain scaling + mRequiresSwapChainScaling = true; + } + else + { + result = GetSwapChainPanelSize(mSwapChainPanel, &mClientRect); + } + } + + if (SUCCEEDED(result)) + { + mNewClientRect = mClientRect; + mClientRectChanged = false; + return registerForSizeChangeEvents(); + } + + return false; +} + +bool SwapChainPanelNativeWindow::registerForSizeChangeEvents() +{ + ComPtr sizeChangedHandler; + ComPtr frameworkElement; + HRESULT result = Microsoft::WRL::MakeAndInitialize(sizeChangedHandler.ReleaseAndGetAddressOf(), this->shared_from_this()); + + if (SUCCEEDED(result)) + { + result = mSwapChainPanel.As(&frameworkElement); + } + + if (SUCCEEDED(result)) + { + result = frameworkElement->add_SizeChanged(sizeChangedHandler.Get(), &mSizeChangedEventToken); + } + + if (SUCCEEDED(result)) + { + return true; + } + + return false; +} + +void SwapChainPanelNativeWindow::unregisterForSizeChangeEvents() +{ + ComPtr frameworkElement; + if (SUCCEEDED(mSwapChainPanel.As(&frameworkElement))) + { + (void)frameworkElement->remove_SizeChanged(mSizeChangedEventToken); + } + + mSizeChangedEventToken.value = 0; +} + +HRESULT SwapChainPanelNativeWindow::createSwapChain(ID3D11Device *device, DXGIFactory *factory, DXGI_FORMAT format, unsigned int width, unsigned int height, DXGISwapChain **swapChain) +{ + if (device == NULL || factory == NULL || swapChain == NULL || width == 0 || height == 0) + { + return E_INVALIDARG; + } + + DXGI_SWAP_CHAIN_DESC1 swapChainDesc = { 0 }; + swapChainDesc.Width = width; + swapChainDesc.Height = height; + swapChainDesc.Format = format; + swapChainDesc.Stereo = FALSE; + swapChainDesc.SampleDesc.Count = 1; + swapChainDesc.SampleDesc.Quality = 0; + swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_BACK_BUFFER; + swapChainDesc.BufferCount = 2; + swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; + swapChainDesc.Scaling = DXGI_SCALING_STRETCH; + swapChainDesc.AlphaMode = DXGI_ALPHA_MODE_IGNORE; + + *swapChain = nullptr; + + ComPtr newSwapChain; + ComPtr swapChainPanelNative; + RECT currentPanelSize = {}; + + HRESULT result = factory->CreateSwapChainForComposition(device, &swapChainDesc, nullptr, newSwapChain.ReleaseAndGetAddressOf()); + + if (SUCCEEDED(result)) + { + result = mSwapChainPanel.As(&swapChainPanelNative); + } + + if (SUCCEEDED(result)) + { + result = swapChainPanelNative->SetSwapChain(newSwapChain.Get()); + } + + if (SUCCEEDED(result)) + { + // The swapchain panel host requires an instance of the swapchain set on the SwapChainPanel + // to perform the runtime-scale behavior. This swapchain is cached here because there are + // no methods for retreiving the currently configured on from ISwapChainPanelNative. + mSwapChain = newSwapChain; + result = newSwapChain.CopyTo(swapChain); + } + + // If the host is responsible for scaling the output of the swapchain, then + // scale it now before returning an instance to the caller. This is done by + // first reading the current size of the swapchain panel, then scaling + if (SUCCEEDED(result) && mRequiresSwapChainScaling) + { + result = GetSwapChainPanelSize(mSwapChainPanel, ¤tPanelSize); + } + + // Scale the swapchain to fit inside the contents of the panel. + if (SUCCEEDED(result) && mRequiresSwapChainScaling) + { + SIZE currentSize = { currentPanelSize.right, currentPanelSize.bottom }; + result = scaleSwapChain(currentSize); + } + + if (SUCCEEDED(result)) + { + // If automatic swapchain resize behaviors have been disabled, then + // unregister for the resize change events. + if (mSupportsSwapChainResize == false) + { + unregisterForSizeChangeEvents(); + } + } + + return result; +} + +HRESULT SwapChainPanelNativeWindow::scaleSwapChain(const SIZE &newSize) +{ + ABI::Windows::Foundation::Size renderScale = { (float)newSize.cx/(float)mClientRect.right, (float)newSize.cy/(float)mClientRect.bottom }; + // Setup a scale matrix for the swap chain + DXGI_MATRIX_3X2_F scaleMatrix = {}; + scaleMatrix._11 = renderScale.Width; + scaleMatrix._22 = renderScale.Height; + + ComPtr swapChain2; + HRESULT result = mSwapChain.As(&swapChain2); + if (SUCCEEDED(result)) + { + result = swapChain2->SetMatrixTransform(&scaleMatrix); + } + + return result; +} + +HRESULT GetSwapChainPanelSize(const ComPtr &swapChainPanel, RECT *windowSize) +{ + ComPtr uiElement; + ABI::Windows::Foundation::Size renderSize = { 0, 0 }; + HRESULT result = swapChainPanel.As(&uiElement); + if (SUCCEEDED(result)) + { + result = uiElement->get_RenderSize(&renderSize); + } + + if (SUCCEEDED(result)) + { + *windowSize = { 0, 0, lround(renderSize.Width), lround(renderSize.Height) }; + } + + return result; +} +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/SwapChainPanelNativeWindow.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/SwapChainPanelNativeWindow.h new file mode 100644 index 0000000000..caf327d913 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/SwapChainPanelNativeWindow.h @@ -0,0 +1,79 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// SwapChainPanelNativeWindow.h: NativeWindow for managing ISwapChainPanel native window types. + +#ifndef LIBANGLE_RENDERER_D3D_D3D11_WINRT_SWAPCHAINPANELNATIVEWINDOW_H_ +#define LIBANGLE_RENDERER_D3D_D3D11_WINRT_SWAPCHAINPANELNATIVEWINDOW_H_ + +#include "libANGLE/renderer/d3d/d3d11/winrt/InspectableNativeWindow.h" + +namespace rx +{ +class SwapChainPanelNativeWindow : public InspectableNativeWindow, public std::enable_shared_from_this +{ + public: + ~SwapChainPanelNativeWindow(); + + bool initialize(EGLNativeWindowType window, IPropertySet *propertySet); + bool registerForSizeChangeEvents(); + void unregisterForSizeChangeEvents(); + HRESULT createSwapChain(ID3D11Device *device, DXGIFactory *factory, DXGI_FORMAT format, unsigned int width, unsigned int height, DXGISwapChain **swapChain); + HRESULT scaleSwapChain(const SIZE &newSize); + + private: + ComPtr mSwapChainPanel; + ComPtr> mPropertyMap; + ComPtr mSwapChain; +}; + +[uuid(8ACBD974-8187-4508-AD80-AEC77F93CF36)] +class SwapChainPanelSizeChangedHandler : + public Microsoft::WRL::RuntimeClass, ABI::Windows::UI::Xaml::ISizeChangedEventHandler> +{ + public: + SwapChainPanelSizeChangedHandler() { } + HRESULT RuntimeClassInitialize(std::shared_ptr host) + { + if (!host) + { + return E_INVALIDARG; + } + + mHost = host; + return S_OK; + } + + // ISizeChangedEventHandler + IFACEMETHOD(Invoke)(IInspectable *sender, ABI::Windows::UI::Xaml::ISizeChangedEventArgs *sizeChangedEventArgs) + { + std::shared_ptr host = mHost.lock(); + if (host) + { + // The size of the ISwapChainPanel control is returned in DIPs. + // We are keeping these in dips because the swapchain created for composition + // also uses dip units. This keeps dimensions, viewports, etc in the same unit. + // XAML Clients of the ISwapChainPanel are required to use dips to define their + // layout sizes as well. + ABI::Windows::Foundation::Size newSize; + HRESULT result = sizeChangedEventArgs->get_NewSize(&newSize); + if (SUCCEEDED(result)) + { + SIZE windowSize = { lround(newSize.Width), lround(newSize.Height) }; + host->setNewClientSize(windowSize); + } + } + + return S_OK; + } + + private: + std::weak_ptr mHost; +}; + +HRESULT GetSwapChainPanelSize(const ComPtr &swapChainPanel, RECT *windowSize); +} +#endif // LIBANGLE_RENDERER_D3D_D3D11_WINRT_SWAPCHAINPANELNATIVEWINDOW_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Blit9.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Blit9.cpp new file mode 100644 index 0000000000..a0bc2960b7 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Blit9.cpp @@ -0,0 +1,679 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Blit9.cpp: Surface copy utility class. + +#include "libANGLE/renderer/d3d/d3d9/Blit9.h" +#include "libANGLE/renderer/d3d/d3d9/renderer9_utils.h" +#include "libANGLE/renderer/d3d/d3d9/formatutils9.h" +#include "libANGLE/renderer/d3d/d3d9/TextureStorage9.h" +#include "libANGLE/renderer/d3d/d3d9/RenderTarget9.h" +#include "libANGLE/renderer/d3d/d3d9/Renderer9.h" +#include "libANGLE/angletypes.h" +#include "libANGLE/Framebuffer.h" +#include "libANGLE/FramebufferAttachment.h" + +namespace +{ +// Precompiled shaders +#include "libANGLE/renderer/d3d/d3d9/shaders/compiled/standardvs.h" +#include "libANGLE/renderer/d3d/d3d9/shaders/compiled/flipyvs.h" +#include "libANGLE/renderer/d3d/d3d9/shaders/compiled/passthroughps.h" +#include "libANGLE/renderer/d3d/d3d9/shaders/compiled/luminanceps.h" +#include "libANGLE/renderer/d3d/d3d9/shaders/compiled/componentmaskps.h" + +const BYTE* const g_shaderCode[] = +{ + g_vs20_standardvs, + g_vs20_flipyvs, + g_ps20_passthroughps, + g_ps20_luminanceps, + g_ps20_componentmaskps +}; + +const size_t g_shaderSize[] = +{ + sizeof(g_vs20_standardvs), + sizeof(g_vs20_flipyvs), + sizeof(g_ps20_passthroughps), + sizeof(g_ps20_luminanceps), + sizeof(g_ps20_componentmaskps) +}; +} + +namespace rx +{ + +Blit9::Blit9(Renderer9 *renderer) + : mRenderer(renderer), + mGeometryLoaded(false), + mQuadVertexBuffer(NULL), + mQuadVertexDeclaration(NULL), + mSavedStateBlock(NULL), + mSavedRenderTarget(NULL), + mSavedDepthStencil(NULL) +{ + memset(mCompiledShaders, 0, sizeof(mCompiledShaders)); +} + +Blit9::~Blit9() +{ + SafeRelease(mSavedStateBlock); + SafeRelease(mQuadVertexBuffer); + SafeRelease(mQuadVertexDeclaration); + + for (int i = 0; i < SHADER_COUNT; i++) + { + SafeRelease(mCompiledShaders[i]); + } +} + +gl::Error Blit9::initialize() +{ + if (mGeometryLoaded) + { + return gl::Error(GL_NO_ERROR); + } + + static const float quad[] = + { + -1, -1, + -1, 1, + 1, -1, + 1, 1 + }; + + IDirect3DDevice9 *device = mRenderer->getDevice(); + + HRESULT result = device->CreateVertexBuffer(sizeof(quad), D3DUSAGE_WRITEONLY, 0, D3DPOOL_DEFAULT, &mQuadVertexBuffer, NULL); + + if (FAILED(result)) + { + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal blit vertex shader, result: 0x%X.", result); + } + + void *lockPtr = NULL; + result = mQuadVertexBuffer->Lock(0, 0, &lockPtr, 0); + + if (FAILED(result) || lockPtr == NULL) + { + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); + SafeRelease(mQuadVertexBuffer); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock internal blit vertex shader, result: 0x%X.", result); + } + + memcpy(lockPtr, quad, sizeof(quad)); + mQuadVertexBuffer->Unlock(); + + static const D3DVERTEXELEMENT9 elements[] = + { + { 0, 0, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 }, + D3DDECL_END() + }; + + result = device->CreateVertexDeclaration(elements, &mQuadVertexDeclaration); + + if (FAILED(result)) + { + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); + SafeRelease(mQuadVertexBuffer); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock internal blit vertex declaration, result: 0x%X.", result); + } + + mGeometryLoaded = true; + return gl::Error(GL_NO_ERROR); +} + +template +gl::Error Blit9::setShader(ShaderId source, const char *profile, + gl::Error (Renderer9::*createShader)(const DWORD *, size_t length, D3DShaderType **outShader), + HRESULT (WINAPI IDirect3DDevice9::*setShader)(D3DShaderType*)) +{ + IDirect3DDevice9 *device = mRenderer->getDevice(); + + D3DShaderType *shader; + + if (mCompiledShaders[source] != NULL) + { + shader = static_cast(mCompiledShaders[source]); + } + else + { + const BYTE* shaderCode = g_shaderCode[source]; + size_t shaderSize = g_shaderSize[source]; + + gl::Error error = (mRenderer->*createShader)(reinterpret_cast(shaderCode), shaderSize, &shader); + if (error.isError()) + { + return error; + } + + mCompiledShaders[source] = shader; + } + + HRESULT hr = (device->*setShader)(shader); + if (FAILED(hr)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to set shader for blit operation, result: 0x%X.", hr); + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Blit9::setVertexShader(ShaderId shader) +{ + return setShader(shader, "vs_2_0", &Renderer9::createVertexShader, &IDirect3DDevice9::SetVertexShader); +} + +gl::Error Blit9::setPixelShader(ShaderId shader) +{ + return setShader(shader, "ps_2_0", &Renderer9::createPixelShader, &IDirect3DDevice9::SetPixelShader); +} + +RECT Blit9::getSurfaceRect(IDirect3DSurface9 *surface) const +{ + D3DSURFACE_DESC desc; + surface->GetDesc(&desc); + + RECT rect; + rect.left = 0; + rect.top = 0; + rect.right = desc.Width; + rect.bottom = desc.Height; + + return rect; +} + +gl::Error Blit9::boxFilter(IDirect3DSurface9 *source, IDirect3DSurface9 *dest) +{ + gl::Error error = initialize(); + if (error.isError()) + { + return error; + } + + IDirect3DTexture9 *texture = NULL; + error = copySurfaceToTexture(source, getSurfaceRect(source), &texture); + if (error.isError()) + { + return error; + } + + IDirect3DDevice9 *device = mRenderer->getDevice(); + + saveState(); + + device->SetTexture(0, texture); + device->SetRenderTarget(0, dest); + + setVertexShader(SHADER_VS_STANDARD); + setPixelShader(SHADER_PS_PASSTHROUGH); + + setCommonBlitState(); + device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); + device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); + + setViewport(getSurfaceRect(dest), gl::Offset(0, 0, 0)); + + render(); + + SafeRelease(texture); + + restoreState(); + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Blit9::copy2D(const gl::Framebuffer *framebuffer, const RECT &sourceRect, GLenum destFormat, const gl::Offset &destOffset, TextureStorage *storage, GLint level) +{ + gl::Error error = initialize(); + if (error.isError()) + { + return error; + } + + gl::FramebufferAttachment *colorbuffer = framebuffer->getColorbuffer(0); + ASSERT(colorbuffer); + + RenderTarget9 *renderTarget9 = NULL; + error = d3d9::GetAttachmentRenderTarget(colorbuffer, &renderTarget9); + if (error.isError()) + { + return error; + } + ASSERT(renderTarget9); + + IDirect3DSurface9 *source = renderTarget9->getSurface(); + ASSERT(source); + + IDirect3DSurface9 *destSurface = NULL; + TextureStorage9_2D *storage9 = TextureStorage9_2D::makeTextureStorage9_2D(storage); + error = storage9->getSurfaceLevel(level, true, &destSurface); + if (error.isError()) + { + return error; + } + ASSERT(destSurface); + + gl::Error result = copy(source, sourceRect, destFormat, destOffset, destSurface); + + SafeRelease(destSurface); + SafeRelease(source); + + return result; +} + +gl::Error Blit9::copyCube(const gl::Framebuffer *framebuffer, const RECT &sourceRect, GLenum destFormat, const gl::Offset &destOffset, TextureStorage *storage, GLenum target, GLint level) +{ + gl::Error error = initialize(); + if (error.isError()) + { + return error; + } + + gl::FramebufferAttachment *colorbuffer = framebuffer->getColorbuffer(0); + ASSERT(colorbuffer); + + RenderTarget9 *renderTarget9 = NULL; + error = d3d9::GetAttachmentRenderTarget(colorbuffer, &renderTarget9); + if (error.isError()) + { + return error; + } + ASSERT(renderTarget9); + + IDirect3DSurface9 *source = renderTarget9->getSurface(); + ASSERT(source); + + IDirect3DSurface9 *destSurface = NULL; + TextureStorage9_Cube *storage9 = TextureStorage9_Cube::makeTextureStorage9_Cube(storage); + error = storage9->getCubeMapSurface(target, level, true, &destSurface); + if (error.isError()) + { + return error; + } + ASSERT(destSurface); + + gl::Error result = copy(source, sourceRect, destFormat, destOffset, destSurface); + + SafeRelease(destSurface); + SafeRelease(source); + + return result; +} + +gl::Error Blit9::copy(IDirect3DSurface9 *source, const RECT &sourceRect, GLenum destFormat, const gl::Offset &destOffset, IDirect3DSurface9 *dest) +{ + ASSERT(source != NULL && dest != NULL); + + IDirect3DDevice9 *device = mRenderer->getDevice(); + + D3DSURFACE_DESC sourceDesc; + D3DSURFACE_DESC destDesc; + source->GetDesc(&sourceDesc); + dest->GetDesc(&destDesc); + + if (sourceDesc.Format == destDesc.Format && destDesc.Usage & D3DUSAGE_RENDERTARGET && + d3d9_gl::IsFormatChannelEquivalent(destDesc.Format, destFormat)) // Can use StretchRect + { + RECT destRect = { destOffset.x, destOffset.y, destOffset.x + (sourceRect.right - sourceRect.left), destOffset.y + (sourceRect.bottom - sourceRect.top)}; + HRESULT result = device->StretchRect(source, &sourceRect, dest, &destRect, D3DTEXF_POINT); + + if (FAILED(result)) + { + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to blit between textures, StretchRect result: 0x%X.", result); + } + + return gl::Error(GL_NO_ERROR); + } + else + { + return formatConvert(source, sourceRect, destFormat, destOffset, dest); + } +} + +gl::Error Blit9::formatConvert(IDirect3DSurface9 *source, const RECT &sourceRect, GLenum destFormat, const gl::Offset &destOffset, IDirect3DSurface9 *dest) +{ + gl::Error error = initialize(); + if (error.isError()) + { + return error; + } + + IDirect3DTexture9 *texture = NULL; + error = copySurfaceToTexture(source, sourceRect, &texture); + if (error.isError()) + { + return error; + } + + IDirect3DDevice9 *device = mRenderer->getDevice(); + + saveState(); + + device->SetTexture(0, texture); + device->SetRenderTarget(0, dest); + + setViewport(sourceRect, destOffset); + + setCommonBlitState(); + + error = setFormatConvertShaders(destFormat); + if (!error.isError()) + { + render(); + } + + SafeRelease(texture); + + restoreState(); + + return error; +} + +gl::Error Blit9::setFormatConvertShaders(GLenum destFormat) +{ + gl::Error error = setVertexShader(SHADER_VS_STANDARD); + if (error.isError()) + { + return error; + } + + switch (destFormat) + { + default: UNREACHABLE(); + case GL_RGBA: + case GL_BGRA_EXT: + case GL_RGB: + case GL_RG_EXT: + case GL_RED_EXT: + case GL_ALPHA: + error = setPixelShader(SHADER_PS_COMPONENTMASK); + break; + + case GL_LUMINANCE: + case GL_LUMINANCE_ALPHA: + error = setPixelShader(SHADER_PS_LUMINANCE); + break; + } + + if (error.isError()) + { + return error; + } + + enum { X = 0, Y = 1, Z = 2, W = 3 }; + + // The meaning of this constant depends on the shader that was selected. + // See the shader assembly code above for details. + // Allocate one array for both registers and split it into two float4's. + float psConst[8] = { 0 }; + float *multConst = &psConst[0]; + float *addConst = &psConst[4]; + + switch (destFormat) + { + default: UNREACHABLE(); + case GL_RGBA: + case GL_BGRA_EXT: + multConst[X] = 1; + multConst[Y] = 1; + multConst[Z] = 1; + multConst[W] = 1; + addConst[X] = 0; + addConst[Y] = 0; + addConst[Z] = 0; + addConst[W] = 0; + break; + + case GL_RGB: + multConst[X] = 1; + multConst[Y] = 1; + multConst[Z] = 1; + multConst[W] = 0; + addConst[X] = 0; + addConst[Y] = 0; + addConst[Z] = 0; + addConst[W] = 1; + break; + + case GL_RG_EXT: + multConst[X] = 1; + multConst[Y] = 1; + multConst[Z] = 0; + multConst[W] = 0; + addConst[X] = 0; + addConst[Y] = 0; + addConst[Z] = 0; + addConst[W] = 1; + break; + + case GL_RED_EXT: + multConst[X] = 1; + multConst[Y] = 0; + multConst[Z] = 0; + multConst[W] = 0; + addConst[X] = 0; + addConst[Y] = 0; + addConst[Z] = 0; + addConst[W] = 1; + break; + + case GL_ALPHA: + multConst[X] = 0; + multConst[Y] = 0; + multConst[Z] = 0; + multConst[W] = 1; + addConst[X] = 0; + addConst[Y] = 0; + addConst[Z] = 0; + addConst[W] = 0; + break; + + case GL_LUMINANCE: + multConst[X] = 1; + multConst[Y] = 0; + multConst[Z] = 0; + multConst[W] = 0; + addConst[X] = 0; + addConst[Y] = 0; + addConst[Z] = 0; + addConst[W] = 1; + break; + + case GL_LUMINANCE_ALPHA: + multConst[X] = 1; + multConst[Y] = 0; + multConst[Z] = 0; + multConst[W] = 1; + addConst[X] = 0; + addConst[Y] = 0; + addConst[Z] = 0; + addConst[W] = 0; + break; + } + + mRenderer->getDevice()->SetPixelShaderConstantF(0, psConst, 2); + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Blit9::copySurfaceToTexture(IDirect3DSurface9 *surface, const RECT &sourceRect, IDirect3DTexture9 **outTexture) +{ + ASSERT(surface); + + IDirect3DDevice9 *device = mRenderer->getDevice(); + + D3DSURFACE_DESC sourceDesc; + surface->GetDesc(&sourceDesc); + + // Copy the render target into a texture + IDirect3DTexture9 *texture; + HRESULT result = device->CreateTexture(sourceRect.right - sourceRect.left, sourceRect.bottom - sourceRect.top, 1, D3DUSAGE_RENDERTARGET, sourceDesc.Format, D3DPOOL_DEFAULT, &texture, NULL); + + if (FAILED(result)) + { + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate internal texture for blit, result: 0x%X.", result); + } + + IDirect3DSurface9 *textureSurface; + result = texture->GetSurfaceLevel(0, &textureSurface); + + if (FAILED(result)) + { + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); + SafeRelease(texture); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to query surface of internal blit texture, result: 0x%X.", result); + } + + mRenderer->endScene(); + result = device->StretchRect(surface, &sourceRect, textureSurface, NULL, D3DTEXF_NONE); + + SafeRelease(textureSurface); + + if (FAILED(result)) + { + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); + SafeRelease(texture); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to copy between internal blit textures, result: 0x%X.", result); + } + + *outTexture = texture; + return gl::Error(GL_NO_ERROR); +} + +void Blit9::setViewport(const RECT &sourceRect, const gl::Offset &offset) +{ + IDirect3DDevice9 *device = mRenderer->getDevice(); + + D3DVIEWPORT9 vp; + vp.X = offset.x; + vp.Y = offset.y; + vp.Width = sourceRect.right - sourceRect.left; + vp.Height = sourceRect.bottom - sourceRect.top; + vp.MinZ = 0.0f; + vp.MaxZ = 1.0f; + device->SetViewport(&vp); + + float halfPixelAdjust[4] = { -1.0f/vp.Width, 1.0f/vp.Height, 0, 0 }; + device->SetVertexShaderConstantF(0, halfPixelAdjust, 1); +} + +void Blit9::setCommonBlitState() +{ + IDirect3DDevice9 *device = mRenderer->getDevice(); + + device->SetDepthStencilSurface(NULL); + + device->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID); + device->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE); + device->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); + device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); + device->SetRenderState(D3DRS_CLIPPLANEENABLE, 0); + device->SetRenderState(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_ALPHA | D3DCOLORWRITEENABLE_BLUE | D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_RED); + device->SetRenderState(D3DRS_SRGBWRITEENABLE, FALSE); + device->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE); + + device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT); + device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT); + device->SetSamplerState(0, D3DSAMP_SRGBTEXTURE, FALSE); + device->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); + device->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); + + RECT scissorRect = {0}; // Scissoring is disabled for flipping, but we need this to capture and restore the old rectangle + device->SetScissorRect(&scissorRect); + + for(int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) + { + device->SetStreamSourceFreq(i, 1); + } +} + +void Blit9::render() +{ + IDirect3DDevice9 *device = mRenderer->getDevice(); + + HRESULT hr = device->SetStreamSource(0, mQuadVertexBuffer, 0, 2 * sizeof(float)); + hr = device->SetVertexDeclaration(mQuadVertexDeclaration); + + mRenderer->startScene(); + hr = device->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); +} + +void Blit9::saveState() +{ + IDirect3DDevice9 *device = mRenderer->getDevice(); + + HRESULT hr; + + device->GetDepthStencilSurface(&mSavedDepthStencil); + device->GetRenderTarget(0, &mSavedRenderTarget); + + if (mSavedStateBlock == NULL) + { + hr = device->BeginStateBlock(); + ASSERT(SUCCEEDED(hr) || hr == D3DERR_OUTOFVIDEOMEMORY || hr == E_OUTOFMEMORY); + + setCommonBlitState(); + + static const float dummyConst[8] = { 0 }; + + device->SetVertexShader(NULL); + device->SetVertexShaderConstantF(0, dummyConst, 2); + device->SetPixelShader(NULL); + device->SetPixelShaderConstantF(0, dummyConst, 2); + + D3DVIEWPORT9 dummyVp; + dummyVp.X = 0; + dummyVp.Y = 0; + dummyVp.Width = 1; + dummyVp.Height = 1; + dummyVp.MinZ = 0; + dummyVp.MaxZ = 1; + + device->SetViewport(&dummyVp); + + device->SetTexture(0, NULL); + + device->SetStreamSource(0, mQuadVertexBuffer, 0, 0); + + device->SetVertexDeclaration(mQuadVertexDeclaration); + + hr = device->EndStateBlock(&mSavedStateBlock); + ASSERT(SUCCEEDED(hr) || hr == D3DERR_OUTOFVIDEOMEMORY || hr == E_OUTOFMEMORY); + } + + ASSERT(mSavedStateBlock != NULL); + + if (mSavedStateBlock != NULL) + { + hr = mSavedStateBlock->Capture(); + ASSERT(SUCCEEDED(hr)); + } +} + +void Blit9::restoreState() +{ + IDirect3DDevice9 *device = mRenderer->getDevice(); + + device->SetDepthStencilSurface(mSavedDepthStencil); + SafeRelease(mSavedDepthStencil); + + device->SetRenderTarget(0, mSavedRenderTarget); + SafeRelease(mSavedRenderTarget); + + ASSERT(mSavedStateBlock != NULL); + + if (mSavedStateBlock != NULL) + { + mSavedStateBlock->Apply(); + } +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Blit9.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Blit9.h new file mode 100644 index 0000000000..586abd2580 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Blit9.h @@ -0,0 +1,97 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Blit9.cpp: Surface copy utility class. + +#ifndef LIBANGLE_RENDERER_D3D_D3D9_BLIT9_H_ +#define LIBANGLE_RENDERER_D3D_D3D9_BLIT9_H_ + +#include "common/angleutils.h" +#include "libANGLE/Error.h" + +#include + +namespace gl +{ +class Framebuffer; +struct Offset; +} + +namespace rx +{ +class Renderer9; +class TextureStorage; + +class Blit9 : angle::NonCopyable +{ + public: + explicit Blit9(Renderer9 *renderer); + ~Blit9(); + + gl::Error initialize(); + + // Copy from source surface to dest surface. + // sourceRect, xoffset, yoffset are in D3D coordinates (0,0 in upper-left) + gl::Error copy2D(const gl::Framebuffer *framebuffer, const RECT &sourceRect, GLenum destFormat, const gl::Offset &destOffset, TextureStorage *storage, GLint level); + gl::Error copyCube(const gl::Framebuffer *framebuffer, const RECT &sourceRect, GLenum destFormat, const gl::Offset &destOffset, TextureStorage *storage, GLenum target, GLint level); + + // Copy from source surface to dest surface. + // sourceRect, xoffset, yoffset are in D3D coordinates (0,0 in upper-left) + // source is interpreted as RGBA and destFormat specifies the desired result format. For example, if destFormat = GL_RGB, the alpha channel will be forced to 0. + gl::Error formatConvert(IDirect3DSurface9 *source, const RECT &sourceRect, GLenum destFormat, const gl::Offset &destOffset, IDirect3DSurface9 *dest); + + // 2x2 box filter sample from source to dest. + // Requires that source is RGB(A) and dest has the same format as source. + gl::Error boxFilter(IDirect3DSurface9 *source, IDirect3DSurface9 *dest); + + private: + Renderer9 *mRenderer; + + bool mGeometryLoaded; + IDirect3DVertexBuffer9 *mQuadVertexBuffer; + IDirect3DVertexDeclaration9 *mQuadVertexDeclaration; + + gl::Error setFormatConvertShaders(GLenum destFormat); + + gl::Error copy(IDirect3DSurface9 *source, const RECT &sourceRect, GLenum destFormat, const gl::Offset &destOffset, IDirect3DSurface9 *dest); + gl::Error copySurfaceToTexture(IDirect3DSurface9 *surface, const RECT &sourceRect, IDirect3DTexture9 **outTexture); + void setViewport(const RECT &sourceRect, const gl::Offset &offset); + void setCommonBlitState(); + RECT getSurfaceRect(IDirect3DSurface9 *surface) const; + + // This enum is used to index mCompiledShaders and mShaderSource. + enum ShaderId + { + SHADER_VS_STANDARD, + SHADER_VS_FLIPY, + SHADER_PS_PASSTHROUGH, + SHADER_PS_LUMINANCE, + SHADER_PS_COMPONENTMASK, + SHADER_COUNT + }; + + // This actually contains IDirect3DVertexShader9 or IDirect3DPixelShader9 casted to IUnknown. + IUnknown *mCompiledShaders[SHADER_COUNT]; + + template + gl::Error setShader(ShaderId source, const char *profile, + gl::Error (Renderer9::*createShader)(const DWORD *, size_t length, D3DShaderType **outShader), + HRESULT (WINAPI IDirect3DDevice9::*setShader)(D3DShaderType*)); + + gl::Error setVertexShader(ShaderId shader); + gl::Error setPixelShader(ShaderId shader); + void render(); + + void saveState(); + void restoreState(); + IDirect3DStateBlock9 *mSavedStateBlock; + IDirect3DSurface9 *mSavedRenderTarget; + IDirect3DSurface9 *mSavedDepthStencil; +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_D3D9_BLIT9_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Buffer9.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Buffer9.cpp new file mode 100644 index 0000000000..b051c81aa8 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Buffer9.cpp @@ -0,0 +1,116 @@ +// +// Copyright 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Buffer9.cpp Defines the Buffer9 class. + +#include "libANGLE/renderer/d3d/d3d9/Buffer9.h" +#include "libANGLE/renderer/d3d/d3d9/Renderer9.h" + +namespace rx +{ + +Buffer9::Buffer9(Renderer9 *renderer) + : BufferD3D(renderer), + mRenderer(renderer), + mSize(0) +{} + +Buffer9::~Buffer9() +{ + mSize = 0; +} + +Buffer9 *Buffer9::makeBuffer9(BufferImpl *buffer) +{ + ASSERT(HAS_DYNAMIC_TYPE(Buffer9*, buffer)); + return static_cast(buffer); +} + +gl::Error Buffer9::setData(const void* data, size_t size, GLenum usage) +{ + if (size > mMemory.size()) + { + if (!mMemory.resize(size)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to resize internal buffer."); + } + } + + mSize = size; + if (data && size > 0) + { + memcpy(mMemory.data(), data, size); + } + + invalidateStaticData(); + + if (usage == GL_STATIC_DRAW) + { + initializeStaticData(); + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Buffer9::getData(const uint8_t **outData) +{ + *outData = mMemory.data(); + return gl::Error(GL_NO_ERROR); +} + +gl::Error Buffer9::setSubData(const void* data, size_t size, size_t offset) +{ + if (offset + size > mMemory.size()) + { + if (!mMemory.resize(offset + size)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to resize internal buffer."); + } + } + + mSize = std::max(mSize, offset + size); + if (data && size > 0) + { + memcpy(mMemory.data() + offset, data, size); + } + + invalidateStaticData(); + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Buffer9::copySubData(BufferImpl* source, GLintptr sourceOffset, GLintptr destOffset, GLsizeiptr size) +{ + // Note: this method is currently unreachable + Buffer9* sourceBuffer = makeBuffer9(source); + ASSERT(sourceBuffer); + + memcpy(mMemory.data() + destOffset, sourceBuffer->mMemory.data() + sourceOffset, size); + + invalidateStaticData(); + + return gl::Error(GL_NO_ERROR); +} + +// We do not support buffer mapping in D3D9 +gl::Error Buffer9::map(size_t offset, size_t length, GLbitfield access, GLvoid **mapPtr) +{ + UNREACHABLE(); + return gl::Error(GL_INVALID_OPERATION); +} + +gl::Error Buffer9::unmap() +{ + UNREACHABLE(); + return gl::Error(GL_INVALID_OPERATION); +} + +void Buffer9::markTransformFeedbackUsage() +{ + UNREACHABLE(); +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Buffer9.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Buffer9.h new file mode 100644 index 0000000000..c1984146fc --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Buffer9.h @@ -0,0 +1,49 @@ +// +// Copyright 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Buffer9.h: Defines the rx::Buffer9 class which implements rx::BufferImpl via rx::BufferD3D. + +#ifndef LIBANGLE_RENDERER_D3D_D3D9_BUFFER9_H_ +#define LIBANGLE_RENDERER_D3D_D3D9_BUFFER9_H_ + +#include "common/MemoryBuffer.h" +#include "libANGLE/angletypes.h" +#include "libANGLE/renderer/d3d/BufferD3D.h" + +namespace rx +{ +class Renderer9; + +class Buffer9 : public BufferD3D +{ + public: + Buffer9(Renderer9 *renderer); + virtual ~Buffer9(); + + static Buffer9 *makeBuffer9(BufferImpl *buffer); + + // BufferD3D implementation + virtual size_t getSize() const { return mSize; } + virtual bool supportsDirectBinding() const { return false; } + + // BufferImpl implementation + virtual gl::Error setData(const void* data, size_t size, GLenum usage); + gl::Error getData(const uint8_t **outData) override; + virtual gl::Error setSubData(const void* data, size_t size, size_t offset); + virtual gl::Error copySubData(BufferImpl* source, GLintptr sourceOffset, GLintptr destOffset, GLsizeiptr size); + virtual gl::Error map(size_t offset, size_t length, GLbitfield access, GLvoid **mapPtr); + virtual gl::Error unmap(); + virtual void markTransformFeedbackUsage(); + + private: + Renderer9 *mRenderer; + MemoryBuffer mMemory; + size_t mSize; +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_D3D9_BUFFER9_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/DebugAnnotator9.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/DebugAnnotator9.cpp new file mode 100644 index 0000000000..09b229bcb1 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/DebugAnnotator9.cpp @@ -0,0 +1,36 @@ +// +// Copyright 2015 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// DebugAnnotator9.h: D3D9 helpers for adding trace annotations. +// + +#include "libANGLE/renderer/d3d/d3d9/DebugAnnotator9.h" + +#include "common/platform.h" + +namespace rx +{ + +void DebugAnnotator9::beginEvent(const std::wstring &eventName) +{ + D3DPERF_BeginEvent(0, eventName.c_str()); +} + +void DebugAnnotator9::endEvent() +{ + D3DPERF_EndEvent(); +} + +void DebugAnnotator9::setMarker(const std::wstring &markerName) +{ + D3DPERF_SetMarker(0, markerName.c_str()); +} + +bool DebugAnnotator9::getStatus() +{ + return !!D3DPERF_GetStatus(); +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/DebugAnnotator9.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/DebugAnnotator9.h new file mode 100644 index 0000000000..02956f7183 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/DebugAnnotator9.h @@ -0,0 +1,29 @@ +// +// Copyright 2015 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// DebugAnnotator9.h: D3D9 helpers for adding trace annotations. +// + +#ifndef LIBANGLE_RENDERER_D3D_D3D9_DEBUGANNOTATOR9_H_ +#define LIBANGLE_RENDERER_D3D_D3D9_DEBUGANNOTATOR9_H_ + +#include "common/debug.h" + +namespace rx +{ + +class DebugAnnotator9 : public gl::DebugAnnotator +{ + public: + DebugAnnotator9() {} + void beginEvent(const std::wstring &eventName) override; + void endEvent() override; + void setMarker(const std::wstring &markerName) override; + bool getStatus() override; +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_D3D9_DEBUGANNOTATOR9_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Fence9.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Fence9.cpp new file mode 100644 index 0000000000..27c265e28d --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Fence9.cpp @@ -0,0 +1,90 @@ +// +// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Fence9.cpp: Defines the rx::FenceNV9 class. + +#include "libANGLE/renderer/d3d/d3d9/Fence9.h" +#include "libANGLE/renderer/d3d/d3d9/renderer9_utils.h" +#include "libANGLE/renderer/d3d/d3d9/Renderer9.h" + +namespace rx +{ + +FenceNV9::FenceNV9(Renderer9 *renderer) + : FenceNVImpl(), + mRenderer(renderer), + mQuery(NULL) +{ +} + +FenceNV9::~FenceNV9() +{ + SafeRelease(mQuery); +} + +gl::Error FenceNV9::set() +{ + if (!mQuery) + { + gl::Error error = mRenderer->allocateEventQuery(&mQuery); + if (error.isError()) + { + return error; + } + } + + HRESULT result = mQuery->Issue(D3DISSUE_END); + if (FAILED(result)) + { + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); + SafeRelease(mQuery); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to end event query, result: 0x%X.", result); + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error FenceNV9::test(bool flushCommandBuffer, GLboolean *outFinished) +{ + ASSERT(mQuery); + + DWORD getDataFlags = (flushCommandBuffer ? D3DGETDATA_FLUSH : 0); + HRESULT result = mQuery->GetData(NULL, 0, getDataFlags); + + if (d3d9::isDeviceLostError(result)) + { + mRenderer->notifyDeviceLost(); + return gl::Error(GL_OUT_OF_MEMORY, "Device was lost while querying result of an event query."); + } + else if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to get query data, result: 0x%X.", result); + } + + ASSERT(result == S_OK || result == S_FALSE); + *outFinished = ((result == S_OK) ? GL_TRUE : GL_FALSE); + return gl::Error(GL_NO_ERROR); +} + +gl::Error FenceNV9::finishFence(GLboolean *outFinished) +{ + ASSERT(outFinished); + + while (*outFinished != GL_TRUE) + { + gl::Error error = test(true, outFinished); + if (error.isError()) + { + return error; + } + + Sleep(0); + } + + return gl::Error(GL_NO_ERROR); +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Fence9.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Fence9.h new file mode 100644 index 0000000000..4b86747396 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Fence9.h @@ -0,0 +1,36 @@ +// +// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Fence9.h: Defines the rx::FenceNV9 class which implements rx::FenceNVImpl. + +#ifndef LIBANGLE_RENDERER_D3D_D3D9_FENCE9_H_ +#define LIBANGLE_RENDERER_D3D_D3D9_FENCE9_H_ + +#include "libANGLE/renderer/FenceNVImpl.h" +#include "libANGLE/renderer/FenceSyncImpl.h" + +namespace rx +{ +class Renderer9; + +class FenceNV9 : public FenceNVImpl +{ + public: + explicit FenceNV9(Renderer9 *renderer); + virtual ~FenceNV9(); + + gl::Error set(); + gl::Error test(bool flushCommandBuffer, GLboolean *outFinished); + gl::Error finishFence(GLboolean *outFinished); + + private: + Renderer9 *mRenderer; + IDirect3DQuery9 *mQuery; +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_D3D9_FENCE9_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Framebuffer9.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Framebuffer9.cpp new file mode 100644 index 0000000000..dbdfc6d6de --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Framebuffer9.cpp @@ -0,0 +1,422 @@ +// +// Copyright 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Framebuffer9.cpp: Implements the Framebuffer9 class. + +#include "libANGLE/renderer/d3d/d3d9/Framebuffer9.h" +#include "libANGLE/renderer/d3d/d3d9/formatutils9.h" +#include "libANGLE/renderer/d3d/d3d9/TextureStorage9.h" +#include "libANGLE/renderer/d3d/d3d9/Renderer9.h" +#include "libANGLE/renderer/d3d/d3d9/renderer9_utils.h" +#include "libANGLE/renderer/d3d/d3d9/RenderTarget9.h" +#include "libANGLE/renderer/d3d/TextureD3D.h" +#include "libANGLE/formatutils.h" +#include "libANGLE/Framebuffer.h" +#include "libANGLE/FramebufferAttachment.h" +#include "libANGLE/Texture.h" + +namespace rx +{ + +Framebuffer9::Framebuffer9(const gl::Framebuffer::Data &data, Renderer9 *renderer) + : FramebufferD3D(data, renderer), + mRenderer(renderer) +{ + ASSERT(mRenderer != nullptr); +} + +Framebuffer9::~Framebuffer9() +{ +} + +gl::Error Framebuffer9::clear(const gl::State &state, const ClearParameters &clearParams) +{ + const gl::FramebufferAttachment *colorAttachment = mData.mColorAttachments[0]; + const gl::FramebufferAttachment *depthStencilAttachment = mData.getDepthOrStencilAttachment(); + + gl::Error error = mRenderer->applyRenderTarget(colorAttachment, depthStencilAttachment); + if (error.isError()) + { + return error; + } + + float nearZ, farZ; + state.getDepthRange(&nearZ, &farZ); + mRenderer->setViewport(state.getViewport(), nearZ, farZ, GL_TRIANGLES, state.getRasterizerState().frontFace, true); + + mRenderer->setScissorRectangle(state.getScissor(), state.isScissorTestEnabled()); + + return mRenderer->clear(clearParams, colorAttachment, depthStencilAttachment); +} + +gl::Error Framebuffer9::readPixels(const gl::Rectangle &area, GLenum format, GLenum type, size_t outputPitch, const gl::PixelPackState &pack, uint8_t *pixels) const +{ + ASSERT(pack.pixelBuffer.get() == NULL); + + const gl::FramebufferAttachment *colorbuffer = mData.mColorAttachments[0]; + ASSERT(colorbuffer); + + RenderTarget9 *renderTarget = NULL; + gl::Error error = d3d9::GetAttachmentRenderTarget(colorbuffer, &renderTarget); + if (error.isError()) + { + return error; + } + ASSERT(renderTarget); + + IDirect3DSurface9 *surface = renderTarget->getSurface(); + ASSERT(surface); + + D3DSURFACE_DESC desc; + surface->GetDesc(&desc); + + if (desc.MultiSampleType != D3DMULTISAMPLE_NONE) + { + UNIMPLEMENTED(); // FIXME: Requires resolve using StretchRect into non-multisampled render target + SafeRelease(surface); + return gl::Error(GL_OUT_OF_MEMORY, "ReadPixels is unimplemented for multisampled framebuffer attachments."); + } + + IDirect3DDevice9 *device = mRenderer->getDevice(); + ASSERT(device); + + HRESULT result; + IDirect3DSurface9 *systemSurface = NULL; + bool directToPixels = !pack.reverseRowOrder && pack.alignment <= 4 && mRenderer->getShareHandleSupport() && + area.x == 0 && area.y == 0 && + static_cast(area.width) == desc.Width && static_cast(area.height) == desc.Height && + desc.Format == D3DFMT_A8R8G8B8 && format == GL_BGRA_EXT && type == GL_UNSIGNED_BYTE; + if (directToPixels) + { + // Use the pixels ptr as a shared handle to write directly into client's memory + result = device->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format, + D3DPOOL_SYSTEMMEM, &systemSurface, reinterpret_cast(&pixels)); + if (FAILED(result)) + { + // Try again without the shared handle + directToPixels = false; + } + } + + if (!directToPixels) + { + result = device->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format, + D3DPOOL_SYSTEMMEM, &systemSurface, NULL); + if (FAILED(result)) + { + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); + SafeRelease(surface); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate internal texture for ReadPixels."); + } + } + + result = device->GetRenderTargetData(surface, systemSurface); + SafeRelease(surface); + + if (FAILED(result)) + { + SafeRelease(systemSurface); + + // It turns out that D3D will sometimes produce more error + // codes than those documented. + if (d3d9::isDeviceLostError(result)) + { + mRenderer->notifyDeviceLost(); + } + else + { + UNREACHABLE(); + } + + return gl::Error(GL_OUT_OF_MEMORY, "Failed to read internal render target data."); + } + + if (directToPixels) + { + SafeRelease(systemSurface); + return gl::Error(GL_NO_ERROR); + } + + RECT rect; + rect.left = gl::clamp(area.x, 0L, static_cast(desc.Width)); + rect.top = gl::clamp(area.y, 0L, static_cast(desc.Height)); + rect.right = gl::clamp(area.x + area.width, 0L, static_cast(desc.Width)); + rect.bottom = gl::clamp(area.y + area.height, 0L, static_cast(desc.Height)); + + D3DLOCKED_RECT lock; + result = systemSurface->LockRect(&lock, &rect, D3DLOCK_READONLY); + + if (FAILED(result)) + { + UNREACHABLE(); + SafeRelease(systemSurface); + + return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock internal render target."); + } + + uint8_t *source; + int inputPitch; + if (pack.reverseRowOrder) + { + source = reinterpret_cast(lock.pBits) + lock.Pitch * (rect.bottom - rect.top - 1); + inputPitch = -lock.Pitch; + } + else + { + source = reinterpret_cast(lock.pBits); + inputPitch = lock.Pitch; + } + + const d3d9::D3DFormat &d3dFormatInfo = d3d9::GetD3DFormatInfo(desc.Format); + const gl::InternalFormat &sourceFormatInfo = gl::GetInternalFormatInfo(d3dFormatInfo.internalFormat); + if (sourceFormatInfo.format == format && sourceFormatInfo.type == type) + { + // Direct copy possible + for (int y = 0; y < rect.bottom - rect.top; y++) + { + memcpy(pixels + y * outputPitch, source + y * inputPitch, (rect.right - rect.left) * sourceFormatInfo.pixelBytes); + } + } + else + { + const d3d9::D3DFormat &sourceD3DFormatInfo = d3d9::GetD3DFormatInfo(desc.Format); + ColorCopyFunction fastCopyFunc = sourceD3DFormatInfo.getFastCopyFunction(format, type); + + GLenum sizedDestInternalFormat = gl::GetSizedInternalFormat(format, type); + const gl::InternalFormat &destFormatInfo = gl::GetInternalFormatInfo(sizedDestInternalFormat); + + if (fastCopyFunc) + { + // Fast copy is possible through some special function + for (int y = 0; y < rect.bottom - rect.top; y++) + { + for (int x = 0; x < rect.right - rect.left; x++) + { + uint8_t *dest = pixels + y * outputPitch + x * destFormatInfo.pixelBytes; + const uint8_t *src = source + y * inputPitch + x * sourceFormatInfo.pixelBytes; + + fastCopyFunc(src, dest); + } + } + } + else + { + ColorReadFunction colorReadFunction = sourceD3DFormatInfo.colorReadFunction; + ColorWriteFunction colorWriteFunction = GetColorWriteFunction(format, type); + + uint8_t temp[sizeof(gl::ColorF)]; + for (int y = 0; y < rect.bottom - rect.top; y++) + { + for (int x = 0; x < rect.right - rect.left; x++) + { + uint8_t *dest = pixels + y * outputPitch + x * destFormatInfo.pixelBytes; + const uint8_t *src = source + y * inputPitch + x * sourceFormatInfo.pixelBytes; + + // readFunc and writeFunc will be using the same type of color, CopyTexImage + // will not allow the copy otherwise. + colorReadFunction(src, temp); + colorWriteFunction(temp, dest); + } + } + } + } + + systemSurface->UnlockRect(); + SafeRelease(systemSurface); + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Framebuffer9::blit(const gl::Rectangle &sourceArea, const gl::Rectangle &destArea, const gl::Rectangle *scissor, + bool blitRenderTarget, bool blitDepth, bool blitStencil, GLenum filter, + const gl::Framebuffer *sourceFramebuffer) +{ + ASSERT(filter == GL_NEAREST); + + IDirect3DDevice9 *device = mRenderer->getDevice(); + ASSERT(device); + + mRenderer->endScene(); + + if (blitRenderTarget) + { + const gl::FramebufferAttachment *readBuffer = sourceFramebuffer->getColorbuffer(0); + ASSERT(readBuffer); + + RenderTarget9 *readRenderTarget = NULL; + gl::Error error = d3d9::GetAttachmentRenderTarget(readBuffer, &readRenderTarget); + if (error.isError()) + { + return error; + } + ASSERT(readRenderTarget); + + const gl::FramebufferAttachment *drawBuffer = mData.mColorAttachments[0]; + ASSERT(drawBuffer); + + RenderTarget9 *drawRenderTarget = NULL; + error = d3d9::GetAttachmentRenderTarget(drawBuffer, &drawRenderTarget); + if (error.isError()) + { + return error; + } + ASSERT(drawRenderTarget); + + // The getSurface calls do an AddRef so save them until after no errors are possible + IDirect3DSurface9* readSurface = readRenderTarget->getSurface(); + ASSERT(readSurface); + + IDirect3DSurface9* drawSurface = drawRenderTarget->getSurface(); + ASSERT(drawSurface); + + gl::Extents srcSize(readRenderTarget->getWidth(), readRenderTarget->getHeight(), 1); + gl::Extents dstSize(drawRenderTarget->getWidth(), drawRenderTarget->getHeight(), 1); + + RECT srcRect; + srcRect.left = sourceArea.x; + srcRect.right = sourceArea.x + sourceArea.width; + srcRect.top = sourceArea.y; + srcRect.bottom = sourceArea.y + sourceArea.height; + + RECT dstRect; + dstRect.left = destArea.x; + dstRect.right = destArea.x + destArea.width; + dstRect.top = destArea.y; + dstRect.bottom = destArea.y + destArea.height; + + // Clip the rectangles to the scissor rectangle + if (scissor) + { + if (dstRect.left < scissor->x) + { + srcRect.left += (scissor->x - dstRect.left); + dstRect.left = scissor->x; + } + if (dstRect.top < scissor->y) + { + srcRect.top += (scissor->y - dstRect.top); + dstRect.top = scissor->y; + } + if (dstRect.right > scissor->x + scissor->width) + { + srcRect.right -= (dstRect.right - (scissor->x + scissor->width)); + dstRect.right = scissor->x + scissor->width; + } + if (dstRect.bottom > scissor->y + scissor->height) + { + srcRect.bottom -= (dstRect.bottom - (scissor->y + scissor->height)); + dstRect.bottom = scissor->y + scissor->height; + } + } + + // Clip the rectangles to the destination size + if (dstRect.left < 0) + { + srcRect.left += -dstRect.left; + dstRect.left = 0; + } + if (dstRect.right > dstSize.width) + { + srcRect.right -= (dstRect.right - dstSize.width); + dstRect.right = dstSize.width; + } + if (dstRect.top < 0) + { + srcRect.top += -dstRect.top; + dstRect.top = 0; + } + if (dstRect.bottom > dstSize.height) + { + srcRect.bottom -= (dstRect.bottom - dstSize.height); + dstRect.bottom = dstSize.height; + } + + // Clip the rectangles to the source size + if (srcRect.left < 0) + { + dstRect.left += -srcRect.left; + srcRect.left = 0; + } + if (srcRect.right > srcSize.width) + { + dstRect.right -= (srcRect.right - srcSize.width); + srcRect.right = srcSize.width; + } + if (srcRect.top < 0) + { + dstRect.top += -srcRect.top; + srcRect.top = 0; + } + if (srcRect.bottom > srcSize.height) + { + dstRect.bottom -= (srcRect.bottom - srcSize.height); + srcRect.bottom = srcSize.height; + } + + HRESULT result = device->StretchRect(readSurface, &srcRect, drawSurface, &dstRect, D3DTEXF_NONE); + + SafeRelease(readSurface); + SafeRelease(drawSurface); + + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Internal blit failed, StretchRect returned 0x%X.", result); + } + } + + if (blitDepth || blitStencil) + { + const gl::FramebufferAttachment *readBuffer = sourceFramebuffer->getDepthOrStencilbuffer(); + ASSERT(readBuffer); + + RenderTarget9 *readDepthStencil = NULL; + gl::Error error = d3d9::GetAttachmentRenderTarget(readBuffer, &readDepthStencil); + if (error.isError()) + { + return error; + } + ASSERT(readDepthStencil); + + const gl::FramebufferAttachment *drawBuffer = mData.getDepthOrStencilAttachment(); + ASSERT(drawBuffer); + + RenderTarget9 *drawDepthStencil = NULL; + error = d3d9::GetAttachmentRenderTarget(drawBuffer, &drawDepthStencil); + if (error.isError()) + { + return error; + } + ASSERT(drawDepthStencil); + + // The getSurface calls do an AddRef so save them until after no errors are possible + IDirect3DSurface9* readSurface = readDepthStencil->getSurface(); + ASSERT(readDepthStencil); + + IDirect3DSurface9* drawSurface = drawDepthStencil->getSurface(); + ASSERT(drawDepthStencil); + + HRESULT result = device->StretchRect(readSurface, NULL, drawSurface, NULL, D3DTEXF_NONE); + + SafeRelease(readSurface); + SafeRelease(drawSurface); + + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Internal blit failed, StretchRect returned 0x%X.", result); + } + } + + return gl::Error(GL_NO_ERROR); +} + +GLenum Framebuffer9::getRenderTargetImplementationFormat(RenderTargetD3D *renderTarget) const +{ + RenderTarget9 *renderTarget9 = RenderTarget9::makeRenderTarget9(renderTarget); + const d3d9::D3DFormat &d3dFormatInfo = d3d9::GetD3DFormatInfo(renderTarget9->getD3DFormat()); + return d3dFormatInfo.internalFormat; +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Framebuffer9.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Framebuffer9.h new file mode 100644 index 0000000000..292118e6db --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Framebuffer9.h @@ -0,0 +1,41 @@ +// +// Copyright 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Framebuffer9.h: Defines the Framebuffer9 class. + +#ifndef LIBANGLE_RENDERER_D3D_D3D9_FRAMBUFFER9_H_ +#define LIBANGLE_RENDERER_D3D_D3D9_FRAMBUFFER9_H_ + +#include "libANGLE/renderer/d3d/FramebufferD3D.h" + +namespace rx +{ +class Renderer9; + +class Framebuffer9 : public FramebufferD3D +{ + public: + Framebuffer9(const gl::Framebuffer::Data &data, Renderer9 *renderer); + virtual ~Framebuffer9(); + + private: + gl::Error clear(const gl::State &state, const ClearParameters &clearParams) override; + + gl::Error readPixels(const gl::Rectangle &area, GLenum format, GLenum type, size_t outputPitch, + const gl::PixelPackState &pack, uint8_t *pixels) const override; + + gl::Error blit(const gl::Rectangle &sourceArea, const gl::Rectangle &destArea, const gl::Rectangle *scissor, + bool blitRenderTarget, bool blitDepth, bool blitStencil, GLenum filter, + const gl::Framebuffer *sourceFramebuffer) override; + + GLenum getRenderTargetImplementationFormat(RenderTargetD3D *renderTarget) const override; + + Renderer9 *const mRenderer; +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_D3D9_FRAMBUFFER9_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Image9.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Image9.cpp new file mode 100644 index 0000000000..d149f7a806 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Image9.cpp @@ -0,0 +1,788 @@ +// +// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Image9.cpp: Implements the rx::Image9 class, which acts as the interface to +// the actual underlying surfaces of a Texture. + +#include "libANGLE/renderer/d3d/d3d9/Image9.h" +#include "libANGLE/renderer/d3d/d3d9/renderer9_utils.h" +#include "libANGLE/renderer/d3d/d3d9/formatutils9.h" +#include "libANGLE/renderer/d3d/d3d9/Renderer9.h" +#include "libANGLE/renderer/d3d/d3d9/RenderTarget9.h" +#include "libANGLE/renderer/d3d/d3d9/TextureStorage9.h" +#include "libANGLE/formatutils.h" +#include "libANGLE/Framebuffer.h" +#include "libANGLE/FramebufferAttachment.h" +#include "libANGLE/Renderbuffer.h" +#include "common/utilities.h" + +namespace rx +{ + +Image9::Image9(Renderer9 *renderer) +{ + mSurface = NULL; + mRenderer = NULL; + + mD3DPool = D3DPOOL_SYSTEMMEM; + mD3DFormat = D3DFMT_UNKNOWN; + + mRenderer = renderer; +} + +Image9::~Image9() +{ + SafeRelease(mSurface); +} + +gl::Error Image9::generateMip(IDirect3DSurface9 *destSurface, IDirect3DSurface9 *sourceSurface) +{ + D3DSURFACE_DESC destDesc; + HRESULT result = destSurface->GetDesc(&destDesc); + ASSERT(SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to query the source surface description for mipmap generation, result: 0x%X.", result); + } + + D3DSURFACE_DESC sourceDesc; + result = sourceSurface->GetDesc(&sourceDesc); + ASSERT(SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to query the destination surface description for mipmap generation, result: 0x%X.", result); + } + + ASSERT(sourceDesc.Format == destDesc.Format); + ASSERT(sourceDesc.Width == 1 || sourceDesc.Width / 2 == destDesc.Width); + ASSERT(sourceDesc.Height == 1 || sourceDesc.Height / 2 == destDesc.Height); + + const d3d9::D3DFormat &d3dFormatInfo = d3d9::GetD3DFormatInfo(sourceDesc.Format); + ASSERT(d3dFormatInfo.mipGenerationFunction != NULL); + + D3DLOCKED_RECT sourceLocked = {0}; + result = sourceSurface->LockRect(&sourceLocked, NULL, D3DLOCK_READONLY); + ASSERT(SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock the source surface for mipmap generation, result: 0x%X.", result); + } + + D3DLOCKED_RECT destLocked = {0}; + result = destSurface->LockRect(&destLocked, NULL, 0); + ASSERT(SUCCEEDED(result)); + if (FAILED(result)) + { + sourceSurface->UnlockRect(); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock the destination surface for mipmap generation, result: 0x%X.", result); + } + + const uint8_t *sourceData = reinterpret_cast(sourceLocked.pBits); + uint8_t *destData = reinterpret_cast(destLocked.pBits); + + ASSERT(sourceData && destData); + + d3dFormatInfo.mipGenerationFunction(sourceDesc.Width, sourceDesc.Height, 1, sourceData, sourceLocked.Pitch, 0, + destData, destLocked.Pitch, 0); + + destSurface->UnlockRect(); + sourceSurface->UnlockRect(); + + return gl::Error(GL_NO_ERROR); +} + +Image9 *Image9::makeImage9(ImageD3D *img) +{ + ASSERT(HAS_DYNAMIC_TYPE(Image9*, img)); + return static_cast(img); +} + +gl::Error Image9::generateMipmap(Image9 *dest, Image9 *source) +{ + IDirect3DSurface9 *sourceSurface = NULL; + gl::Error error = source->getSurface(&sourceSurface); + if (error.isError()) + { + return error; + } + + IDirect3DSurface9 *destSurface = NULL; + error = dest->getSurface(&destSurface); + if (error.isError()) + { + return error; + } + + error = generateMip(destSurface, sourceSurface); + if (error.isError()) + { + return error; + } + + dest->markDirty(); + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Image9::copyLockableSurfaces(IDirect3DSurface9 *dest, IDirect3DSurface9 *source) +{ + D3DLOCKED_RECT sourceLock = {0}; + D3DLOCKED_RECT destLock = {0}; + + HRESULT result; + + result = source->LockRect(&sourceLock, NULL, 0); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock source surface for copy, result: 0x%X.", result); + } + + result = dest->LockRect(&destLock, NULL, 0); + if (FAILED(result)) + { + source->UnlockRect(); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock source surface for copy, result: 0x%X.", result); + } + + ASSERT(sourceLock.pBits && destLock.pBits); + + D3DSURFACE_DESC desc; + source->GetDesc(&desc); + + const d3d9::D3DFormat &d3dFormatInfo = d3d9::GetD3DFormatInfo(desc.Format); + unsigned int rows = desc.Height / d3dFormatInfo.blockHeight; + + unsigned int bytes = d3d9::ComputeBlockSize(desc.Format, desc.Width, d3dFormatInfo.blockHeight); + ASSERT(bytes <= static_cast(sourceLock.Pitch) && + bytes <= static_cast(destLock.Pitch)); + + for(unsigned int i = 0; i < rows; i++) + { + memcpy((char*)destLock.pBits + destLock.Pitch * i, (char*)sourceLock.pBits + sourceLock.Pitch * i, bytes); + } + + source->UnlockRect(); + dest->UnlockRect(); + + return gl::Error(GL_NO_ERROR); +} + +bool Image9::redefine(GLenum target, GLenum internalformat, const gl::Extents &size, bool forceRelease) +{ + // 3D textures are not supported by the D3D9 backend. + ASSERT(size.depth <= 1); + + // Only 2D and cube texture are supported by the D3D9 backend. + ASSERT(target == GL_TEXTURE_2D || target == GL_TEXTURE_CUBE_MAP); + + if (mWidth != size.width || + mHeight != size.height || + mDepth != size.depth || + mInternalFormat != internalformat || + forceRelease) + { + mWidth = size.width; + mHeight = size.height; + mDepth = size.depth; + mInternalFormat = internalformat; + + // compute the d3d format that will be used + const d3d9::TextureFormat &d3d9FormatInfo = d3d9::GetTextureFormatInfo(internalformat); + mD3DFormat = d3d9FormatInfo.texFormat; + mRenderable = (d3d9FormatInfo.renderFormat != D3DFMT_UNKNOWN); + + SafeRelease(mSurface); + mDirty = (d3d9FormatInfo.dataInitializerFunction != NULL); + + return true; + } + + return false; +} + +gl::Error Image9::createSurface() +{ + if (mSurface) + { + return gl::Error(GL_NO_ERROR); + } + + IDirect3DTexture9 *newTexture = NULL; + IDirect3DSurface9 *newSurface = NULL; + const D3DPOOL poolToUse = D3DPOOL_SYSTEMMEM; + const D3DFORMAT d3dFormat = getD3DFormat(); + + if (mWidth != 0 && mHeight != 0) + { + int levelToFetch = 0; + GLsizei requestWidth = mWidth; + GLsizei requestHeight = mHeight; + d3d9::MakeValidSize(true, d3dFormat, &requestWidth, &requestHeight, &levelToFetch); + + IDirect3DDevice9 *device = mRenderer->getDevice(); + + HRESULT result = device->CreateTexture(requestWidth, requestHeight, levelToFetch + 1, 0, d3dFormat, + poolToUse, &newTexture, NULL); + + if (FAILED(result)) + { + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create image surface, result: 0x%X.", result); + } + + newTexture->GetSurfaceLevel(levelToFetch, &newSurface); + SafeRelease(newTexture); + + const d3d9::TextureFormat &d3dFormatInfo = d3d9::GetTextureFormatInfo(mInternalFormat); + if (d3dFormatInfo.dataInitializerFunction != NULL) + { + RECT entireRect; + entireRect.left = 0; + entireRect.right = mWidth; + entireRect.top = 0; + entireRect.bottom = mHeight; + + D3DLOCKED_RECT lockedRect; + result = newSurface->LockRect(&lockedRect, &entireRect, 0); + ASSERT(SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock image surface, result: 0x%X.", result); + } + + d3dFormatInfo.dataInitializerFunction(mWidth, mHeight, 1, reinterpret_cast(lockedRect.pBits), + lockedRect.Pitch, 0); + + result = newSurface->UnlockRect(); + ASSERT(SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to unlock image surface, result: 0x%X.", result); + } + } + } + + mSurface = newSurface; + mDirty = false; + mD3DPool = poolToUse; + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Image9::lock(D3DLOCKED_RECT *lockedRect, const RECT &rect) +{ + gl::Error error = createSurface(); + if (error.isError()) + { + return error; + } + + if (mSurface) + { + HRESULT result = mSurface->LockRect(lockedRect, &rect, 0); + ASSERT(SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock image surface, result: 0x%X.", result); + } + + mDirty = true; + } + + return gl::Error(GL_NO_ERROR); +} + +void Image9::unlock() +{ + if (mSurface) + { + HRESULT result = mSurface->UnlockRect(); + UNUSED_ASSERTION_VARIABLE(result); + ASSERT(SUCCEEDED(result)); + } +} + +D3DFORMAT Image9::getD3DFormat() const +{ + // this should only happen if the image hasn't been redefined first + // which would be a bug by the caller + ASSERT(mD3DFormat != D3DFMT_UNKNOWN); + + return mD3DFormat; +} + +bool Image9::isDirty() const +{ + // Make sure to that this image is marked as dirty even if the staging texture hasn't been created yet + // if initialization is required before use. + return (mSurface || d3d9::GetTextureFormatInfo(mInternalFormat).dataInitializerFunction != NULL) && mDirty; +} + +gl::Error Image9::getSurface(IDirect3DSurface9 **outSurface) +{ + gl::Error error = createSurface(); + if (error.isError()) + { + return error; + } + + *outSurface = mSurface; + return gl::Error(GL_NO_ERROR); +} + +gl::Error Image9::setManagedSurface2D(TextureStorage *storage, int level) +{ + IDirect3DSurface9 *surface = NULL; + TextureStorage9_2D *storage9 = TextureStorage9_2D::makeTextureStorage9_2D(storage); + gl::Error error = storage9->getSurfaceLevel(level, false, &surface); + if (error.isError()) + { + return error; + } + return setManagedSurface(surface); +} + +gl::Error Image9::setManagedSurfaceCube(TextureStorage *storage, int face, int level) +{ + IDirect3DSurface9 *surface = NULL; + TextureStorage9_Cube *storage9 = TextureStorage9_Cube::makeTextureStorage9_Cube(storage); + gl::Error error = storage9->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level, false, &surface); + if (error.isError()) + { + return error; + } + return setManagedSurface(surface); +} + +gl::Error Image9::setManagedSurface(IDirect3DSurface9 *surface) +{ + D3DSURFACE_DESC desc; + surface->GetDesc(&desc); + ASSERT(desc.Pool == D3DPOOL_MANAGED); + + if ((GLsizei)desc.Width == mWidth && (GLsizei)desc.Height == mHeight) + { + if (mSurface) + { + gl::Error error = copyLockableSurfaces(surface, mSurface); + SafeRelease(mSurface); + if (error.isError()) + { + return error; + } + } + + mSurface = surface; + mD3DPool = desc.Pool; + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Image9::copyToStorage(TextureStorage *storage, const gl::ImageIndex &index, const gl::Box ®ion) +{ + gl::Error error = createSurface(); + if (error.isError()) + { + return error; + } + + IDirect3DSurface9 *destSurface = NULL; + + if (index.type == GL_TEXTURE_2D) + { + TextureStorage9_2D *storage9 = TextureStorage9_2D::makeTextureStorage9_2D(storage); + error = storage9->getSurfaceLevel(index.mipIndex, true, &destSurface); + if (error.isError()) + { + return error; + } + } + else + { + ASSERT(gl::IsCubeMapTextureTarget(index.type)); + TextureStorage9_Cube *storage9 = TextureStorage9_Cube::makeTextureStorage9_Cube(storage); + error = storage9->getCubeMapSurface(index.type, index.mipIndex, true, &destSurface); + if (error.isError()) + { + return error; + } + } + + error = copyToSurface(destSurface, region); + SafeRelease(destSurface); + return error; +} + +gl::Error Image9::copyToSurface(IDirect3DSurface9 *destSurface, const gl::Box &area) +{ + ASSERT(area.width > 0 && area.height > 0 && area.depth == 1); + ASSERT(destSurface); + + IDirect3DSurface9 *sourceSurface = NULL; + gl::Error error = getSurface(&sourceSurface); + if (error.isError()) + { + return error; + } + + ASSERT(sourceSurface && sourceSurface != destSurface); + + RECT rect; + rect.left = area.x; + rect.top = area.y; + rect.right = area.x + area.width; + rect.bottom = area.y + area.height; + + POINT point = {rect.left, rect.top}; + + IDirect3DDevice9 *device = mRenderer->getDevice(); + + if (mD3DPool == D3DPOOL_MANAGED) + { + D3DSURFACE_DESC desc; + sourceSurface->GetDesc(&desc); + + IDirect3DSurface9 *surf = 0; + HRESULT result = device->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format, D3DPOOL_SYSTEMMEM, &surf, NULL); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Internal CreateOffscreenPlainSurface call failed, result: 0x%X.", result); + } + + copyLockableSurfaces(surf, sourceSurface); + result = device->UpdateSurface(surf, &rect, destSurface, &point); + SafeRelease(surf); + ASSERT(SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Internal UpdateSurface call failed, result: 0x%X.", result); + } + } + else + { + // UpdateSurface: source must be SYSTEMMEM, dest must be DEFAULT pools + HRESULT result = device->UpdateSurface(sourceSurface, &rect, destSurface, &point); + ASSERT(SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Internal UpdateSurface call failed, result: 0x%X.", result); + } + } + + return gl::Error(GL_NO_ERROR); +} + +// Store the pixel rectangle designated by xoffset,yoffset,width,height with pixels stored as format/type at input +// into the target pixel rectangle. +gl::Error Image9::loadData(const gl::Box &area, const gl::PixelUnpackState &unpack, GLenum type, const void *input) +{ + // 3D textures are not supported by the D3D9 backend. + ASSERT(area.z == 0 && area.depth == 1); + + const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(mInternalFormat); + GLsizei inputRowPitch = formatInfo.computeRowPitch(type, area.width, unpack.alignment, unpack.rowLength); + + const d3d9::TextureFormat &d3dFormatInfo = d3d9::GetTextureFormatInfo(mInternalFormat); + ASSERT(d3dFormatInfo.loadFunction != NULL); + + RECT lockRect = + { + area.x, area.y, + area.x + area.width, area.y + area.height + }; + + D3DLOCKED_RECT locked; + gl::Error error = lock(&locked, lockRect); + if (error.isError()) + { + return error; + } + + d3dFormatInfo.loadFunction(area.width, area.height, area.depth, + reinterpret_cast(input), inputRowPitch, 0, + reinterpret_cast(locked.pBits), locked.Pitch, 0); + + unlock(); + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Image9::loadCompressedData(const gl::Box &area, const void *input) +{ + // 3D textures are not supported by the D3D9 backend. + ASSERT(area.z == 0 && area.depth == 1); + + const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(mInternalFormat); + GLsizei inputRowPitch = formatInfo.computeRowPitch(GL_UNSIGNED_BYTE, area.width, 1, 0); + GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, area.width, area.height, 1, 0); + + const d3d9::TextureFormat &d3d9FormatInfo = d3d9::GetTextureFormatInfo(mInternalFormat); + + ASSERT(area.x % d3d9::GetD3DFormatInfo(d3d9FormatInfo.texFormat).blockWidth == 0); + ASSERT(area.y % d3d9::GetD3DFormatInfo(d3d9FormatInfo.texFormat).blockHeight == 0); + + ASSERT(d3d9FormatInfo.loadFunction != NULL); + + RECT lockRect = + { + area.x, area.y, + area.x + area.width, area.y + area.height + }; + + D3DLOCKED_RECT locked; + gl::Error error = lock(&locked, lockRect); + if (error.isError()) + { + return error; + } + + d3d9FormatInfo.loadFunction(area.width, area.height, area.depth, + reinterpret_cast(input), inputRowPitch, inputDepthPitch, + reinterpret_cast(locked.pBits), locked.Pitch, 0); + + unlock(); + + return gl::Error(GL_NO_ERROR); +} + +// This implements glCopyTex[Sub]Image2D for non-renderable internal texture formats and incomplete textures +gl::Error Image9::copy(const gl::Offset &destOffset, const gl::Rectangle &sourceArea, RenderTargetD3D *source) +{ + ASSERT(source); + + // ES3.0 only behaviour to copy into a 3d texture + ASSERT(destOffset.z == 0); + + RenderTarget9 *renderTarget = RenderTarget9::makeRenderTarget9(source); + + IDirect3DSurface9 *surface = renderTarget->getSurface(); + ASSERT(surface); + + IDirect3DDevice9 *device = mRenderer->getDevice(); + + IDirect3DSurface9 *renderTargetData = NULL; + D3DSURFACE_DESC description; + surface->GetDesc(&description); + + HRESULT result = device->CreateOffscreenPlainSurface(description.Width, description.Height, description.Format, D3DPOOL_SYSTEMMEM, &renderTargetData, NULL); + + if (FAILED(result)) + { + SafeRelease(surface); + return gl::Error(GL_OUT_OF_MEMORY, "Could not create matching destination surface, result: 0x%X.", result); + } + + result = device->GetRenderTargetData(surface, renderTargetData); + + if (FAILED(result)) + { + SafeRelease(renderTargetData); + SafeRelease(surface); + return gl::Error(GL_OUT_OF_MEMORY, "GetRenderTargetData unexpectedly failed, result: 0x%X.", result); + } + + int width = sourceArea.width; + int height = sourceArea.height; + + RECT sourceRect = { sourceArea.x, sourceArea.y, sourceArea.x + width, sourceArea.y + height }; + RECT destRect = { destOffset.x, destOffset.y, destOffset.x + width, destOffset.y + height }; + + D3DLOCKED_RECT sourceLock = {0}; + result = renderTargetData->LockRect(&sourceLock, &sourceRect, 0); + + if (FAILED(result)) + { + SafeRelease(renderTargetData); + SafeRelease(surface); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock the source surface (rectangle might be invalid), result: 0x%X.", result); + } + + D3DLOCKED_RECT destLock = {0}; + gl::Error error = lock(&destLock, destRect); + if (error.isError()) + { + renderTargetData->UnlockRect(); + SafeRelease(renderTargetData); + SafeRelease(surface); + return error; + } + + ASSERT(destLock.pBits && sourceLock.pBits); + + unsigned char *sourcePixels = (unsigned char*)sourceLock.pBits; + unsigned char *destPixels = (unsigned char*)destLock.pBits; + + switch (description.Format) + { + case D3DFMT_X8R8G8B8: + case D3DFMT_A8R8G8B8: + switch (getD3DFormat()) + { + case D3DFMT_X8R8G8B8: + case D3DFMT_A8R8G8B8: + for (int y = 0; y < height; y++) + { + memcpy(destPixels, sourcePixels, 4 * width); + sourcePixels += sourceLock.Pitch; + destPixels += destLock.Pitch; + } + break; + case D3DFMT_L8: + for (int y = 0; y < height; y++) + { + for (int x = 0; x < width; x++) + { + destPixels[x] = sourcePixels[x * 4 + 2]; + } + sourcePixels += sourceLock.Pitch; + destPixels += destLock.Pitch; + } + break; + case D3DFMT_A8L8: + for (int y = 0; y < height; y++) + { + for (int x = 0; x < width; x++) + { + destPixels[x * 2 + 0] = sourcePixels[x * 4 + 2]; + destPixels[x * 2 + 1] = sourcePixels[x * 4 + 3]; + } + sourcePixels += sourceLock.Pitch; + destPixels += destLock.Pitch; + } + break; + default: + UNREACHABLE(); + } + break; + case D3DFMT_R5G6B5: + switch (getD3DFormat()) + { + case D3DFMT_X8R8G8B8: + for (int y = 0; y < height; y++) + { + for (int x = 0; x < width; x++) + { + unsigned short rgb = ((unsigned short*)sourcePixels)[x]; + unsigned char red = (rgb & 0xF800) >> 8; + unsigned char green = (rgb & 0x07E0) >> 3; + unsigned char blue = (rgb & 0x001F) << 3; + destPixels[x + 0] = blue | (blue >> 5); + destPixels[x + 1] = green | (green >> 6); + destPixels[x + 2] = red | (red >> 5); + destPixels[x + 3] = 0xFF; + } + sourcePixels += sourceLock.Pitch; + destPixels += destLock.Pitch; + } + break; + case D3DFMT_L8: + for (int y = 0; y < height; y++) + { + for (int x = 0; x < width; x++) + { + unsigned char red = sourcePixels[x * 2 + 1] & 0xF8; + destPixels[x] = red | (red >> 5); + } + sourcePixels += sourceLock.Pitch; + destPixels += destLock.Pitch; + } + break; + default: + UNREACHABLE(); + } + break; + case D3DFMT_A1R5G5B5: + switch (getD3DFormat()) + { + case D3DFMT_X8R8G8B8: + for (int y = 0; y < height; y++) + { + for (int x = 0; x < width; x++) + { + unsigned short argb = ((unsigned short*)sourcePixels)[x]; + unsigned char red = (argb & 0x7C00) >> 7; + unsigned char green = (argb & 0x03E0) >> 2; + unsigned char blue = (argb & 0x001F) << 3; + destPixels[x + 0] = blue | (blue >> 5); + destPixels[x + 1] = green | (green >> 5); + destPixels[x + 2] = red | (red >> 5); + destPixels[x + 3] = 0xFF; + } + sourcePixels += sourceLock.Pitch; + destPixels += destLock.Pitch; + } + break; + case D3DFMT_A8R8G8B8: + for (int y = 0; y < height; y++) + { + for (int x = 0; x < width; x++) + { + unsigned short argb = ((unsigned short*)sourcePixels)[x]; + unsigned char red = (argb & 0x7C00) >> 7; + unsigned char green = (argb & 0x03E0) >> 2; + unsigned char blue = (argb & 0x001F) << 3; + unsigned char alpha = (signed short)argb >> 15; + destPixels[x + 0] = blue | (blue >> 5); + destPixels[x + 1] = green | (green >> 5); + destPixels[x + 2] = red | (red >> 5); + destPixels[x + 3] = alpha; + } + sourcePixels += sourceLock.Pitch; + destPixels += destLock.Pitch; + } + break; + case D3DFMT_L8: + for (int y = 0; y < height; y++) + { + for (int x = 0; x < width; x++) + { + unsigned char red = sourcePixels[x * 2 + 1] & 0x7C; + destPixels[x] = (red << 1) | (red >> 4); + } + sourcePixels += sourceLock.Pitch; + destPixels += destLock.Pitch; + } + break; + case D3DFMT_A8L8: + for (int y = 0; y < height; y++) + { + for (int x = 0; x < width; x++) + { + unsigned char red = sourcePixels[x * 2 + 1] & 0x7C; + destPixels[x * 2 + 0] = (red << 1) | (red >> 4); + destPixels[x * 2 + 1] = (signed char)sourcePixels[x * 2 + 1] >> 7; + } + sourcePixels += sourceLock.Pitch; + destPixels += destLock.Pitch; + } + break; + default: + UNREACHABLE(); + } + break; + default: + UNREACHABLE(); + } + + unlock(); + renderTargetData->UnlockRect(); + + SafeRelease(renderTargetData); + SafeRelease(surface); + + mDirty = true; + return gl::Error(GL_NO_ERROR); +} + +gl::Error Image9::copy(const gl::Offset &destOffset, const gl::Box &area, const gl::ImageIndex &srcIndex, TextureStorage *srcStorage) +{ + // Currently unreachable, due to only being used in a D3D11-only workaround + UNIMPLEMENTED(); + return gl::Error(GL_INVALID_OPERATION); +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Image9.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Image9.h new file mode 100644 index 0000000000..8cbfbbebf6 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Image9.h @@ -0,0 +1,73 @@ +// +// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Image9.h: Defines the rx::Image9 class, which acts as the interface to +// the actual underlying surfaces of a Texture. + +#ifndef LIBANGLE_RENDERER_D3D_D3D9_IMAGE9_H_ +#define LIBANGLE_RENDERER_D3D_D3D9_IMAGE9_H_ + +#include "libANGLE/renderer/d3d/ImageD3D.h" +#include "common/debug.h" + +namespace gl +{ +class Framebuffer; +} + +namespace rx +{ +class Renderer9; + +class Image9 : public ImageD3D +{ + public: + Image9(Renderer9 *renderer); + ~Image9(); + + static Image9 *makeImage9(ImageD3D *img); + + static gl::Error generateMipmap(Image9 *dest, Image9 *source); + static gl::Error generateMip(IDirect3DSurface9 *destSurface, IDirect3DSurface9 *sourceSurface); + static gl::Error copyLockableSurfaces(IDirect3DSurface9 *dest, IDirect3DSurface9 *source); + + bool redefine(GLenum target, GLenum internalformat, const gl::Extents &size, bool forceRelease) override; + + D3DFORMAT getD3DFormat() const; + + virtual bool isDirty() const; + + virtual gl::Error setManagedSurface2D(TextureStorage *storage, int level); + virtual gl::Error setManagedSurfaceCube(TextureStorage *storage, int face, int level); + virtual gl::Error copyToStorage(TextureStorage *storage, const gl::ImageIndex &index, const gl::Box ®ion); + + virtual gl::Error loadData(const gl::Box &area, const gl::PixelUnpackState &unpack, GLenum type, const void *input); + virtual gl::Error loadCompressedData(const gl::Box &area, const void *input); + + virtual gl::Error copy(const gl::Offset &destOffset, const gl::Rectangle &sourceArea, RenderTargetD3D *source); + virtual gl::Error copy(const gl::Offset &destOffset, const gl::Box &sourceArea, + const gl::ImageIndex &sourceIndex, TextureStorage *source); + + private: + gl::Error getSurface(IDirect3DSurface9 **outSurface); + + gl::Error createSurface(); + gl::Error setManagedSurface(IDirect3DSurface9 *surface); + gl::Error copyToSurface(IDirect3DSurface9 *dest, const gl::Box &area); + + gl::Error lock(D3DLOCKED_RECT *lockedRect, const RECT &rect); + void unlock(); + + Renderer9 *mRenderer; + + D3DPOOL mD3DPool; // can only be D3DPOOL_SYSTEMMEM or D3DPOOL_MANAGED since it needs to be lockable. + D3DFORMAT mD3DFormat; + + IDirect3DSurface9 *mSurface; +}; +} + +#endif // LIBANGLE_RENDERER_D3D_D3D9_IMAGE9_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/IndexBuffer9.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/IndexBuffer9.cpp new file mode 100644 index 0000000000..c5d72e6a50 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/IndexBuffer9.cpp @@ -0,0 +1,173 @@ +// +// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Indexffer9.cpp: Defines the D3D9 IndexBuffer implementation. + +#include "libANGLE/renderer/d3d/d3d9/IndexBuffer9.h" +#include "libANGLE/renderer/d3d/d3d9/Renderer9.h" + +namespace rx +{ + +IndexBuffer9::IndexBuffer9(Renderer9 *const renderer) : mRenderer(renderer) +{ + mIndexBuffer = NULL; + mBufferSize = 0; + mIndexType = 0; + mDynamic = false; +} + +IndexBuffer9::~IndexBuffer9() +{ + SafeRelease(mIndexBuffer); +} + +gl::Error IndexBuffer9::initialize(unsigned int bufferSize, GLenum indexType, bool dynamic) +{ + SafeRelease(mIndexBuffer); + + updateSerial(); + + if (bufferSize > 0) + { + D3DFORMAT format = D3DFMT_UNKNOWN; + if (indexType == GL_UNSIGNED_SHORT || indexType == GL_UNSIGNED_BYTE) + { + format = D3DFMT_INDEX16; + } + else if (indexType == GL_UNSIGNED_INT) + { + ASSERT(mRenderer->getRendererExtensions().elementIndexUint); + format = D3DFMT_INDEX32; + } + else UNREACHABLE(); + + DWORD usageFlags = D3DUSAGE_WRITEONLY; + if (dynamic) + { + usageFlags |= D3DUSAGE_DYNAMIC; + } + + HRESULT result = mRenderer->createIndexBuffer(bufferSize, usageFlags, format, &mIndexBuffer); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate internal index buffer of size, %lu.", bufferSize); + } + } + + mBufferSize = bufferSize; + mIndexType = indexType; + mDynamic = dynamic; + + return gl::Error(GL_NO_ERROR); +} + +IndexBuffer9 *IndexBuffer9::makeIndexBuffer9(IndexBuffer *indexBuffer) +{ + ASSERT(HAS_DYNAMIC_TYPE(IndexBuffer9*, indexBuffer)); + return static_cast(indexBuffer); +} + +gl::Error IndexBuffer9::mapBuffer(unsigned int offset, unsigned int size, void** outMappedMemory) +{ + if (!mIndexBuffer) + { + return gl::Error(GL_OUT_OF_MEMORY, "Internal index buffer is not initialized."); + } + + DWORD lockFlags = mDynamic ? D3DLOCK_NOOVERWRITE : 0; + + void *mapPtr = NULL; + HRESULT result = mIndexBuffer->Lock(offset, size, &mapPtr, lockFlags); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock internal index buffer, HRESULT: 0x%08x.", result); + } + + *outMappedMemory = mapPtr; + return gl::Error(GL_NO_ERROR); +} + +gl::Error IndexBuffer9::unmapBuffer() +{ + if (!mIndexBuffer) + { + return gl::Error(GL_OUT_OF_MEMORY, "Internal index buffer is not initialized."); + } + + HRESULT result = mIndexBuffer->Unlock(); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to unlock internal index buffer, HRESULT: 0x%08x.", result); + } + + return gl::Error(GL_NO_ERROR); +} + +GLenum IndexBuffer9::getIndexType() const +{ + return mIndexType; +} + +unsigned int IndexBuffer9::getBufferSize() const +{ + return mBufferSize; +} + +gl::Error IndexBuffer9::setSize(unsigned int bufferSize, GLenum indexType) +{ + if (bufferSize > mBufferSize || indexType != mIndexType) + { + return initialize(bufferSize, indexType, mDynamic); + } + else + { + return gl::Error(GL_NO_ERROR); + } +} + +gl::Error IndexBuffer9::discard() +{ + if (!mIndexBuffer) + { + return gl::Error(GL_OUT_OF_MEMORY, "Internal index buffer is not initialized."); + } + + void *dummy; + HRESULT result; + + result = mIndexBuffer->Lock(0, 1, &dummy, D3DLOCK_DISCARD); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock internal index buffer, HRESULT: 0x%08x.", result); + } + + result = mIndexBuffer->Unlock(); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to unlock internal index buffer, HRESULT: 0x%08x.", result); + } + + return gl::Error(GL_NO_ERROR); +} + +D3DFORMAT IndexBuffer9::getIndexFormat() const +{ + switch (mIndexType) + { + case GL_UNSIGNED_BYTE: return D3DFMT_INDEX16; + case GL_UNSIGNED_SHORT: return D3DFMT_INDEX16; + case GL_UNSIGNED_INT: return D3DFMT_INDEX32; + default: UNREACHABLE(); return D3DFMT_UNKNOWN; + } +} + +IDirect3DIndexBuffer9 * IndexBuffer9::getBuffer() const +{ + return mIndexBuffer; +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/IndexBuffer9.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/IndexBuffer9.h new file mode 100644 index 0000000000..61f8b11566 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/IndexBuffer9.h @@ -0,0 +1,51 @@ +// +// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Indexffer9.h: Defines the D3D9 IndexBuffer implementation. + +#ifndef LIBANGLE_RENDERER_D3D_D3D9_INDEXBUFFER9_H_ +#define LIBANGLE_RENDERER_D3D_D3D9_INDEXBUFFER9_H_ + +#include "libANGLE/renderer/d3d/IndexBuffer.h" + +namespace rx +{ +class Renderer9; + +class IndexBuffer9 : public IndexBuffer +{ + public: + explicit IndexBuffer9(Renderer9 *const renderer); + virtual ~IndexBuffer9(); + + virtual gl::Error initialize(unsigned int bufferSize, GLenum indexType, bool dynamic); + + static IndexBuffer9 *makeIndexBuffer9(IndexBuffer *indexBuffer); + + virtual gl::Error mapBuffer(unsigned int offset, unsigned int size, void** outMappedMemory); + virtual gl::Error unmapBuffer(); + + virtual GLenum getIndexType() const; + virtual unsigned int getBufferSize() const; + virtual gl::Error setSize(unsigned int bufferSize, GLenum indexType); + + virtual gl::Error discard(); + + D3DFORMAT getIndexFormat() const; + IDirect3DIndexBuffer9 *getBuffer() const; + + private: + Renderer9 *const mRenderer; + + IDirect3DIndexBuffer9 *mIndexBuffer; + unsigned int mBufferSize; + GLenum mIndexType; + bool mDynamic; +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_D3D9_INDEXBUFFER9_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Query9.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Query9.cpp new file mode 100644 index 0000000000..96f12d7868 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Query9.cpp @@ -0,0 +1,144 @@ +// +// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Query9.cpp: Defines the rx::Query9 class which implements rx::QueryImpl. + +#include "libANGLE/renderer/d3d/d3d9/Query9.h" +#include "libANGLE/renderer/d3d/d3d9/renderer9_utils.h" +#include "libANGLE/renderer/d3d/d3d9/Renderer9.h" + +#include + +namespace rx +{ +Query9::Query9(Renderer9 *renderer, GLenum type) + : QueryImpl(type), + mResult(GL_FALSE), + mQueryFinished(false), + mRenderer(renderer), + mQuery(NULL) +{ +} + +Query9::~Query9() +{ + SafeRelease(mQuery); +} + +gl::Error Query9::begin() +{ + if (mQuery == NULL) + { + HRESULT result = mRenderer->getDevice()->CreateQuery(D3DQUERYTYPE_OCCLUSION, &mQuery); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Internal query creation failed, result: 0x%X.", result); + } + } + + HRESULT result = mQuery->Issue(D3DISSUE_BEGIN); + ASSERT(SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to begin internal query, result: 0x%X.", result); + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Query9::end() +{ + ASSERT(mQuery); + + HRESULT result = mQuery->Issue(D3DISSUE_END); + ASSERT(SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to end internal query, result: 0x%X.", result); + } + + mQueryFinished = false; + mResult = GL_FALSE; + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Query9::getResult(GLuint *params) +{ + while (!mQueryFinished) + { + gl::Error error = testQuery(); + if (error.isError()) + { + return error; + } + + if (!mQueryFinished) + { + Sleep(0); + } + } + + ASSERT(mQueryFinished); + *params = mResult; + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Query9::isResultAvailable(GLuint *available) +{ + gl::Error error = testQuery(); + if (error.isError()) + { + return error; + } + + *available = (mQueryFinished ? GL_TRUE : GL_FALSE); + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Query9::testQuery() +{ + if (!mQueryFinished) + { + ASSERT(mQuery); + + DWORD numPixels = 0; + + HRESULT hres = mQuery->GetData(&numPixels, sizeof(DWORD), D3DGETDATA_FLUSH); + if (hres == S_OK) + { + mQueryFinished = true; + + switch (getType()) + { + case GL_ANY_SAMPLES_PASSED_EXT: + case GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT: + mResult = (numPixels > 0) ? GL_TRUE : GL_FALSE; + break; + + default: + UNREACHABLE(); + break; + } + } + else if (d3d9::isDeviceLostError(hres)) + { + mRenderer->notifyDeviceLost(); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to test get query result, device is lost."); + } + else if (mRenderer->testDeviceLost()) + { + mRenderer->notifyDeviceLost(); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to test get query result, device is lost."); + } + } + + return gl::Error(GL_NO_ERROR); +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Query9.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Query9.h new file mode 100644 index 0000000000..399da2ed83 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Query9.h @@ -0,0 +1,41 @@ +// +// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Query9.h: Defines the rx::Query9 class which implements rx::QueryImpl. + +#ifndef LIBANGLE_RENDERER_D3D_D3D9_QUERY9_H_ +#define LIBANGLE_RENDERER_D3D_D3D9_QUERY9_H_ + +#include "libANGLE/renderer/QueryImpl.h" + +namespace rx +{ +class Renderer9; + +class Query9 : public QueryImpl +{ + public: + Query9(Renderer9 *renderer, GLenum type); + virtual ~Query9(); + + virtual gl::Error begin(); + virtual gl::Error end(); + virtual gl::Error getResult(GLuint *params); + virtual gl::Error isResultAvailable(GLuint *available); + + private: + gl::Error testQuery(); + + GLuint mResult; + bool mQueryFinished; + + Renderer9 *mRenderer; + IDirect3DQuery9 *mQuery; +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_D3D9_QUERY9_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/RenderTarget9.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/RenderTarget9.cpp new file mode 100644 index 0000000000..412c0109f5 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/RenderTarget9.cpp @@ -0,0 +1,139 @@ +// +// Copyright (c) 2012-2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// RenderTarget9.cpp: Implements a D3D9-specific wrapper for IDirect3DSurface9 +// pointers retained by renderbuffers. + +#include "libANGLE/renderer/d3d/d3d9/RenderTarget9.h" +#include "libANGLE/renderer/d3d/d3d9/Renderer9.h" +#include "libANGLE/renderer/d3d/d3d9/renderer9_utils.h" +#include "libANGLE/renderer/d3d/d3d9/SwapChain9.h" +#include "libANGLE/renderer/d3d/d3d9/formatutils9.h" + +namespace rx +{ + +RenderTarget9 *RenderTarget9::makeRenderTarget9(RenderTargetD3D *target) +{ + ASSERT(HAS_DYNAMIC_TYPE(RenderTarget9*, target)); + return static_cast(target); +} + +// TODO: AddRef the incoming surface to take ownership instead of expecting that its ref is being given. +TextureRenderTarget9::TextureRenderTarget9(IDirect3DSurface9 *surface, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, + GLsizei samples) + : mWidth(width), + mHeight(height), + mDepth(depth), + mInternalFormat(internalFormat), + mD3DFormat(D3DFMT_UNKNOWN), + mSamples(samples), + mRenderTarget(surface) +{ + ASSERT(mDepth == 1); + + if (mRenderTarget) + { + D3DSURFACE_DESC description; + mRenderTarget->GetDesc(&description); + mD3DFormat = description.Format; + } +} + +TextureRenderTarget9::~TextureRenderTarget9() +{ + SafeRelease(mRenderTarget); +} + +GLsizei TextureRenderTarget9::getWidth() const +{ + return mWidth; +} + +GLsizei TextureRenderTarget9::getHeight() const +{ + return mHeight; +} + +GLsizei TextureRenderTarget9::getDepth() const +{ + return mDepth; +} + +GLenum TextureRenderTarget9::getInternalFormat() const +{ + return mInternalFormat; +} + +GLsizei TextureRenderTarget9::getSamples() const +{ + return mSamples; +} + +IDirect3DSurface9 *TextureRenderTarget9::getSurface() +{ + // Caller is responsible for releasing the returned surface reference. + // TODO: remove the AddRef to match RenderTarget11 + if (mRenderTarget) + { + mRenderTarget->AddRef(); + } + + return mRenderTarget; +} + +D3DFORMAT TextureRenderTarget9::getD3DFormat() const +{ + return mD3DFormat; +} + +SurfaceRenderTarget9::SurfaceRenderTarget9(SwapChain9 *swapChain, bool depth) + : mSwapChain(swapChain), + mDepth(depth) +{ +} + +SurfaceRenderTarget9::~SurfaceRenderTarget9() +{ +} + +GLsizei SurfaceRenderTarget9::getWidth() const +{ + return mSwapChain->getWidth(); +} + +GLsizei SurfaceRenderTarget9::getHeight() const +{ + return mSwapChain->getHeight(); +} + +GLsizei SurfaceRenderTarget9::getDepth() const +{ + return 1; +} + +GLenum SurfaceRenderTarget9::getInternalFormat() const +{ + return (mDepth ? mSwapChain->GetDepthBufferInternalFormat() : mSwapChain->GetBackBufferInternalFormat()); +} + +GLsizei SurfaceRenderTarget9::getSamples() const +{ + // Our EGL surfaces do not support multisampling. + return 0; +} + +IDirect3DSurface9 *SurfaceRenderTarget9::getSurface() +{ + return (mDepth ? mSwapChain->getDepthStencil() : mSwapChain->getRenderTarget()); +} + +D3DFORMAT SurfaceRenderTarget9::getD3DFormat() const +{ + return d3d9::GetTextureFormatInfo(getInternalFormat()).texFormat; +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/RenderTarget9.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/RenderTarget9.h new file mode 100644 index 0000000000..32c7dfa09c --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/RenderTarget9.h @@ -0,0 +1,84 @@ +// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// RenderTarget9.h: Defines a D3D9-specific wrapper for IDirect3DSurface9 pointers +// retained by Renderbuffers. + +#ifndef LIBANGLE_RENDERER_D3D_D3D9_RENDERTARGET9_H_ +#define LIBANGLE_RENDERER_D3D_D3D9_RENDERTARGET9_H_ + +#include "libANGLE/renderer/d3d/RenderTargetD3D.h" + +namespace rx +{ +class Renderer9; +class SwapChain9; + +class RenderTarget9 : public RenderTargetD3D +{ + public: + RenderTarget9() { } + virtual ~RenderTarget9() { } + + static RenderTarget9 *makeRenderTarget9(RenderTargetD3D *renderTarget); + + virtual IDirect3DSurface9 *getSurface() = 0; + + virtual D3DFORMAT getD3DFormat() const = 0; +}; + +class TextureRenderTarget9 : public RenderTarget9 +{ + public: + TextureRenderTarget9(IDirect3DSurface9 *surface, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, + GLsizei samples); + virtual ~TextureRenderTarget9(); + + GLsizei getWidth() const override; + GLsizei getHeight() const override; + GLsizei getDepth() const override; + GLenum getInternalFormat() const override; + GLsizei getSamples() const override; + + IDirect3DSurface9 *getSurface() override; + + D3DFORMAT getD3DFormat() const override; + + private: + GLsizei mWidth; + GLsizei mHeight; + GLsizei mDepth; + GLenum mInternalFormat; + D3DFORMAT mD3DFormat; + GLsizei mSamples; + + IDirect3DSurface9 *mRenderTarget; +}; + +class SurfaceRenderTarget9 : public RenderTarget9 +{ + public: + SurfaceRenderTarget9(SwapChain9 *swapChain, bool depth); + virtual ~SurfaceRenderTarget9(); + + GLsizei getWidth() const override; + GLsizei getHeight() const override; + GLsizei getDepth() const override; + GLenum getInternalFormat() const override; + GLsizei getSamples() const override; + + IDirect3DSurface9 *getSurface() override; + + D3DFORMAT getD3DFormat() const override; + + private: + SwapChain9 *mSwapChain; + bool mDepth; +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_D3D9_RENDERTARGET9_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Renderer9.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Renderer9.cpp new file mode 100644 index 0000000000..bf1c367693 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Renderer9.cpp @@ -0,0 +1,2933 @@ +// +// Copyright (c) 2012-2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Renderer9.cpp: Implements a back-end specific class for the D3D9 renderer. + +#include "libANGLE/renderer/d3d/d3d9/Renderer9.h" + +#include "common/utilities.h" +#include "libANGLE/Buffer.h" +#include "libANGLE/Display.h" +#include "libANGLE/Framebuffer.h" +#include "libANGLE/FramebufferAttachment.h" +#include "libANGLE/Program.h" +#include "libANGLE/Renderbuffer.h" +#include "libANGLE/State.h" +#include "libANGLE/Surface.h" +#include "libANGLE/Texture.h" +#include "libANGLE/angletypes.h" +#include "libANGLE/features.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/d3d9/Blit9.h" +#include "libANGLE/renderer/d3d/d3d9/Buffer9.h" +#include "libANGLE/renderer/d3d/d3d9/Fence9.h" +#include "libANGLE/renderer/d3d/d3d9/Framebuffer9.h" +#include "libANGLE/renderer/d3d/d3d9/Image9.h" +#include "libANGLE/renderer/d3d/d3d9/IndexBuffer9.h" +#include "libANGLE/renderer/d3d/d3d9/Query9.h" +#include "libANGLE/renderer/d3d/d3d9/RenderTarget9.h" +#include "libANGLE/renderer/d3d/d3d9/ShaderExecutable9.h" +#include "libANGLE/renderer/d3d/d3d9/SwapChain9.h" +#include "libANGLE/renderer/d3d/d3d9/TextureStorage9.h" +#include "libANGLE/renderer/d3d/d3d9/VertexArray9.h" +#include "libANGLE/renderer/d3d/d3d9/VertexBuffer9.h" +#include "libANGLE/renderer/d3d/d3d9/renderer9_utils.h" +#include "libANGLE/renderer/d3d/d3d9/formatutils9.h" + +#include "third_party/trace_event/trace_event.h" + +#include + +#include + +#if !defined(ANGLE_COMPILE_OPTIMIZATION_LEVEL) +#define ANGLE_COMPILE_OPTIMIZATION_LEVEL D3DCOMPILE_OPTIMIZATION_LEVEL3 +#endif + +// Enable ANGLE_SUPPORT_SHADER_MODEL_2 if you wish devices with only shader model 2. +// Such a device would not be conformant. +#ifndef ANGLE_SUPPORT_SHADER_MODEL_2 +#define ANGLE_SUPPORT_SHADER_MODEL_2 0 +#endif + +namespace rx +{ + +enum +{ + MAX_VERTEX_CONSTANT_VECTORS_D3D9 = 256, + MAX_PIXEL_CONSTANT_VECTORS_SM2 = 32, + MAX_PIXEL_CONSTANT_VECTORS_SM3 = 224, + MAX_VARYING_VECTORS_SM2 = 8, + MAX_VARYING_VECTORS_SM3 = 10, + + MAX_TEXTURE_IMAGE_UNITS_VTF_SM3 = 4 +}; + +Renderer9::Renderer9(egl::Display *display) + : RendererD3D(display) +{ + // Initialize global annotator + gl::InitializeDebugAnnotations(&mAnnotator); + + mD3d9Module = NULL; + + mD3d9 = NULL; + mD3d9Ex = NULL; + mDevice = NULL; + mDeviceEx = NULL; + mDeviceWindow = NULL; + mBlit = NULL; + + mAdapter = D3DADAPTER_DEFAULT; + + const egl::AttributeMap &attributes = display->getAttributeMap(); + 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: + mDeviceType = D3DDEVTYPE_HAL; + break; + + case EGL_PLATFORM_ANGLE_DEVICE_TYPE_REFERENCE_ANGLE: + mDeviceType = D3DDEVTYPE_REF; + break; + + case EGL_PLATFORM_ANGLE_DEVICE_TYPE_NULL_ANGLE: + mDeviceType = D3DDEVTYPE_NULLREF; + break; + + default: + UNREACHABLE(); + } + + mMaskedClearSavedState = NULL; + + mVertexDataManager = NULL; + mIndexDataManager = NULL; + mLineLoopIB = NULL; + mCountingIB = NULL; + + mMaxNullColorbufferLRU = 0; + for (int i = 0; i < NUM_NULL_COLORBUFFER_CACHE_ENTRIES; i++) + { + mNullColorbufferCache[i].lruCount = 0; + mNullColorbufferCache[i].width = 0; + mNullColorbufferCache[i].height = 0; + mNullColorbufferCache[i].buffer = NULL; + } + + mAppliedVertexShader = NULL; + mAppliedPixelShader = NULL; + mAppliedProgramSerial = 0; +} + +Renderer9::~Renderer9() +{ + if (mDevice) + { + // If the device is lost, reset it first to prevent leaving the driver in an unstable state + if (testDeviceLost()) + { + resetDevice(); + } + } + + release(); + + gl::UninitializeDebugAnnotations(); +} + +void Renderer9::release() +{ + RendererD3D::cleanup(); + + releaseDeviceResources(); + + SafeRelease(mDevice); + SafeRelease(mDeviceEx); + SafeRelease(mD3d9); + SafeRelease(mD3d9Ex); + + mCompiler.release(); + + if (mDeviceWindow) + { + DestroyWindow(mDeviceWindow); + mDeviceWindow = NULL; + } + + mD3d9Module = NULL; +} + +Renderer9 *Renderer9::makeRenderer9(Renderer *renderer) +{ + ASSERT(HAS_DYNAMIC_TYPE(Renderer9*, renderer)); + return static_cast(renderer); +} + +egl::Error Renderer9::initialize() +{ + if (!mCompiler.initialize()) + { + return egl::Error(EGL_NOT_INITIALIZED, + D3D9_INIT_COMPILER_ERROR, + "Compiler failed to initialize."); + } + + TRACE_EVENT0("gpu", "GetModuleHandle_d3d9"); + mD3d9Module = GetModuleHandle(TEXT("d3d9.dll")); + + if (mD3d9Module == NULL) + { + return egl::Error(EGL_NOT_INITIALIZED, D3D9_INIT_MISSING_DEP, "No D3D9 module found."); + } + + typedef HRESULT (WINAPI *Direct3DCreate9ExFunc)(UINT, IDirect3D9Ex**); + Direct3DCreate9ExFunc Direct3DCreate9ExPtr = reinterpret_cast(GetProcAddress(mD3d9Module, "Direct3DCreate9Ex")); + + // Use Direct3D9Ex if available. Among other things, this version is less + // inclined to report a lost context, for example when the user switches + // desktop. Direct3D9Ex is available in Windows Vista and later if suitable drivers are available. + if (ANGLE_D3D9EX == ANGLE_ENABLED && Direct3DCreate9ExPtr && SUCCEEDED(Direct3DCreate9ExPtr(D3D_SDK_VERSION, &mD3d9Ex))) + { + TRACE_EVENT0("gpu", "D3d9Ex_QueryInterface"); + ASSERT(mD3d9Ex); + mD3d9Ex->QueryInterface(IID_IDirect3D9, reinterpret_cast(&mD3d9)); + ASSERT(mD3d9); + } + else + { + TRACE_EVENT0("gpu", "Direct3DCreate9"); + mD3d9 = Direct3DCreate9(D3D_SDK_VERSION); + } + + if (!mD3d9) + { + return egl::Error(EGL_NOT_INITIALIZED, D3D9_INIT_MISSING_DEP, "Could not create D3D9 device."); + } + + if (mDisplay->getNativeDisplayId() != nullptr) + { + // UNIMPLEMENTED(); // FIXME: Determine which adapter index the device context corresponds to + } + + HRESULT result; + + // Give up on getting device caps after about one second. + { + TRACE_EVENT0("gpu", "GetDeviceCaps"); + for (int i = 0; i < 10; ++i) + { + result = mD3d9->GetDeviceCaps(mAdapter, mDeviceType, &mDeviceCaps); + if (SUCCEEDED(result)) + { + break; + } + else if (result == D3DERR_NOTAVAILABLE) + { + Sleep(100); // Give the driver some time to initialize/recover + } + else if (FAILED(result)) // D3DERR_OUTOFVIDEOMEMORY, E_OUTOFMEMORY, D3DERR_INVALIDDEVICE, or another error we can't recover from + { + return egl::Error(EGL_NOT_INITIALIZED, + D3D9_INIT_OTHER_ERROR, + "Failed to get device caps: Error code 0x%x\n", result); + } + } + } + +#if ANGLE_SUPPORT_SHADER_MODEL_2 + size_t minShaderModel = 2; +#else + size_t minShaderModel = 3; +#endif + + if (mDeviceCaps.PixelShaderVersion < D3DPS_VERSION(minShaderModel, 0)) + { + return egl::Error(EGL_NOT_INITIALIZED, + D3D9_INIT_UNSUPPORTED_VERSION, + "Renderer does not support PS %u.%u.aborting!", minShaderModel, 0); + } + + // When DirectX9 is running with an older DirectX8 driver, a StretchRect from a regular texture to a render target texture is not supported. + // This is required by Texture2D::ensureRenderTarget. + if ((mDeviceCaps.DevCaps2 & D3DDEVCAPS2_CAN_STRETCHRECT_FROM_TEXTURES) == 0) + { + return egl::Error(EGL_NOT_INITIALIZED, + D3D9_INIT_UNSUPPORTED_STRETCHRECT, + "Renderer does not support StretctRect from textures."); + } + + { + TRACE_EVENT0("gpu", "GetAdapterIdentifier"); + mD3d9->GetAdapterIdentifier(mAdapter, 0, &mAdapterIdentifier); + } + + static const TCHAR windowName[] = TEXT("AngleHiddenWindow"); + static const TCHAR className[] = TEXT("STATIC"); + + { + TRACE_EVENT0("gpu", "CreateWindowEx"); + mDeviceWindow = CreateWindowEx(WS_EX_NOACTIVATE, className, windowName, WS_DISABLED | WS_POPUP, 0, 0, 1, 1, HWND_MESSAGE, NULL, GetModuleHandle(NULL), NULL); + } + + D3DPRESENT_PARAMETERS presentParameters = getDefaultPresentParameters(); + DWORD behaviorFlags = D3DCREATE_FPU_PRESERVE | D3DCREATE_NOWINDOWCHANGES | D3DCREATE_MULTITHREADED; + + { + TRACE_EVENT0("gpu", "D3d9_CreateDevice"); + result = mD3d9->CreateDevice(mAdapter, mDeviceType, mDeviceWindow, behaviorFlags | D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE, &presentParameters, &mDevice); + } + if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_DEVICELOST) + { + return egl::Error(EGL_BAD_ALLOC, D3D9_INIT_OUT_OF_MEMORY, + "CreateDevice failed: device lost of out of memory"); + } + + if (FAILED(result)) + { + TRACE_EVENT0("gpu", "D3d9_CreateDevice2"); + result = mD3d9->CreateDevice(mAdapter, mDeviceType, mDeviceWindow, behaviorFlags | D3DCREATE_SOFTWARE_VERTEXPROCESSING, &presentParameters, &mDevice); + + if (FAILED(result)) + { + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_NOTAVAILABLE || result == D3DERR_DEVICELOST); + return egl::Error(EGL_BAD_ALLOC, D3D9_INIT_OUT_OF_MEMORY, + "CreateDevice2 failed: device lost, not available, or of out of memory"); + } + } + + if (mD3d9Ex) + { + TRACE_EVENT0("gpu", "mDevice_QueryInterface"); + result = mDevice->QueryInterface(IID_IDirect3DDevice9Ex, (void**)&mDeviceEx); + ASSERT(SUCCEEDED(result)); + } + + { + TRACE_EVENT0("gpu", "ShaderCache initialize"); + mVertexShaderCache.initialize(mDevice); + mPixelShaderCache.initialize(mDevice); + } + + D3DDISPLAYMODE currentDisplayMode; + mD3d9->GetAdapterDisplayMode(mAdapter, ¤tDisplayMode); + + // Check vertex texture support + // Only Direct3D 10 ready devices support all the necessary vertex texture formats. + // We test this using D3D9 by checking support for the R16F format. + mVertexTextureSupport = mDeviceCaps.PixelShaderVersion >= D3DPS_VERSION(3, 0) && + SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, + D3DUSAGE_QUERY_VERTEXTEXTURE, D3DRTYPE_TEXTURE, D3DFMT_R16F)); + + initializeDevice(); + + return egl::Error(EGL_SUCCESS); +} + +// do any one-time device initialization +// NOTE: this is also needed after a device lost/reset +// to reset the scene status and ensure the default states are reset. +void Renderer9::initializeDevice() +{ + // Permanent non-default states + mDevice->SetRenderState(D3DRS_POINTSPRITEENABLE, TRUE); + mDevice->SetRenderState(D3DRS_LASTPIXEL, FALSE); + + if (mDeviceCaps.PixelShaderVersion >= D3DPS_VERSION(3, 0)) + { + mDevice->SetRenderState(D3DRS_POINTSIZE_MAX, (DWORD&)mDeviceCaps.MaxPointSize); + } + else + { + mDevice->SetRenderState(D3DRS_POINTSIZE_MAX, 0x3F800000); // 1.0f + } + + const gl::Caps &rendererCaps = getRendererCaps(); + + mForceSetVertexSamplerStates.resize(rendererCaps.maxVertexTextureImageUnits); + mCurVertexSamplerStates.resize(rendererCaps.maxVertexTextureImageUnits); + + mForceSetPixelSamplerStates.resize(rendererCaps.maxTextureImageUnits); + mCurPixelSamplerStates.resize(rendererCaps.maxTextureImageUnits); + + mCurVertexTextureSerials.resize(rendererCaps.maxVertexTextureImageUnits); + mCurPixelTextureSerials.resize(rendererCaps.maxTextureImageUnits); + + markAllStateDirty(); + + mSceneStarted = false; + + ASSERT(!mBlit); + mBlit = new Blit9(this); + mBlit->initialize(); + + ASSERT(!mVertexDataManager && !mIndexDataManager); + mVertexDataManager = new VertexDataManager(this); + mIndexDataManager = new IndexDataManager(this, getRendererClass()); +} + +D3DPRESENT_PARAMETERS Renderer9::getDefaultPresentParameters() +{ + D3DPRESENT_PARAMETERS presentParameters = {0}; + + // The default swap chain is never actually used. Surface will create a new swap chain with the proper parameters. + presentParameters.AutoDepthStencilFormat = D3DFMT_UNKNOWN; + presentParameters.BackBufferCount = 1; + presentParameters.BackBufferFormat = D3DFMT_UNKNOWN; + presentParameters.BackBufferWidth = 1; + presentParameters.BackBufferHeight = 1; + presentParameters.EnableAutoDepthStencil = FALSE; + presentParameters.Flags = 0; + presentParameters.hDeviceWindow = mDeviceWindow; + presentParameters.MultiSampleQuality = 0; + presentParameters.MultiSampleType = D3DMULTISAMPLE_NONE; + presentParameters.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT; + presentParameters.SwapEffect = D3DSWAPEFFECT_DISCARD; + presentParameters.Windowed = TRUE; + + return presentParameters; +} + +egl::ConfigSet Renderer9::generateConfigs() const +{ + static const GLenum colorBufferFormats[] = + { + GL_BGR5_A1_ANGLEX, + GL_BGRA8_EXT, + GL_RGB565, + + }; + + static const GLenum depthStencilBufferFormats[] = + { + GL_NONE, + GL_DEPTH_COMPONENT32_OES, + GL_DEPTH24_STENCIL8_OES, + GL_DEPTH_COMPONENT24_OES, + GL_DEPTH_COMPONENT16, + }; + + const gl::Caps &rendererCaps = getRendererCaps(); + const gl::TextureCapsMap &rendererTextureCaps = getRendererTextureCaps(); + + D3DDISPLAYMODE currentDisplayMode; + mD3d9->GetAdapterDisplayMode(mAdapter, ¤tDisplayMode); + + // Determine the min and max swap intervals + int minSwapInterval = 4; + int maxSwapInterval = 0; + + if (mDeviceCaps.PresentationIntervals & D3DPRESENT_INTERVAL_IMMEDIATE) + { + minSwapInterval = std::min(minSwapInterval, 0); + maxSwapInterval = std::max(maxSwapInterval, 0); + } + if (mDeviceCaps.PresentationIntervals & D3DPRESENT_INTERVAL_ONE) + { + minSwapInterval = std::min(minSwapInterval, 1); + maxSwapInterval = std::max(maxSwapInterval, 1); + } + if (mDeviceCaps.PresentationIntervals & D3DPRESENT_INTERVAL_TWO) + { + minSwapInterval = std::min(minSwapInterval, 2); + maxSwapInterval = std::max(maxSwapInterval, 2); + } + if (mDeviceCaps.PresentationIntervals & D3DPRESENT_INTERVAL_THREE) + { + minSwapInterval = std::min(minSwapInterval, 3); + maxSwapInterval = std::max(maxSwapInterval, 3); + } + if (mDeviceCaps.PresentationIntervals & D3DPRESENT_INTERVAL_FOUR) + { + minSwapInterval = std::min(minSwapInterval, 4); + maxSwapInterval = std::max(maxSwapInterval, 4); + } + + egl::ConfigSet configs; + for (size_t formatIndex = 0; formatIndex < ArraySize(colorBufferFormats); formatIndex++) + { + GLenum colorBufferInternalFormat = colorBufferFormats[formatIndex]; + const gl::TextureCaps &colorBufferFormatCaps = rendererTextureCaps.get(colorBufferInternalFormat); + if (colorBufferFormatCaps.renderable) + { + for (size_t depthStencilIndex = 0; depthStencilIndex < ArraySize(depthStencilBufferFormats); depthStencilIndex++) + { + 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); + const d3d9::TextureFormat &d3d9ColorBufferFormatInfo = d3d9::GetTextureFormatInfo(colorBufferInternalFormat); + + 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; + // Mark as slow if blits to the back-buffer won't be straight forward + config.configCaveat = (currentDisplayMode.Format == d3d9ColorBufferFormatInfo.renderFormat) ? EGL_NONE : EGL_SLOW_CONFIG; + config.configID = static_cast(configs.size() + 1); + config.conformant = EGL_OPENGL_ES2_BIT; + 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 = maxSwapInterval; + config.minSwapInterval = minSwapInterval; + config.nativeRenderable = EGL_FALSE; + config.nativeVisualID = 0; + config.nativeVisualType = EGL_NONE; + config.renderableType = EGL_OPENGL_ES2_BIT; + 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); + } + } + } + } + + ASSERT(configs.size() > 0); + return configs; +} + +void Renderer9::startScene() +{ + if (!mSceneStarted) + { + long result = mDevice->BeginScene(); + if (SUCCEEDED(result)) { + // This is defensive checking against the device being + // lost at unexpected times. + mSceneStarted = true; + } + } +} + +void Renderer9::endScene() +{ + if (mSceneStarted) + { + // EndScene can fail if the device was lost, for example due + // to a TDR during a draw call. + mDevice->EndScene(); + mSceneStarted = false; + } +} + +gl::Error Renderer9::flush() +{ + IDirect3DQuery9* query = NULL; + gl::Error error = allocateEventQuery(&query); + if (error.isError()) + { + return error; + } + + HRESULT result = query->Issue(D3DISSUE_END); + if (FAILED(result)) + { + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to issue event query, result: 0x%X.", result); + } + + // Grab the query data once + result = query->GetData(NULL, 0, D3DGETDATA_FLUSH); + freeEventQuery(query); + if (FAILED(result)) + { + if (d3d9::isDeviceLostError(result)) + { + notifyDeviceLost(); + } + + return gl::Error(GL_OUT_OF_MEMORY, "Failed to get event query data, result: 0x%X.", result); + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Renderer9::finish() +{ + IDirect3DQuery9* query = NULL; + gl::Error error = allocateEventQuery(&query); + if (error.isError()) + { + return error; + } + + HRESULT result = query->Issue(D3DISSUE_END); + if (FAILED(result)) + { + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to issue event query, result: 0x%X.", result); + } + + // Grab the query data once + result = query->GetData(NULL, 0, D3DGETDATA_FLUSH); + if (FAILED(result)) + { + if (d3d9::isDeviceLostError(result)) + { + notifyDeviceLost(); + } + + freeEventQuery(query); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to get event query data, result: 0x%X.", result); + } + + // Loop until the query completes + while (result == S_FALSE) + { + // Keep polling, but allow other threads to do something useful first + Sleep(0); + + result = query->GetData(NULL, 0, D3DGETDATA_FLUSH); + + // explicitly check for device loss + // some drivers seem to return S_FALSE even if the device is lost + // instead of D3DERR_DEVICELOST like they should + if (result == S_FALSE && testDeviceLost()) + { + result = D3DERR_DEVICELOST; + } + + if (FAILED(result)) + { + if (d3d9::isDeviceLostError(result)) + { + notifyDeviceLost(); + } + + freeEventQuery(query); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to get event query data, result: 0x%X.", result); + } + + } + + freeEventQuery(query); + + return gl::Error(GL_NO_ERROR); +} + +SwapChainD3D *Renderer9::createSwapChain(NativeWindow nativeWindow, HANDLE shareHandle, GLenum backBufferFormat, GLenum depthBufferFormat) +{ + return new SwapChain9(this, nativeWindow, shareHandle, backBufferFormat, depthBufferFormat); +} + +gl::Error Renderer9::allocateEventQuery(IDirect3DQuery9 **outQuery) +{ + if (mEventQueryPool.empty()) + { + HRESULT result = mDevice->CreateQuery(D3DQUERYTYPE_EVENT, outQuery); + if (FAILED(result)) + { + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate event query, result: 0x%X.", result); + } + } + else + { + *outQuery = mEventQueryPool.back(); + mEventQueryPool.pop_back(); + } + + return gl::Error(GL_NO_ERROR); +} + +void Renderer9::freeEventQuery(IDirect3DQuery9* query) +{ + if (mEventQueryPool.size() > 1000) + { + SafeRelease(query); + } + else + { + mEventQueryPool.push_back(query); + } +} + +gl::Error Renderer9::createVertexShader(const DWORD *function, size_t length, IDirect3DVertexShader9 **outShader) +{ + return mVertexShaderCache.create(function, length, outShader); +} + +gl::Error Renderer9::createPixelShader(const DWORD *function, size_t length, IDirect3DPixelShader9 **outShader) +{ + return mPixelShaderCache.create(function, length, outShader); +} + +HRESULT Renderer9::createVertexBuffer(UINT Length, DWORD Usage, IDirect3DVertexBuffer9 **ppVertexBuffer) +{ + D3DPOOL Pool = getBufferPool(Usage); + return mDevice->CreateVertexBuffer(Length, Usage, 0, Pool, ppVertexBuffer, NULL); +} + +VertexBuffer *Renderer9::createVertexBuffer() +{ + return new VertexBuffer9(this); +} + +HRESULT Renderer9::createIndexBuffer(UINT Length, DWORD Usage, D3DFORMAT Format, IDirect3DIndexBuffer9 **ppIndexBuffer) +{ + D3DPOOL Pool = getBufferPool(Usage); + return mDevice->CreateIndexBuffer(Length, Usage, Format, Pool, ppIndexBuffer, NULL); +} + +IndexBuffer *Renderer9::createIndexBuffer() +{ + return new IndexBuffer9(this); +} + +BufferImpl *Renderer9::createBuffer() +{ + return new Buffer9(this); +} + +VertexArrayImpl *Renderer9::createVertexArray() +{ + return new VertexArray9(this); +} + +QueryImpl *Renderer9::createQuery(GLenum type) +{ + return new Query9(this, type); +} + +FenceNVImpl *Renderer9::createFenceNV() +{ + return new FenceNV9(this); +} + +FenceSyncImpl *Renderer9::createFenceSync() +{ + // Renderer9 doesn't support ES 3.0 and its sync objects. + UNREACHABLE(); + return NULL; +} + +TransformFeedbackImpl* Renderer9::createTransformFeedback() +{ + return new TransformFeedbackD3D(); +} + +bool Renderer9::supportsFastCopyBufferToTexture(GLenum internalFormat) const +{ + // Pixel buffer objects are not supported in D3D9, since D3D9 is ES2-only and PBOs are ES3. + return false; +} + +gl::Error Renderer9::fastCopyBufferToTexture(const gl::PixelUnpackState &unpack, unsigned int offset, RenderTargetD3D *destRenderTarget, + GLenum destinationFormat, GLenum sourcePixelsType, const gl::Box &destArea) +{ + // Pixel buffer objects are not supported in D3D9, since D3D9 is ES2-only and PBOs are ES3. + UNREACHABLE(); + return gl::Error(GL_INVALID_OPERATION); +} + +gl::Error Renderer9::generateSwizzle(gl::Texture *texture) +{ + // Swizzled textures are not available in ES2 or D3D9 + UNREACHABLE(); + return gl::Error(GL_INVALID_OPERATION); +} + +gl::Error Renderer9::setSamplerState(gl::SamplerType type, int index, gl::Texture *texture, const gl::SamplerState &samplerState) +{ + std::vector &forceSetSamplers = (type == gl::SAMPLER_PIXEL) ? mForceSetPixelSamplerStates : mForceSetVertexSamplerStates; + std::vector &appliedSamplers = (type == gl::SAMPLER_PIXEL) ? mCurPixelSamplerStates: mCurVertexSamplerStates; + + if (forceSetSamplers[index] || memcmp(&samplerState, &appliedSamplers[index], sizeof(gl::SamplerState)) != 0) + { + int d3dSamplerOffset = (type == gl::SAMPLER_PIXEL) ? 0 : D3DVERTEXTEXTURESAMPLER0; + int d3dSampler = index + d3dSamplerOffset; + + // Make sure to add the level offset for our tiny compressed texture workaround + TextureD3D *textureD3D = GetImplAs(texture); + + TextureStorage *storage = nullptr; + gl::Error error = textureD3D->getNativeTexture(&storage); + if (error.isError()) + { + return error; + } + + // Storage should exist, texture should be complete + ASSERT(storage); + + DWORD baseLevel = samplerState.baseLevel + storage->getTopLevel(); + + mDevice->SetSamplerState(d3dSampler, D3DSAMP_ADDRESSU, gl_d3d9::ConvertTextureWrap(samplerState.wrapS)); + mDevice->SetSamplerState(d3dSampler, D3DSAMP_ADDRESSV, gl_d3d9::ConvertTextureWrap(samplerState.wrapT)); + + mDevice->SetSamplerState(d3dSampler, D3DSAMP_MAGFILTER, gl_d3d9::ConvertMagFilter(samplerState.magFilter, samplerState.maxAnisotropy)); + D3DTEXTUREFILTERTYPE d3dMinFilter, d3dMipFilter; + gl_d3d9::ConvertMinFilter(samplerState.minFilter, &d3dMinFilter, &d3dMipFilter, samplerState.maxAnisotropy); + mDevice->SetSamplerState(d3dSampler, D3DSAMP_MINFILTER, d3dMinFilter); + mDevice->SetSamplerState(d3dSampler, D3DSAMP_MIPFILTER, d3dMipFilter); + mDevice->SetSamplerState(d3dSampler, D3DSAMP_MAXMIPLEVEL, baseLevel); + if (getRendererExtensions().textureFilterAnisotropic) + { + mDevice->SetSamplerState(d3dSampler, D3DSAMP_MAXANISOTROPY, (DWORD)samplerState.maxAnisotropy); + } + } + + forceSetSamplers[index] = false; + appliedSamplers[index] = samplerState; + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Renderer9::setTexture(gl::SamplerType type, int index, gl::Texture *texture) +{ + int d3dSamplerOffset = (type == gl::SAMPLER_PIXEL) ? 0 : D3DVERTEXTEXTURESAMPLER0; + int d3dSampler = index + d3dSamplerOffset; + IDirect3DBaseTexture9 *d3dTexture = NULL; + unsigned int serial = 0; + bool forceSetTexture = false; + + std::vector &appliedSerials = (type == gl::SAMPLER_PIXEL) ? mCurPixelTextureSerials : mCurVertexTextureSerials; + + if (texture) + { + TextureD3D *textureImpl = GetImplAs(texture); + + TextureStorage *texStorage = nullptr; + gl::Error error = textureImpl->getNativeTexture(&texStorage); + if (error.isError()) + { + return error; + } + + // Texture should be complete and have a storage + ASSERT(texStorage); + + TextureStorage9 *storage9 = TextureStorage9::makeTextureStorage9(texStorage); + error = storage9->getBaseTexture(&d3dTexture); + if (error.isError()) + { + return error; + } + + // If we get NULL back from getBaseTexture here, something went wrong + // in the texture class and we're unexpectedly missing the d3d texture + ASSERT(d3dTexture != NULL); + + serial = texture->getTextureSerial(); + forceSetTexture = textureImpl->hasDirtyImages(); + textureImpl->resetDirty(); + } + + if (forceSetTexture || appliedSerials[index] != serial) + { + mDevice->SetTexture(d3dSampler, d3dTexture); + } + + appliedSerials[index] = serial; + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Renderer9::setUniformBuffers(const gl::Data &/*data*/, + const GLint /*vertexUniformBuffers*/[], + const GLint /*fragmentUniformBuffers*/[]) +{ + // No effect in ES2/D3D9 + return gl::Error(GL_NO_ERROR); +} + +gl::Error Renderer9::setRasterizerState(const gl::RasterizerState &rasterState) +{ + bool rasterStateChanged = mForceSetRasterState || memcmp(&rasterState, &mCurRasterState, sizeof(gl::RasterizerState)) != 0; + + if (rasterStateChanged) + { + // Set the cull mode + if (rasterState.cullFace) + { + mDevice->SetRenderState(D3DRS_CULLMODE, gl_d3d9::ConvertCullMode(rasterState.cullMode, rasterState.frontFace)); + } + else + { + mDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); + } + + if (rasterState.polygonOffsetFill) + { + if (mCurDepthSize > 0) + { + mDevice->SetRenderState(D3DRS_SLOPESCALEDEPTHBIAS, *(DWORD*)&rasterState.polygonOffsetFactor); + + float depthBias = ldexp(rasterState.polygonOffsetUnits, -static_cast(mCurDepthSize)); + mDevice->SetRenderState(D3DRS_DEPTHBIAS, *(DWORD*)&depthBias); + } + } + else + { + mDevice->SetRenderState(D3DRS_SLOPESCALEDEPTHBIAS, 0); + mDevice->SetRenderState(D3DRS_DEPTHBIAS, 0); + } + + mCurRasterState = rasterState; + } + + mForceSetRasterState = false; + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Renderer9::setBlendState(const gl::Framebuffer *framebuffer, const gl::BlendState &blendState, const gl::ColorF &blendColor, + unsigned int sampleMask) +{ + bool blendStateChanged = mForceSetBlendState || memcmp(&blendState, &mCurBlendState, sizeof(gl::BlendState)) != 0; + bool blendColorChanged = mForceSetBlendState || memcmp(&blendColor, &mCurBlendColor, sizeof(gl::ColorF)) != 0; + bool sampleMaskChanged = mForceSetBlendState || sampleMask != mCurSampleMask; + + if (blendStateChanged || blendColorChanged) + { + if (blendState.blend) + { + mDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); + + 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) + { + mDevice->SetRenderState(D3DRS_BLENDFACTOR, gl_d3d9::ConvertColor(blendColor)); + } + else + { + mDevice->SetRenderState(D3DRS_BLENDFACTOR, D3DCOLOR_RGBA(gl::unorm<8>(blendColor.alpha), + gl::unorm<8>(blendColor.alpha), + gl::unorm<8>(blendColor.alpha), + gl::unorm<8>(blendColor.alpha))); + } + + mDevice->SetRenderState(D3DRS_SRCBLEND, gl_d3d9::ConvertBlendFunc(blendState.sourceBlendRGB)); + mDevice->SetRenderState(D3DRS_DESTBLEND, gl_d3d9::ConvertBlendFunc(blendState.destBlendRGB)); + mDevice->SetRenderState(D3DRS_BLENDOP, gl_d3d9::ConvertBlendOp(blendState.blendEquationRGB)); + + if (blendState.sourceBlendRGB != blendState.sourceBlendAlpha || + blendState.destBlendRGB != blendState.destBlendAlpha || + blendState.blendEquationRGB != blendState.blendEquationAlpha) + { + mDevice->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, TRUE); + + mDevice->SetRenderState(D3DRS_SRCBLENDALPHA, gl_d3d9::ConvertBlendFunc(blendState.sourceBlendAlpha)); + mDevice->SetRenderState(D3DRS_DESTBLENDALPHA, gl_d3d9::ConvertBlendFunc(blendState.destBlendAlpha)); + mDevice->SetRenderState(D3DRS_BLENDOPALPHA, gl_d3d9::ConvertBlendOp(blendState.blendEquationAlpha)); + } + else + { + mDevice->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, FALSE); + } + } + else + { + mDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); + } + + if (blendState.sampleAlphaToCoverage) + { + FIXME("Sample alpha to coverage is unimplemented."); + } + + gl::FramebufferAttachment *attachment = framebuffer->getFirstColorbuffer(); + GLenum internalFormat = attachment ? attachment->getInternalFormat() : GL_NONE; + + // Set the color mask + bool zeroColorMaskAllowed = getVendorId() != VENDOR_ID_AMD; + // Apparently some ATI cards have a bug where a draw with a zero color + // write mask can cause later draws to have incorrect results. Instead, + // set a nonzero color write mask but modify the blend state so that no + // drawing is done. + // http://code.google.com/p/angleproject/issues/detail?id=169 + + const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat); + DWORD colorMask = gl_d3d9::ConvertColorMask(formatInfo.redBits > 0 && blendState.colorMaskRed, + formatInfo.greenBits > 0 && blendState.colorMaskGreen, + formatInfo.blueBits > 0 && blendState.colorMaskBlue, + formatInfo.alphaBits > 0 && blendState.colorMaskAlpha); + if (colorMask == 0 && !zeroColorMaskAllowed) + { + // Enable green channel, but set blending so nothing will be drawn. + mDevice->SetRenderState(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_GREEN); + mDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); + + mDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ZERO); + mDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE); + mDevice->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD); + } + else + { + mDevice->SetRenderState(D3DRS_COLORWRITEENABLE, colorMask); + } + + mDevice->SetRenderState(D3DRS_DITHERENABLE, blendState.dither ? TRUE : FALSE); + + mCurBlendState = blendState; + mCurBlendColor = blendColor; + } + + if (sampleMaskChanged) + { + // Set the multisample mask + mDevice->SetRenderState(D3DRS_MULTISAMPLEANTIALIAS, TRUE); + mDevice->SetRenderState(D3DRS_MULTISAMPLEMASK, static_cast(sampleMask)); + + mCurSampleMask = sampleMask; + } + + mForceSetBlendState = false; + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Renderer9::setDepthStencilState(const gl::DepthStencilState &depthStencilState, int stencilRef, + int stencilBackRef, bool frontFaceCCW) +{ + bool depthStencilStateChanged = mForceSetDepthStencilState || + memcmp(&depthStencilState, &mCurDepthStencilState, sizeof(gl::DepthStencilState)) != 0; + bool stencilRefChanged = mForceSetDepthStencilState || stencilRef != mCurStencilRef || + stencilBackRef != mCurStencilBackRef; + bool frontFaceCCWChanged = mForceSetDepthStencilState || frontFaceCCW != mCurFrontFaceCCW; + + if (depthStencilStateChanged) + { + if (depthStencilState.depthTest) + { + mDevice->SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE); + mDevice->SetRenderState(D3DRS_ZFUNC, gl_d3d9::ConvertComparison(depthStencilState.depthFunc)); + } + else + { + mDevice->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE); + } + + mCurDepthStencilState = depthStencilState; + } + + if (depthStencilStateChanged || stencilRefChanged || frontFaceCCWChanged) + { + if (depthStencilState.stencilTest && mCurStencilSize > 0) + { + mDevice->SetRenderState(D3DRS_STENCILENABLE, TRUE); + mDevice->SetRenderState(D3DRS_TWOSIDEDSTENCILMODE, TRUE); + + // FIXME: Unsupported by D3D9 + const D3DRENDERSTATETYPE D3DRS_CCW_STENCILREF = D3DRS_STENCILREF; + const D3DRENDERSTATETYPE D3DRS_CCW_STENCILMASK = D3DRS_STENCILMASK; + const D3DRENDERSTATETYPE D3DRS_CCW_STENCILWRITEMASK = D3DRS_STENCILWRITEMASK; + + ASSERT(depthStencilState.stencilWritemask == depthStencilState.stencilBackWritemask); + ASSERT(stencilRef == stencilBackRef); + ASSERT(depthStencilState.stencilMask == depthStencilState.stencilBackMask); + + // get the maximum size of the stencil ref + unsigned int maxStencil = (1 << mCurStencilSize) - 1; + + mDevice->SetRenderState(frontFaceCCW ? D3DRS_STENCILWRITEMASK : D3DRS_CCW_STENCILWRITEMASK, + depthStencilState.stencilWritemask); + mDevice->SetRenderState(frontFaceCCW ? D3DRS_STENCILFUNC : D3DRS_CCW_STENCILFUNC, + gl_d3d9::ConvertComparison(depthStencilState.stencilFunc)); + + mDevice->SetRenderState(frontFaceCCW ? D3DRS_STENCILREF : D3DRS_CCW_STENCILREF, + (stencilRef < (int)maxStencil) ? stencilRef : maxStencil); + mDevice->SetRenderState(frontFaceCCW ? D3DRS_STENCILMASK : D3DRS_CCW_STENCILMASK, + depthStencilState.stencilMask); + + mDevice->SetRenderState(frontFaceCCW ? D3DRS_STENCILFAIL : D3DRS_CCW_STENCILFAIL, + gl_d3d9::ConvertStencilOp(depthStencilState.stencilFail)); + mDevice->SetRenderState(frontFaceCCW ? D3DRS_STENCILZFAIL : D3DRS_CCW_STENCILZFAIL, + gl_d3d9::ConvertStencilOp(depthStencilState.stencilPassDepthFail)); + mDevice->SetRenderState(frontFaceCCW ? D3DRS_STENCILPASS : D3DRS_CCW_STENCILPASS, + gl_d3d9::ConvertStencilOp(depthStencilState.stencilPassDepthPass)); + + mDevice->SetRenderState(!frontFaceCCW ? D3DRS_STENCILWRITEMASK : D3DRS_CCW_STENCILWRITEMASK, + depthStencilState.stencilBackWritemask); + mDevice->SetRenderState(!frontFaceCCW ? D3DRS_STENCILFUNC : D3DRS_CCW_STENCILFUNC, + gl_d3d9::ConvertComparison(depthStencilState.stencilBackFunc)); + + mDevice->SetRenderState(!frontFaceCCW ? D3DRS_STENCILREF : D3DRS_CCW_STENCILREF, + (stencilBackRef < (int)maxStencil) ? stencilBackRef : maxStencil); + mDevice->SetRenderState(!frontFaceCCW ? D3DRS_STENCILMASK : D3DRS_CCW_STENCILMASK, + depthStencilState.stencilBackMask); + + mDevice->SetRenderState(!frontFaceCCW ? D3DRS_STENCILFAIL : D3DRS_CCW_STENCILFAIL, + gl_d3d9::ConvertStencilOp(depthStencilState.stencilBackFail)); + mDevice->SetRenderState(!frontFaceCCW ? D3DRS_STENCILZFAIL : D3DRS_CCW_STENCILZFAIL, + gl_d3d9::ConvertStencilOp(depthStencilState.stencilBackPassDepthFail)); + mDevice->SetRenderState(!frontFaceCCW ? D3DRS_STENCILPASS : D3DRS_CCW_STENCILPASS, + gl_d3d9::ConvertStencilOp(depthStencilState.stencilBackPassDepthPass)); + } + else + { + mDevice->SetRenderState(D3DRS_STENCILENABLE, FALSE); + } + + mDevice->SetRenderState(D3DRS_ZWRITEENABLE, depthStencilState.depthMask ? TRUE : FALSE); + + mCurStencilRef = stencilRef; + mCurStencilBackRef = stencilBackRef; + mCurFrontFaceCCW = frontFaceCCW; + } + + mForceSetDepthStencilState = false; + + return gl::Error(GL_NO_ERROR); +} + +void Renderer9::setScissorRectangle(const gl::Rectangle &scissor, bool enabled) +{ + bool scissorChanged = mForceSetScissor || + memcmp(&scissor, &mCurScissor, sizeof(gl::Rectangle)) != 0 || + enabled != mScissorEnabled; + + if (scissorChanged) + { + if (enabled) + { + RECT rect; + rect.left = gl::clamp(scissor.x, 0, static_cast(mRenderTargetDesc.width)); + rect.top = gl::clamp(scissor.y, 0, static_cast(mRenderTargetDesc.height)); + rect.right = gl::clamp(scissor.x + scissor.width, 0, static_cast(mRenderTargetDesc.width)); + rect.bottom = gl::clamp(scissor.y + scissor.height, 0, static_cast(mRenderTargetDesc.height)); + mDevice->SetScissorRect(&rect); + } + + mDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, enabled ? TRUE : FALSE); + + mScissorEnabled = enabled; + mCurScissor = scissor; + } + + mForceSetScissor = false; +} + +void Renderer9::setViewport(const gl::Rectangle &viewport, float zNear, float zFar, GLenum drawMode, GLenum frontFace, + bool ignoreViewport) +{ + 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; + } + + D3DVIEWPORT9 dxViewport; + dxViewport.X = gl::clamp(actualViewport.x, 0, static_cast(mRenderTargetDesc.width)); + dxViewport.Y = gl::clamp(actualViewport.y, 0, static_cast(mRenderTargetDesc.height)); + dxViewport.Width = gl::clamp(actualViewport.width, 0, static_cast(mRenderTargetDesc.width) - static_cast(dxViewport.X)); + dxViewport.Height = gl::clamp(actualViewport.height, 0, static_cast(mRenderTargetDesc.height) - static_cast(dxViewport.Y)); + dxViewport.MinZ = actualZNear; + dxViewport.MaxZ = actualZFar; + + float depthFront = !gl::IsTriangleMode(drawMode) ? 0.0f : (frontFace == GL_CCW ? 1.0f : -1.0f); + + bool viewportChanged = mForceSetViewport || memcmp(&actualViewport, &mCurViewport, sizeof(gl::Rectangle)) != 0 || + actualZNear != mCurNear || actualZFar != mCurFar || mCurDepthFront != depthFront; + if (viewportChanged) + { + mDevice->SetViewport(&dxViewport); + + mCurViewport = actualViewport; + mCurNear = actualZNear; + mCurFar = actualZFar; + mCurDepthFront = depthFront; + + dx_VertexConstants vc = {0}; + dx_PixelConstants pc = {0}; + + vc.viewAdjust[0] = (float)((actualViewport.width - (int)dxViewport.Width) + 2 * (actualViewport.x - (int)dxViewport.X) - 1) / dxViewport.Width; + vc.viewAdjust[1] = (float)((actualViewport.height - (int)dxViewport.Height) + 2 * (actualViewport.y - (int)dxViewport.Y) - 1) / dxViewport.Height; + vc.viewAdjust[2] = (float)actualViewport.width / dxViewport.Width; + vc.viewAdjust[3] = (float)actualViewport.height / dxViewport.Height; + + pc.viewCoords[0] = actualViewport.width * 0.5f; + pc.viewCoords[1] = actualViewport.height * 0.5f; + pc.viewCoords[2] = actualViewport.x + (actualViewport.width * 0.5f); + pc.viewCoords[3] = actualViewport.y + (actualViewport.height * 0.5f); + + pc.depthFront[0] = (actualZFar - actualZNear) * 0.5f; + pc.depthFront[1] = (actualZNear + actualZFar) * 0.5f; + pc.depthFront[2] = depthFront; + + vc.depthRange[0] = actualZNear; + vc.depthRange[1] = actualZFar; + vc.depthRange[2] = actualZFar - actualZNear; + + pc.depthRange[0] = actualZNear; + pc.depthRange[1] = actualZFar; + pc.depthRange[2] = actualZFar - actualZNear; + + if (memcmp(&vc, &mVertexConstants, sizeof(dx_VertexConstants)) != 0) + { + mVertexConstants = vc; + mDxUniformsDirty = true; + } + + if (memcmp(&pc, &mPixelConstants, sizeof(dx_PixelConstants)) != 0) + { + mPixelConstants = pc; + mDxUniformsDirty = true; + } + } + + mForceSetViewport = false; +} + +bool Renderer9::applyPrimitiveType(GLenum mode, GLsizei count, bool usesPointSize) +{ + switch (mode) + { + case GL_POINTS: + mPrimitiveType = D3DPT_POINTLIST; + mPrimitiveCount = count; + break; + case GL_LINES: + mPrimitiveType = D3DPT_LINELIST; + mPrimitiveCount = count / 2; + break; + case GL_LINE_LOOP: + mPrimitiveType = D3DPT_LINESTRIP; + mPrimitiveCount = count - 1; // D3D doesn't support line loops, so we draw the last line separately + break; + case GL_LINE_STRIP: + mPrimitiveType = D3DPT_LINESTRIP; + mPrimitiveCount = count - 1; + break; + case GL_TRIANGLES: + mPrimitiveType = D3DPT_TRIANGLELIST; + mPrimitiveCount = count / 3; + break; + case GL_TRIANGLE_STRIP: + mPrimitiveType = D3DPT_TRIANGLESTRIP; + mPrimitiveCount = count - 2; + break; + case GL_TRIANGLE_FAN: + mPrimitiveType = D3DPT_TRIANGLEFAN; + mPrimitiveCount = count - 2; + break; + default: + UNREACHABLE(); + return false; + } + + return mPrimitiveCount > 0; +} + + +gl::Error Renderer9::getNullColorbuffer(const gl::FramebufferAttachment *depthbuffer, const gl::FramebufferAttachment **outColorBuffer) +{ + ASSERT(depthbuffer); + + GLsizei width = depthbuffer->getWidth(); + GLsizei height = depthbuffer->getHeight(); + + // search cached nullcolorbuffers + for (int i = 0; i < NUM_NULL_COLORBUFFER_CACHE_ENTRIES; i++) + { + if (mNullColorbufferCache[i].buffer != NULL && + mNullColorbufferCache[i].width == width && + mNullColorbufferCache[i].height == height) + { + mNullColorbufferCache[i].lruCount = ++mMaxNullColorbufferLRU; + *outColorBuffer = mNullColorbufferCache[i].buffer; + return gl::Error(GL_NO_ERROR); + } + } + + gl::Renderbuffer *nullRenderbuffer = new gl::Renderbuffer(createRenderbuffer(), 0); + gl::Error error = nullRenderbuffer->setStorage(GL_NONE, width, height); + if (error.isError()) + { + SafeDelete(nullRenderbuffer); + return error; + } + + gl::RenderbufferAttachment *nullbuffer = new gl::RenderbufferAttachment(GL_NONE, nullRenderbuffer); + + // add nullbuffer to the cache + NullColorbufferCacheEntry *oldest = &mNullColorbufferCache[0]; + for (int i = 1; i < NUM_NULL_COLORBUFFER_CACHE_ENTRIES; i++) + { + if (mNullColorbufferCache[i].lruCount < oldest->lruCount) + { + oldest = &mNullColorbufferCache[i]; + } + } + + delete oldest->buffer; + oldest->buffer = nullbuffer; + oldest->lruCount = ++mMaxNullColorbufferLRU; + oldest->width = width; + oldest->height = height; + + *outColorBuffer = nullbuffer; + return gl::Error(GL_NO_ERROR); +} + +gl::Error Renderer9::applyRenderTarget(const gl::FramebufferAttachment *colorBuffer, const gl::FramebufferAttachment *depthStencilBuffer) +{ + // if there is no color attachment we must synthesize a NULL colorattachment + // to keep the D3D runtime happy. This should only be possible if depth texturing. + if (!colorBuffer) + { + gl::Error error = getNullColorbuffer(depthStencilBuffer, &colorBuffer); + if (error.isError()) + { + return error; + } + } + ASSERT(colorBuffer); + + size_t renderTargetWidth = 0; + size_t renderTargetHeight = 0; + D3DFORMAT renderTargetFormat = D3DFMT_UNKNOWN; + + bool renderTargetChanged = false; + unsigned int renderTargetSerial = GetAttachmentSerial(colorBuffer); + if (renderTargetSerial != mAppliedRenderTargetSerial) + { + // Apply the render target on the device + RenderTarget9 *renderTarget = NULL; + gl::Error error = d3d9::GetAttachmentRenderTarget(colorBuffer, &renderTarget); + if (error.isError()) + { + return error; + } + ASSERT(renderTarget); + + IDirect3DSurface9 *renderTargetSurface = renderTarget->getSurface(); + ASSERT(renderTargetSurface); + + mDevice->SetRenderTarget(0, renderTargetSurface); + SafeRelease(renderTargetSurface); + + renderTargetWidth = renderTarget->getWidth(); + renderTargetHeight = renderTarget->getHeight(); + renderTargetFormat = renderTarget->getD3DFormat(); + + mAppliedRenderTargetSerial = renderTargetSerial; + renderTargetChanged = true; + } + + unsigned int depthStencilSerial = (depthStencilBuffer != nullptr) ? GetAttachmentSerial(depthStencilBuffer) : 0; + if (depthStencilSerial != mAppliedDepthStencilSerial || !mDepthStencilInitialized) + { + unsigned int depthSize = 0; + unsigned int stencilSize = 0; + + // Apply the depth stencil on the device + if (depthStencilBuffer) + { + RenderTarget9 *depthStencilRenderTarget = NULL; + gl::Error error = d3d9::GetAttachmentRenderTarget(depthStencilBuffer, &depthStencilRenderTarget); + if (error.isError()) + { + return error; + } + ASSERT(depthStencilRenderTarget); + + IDirect3DSurface9 *depthStencilSurface = depthStencilRenderTarget->getSurface(); + ASSERT(depthStencilSurface); + + mDevice->SetDepthStencilSurface(depthStencilSurface); + SafeRelease(depthStencilSurface); + + depthSize = depthStencilBuffer->getDepthSize(); + stencilSize = depthStencilBuffer->getStencilSize(); + } + else + { + mDevice->SetDepthStencilSurface(NULL); + } + + if (!mDepthStencilInitialized || depthSize != mCurDepthSize) + { + mCurDepthSize = depthSize; + mForceSetRasterState = true; + } + + if (!mDepthStencilInitialized || stencilSize != mCurStencilSize) + { + mCurStencilSize = stencilSize; + mForceSetDepthStencilState = true; + } + + mAppliedDepthStencilSerial = depthStencilSerial; + mDepthStencilInitialized = true; + } + + if (renderTargetChanged || !mRenderTargetDescInitialized) + { + mForceSetScissor = true; + mForceSetViewport = true; + mForceSetBlendState = true; + + mRenderTargetDesc.width = renderTargetWidth; + mRenderTargetDesc.height = renderTargetHeight; + mRenderTargetDesc.format = renderTargetFormat; + mRenderTargetDescInitialized = true; + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Renderer9::applyRenderTarget(const gl::Framebuffer *framebuffer) +{ + return applyRenderTarget(framebuffer->getColorbuffer(0), framebuffer->getDepthOrStencilbuffer()); +} + +gl::Error Renderer9::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()) + { + return error; + } + + return mVertexDeclarationCache.applyDeclaration(mDevice, attributes, state.getProgram(), instances, &mRepeatDraw); +} + +// Applies the indices and element array bindings to the Direct3D 9 device +gl::Error Renderer9::applyIndexBuffer(const GLvoid *indices, gl::Buffer *elementArrayBuffer, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo) +{ + gl::Error error = mIndexDataManager->prepareIndexData(type, count, elementArrayBuffer, indices, indexInfo); + if (error.isError()) + { + return error; + } + + // Directly binding the storage buffer is not supported for d3d9 + ASSERT(indexInfo->storage == NULL); + + if (indexInfo->serial != mAppliedIBSerial) + { + IndexBuffer9* indexBuffer = IndexBuffer9::makeIndexBuffer9(indexInfo->indexBuffer); + + mDevice->SetIndices(indexBuffer->getBuffer()); + mAppliedIBSerial = indexInfo->serial; + } + + return gl::Error(GL_NO_ERROR); +} + +void Renderer9::applyTransformFeedbackBuffers(const gl::State& state) +{ + ASSERT(!state.isTransformFeedbackActiveUnpaused()); +} + +gl::Error Renderer9::drawArrays(const gl::Data &data, GLenum mode, GLsizei count, GLsizei instances, bool usesPointSize) +{ + ASSERT(!data.state->isTransformFeedbackActiveUnpaused()); + + startScene(); + + if (mode == GL_LINE_LOOP) + { + return drawLineLoop(count, GL_NONE, NULL, 0, NULL); + } + else if (instances > 0) + { + StaticIndexBufferInterface *countingIB = NULL; + gl::Error error = getCountingIB(count, &countingIB); + if (error.isError()) + { + return error; + } + + if (mAppliedIBSerial != countingIB->getSerial()) + { + IndexBuffer9 *indexBuffer = IndexBuffer9::makeIndexBuffer9(countingIB->getIndexBuffer()); + + mDevice->SetIndices(indexBuffer->getBuffer()); + mAppliedIBSerial = countingIB->getSerial(); + } + + for (int i = 0; i < mRepeatDraw; i++) + { + mDevice->DrawIndexedPrimitive(mPrimitiveType, 0, 0, count, 0, mPrimitiveCount); + } + + return gl::Error(GL_NO_ERROR); + } + else // Regular case + { + mDevice->DrawPrimitive(mPrimitiveType, 0, mPrimitiveCount); + return gl::Error(GL_NO_ERROR); + } +} + +gl::Error Renderer9::drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, + gl::Buffer *elementArrayBuffer, const TranslatedIndexData &indexInfo, GLsizei /*instances*/) +{ + startScene(); + + int minIndex = static_cast(indexInfo.indexRange.start); + + if (mode == GL_POINTS) + { + return drawIndexedPoints(count, type, indices, minIndex, elementArrayBuffer); + } + else if (mode == GL_LINE_LOOP) + { + return drawLineLoop(count, type, indices, minIndex, elementArrayBuffer); + } + else + { + for (int i = 0; i < mRepeatDraw; i++) + { + GLsizei vertexCount = static_cast(indexInfo.indexRange.length()) + 1; + mDevice->DrawIndexedPrimitive(mPrimitiveType, -minIndex, minIndex, vertexCount, indexInfo.startIndex, mPrimitiveCount); + } + return gl::Error(GL_NO_ERROR); + } +} + +gl::Error Renderer9::drawLineLoop(GLsizei count, GLenum type, const GLvoid *indices, int minIndex, gl::Buffer *elementArrayBuffer) +{ + // Get the raw indices for an indexed draw + if (type != GL_NONE && elementArrayBuffer) + { + BufferD3D *storage = GetImplAs(elementArrayBuffer); + intptr_t offset = reinterpret_cast(indices); + const uint8_t *bufferData = NULL; + gl::Error error = storage->getData(&bufferData); + if (error.isError()) + { + return error; + } + indices = bufferData + offset; + } + + unsigned int startIndex = 0; + + if (getRendererExtensions().elementIndexUint) + { + if (!mLineLoopIB) + { + mLineLoopIB = new StreamingIndexBufferInterface(this); + gl::Error error = mLineLoopIB->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_INT); + if (error.isError()) + { + SafeDelete(mLineLoopIB); + return error; + } + } + + // Checked by Renderer9::applyPrimitiveType + ASSERT(count >= 0); + + if (static_cast(count) + 1 > (std::numeric_limits::max() / sizeof(unsigned int))) + { + 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(count)+1) * sizeof(unsigned int); + gl::Error error = mLineLoopIB->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_INT); + if (error.isError()) + { + return error; + } + + void* mappedMemory = NULL; + unsigned int offset = 0; + error = mLineLoopIB->mapBuffer(spaceNeeded, &mappedMemory, &offset); + if (error.isError()) + { + return error; + } + + startIndex = static_cast(offset) / 4; + unsigned int *data = reinterpret_cast(mappedMemory); + + 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(indices)[i]; + } + data[count] = static_cast(indices)[0]; + break; + case GL_UNSIGNED_SHORT: + for (int i = 0; i < count; i++) + { + data[i] = static_cast(indices)[i]; + } + data[count] = static_cast(indices)[0]; + break; + case GL_UNSIGNED_INT: + for (int i = 0; i < count; i++) + { + data[i] = static_cast(indices)[i]; + } + data[count] = static_cast(indices)[0]; + break; + default: UNREACHABLE(); + } + + error = mLineLoopIB->unmapBuffer(); + if (error.isError()) + { + return error; + } + } + else + { + if (!mLineLoopIB) + { + mLineLoopIB = new StreamingIndexBufferInterface(this); + gl::Error error = mLineLoopIB->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_SHORT); + if (error.isError()) + { + SafeDelete(mLineLoopIB); + return error; + } + } + + // Checked by Renderer9::applyPrimitiveType + ASSERT(count >= 0); + + if (static_cast(count) + 1 > (std::numeric_limits::max() / sizeof(unsigned short))) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create a 16-bit looping index buffer for GL_LINE_LOOP, too many indices required."); + } + + const unsigned int spaceNeeded = (static_cast(count) + 1) * sizeof(unsigned short); + gl::Error error = mLineLoopIB->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_SHORT); + if (error.isError()) + { + return error; + } + + void* mappedMemory = NULL; + unsigned int offset; + error = mLineLoopIB->mapBuffer(spaceNeeded, &mappedMemory, &offset); + if (error.isError()) + { + return error; + } + + startIndex = static_cast(offset) / 2; + unsigned short *data = reinterpret_cast(mappedMemory); + + 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(indices)[i]; + } + data[count] = static_cast(indices)[0]; + break; + case GL_UNSIGNED_SHORT: + for (int i = 0; i < count; i++) + { + data[i] = static_cast(indices)[i]; + } + data[count] = static_cast(indices)[0]; + break; + case GL_UNSIGNED_INT: + for (int i = 0; i < count; i++) + { + data[i] = static_cast(indices)[i]; + } + data[count] = static_cast(indices)[0]; + break; + default: UNREACHABLE(); + } + + error = mLineLoopIB->unmapBuffer(); + if (error.isError()) + { + return error; + } + } + + if (mAppliedIBSerial != mLineLoopIB->getSerial()) + { + IndexBuffer9 *indexBuffer = IndexBuffer9::makeIndexBuffer9(mLineLoopIB->getIndexBuffer()); + + mDevice->SetIndices(indexBuffer->getBuffer()); + mAppliedIBSerial = mLineLoopIB->getSerial(); + } + + mDevice->DrawIndexedPrimitive(D3DPT_LINESTRIP, -minIndex, minIndex, count, startIndex, count); + + return gl::Error(GL_NO_ERROR); +} + +template +static gl::Error drawPoints(IDirect3DDevice9* device, GLsizei count, const GLvoid *indices, int minIndex) +{ + for (int i = 0; i < count; i++) + { + unsigned int indexValue = static_cast(static_cast(indices)[i]) - minIndex; + device->DrawPrimitive(D3DPT_POINTLIST, indexValue, 1); + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Renderer9::drawIndexedPoints(GLsizei count, GLenum type, const GLvoid *indices, int minIndex, gl::Buffer *elementArrayBuffer) +{ + // Drawing index point lists is unsupported in d3d9, fall back to a regular DrawPrimitive call + // for each individual point. This call is not expected to happen often. + + if (elementArrayBuffer) + { + BufferD3D *storage = GetImplAs(elementArrayBuffer); + intptr_t offset = reinterpret_cast(indices); + + const uint8_t *bufferData = NULL; + gl::Error error = storage->getData(&bufferData); + if (error.isError()) + { + return error; + } + + indices = bufferData + offset; + } + + switch (type) + { + case GL_UNSIGNED_BYTE: return drawPoints(mDevice, count, indices, minIndex); + case GL_UNSIGNED_SHORT: return drawPoints(mDevice, count, indices, minIndex); + case GL_UNSIGNED_INT: return drawPoints(mDevice, count, indices, minIndex); + default: UNREACHABLE(); return gl::Error(GL_INVALID_OPERATION); + } +} + +gl::Error Renderer9::getCountingIB(size_t count, StaticIndexBufferInterface **outIB) +{ + // Update the counting index buffer if it is not large enough or has not been created yet. + if (count <= 65536) // 16-bit indices + { + const unsigned int spaceNeeded = count * sizeof(unsigned short); + + if (!mCountingIB || mCountingIB->getBufferSize() < spaceNeeded) + { + SafeDelete(mCountingIB); + mCountingIB = new StaticIndexBufferInterface(this); + mCountingIB->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_SHORT); + + void *mappedMemory = NULL; + gl::Error error = mCountingIB->mapBuffer(spaceNeeded, &mappedMemory, NULL); + if (error.isError()) + { + return error; + } + + unsigned short *data = reinterpret_cast(mappedMemory); + for (size_t i = 0; i < count; i++) + { + data[i] = i; + } + + error = mCountingIB->unmapBuffer(); + if (error.isError()) + { + return error; + } + } + } + else if (getRendererExtensions().elementIndexUint) + { + const unsigned int spaceNeeded = count * sizeof(unsigned int); + + if (!mCountingIB || mCountingIB->getBufferSize() < spaceNeeded) + { + SafeDelete(mCountingIB); + mCountingIB = new StaticIndexBufferInterface(this); + mCountingIB->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_INT); + + void *mappedMemory = NULL; + gl::Error error = mCountingIB->mapBuffer(spaceNeeded, &mappedMemory, NULL); + if (error.isError()) + { + return error; + } + + unsigned int *data = reinterpret_cast(mappedMemory); + for (size_t i = 0; i < count; i++) + { + data[i] = i; + } + + error = mCountingIB->unmapBuffer(); + if (error.isError()) + { + return error; + } + } + } + else + { + return gl::Error(GL_OUT_OF_MEMORY, "Could not create a counting index buffer for glDrawArraysInstanced."); + } + + *outIB = mCountingIB; + return gl::Error(GL_NO_ERROR); +} + +gl::Error Renderer9::applyShaders(gl::Program *program, const gl::VertexFormat inputLayout[], const gl::Framebuffer *framebuffer, + bool rasterizerDiscard, bool transformFeedbackActive) +{ + ASSERT(!transformFeedbackActive); + ASSERT(!rasterizerDiscard); + + ProgramD3D *programD3D = GetImplAs(program); + + ShaderExecutableD3D *vertexExe = NULL; + gl::Error error = programD3D->getVertexExecutableForInputLayout(inputLayout, &vertexExe, nullptr); + if (error.isError()) + { + return error; + } + + ShaderExecutableD3D *pixelExe = NULL; + error = programD3D->getPixelExecutableForFramebuffer(framebuffer, &pixelExe); + if (error.isError()) + { + return error; + } + + IDirect3DVertexShader9 *vertexShader = (vertexExe ? ShaderExecutable9::makeShaderExecutable9(vertexExe)->getVertexShader() : NULL); + IDirect3DPixelShader9 *pixelShader = (pixelExe ? ShaderExecutable9::makeShaderExecutable9(pixelExe)->getPixelShader() : NULL); + + if (vertexShader != mAppliedVertexShader) + { + mDevice->SetVertexShader(vertexShader); + mAppliedVertexShader = vertexShader; + } + + if (pixelShader != mAppliedPixelShader) + { + mDevice->SetPixelShader(pixelShader); + mAppliedPixelShader = pixelShader; + } + + // D3D9 has a quirk where creating multiple shaders with the same content + // can return the same shader pointer. Because GL programs store different data + // per-program, checking the program serial guarantees we upload fresh + // uniform data even if our shader pointers are the same. + // https://code.google.com/p/angleproject/issues/detail?id=661 + unsigned int programSerial = programD3D->getSerial(); + if (programSerial != mAppliedProgramSerial) + { + programD3D->dirtyAllUniforms(); + mDxUniformsDirty = true; + mAppliedProgramSerial = programSerial; + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Renderer9::applyUniforms(const ProgramImpl &program, const std::vector &uniformArray) +{ + for (size_t uniformIndex = 0; uniformIndex < uniformArray.size(); uniformIndex++) + { + gl::LinkedUniform *targetUniform = uniformArray[uniformIndex]; + + if (targetUniform->dirty) + { + GLfloat *f = (GLfloat*)targetUniform->data; + GLint *i = (GLint*)targetUniform->data; + + switch (targetUniform->type) + { + case GL_SAMPLER_2D: + case GL_SAMPLER_CUBE: + break; + case GL_BOOL: + case GL_BOOL_VEC2: + case GL_BOOL_VEC3: + case GL_BOOL_VEC4: + applyUniformnbv(targetUniform, i); + break; + case GL_FLOAT: + case GL_FLOAT_VEC2: + case GL_FLOAT_VEC3: + case GL_FLOAT_VEC4: + case GL_FLOAT_MAT2: + case GL_FLOAT_MAT3: + case GL_FLOAT_MAT4: + applyUniformnfv(targetUniform, f); + break; + case GL_INT: + case GL_INT_VEC2: + case GL_INT_VEC3: + case GL_INT_VEC4: + applyUniformniv(targetUniform, i); + break; + default: + UNREACHABLE(); + } + } + } + + // Driver uniforms + if (mDxUniformsDirty) + { + mDevice->SetVertexShaderConstantF(0, (float*)&mVertexConstants, sizeof(dx_VertexConstants) / sizeof(float[4])); + mDevice->SetPixelShaderConstantF(0, (float*)&mPixelConstants, sizeof(dx_PixelConstants) / sizeof(float[4])); + mDxUniformsDirty = false; + } + + return gl::Error(GL_NO_ERROR); +} + +void Renderer9::applyUniformnfv(gl::LinkedUniform *targetUniform, const GLfloat *v) +{ + if (targetUniform->isReferencedByFragmentShader()) + { + mDevice->SetPixelShaderConstantF(targetUniform->psRegisterIndex, v, targetUniform->registerCount); + } + + if (targetUniform->isReferencedByVertexShader()) + { + mDevice->SetVertexShaderConstantF(targetUniform->vsRegisterIndex, v, targetUniform->registerCount); + } +} + +void Renderer9::applyUniformniv(gl::LinkedUniform *targetUniform, const GLint *v) +{ + ASSERT(targetUniform->registerCount <= MAX_VERTEX_CONSTANT_VECTORS_D3D9); + GLfloat vector[MAX_VERTEX_CONSTANT_VECTORS_D3D9][4]; + + for (unsigned int i = 0; i < targetUniform->registerCount; i++) + { + vector[i][0] = (GLfloat)v[4 * i + 0]; + vector[i][1] = (GLfloat)v[4 * i + 1]; + vector[i][2] = (GLfloat)v[4 * i + 2]; + vector[i][3] = (GLfloat)v[4 * i + 3]; + } + + applyUniformnfv(targetUniform, (GLfloat*)vector); +} + +void Renderer9::applyUniformnbv(gl::LinkedUniform *targetUniform, const GLint *v) +{ + ASSERT(targetUniform->registerCount <= MAX_VERTEX_CONSTANT_VECTORS_D3D9); + GLfloat vector[MAX_VERTEX_CONSTANT_VECTORS_D3D9][4]; + + for (unsigned int i = 0; i < targetUniform->registerCount; i++) + { + vector[i][0] = (v[4 * i + 0] == GL_FALSE) ? 0.0f : 1.0f; + vector[i][1] = (v[4 * i + 1] == GL_FALSE) ? 0.0f : 1.0f; + vector[i][2] = (v[4 * i + 2] == GL_FALSE) ? 0.0f : 1.0f; + vector[i][3] = (v[4 * i + 3] == GL_FALSE) ? 0.0f : 1.0f; + } + + applyUniformnfv(targetUniform, (GLfloat*)vector); +} + +gl::Error Renderer9::clear(const ClearParameters &clearParams, + const gl::FramebufferAttachment *colorBuffer, + const gl::FramebufferAttachment *depthStencilBuffer) +{ + if (clearParams.colorClearType != GL_FLOAT) + { + // Clearing buffers with non-float values is not supported by Renderer9 and ES 2.0 + UNREACHABLE(); + return gl::Error(GL_INVALID_OPERATION); + } + + bool clearColor = clearParams.clearColor[0]; + for (unsigned int i = 0; i < ArraySize(clearParams.clearColor); i++) + { + if (clearParams.clearColor[i] != clearColor) + { + // Clearing individual buffers other than buffer zero is not supported by Renderer9 and ES 2.0 + UNREACHABLE(); + return gl::Error(GL_INVALID_OPERATION); + } + } + + float depth = gl::clamp01(clearParams.depthClearValue); + DWORD stencil = clearParams.stencilClearValue & 0x000000FF; + + unsigned int stencilUnmasked = 0x0; + if (clearParams.clearStencil && depthStencilBuffer->getStencilSize() > 0) + { + RenderTargetD3D *stencilRenderTarget = NULL; + gl::Error error = GetAttachmentRenderTarget(depthStencilBuffer, &stencilRenderTarget); + if (error.isError()) + { + return error; + } + + RenderTarget9 *stencilRenderTarget9 = RenderTarget9::makeRenderTarget9(stencilRenderTarget); + ASSERT(stencilRenderTarget9); + + const d3d9::D3DFormat &d3dFormatInfo = d3d9::GetD3DFormatInfo(stencilRenderTarget9->getD3DFormat()); + stencilUnmasked = (0x1 << d3dFormatInfo.stencilBits) - 1; + } + + const bool needMaskedStencilClear = clearParams.clearStencil && + (clearParams.stencilWriteMask & stencilUnmasked) != stencilUnmasked; + + bool needMaskedColorClear = false; + D3DCOLOR color = D3DCOLOR_ARGB(255, 0, 0, 0); + if (clearColor) + { + RenderTargetD3D *colorRenderTarget = NULL; + gl::Error error = GetAttachmentRenderTarget(colorBuffer, &colorRenderTarget); + if (error.isError()) + { + return error; + } + + RenderTarget9 *colorRenderTarget9 = RenderTarget9::makeRenderTarget9(colorRenderTarget); + ASSERT(colorRenderTarget9); + + const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(colorBuffer->getInternalFormat()); + const d3d9::D3DFormat &d3dFormatInfo = d3d9::GetD3DFormatInfo(colorRenderTarget9->getD3DFormat()); + + color = D3DCOLOR_ARGB(gl::unorm<8>((formatInfo.alphaBits == 0 && d3dFormatInfo.alphaBits > 0) ? 1.0f : clearParams.colorFClearValue.alpha), + gl::unorm<8>((formatInfo.redBits == 0 && d3dFormatInfo.redBits > 0) ? 0.0f : clearParams.colorFClearValue.red), + gl::unorm<8>((formatInfo.greenBits == 0 && d3dFormatInfo.greenBits > 0) ? 0.0f : clearParams.colorFClearValue.green), + gl::unorm<8>((formatInfo.blueBits == 0 && d3dFormatInfo.blueBits > 0) ? 0.0f : clearParams.colorFClearValue.blue)); + + if ((formatInfo.redBits > 0 && !clearParams.colorMaskRed) || + (formatInfo.greenBits > 0 && !clearParams.colorMaskGreen) || + (formatInfo.blueBits > 0 && !clearParams.colorMaskBlue) || + (formatInfo.alphaBits > 0 && !clearParams.colorMaskAlpha)) + { + needMaskedColorClear = true; + } + } + + if (needMaskedColorClear || needMaskedStencilClear) + { + // State which is altered in all paths from this point to the clear call is saved. + // State which is altered in only some paths will be flagged dirty in the case that + // that path is taken. + HRESULT hr; + if (mMaskedClearSavedState == NULL) + { + hr = mDevice->BeginStateBlock(); + ASSERT(SUCCEEDED(hr) || hr == D3DERR_OUTOFVIDEOMEMORY || hr == E_OUTOFMEMORY); + + mDevice->SetRenderState(D3DRS_ZWRITEENABLE, FALSE); + mDevice->SetRenderState(D3DRS_ZFUNC, D3DCMP_ALWAYS); + mDevice->SetRenderState(D3DRS_ZENABLE, FALSE); + mDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); + mDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID); + mDevice->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE); + mDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); + mDevice->SetRenderState(D3DRS_CLIPPLANEENABLE, 0); + mDevice->SetRenderState(D3DRS_COLORWRITEENABLE, 0); + mDevice->SetRenderState(D3DRS_STENCILENABLE, FALSE); + mDevice->SetPixelShader(NULL); + mDevice->SetVertexShader(NULL); + mDevice->SetFVF(D3DFVF_XYZRHW | D3DFVF_DIFFUSE); + mDevice->SetStreamSource(0, NULL, 0, 0); + mDevice->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, TRUE); + mDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1); + mDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TFACTOR); + mDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1); + mDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TFACTOR); + mDevice->SetRenderState(D3DRS_TEXTUREFACTOR, color); + mDevice->SetRenderState(D3DRS_MULTISAMPLEMASK, 0xFFFFFFFF); + + for(int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) + { + mDevice->SetStreamSourceFreq(i, 1); + } + + hr = mDevice->EndStateBlock(&mMaskedClearSavedState); + ASSERT(SUCCEEDED(hr) || hr == D3DERR_OUTOFVIDEOMEMORY || hr == E_OUTOFMEMORY); + } + + ASSERT(mMaskedClearSavedState != NULL); + + if (mMaskedClearSavedState != NULL) + { + hr = mMaskedClearSavedState->Capture(); + ASSERT(SUCCEEDED(hr)); + } + + mDevice->SetRenderState(D3DRS_ZWRITEENABLE, FALSE); + mDevice->SetRenderState(D3DRS_ZFUNC, D3DCMP_ALWAYS); + mDevice->SetRenderState(D3DRS_ZENABLE, FALSE); + mDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); + mDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID); + mDevice->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE); + mDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); + mDevice->SetRenderState(D3DRS_CLIPPLANEENABLE, 0); + + if (clearColor) + { + mDevice->SetRenderState(D3DRS_COLORWRITEENABLE, + gl_d3d9::ConvertColorMask(clearParams.colorMaskRed, + clearParams.colorMaskGreen, + clearParams.colorMaskBlue, + clearParams.colorMaskAlpha)); + } + else + { + mDevice->SetRenderState(D3DRS_COLORWRITEENABLE, 0); + } + + if (stencilUnmasked != 0x0 && clearParams.clearStencil) + { + mDevice->SetRenderState(D3DRS_STENCILENABLE, TRUE); + mDevice->SetRenderState(D3DRS_TWOSIDEDSTENCILMODE, FALSE); + mDevice->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_ALWAYS); + mDevice->SetRenderState(D3DRS_STENCILREF, stencil); + mDevice->SetRenderState(D3DRS_STENCILWRITEMASK, clearParams.stencilWriteMask); + mDevice->SetRenderState(D3DRS_STENCILFAIL, D3DSTENCILOP_REPLACE); + mDevice->SetRenderState(D3DRS_STENCILZFAIL, D3DSTENCILOP_REPLACE); + mDevice->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_REPLACE); + } + else + { + mDevice->SetRenderState(D3DRS_STENCILENABLE, FALSE); + } + + mDevice->SetPixelShader(NULL); + mDevice->SetVertexShader(NULL); + mDevice->SetFVF(D3DFVF_XYZRHW); + mDevice->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, TRUE); + mDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1); + mDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TFACTOR); + mDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1); + mDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TFACTOR); + mDevice->SetRenderState(D3DRS_TEXTUREFACTOR, color); + mDevice->SetRenderState(D3DRS_MULTISAMPLEMASK, 0xFFFFFFFF); + + for(int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) + { + mDevice->SetStreamSourceFreq(i, 1); + } + + float quad[4][4]; // A quadrilateral covering the target, aligned to match the edges + quad[0][0] = -0.5f; + quad[0][1] = mRenderTargetDesc.height - 0.5f; + quad[0][2] = 0.0f; + quad[0][3] = 1.0f; + + quad[1][0] = mRenderTargetDesc.width - 0.5f; + quad[1][1] = mRenderTargetDesc.height - 0.5f; + quad[1][2] = 0.0f; + quad[1][3] = 1.0f; + + quad[2][0] = -0.5f; + quad[2][1] = -0.5f; + quad[2][2] = 0.0f; + quad[2][3] = 1.0f; + + quad[3][0] = mRenderTargetDesc.width - 0.5f; + quad[3][1] = -0.5f; + quad[3][2] = 0.0f; + quad[3][3] = 1.0f; + + startScene(); + mDevice->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, quad, sizeof(float[4])); + + if (clearParams.clearDepth) + { + mDevice->SetRenderState(D3DRS_ZENABLE, TRUE); + mDevice->SetRenderState(D3DRS_ZWRITEENABLE, TRUE); + mDevice->Clear(0, NULL, D3DCLEAR_ZBUFFER, color, depth, stencil); + } + + if (mMaskedClearSavedState != NULL) + { + mMaskedClearSavedState->Apply(); + } + } + else if (clearColor || clearParams.clearDepth || clearParams.clearStencil) + { + DWORD dxClearFlags = 0; + if (clearColor) + { + dxClearFlags |= D3DCLEAR_TARGET; + } + if (clearParams.clearDepth) + { + dxClearFlags |= D3DCLEAR_ZBUFFER; + } + if (clearParams.clearStencil) + { + dxClearFlags |= D3DCLEAR_STENCIL; + } + + mDevice->Clear(0, NULL, dxClearFlags, color, depth, stencil); + } + + return gl::Error(GL_NO_ERROR); +} + +void Renderer9::markAllStateDirty() +{ + mAppliedRenderTargetSerial = 0; + mAppliedDepthStencilSerial = 0; + mDepthStencilInitialized = false; + mRenderTargetDescInitialized = false; + + mForceSetDepthStencilState = true; + mForceSetRasterState = true; + mForceSetScissor = true; + mForceSetViewport = true; + mForceSetBlendState = true; + + ASSERT(mForceSetVertexSamplerStates.size() == mCurVertexTextureSerials.size()); + for (unsigned int i = 0; i < mForceSetVertexSamplerStates.size(); i++) + { + mForceSetVertexSamplerStates[i] = true; + mCurVertexTextureSerials[i] = 0; + } + + ASSERT(mForceSetPixelSamplerStates.size() == mCurPixelTextureSerials.size()); + for (unsigned int i = 0; i < mForceSetPixelSamplerStates.size(); i++) + { + mForceSetPixelSamplerStates[i] = true; + mCurPixelTextureSerials[i] = 0; + } + + mAppliedIBSerial = 0; + mAppliedVertexShader = NULL; + mAppliedPixelShader = NULL; + mAppliedProgramSerial = 0; + mDxUniformsDirty = true; + + mVertexDeclarationCache.markStateDirty(); +} + +void Renderer9::releaseDeviceResources() +{ + for (size_t i = 0; i < mEventQueryPool.size(); i++) + { + SafeRelease(mEventQueryPool[i]); + } + mEventQueryPool.clear(); + + SafeRelease(mMaskedClearSavedState); + + mVertexShaderCache.clear(); + mPixelShaderCache.clear(); + + SafeDelete(mBlit); + SafeDelete(mVertexDataManager); + SafeDelete(mIndexDataManager); + SafeDelete(mLineLoopIB); + SafeDelete(mCountingIB); + + for (int i = 0; i < NUM_NULL_COLORBUFFER_CACHE_ENTRIES; i++) + { + SafeDelete(mNullColorbufferCache[i].buffer); + } +} + +// set notify to true to broadcast a message to all contexts of the device loss +bool Renderer9::testDeviceLost() +{ + HRESULT status = getDeviceStatusCode(); + bool isLost = FAILED(status); + + if (isLost) + { + // ensure we note the device loss -- + // we'll probably get this done again by notifyDeviceLost + // but best to remember it! + // Note that we don't want to clear the device loss status here + // -- this needs to be done by resetDevice + mDeviceLost = true; + } + + return isLost; +} + +HRESULT Renderer9::getDeviceStatusCode() +{ + HRESULT status = D3D_OK; + + if (mDeviceEx) + { + status = mDeviceEx->CheckDeviceState(NULL); + } + else if (mDevice) + { + status = mDevice->TestCooperativeLevel(); + } + + return status; +} + +bool Renderer9::testDeviceResettable() +{ + // On D3D9Ex, DEVICELOST represents a hung device that needs to be restarted + // DEVICEREMOVED indicates the device has been stopped and must be recreated + switch (getDeviceStatusCode()) + { + case D3DERR_DEVICENOTRESET: + case D3DERR_DEVICEHUNG: + return true; + case D3DERR_DEVICELOST: + return (mDeviceEx != NULL); + case D3DERR_DEVICEREMOVED: + ASSERT(mDeviceEx != NULL); + return isRemovedDeviceResettable(); + default: + return false; + } +} + +bool Renderer9::resetDevice() +{ + releaseDeviceResources(); + + D3DPRESENT_PARAMETERS presentParameters = getDefaultPresentParameters(); + + HRESULT result = D3D_OK; + bool lost = testDeviceLost(); + bool removedDevice = (getDeviceStatusCode() == D3DERR_DEVICEREMOVED); + + // Device Removed is a feature which is only present with D3D9Ex + ASSERT(mDeviceEx != NULL || !removedDevice); + + for (int attempts = 3; lost && attempts > 0; attempts--) + { + if (removedDevice) + { + // Device removed, which may trigger on driver reinstallation, + // may cause a longer wait other reset attempts before the + // system is ready to handle creating a new device. + Sleep(800); + lost = !resetRemovedDevice(); + } + else if (mDeviceEx) + { + Sleep(500); // Give the graphics driver some CPU time + result = mDeviceEx->ResetEx(&presentParameters, NULL); + lost = testDeviceLost(); + } + else + { + result = mDevice->TestCooperativeLevel(); + while (result == D3DERR_DEVICELOST) + { + Sleep(100); // Give the graphics driver some CPU time + result = mDevice->TestCooperativeLevel(); + } + + if (result == D3DERR_DEVICENOTRESET) + { + result = mDevice->Reset(&presentParameters); + } + lost = testDeviceLost(); + } + } + + if (FAILED(result)) + { + ERR("Reset/ResetEx failed multiple times: 0x%08X", result); + return false; + } + + if (removedDevice && lost) + { + ERR("Device lost reset failed multiple times"); + return false; + } + + // If the device was removed, we already finished re-initialization in resetRemovedDevice + if (!removedDevice) + { + // reset device defaults + initializeDevice(); + } + + mDeviceLost = false; + + return true; +} + +bool Renderer9::isRemovedDeviceResettable() const +{ + bool success = false; + +#if ANGLE_D3D9EX == ANGLE_ENABLED + IDirect3D9Ex *d3d9Ex = NULL; + typedef HRESULT (WINAPI *Direct3DCreate9ExFunc)(UINT, IDirect3D9Ex**); + Direct3DCreate9ExFunc Direct3DCreate9ExPtr = reinterpret_cast(GetProcAddress(mD3d9Module, "Direct3DCreate9Ex")); + + if (Direct3DCreate9ExPtr && SUCCEEDED(Direct3DCreate9ExPtr(D3D_SDK_VERSION, &d3d9Ex))) + { + D3DCAPS9 deviceCaps; + HRESULT result = d3d9Ex->GetDeviceCaps(mAdapter, mDeviceType, &deviceCaps); + success = SUCCEEDED(result); + } + + SafeRelease(d3d9Ex); +#else + ASSERT(UNREACHABLE()); +#endif + + return success; +} + +bool Renderer9::resetRemovedDevice() +{ + // From http://msdn.microsoft.com/en-us/library/windows/desktop/bb172554(v=vs.85).aspx: + // The hardware adapter has been removed. Application must destroy the device, do enumeration of + // adapters and create another Direct3D device. If application continues rendering without + // calling Reset, the rendering calls will succeed. Applies to Direct3D 9Ex only. + release(); + return !initialize().isError(); +} + +VendorID Renderer9::getVendorId() const +{ + return static_cast(mAdapterIdentifier.VendorId); +} + +std::string Renderer9::getRendererDescription() const +{ + std::ostringstream rendererString; + + rendererString << mAdapterIdentifier.Description; + if (getShareHandleSupport()) + { + rendererString << " Direct3D9Ex"; + } + else + { + rendererString << " Direct3D9"; + } + + rendererString << " vs_" << D3DSHADER_VERSION_MAJOR(mDeviceCaps.VertexShaderVersion) << "_" << D3DSHADER_VERSION_MINOR(mDeviceCaps.VertexShaderVersion); + rendererString << " ps_" << D3DSHADER_VERSION_MAJOR(mDeviceCaps.PixelShaderVersion) << "_" << D3DSHADER_VERSION_MINOR(mDeviceCaps.PixelShaderVersion); + + return rendererString.str(); +} + +GUID Renderer9::getAdapterIdentifier() const +{ + return mAdapterIdentifier.DeviceIdentifier; +} + +unsigned int Renderer9::getReservedVertexUniformVectors() const +{ + return 2; // dx_ViewAdjust and dx_DepthRange. +} + +unsigned int Renderer9::getReservedFragmentUniformVectors() const +{ + return 3; // dx_ViewCoords, dx_DepthFront and dx_DepthRange. +} + +unsigned int Renderer9::getReservedVertexUniformBuffers() const +{ + return 0; +} + +unsigned int Renderer9::getReservedFragmentUniformBuffers() const +{ + return 0; +} + +bool Renderer9::getShareHandleSupport() const +{ + // PIX doesn't seem to support using share handles, so disable them. + return (mD3d9Ex != NULL) && !gl::DebugAnnotationsActive(); +} + +bool Renderer9::getPostSubBufferSupport() const +{ + return true; +} + +int Renderer9::getMajorShaderModel() const +{ + return D3DSHADER_VERSION_MAJOR(mDeviceCaps.PixelShaderVersion); +} + +int Renderer9::getMinorShaderModel() const +{ + return D3DSHADER_VERSION_MINOR(mDeviceCaps.PixelShaderVersion); +} + +std::string Renderer9::getShaderModelSuffix() const +{ + return ""; +} + +DWORD Renderer9::getCapsDeclTypes() const +{ + return mDeviceCaps.DeclTypes; +} + +D3DPOOL Renderer9::getBufferPool(DWORD usage) const +{ + if (mD3d9Ex != NULL) + { + return D3DPOOL_DEFAULT; + } + else + { + if (!(usage & D3DUSAGE_DYNAMIC)) + { + return D3DPOOL_MANAGED; + } + } + + return D3DPOOL_DEFAULT; +} + +gl::Error Renderer9::copyImage2D(const gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, + const gl::Offset &destOffset, TextureStorage *storage, GLint level) +{ + RECT rect; + rect.left = sourceRect.x; + rect.top = sourceRect.y; + rect.right = sourceRect.x + sourceRect.width; + rect.bottom = sourceRect.y + sourceRect.height; + + return mBlit->copy2D(framebuffer, rect, destFormat, destOffset, storage, level); +} + +gl::Error Renderer9::copyImageCube(const gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, + const gl::Offset &destOffset, TextureStorage *storage, GLenum target, GLint level) +{ + RECT rect; + rect.left = sourceRect.x; + rect.top = sourceRect.y; + rect.right = sourceRect.x + sourceRect.width; + rect.bottom = sourceRect.y + sourceRect.height; + + return mBlit->copyCube(framebuffer, rect, destFormat, destOffset, storage, target, level); +} + +gl::Error Renderer9::copyImage3D(const gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, + const gl::Offset &destOffset, TextureStorage *storage, GLint level) +{ + // 3D textures are not available in the D3D9 backend. + UNREACHABLE(); + return gl::Error(GL_INVALID_OPERATION); +} + +gl::Error Renderer9::copyImage2DArray(const gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, + const gl::Offset &destOffset, TextureStorage *storage, GLint level) +{ + // 2D array textures are not available in the D3D9 backend. + UNREACHABLE(); + return gl::Error(GL_INVALID_OPERATION); +} + +gl::Error Renderer9::createRenderTarget(int width, int height, GLenum format, GLsizei samples, RenderTargetD3D **outRT) +{ + const d3d9::TextureFormat &d3d9FormatInfo = d3d9::GetTextureFormatInfo(format); + + const gl::TextureCaps &textureCaps = getRendererTextureCaps().get(format); + GLuint supportedSamples = textureCaps.getNearestSamples(samples); + + IDirect3DSurface9 *renderTarget = NULL; + if (width > 0 && height > 0) + { + bool requiresInitialization = false; + HRESULT result = D3DERR_INVALIDCALL; + + const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format); + if (formatInfo.depthBits > 0 || formatInfo.stencilBits > 0) + { + result = mDevice->CreateDepthStencilSurface(width, height, d3d9FormatInfo.renderFormat, + gl_d3d9::GetMultisampleType(supportedSamples), + 0, FALSE, &renderTarget, NULL); + } + else + { + requiresInitialization = (d3d9FormatInfo.dataInitializerFunction != NULL); + result = mDevice->CreateRenderTarget(width, height, d3d9FormatInfo.renderFormat, + gl_d3d9::GetMultisampleType(supportedSamples), + 0, FALSE, &renderTarget, NULL); + } + + if (FAILED(result)) + { + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create render target, result: 0x%X.", result); + } + + if (requiresInitialization) + { + // This format requires that the data be initialized before the render target can be used + // Unfortunately this requires a Get call on the d3d device but it is far better than having + // to mark the render target as lockable and copy data to the gpu. + IDirect3DSurface9 *prevRenderTarget = NULL; + mDevice->GetRenderTarget(0, &prevRenderTarget); + mDevice->SetRenderTarget(0, renderTarget); + mDevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_RGBA(0, 0, 0, 255), 0.0f, 0); + mDevice->SetRenderTarget(0, prevRenderTarget); + } + } + + *outRT = new TextureRenderTarget9(renderTarget, format, width, height, 1, supportedSamples); + return gl::Error(GL_NO_ERROR); +} + +FramebufferImpl *Renderer9::createDefaultFramebuffer(const gl::Framebuffer::Data &data) +{ + return createFramebuffer(data); +} + +FramebufferImpl *Renderer9::createFramebuffer(const gl::Framebuffer::Data &data) +{ + return new Framebuffer9(data, this); +} + +CompilerImpl *Renderer9::createCompiler(const gl::Data &data) +{ + return new CompilerD3D(data, SH_HLSL9_OUTPUT); +} + +ShaderImpl *Renderer9::createShader(GLenum type) +{ + return new ShaderD3D(type); +} + +ProgramImpl *Renderer9::createProgram() +{ + return new ProgramD3D(this); +} + +gl::Error Renderer9::loadExecutable(const void *function, size_t length, ShaderType type, + const std::vector &transformFeedbackVaryings, + bool separatedOutputBuffers, ShaderExecutableD3D **outExecutable) +{ + // Transform feedback is not supported in ES2 or D3D9 + ASSERT(transformFeedbackVaryings.size() == 0); + + switch (type) + { + case SHADER_VERTEX: + { + IDirect3DVertexShader9 *vshader = NULL; + gl::Error error = createVertexShader((DWORD*)function, length, &vshader); + if (error.isError()) + { + return error; + } + *outExecutable = new ShaderExecutable9(function, length, vshader); + } + break; + case SHADER_PIXEL: + { + IDirect3DPixelShader9 *pshader = NULL; + gl::Error error = createPixelShader((DWORD*)function, length, &pshader); + if (error.isError()) + { + return error; + } + *outExecutable = new ShaderExecutable9(function, length, pshader); + } + break; + default: + UNREACHABLE(); + return gl::Error(GL_INVALID_OPERATION); + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Renderer9::compileToExecutable(gl::InfoLog &infoLog, const std::string &shaderHLSL, ShaderType type, + const std::vector &transformFeedbackVaryings, + bool separatedOutputBuffers, const D3DCompilerWorkarounds &workarounds, + ShaderExecutableD3D **outExectuable) +{ + // Transform feedback is not supported in ES2 or D3D9 + ASSERT(transformFeedbackVaryings.size() == 0); + + const char *profileType = NULL; + switch (type) + { + case SHADER_VERTEX: + profileType = "vs"; + break; + case SHADER_PIXEL: + profileType = "ps"; + break; + default: + UNREACHABLE(); + return gl::Error(GL_INVALID_OPERATION); + } + unsigned int profileMajorVersion = (getMajorShaderModel() >= 3) ? 3 : 2; + unsigned int profileMinorVersion = 0; + std::string profile = FormatString("%s_%u_%u", profileType, profileMajorVersion, profileMinorVersion); + + UINT flags = ANGLE_COMPILE_OPTIMIZATION_LEVEL; + + if (workarounds.skipOptimization) + { + flags = D3DCOMPILE_SKIP_OPTIMIZATION; + } + else if (workarounds.useMaxOptimization) + { + flags = D3DCOMPILE_OPTIMIZATION_LEVEL3; + } + + if (gl::DebugAnnotationsActive()) + { +#ifndef NDEBUG + flags = D3DCOMPILE_SKIP_OPTIMIZATION; +#endif + + flags |= D3DCOMPILE_DEBUG; + } + + // Sometimes D3DCompile will fail with the default compilation flags for complicated shaders when it would otherwise pass with alternative options. + // Try the default flags first and if compilation fails, try some alternatives. + std::vector configs; + configs.push_back(CompileConfig(flags, "default" )); + configs.push_back(CompileConfig(flags | D3DCOMPILE_AVOID_FLOW_CONTROL, "avoid flow control" )); + configs.push_back(CompileConfig(flags | D3DCOMPILE_PREFER_FLOW_CONTROL, "prefer flow control")); + + ID3DBlob *binary = NULL; + std::string debugInfo; + gl::Error error = mCompiler.compileToBinary(infoLog, shaderHLSL, profile, configs, NULL, &binary, &debugInfo); + if (error.isError()) + { + return error; + } + + // It's possible that binary is NULL if the compiler failed in all configurations. Set the executable to NULL + // and return GL_NO_ERROR to signify that there was a link error but the internal state is still OK. + if (!binary) + { + *outExectuable = NULL; + return gl::Error(GL_NO_ERROR); + } + + error = loadExecutable(binary->GetBufferPointer(), binary->GetBufferSize(), type, + transformFeedbackVaryings, separatedOutputBuffers, outExectuable); + + SafeRelease(binary); + if (error.isError()) + { + return error; + } + + if (!debugInfo.empty()) + { + (*outExectuable)->appendDebugInfo(debugInfo); + } + + return gl::Error(GL_NO_ERROR); +} + +UniformStorageD3D *Renderer9::createUniformStorage(size_t storageSize) +{ + return new UniformStorageD3D(storageSize); +} + +gl::Error Renderer9::boxFilter(IDirect3DSurface9 *source, IDirect3DSurface9 *dest) +{ + return mBlit->boxFilter(source, dest); +} + +D3DPOOL Renderer9::getTexturePool(DWORD usage) const +{ + if (mD3d9Ex != NULL) + { + return D3DPOOL_DEFAULT; + } + else + { + if (!(usage & (D3DUSAGE_DEPTHSTENCIL | D3DUSAGE_RENDERTARGET))) + { + return D3DPOOL_MANAGED; + } + } + + return D3DPOOL_DEFAULT; +} + +gl::Error Renderer9::copyToRenderTarget(IDirect3DSurface9 *dest, IDirect3DSurface9 *source, bool fromManaged) +{ + ASSERT(source && dest); + + HRESULT result = D3DERR_OUTOFVIDEOMEMORY; + + if (fromManaged) + { + D3DSURFACE_DESC desc; + source->GetDesc(&desc); + + IDirect3DSurface9 *surf = 0; + result = mDevice->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format, D3DPOOL_SYSTEMMEM, &surf, NULL); + + if (SUCCEEDED(result)) + { + Image9::copyLockableSurfaces(surf, source); + result = mDevice->UpdateSurface(surf, NULL, dest, NULL); + SafeRelease(surf); + } + } + else + { + endScene(); + result = mDevice->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE); + } + + if (FAILED(result)) + { + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to blit internal texture, result: 0x%X.", result); + } + + return gl::Error(GL_NO_ERROR); +} + +ImageD3D *Renderer9::createImage() +{ + return new Image9(this); +} + +gl::Error Renderer9::generateMipmap(ImageD3D *dest, ImageD3D *src) +{ + Image9 *src9 = Image9::makeImage9(src); + Image9 *dst9 = Image9::makeImage9(dest); + return Image9::generateMipmap(dst9, src9); +} + +TextureStorage *Renderer9::createTextureStorage2D(SwapChainD3D *swapChain) +{ + SwapChain9 *swapChain9 = SwapChain9::makeSwapChain9(swapChain); + return new TextureStorage9_2D(this, swapChain9); +} + +TextureStorage *Renderer9::createTextureStorage2D(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels, bool hintLevelZeroOnly) +{ + return new TextureStorage9_2D(this, internalformat, renderTarget, width, height, levels); +} + +TextureStorage *Renderer9::createTextureStorageCube(GLenum internalformat, bool renderTarget, int size, int levels, bool hintLevelZeroOnly) +{ + return new TextureStorage9_Cube(this, internalformat, renderTarget, size, levels, hintLevelZeroOnly); +} + +TextureStorage *Renderer9::createTextureStorage3D(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth, int levels) +{ + // 3D textures are not supported by the D3D9 backend. + UNREACHABLE(); + + return NULL; +} + +TextureStorage *Renderer9::createTextureStorage2DArray(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth, int levels) +{ + // 2D array textures are not supported by the D3D9 backend. + UNREACHABLE(); + + return NULL; +} + +TextureImpl *Renderer9::createTexture(GLenum target) +{ + switch(target) + { + case GL_TEXTURE_2D: return new TextureD3D_2D(this); + case GL_TEXTURE_CUBE_MAP: return new TextureD3D_Cube(this); + default: UNREACHABLE(); + } + + return NULL; +} + +RenderbufferImpl *Renderer9::createRenderbuffer() +{ + RenderbufferD3D *renderbuffer = new RenderbufferD3D(this); + return renderbuffer; +} + +bool Renderer9::getLUID(LUID *adapterLuid) const +{ + adapterLuid->HighPart = 0; + adapterLuid->LowPart = 0; + + if (mD3d9Ex) + { + mD3d9Ex->GetAdapterLUID(mAdapter, adapterLuid); + return true; + } + + return false; +} + +VertexConversionType Renderer9::getVertexConversionType(const gl::VertexFormat &vertexFormat) const +{ + return d3d9::GetVertexFormatInfo(getCapsDeclTypes(), vertexFormat).conversionType; +} + +GLenum Renderer9::getVertexComponentType(const gl::VertexFormat &vertexFormat) const +{ + return d3d9::GetVertexFormatInfo(getCapsDeclTypes(), vertexFormat).componentType; +} + +void Renderer9::generateCaps(gl::Caps *outCaps, gl::TextureCapsMap *outTextureCaps, gl::Extensions *outExtensions) const +{ + d3d9_gl::GenerateCaps(mD3d9, mDevice, mDeviceType, mAdapter, outCaps, outTextureCaps, outExtensions); +} + +Workarounds Renderer9::generateWorkarounds() const +{ + return d3d9::GenerateWorkarounds(); +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Renderer9.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Renderer9.h new file mode 100644 index 0000000000..19bea3eb35 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Renderer9.h @@ -0,0 +1,377 @@ +// +// Copyright (c) 2012-2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Renderer9.h: Defines a back-end specific class for the D3D9 renderer. + +#ifndef LIBANGLE_RENDERER_D3D_D3D9_RENDERER9_H_ +#define LIBANGLE_RENDERER_D3D_D3D9_RENDERER9_H_ + +#include "common/angleutils.h" +#include "common/mathutil.h" +#include "libANGLE/renderer/d3d/HLSLCompiler.h" +#include "libANGLE/renderer/d3d/RendererD3D.h" +#include "libANGLE/renderer/d3d/RenderTargetD3D.h" +#include "libANGLE/renderer/d3d/d3d9/DebugAnnotator9.h" +#include "libANGLE/renderer/d3d/d3d9/ShaderCache.h" +#include "libANGLE/renderer/d3d/d3d9/VertexDeclarationCache.h" + +namespace gl +{ +class FramebufferAttachment; +} + +namespace egl +{ +class AttributeMap; +} + +namespace rx +{ +class Blit9; +class IndexDataManager; +class StreamingIndexBufferInterface; +class StaticIndexBufferInterface; +class VertexDataManager; +struct ClearParameters; +struct TranslatedAttribute; + +enum D3D9InitError +{ + D3D9_INIT_SUCCESS = 0, + // Failed to load the D3D or ANGLE compiler + D3D9_INIT_COMPILER_ERROR, + // Failed to load a necessary DLL + D3D9_INIT_MISSING_DEP, + // Device creation error + D3D9_INIT_CREATE_DEVICE_ERROR, + // System does not meet minimum shader spec + D3D9_INIT_UNSUPPORTED_VERSION, + // System does not support stretchrect from textures + D3D9_INIT_UNSUPPORTED_STRETCHRECT, + // A call returned out of memory or device lost + D3D9_INIT_OUT_OF_MEMORY, + // Other unspecified error + D3D9_INIT_OTHER_ERROR, + NUM_D3D9_INIT_ERRORS +}; + +class Renderer9 : public RendererD3D +{ + public: + explicit Renderer9(egl::Display *display); + virtual ~Renderer9(); + + static Renderer9 *makeRenderer9(Renderer *renderer); + + egl::Error initialize() override; + virtual bool resetDevice(); + + egl::ConfigSet generateConfigs() const override; + + void startScene(); + void endScene(); + + gl::Error flush() override; + gl::Error finish() override; + + virtual SwapChainD3D *createSwapChain(NativeWindow nativeWindow, HANDLE shareHandle, GLenum backBufferFormat, GLenum depthBufferFormat); + + gl::Error allocateEventQuery(IDirect3DQuery9 **outQuery); + void freeEventQuery(IDirect3DQuery9* query); + + // resource creation + gl::Error createVertexShader(const DWORD *function, size_t length, IDirect3DVertexShader9 **outShader); + gl::Error createPixelShader(const DWORD *function, size_t length, IDirect3DPixelShader9 **outShader); + HRESULT createVertexBuffer(UINT Length, DWORD Usage, IDirect3DVertexBuffer9 **ppVertexBuffer); + HRESULT createIndexBuffer(UINT Length, DWORD Usage, D3DFORMAT Format, IDirect3DIndexBuffer9 **ppIndexBuffer); + virtual gl::Error generateSwizzle(gl::Texture *texture); + virtual gl::Error setSamplerState(gl::SamplerType type, int index, gl::Texture *texture, const gl::SamplerState &sampler); + virtual gl::Error setTexture(gl::SamplerType type, int index, gl::Texture *texture); + + gl::Error setUniformBuffers(const gl::Data &data, + const GLint vertexUniformBuffers[], + const GLint fragmentUniformBuffers[]) override; + + virtual gl::Error setRasterizerState(const gl::RasterizerState &rasterState); + gl::Error setBlendState(const gl::Framebuffer *framebuffer, const gl::BlendState &blendState, const gl::ColorF &blendColor, + unsigned int sampleMask) override; + virtual gl::Error setDepthStencilState(const gl::DepthStencilState &depthStencilState, int stencilRef, + int stencilBackRef, bool frontFaceCCW); + + virtual void setScissorRectangle(const gl::Rectangle &scissor, bool enabled); + virtual void setViewport(const gl::Rectangle &viewport, float zNear, float zFar, GLenum drawMode, GLenum frontFace, + bool ignoreViewport); + + gl::Error applyRenderTarget(const gl::Framebuffer *frameBuffer) override; + gl::Error applyRenderTarget(const gl::FramebufferAttachment *colorBuffer, const gl::FramebufferAttachment *depthStencilBuffer); + virtual gl::Error applyShaders(gl::Program *program, const gl::VertexFormat inputLayout[], const gl::Framebuffer *framebuffer, + bool rasterizerDiscard, bool transformFeedbackActive); + virtual gl::Error applyUniforms(const ProgramImpl &program, const std::vector &uniformArray); + virtual bool applyPrimitiveType(GLenum primitiveType, GLsizei elementCount, bool usesPointSize); + virtual gl::Error applyVertexBuffer(const gl::State &state, GLenum mode, GLint first, GLsizei count, GLsizei instances); + virtual gl::Error applyIndexBuffer(const GLvoid *indices, gl::Buffer *elementArrayBuffer, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo); + + void applyTransformFeedbackBuffers(const gl::State &state) override; + + gl::Error drawArrays(const gl::Data &data, GLenum mode, GLsizei count, GLsizei instances, bool usesPointSize) override; + virtual gl::Error drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, + gl::Buffer *elementArrayBuffer, const TranslatedIndexData &indexInfo, GLsizei instances); + + gl::Error clear(const ClearParameters &clearParams, + const gl::FramebufferAttachment *colorBuffer, + const gl::FramebufferAttachment *depthStencilBuffer); + + virtual void markAllStateDirty(); + + // lost device + bool testDeviceLost() override; + bool testDeviceResettable() override; + + VendorID getVendorId() const override; + std::string getRendererDescription() const override; + GUID getAdapterIdentifier() const override; + + IDirect3DDevice9 *getDevice() { return mDevice; } + + virtual unsigned int getReservedVertexUniformVectors() const; + virtual unsigned int getReservedFragmentUniformVectors() const; + virtual unsigned int getReservedVertexUniformBuffers() const; + virtual unsigned int getReservedFragmentUniformBuffers() const; + virtual bool getShareHandleSupport() const; + virtual bool getPostSubBufferSupport() const; + + virtual int getMajorShaderModel() const; + int getMinorShaderModel() const override; + std::string getShaderModelSuffix() const override; + + DWORD getCapsDeclTypes() const; + + // Pixel operations + virtual gl::Error copyImage2D(const gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, + const gl::Offset &destOffset, TextureStorage *storage, GLint level); + virtual gl::Error copyImageCube(const gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, + const gl::Offset &destOffset, TextureStorage *storage, GLenum target, GLint level); + virtual gl::Error copyImage3D(const gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, + const gl::Offset &destOffset, TextureStorage *storage, GLint level); + virtual gl::Error copyImage2DArray(const gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, + const gl::Offset &destOffset, TextureStorage *storage, GLint level); + + // RenderTarget creation + virtual gl::Error createRenderTarget(int width, int height, GLenum format, GLsizei samples, RenderTargetD3D **outRT); + + // Framebuffer creation + FramebufferImpl *createDefaultFramebuffer(const gl::Framebuffer::Data &data) override; + FramebufferImpl *createFramebuffer(const gl::Framebuffer::Data &data) override; + + // Shader creation + virtual CompilerImpl *createCompiler(const gl::Data &data); + virtual ShaderImpl *createShader(GLenum type); + virtual ProgramImpl *createProgram(); + + // Shader operations + virtual gl::Error loadExecutable(const void *function, size_t length, ShaderType type, + const std::vector &transformFeedbackVaryings, + bool separatedOutputBuffers, ShaderExecutableD3D **outExecutable); + virtual gl::Error compileToExecutable(gl::InfoLog &infoLog, const std::string &shaderHLSL, ShaderType type, + const std::vector &transformFeedbackVaryings, + bool separatedOutputBuffers, const D3DCompilerWorkarounds &workarounds, + ShaderExecutableD3D **outExectuable); + virtual UniformStorageD3D *createUniformStorage(size_t storageSize); + + // Image operations + virtual ImageD3D *createImage(); + gl::Error generateMipmap(ImageD3D *dest, ImageD3D *source) override; + virtual TextureStorage *createTextureStorage2D(SwapChainD3D *swapChain); + virtual TextureStorage *createTextureStorage2D(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels, bool hintLevelZeroOnly); + virtual TextureStorage *createTextureStorageCube(GLenum internalformat, bool renderTarget, int size, int levels, bool hintLevelZeroOnly); + virtual TextureStorage *createTextureStorage3D(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth, int levels); + virtual TextureStorage *createTextureStorage2DArray(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth, int levels); + + // Texture creation + virtual TextureImpl *createTexture(GLenum target); + + // Renderbuffer creation + virtual RenderbufferImpl *createRenderbuffer(); + + // Buffer creation + virtual BufferImpl *createBuffer(); + virtual VertexBuffer *createVertexBuffer(); + virtual IndexBuffer *createIndexBuffer(); + + // Vertex Array creation + virtual VertexArrayImpl *createVertexArray(); + + // Query and Fence creation + virtual QueryImpl *createQuery(GLenum type); + virtual FenceNVImpl *createFenceNV(); + virtual FenceSyncImpl *createFenceSync(); + + // Transform Feedback creation + virtual TransformFeedbackImpl* createTransformFeedback(); + + // Buffer-to-texture and Texture-to-buffer copies + virtual bool supportsFastCopyBufferToTexture(GLenum internalFormat) const; + virtual gl::Error fastCopyBufferToTexture(const gl::PixelUnpackState &unpack, unsigned int offset, RenderTargetD3D *destRenderTarget, + GLenum destinationFormat, GLenum sourcePixelsType, const gl::Box &destArea); + + // D3D9-renderer specific methods + gl::Error boxFilter(IDirect3DSurface9 *source, IDirect3DSurface9 *dest); + + D3DPOOL getTexturePool(DWORD usage) const; + + bool getLUID(LUID *adapterLuid) const override; + virtual VertexConversionType getVertexConversionType(const gl::VertexFormat &vertexFormat) const; + virtual GLenum getVertexComponentType(const gl::VertexFormat &vertexFormat) const; + + gl::Error copyToRenderTarget(IDirect3DSurface9 *dest, IDirect3DSurface9 *source, bool fromManaged); + + RendererClass getRendererClass() const override { return RENDERER_D3D9; } + + D3DDEVTYPE getD3D9DeviceType() const { return mDeviceType; } + + private: + void generateCaps(gl::Caps *outCaps, gl::TextureCapsMap *outTextureCaps, gl::Extensions *outExtensions) const override; + Workarounds generateWorkarounds() const override; + + void release(); + + void applyUniformnfv(gl::LinkedUniform *targetUniform, const GLfloat *v); + void applyUniformniv(gl::LinkedUniform *targetUniform, const GLint *v); + void applyUniformnbv(gl::LinkedUniform *targetUniform, const GLint *v); + + gl::Error drawLineLoop(GLsizei count, GLenum type, const GLvoid *indices, int minIndex, gl::Buffer *elementArrayBuffer); + gl::Error drawIndexedPoints(GLsizei count, GLenum type, const GLvoid *indices, int minIndex, gl::Buffer *elementArrayBuffer); + + gl::Error getCountingIB(size_t count, StaticIndexBufferInterface **outIB); + + gl::Error getNullColorbuffer(const gl::FramebufferAttachment *depthbuffer, const gl::FramebufferAttachment **outColorBuffer); + + D3DPOOL getBufferPool(DWORD usage) const; + + HMODULE mD3d9Module; + + void initializeDevice(); + D3DPRESENT_PARAMETERS getDefaultPresentParameters(); + void releaseDeviceResources(); + + HRESULT getDeviceStatusCode(); + bool isRemovedDeviceResettable() const; + bool resetRemovedDevice(); + + UINT mAdapter; + D3DDEVTYPE mDeviceType; + IDirect3D9 *mD3d9; // Always valid after successful initialization. + IDirect3D9Ex *mD3d9Ex; // Might be null if D3D9Ex is not supported. + IDirect3DDevice9 *mDevice; + IDirect3DDevice9Ex *mDeviceEx; // Might be null if D3D9Ex is not supported. + + HLSLCompiler mCompiler; + + Blit9 *mBlit; + + HWND mDeviceWindow; + + D3DCAPS9 mDeviceCaps; + D3DADAPTER_IDENTIFIER9 mAdapterIdentifier; + + D3DPRIMITIVETYPE mPrimitiveType; + int mPrimitiveCount; + GLsizei mRepeatDraw; + + bool mSceneStarted; + + bool mVertexTextureSupport; + + // current render target states + unsigned int mAppliedRenderTargetSerial; + unsigned int mAppliedDepthStencilSerial; + bool mDepthStencilInitialized; + bool mRenderTargetDescInitialized; + unsigned int mCurStencilSize; + unsigned int mCurDepthSize; + + struct RenderTargetDesc + { + size_t width; + size_t height; + D3DFORMAT format; + }; + RenderTargetDesc mRenderTargetDesc; + + IDirect3DStateBlock9 *mMaskedClearSavedState; + + // previously set render states + bool mForceSetDepthStencilState; + gl::DepthStencilState mCurDepthStencilState; + int mCurStencilRef; + int mCurStencilBackRef; + bool mCurFrontFaceCCW; + + bool mForceSetRasterState; + gl::RasterizerState mCurRasterState; + + bool mForceSetScissor; + gl::Rectangle mCurScissor; + bool mScissorEnabled; + + bool mForceSetViewport; + gl::Rectangle mCurViewport; + float mCurNear; + float mCurFar; + float mCurDepthFront; + + bool mForceSetBlendState; + gl::BlendState mCurBlendState; + gl::ColorF mCurBlendColor; + GLuint mCurSampleMask; + + // Currently applied sampler states + std::vector mForceSetVertexSamplerStates; + std::vector mCurVertexSamplerStates; + + std::vector mForceSetPixelSamplerStates; + std::vector mCurPixelSamplerStates; + + // Currently applied textures + std::vector mCurVertexTextureSerials; + std::vector mCurPixelTextureSerials; + + unsigned int mAppliedIBSerial; + IDirect3DVertexShader9 *mAppliedVertexShader; + IDirect3DPixelShader9 *mAppliedPixelShader; + unsigned int mAppliedProgramSerial; + + dx_VertexConstants mVertexConstants; + dx_PixelConstants mPixelConstants; + bool mDxUniformsDirty; + + // A pool of event queries that are currently unused. + std::vector mEventQueryPool; + VertexShaderCache mVertexShaderCache; + PixelShaderCache mPixelShaderCache; + + VertexDataManager *mVertexDataManager; + VertexDeclarationCache mVertexDeclarationCache; + + IndexDataManager *mIndexDataManager; + StreamingIndexBufferInterface *mLineLoopIB; + StaticIndexBufferInterface *mCountingIB; + + enum { NUM_NULL_COLORBUFFER_CACHE_ENTRIES = 12 }; + struct NullColorbufferCacheEntry + { + UINT lruCount; + int width; + int height; + gl::FramebufferAttachment *buffer; + } mNullColorbufferCache[NUM_NULL_COLORBUFFER_CACHE_ENTRIES]; + UINT mMaxNullColorbufferLRU; + + DebugAnnotator9 mAnnotator; +}; + +} +#endif // LIBANGLE_RENDERER_D3D_D3D9_RENDERER9_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/ShaderCache.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/ShaderCache.h new file mode 100644 index 0000000000..cf831c62fa --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/ShaderCache.h @@ -0,0 +1,108 @@ +// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// ShaderCache: Defines rx::ShaderCache, a cache of Direct3D shader objects +// keyed by their byte code. + +#ifndef LIBANGLE_RENDERER_D3D_D3D9_SHADERCACHE_H_ +#define LIBANGLE_RENDERER_D3D_D3D9_SHADERCACHE_H_ + +#include "libANGLE/Error.h" + +#include "common/debug.h" + +#include +#include +#include + +namespace rx +{ +template +class ShaderCache : angle::NonCopyable +{ + public: + ShaderCache() : mDevice(NULL) + { + } + + ~ShaderCache() + { + // Call clear while the device is still valid. + ASSERT(mMap.empty()); + } + + void initialize(IDirect3DDevice9* device) + { + mDevice = device; + } + + gl::Error create(const DWORD *function, size_t length, ShaderObject **outShaderObject) + { + std::string key(reinterpret_cast(function), length); + typename Map::iterator it = mMap.find(key); + if (it != mMap.end()) + { + it->second->AddRef(); + *outShaderObject = it->second; + return gl::Error(GL_NO_ERROR); + } + + ShaderObject *shader; + HRESULT result = createShader(function, &shader); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create shader, result: 0x%X.", result); + } + + // Random eviction policy. + if (mMap.size() >= kMaxMapSize) + { + SafeRelease(mMap.begin()->second); + mMap.erase(mMap.begin()); + } + + shader->AddRef(); + mMap[key] = shader; + + *outShaderObject = shader; + return gl::Error(GL_NO_ERROR); + } + + void clear() + { + for (typename Map::iterator it = mMap.begin(); it != mMap.end(); ++it) + { + SafeRelease(it->second); + } + + mMap.clear(); + } + + private: + const static size_t kMaxMapSize = 100; + + HRESULT createShader(const DWORD *function, IDirect3DVertexShader9 **shader) + { + return mDevice->CreateVertexShader(function, shader); + } + + HRESULT createShader(const DWORD *function, IDirect3DPixelShader9 **shader) + { + return mDevice->CreatePixelShader(function, shader); + } + + typedef std::unordered_map Map; + Map mMap; + + IDirect3DDevice9 *mDevice; +}; + +typedef ShaderCache VertexShaderCache; +typedef ShaderCache PixelShaderCache; + +} + +#endif // LIBANGLE_RENDERER_D3D_D3D9_SHADERCACHE_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/ShaderExecutable9.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/ShaderExecutable9.cpp new file mode 100644 index 0000000000..280e80930b --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/ShaderExecutable9.cpp @@ -0,0 +1,53 @@ +// +// Copyright (c) 2012-2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// ShaderExecutable9.cpp: Implements a D3D9-specific class to contain shader +// executable implementation details. + +#include "libANGLE/renderer/d3d/d3d9/ShaderExecutable9.h" + +#include "common/debug.h" + +namespace rx +{ + +ShaderExecutable9::ShaderExecutable9(const void *function, size_t length, IDirect3DPixelShader9 *executable) + : ShaderExecutableD3D(function, length) +{ + mPixelExecutable = executable; + mVertexExecutable = NULL; +} + +ShaderExecutable9::ShaderExecutable9(const void *function, size_t length, IDirect3DVertexShader9 *executable) + : ShaderExecutableD3D(function, length) +{ + mVertexExecutable = executable; + mPixelExecutable = NULL; +} + +ShaderExecutable9::~ShaderExecutable9() +{ + SafeRelease(mVertexExecutable); + SafeRelease(mPixelExecutable); +} + +ShaderExecutable9 *ShaderExecutable9::makeShaderExecutable9(ShaderExecutableD3D *executable) +{ + ASSERT(HAS_DYNAMIC_TYPE(ShaderExecutable9*, executable)); + return static_cast(executable); +} + +IDirect3DVertexShader9 *ShaderExecutable9::getVertexShader() const +{ + return mVertexExecutable; +} + +IDirect3DPixelShader9 *ShaderExecutable9::getPixelShader() const +{ + return mPixelExecutable; +} + +} \ No newline at end of file diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/ShaderExecutable9.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/ShaderExecutable9.h new file mode 100644 index 0000000000..561f7defc8 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/ShaderExecutable9.h @@ -0,0 +1,37 @@ +// +// Copyright (c) 2012-2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// ShaderExecutable9.h: Defines a D3D9-specific class to contain shader +// executable implementation details. + +#ifndef LIBANGLE_RENDERER_D3D_D3D9_SHADEREXECUTABLE9_H_ +#define LIBANGLE_RENDERER_D3D_D3D9_SHADEREXECUTABLE9_H_ + +#include "libANGLE/renderer/d3d/ShaderExecutableD3D.h" + +namespace rx +{ + +class ShaderExecutable9 : public ShaderExecutableD3D +{ + public: + ShaderExecutable9(const void *function, size_t length, IDirect3DPixelShader9 *executable); + ShaderExecutable9(const void *function, size_t length, IDirect3DVertexShader9 *executable); + virtual ~ShaderExecutable9(); + + static ShaderExecutable9 *makeShaderExecutable9(ShaderExecutableD3D *executable); + + IDirect3DPixelShader9 *getPixelShader() const; + IDirect3DVertexShader9 *getVertexShader() const; + + private: + IDirect3DPixelShader9 *mPixelExecutable; + IDirect3DVertexShader9 *mVertexExecutable; +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_D3D9_SHADEREXECUTABLE9_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/SwapChain9.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/SwapChain9.cpp new file mode 100644 index 0000000000..1620668166 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/SwapChain9.cpp @@ -0,0 +1,425 @@ +// +// Copyright (c) 2012-2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// SwapChain9.cpp: Implements a back-end specific class for the D3D9 swap chain. + +#include "libANGLE/renderer/d3d/d3d9/SwapChain9.h" +#include "libANGLE/renderer/d3d/d3d9/renderer9_utils.h" +#include "libANGLE/renderer/d3d/d3d9/formatutils9.h" +#include "libANGLE/renderer/d3d/d3d9/Renderer9.h" +#include "libANGLE/features.h" + +namespace rx +{ + +SwapChain9::SwapChain9(Renderer9 *renderer, NativeWindow nativeWindow, HANDLE shareHandle, + GLenum backBufferFormat, GLenum depthBufferFormat) + : mRenderer(renderer), + SwapChainD3D(nativeWindow, shareHandle, backBufferFormat, depthBufferFormat), + mColorRenderTarget(this, false), + mDepthStencilRenderTarget(this, true) +{ + mSwapChain = NULL; + mBackBuffer = NULL; + mDepthStencil = NULL; + mRenderTarget = NULL; + mOffscreenTexture = NULL; + mWidth = -1; + mHeight = -1; + mSwapInterval = -1; +} + +SwapChain9::~SwapChain9() +{ + release(); +} + +void SwapChain9::release() +{ + SafeRelease(mSwapChain); + SafeRelease(mBackBuffer); + SafeRelease(mDepthStencil); + SafeRelease(mRenderTarget); + SafeRelease(mOffscreenTexture); + + if (mNativeWindow.getNativeWindow()) + { + mShareHandle = NULL; + } +} + +static DWORD convertInterval(EGLint interval) +{ +#if ANGLE_VSYNC == ANGLE_DISABLED + return D3DPRESENT_INTERVAL_IMMEDIATE; +#else + switch(interval) + { + case 0: return D3DPRESENT_INTERVAL_IMMEDIATE; + case 1: return D3DPRESENT_INTERVAL_ONE; + case 2: return D3DPRESENT_INTERVAL_TWO; + case 3: return D3DPRESENT_INTERVAL_THREE; + case 4: return D3DPRESENT_INTERVAL_FOUR; + default: UNREACHABLE(); + } + + return D3DPRESENT_INTERVAL_DEFAULT; +#endif +} + +EGLint SwapChain9::resize(int backbufferWidth, int backbufferHeight) +{ + // D3D9 does not support resizing swap chains without recreating them + return reset(backbufferWidth, backbufferHeight, mSwapInterval); +} + +EGLint SwapChain9::reset(int backbufferWidth, int backbufferHeight, EGLint swapInterval) +{ + IDirect3DDevice9 *device = mRenderer->getDevice(); + + if (device == NULL) + { + return EGL_BAD_ACCESS; + } + + // Evict all non-render target textures to system memory and release all resources + // before reallocating them to free up as much video memory as possible. + device->EvictManagedResources(); + + HRESULT result; + + // Release specific resources to free up memory for the new render target, while the + // old render target still exists for the purpose of preserving its contents. + SafeRelease(mSwapChain); + SafeRelease(mBackBuffer); + SafeRelease(mOffscreenTexture); + SafeRelease(mDepthStencil); + + HANDLE *pShareHandle = NULL; + if (!mNativeWindow.getNativeWindow() && mRenderer->getShareHandleSupport()) + { + pShareHandle = &mShareHandle; + } + + const d3d9::TextureFormat &backBufferd3dFormatInfo = d3d9::GetTextureFormatInfo(mBackBufferFormat); + result = device->CreateTexture(backbufferWidth, backbufferHeight, 1, D3DUSAGE_RENDERTARGET, + backBufferd3dFormatInfo.texFormat, D3DPOOL_DEFAULT, &mOffscreenTexture, + pShareHandle); + if (FAILED(result)) + { + ERR("Could not create offscreen texture: %08lX", result); + release(); + + if (d3d9::isDeviceLostError(result)) + { + return EGL_CONTEXT_LOST; + } + else + { + return EGL_BAD_ALLOC; + } + } + + IDirect3DSurface9 *oldRenderTarget = mRenderTarget; + + result = mOffscreenTexture->GetSurfaceLevel(0, &mRenderTarget); + ASSERT(SUCCEEDED(result)); + + if (oldRenderTarget) + { + RECT rect = + { + 0, 0, + mWidth, mHeight + }; + + if (rect.right > static_cast(backbufferWidth)) + { + rect.right = backbufferWidth; + } + + if (rect.bottom > static_cast(backbufferHeight)) + { + rect.bottom = backbufferHeight; + } + + mRenderer->endScene(); + + result = device->StretchRect(oldRenderTarget, &rect, mRenderTarget, &rect, D3DTEXF_NONE); + ASSERT(SUCCEEDED(result)); + + SafeRelease(oldRenderTarget); + } + + const d3d9::TextureFormat &depthBufferd3dFormatInfo = d3d9::GetTextureFormatInfo(mDepthBufferFormat); + + // Don't create a swapchain for NULLREF devices + D3DDEVTYPE deviceType = mRenderer->getD3D9DeviceType(); + EGLNativeWindowType window = mNativeWindow.getNativeWindow(); + if (window && deviceType != D3DDEVTYPE_NULLREF) + { + D3DPRESENT_PARAMETERS presentParameters = {0}; + presentParameters.AutoDepthStencilFormat = depthBufferd3dFormatInfo.renderFormat; + presentParameters.BackBufferCount = 1; + presentParameters.BackBufferFormat = backBufferd3dFormatInfo.renderFormat; + presentParameters.EnableAutoDepthStencil = FALSE; + presentParameters.Flags = 0; + presentParameters.hDeviceWindow = window; + presentParameters.MultiSampleQuality = 0; // FIXME: Unimplemented + presentParameters.MultiSampleType = D3DMULTISAMPLE_NONE; // FIXME: Unimplemented + presentParameters.PresentationInterval = convertInterval(swapInterval); + presentParameters.SwapEffect = D3DSWAPEFFECT_DISCARD; + presentParameters.Windowed = TRUE; + presentParameters.BackBufferWidth = backbufferWidth; + presentParameters.BackBufferHeight = backbufferHeight; + + // http://crbug.com/140239 + // http://crbug.com/143434 + // + // Some AMD/Intel switchable systems / drivers appear to round swap chain surfaces to a multiple of 64 pixels in width + // when using the integrated Intel. This rounds the width up rather than down. + // + // Some non-switchable AMD GPUs / drivers do not respect the source rectangle to Present. Therefore, when the vendor ID + // is not Intel, the back buffer width must be exactly the same width as the window or horizontal scaling will occur. + if (mRenderer->getVendorId() == VENDOR_ID_INTEL) + { + presentParameters.BackBufferWidth = (presentParameters.BackBufferWidth + 63) / 64 * 64; + } + + result = device->CreateAdditionalSwapChain(&presentParameters, &mSwapChain); + + if (FAILED(result)) + { + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_INVALIDCALL || result == D3DERR_DEVICELOST); + + ERR("Could not create additional swap chains or offscreen surfaces: %08lX", result); + release(); + + if (d3d9::isDeviceLostError(result)) + { + return EGL_CONTEXT_LOST; + } + else + { + return EGL_BAD_ALLOC; + } + } + + result = mSwapChain->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &mBackBuffer); + ASSERT(SUCCEEDED(result)); + InvalidateRect(window, NULL, FALSE); + } + + if (mDepthBufferFormat != GL_NONE) + { + result = device->CreateDepthStencilSurface(backbufferWidth, backbufferHeight, + depthBufferd3dFormatInfo.renderFormat, + D3DMULTISAMPLE_NONE, 0, FALSE, &mDepthStencil, NULL); + + if (FAILED(result)) + { + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_INVALIDCALL); + + ERR("Could not create depthstencil surface for new swap chain: 0x%08X", result); + release(); + + if (d3d9::isDeviceLostError(result)) + { + return EGL_CONTEXT_LOST; + } + else + { + return EGL_BAD_ALLOC; + } + } + } + + mWidth = backbufferWidth; + mHeight = backbufferHeight; + mSwapInterval = swapInterval; + + return EGL_SUCCESS; +} + +// parameters should be validated/clamped by caller +EGLint SwapChain9::swapRect(EGLint x, EGLint y, EGLint width, EGLint height) +{ + if (!mSwapChain) + { + return EGL_SUCCESS; + } + + IDirect3DDevice9 *device = mRenderer->getDevice(); + + // Disable all pipeline operations + device->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE); + device->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID); + device->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE); + device->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); + device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); + device->SetRenderState(D3DRS_STENCILENABLE, FALSE); + device->SetRenderState(D3DRS_CLIPPLANEENABLE, 0); + device->SetRenderState(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_ALPHA | D3DCOLORWRITEENABLE_BLUE | D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_RED); + device->SetRenderState(D3DRS_SRGBWRITEENABLE, FALSE); + device->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE); + device->SetPixelShader(NULL); + device->SetVertexShader(NULL); + + device->SetRenderTarget(0, mBackBuffer); + device->SetDepthStencilSurface(NULL); + + device->SetTexture(0, mOffscreenTexture); + device->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1); + device->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); + device->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE); + device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT); + device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT); + device->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); + device->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); + device->SetFVF(D3DFVF_XYZRHW | D3DFVF_TEX1); + + for (UINT streamIndex = 0; streamIndex < gl::MAX_VERTEX_ATTRIBS; streamIndex++) + { + device->SetStreamSourceFreq(streamIndex, 1); + } + + D3DVIEWPORT9 viewport = {0, 0, mWidth, mHeight, 0.0f, 1.0f}; + device->SetViewport(&viewport); + + float x1 = x - 0.5f; + float y1 = (mHeight - y - height) - 0.5f; + float x2 = (x + width) - 0.5f; + float y2 = (mHeight - y) - 0.5f; + + float u1 = x / float(mWidth); + float v1 = y / float(mHeight); + float u2 = (x + width) / float(mWidth); + float v2 = (y + height) / float(mHeight); + + float quad[4][6] = {{x1, y1, 0.0f, 1.0f, u1, v2}, + {x2, y1, 0.0f, 1.0f, u2, v2}, + {x2, y2, 0.0f, 1.0f, u2, v1}, + {x1, y2, 0.0f, 1.0f, u1, v1}}; // x, y, z, rhw, u, v + + mRenderer->startScene(); + device->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, quad, 6 * sizeof(float)); + mRenderer->endScene(); + + device->SetTexture(0, NULL); + + RECT rect = + { + x, mHeight - y - height, + x + width, mHeight - y + }; + + HRESULT result = mSwapChain->Present(&rect, &rect, NULL, NULL, 0); + + mRenderer->markAllStateDirty(); + + if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_DRIVERINTERNALERROR) + { + return EGL_BAD_ALLOC; + } + + // On Windows 8 systems, IDirect3DSwapChain9::Present sometimes returns 0x88760873 when the windows is + // in the process of entering/exiting fullscreen. This code doesn't seem to have any documentation. The + // device appears to be ok after emitting this error so simply return a failure to swap. + if (result == 0x88760873) + { + return EGL_BAD_MATCH; + } + + // http://crbug.com/313210 + // If our swap failed, trigger a device lost event. Resetting will work around an AMD-specific + // device removed bug with lost contexts when reinstalling drivers. + if (FAILED(result)) + { + mRenderer->notifyDeviceLost(); + return EGL_CONTEXT_LOST; + } + + return EGL_SUCCESS; +} + +// Increments refcount on surface. +// caller must Release() the returned surface +// TODO: remove the AddRef to match SwapChain11 +IDirect3DSurface9 *SwapChain9::getRenderTarget() +{ + if (mRenderTarget) + { + mRenderTarget->AddRef(); + } + + return mRenderTarget; +} + +// Increments refcount on surface. +// caller must Release() the returned surface +// TODO: remove the AddRef to match SwapChain11 +IDirect3DSurface9 *SwapChain9::getDepthStencil() +{ + if (mDepthStencil) + { + mDepthStencil->AddRef(); + } + + return mDepthStencil; +} + +// Increments refcount on texture. +// caller must Release() the returned texture +// TODO: remove the AddRef to match SwapChain11 +IDirect3DTexture9 *SwapChain9::getOffscreenTexture() +{ + if (mOffscreenTexture) + { + mOffscreenTexture->AddRef(); + } + + return mOffscreenTexture; +} + +SwapChain9 *SwapChain9::makeSwapChain9(SwapChainD3D *swapChain) +{ + ASSERT(HAS_DYNAMIC_TYPE(SwapChain9*, swapChain)); + return static_cast(swapChain); +} + +void SwapChain9::recreate() +{ + if (!mSwapChain) + { + return; + } + + IDirect3DDevice9 *device = mRenderer->getDevice(); + if (device == NULL) + { + return; + } + + D3DPRESENT_PARAMETERS presentParameters; + HRESULT result = mSwapChain->GetPresentParameters(&presentParameters); + ASSERT(SUCCEEDED(result)); + + IDirect3DSwapChain9* newSwapChain = NULL; + result = device->CreateAdditionalSwapChain(&presentParameters, &newSwapChain); + if (FAILED(result)) + { + return; + } + + SafeRelease(mSwapChain); + mSwapChain = newSwapChain; + + SafeRelease(mBackBuffer); + result = mSwapChain->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &mBackBuffer); + ASSERT(SUCCEEDED(result)); +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/SwapChain9.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/SwapChain9.h new file mode 100644 index 0000000000..81ac08ca7b --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/SwapChain9.h @@ -0,0 +1,63 @@ +// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// SwapChain9.h: Defines a back-end specific class for the D3D9 swap chain. + +#ifndef LIBANGLE_RENDERER_D3D_D3D9_SWAPCHAIN9_H_ +#define LIBANGLE_RENDERER_D3D_D3D9_SWAPCHAIN9_H_ + +#include "common/angleutils.h" +#include "libANGLE/renderer/d3d/SwapChainD3D.h" +#include "libANGLE/renderer/d3d/d3d9/RenderTarget9.h" + +namespace rx +{ +class Renderer9; + +class SwapChain9 : public SwapChainD3D +{ + public: + SwapChain9(Renderer9 *renderer, NativeWindow nativeWindow, HANDLE shareHandle, + GLenum backBufferFormat, GLenum depthBufferFormat); + virtual ~SwapChain9(); + + EGLint resize(EGLint backbufferWidth, EGLint backbufferHeight); + virtual EGLint reset(EGLint backbufferWidth, EGLint backbufferHeight, EGLint swapInterval); + virtual EGLint swapRect(EGLint x, EGLint y, EGLint width, EGLint height); + virtual void recreate(); + + RenderTargetD3D *getColorRenderTarget() override { return &mColorRenderTarget; } + RenderTargetD3D *getDepthStencilRenderTarget() override { return &mDepthStencilRenderTarget; } + + virtual IDirect3DSurface9 *getRenderTarget(); + virtual IDirect3DSurface9 *getDepthStencil(); + virtual IDirect3DTexture9 *getOffscreenTexture(); + + EGLint getWidth() const { return mWidth; } + EGLint getHeight() const { return mHeight; } + + static SwapChain9 *makeSwapChain9(SwapChainD3D *swapChain); + + private: + void release(); + + Renderer9 *mRenderer; + EGLint mHeight; + EGLint mWidth; + EGLint mSwapInterval; + + IDirect3DSwapChain9 *mSwapChain; + IDirect3DSurface9 *mBackBuffer; + IDirect3DSurface9 *mRenderTarget; + IDirect3DSurface9 *mDepthStencil; + IDirect3DTexture9* mOffscreenTexture; + + SurfaceRenderTarget9 mColorRenderTarget; + SurfaceRenderTarget9 mDepthStencilRenderTarget; +}; + +} +#endif // LIBANGLE_RENDERER_D3D_D3D9_SWAPCHAIN9_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/TextureStorage9.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/TextureStorage9.cpp new file mode 100644 index 0000000000..139cb3eb08 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/TextureStorage9.cpp @@ -0,0 +1,472 @@ +// +// Copyright (c) 2012-2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// TextureStorage9.cpp: Implements the abstract rx::TextureStorage9 class and its concrete derived +// classes TextureStorage9_2D and TextureStorage9_Cube, which act as the interface to the +// D3D9 texture. + +#include "libANGLE/renderer/d3d/d3d9/TextureStorage9.h" +#include "libANGLE/renderer/d3d/d3d9/Renderer9.h" +#include "libANGLE/renderer/d3d/d3d9/SwapChain9.h" +#include "libANGLE/renderer/d3d/d3d9/RenderTarget9.h" +#include "libANGLE/renderer/d3d/d3d9/renderer9_utils.h" +#include "libANGLE/renderer/d3d/d3d9/formatutils9.h" +#include "libANGLE/renderer/d3d/TextureD3D.h" +#include "libANGLE/formatutils.h" +#include "libANGLE/Texture.h" + +namespace rx +{ +TextureStorage9::TextureStorage9(Renderer9 *renderer, DWORD usage) + : mTopLevel(0), + mMipLevels(0), + mTextureWidth(0), + mTextureHeight(0), + mInternalFormat(GL_NONE), + mTextureFormat(D3DFMT_UNKNOWN), + mRenderer(Renderer9::makeRenderer9(renderer)), + mD3DUsage(usage), + mD3DPool(mRenderer->getTexturePool(usage)) +{ +} + +TextureStorage9::~TextureStorage9() +{ +} + +TextureStorage9 *TextureStorage9::makeTextureStorage9(TextureStorage *storage) +{ + ASSERT(HAS_DYNAMIC_TYPE(TextureStorage9*, storage)); + return static_cast(storage); +} + +DWORD TextureStorage9::GetTextureUsage(GLenum internalformat, bool renderTarget) +{ + DWORD d3dusage = 0; + + const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat); + const d3d9::TextureFormat &d3dFormatInfo = d3d9::GetTextureFormatInfo(internalformat); + if (formatInfo.depthBits > 0 || formatInfo.stencilBits > 0) + { + d3dusage |= D3DUSAGE_DEPTHSTENCIL; + } + else if (renderTarget && (d3dFormatInfo.renderFormat != D3DFMT_UNKNOWN)) + { + d3dusage |= D3DUSAGE_RENDERTARGET; + } + + return d3dusage; +} + + +bool TextureStorage9::isRenderTarget() const +{ + return (mD3DUsage & (D3DUSAGE_RENDERTARGET | D3DUSAGE_DEPTHSTENCIL)) != 0; +} + +bool TextureStorage9::isManaged() const +{ + return (mD3DPool == D3DPOOL_MANAGED); +} + +D3DPOOL TextureStorage9::getPool() const +{ + return mD3DPool; +} + +DWORD TextureStorage9::getUsage() const +{ + return mD3DUsage; +} + +int TextureStorage9::getTopLevel() const +{ + return mTopLevel; +} + +int TextureStorage9::getLevelCount() const +{ + return mMipLevels - mTopLevel; +} + +gl::Error TextureStorage9::setData(const gl::ImageIndex &index, ImageD3D *image, const gl::Box *destBox, GLenum type, + const gl::PixelUnpackState &unpack, const uint8_t *pixelData) +{ + UNREACHABLE(); + return gl::Error(GL_INVALID_OPERATION); +} + +TextureStorage9_2D::TextureStorage9_2D(Renderer9 *renderer, SwapChain9 *swapchain) + : TextureStorage9(renderer, D3DUSAGE_RENDERTARGET) +{ + IDirect3DTexture9 *surfaceTexture = swapchain->getOffscreenTexture(); + mTexture = surfaceTexture; + mMipLevels = surfaceTexture->GetLevelCount(); + + mInternalFormat = swapchain->GetBackBufferInternalFormat(); + + D3DSURFACE_DESC surfaceDesc; + surfaceTexture->GetLevelDesc(0, &surfaceDesc); + mTextureWidth = surfaceDesc.Width; + mTextureHeight = surfaceDesc.Height; + mTextureFormat = surfaceDesc.Format; + + mRenderTarget = NULL; + + initializeSerials(1, 1); +} + +TextureStorage9_2D::TextureStorage9_2D(Renderer9 *renderer, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels) + : TextureStorage9(renderer, GetTextureUsage(internalformat, renderTarget)) +{ + mTexture = NULL; + mRenderTarget = NULL; + + mInternalFormat = internalformat; + + const d3d9::TextureFormat &d3dFormatInfo = d3d9::GetTextureFormatInfo(internalformat); + mTextureFormat = d3dFormatInfo.texFormat; + + d3d9::MakeValidSize(false, d3dFormatInfo.texFormat, &width, &height, &mTopLevel); + mTextureWidth = width; + mTextureHeight = height; + mMipLevels = mTopLevel + levels; + + initializeSerials(getLevelCount(), 1); +} + +TextureStorage9_2D::~TextureStorage9_2D() +{ + SafeRelease(mTexture); + SafeDelete(mRenderTarget); +} + +TextureStorage9_2D *TextureStorage9_2D::makeTextureStorage9_2D(TextureStorage *storage) +{ + ASSERT(HAS_DYNAMIC_TYPE(TextureStorage9_2D*, storage)); + return static_cast(storage); +} + +// Increments refcount on surface. +// caller must Release() the returned surface +gl::Error TextureStorage9_2D::getSurfaceLevel(int level, bool dirty, IDirect3DSurface9 **outSurface) +{ + IDirect3DBaseTexture9 *baseTexture = NULL; + gl::Error error = getBaseTexture(&baseTexture); + if (error.isError()) + { + return error; + } + + IDirect3DTexture9 *texture = static_cast(baseTexture); + + HRESULT result = texture->GetSurfaceLevel(level + mTopLevel, outSurface); + + ASSERT(SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to get the surface from a texture, result: 0x%X.", result); + } + + // With managed textures the driver needs to be informed of updates to the lower mipmap levels + if (level + mTopLevel != 0 && isManaged() && dirty) + { + texture->AddDirtyRect(NULL); + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureStorage9_2D::getRenderTarget(const gl::ImageIndex &/*index*/, RenderTargetD3D **outRT) +{ + if (!mRenderTarget && isRenderTarget()) + { + IDirect3DSurface9 *surface = NULL; + gl::Error error = getSurfaceLevel(0, false, &surface); + if (error.isError()) + { + return error; + } + + mRenderTarget = new TextureRenderTarget9(surface, mInternalFormat, mTextureWidth, mTextureHeight, 1, 0); + } + + ASSERT(outRT); + *outRT = mRenderTarget; + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureStorage9_2D::generateMipmap(const gl::ImageIndex &sourceIndex, const gl::ImageIndex &destIndex) +{ + IDirect3DSurface9 *upper = NULL; + gl::Error error = getSurfaceLevel(sourceIndex.mipIndex, false, &upper); + if (error.isError()) + { + return error; + } + + IDirect3DSurface9 *lower = NULL; + error = getSurfaceLevel(destIndex.mipIndex, true, &lower); + if (error.isError()) + { + SafeRelease(upper); + return error; + } + + ASSERT(upper && lower); + error = mRenderer->boxFilter(upper, lower); + + SafeRelease(upper); + SafeRelease(lower); + + return error; +} + +gl::Error TextureStorage9_2D::getBaseTexture(IDirect3DBaseTexture9 **outTexture) +{ + // if the width or height is not positive this should be treated as an incomplete texture + // we handle that here by skipping the d3d texture creation + if (mTexture == NULL && mTextureWidth > 0 && mTextureHeight > 0) + { + ASSERT(mMipLevels > 0); + + IDirect3DDevice9 *device = mRenderer->getDevice(); + HRESULT result = device->CreateTexture(mTextureWidth, mTextureHeight, mMipLevels, getUsage(), mTextureFormat, + getPool(), &mTexture, NULL); + + if (FAILED(result)) + { + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create 2D storage texture, result: 0x%X.", result); + } + } + + *outTexture = mTexture; + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureStorage9_2D::copyToStorage(TextureStorage *destStorage) +{ + ASSERT(destStorage); + + TextureStorage9_2D *dest9 = TextureStorage9_2D::makeTextureStorage9_2D(destStorage); + + int levels = getLevelCount(); + for (int i = 0; i < levels; ++i) + { + IDirect3DSurface9 *srcSurf = NULL; + gl::Error error = getSurfaceLevel(i, false, &srcSurf); + if (error.isError()) + { + return error; + } + + IDirect3DSurface9 *dstSurf = NULL; + error = dest9->getSurfaceLevel(i, true, &dstSurf); + if (error.isError()) + { + SafeRelease(srcSurf); + return error; + } + + error = mRenderer->copyToRenderTarget(dstSurf, srcSurf, isManaged()); + + SafeRelease(srcSurf); + SafeRelease(dstSurf); + + if (error.isError()) + { + return error; + } + } + + return gl::Error(GL_NO_ERROR); +} + +TextureStorage9_Cube::TextureStorage9_Cube(Renderer9 *renderer, GLenum internalformat, bool renderTarget, int size, int levels, bool hintLevelZeroOnly) + : TextureStorage9(renderer, GetTextureUsage(internalformat, renderTarget)) +{ + mTexture = NULL; + for (int i = 0; i < CUBE_FACE_COUNT; ++i) + { + mRenderTarget[i] = NULL; + } + + mInternalFormat = internalformat; + + const d3d9::TextureFormat &d3dFormatInfo = d3d9::GetTextureFormatInfo(internalformat); + mTextureFormat = d3dFormatInfo.texFormat; + + int height = size; + d3d9::MakeValidSize(false, d3dFormatInfo.texFormat, &size, &height, &mTopLevel); + mTextureWidth = size; + mTextureHeight = size; + mMipLevels = mTopLevel + levels; + + initializeSerials(getLevelCount() * CUBE_FACE_COUNT, CUBE_FACE_COUNT); +} + +TextureStorage9_Cube::~TextureStorage9_Cube() +{ + SafeRelease(mTexture); + + for (int i = 0; i < CUBE_FACE_COUNT; ++i) + { + SafeDelete(mRenderTarget[i]); + } +} + +TextureStorage9_Cube *TextureStorage9_Cube::makeTextureStorage9_Cube(TextureStorage *storage) +{ + ASSERT(HAS_DYNAMIC_TYPE(TextureStorage9_Cube*, storage)); + return static_cast(storage); +} + +// Increments refcount on surface. +// caller must Release() the returned surface +gl::Error TextureStorage9_Cube::getCubeMapSurface(GLenum faceTarget, int level, bool dirty, IDirect3DSurface9 **outSurface) +{ + IDirect3DBaseTexture9 *baseTexture = NULL; + gl::Error error = getBaseTexture(&baseTexture); + if (error.isError()) + { + return error; + } + + IDirect3DCubeTexture9 *texture = static_cast(baseTexture); + + D3DCUBEMAP_FACES face = gl_d3d9::ConvertCubeFace(faceTarget); + HRESULT result = texture->GetCubeMapSurface(face, level + mTopLevel, outSurface); + + ASSERT(SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to get the surface from a texture, result: 0x%X.", result); + } + + // With managed textures the driver needs to be informed of updates to the lower mipmap levels + if (level != 0 && isManaged() && dirty) + { + texture->AddDirtyRect(face, NULL); + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureStorage9_Cube::getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT) +{ + ASSERT(outRT); + ASSERT(index.mipIndex == 0); + ASSERT(index.layerIndex >= 0 && index.layerIndex < CUBE_FACE_COUNT); + + if (mRenderTarget[index.layerIndex] == NULL && isRenderTarget()) + { + IDirect3DSurface9 *surface = NULL; + gl::Error error = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + index.layerIndex, 0, false, &surface); + if (error.isError()) + { + return error; + } + + mRenderTarget[index.layerIndex] = new TextureRenderTarget9(surface, mInternalFormat, mTextureWidth, mTextureHeight, 1, 0); + } + + *outRT = mRenderTarget[index.layerIndex]; + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureStorage9_Cube::generateMipmap(const gl::ImageIndex &sourceIndex, const gl::ImageIndex &destIndex) +{ + IDirect3DSurface9 *upper = NULL; + gl::Error error = getCubeMapSurface(sourceIndex.type, sourceIndex.mipIndex, false, &upper); + if (error.isError()) + { + return error; + } + + IDirect3DSurface9 *lower = NULL; + error = getCubeMapSurface(destIndex.type, destIndex.mipIndex, true, &lower); + if (error.isError()) + { + SafeRelease(upper); + return error; + } + + ASSERT(upper && lower); + error = mRenderer->boxFilter(upper, lower); + + SafeRelease(upper); + SafeRelease(lower); + + return error; +} + +gl::Error TextureStorage9_Cube::getBaseTexture(IDirect3DBaseTexture9 **outTexture) +{ + // if the size is not positive this should be treated as an incomplete texture + // we handle that here by skipping the d3d texture creation + if (mTexture == NULL && mTextureWidth > 0 && mTextureHeight > 0) + { + ASSERT(mMipLevels > 0); + ASSERT(mTextureWidth == mTextureHeight); + + IDirect3DDevice9 *device = mRenderer->getDevice(); + HRESULT result = device->CreateCubeTexture(mTextureWidth, mMipLevels, getUsage(), mTextureFormat, getPool(), + &mTexture, NULL); + + if (FAILED(result)) + { + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create cube storage texture, result: 0x%X.", result); + } + } + + *outTexture = mTexture; + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureStorage9_Cube::copyToStorage(TextureStorage *destStorage) +{ + ASSERT(destStorage); + + TextureStorage9_Cube *dest9 = TextureStorage9_Cube::makeTextureStorage9_Cube(destStorage); + + int levels = getLevelCount(); + for (int f = 0; f < CUBE_FACE_COUNT; f++) + { + for (int i = 0; i < levels; i++) + { + IDirect3DSurface9 *srcSurf = NULL; + gl::Error error = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i, false, &srcSurf); + if (error.isError()) + { + return error; + } + + IDirect3DSurface9 *dstSurf = NULL; + error = dest9->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i, true, &dstSurf); + if (error.isError()) + { + SafeRelease(srcSurf); + return error; + } + + error = mRenderer->copyToRenderTarget(dstSurf, srcSurf, isManaged()); + + SafeRelease(srcSurf); + SafeRelease(dstSurf); + + if (error.isError()) + { + return error; + } + } + } + + return gl::Error(GL_NO_ERROR); +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/TextureStorage9.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/TextureStorage9.h new file mode 100644 index 0000000000..5cc06f07b1 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/TextureStorage9.h @@ -0,0 +1,108 @@ +// +// Copyright (c) 2012-2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// TextureStorage9.h: Defines the abstract rx::TextureStorage9 class and its concrete derived +// classes TextureStorage9_2D and TextureStorage9_Cube, which act as the interface to the +// D3D9 texture. + +#ifndef LIBANGLE_RENDERER_D3D_D3D9_TEXTURESTORAGE9_H_ +#define LIBANGLE_RENDERER_D3D_D3D9_TEXTURESTORAGE9_H_ + +#include "libANGLE/renderer/d3d/TextureStorage.h" +#include "common/debug.h" + +namespace rx +{ +class Renderer9; +class SwapChain9; +class RenderTargetD3D; +class RenderTarget9; + +class TextureStorage9 : public TextureStorage +{ + public: + virtual ~TextureStorage9(); + + static TextureStorage9 *makeTextureStorage9(TextureStorage *storage); + + static DWORD GetTextureUsage(GLenum internalformat, bool renderTarget); + + D3DPOOL getPool() const; + DWORD getUsage() const; + + virtual gl::Error getBaseTexture(IDirect3DBaseTexture9 **outTexture) = 0; + virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT) = 0; + + virtual int getTopLevel() const; + virtual bool isRenderTarget() const; + virtual bool isManaged() const; + virtual int getLevelCount() const; + + virtual gl::Error setData(const gl::ImageIndex &index, ImageD3D *image, const gl::Box *destBox, GLenum type, + const gl::PixelUnpackState &unpack, const uint8_t *pixelData); + + protected: + int mTopLevel; + size_t mMipLevels; + size_t mTextureWidth; + size_t mTextureHeight; + GLenum mInternalFormat; + D3DFORMAT mTextureFormat; + + Renderer9 *mRenderer; + + TextureStorage9(Renderer9 *renderer, DWORD usage); + + private: + const DWORD mD3DUsage; + const D3DPOOL mD3DPool; +}; + +class TextureStorage9_2D : public TextureStorage9 +{ + public: + TextureStorage9_2D(Renderer9 *renderer, SwapChain9 *swapchain); + TextureStorage9_2D(Renderer9 *renderer, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels); + virtual ~TextureStorage9_2D(); + + static TextureStorage9_2D *makeTextureStorage9_2D(TextureStorage *storage); + + gl::Error getSurfaceLevel(int level, bool dirty, IDirect3DSurface9 **outSurface); + virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT); + virtual gl::Error getBaseTexture(IDirect3DBaseTexture9 **outTexture); + virtual gl::Error generateMipmap(const gl::ImageIndex &sourceIndex, const gl::ImageIndex &destIndex); + virtual gl::Error copyToStorage(TextureStorage *destStorage); + + private: + IDirect3DTexture9 *mTexture; + RenderTarget9 *mRenderTarget; +}; + +class TextureStorage9_Cube : public TextureStorage9 +{ + public: + TextureStorage9_Cube(Renderer9 *renderer, GLenum internalformat, bool renderTarget, int size, int levels, bool hintLevelZeroOnly); + virtual ~TextureStorage9_Cube(); + + static TextureStorage9_Cube *makeTextureStorage9_Cube(TextureStorage *storage); + + gl::Error getCubeMapSurface(GLenum faceTarget, int level, bool dirty, IDirect3DSurface9 **outSurface); + virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT); + virtual gl::Error getBaseTexture(IDirect3DBaseTexture9 **outTexture); + virtual gl::Error generateMipmap(const gl::ImageIndex &sourceIndex, const gl::ImageIndex &destIndex); + virtual gl::Error copyToStorage(TextureStorage *destStorage); + + private: + static const size_t CUBE_FACE_COUNT = 6; + + IDirect3DCubeTexture9 *mTexture; + RenderTarget9 *mRenderTarget[CUBE_FACE_COUNT]; +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_D3D9_TEXTURESTORAGE9_H_ + diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/VertexArray9.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/VertexArray9.h new file mode 100644 index 0000000000..fb626bc0cf --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/VertexArray9.h @@ -0,0 +1,41 @@ +// +// Copyright 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// VertexArray9.h: Defines the rx::VertexArray9 class which implements rx::VertexArrayImpl. + +#ifndef LIBANGLE_RENDERER_D3D_D3D9_VERTEXARRAY9_H_ +#define LIBANGLE_RENDERER_D3D_D3D9_VERTEXARRAY9_H_ + +#include "libANGLE/renderer/VertexArrayImpl.h" +#include "libANGLE/renderer/d3d/d3d9/Renderer9.h" + +namespace rx +{ +class Renderer9; + +class VertexArray9 : public VertexArrayImpl +{ + public: + VertexArray9(Renderer9 *renderer) + : VertexArrayImpl(), + mRenderer(renderer) + { + } + + virtual ~VertexArray9() { } + + virtual void setElementArrayBuffer(const gl::Buffer *buffer) { } + virtual void setAttribute(size_t idx, const gl::VertexAttribute &attr) { } + virtual void setAttributeDivisor(size_t idx, GLuint divisor) { } + virtual void enableAttribute(size_t idx, bool enabledState) { } + + private: + Renderer9 *mRenderer; +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_D3D9_VERTEXARRAY9_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/VertexBuffer9.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/VertexBuffer9.cpp new file mode 100644 index 0000000000..cb5003997f --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/VertexBuffer9.cpp @@ -0,0 +1,239 @@ +// +// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// VertexBuffer9.cpp: Defines the D3D9 VertexBuffer implementation. + +#include "libANGLE/renderer/d3d/d3d9/VertexBuffer9.h" +#include "libANGLE/renderer/d3d/d3d9/Renderer9.h" +#include "libANGLE/renderer/d3d/d3d9/formatutils9.h" +#include "libANGLE/renderer/d3d/d3d9/vertexconversion.h" +#include "libANGLE/renderer/d3d/BufferD3D.h" +#include "libANGLE/VertexAttribute.h" +#include "libANGLE/Buffer.h" + +namespace rx +{ + +VertexBuffer9::VertexBuffer9(Renderer9 *renderer) : mRenderer(renderer) +{ + mVertexBuffer = NULL; + mBufferSize = 0; + mDynamicUsage = false; +} + +VertexBuffer9::~VertexBuffer9() +{ + SafeRelease(mVertexBuffer); +} + +gl::Error VertexBuffer9::initialize(unsigned int size, bool dynamicUsage) +{ + SafeRelease(mVertexBuffer); + + updateSerial(); + + if (size > 0) + { + DWORD flags = D3DUSAGE_WRITEONLY; + if (dynamicUsage) + { + flags |= D3DUSAGE_DYNAMIC; + } + + HRESULT result = mRenderer->createVertexBuffer(size, flags, &mVertexBuffer); + + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate internal vertex buffer of size, %lu.", size); + } + } + + mBufferSize = size; + mDynamicUsage = dynamicUsage; + return gl::Error(GL_NO_ERROR); +} + +VertexBuffer9 *VertexBuffer9::makeVertexBuffer9(VertexBuffer *vertexBuffer) +{ + ASSERT(HAS_DYNAMIC_TYPE(VertexBuffer9*, vertexBuffer)); + return static_cast(vertexBuffer); +} + +gl::Error VertexBuffer9::storeVertexAttributes(const gl::VertexAttribute &attrib, const gl::VertexAttribCurrentValueData ¤tValue, + GLint start, GLsizei count, GLsizei instances, unsigned int offset) +{ + if (!mVertexBuffer) + { + return gl::Error(GL_OUT_OF_MEMORY, "Internal vertex buffer is not initialized."); + } + + gl::Buffer *buffer = attrib.buffer.get(); + + int inputStride = gl::ComputeVertexAttributeStride(attrib); + int elementSize = gl::ComputeVertexAttributeTypeSize(attrib); + + DWORD lockFlags = mDynamicUsage ? D3DLOCK_NOOVERWRITE : 0; + + uint8_t *mapPtr = NULL; + + unsigned int mapSize; + gl::Error error = spaceRequired(attrib, count, instances, &mapSize); + if (error.isError()) + { + return error; + } + + HRESULT result = mVertexBuffer->Lock(offset, mapSize, reinterpret_cast(&mapPtr), lockFlags); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock internal vertex buffer, HRESULT: 0x%08x.", result); + } + + const uint8_t *input = NULL; + if (attrib.enabled) + { + if (buffer) + { + BufferD3D *storage = GetImplAs(buffer); + ASSERT(storage); + error = storage->getData(&input); + if (error.isError()) + { + return error; + } + input += static_cast(attrib.offset); + } + else + { + input = static_cast(attrib.pointer); + } + } + else + { + input = reinterpret_cast(currentValue.FloatValues); + } + + if (instances == 0 || attrib.divisor == 0) + { + input += inputStride * start; + } + + gl::VertexFormat vertexFormat(attrib, currentValue.Type); + const d3d9::VertexFormat &d3dVertexInfo = d3d9::GetVertexFormatInfo(mRenderer->getCapsDeclTypes(), vertexFormat); + bool needsConversion = (d3dVertexInfo.conversionType & VERTEX_CONVERT_CPU) > 0; + + if (!needsConversion && inputStride == elementSize) + { + size_t copySize = static_cast(count) * static_cast(inputStride); + memcpy(mapPtr, input, copySize); + } + else + { + d3dVertexInfo.copyFunction(input, inputStride, count, mapPtr); + } + + mVertexBuffer->Unlock(); + + return gl::Error(GL_NO_ERROR); +} + +gl::Error VertexBuffer9::getSpaceRequired(const gl::VertexAttribute &attrib, GLsizei count, GLsizei instances, + unsigned int *outSpaceRequired) const +{ + return spaceRequired(attrib, count, instances, outSpaceRequired); +} + +unsigned int VertexBuffer9::getBufferSize() const +{ + return mBufferSize; +} + +gl::Error VertexBuffer9::setBufferSize(unsigned int size) +{ + if (size > mBufferSize) + { + return initialize(size, mDynamicUsage); + } + else + { + return gl::Error(GL_NO_ERROR); + } +} + +gl::Error VertexBuffer9::discard() +{ + if (!mVertexBuffer) + { + return gl::Error(GL_OUT_OF_MEMORY, "Internal vertex buffer is not initialized."); + } + + void *dummy; + HRESULT result; + + result = mVertexBuffer->Lock(0, 1, &dummy, D3DLOCK_DISCARD); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock internal buffer for discarding, HRESULT: 0x%08x", result); + } + + result = mVertexBuffer->Unlock(); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to unlock internal buffer for discarding, HRESULT: 0x%08x", result); + } + + return gl::Error(GL_NO_ERROR); +} + +IDirect3DVertexBuffer9 * VertexBuffer9::getBuffer() const +{ + return mVertexBuffer; +} + +gl::Error VertexBuffer9::spaceRequired(const gl::VertexAttribute &attrib, std::size_t count, GLsizei instances, + unsigned int *outSpaceRequired) const +{ + gl::VertexFormat vertexFormat(attrib, GL_FLOAT); + const d3d9::VertexFormat &d3d9VertexInfo = d3d9::GetVertexFormatInfo(mRenderer->getCapsDeclTypes(), vertexFormat); + + if (attrib.enabled) + { + unsigned int elementCount = 0; + if (instances == 0 || attrib.divisor == 0) + { + elementCount = count; + } + else + { + // Round up to divisor, if possible + elementCount = UnsignedCeilDivide(static_cast(instances), attrib.divisor); + } + + if (d3d9VertexInfo.outputElementSize <= std::numeric_limits::max() / elementCount) + { + if (outSpaceRequired) + { + *outSpaceRequired = d3d9VertexInfo.outputElementSize * elementCount; + } + return gl::Error(GL_NO_ERROR); + } + else + { + return gl::Error(GL_OUT_OF_MEMORY, "New vertex buffer size would result in an overflow."); + } + } + else + { + const unsigned int elementSize = 4; + if (outSpaceRequired) + { + *outSpaceRequired = elementSize * 4; + } + return gl::Error(GL_NO_ERROR); + } +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/VertexBuffer9.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/VertexBuffer9.h new file mode 100644 index 0000000000..f5b110b22b --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/VertexBuffer9.h @@ -0,0 +1,52 @@ +// +// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// VertexBuffer9.h: Defines the D3D9 VertexBuffer implementation. + +#ifndef LIBANGLE_RENDERER_D3D_D3D9_VERTEXBUFFER9_H_ +#define LIBANGLE_RENDERER_D3D_D3D9_VERTEXBUFFER9_H_ + +#include "libANGLE/renderer/d3d/VertexBuffer.h" + +namespace rx +{ +class Renderer9; + +class VertexBuffer9 : public VertexBuffer +{ + public: + explicit VertexBuffer9(Renderer9 *renderer); + virtual ~VertexBuffer9(); + + virtual gl::Error initialize(unsigned int size, bool dynamicUsage); + + static VertexBuffer9 *makeVertexBuffer9(VertexBuffer *vertexBuffer); + + virtual gl::Error storeVertexAttributes(const gl::VertexAttribute &attrib, const gl::VertexAttribCurrentValueData ¤tValue, + GLint start, GLsizei count, GLsizei instances, unsigned int offset); + + virtual gl::Error getSpaceRequired(const gl::VertexAttribute &attrib, GLsizei count, GLsizei instances, unsigned int *outSpaceRequired) const; + + virtual unsigned int getBufferSize() const; + virtual gl::Error setBufferSize(unsigned int size); + virtual gl::Error discard(); + + IDirect3DVertexBuffer9 *getBuffer() const; + + private: + Renderer9 *mRenderer; + + IDirect3DVertexBuffer9 *mVertexBuffer; + unsigned int mBufferSize; + bool mDynamicUsage; + + gl::Error spaceRequired(const gl::VertexAttribute &attrib, std::size_t count, GLsizei instances, + unsigned int *outSpaceRequired) const; +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_D3D9_VERTEXBUFFER9_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/VertexDeclarationCache.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/VertexDeclarationCache.cpp new file mode 100644 index 0000000000..f9eded9b50 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/VertexDeclarationCache.cpp @@ -0,0 +1,237 @@ +// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// VertexDeclarationCache.cpp: Implements a helper class to construct and cache vertex declarations. + +#include "libANGLE/renderer/d3d/d3d9/VertexDeclarationCache.h" +#include "libANGLE/renderer/d3d/d3d9/VertexBuffer9.h" +#include "libANGLE/renderer/d3d/d3d9/formatutils9.h" +#include "libANGLE/Program.h" +#include "libANGLE/VertexAttribute.h" + +namespace rx +{ + +VertexDeclarationCache::VertexDeclarationCache() : mMaxLru(0) +{ + for (int i = 0; i < NUM_VERTEX_DECL_CACHE_ENTRIES; i++) + { + mVertexDeclCache[i].vertexDeclaration = NULL; + mVertexDeclCache[i].lruCount = 0; + } + + for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) + { + mAppliedVBs[i].serial = 0; + } + + mLastSetVDecl = NULL; + mInstancingEnabled = true; +} + +VertexDeclarationCache::~VertexDeclarationCache() +{ + for (int i = 0; i < NUM_VERTEX_DECL_CACHE_ENTRIES; i++) + { + SafeRelease(mVertexDeclCache[i].vertexDeclaration); + } +} + +gl::Error VertexDeclarationCache::applyDeclaration(IDirect3DDevice9 *device, TranslatedAttribute attributes[], gl::Program *program, GLsizei instances, GLsizei *repeatDraw) +{ + *repeatDraw = 1; + + int indexedAttribute = gl::MAX_VERTEX_ATTRIBS; + int instancedAttribute = gl::MAX_VERTEX_ATTRIBS; + + if (instances == 0) + { + for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; ++i) + { + if (attributes[i].divisor != 0) + { + // If a divisor is set, it still applies even if an instanced draw was not used, so treat + // as a single-instance draw. + instances = 1; + break; + } + } + } + + if (instances > 0) + { + // Find an indexed attribute to be mapped to D3D stream 0 + for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) + { + if (attributes[i].active) + { + if (indexedAttribute == gl::MAX_VERTEX_ATTRIBS && attributes[i].divisor == 0) + { + indexedAttribute = i; + } + else if (instancedAttribute == gl::MAX_VERTEX_ATTRIBS && attributes[i].divisor != 0) + { + instancedAttribute = i; + } + if (indexedAttribute != gl::MAX_VERTEX_ATTRIBS && instancedAttribute != gl::MAX_VERTEX_ATTRIBS) + break; // Found both an indexed and instanced attribute + } + } + + // The validation layer checks that there is at least one active attribute with a zero divisor as per + // the GL_ANGLE_instanced_arrays spec. + ASSERT(indexedAttribute != gl::MAX_VERTEX_ATTRIBS); + } + + D3DCAPS9 caps; + device->GetDeviceCaps(&caps); + + D3DVERTEXELEMENT9 elements[gl::MAX_VERTEX_ATTRIBS + 1]; + D3DVERTEXELEMENT9 *element = &elements[0]; + + for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) + { + if (attributes[i].active) + { + // Directly binding the storage buffer is not supported for d3d9 + ASSERT(attributes[i].storage == NULL); + + int stream = i; + + if (instances > 0) + { + // Due to a bug on ATI cards we can't enable instancing when none of the attributes are instanced. + if (instancedAttribute == gl::MAX_VERTEX_ATTRIBS) + { + *repeatDraw = instances; + } + else + { + if (i == indexedAttribute) + { + stream = 0; + } + else if (i == 0) + { + stream = indexedAttribute; + } + + UINT frequency = 1; + + if (attributes[i].divisor == 0) + { + frequency = D3DSTREAMSOURCE_INDEXEDDATA | instances; + } + else + { + frequency = D3DSTREAMSOURCE_INSTANCEDATA | attributes[i].divisor; + } + + device->SetStreamSourceFreq(stream, frequency); + mInstancingEnabled = true; + } + } + + VertexBuffer9 *vertexBuffer = VertexBuffer9::makeVertexBuffer9(attributes[i].vertexBuffer); + + if (mAppliedVBs[stream].serial != attributes[i].serial || + mAppliedVBs[stream].stride != attributes[i].stride || + mAppliedVBs[stream].offset != attributes[i].offset) + { + device->SetStreamSource(stream, vertexBuffer->getBuffer(), attributes[i].offset, attributes[i].stride); + mAppliedVBs[stream].serial = attributes[i].serial; + mAppliedVBs[stream].stride = attributes[i].stride; + mAppliedVBs[stream].offset = attributes[i].offset; + } + + gl::VertexFormat vertexFormat(*attributes[i].attribute, GL_FLOAT); + const d3d9::VertexFormat &d3d9VertexInfo = d3d9::GetVertexFormatInfo(caps.DeclTypes, vertexFormat); + + element->Stream = stream; + element->Offset = 0; + element->Type = d3d9VertexInfo.nativeFormat; + element->Method = D3DDECLMETHOD_DEFAULT; + element->Usage = D3DDECLUSAGE_TEXCOORD; + element->UsageIndex = program->getSemanticIndex(i); + element++; + } + } + + if (instances == 0 || instancedAttribute == gl::MAX_VERTEX_ATTRIBS) + { + if (mInstancingEnabled) + { + for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) + { + device->SetStreamSourceFreq(i, 1); + } + + mInstancingEnabled = false; + } + } + + static const D3DVERTEXELEMENT9 end = D3DDECL_END(); + *(element++) = end; + + for (int i = 0; i < NUM_VERTEX_DECL_CACHE_ENTRIES; i++) + { + VertexDeclCacheEntry *entry = &mVertexDeclCache[i]; + if (memcmp(entry->cachedElements, elements, (element - elements) * sizeof(D3DVERTEXELEMENT9)) == 0 && entry->vertexDeclaration) + { + entry->lruCount = ++mMaxLru; + if(entry->vertexDeclaration != mLastSetVDecl) + { + device->SetVertexDeclaration(entry->vertexDeclaration); + mLastSetVDecl = entry->vertexDeclaration; + } + + return gl::Error(GL_NO_ERROR); + } + } + + VertexDeclCacheEntry *lastCache = mVertexDeclCache; + + for (int i = 0; i < NUM_VERTEX_DECL_CACHE_ENTRIES; i++) + { + if (mVertexDeclCache[i].lruCount < lastCache->lruCount) + { + lastCache = &mVertexDeclCache[i]; + } + } + + if (lastCache->vertexDeclaration != NULL) + { + SafeRelease(lastCache->vertexDeclaration); + // mLastSetVDecl is set to the replacement, so we don't have to worry + // about it. + } + + memcpy(lastCache->cachedElements, elements, (element - elements) * sizeof(D3DVERTEXELEMENT9)); + HRESULT result = device->CreateVertexDeclaration(elements, &lastCache->vertexDeclaration); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal vertex declaration, result: 0x%X.", result); + } + + device->SetVertexDeclaration(lastCache->vertexDeclaration); + mLastSetVDecl = lastCache->vertexDeclaration; + lastCache->lruCount = ++mMaxLru; + + return gl::Error(GL_NO_ERROR); +} + +void VertexDeclarationCache::markStateDirty() +{ + for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) + { + mAppliedVBs[i].serial = 0; + } + + mLastSetVDecl = NULL; + mInstancingEnabled = true; // Forces it to be disabled when not used +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/VertexDeclarationCache.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/VertexDeclarationCache.h new file mode 100644 index 0000000000..fbd673097f --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/VertexDeclarationCache.h @@ -0,0 +1,60 @@ +// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// VertexDeclarationCache.h: Defines a helper class to construct and cache vertex declarations. + +#ifndef LIBANGLE_RENDERER_D3D_D3D9_VERTEXDECLARATIONCACHE_H_ +#define LIBANGLE_RENDERER_D3D_D3D9_VERTEXDECLARATIONCACHE_H_ + +#include "libANGLE/Error.h" +#include "libANGLE/renderer/d3d/VertexDataManager.h" + +namespace gl +{ +class VertexDataManager; +class Program; +} + +namespace rx +{ + +class VertexDeclarationCache +{ + public: + VertexDeclarationCache(); + ~VertexDeclarationCache(); + + gl::Error applyDeclaration(IDirect3DDevice9 *device, TranslatedAttribute attributes[], gl::Program *program, GLsizei instances, GLsizei *repeatDraw); + + void markStateDirty(); + + private: + UINT mMaxLru; + + enum { NUM_VERTEX_DECL_CACHE_ENTRIES = 32 }; + + struct VBData + { + unsigned int serial; + unsigned int stride; + unsigned int offset; + }; + + VBData mAppliedVBs[gl::MAX_VERTEX_ATTRIBS]; + IDirect3DVertexDeclaration9 *mLastSetVDecl; + bool mInstancingEnabled; + + struct VertexDeclCacheEntry + { + D3DVERTEXELEMENT9 cachedElements[gl::MAX_VERTEX_ATTRIBS + 1]; + UINT lruCount; + IDirect3DVertexDeclaration9 *vertexDeclaration; + } mVertexDeclCache[NUM_VERTEX_DECL_CACHE_ENTRIES]; +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_D3D9_VERTEXDECLARATIONCACHE_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/formatutils9.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/formatutils9.cpp new file mode 100644 index 0000000000..9bad5503d9 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/formatutils9.cpp @@ -0,0 +1,602 @@ +// +// Copyright (c) 2013-2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// formatutils9.cpp: Queries for GL image formats and their translations to D3D9 +// formats. + +#include "libANGLE/renderer/d3d/copyimage.h" +#include "libANGLE/renderer/d3d/d3d9/formatutils9.h" +#include "libANGLE/renderer/d3d/d3d9/Renderer9.h" +#include "libANGLE/renderer/d3d/d3d9/vertexconversion.h" +#include "libANGLE/renderer/d3d/generatemip.h" +#include "libANGLE/renderer/d3d/loadimage.h" + +namespace rx +{ + +namespace d3d9 +{ + +const D3DFORMAT D3DFMT_INTZ = ((D3DFORMAT)(MAKEFOURCC('I', 'N', 'T', 'Z'))); +const D3DFORMAT D3DFMT_NULL = ((D3DFORMAT)(MAKEFOURCC('N', 'U', 'L', 'L'))); + +struct D3D9FastCopyFormat +{ + GLenum destFormat; + GLenum destType; + ColorCopyFunction copyFunction; + + D3D9FastCopyFormat(GLenum destFormat, GLenum destType, ColorCopyFunction copyFunction) + : destFormat(destFormat), destType(destType), copyFunction(copyFunction) + { } + + bool operator<(const D3D9FastCopyFormat& other) const + { + return memcmp(this, &other, sizeof(D3D9FastCopyFormat)) < 0; + } +}; + +typedef std::multimap D3D9FastCopyMap; + +static D3D9FastCopyMap BuildFastCopyMap() +{ + D3D9FastCopyMap map; + + map.insert(std::make_pair(D3DFMT_A8R8G8B8, D3D9FastCopyFormat(GL_RGBA, GL_UNSIGNED_BYTE, CopyBGRA8ToRGBA8))); + + return map; +} + +// A map to determine the pixel size and mip generation function of a given D3D format +typedef std::map D3D9FormatInfoMap; + +D3DFormat::D3DFormat() + : pixelBytes(0), + blockWidth(0), + blockHeight(0), + redBits(0), + greenBits(0), + blueBits(0), + alphaBits(0), + luminanceBits(0), + depthBits(0), + stencilBits(0), + internalFormat(GL_NONE), + mipGenerationFunction(NULL), + colorReadFunction(NULL), + fastCopyFunctions() +{ +} + +ColorCopyFunction D3DFormat::getFastCopyFunction(GLenum format, GLenum type) const +{ + FastCopyFunctionMap::const_iterator iter = fastCopyFunctions.find(std::make_pair(format, type)); + return (iter != fastCopyFunctions.end()) ? iter->second : NULL; +} + +static inline void InsertD3DFormatInfo(D3D9FormatInfoMap *map, D3DFORMAT format, GLuint bits, GLuint blockWidth, + GLuint blockHeight, GLuint redBits, GLuint greenBits, GLuint blueBits, + GLuint alphaBits, GLuint lumBits, GLuint depthBits, GLuint stencilBits, + GLenum internalFormat, MipGenerationFunction mipFunc, + ColorReadFunction colorReadFunc) +{ + D3DFormat info; + info.pixelBytes = bits / 8; + info.blockWidth = blockWidth; + info.blockHeight = blockHeight; + info.redBits = redBits; + info.greenBits = greenBits; + info.blueBits = blueBits; + info.alphaBits = alphaBits; + info.luminanceBits = lumBits; + info.depthBits = depthBits; + info.stencilBits = stencilBits; + info.internalFormat = internalFormat; + info.mipGenerationFunction = mipFunc; + info.colorReadFunction = colorReadFunc; + + static const D3D9FastCopyMap fastCopyMap = BuildFastCopyMap(); + std::pair fastCopyIter = fastCopyMap.equal_range(format); + for (D3D9FastCopyMap::const_iterator i = fastCopyIter.first; i != fastCopyIter.second; i++) + { + info.fastCopyFunctions.insert(std::make_pair(std::make_pair(i->second.destFormat, i->second.destType), i->second.copyFunction)); + } + + map->insert(std::make_pair(format, info)); +} + +static D3D9FormatInfoMap BuildD3D9FormatInfoMap() +{ + D3D9FormatInfoMap map; + + // | D3DFORMAT | S |W |H | R | G | B | A | L | D | S | Internal format | Mip generation function | Color read function | + InsertD3DFormatInfo(&map, D3DFMT_NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, GL_NONE, NULL, NULL ); + InsertD3DFormatInfo(&map, D3DFMT_UNKNOWN, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, GL_NONE, NULL, NULL ); + + InsertD3DFormatInfo(&map, D3DFMT_L8, 8, 1, 1, 0, 0, 0, 0, 8, 0, 0, GL_LUMINANCE8_EXT, GenerateMip, ReadColor ); + InsertD3DFormatInfo(&map, D3DFMT_A8, 8, 1, 1, 0, 0, 0, 8, 0, 0, 0, GL_ALPHA8_EXT, GenerateMip, ReadColor ); + InsertD3DFormatInfo(&map, D3DFMT_A8L8, 16, 1, 1, 0, 0, 0, 8, 8, 0, 0, GL_LUMINANCE8_ALPHA8_EXT, GenerateMip, ReadColor ); + InsertD3DFormatInfo(&map, D3DFMT_A4R4G4B4, 16, 1, 1, 4, 4, 4, 4, 0, 0, 0, GL_BGRA4_ANGLEX, GenerateMip, ReadColor ); + InsertD3DFormatInfo(&map, D3DFMT_A1R5G5B5, 16, 1, 1, 5, 5, 5, 1, 0, 0, 0, GL_BGR5_A1_ANGLEX, GenerateMip, ReadColor ); + InsertD3DFormatInfo(&map, D3DFMT_R5G6B5, 16, 1, 1, 5, 6, 5, 0, 0, 0, 0, GL_RGB565, GenerateMip, ReadColor ); + InsertD3DFormatInfo(&map, D3DFMT_X8R8G8B8, 32, 1, 1, 8, 8, 8, 0, 0, 0, 0, GL_BGRA8_EXT, GenerateMip, ReadColor ); + InsertD3DFormatInfo(&map, D3DFMT_A8R8G8B8, 32, 1, 1, 8, 8, 8, 8, 0, 0, 0, GL_BGRA8_EXT, GenerateMip, ReadColor ); + InsertD3DFormatInfo(&map, D3DFMT_R16F, 16, 1, 1, 16, 0, 0, 0, 0, 0, 0, GL_R16F_EXT, GenerateMip, ReadColor ); + InsertD3DFormatInfo(&map, D3DFMT_G16R16F, 32, 1, 1, 16, 16, 0, 0, 0, 0, 0, GL_RG16F_EXT, GenerateMip, ReadColor ); + InsertD3DFormatInfo(&map, D3DFMT_A16B16G16R16F, 64, 1, 1, 16, 16, 16, 16, 0, 0, 0, GL_RGBA16F_EXT, GenerateMip, ReadColor); + InsertD3DFormatInfo(&map, D3DFMT_R32F, 32, 1, 1, 32, 0, 0, 0, 0, 0, 0, GL_R32F_EXT, GenerateMip, ReadColor ); + InsertD3DFormatInfo(&map, D3DFMT_G32R32F, 64, 1, 1, 32, 32, 0, 0, 0, 0, 0, GL_RG32F_EXT, GenerateMip, ReadColor ); + InsertD3DFormatInfo(&map, D3DFMT_A32B32G32R32F, 128, 1, 1, 32, 32, 32, 32, 0, 0, 0, GL_RGBA32F_EXT, GenerateMip, ReadColor); + + InsertD3DFormatInfo(&map, D3DFMT_D16, 16, 1, 1, 0, 0, 0, 0, 0, 16, 0, GL_DEPTH_COMPONENT16, NULL, NULL ); + InsertD3DFormatInfo(&map, D3DFMT_D24S8, 32, 1, 1, 0, 0, 0, 0, 0, 24, 8, GL_DEPTH24_STENCIL8_OES, NULL, NULL ); + InsertD3DFormatInfo(&map, D3DFMT_D24X8, 32, 1, 1, 0, 0, 0, 0, 0, 24, 0, GL_DEPTH_COMPONENT16, NULL, NULL ); + InsertD3DFormatInfo(&map, D3DFMT_D32, 32, 1, 1, 0, 0, 0, 0, 0, 32, 0, GL_DEPTH_COMPONENT32_OES, NULL, NULL ); + + InsertD3DFormatInfo(&map, D3DFMT_INTZ, 32, 1, 1, 0, 0, 0, 0, 0, 24, 8, GL_DEPTH24_STENCIL8_OES, NULL, NULL ); + + InsertD3DFormatInfo(&map, D3DFMT_DXT1, 64, 4, 4, 0, 0, 0, 0, 0, 0, 0, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, NULL, NULL ); + InsertD3DFormatInfo(&map, D3DFMT_DXT3, 128, 4, 4, 0, 0, 0, 0, 0, 0, 0, GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE, NULL, NULL ); + InsertD3DFormatInfo(&map, D3DFMT_DXT5, 128, 4, 4, 0, 0, 0, 0, 0, 0, 0, GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE, NULL, NULL ); + + return map; +} + +const D3DFormat &GetD3DFormatInfo(D3DFORMAT format) +{ + static const D3D9FormatInfoMap infoMap = BuildD3D9FormatInfoMap(); + D3D9FormatInfoMap::const_iterator iter = infoMap.find(format); + if (iter != infoMap.end()) + { + return iter->second; + } + else + { + static const D3DFormat defaultInfo; + return defaultInfo; + } +} + + + +typedef std::pair InternalFormatInitialzerPair; +typedef std::map InternalFormatInitialzerMap; + +static InternalFormatInitialzerMap BuildInternalFormatInitialzerMap() +{ + InternalFormatInitialzerMap map; + + map.insert(InternalFormatInitialzerPair(GL_RGB16F, Initialize4ComponentData)); + map.insert(InternalFormatInitialzerPair(GL_RGB32F, Initialize4ComponentData)); + + return map; +} + +// Each GL internal format corresponds to one D3D format and data loading function. +// Due to not all formats being available all the time, some of the function/format types are wrapped +// in templates that perform format support queries on a Renderer9 object which is supplied +// when requesting the function or format. + +typedef bool(*FallbackPredicateFunction)(); + +template +static void FallbackLoad(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + if (pred()) + { + prefered(width, height, depth, input, inputRowPitch, inputDepthPitch, output, outputRowPitch, outputDepthPitch); + } + else + { + fallback(width, height, depth, input, inputRowPitch, inputDepthPitch, output, outputRowPitch, outputDepthPitch); + } +} + +static void UnreachableLoad(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + UNREACHABLE(); +} + +typedef std::pair D3D9FormatPair; +typedef std::map D3D9FormatMap; + +TextureFormat::TextureFormat() + : texFormat(D3DFMT_UNKNOWN), + renderFormat(D3DFMT_UNKNOWN), + dataInitializerFunction(NULL), + loadFunction(UnreachableLoad) +{ +} + +static inline void InsertD3D9FormatInfo(D3D9FormatMap *map, GLenum internalFormat, D3DFORMAT texFormat, + D3DFORMAT renderFormat, LoadImageFunction loadFunction) +{ + TextureFormat info; + info.texFormat = texFormat; + info.renderFormat = renderFormat; + + static const InternalFormatInitialzerMap dataInitializationMap = BuildInternalFormatInitialzerMap(); + InternalFormatInitialzerMap::const_iterator dataInitIter = dataInitializationMap.find(internalFormat); + info.dataInitializerFunction = (dataInitIter != dataInitializationMap.end()) ? dataInitIter->second : NULL; + + info.loadFunction = loadFunction; + + map->insert(std::make_pair(internalFormat, info)); +} + +static D3D9FormatMap BuildD3D9FormatMap() +{ + D3D9FormatMap map; + + // | Internal format | Texture format | Render format | Load function | + InsertD3D9FormatInfo(&map, GL_NONE, D3DFMT_NULL, D3DFMT_NULL, UnreachableLoad ); + + // We choose to downsample the GL_DEPTH_COMPONENT32_OES format to a 24-bit format because D3DFMT_D32 is not widely + // supported. We're allowed to do this because: + // - The ES spec 2.0.25 sec 3.7.1 states that we're allowed to store texture formats with internal format + // resolutions of our own choosing. + // - OES_depth_texture states that downsampling of the depth formats is allowed. + // - ANGLE_depth_texture does not state minimum required resolutions of the depth texture formats it + // introduces. + // In ES3 however, there are minimum resolutions for the texture formats and this would not be allowed. + + InsertD3D9FormatInfo(&map, GL_DEPTH_COMPONENT16, D3DFMT_INTZ, D3DFMT_D24S8, UnreachableLoad ); + InsertD3D9FormatInfo(&map, GL_DEPTH_COMPONENT32_OES, D3DFMT_INTZ, D3DFMT_D24X8, UnreachableLoad ); + InsertD3D9FormatInfo(&map, GL_DEPTH24_STENCIL8_OES, D3DFMT_INTZ, D3DFMT_D24S8, UnreachableLoad ); + InsertD3D9FormatInfo(&map, GL_STENCIL_INDEX8, D3DFMT_UNKNOWN, D3DFMT_D24S8, UnreachableLoad ); // TODO: What's the texture format? + + InsertD3D9FormatInfo(&map, GL_RGBA32F_EXT, D3DFMT_A32B32G32R32F, D3DFMT_A32B32G32R32F, LoadToNative ); + InsertD3D9FormatInfo(&map, GL_RGB32F_EXT, D3DFMT_A32B32G32R32F, D3DFMT_A32B32G32R32F, LoadToNative3To4); + InsertD3D9FormatInfo(&map, GL_RG32F_EXT, D3DFMT_G32R32F, D3DFMT_G32R32F, LoadToNative ); + InsertD3D9FormatInfo(&map, GL_R32F_EXT, D3DFMT_R32F, D3DFMT_R32F, LoadToNative ); + InsertD3D9FormatInfo(&map, GL_ALPHA32F_EXT, D3DFMT_A32B32G32R32F, D3DFMT_UNKNOWN, LoadA32FToRGBA32F ); + InsertD3D9FormatInfo(&map, GL_LUMINANCE32F_EXT, D3DFMT_A32B32G32R32F, D3DFMT_UNKNOWN, LoadL32FToRGBA32F ); + InsertD3D9FormatInfo(&map, GL_LUMINANCE_ALPHA32F_EXT, D3DFMT_A32B32G32R32F, D3DFMT_UNKNOWN, LoadLA32FToRGBA32F ); + + InsertD3D9FormatInfo(&map, GL_RGBA16F_EXT, D3DFMT_A16B16G16R16F, D3DFMT_A16B16G16R16F, LoadToNative ); + InsertD3D9FormatInfo(&map, GL_RGB16F_EXT, D3DFMT_A16B16G16R16F, D3DFMT_A16B16G16R16F, LoadToNative3To4 ); + InsertD3D9FormatInfo(&map, GL_RG16F_EXT, D3DFMT_G16R16F, D3DFMT_G16R16F, LoadToNative ); + InsertD3D9FormatInfo(&map, GL_R16F_EXT, D3DFMT_R16F, D3DFMT_R16F, LoadToNative ); + InsertD3D9FormatInfo(&map, GL_ALPHA16F_EXT, D3DFMT_A16B16G16R16F, D3DFMT_UNKNOWN, LoadA16FToRGBA16F ); + InsertD3D9FormatInfo(&map, GL_LUMINANCE16F_EXT, D3DFMT_A16B16G16R16F, D3DFMT_UNKNOWN, LoadL16FToRGBA16F ); + InsertD3D9FormatInfo(&map, GL_LUMINANCE_ALPHA16F_EXT, D3DFMT_A16B16G16R16F, D3DFMT_UNKNOWN, LoadLA16FToRGBA16F ); + + InsertD3D9FormatInfo(&map, GL_ALPHA8_EXT, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, FallbackLoad); + + InsertD3D9FormatInfo(&map, GL_RGB8_OES, D3DFMT_X8R8G8B8, D3DFMT_X8R8G8B8, LoadRGB8ToBGRX8 ); + InsertD3D9FormatInfo(&map, GL_RGB565, D3DFMT_X8R8G8B8, D3DFMT_X8R8G8B8, LoadR5G6B5ToBGRA8 ); + InsertD3D9FormatInfo(&map, GL_RGBA8_OES, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, FallbackLoad); + InsertD3D9FormatInfo(&map, GL_RGBA4, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, LoadRGBA4ToBGRA8 ); + InsertD3D9FormatInfo(&map, GL_RGB5_A1, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, LoadRGB5A1ToBGRA8 ); + InsertD3D9FormatInfo(&map, GL_R8_EXT, D3DFMT_X8R8G8B8, D3DFMT_X8R8G8B8, LoadR8ToBGRX8 ); + InsertD3D9FormatInfo(&map, GL_RG8_EXT, D3DFMT_X8R8G8B8, D3DFMT_X8R8G8B8, LoadRG8ToBGRX8 ); + + InsertD3D9FormatInfo(&map, GL_BGRA8_EXT, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, LoadToNative ); + InsertD3D9FormatInfo(&map, GL_BGRA4_ANGLEX, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, LoadBGRA4ToBGRA8 ); + InsertD3D9FormatInfo(&map, GL_BGR5_A1_ANGLEX, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, LoadBGR5A1ToBGRA8 ); + + InsertD3D9FormatInfo(&map, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, D3DFMT_DXT1, D3DFMT_UNKNOWN, LoadCompressedToNative<4, 4, 8> ); + InsertD3D9FormatInfo(&map, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, D3DFMT_DXT1, D3DFMT_UNKNOWN, LoadCompressedToNative<4, 4, 8> ); + InsertD3D9FormatInfo(&map, GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE, D3DFMT_DXT3, D3DFMT_UNKNOWN, LoadCompressedToNative<4, 4, 16> ); + InsertD3D9FormatInfo(&map, GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE, D3DFMT_DXT5, D3DFMT_UNKNOWN, LoadCompressedToNative<4, 4, 16> ); + + // These formats require checking if the renderer supports D3DFMT_L8 or D3DFMT_A8L8 and + // then changing the format and loading function appropriately. + InsertD3D9FormatInfo(&map, GL_LUMINANCE8_EXT, D3DFMT_L8, D3DFMT_UNKNOWN, LoadToNative ); + InsertD3D9FormatInfo(&map, GL_LUMINANCE8_ALPHA8_EXT, D3DFMT_A8L8, D3DFMT_UNKNOWN, LoadToNative ); + + return map; +} + +const TextureFormat &GetTextureFormatInfo(GLenum internalFormat) +{ + static const D3D9FormatMap formatMap = BuildD3D9FormatMap(); + D3D9FormatMap::const_iterator iter = formatMap.find(internalFormat); + if (iter != formatMap.end()) + { + return iter->second; + } + else + { + static const TextureFormat defaultInfo; + return defaultInfo; + } +} + +static GLenum GetDeclTypeComponentType(D3DDECLTYPE declType) +{ + switch (declType) + { + case D3DDECLTYPE_FLOAT1: return GL_FLOAT; + case D3DDECLTYPE_FLOAT2: return GL_FLOAT; + case D3DDECLTYPE_FLOAT3: return GL_FLOAT; + case D3DDECLTYPE_FLOAT4: return GL_FLOAT; + case D3DDECLTYPE_UBYTE4: return GL_UNSIGNED_INT; + case D3DDECLTYPE_SHORT2: return GL_INT; + case D3DDECLTYPE_SHORT4: return GL_INT; + case D3DDECLTYPE_UBYTE4N: return GL_UNSIGNED_NORMALIZED; + case D3DDECLTYPE_SHORT4N: return GL_SIGNED_NORMALIZED; + case D3DDECLTYPE_USHORT4N: return GL_UNSIGNED_NORMALIZED; + case D3DDECLTYPE_SHORT2N: return GL_SIGNED_NORMALIZED; + case D3DDECLTYPE_USHORT2N: return GL_UNSIGNED_NORMALIZED; + default: UNREACHABLE(); return GL_NONE; + } +} + +// Attribute format conversion +enum { NUM_GL_VERTEX_ATTRIB_TYPES = 6 }; + +struct TranslationDescription +{ + DWORD capsFlag; + VertexFormat preferredConversion; + VertexFormat fallbackConversion; +}; + +// Mapping from OpenGL-ES vertex attrib type to D3D decl type: +// +// BYTE SHORT (Cast) +// BYTE-norm FLOAT (Normalize) (can't be exactly represented as SHORT-norm) +// UNSIGNED_BYTE UBYTE4 (Identity) or SHORT (Cast) +// UNSIGNED_BYTE-norm UBYTE4N (Identity) or FLOAT (Normalize) +// SHORT SHORT (Identity) +// SHORT-norm SHORT-norm (Identity) or FLOAT (Normalize) +// UNSIGNED_SHORT FLOAT (Cast) +// UNSIGNED_SHORT-norm USHORT-norm (Identity) or FLOAT (Normalize) +// FIXED (not in WebGL) FLOAT (FixedToFloat) +// FLOAT FLOAT (Identity) + +// GLToCType maps from GL type (as GLenum) to the C typedef. +template struct GLToCType { }; + +template <> struct GLToCType { typedef GLbyte type; }; +template <> struct GLToCType { typedef GLubyte type; }; +template <> struct GLToCType { typedef GLshort type; }; +template <> struct GLToCType { typedef GLushort type; }; +template <> struct GLToCType { typedef GLuint type; }; +template <> struct GLToCType { typedef GLfloat type; }; + +// This differs from D3DDECLTYPE in that it is unsized. (Size expansion is applied last.) +enum D3DVertexType +{ + D3DVT_FLOAT, + D3DVT_SHORT, + D3DVT_SHORT_NORM, + D3DVT_UBYTE, + D3DVT_UBYTE_NORM, + D3DVT_USHORT_NORM +}; + +// D3DToCType maps from D3D vertex type (as enum D3DVertexType) to the corresponding C type. +template struct D3DToCType { }; + +template <> struct D3DToCType { typedef float type; }; +template <> struct D3DToCType { typedef short type; }; +template <> struct D3DToCType { typedef short type; }; +template <> struct D3DToCType { typedef unsigned char type; }; +template <> struct D3DToCType { typedef unsigned char type; }; +template <> struct D3DToCType { typedef unsigned short type; }; + +// Encode the type/size combinations that D3D permits. For each type/size it expands to a widener that will provide the appropriate final size. +template struct WidenRule { }; + +template struct WidenRule : NoWiden { }; +template struct WidenRule : WidenToEven { }; +template struct WidenRule : WidenToEven { }; +template struct WidenRule : WidenToFour { }; +template struct WidenRule : WidenToFour { }; +template struct WidenRule : WidenToEven { }; + +// VertexTypeFlags encodes the D3DCAPS9::DeclType flag and vertex declaration flag for each D3D vertex type & size combination. +template struct VertexTypeFlags { }; + +template +struct VertexTypeFlagsHelper +{ + enum { capflag = _capflag }; + enum { declflag = _declflag }; +}; + +template <> struct VertexTypeFlags : VertexTypeFlagsHelper<0, D3DDECLTYPE_FLOAT1> { }; +template <> struct VertexTypeFlags : VertexTypeFlagsHelper<0, D3DDECLTYPE_FLOAT2> { }; +template <> struct VertexTypeFlags : VertexTypeFlagsHelper<0, D3DDECLTYPE_FLOAT3> { }; +template <> struct VertexTypeFlags : VertexTypeFlagsHelper<0, D3DDECLTYPE_FLOAT4> { }; +template <> struct VertexTypeFlags : VertexTypeFlagsHelper<0, D3DDECLTYPE_SHORT2> { }; +template <> struct VertexTypeFlags : VertexTypeFlagsHelper<0, D3DDECLTYPE_SHORT4> { }; +template <> struct VertexTypeFlags : VertexTypeFlagsHelper { }; +template <> struct VertexTypeFlags : VertexTypeFlagsHelper { }; +template <> struct VertexTypeFlags : VertexTypeFlagsHelper { }; +template <> struct VertexTypeFlags : VertexTypeFlagsHelper { }; +template <> struct VertexTypeFlags : VertexTypeFlagsHelper { }; +template <> struct VertexTypeFlags : VertexTypeFlagsHelper { }; + + +// VertexTypeMapping maps GL type & normalized flag to preferred and fallback D3D vertex types (as D3DVertexType enums). +template struct VertexTypeMapping { }; + +template +struct VertexTypeMappingBase +{ + enum { preferred = Preferred }; + enum { fallback = Fallback }; +}; + +template <> struct VertexTypeMapping : VertexTypeMappingBase { }; // Cast +template <> struct VertexTypeMapping : VertexTypeMappingBase { }; // Normalize +template <> struct VertexTypeMapping : VertexTypeMappingBase { }; // Identity, Cast +template <> struct VertexTypeMapping : VertexTypeMappingBase { }; // Identity, Normalize +template <> struct VertexTypeMapping : VertexTypeMappingBase { }; // Identity +template <> struct VertexTypeMapping : VertexTypeMappingBase { }; // Cast, Normalize +template <> struct VertexTypeMapping : VertexTypeMappingBase { }; // Cast +template <> struct VertexTypeMapping : VertexTypeMappingBase { }; // Cast, Normalize +template struct VertexTypeMapping : VertexTypeMappingBase { }; // FixedToFloat +template struct VertexTypeMapping : VertexTypeMappingBase { }; // Identity + + +// Given a GL type & norm flag and a D3D type, ConversionRule provides the type conversion rule (Cast, Normalize, Identity, FixedToFloat). +// The conversion rules themselves are defined in vertexconversion.h. + +// Almost all cases are covered by Cast (including those that are actually Identity since Cast knows it's an identity mapping). +template +struct ConversionRule : Cast::type, typename D3DToCType::type> { }; + +// All conversions from normalized types to float use the Normalize operator. +template struct ConversionRule : Normalize::type> { }; + +// Use a full specialization for this so that it preferentially matches ahead of the generic normalize-to-float rules. +template <> struct ConversionRule : FixedToFloat { }; +template <> struct ConversionRule : FixedToFloat { }; + +// A 2-stage construction is used for DefaultVertexValues because float must use SimpleDefaultValues (i.e. 0/1) +// whether it is normalized or not. +template struct DefaultVertexValuesStage2 { }; + +template struct DefaultVertexValuesStage2 : NormalizedDefaultValues { }; +template struct DefaultVertexValuesStage2 : SimpleDefaultValues { }; + +// Work out the default value rule for a D3D type (expressed as the C type) and +template struct DefaultVertexValues : DefaultVertexValuesStage2 { }; +template struct DefaultVertexValues : SimpleDefaultValues { }; + +// Policy rules for use with Converter, to choose whether to use the preferred or fallback conversion. +// The fallback conversion produces an output that all D3D9 devices must support. +template struct UsePreferred { enum { type = T::preferred }; }; +template struct UseFallback { enum { type = T::fallback }; }; + +// Converter ties it all together. Given an OpenGL type/norm/size and choice of preferred/fallback conversion, +// it provides all the members of the appropriate VertexDataConverter, the D3DCAPS9::DeclTypes flag in cap flag +// and the D3DDECLTYPE member needed for the vertex declaration in declflag. +template class PreferenceRule> +struct Converter + : VertexDataConverter::type, + WidenRule >::type, size>, + ConversionRule >::type>, + DefaultVertexValues >::type>::type, normalized > > +{ +private: + enum { d3dtype = PreferenceRule< VertexTypeMapping >::type }; + enum { d3dsize = WidenRule::finalWidth }; + +public: + enum { capflag = VertexTypeFlags::capflag }; + enum { declflag = VertexTypeFlags::declflag }; +}; + +VertexFormat::VertexFormat() + : conversionType(VERTEX_CONVERT_NONE), + outputElementSize(0), + copyFunction(NULL), + nativeFormat(D3DDECLTYPE_UNUSED), + componentType(GL_NONE) +{ +} + +// Initialize a TranslationInfo +VertexFormat CreateVertexFormatInfo(bool identity, size_t elementSize, VertexCopyFunction copyFunc, D3DDECLTYPE nativeFormat) +{ + VertexFormat formatInfo; + formatInfo.conversionType = identity ? VERTEX_CONVERT_NONE : VERTEX_CONVERT_CPU; + formatInfo.outputElementSize = elementSize; + formatInfo.copyFunction = copyFunc; + formatInfo.nativeFormat = nativeFormat; + formatInfo.componentType = GetDeclTypeComponentType(nativeFormat); + return formatInfo; +} + +#define TRANSLATION(type, norm, size, preferred) \ + CreateVertexFormatInfo \ + ( \ + Converter::identity, \ + Converter::finalSize, \ + Converter::convertArray, \ + static_cast(Converter::declflag) \ + ) + +#define TRANSLATION_FOR_TYPE_NORM_SIZE(type, norm, size) \ + { \ + Converter::capflag, \ + TRANSLATION(type, norm, size, UsePreferred), \ + TRANSLATION(type, norm, size, UseFallback) \ + } + +#define TRANSLATIONS_FOR_TYPE(type) \ + { \ + { TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 1), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 2), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 3), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 4) }, \ + { TRANSLATION_FOR_TYPE_NORM_SIZE(type, true, 1), TRANSLATION_FOR_TYPE_NORM_SIZE(type, true, 2), TRANSLATION_FOR_TYPE_NORM_SIZE(type, true, 3), TRANSLATION_FOR_TYPE_NORM_SIZE(type, true, 4) }, \ + } + +#define TRANSLATIONS_FOR_TYPE_NO_NORM(type) \ + { \ + { TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 1), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 2), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 3), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 4) }, \ + { TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 1), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 2), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 3), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 4) }, \ + } + +static inline unsigned int ComputeTypeIndex(GLenum type) +{ + switch (type) + { + case GL_BYTE: return 0; + case GL_UNSIGNED_BYTE: return 1; + case GL_SHORT: return 2; + case GL_UNSIGNED_SHORT: return 3; + case GL_FIXED: return 4; + case GL_FLOAT: return 5; + + default: UNREACHABLE(); return 5; + } +} + +const VertexFormat &GetVertexFormatInfo(DWORD supportedDeclTypes, const gl::VertexFormat &vertexFormat) +{ + static bool initialized = false; + static DWORD intializedDeclTypes = 0; + static VertexFormat formatConverters[NUM_GL_VERTEX_ATTRIB_TYPES][2][4]; + if (intializedDeclTypes != supportedDeclTypes) + { + const TranslationDescription translations[NUM_GL_VERTEX_ATTRIB_TYPES][2][4] = // [GL types as enumerated by typeIndex()][normalized][size-1] + { + TRANSLATIONS_FOR_TYPE(GL_BYTE), + TRANSLATIONS_FOR_TYPE(GL_UNSIGNED_BYTE), + TRANSLATIONS_FOR_TYPE(GL_SHORT), + TRANSLATIONS_FOR_TYPE(GL_UNSIGNED_SHORT), + TRANSLATIONS_FOR_TYPE_NO_NORM(GL_FIXED), + TRANSLATIONS_FOR_TYPE_NO_NORM(GL_FLOAT) + }; + for (unsigned int i = 0; i < NUM_GL_VERTEX_ATTRIB_TYPES; i++) + { + for (unsigned int j = 0; j < 2; j++) + { + for (unsigned int k = 0; k < 4; k++) + { + if (translations[i][j][k].capsFlag == 0 || (supportedDeclTypes & translations[i][j][k].capsFlag) != 0) + { + formatConverters[i][j][k] = translations[i][j][k].preferredConversion; + } + else + { + formatConverters[i][j][k] = translations[i][j][k].fallbackConversion; + } + } + } + } + initialized = true; + intializedDeclTypes = supportedDeclTypes; + } + + // Pure integer attributes only supported in ES3.0 + ASSERT(!vertexFormat.mPureInteger); + return formatConverters[ComputeTypeIndex(vertexFormat.mType)][vertexFormat.mNormalized][vertexFormat.mComponents - 1]; +} + +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/formatutils9.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/formatutils9.h new file mode 100644 index 0000000000..15e26599c8 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/formatutils9.h @@ -0,0 +1,86 @@ +// +// Copyright (c) 2013-2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// formatutils9.h: Queries for GL image formats and their translations to D3D9 +// formats. + +#ifndef LIBANGLE_RENDERER_D3D_D3D9_FORMATUTILS9_H_ +#define LIBANGLE_RENDERER_D3D_D3D9_FORMATUTILS9_H_ + +#include "libANGLE/renderer/d3d/formatutilsD3D.h" +#include "libANGLE/angletypes.h" + +#include "common/platform.h" + +#include + +namespace rx +{ + +class Renderer9; + +namespace d3d9 +{ + +typedef std::map, ColorCopyFunction> FastCopyFunctionMap; + +struct D3DFormat +{ + D3DFormat(); + + GLuint pixelBytes; + GLuint blockWidth; + GLuint blockHeight; + + GLuint redBits; + GLuint greenBits; + GLuint blueBits; + GLuint alphaBits; + GLuint luminanceBits; + + GLuint depthBits; + GLuint stencilBits; + + GLenum internalFormat; + + MipGenerationFunction mipGenerationFunction; + ColorReadFunction colorReadFunction; + + FastCopyFunctionMap fastCopyFunctions; + ColorCopyFunction getFastCopyFunction(GLenum format, GLenum type) const; +}; +const D3DFormat &GetD3DFormatInfo(D3DFORMAT format); + +struct VertexFormat +{ + VertexFormat(); + + VertexConversionType conversionType; + size_t outputElementSize; + VertexCopyFunction copyFunction; + D3DDECLTYPE nativeFormat; + GLenum componentType; +}; +const VertexFormat &GetVertexFormatInfo(DWORD supportedDeclTypes, const gl::VertexFormat &vertexFormat); + +struct TextureFormat +{ + TextureFormat(); + + D3DFORMAT texFormat; + D3DFORMAT renderFormat; + + InitializeTextureDataFunction dataInitializerFunction; + + LoadImageFunction loadFunction; +}; +const TextureFormat &GetTextureFormatInfo(GLenum internalFormat); + +} + +} + +#endif // LIBANGLE_RENDERER_D3D_D3D9_FORMATUTILS9_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/renderer9_utils.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/renderer9_utils.cpp new file mode 100644 index 0000000000..c9711ac052 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/renderer9_utils.cpp @@ -0,0 +1,597 @@ +// +// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// renderer9_utils.cpp: Conversion functions and other utility routines +// specific to the D3D9 renderer. + +#include "libANGLE/renderer/d3d/d3d9/renderer9_utils.h" +#include "libANGLE/renderer/d3d/d3d9/formatutils9.h" +#include "libANGLE/renderer/d3d/FramebufferD3D.h" +#include "libANGLE/renderer/Workarounds.h" +#include "libANGLE/formatutils.h" +#include "libANGLE/Framebuffer.h" +#include "libANGLE/renderer/d3d/d3d9/RenderTarget9.h" + +#include "common/mathutil.h" +#include "common/debug.h" + +#include "third_party/systeminfo/SystemInfo.h" + +namespace rx +{ + +namespace gl_d3d9 +{ + +D3DCMPFUNC ConvertComparison(GLenum comparison) +{ + D3DCMPFUNC d3dComp = D3DCMP_ALWAYS; + switch (comparison) + { + case GL_NEVER: d3dComp = D3DCMP_NEVER; break; + case GL_ALWAYS: d3dComp = D3DCMP_ALWAYS; break; + case GL_LESS: d3dComp = D3DCMP_LESS; break; + case GL_LEQUAL: d3dComp = D3DCMP_LESSEQUAL; break; + case GL_EQUAL: d3dComp = D3DCMP_EQUAL; break; + case GL_GREATER: d3dComp = D3DCMP_GREATER; break; + case GL_GEQUAL: d3dComp = D3DCMP_GREATEREQUAL; break; + case GL_NOTEQUAL: d3dComp = D3DCMP_NOTEQUAL; break; + default: UNREACHABLE(); + } + + return d3dComp; +} + +D3DCOLOR ConvertColor(gl::ColorF color) +{ + return D3DCOLOR_RGBA(gl::unorm<8>(color.red), + gl::unorm<8>(color.green), + gl::unorm<8>(color.blue), + gl::unorm<8>(color.alpha)); +} + +D3DBLEND ConvertBlendFunc(GLenum blend) +{ + D3DBLEND d3dBlend = D3DBLEND_ZERO; + + switch (blend) + { + case GL_ZERO: d3dBlend = D3DBLEND_ZERO; break; + case GL_ONE: d3dBlend = D3DBLEND_ONE; break; + case GL_SRC_COLOR: d3dBlend = D3DBLEND_SRCCOLOR; break; + case GL_ONE_MINUS_SRC_COLOR: d3dBlend = D3DBLEND_INVSRCCOLOR; break; + case GL_DST_COLOR: d3dBlend = D3DBLEND_DESTCOLOR; break; + case GL_ONE_MINUS_DST_COLOR: d3dBlend = D3DBLEND_INVDESTCOLOR; break; + case GL_SRC_ALPHA: d3dBlend = D3DBLEND_SRCALPHA; break; + case GL_ONE_MINUS_SRC_ALPHA: d3dBlend = D3DBLEND_INVSRCALPHA; break; + case GL_DST_ALPHA: d3dBlend = D3DBLEND_DESTALPHA; break; + case GL_ONE_MINUS_DST_ALPHA: d3dBlend = D3DBLEND_INVDESTALPHA; break; + case GL_CONSTANT_COLOR: d3dBlend = D3DBLEND_BLENDFACTOR; break; + case GL_ONE_MINUS_CONSTANT_COLOR: d3dBlend = D3DBLEND_INVBLENDFACTOR; break; + case GL_CONSTANT_ALPHA: d3dBlend = D3DBLEND_BLENDFACTOR; break; + case GL_ONE_MINUS_CONSTANT_ALPHA: d3dBlend = D3DBLEND_INVBLENDFACTOR; break; + case GL_SRC_ALPHA_SATURATE: d3dBlend = D3DBLEND_SRCALPHASAT; break; + default: UNREACHABLE(); + } + + return d3dBlend; +} + +D3DBLENDOP ConvertBlendOp(GLenum blendOp) +{ + D3DBLENDOP d3dBlendOp = D3DBLENDOP_ADD; + + switch (blendOp) + { + case GL_FUNC_ADD: d3dBlendOp = D3DBLENDOP_ADD; break; + case GL_FUNC_SUBTRACT: d3dBlendOp = D3DBLENDOP_SUBTRACT; break; + case GL_FUNC_REVERSE_SUBTRACT: d3dBlendOp = D3DBLENDOP_REVSUBTRACT; break; + case GL_MIN_EXT: d3dBlendOp = D3DBLENDOP_MIN; break; + case GL_MAX_EXT: d3dBlendOp = D3DBLENDOP_MAX; break; + default: UNREACHABLE(); + } + + return d3dBlendOp; +} + +D3DSTENCILOP ConvertStencilOp(GLenum stencilOp) +{ + D3DSTENCILOP d3dStencilOp = D3DSTENCILOP_KEEP; + + switch (stencilOp) + { + case GL_ZERO: d3dStencilOp = D3DSTENCILOP_ZERO; break; + case GL_KEEP: d3dStencilOp = D3DSTENCILOP_KEEP; break; + case GL_REPLACE: d3dStencilOp = D3DSTENCILOP_REPLACE; break; + case GL_INCR: d3dStencilOp = D3DSTENCILOP_INCRSAT; break; + case GL_DECR: d3dStencilOp = D3DSTENCILOP_DECRSAT; break; + case GL_INVERT: d3dStencilOp = D3DSTENCILOP_INVERT; break; + case GL_INCR_WRAP: d3dStencilOp = D3DSTENCILOP_INCR; break; + case GL_DECR_WRAP: d3dStencilOp = D3DSTENCILOP_DECR; break; + default: UNREACHABLE(); + } + + return d3dStencilOp; +} + +D3DTEXTUREADDRESS ConvertTextureWrap(GLenum wrap) +{ + D3DTEXTUREADDRESS d3dWrap = D3DTADDRESS_WRAP; + + switch (wrap) + { + case GL_REPEAT: d3dWrap = D3DTADDRESS_WRAP; break; + case GL_CLAMP_TO_EDGE: d3dWrap = D3DTADDRESS_CLAMP; break; + case GL_MIRRORED_REPEAT: d3dWrap = D3DTADDRESS_MIRROR; break; + default: UNREACHABLE(); + } + + return d3dWrap; +} + +D3DCULL ConvertCullMode(GLenum cullFace, GLenum frontFace) +{ + D3DCULL cull = D3DCULL_CCW; + switch (cullFace) + { + case GL_FRONT: + cull = (frontFace == GL_CCW ? D3DCULL_CW : D3DCULL_CCW); + break; + case GL_BACK: + cull = (frontFace == GL_CCW ? D3DCULL_CCW : D3DCULL_CW); + break; + case GL_FRONT_AND_BACK: + cull = D3DCULL_NONE; // culling will be handled during draw + break; + default: UNREACHABLE(); + } + + return cull; +} + +D3DCUBEMAP_FACES ConvertCubeFace(GLenum cubeFace) +{ + D3DCUBEMAP_FACES face = D3DCUBEMAP_FACE_POSITIVE_X; + + switch (cubeFace) + { + case GL_TEXTURE_CUBE_MAP_POSITIVE_X: + face = D3DCUBEMAP_FACE_POSITIVE_X; + break; + case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: + face = D3DCUBEMAP_FACE_NEGATIVE_X; + break; + case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: + face = D3DCUBEMAP_FACE_POSITIVE_Y; + break; + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: + face = D3DCUBEMAP_FACE_NEGATIVE_Y; + break; + case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: + face = D3DCUBEMAP_FACE_POSITIVE_Z; + break; + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: + face = D3DCUBEMAP_FACE_NEGATIVE_Z; + break; + default: UNREACHABLE(); + } + + return face; +} + +DWORD ConvertColorMask(bool red, bool green, bool blue, bool alpha) +{ + return (red ? D3DCOLORWRITEENABLE_RED : 0) | + (green ? D3DCOLORWRITEENABLE_GREEN : 0) | + (blue ? D3DCOLORWRITEENABLE_BLUE : 0) | + (alpha ? D3DCOLORWRITEENABLE_ALPHA : 0); +} + +D3DTEXTUREFILTERTYPE ConvertMagFilter(GLenum magFilter, float maxAnisotropy) +{ + if (maxAnisotropy > 1.0f) + { + return D3DTEXF_ANISOTROPIC; + } + + D3DTEXTUREFILTERTYPE d3dMagFilter = D3DTEXF_POINT; + switch (magFilter) + { + case GL_NEAREST: d3dMagFilter = D3DTEXF_POINT; break; + case GL_LINEAR: d3dMagFilter = D3DTEXF_LINEAR; break; + default: UNREACHABLE(); + } + + return d3dMagFilter; +} + +void ConvertMinFilter(GLenum minFilter, D3DTEXTUREFILTERTYPE *d3dMinFilter, D3DTEXTUREFILTERTYPE *d3dMipFilter, float maxAnisotropy) +{ + switch (minFilter) + { + case GL_NEAREST: + *d3dMinFilter = D3DTEXF_POINT; + *d3dMipFilter = D3DTEXF_NONE; + break; + case GL_LINEAR: + *d3dMinFilter = D3DTEXF_LINEAR; + *d3dMipFilter = D3DTEXF_NONE; + break; + case GL_NEAREST_MIPMAP_NEAREST: + *d3dMinFilter = D3DTEXF_POINT; + *d3dMipFilter = D3DTEXF_POINT; + break; + case GL_LINEAR_MIPMAP_NEAREST: + *d3dMinFilter = D3DTEXF_LINEAR; + *d3dMipFilter = D3DTEXF_POINT; + break; + case GL_NEAREST_MIPMAP_LINEAR: + *d3dMinFilter = D3DTEXF_POINT; + *d3dMipFilter = D3DTEXF_LINEAR; + break; + case GL_LINEAR_MIPMAP_LINEAR: + *d3dMinFilter = D3DTEXF_LINEAR; + *d3dMipFilter = D3DTEXF_LINEAR; + break; + default: + *d3dMinFilter = D3DTEXF_POINT; + *d3dMipFilter = D3DTEXF_NONE; + UNREACHABLE(); + } + + if (maxAnisotropy > 1.0f) + { + *d3dMinFilter = D3DTEXF_ANISOTROPIC; + } +} + +D3DMULTISAMPLE_TYPE GetMultisampleType(GLuint samples) +{ + return (samples > 1) ? static_cast(samples) : D3DMULTISAMPLE_NONE; +} + +} + +namespace d3d9_gl +{ + +GLsizei GetSamplesCount(D3DMULTISAMPLE_TYPE type) +{ + return (type != D3DMULTISAMPLE_NONMASKABLE) ? type : 0; +} + +bool IsFormatChannelEquivalent(D3DFORMAT d3dformat, GLenum format) +{ + GLenum internalFormat = d3d9::GetD3DFormatInfo(d3dformat).internalFormat; + GLenum convertedFormat = gl::GetInternalFormatInfo(internalFormat).format; + return convertedFormat == format; +} + +static gl::TextureCaps GenerateTextureFormatCaps(GLenum internalFormat, IDirect3D9 *d3d9, D3DDEVTYPE deviceType, + UINT adapter, D3DFORMAT adapterFormat) +{ + gl::TextureCaps textureCaps; + + const d3d9::TextureFormat &d3dFormatInfo = d3d9::GetTextureFormatInfo(internalFormat); + const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat); + + if (d3dFormatInfo.texFormat != D3DFMT_UNKNOWN) + { + if (formatInfo.depthBits > 0 || formatInfo.stencilBits > 0) + { + textureCaps.texturable = SUCCEEDED(d3d9->CheckDeviceFormat(adapter, deviceType, adapterFormat, 0, D3DRTYPE_TEXTURE, d3dFormatInfo.texFormat)); + } + else + { + textureCaps.texturable = SUCCEEDED(d3d9->CheckDeviceFormat(adapter, deviceType, adapterFormat, 0, D3DRTYPE_TEXTURE, d3dFormatInfo.texFormat)) && + SUCCEEDED(d3d9->CheckDeviceFormat(adapter, deviceType, adapterFormat, 0, D3DRTYPE_CUBETEXTURE, d3dFormatInfo.texFormat)); + } + + textureCaps.filterable = SUCCEEDED(d3d9->CheckDeviceFormat(adapter, deviceType, adapterFormat, D3DUSAGE_QUERY_FILTER, D3DRTYPE_TEXTURE, d3dFormatInfo.texFormat)); + } + + if (d3dFormatInfo.renderFormat != D3DFMT_UNKNOWN) + { + textureCaps.renderable = SUCCEEDED(d3d9->CheckDeviceFormat(adapter, deviceType, adapterFormat, D3DUSAGE_RENDERTARGET, D3DRTYPE_TEXTURE, d3dFormatInfo.renderFormat)); + + if ((formatInfo.depthBits > 0 || formatInfo.stencilBits > 0) && !textureCaps.renderable) + { + textureCaps.renderable = SUCCEEDED(d3d9->CheckDeviceFormat(adapter, deviceType, adapterFormat, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_TEXTURE, d3dFormatInfo.renderFormat)); + } + + textureCaps.sampleCounts.insert(1); + for (size_t i = D3DMULTISAMPLE_2_SAMPLES; i <= D3DMULTISAMPLE_16_SAMPLES; i++) + { + D3DMULTISAMPLE_TYPE multisampleType = D3DMULTISAMPLE_TYPE(i); + + HRESULT result = d3d9->CheckDeviceMultiSampleType(adapter, deviceType, d3dFormatInfo.renderFormat, TRUE, multisampleType, NULL); + if (SUCCEEDED(result)) + { + textureCaps.sampleCounts.insert(i); + } + } + } + + return textureCaps; +} + +void GenerateCaps(IDirect3D9 *d3d9, IDirect3DDevice9 *device, D3DDEVTYPE deviceType, UINT adapter, gl::Caps *caps, + gl::TextureCapsMap *textureCapsMap, gl::Extensions *extensions) +{ + D3DCAPS9 deviceCaps; + if (FAILED(d3d9->GetDeviceCaps(adapter, deviceType, &deviceCaps))) + { + // Can't continue with out device caps + return; + } + + D3DDISPLAYMODE currentDisplayMode; + d3d9->GetAdapterDisplayMode(adapter, ¤tDisplayMode); + + GLuint maxSamples = 0; + const gl::FormatSet &allFormats = gl::GetAllSizedInternalFormats(); + for (gl::FormatSet::const_iterator internalFormat = allFormats.begin(); internalFormat != allFormats.end(); ++internalFormat) + { + gl::TextureCaps textureCaps = GenerateTextureFormatCaps(*internalFormat, d3d9, deviceType, adapter, + currentDisplayMode.Format); + textureCapsMap->insert(*internalFormat, textureCaps); + + maxSamples = std::max(maxSamples, textureCaps.getMaxSamples()); + + if (gl::GetInternalFormatInfo(*internalFormat).compressed) + { + caps->compressedTextureFormats.push_back(*internalFormat); + } + } + + // GL core feature limits + caps->maxElementIndex = static_cast(std::numeric_limits::max()); + + // 3D textures are unimplemented in D3D9 + caps->max3DTextureSize = 1; + + // Only one limit in GL, use the minimum dimension + caps->max2DTextureSize = std::min(deviceCaps.MaxTextureWidth, deviceCaps.MaxTextureHeight); + + // D3D treats cube maps as a special case of 2D textures + caps->maxCubeMapTextureSize = caps->max2DTextureSize; + + // Array textures are not available in D3D9 + caps->maxArrayTextureLayers = 1; + + // ES3-only feature + caps->maxLODBias = 0.0f; + + // No specific limits on render target size, maximum 2D texture size is equivalent + caps->maxRenderbufferSize = caps->max2DTextureSize; + + // Draw buffers are not supported in D3D9 + caps->maxDrawBuffers = 1; + caps->maxColorAttachments = 1; + + // No specific limits on viewport size, maximum 2D texture size is equivalent + caps->maxViewportWidth = caps->max2DTextureSize; + caps->maxViewportHeight = caps->maxViewportWidth; + + // Point size is clamped to 1.0f when the shader model is less than 3 + caps->minAliasedPointSize = 1.0f; + caps->maxAliasedPointSize = ((D3DSHADER_VERSION_MAJOR(deviceCaps.PixelShaderVersion) >= 3) ? deviceCaps.MaxPointSize : 1.0f); + + // Wide lines not supported + caps->minAliasedLineWidth = 1.0f; + caps->maxAliasedLineWidth = 1.0f; + + // Primitive count limits (unused in ES2) + caps->maxElementsIndices = 0; + caps->maxElementsVertices = 0; + + // Program and shader binary formats (no supported shader binary formats) + caps->programBinaryFormats.push_back(GL_PROGRAM_BINARY_ANGLE); + + caps->vertexHighpFloat.setIEEEFloat(); + caps->vertexMediumpFloat.setIEEEFloat(); + caps->vertexLowpFloat.setIEEEFloat(); + caps->fragmentHighpFloat.setIEEEFloat(); + caps->fragmentMediumpFloat.setIEEEFloat(); + caps->fragmentLowpFloat.setIEEEFloat(); + + // Some (most) hardware only supports single-precision floating-point numbers, + // which can accurately represent integers up to +/-16777216 + caps->vertexHighpInt.setSimulatedInt(24); + caps->vertexMediumpInt.setSimulatedInt(24); + caps->vertexLowpInt.setSimulatedInt(24); + caps->fragmentHighpInt.setSimulatedInt(24); + caps->fragmentMediumpInt.setSimulatedInt(24); + caps->fragmentLowpInt.setSimulatedInt(24); + + // WaitSync is ES3-only, set to zero + caps->maxServerWaitTimeout = 0; + + // Vertex shader limits + caps->maxVertexAttributes = 16; + + const size_t reservedVertexUniformVectors = 2; // dx_ViewAdjust and dx_DepthRange. + const size_t MAX_VERTEX_CONSTANT_VECTORS_D3D9 = 256; + caps->maxVertexUniformVectors = MAX_VERTEX_CONSTANT_VECTORS_D3D9 - reservedVertexUniformVectors; + caps->maxVertexUniformComponents = caps->maxVertexUniformVectors * 4; + + caps->maxVertexUniformBlocks = 0; + + // SM3 only supports 11 output variables, with a special 12th register for PSIZE. + const size_t MAX_VERTEX_OUTPUT_VECTORS_SM3 = 9; + const size_t MAX_VERTEX_OUTPUT_VECTORS_SM2 = 7; + caps->maxVertexOutputComponents = ((deviceCaps.VertexShaderVersion >= D3DVS_VERSION(3, 0)) ? MAX_VERTEX_OUTPUT_VECTORS_SM3 + : MAX_VERTEX_OUTPUT_VECTORS_SM2) * 4; + + // Only Direct3D 10 ready devices support all the necessary vertex texture formats. + // We test this using D3D9 by checking support for the R16F format. + if (deviceCaps.VertexShaderVersion >= D3DVS_VERSION(3, 0) && + SUCCEEDED(d3d9->CheckDeviceFormat(adapter, deviceType, currentDisplayMode.Format, + D3DUSAGE_QUERY_VERTEXTEXTURE, D3DRTYPE_TEXTURE, D3DFMT_R16F))) + { + const size_t MAX_TEXTURE_IMAGE_UNITS_VTF_SM3 = 4; + caps->maxVertexTextureImageUnits = MAX_TEXTURE_IMAGE_UNITS_VTF_SM3; + } + else + { + caps->maxVertexTextureImageUnits = 0; + } + + // Fragment shader limits + const size_t reservedPixelUniformVectors = 3; // dx_ViewCoords, dx_DepthFront and dx_DepthRange. + + const size_t MAX_PIXEL_CONSTANT_VECTORS_SM3 = 224; + const size_t MAX_PIXEL_CONSTANT_VECTORS_SM2 = 32; + caps->maxFragmentUniformVectors = ((deviceCaps.PixelShaderVersion >= D3DPS_VERSION(3, 0)) ? MAX_PIXEL_CONSTANT_VECTORS_SM3 + : MAX_PIXEL_CONSTANT_VECTORS_SM2) - reservedPixelUniformVectors; + caps->maxFragmentUniformComponents = caps->maxFragmentUniformVectors * 4; + caps->maxFragmentUniformBlocks = 0; + caps->maxFragmentInputComponents = caps->maxVertexOutputComponents; + caps->maxTextureImageUnits = 16; + caps->minProgramTexelOffset = 0; + caps->maxProgramTexelOffset = 0; + + // Aggregate shader limits (unused in ES2) + caps->maxUniformBufferBindings = 0; + caps->maxUniformBlockSize = 0; + caps->uniformBufferOffsetAlignment = 0; + caps->maxCombinedUniformBlocks = 0; + caps->maxCombinedVertexUniformComponents = 0; + caps->maxCombinedFragmentUniformComponents = 0; + caps->maxVaryingComponents = 0; + + // Aggregate shader limits + caps->maxVaryingVectors = caps->maxVertexOutputComponents / 4; + caps->maxCombinedTextureImageUnits = caps->maxVertexTextureImageUnits + caps->maxTextureImageUnits; + + // Transform feedback limits + caps->maxTransformFeedbackInterleavedComponents = 0; + caps->maxTransformFeedbackSeparateAttributes = 0; + caps->maxTransformFeedbackSeparateComponents = 0; + + // GL extension support + extensions->setTextureExtensionSupport(*textureCapsMap); + extensions->elementIndexUint = deviceCaps.MaxVertexIndex >= (1 << 16); + extensions->packedDepthStencil = true; + extensions->getProgramBinary = true; + extensions->rgb8rgba8 = true; + extensions->readFormatBGRA = true; + extensions->pixelBufferObject = false; + extensions->mapBuffer = false; + extensions->mapBufferRange = false; + + // textureRG is emulated and not performant. + extensions->textureRG = false; + + D3DADAPTER_IDENTIFIER9 adapterId = { 0 }; + if (SUCCEEDED(d3d9->GetAdapterIdentifier(adapter, 0, &adapterId))) + { + // ATI cards on XP have problems with non-power-of-two textures. + extensions->textureNPOT = !(deviceCaps.TextureCaps & D3DPTEXTURECAPS_POW2) && + !(deviceCaps.TextureCaps & D3DPTEXTURECAPS_CUBEMAP_POW2) && + !(deviceCaps.TextureCaps & D3DPTEXTURECAPS_NONPOW2CONDITIONAL) && + !(!isWindowsVistaOrGreater() && adapterId.VendorId == VENDOR_ID_AMD); + + // Disable depth texture support on AMD cards (See ANGLE issue 839) + if (adapterId.VendorId == VENDOR_ID_AMD) + { + extensions->depthTextures = false; + } + } + else + { + extensions->textureNPOT = false; + } + + extensions->drawBuffers = false; + extensions->textureStorage = true; + + // Must support a minimum of 2:1 anisotropy for max anisotropy to be considered supported, per the spec + extensions->textureFilterAnisotropic = (deviceCaps.RasterCaps & D3DPRASTERCAPS_ANISOTROPY) != 0 && deviceCaps.MaxAnisotropy >= 2; + extensions->maxTextureAnisotropy = static_cast(deviceCaps.MaxAnisotropy); + + // Check occlusion query support by trying to create one + IDirect3DQuery9 *occlusionQuery = NULL; + extensions->occlusionQueryBoolean = SUCCEEDED(device->CreateQuery(D3DQUERYTYPE_OCCLUSION, &occlusionQuery)) && occlusionQuery; + SafeRelease(occlusionQuery); + + // Check event query support by trying to create one + IDirect3DQuery9 *eventQuery = NULL; + extensions->fence = SUCCEEDED(device->CreateQuery(D3DQUERYTYPE_EVENT, &eventQuery)) && eventQuery; + SafeRelease(eventQuery); + + extensions->timerQuery = false; // Unimplemented + extensions->robustness = true; + extensions->blendMinMax = true; + extensions->framebufferBlit = true; + extensions->framebufferMultisample = true; + extensions->maxSamples = maxSamples; + extensions->instancedArrays = deviceCaps.PixelShaderVersion >= D3DPS_VERSION(3, 0); + extensions->packReverseRowOrder = true; + extensions->standardDerivatives = (deviceCaps.PS20Caps.Caps & D3DPS20CAPS_GRADIENTINSTRUCTIONS) != 0; + extensions->shaderTextureLOD = true; + extensions->fragDepth = true; + extensions->textureUsage = true; + extensions->translatedShaderSource = true; + extensions->colorBufferFloat = false; +} + +} + +namespace d3d9 +{ + +GLuint ComputeBlockSize(D3DFORMAT format, GLuint width, GLuint height) +{ + const D3DFormat &d3dFormatInfo = d3d9::GetD3DFormatInfo(format); + GLuint numBlocksWide = (width + d3dFormatInfo.blockWidth - 1) / d3dFormatInfo.blockWidth; + GLuint numBlocksHight = (height + d3dFormatInfo.blockHeight - 1) / d3dFormatInfo.blockHeight; + return (d3dFormatInfo.pixelBytes * numBlocksWide * numBlocksHight); +} + +void MakeValidSize(bool isImage, D3DFORMAT format, GLsizei *requestWidth, GLsizei *requestHeight, int *levelOffset) +{ + const D3DFormat &d3dFormatInfo = d3d9::GetD3DFormatInfo(format); + + int upsampleCount = 0; + // Don't expand the size of full textures that are at least (blockWidth x blockHeight) already. + if (isImage || *requestWidth < static_cast(d3dFormatInfo.blockWidth) || + *requestHeight < static_cast(d3dFormatInfo.blockHeight)) + { + while (*requestWidth % d3dFormatInfo.blockWidth != 0 || *requestHeight % d3dFormatInfo.blockHeight != 0) + { + *requestWidth <<= 1; + *requestHeight <<= 1; + upsampleCount++; + } + } + *levelOffset = upsampleCount; +} + +gl::Error GetAttachmentRenderTarget(const gl::FramebufferAttachment *attachment, RenderTarget9 **outRT) +{ + RenderTargetD3D *renderTarget = NULL; + gl::Error error = rx::GetAttachmentRenderTarget(attachment, &renderTarget); + if (error.isError()) + { + return error; + } + *outRT = RenderTarget9::makeRenderTarget9(renderTarget); + return gl::Error(GL_NO_ERROR); +} + +Workarounds GenerateWorkarounds() +{ + Workarounds workarounds; + workarounds.mrtPerfWorkaround = true; + workarounds.setDataFasterThanImageUpload = false; + workarounds.useInstancedPointSpriteEmulation = false; + return workarounds; +} + +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/renderer9_utils.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/renderer9_utils.h new file mode 100644 index 0000000000..3c6a57aee3 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/renderer9_utils.h @@ -0,0 +1,86 @@ +// +// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// renderer9_utils.h: Conversion functions and other utility routines +// specific to the D3D9 renderer + +#ifndef LIBANGLE_RENDERER_D3D_D3D9_RENDERER9UTILS_H_ +#define LIBANGLE_RENDERER_D3D_D3D9_RENDERER9UTILS_H_ + +#include "libANGLE/angletypes.h" +#include "libANGLE/Caps.h" +#include "libANGLE/Error.h" + +namespace gl +{ +class FramebufferAttachment; +} + +namespace rx +{ +class RenderTarget9; +struct Workarounds; + +namespace gl_d3d9 +{ + +D3DCMPFUNC ConvertComparison(GLenum comparison); +D3DCOLOR ConvertColor(gl::ColorF color); +D3DBLEND ConvertBlendFunc(GLenum blend); +D3DBLENDOP ConvertBlendOp(GLenum blendOp); +D3DSTENCILOP ConvertStencilOp(GLenum stencilOp); +D3DTEXTUREADDRESS ConvertTextureWrap(GLenum wrap); +D3DCULL ConvertCullMode(GLenum cullFace, GLenum frontFace); +D3DCUBEMAP_FACES ConvertCubeFace(GLenum cubeFace); +DWORD ConvertColorMask(bool red, bool green, bool blue, bool alpha); +D3DTEXTUREFILTERTYPE ConvertMagFilter(GLenum magFilter, float maxAnisotropy); +void ConvertMinFilter(GLenum minFilter, D3DTEXTUREFILTERTYPE *d3dMinFilter, D3DTEXTUREFILTERTYPE *d3dMipFilter, float maxAnisotropy); + +D3DMULTISAMPLE_TYPE GetMultisampleType(GLuint samples); + +} + +namespace d3d9_gl +{ + +GLsizei GetSamplesCount(D3DMULTISAMPLE_TYPE type); + +bool IsFormatChannelEquivalent(D3DFORMAT d3dformat, GLenum format); + +void GenerateCaps(IDirect3D9 *d3d9, IDirect3DDevice9 *device, D3DDEVTYPE deviceType, UINT adapter, gl::Caps *caps, + gl::TextureCapsMap *textureCapsMap, gl::Extensions *extensions); + +} + +namespace d3d9 +{ + +GLuint ComputeBlockSize(D3DFORMAT format, GLuint width, GLuint height); + +void MakeValidSize(bool isImage, D3DFORMAT format, GLsizei *requestWidth, GLsizei *requestHeight, int *levelOffset); + +inline bool isDeviceLostError(HRESULT errorCode) +{ + switch (errorCode) + { + case D3DERR_DRIVERINTERNALERROR: + case D3DERR_DEVICELOST: + case D3DERR_DEVICEHUNG: + case D3DERR_DEVICEREMOVED: + return true; + default: + return false; + } +} + +gl::Error GetAttachmentRenderTarget(const gl::FramebufferAttachment *attachment, RenderTarget9 **outRT); +Workarounds GenerateWorkarounds(); + +} + +} + +#endif // LIBANGLE_RENDERER_D3D_D3D9_RENDERER9UTILS_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/shaders/Blit.ps b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/shaders/Blit.ps new file mode 100644 index 0000000000..dc357d0fa6 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/shaders/Blit.ps @@ -0,0 +1,33 @@ +// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +sampler2D tex : s0; + +uniform float4 mult : c0; +uniform float4 add : c1; + +// Passthrough Pixel Shader +// Outputs texture 0 sampled at texcoord 0. +float4 passthroughps(float4 texcoord : TEXCOORD0) : COLOR +{ + return tex2D(tex, texcoord.xy); +}; + +// Luminance Conversion Pixel Shader +// Performs a mad operation using the LA data from the texture with mult.xw and add.xw. +// Returns data in the form of llla +float4 luminanceps(float4 texcoord : TEXCOORD0) : COLOR +{ + return (tex2D(tex, texcoord.xy).xw * mult.xw + add.xw).xxxy; +}; + +// RGB/A Component Mask Pixel Shader +// Performs a mad operation using the texture's RGBA data with mult.xyzw and add.xyzw. +// Returns data in the form of rgba +float4 componentmaskps(float4 texcoord : TEXCOORD0) : COLOR +{ + return tex2D(tex, texcoord.xy) * mult + add; +}; diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/shaders/Blit.vs b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/shaders/Blit.vs new file mode 100644 index 0000000000..3a36980b93 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/shaders/Blit.vs @@ -0,0 +1,43 @@ +// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +struct VS_OUTPUT +{ + float4 position : POSITION; + float4 texcoord : TEXCOORD0; +}; + +uniform float4 halfPixelSize : c0; + +// Standard Vertex Shader +// Input 0 is the homogenous position. +// Outputs the homogenous position as-is. +// Outputs a tex coord with (0,0) in the upper-left corner of the screen and (1,1) in the bottom right. +// C0.X must be negative half-pixel width, C0.Y must be half-pixel height. C0.ZW must be 0. +VS_OUTPUT standardvs(in float4 position : POSITION) +{ + VS_OUTPUT Out; + + Out.position = position + halfPixelSize; + Out.texcoord = position * float4(0.5, -0.5, 1.0, 1.0) + float4(0.5, 0.5, 0, 0); + + return Out; +}; + +// Flip Y Vertex Shader +// Input 0 is the homogenous position. +// Outputs the homogenous position as-is. +// Outputs a tex coord with (0,1) in the upper-left corner of the screen and (1,0) in the bottom right. +// C0.XY must be the half-pixel width and height. C0.ZW must be 0. +VS_OUTPUT flipyvs(in float4 position : POSITION) +{ + VS_OUTPUT Out; + + Out.position = position + halfPixelSize; + Out.texcoord = position * float4(0.5, 0.5, 1.0, 1.0) + float4(0.5, 0.5, 0, 0); + + return Out; +}; diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/vertexconversion.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/vertexconversion.h new file mode 100644 index 0000000000..32eb376a78 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/vertexconversion.h @@ -0,0 +1,197 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// vertexconversion.h: A library of vertex conversion classes that can be used to build +// the FormatConverter objects used by the buffer conversion system. + +#ifndef LIBANGLE_RENDERER_D3D_D3D9_VERTEXCONVERSION_H_ +#define LIBANGLE_RENDERER_D3D_D3D9_VERTEXCONVERSION_H_ + +#include +#include +#include + +namespace rx +{ + +// Conversion types: +// static const bool identity: true if this is an identity transform, false otherwise +// static U convert(T): convert a single element from the input type to the output type +// typedef ... OutputType: the type produced by this conversion + +template +struct Identity +{ + static const bool identity = true; + + typedef T OutputType; + + static T convert(T x) + { + return x; + } +}; + +template +struct Cast +{ + static const bool identity = false; + + typedef ToT OutputType; + + static ToT convert(FromT x) + { + return static_cast(x); + } +}; + +template +struct Cast +{ + static const bool identity = true; + + typedef T OutputType; + + static T convert(T x) + { + return static_cast(x); + } +}; + +template +struct Normalize +{ + static const bool identity = false; + + typedef float OutputType; + + static float convert(T x) + { + typedef std::numeric_limits NL; + float f = static_cast(x); + + if (NL::is_signed) + { + // const float => VC2008 computes it at compile time + // static const float => VC2008 computes it the first time we get here, stores it to memory with static guard and all that. + const float divisor = 1.0f/(2*static_cast(NL::max())+1); + return (2*f+1)*divisor; + } + else + { + return f/NL::max(); + } + } +}; + +template +struct FixedToFloat +{ + static const bool identity = false; + + typedef float OutputType; + + static float convert(FromType x) + { + const float divisor = 1.0f / static_cast(static_cast(1) << ScaleBits); + return static_cast(x) * divisor; + } +}; + +// Widen types: +// static const unsigned int initialWidth: number of components before conversion +// static const unsigned int finalWidth: number of components after conversion + +// Float is supported at any size. +template +struct NoWiden +{ + static const std::size_t initialWidth = N; + static const std::size_t finalWidth = N; +}; + +// SHORT, norm-SHORT, norm-UNSIGNED_SHORT are supported but only with 2 or 4 components +template +struct WidenToEven +{ + static const std::size_t initialWidth = N; + static const std::size_t finalWidth = N+(N&1); +}; + +template +struct WidenToFour +{ + static const std::size_t initialWidth = N; + static const std::size_t finalWidth = 4; +}; + +// Most types have 0 and 1 that are just that. +template +struct SimpleDefaultValues +{ + static T zero() { return static_cast(0); } + static T one() { return static_cast(1); } +}; + +// But normalised types only store [0,1] or [-1,1] so 1.0 is represented by the max value. +template +struct NormalizedDefaultValues +{ + static T zero() { return static_cast(0); } + static T one() { return std::numeric_limits::max(); } +}; + +// Converter: +// static const bool identity: true if this is an identity transform (with no widening) +// static const std::size_t finalSize: number of bytes per output vertex +// static void convertArray(const void *in, std::size_t stride, std::size_t n, void *out): convert an array of vertices. Input may be strided, but output will be unstrided. + +template > +struct VertexDataConverter +{ + typedef typename Converter::OutputType OutputType; + typedef InT InputType; + + static const bool identity = (WidenRule::initialWidth == WidenRule::finalWidth) && Converter::identity; + static const std::size_t finalSize = WidenRule::finalWidth * sizeof(OutputType); + + static void convertArray(const uint8_t *input, size_t stride, size_t n, uint8_t *output) + { + OutputType *out = reinterpret_cast(output); + + for (std::size_t i = 0; i < n; i++) + { + const InputType *ein = reinterpret_cast(input + i * stride); + + copyComponent(out, ein, 0, static_cast(DefaultValueRule::zero())); + copyComponent(out, ein, 1, static_cast(DefaultValueRule::zero())); + copyComponent(out, ein, 2, static_cast(DefaultValueRule::zero())); + copyComponent(out, ein, 3, static_cast(DefaultValueRule::one())); + + out += WidenRule::finalWidth; + } + } + + private: + static void copyComponent(OutputType *out, const InputType *in, std::size_t elementindex, OutputType defaultvalue) + { + if (WidenRule::finalWidth > elementindex) + { + if (WidenRule::initialWidth > elementindex) + { + out[elementindex] = Converter::convert(in[elementindex]); + } + else + { + out[elementindex] = defaultvalue; + } + } + } +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_D3D9_VERTEXCONVERSION_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/formatutilsD3D.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/formatutilsD3D.cpp new file mode 100644 index 0000000000..8a4d41cbd9 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/formatutilsD3D.cpp @@ -0,0 +1,147 @@ +// +// Copyright (c) 2015 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// formatutils9.cpp: Queries for GL image formats and their translations to D3D +// formats. + +#include "libANGLE/renderer/d3d/formatutilsD3D.h" + +#include + +#include "common/debug.h" +#include "libANGLE/renderer/d3d/imageformats.h" +#include "libANGLE/renderer/d3d/copyimage.h" + +namespace rx +{ + +typedef std::pair FormatTypePair; +typedef std::pair FormatWriteFunctionPair; +typedef std::map FormatWriteFunctionMap; + +static inline void InsertFormatWriteFunctionMapping(FormatWriteFunctionMap *map, GLenum format, GLenum type, + ColorWriteFunction writeFunc) +{ + map->insert(FormatWriteFunctionPair(FormatTypePair(format, type), writeFunc)); +} + +static FormatWriteFunctionMap BuildFormatWriteFunctionMap() +{ + FormatWriteFunctionMap map; + + // | Format | Type | Color write function | + InsertFormatWriteFunctionMapping(&map, GL_RGBA, GL_UNSIGNED_BYTE, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RGBA, GL_BYTE, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RGBA, GL_FLOAT, WriteColor); + InsertFormatWriteFunctionMapping(&map, GL_RGBA, GL_HALF_FLOAT, WriteColor); + InsertFormatWriteFunctionMapping(&map, GL_RGBA, GL_HALF_FLOAT_OES, WriteColor); + + InsertFormatWriteFunctionMapping(&map, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RGBA_INTEGER, GL_BYTE, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RGBA_INTEGER, GL_UNSIGNED_SHORT, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RGBA_INTEGER, GL_SHORT, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RGBA_INTEGER, GL_UNSIGNED_INT, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RGBA_INTEGER, GL_INT, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RGBA_INTEGER, GL_UNSIGNED_INT_2_10_10_10_REV, WriteColor ); + + InsertFormatWriteFunctionMapping(&map, GL_RGB, GL_UNSIGNED_BYTE, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RGB, GL_BYTE, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RGB, GL_UNSIGNED_INT_10F_11F_11F_REV, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RGB, GL_UNSIGNED_INT_5_9_9_9_REV, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RGB, GL_FLOAT, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RGB, GL_HALF_FLOAT, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RGB, GL_HALF_FLOAT_OES, WriteColor ); + + InsertFormatWriteFunctionMapping(&map, GL_RGB_INTEGER, GL_UNSIGNED_BYTE, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RGB_INTEGER, GL_BYTE, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RGB_INTEGER, GL_UNSIGNED_SHORT, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RGB_INTEGER, GL_SHORT, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RGB_INTEGER, GL_UNSIGNED_INT, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RGB_INTEGER, GL_INT, WriteColor ); + + InsertFormatWriteFunctionMapping(&map, GL_RG, GL_UNSIGNED_BYTE, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RG, GL_BYTE, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RG, GL_FLOAT, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RG, GL_HALF_FLOAT, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RG, GL_HALF_FLOAT_OES, WriteColor ); + + InsertFormatWriteFunctionMapping(&map, GL_RG_INTEGER, GL_UNSIGNED_BYTE, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RG_INTEGER, GL_BYTE, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RG_INTEGER, GL_UNSIGNED_SHORT, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RG_INTEGER, GL_SHORT, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RG_INTEGER, GL_UNSIGNED_INT, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RG_INTEGER, GL_INT, WriteColor ); + + InsertFormatWriteFunctionMapping(&map, GL_RED, GL_UNSIGNED_BYTE, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RED, GL_BYTE, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RED, GL_FLOAT, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RED, GL_HALF_FLOAT, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RED, GL_HALF_FLOAT_OES, WriteColor ); + + InsertFormatWriteFunctionMapping(&map, GL_RED_INTEGER, GL_UNSIGNED_BYTE, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RED_INTEGER, GL_BYTE, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RED_INTEGER, GL_UNSIGNED_SHORT, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RED_INTEGER, GL_SHORT, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RED_INTEGER, GL_UNSIGNED_INT, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RED_INTEGER, GL_INT, WriteColor ); + + InsertFormatWriteFunctionMapping(&map, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_LUMINANCE, GL_UNSIGNED_BYTE, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_ALPHA, GL_UNSIGNED_BYTE, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_LUMINANCE_ALPHA, GL_FLOAT, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_LUMINANCE, GL_FLOAT, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_ALPHA, GL_FLOAT, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_LUMINANCE_ALPHA, GL_HALF_FLOAT, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_LUMINANCE_ALPHA, GL_HALF_FLOAT_OES, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_LUMINANCE, GL_HALF_FLOAT, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_LUMINANCE, GL_HALF_FLOAT_OES, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_ALPHA, GL_HALF_FLOAT, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_ALPHA, GL_HALF_FLOAT_OES, WriteColor ); + + InsertFormatWriteFunctionMapping(&map, GL_BGRA_EXT, GL_UNSIGNED_BYTE, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_BGRA_EXT, GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_BGRA_EXT, GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT, WriteColor ); + + InsertFormatWriteFunctionMapping(&map, GL_SRGB_EXT, GL_UNSIGNED_BYTE, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_SRGB_ALPHA_EXT, GL_UNSIGNED_BYTE, WriteColor ); + + InsertFormatWriteFunctionMapping(&map, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_UNSIGNED_BYTE, NULL ); + InsertFormatWriteFunctionMapping(&map, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, GL_UNSIGNED_BYTE, NULL ); + InsertFormatWriteFunctionMapping(&map, GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE, GL_UNSIGNED_BYTE, NULL ); + InsertFormatWriteFunctionMapping(&map, GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE, GL_UNSIGNED_BYTE, NULL ); + + InsertFormatWriteFunctionMapping(&map, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, NULL ); + InsertFormatWriteFunctionMapping(&map, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL ); + InsertFormatWriteFunctionMapping(&map, GL_DEPTH_COMPONENT, GL_FLOAT, NULL ); + + InsertFormatWriteFunctionMapping(&map, GL_STENCIL, GL_UNSIGNED_BYTE, NULL ); + + InsertFormatWriteFunctionMapping(&map, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, NULL ); + InsertFormatWriteFunctionMapping(&map, GL_DEPTH_STENCIL, GL_FLOAT_32_UNSIGNED_INT_24_8_REV, NULL ); + + return map; +} + +ColorWriteFunction GetColorWriteFunction(GLenum format, GLenum type) +{ + static const FormatWriteFunctionMap formatTypeMap = BuildFormatWriteFunctionMap(); + FormatWriteFunctionMap::const_iterator iter = formatTypeMap.find(FormatTypePair(format, type)); + ASSERT(iter != formatTypeMap.end()); + if (iter != formatTypeMap.end()) + { + return iter->second; + } + else + { + return NULL; + } +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/formatutilsD3D.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/formatutilsD3D.h new file mode 100644 index 0000000000..6dd59ca94b --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/formatutilsD3D.h @@ -0,0 +1,50 @@ +// +// Copyright (c) 2015 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// formatutils9.h: Queries for GL image formats and their translations to D3D +// formats. + +#ifndef LIBANGLE_RENDERER_D3D_FORMATUTILSD3D_H_ +#define LIBANGLE_RENDERER_D3D_FORMATUTILSD3D_H_ + +#include "angle_gl.h" + +#include +#include + +namespace rx +{ + +typedef void (*MipGenerationFunction)(size_t sourceWidth, size_t sourceHeight, size_t sourceDepth, + const uint8_t *sourceData, size_t sourceRowPitch, size_t sourceDepthPitch, + uint8_t *destData, size_t destRowPitch, size_t destDepthPitch); + +typedef void (*LoadImageFunction)(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +typedef void (*InitializeTextureDataFunction)(size_t width, size_t height, size_t depth, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +typedef void (*ColorReadFunction)(const uint8_t *source, uint8_t *dest); +typedef void (*ColorWriteFunction)(const uint8_t *source, uint8_t *dest); +typedef void (*ColorCopyFunction)(const uint8_t *source, uint8_t *dest); + +typedef void (*VertexCopyFunction)(const uint8_t *input, size_t stride, size_t count, uint8_t *output); + +enum VertexConversionType +{ + VERTEX_CONVERT_NONE = 0, + VERTEX_CONVERT_CPU = 1, + VERTEX_CONVERT_GPU = 2, + VERTEX_CONVERT_BOTH = 3 +}; + +ColorWriteFunction GetColorWriteFunction(GLenum format, GLenum type); + +} + +#endif // LIBANGLE_RENDERER_D3D_FORMATUTILSD3D_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/generatemip.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/generatemip.h new file mode 100644 index 0000000000..398ef26b30 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/generatemip.h @@ -0,0 +1,28 @@ +// +// Copyright (c) 2002-2015 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// generatemip.h: Defines the GenerateMip function, templated on the format +// type of the image for which mip levels are being generated. + +#ifndef LIBANGLE_RENDERER_D3D_GENERATEMIP_H_ +#define LIBANGLE_RENDERER_D3D_GENERATEMIP_H_ + +#include "libANGLE/renderer/d3d/imageformats.h" +#include "libANGLE/angletypes.h" + +namespace rx +{ + +template +inline void GenerateMip(size_t sourceWidth, size_t sourceHeight, size_t sourceDepth, + const uint8_t *sourceData, size_t sourceRowPitch, size_t sourceDepthPitch, + uint8_t *destData, size_t destRowPitch, size_t destDepthPitch); + +} + +#include "generatemip.inl" + +#endif // LIBANGLE_RENDERER_D3D_GENERATEMIP_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/generatemip.inl b/src/3rdparty/angle/src/libANGLE/renderer/d3d/generatemip.inl new file mode 100644 index 0000000000..265783641e --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/generatemip.inl @@ -0,0 +1,266 @@ +// +// Copyright (c) 2015 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// generatemip.inl: Defines the GenerateMip function, templated on the format +// type of the image for which mip levels are being generated. + +#include "common/mathutil.h" + +namespace rx +{ + +namespace priv +{ + +template +static inline T *GetPixel(uint8_t *data, size_t x, size_t y, size_t z, size_t rowPitch, size_t depthPitch) +{ + return reinterpret_cast(data + (x * sizeof(T)) + (y * rowPitch) + (z * depthPitch)); +} + +template +static inline const T *GetPixel(const uint8_t *data, size_t x, size_t y, size_t z, size_t rowPitch, size_t depthPitch) +{ + return reinterpret_cast(data + (x * sizeof(T)) + (y * rowPitch) + (z * depthPitch)); +} + +template +static void GenerateMip_Y(size_t sourceWidth, size_t sourceHeight, size_t sourceDepth, + const uint8_t *sourceData, size_t sourceRowPitch, size_t sourceDepthPitch, + size_t destWidth, size_t destHeight, size_t destDepth, + uint8_t *destData, size_t destRowPitch, size_t destDepthPitch) +{ + ASSERT(sourceWidth == 1); + ASSERT(sourceHeight > 1); + ASSERT(sourceDepth == 1); + + for (size_t y = 0; y < destHeight; y++) + { + const T *src0 = GetPixel(sourceData, 0, y * 2, 0, sourceRowPitch, sourceDepthPitch); + const T *src1 = GetPixel(sourceData, 0, y * 2 + 1, 0, sourceRowPitch, sourceDepthPitch); + T *dst = GetPixel(destData, 0, y, 0, destRowPitch, destDepthPitch); + + T::average(dst, src0, src1); + } +} + +template +static void GenerateMip_X(size_t sourceWidth, size_t sourceHeight, size_t sourceDepth, + const uint8_t *sourceData, size_t sourceRowPitch, size_t sourceDepthPitch, + size_t destWidth, size_t destHeight, size_t destDepth, + uint8_t *destData, size_t destRowPitch, size_t destDepthPitch) +{ + ASSERT(sourceWidth > 1); + ASSERT(sourceHeight == 1); + ASSERT(sourceDepth == 1); + + for (size_t x = 0; x < destWidth; x++) + { + const T *src0 = GetPixel(sourceData, x * 2, 0, 0, sourceRowPitch, sourceDepthPitch); + const T *src1 = GetPixel(sourceData, x * 2 + 1, 0, 0, sourceRowPitch, sourceDepthPitch); + T *dst = GetPixel(destData, x, 0, 0, destRowPitch, destDepthPitch); + + T::average(dst, src0, src1); + } +} + +template +static void GenerateMip_Z(size_t sourceWidth, size_t sourceHeight, size_t sourceDepth, + const uint8_t *sourceData, size_t sourceRowPitch, size_t sourceDepthPitch, + size_t destWidth, size_t destHeight, size_t destDepth, + uint8_t *destData, size_t destRowPitch, size_t destDepthPitch) +{ + ASSERT(sourceWidth == 1); + ASSERT(sourceHeight == 1); + ASSERT(sourceDepth > 1); + + for (size_t z = 0; z < destDepth; z++) + { + const T *src0 = GetPixel(sourceData, 0, 0, z * 2, sourceRowPitch, sourceDepthPitch); + const T *src1 = GetPixel(sourceData, 0, 0, z * 2 + 1, sourceRowPitch, sourceDepthPitch); + T *dst = GetPixel(destData, 0, 0, z, destRowPitch, destDepthPitch); + + T::average(dst, src0, src1); + } +} + +template +static void GenerateMip_XY(size_t sourceWidth, size_t sourceHeight, size_t sourceDepth, + const uint8_t *sourceData, size_t sourceRowPitch, size_t sourceDepthPitch, + size_t destWidth, size_t destHeight, size_t destDepth, + uint8_t *destData, size_t destRowPitch, size_t destDepthPitch) +{ + ASSERT(sourceWidth > 1); + ASSERT(sourceHeight > 1); + ASSERT(sourceDepth == 1); + + for (size_t y = 0; y < destHeight; y++) + { + for (size_t x = 0; x < destWidth; x++) + { + const T *src0 = GetPixel(sourceData, x * 2, y * 2, 0, sourceRowPitch, sourceDepthPitch); + const T *src1 = GetPixel(sourceData, x * 2, y * 2 + 1, 0, sourceRowPitch, sourceDepthPitch); + const T *src2 = GetPixel(sourceData, x * 2 + 1, y * 2, 0, sourceRowPitch, sourceDepthPitch); + const T *src3 = GetPixel(sourceData, x * 2 + 1, y * 2 + 1, 0, sourceRowPitch, sourceDepthPitch); + T *dst = GetPixel(destData, x, y, 0, destRowPitch, destDepthPitch); + + T tmp0, tmp1; + + T::average(&tmp0, src0, src1); + T::average(&tmp1, src2, src3); + T::average(dst, &tmp0, &tmp1); + } + } +} + +template +static void GenerateMip_YZ(size_t sourceWidth, size_t sourceHeight, size_t sourceDepth, + const uint8_t *sourceData, size_t sourceRowPitch, size_t sourceDepthPitch, + size_t destWidth, size_t destHeight, size_t destDepth, + uint8_t *destData, size_t destRowPitch, size_t destDepthPitch) +{ + ASSERT(sourceWidth == 1); + ASSERT(sourceHeight > 1); + ASSERT(sourceDepth > 1); + + for (size_t z = 0; z < destDepth; z++) + { + for (size_t y = 0; y < destHeight; y++) + { + const T *src0 = GetPixel(sourceData, 0, y * 2, z * 2, sourceRowPitch, sourceDepthPitch); + const T *src1 = GetPixel(sourceData, 0, y * 2, z * 2 + 1, sourceRowPitch, sourceDepthPitch); + const T *src2 = GetPixel(sourceData, 0, y * 2 + 1, z * 2, sourceRowPitch, sourceDepthPitch); + const T *src3 = GetPixel(sourceData, 0, y * 2 + 1, z * 2 + 1, sourceRowPitch, sourceDepthPitch); + T *dst = GetPixel(destData, 0, y, z, destRowPitch, destDepthPitch); + + T tmp0, tmp1; + + T::average(&tmp0, src0, src1); + T::average(&tmp1, src2, src3); + T::average(dst, &tmp0, &tmp1); + } + } +} + +template +static void GenerateMip_XZ(size_t sourceWidth, size_t sourceHeight, size_t sourceDepth, + const uint8_t *sourceData, size_t sourceRowPitch, size_t sourceDepthPitch, + size_t destWidth, size_t destHeight, size_t destDepth, + uint8_t *destData, size_t destRowPitch, size_t destDepthPitch) +{ + ASSERT(sourceWidth > 1); + ASSERT(sourceHeight == 1); + ASSERT(sourceDepth > 1); + + for (size_t z = 0; z < destDepth; z++) + { + for (size_t x = 0; x < destWidth; x++) + { + const T *src0 = GetPixel(sourceData, x * 2, 0, z * 2, sourceRowPitch, sourceDepthPitch); + const T *src1 = GetPixel(sourceData, x * 2, 0, z * 2 + 1, sourceRowPitch, sourceDepthPitch); + const T *src2 = GetPixel(sourceData, x * 2 + 1, 0, z * 2, sourceRowPitch, sourceDepthPitch); + const T *src3 = GetPixel(sourceData, x * 2 + 1, 0, z * 2 + 1, sourceRowPitch, sourceDepthPitch); + T *dst = GetPixel(destData, x, 0, z, destRowPitch, destDepthPitch); + + T tmp0, tmp1; + + T::average(&tmp0, src0, src1); + T::average(&tmp1, src2, src3); + T::average(dst, &tmp0, &tmp1); + } + } +} + +template +static void GenerateMip_XYZ(size_t sourceWidth, size_t sourceHeight, size_t sourceDepth, + const uint8_t *sourceData, size_t sourceRowPitch, size_t sourceDepthPitch, + size_t destWidth, size_t destHeight, size_t destDepth, + uint8_t *destData, size_t destRowPitch, size_t destDepthPitch) +{ + ASSERT(sourceWidth > 1); + ASSERT(sourceHeight > 1); + ASSERT(sourceDepth > 1); + + for (size_t z = 0; z < destDepth; z++) + { + for (size_t y = 0; y < destHeight; y++) + { + for (size_t x = 0; x < destWidth; x++) + { + const T *src0 = GetPixel(sourceData, x * 2, y * 2, z * 2, sourceRowPitch, sourceDepthPitch); + const T *src1 = GetPixel(sourceData, x * 2, y * 2, z * 2 + 1, sourceRowPitch, sourceDepthPitch); + const T *src2 = GetPixel(sourceData, x * 2, y * 2 + 1, z * 2, sourceRowPitch, sourceDepthPitch); + const T *src3 = GetPixel(sourceData, x * 2, y * 2 + 1, z * 2 + 1, sourceRowPitch, sourceDepthPitch); + const T *src4 = GetPixel(sourceData, x * 2 + 1, y * 2, z * 2, sourceRowPitch, sourceDepthPitch); + const T *src5 = GetPixel(sourceData, x * 2 + 1, y * 2, z * 2 + 1, sourceRowPitch, sourceDepthPitch); + const T *src6 = GetPixel(sourceData, x * 2 + 1, y * 2 + 1, z * 2, sourceRowPitch, sourceDepthPitch); + const T *src7 = GetPixel(sourceData, x * 2 + 1, y * 2 + 1, z * 2 + 1, sourceRowPitch, sourceDepthPitch); + T *dst = GetPixel(destData, x, y, z, destRowPitch, destDepthPitch); + + T tmp0, tmp1, tmp2, tmp3, tmp4, tmp5; + + T::average(&tmp0, src0, src1); + T::average(&tmp1, src2, src3); + T::average(&tmp2, src4, src5); + T::average(&tmp3, src6, src7); + + T::average(&tmp4, &tmp0, &tmp1); + T::average(&tmp5, &tmp2, &tmp3); + + T::average(dst, &tmp4, &tmp5); + } + } + } +} + + +typedef void (*MipGenerationFunction)(size_t sourceWidth, size_t sourceHeight, size_t sourceDepth, + const uint8_t *sourceData, size_t sourceRowPitch, size_t sourceDepthPitch, + size_t destWidth, size_t destHeight, size_t destDepth, + uint8_t *destData, size_t destRowPitch, size_t destDepthPitch); + +template +static MipGenerationFunction GetMipGenerationFunction(size_t sourceWidth, size_t sourceHeight, size_t sourceDepth) +{ + uint8_t index = ((sourceWidth > 1) ? 1 : 0) | + ((sourceHeight > 1) ? 2 : 0) | + ((sourceDepth > 1) ? 4 : 0); + + switch (index) + { + case 0: return NULL; + case 1: return GenerateMip_X; // W x 1 x 1 + case 2: return GenerateMip_Y; // 1 x H x 1 + case 3: return GenerateMip_XY; // W x H x 1 + case 4: return GenerateMip_Z; // 1 x 1 x D + case 5: return GenerateMip_XZ; // W x 1 x D + case 6: return GenerateMip_YZ; // 1 x H x D + case 7: return GenerateMip_XYZ; // W x H x D + } + + UNREACHABLE(); + return NULL; +} + +} + +template +inline void GenerateMip(size_t sourceWidth, size_t sourceHeight, size_t sourceDepth, + const uint8_t *sourceData, size_t sourceRowPitch, size_t sourceDepthPitch, + uint8_t *destData, size_t destRowPitch, size_t destDepthPitch) +{ + size_t mipWidth = std::max(1, sourceWidth >> 1); + size_t mipHeight = std::max(1, sourceHeight >> 1); + size_t mipDepth = std::max(1, sourceDepth >> 1); + + priv::MipGenerationFunction generationFunction = priv::GetMipGenerationFunction(sourceWidth, sourceHeight, sourceDepth); + ASSERT(generationFunction != NULL); + + generationFunction(sourceWidth, sourceHeight, sourceDepth, sourceData, sourceRowPitch, sourceDepthPitch, + mipWidth, mipHeight, mipDepth, destData, destRowPitch, destDepthPitch); +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/imageformats.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/imageformats.h new file mode 100644 index 0000000000..e0f9a16c1a --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/imageformats.h @@ -0,0 +1,2031 @@ +// +// Copyright (c) 2013-2015 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// imageformats.h: Defines image format types with functions for mip generation +// and copying. + +#ifndef LIBANGLE_RENDERER_D3D_IMAGEFORMATS_H_ +#define LIBANGLE_RENDERER_D3D_IMAGEFORMATS_H_ + +#include "libANGLE/angletypes.h" + +#include "common/mathutil.h" + +namespace rx +{ + +// Several structures share functionality for reading, writing or mipmapping but the layout +// must match the texture format which the structure represents. If collapsing or typedefing +// structs in this header, make sure the functionality and memory layout is exactly the same. + +struct L8 +{ + unsigned char L; + + static void readColor(gl::ColorF *dst, const L8 *src) + { + const float lum = gl::normalizedToFloat(src->L); + dst->red = lum; + dst->green = lum; + dst->blue = lum; + dst->alpha = 1.0f; + } + + static void writeColor(L8 *dst, const gl::ColorF *src) + { + dst->L = gl::floatToNormalized((src->red + src->green + src->blue) / 3.0f); + } + + static void average(L8 *dst, const L8 *src1, const L8 *src2) + { + dst->L = gl::average(src1->L, src2->L); + } +}; + +struct R8 +{ + unsigned char R; + + static void readColor(gl::ColorF *dst, const R8 *src) + { + dst->red = gl::normalizedToFloat(src->R); + dst->green = 0.0f; + dst->blue = 0.0f; + dst->alpha = 1.0f; + } + + static void readColor(gl::ColorUI *dst, const R8 *src) + { + dst->red = src->R; + dst->green = 0; + dst->blue = 0; + dst->alpha = 1; + } + + static void writeColor(R8 *dst, const gl::ColorF *src) + { + dst->R = gl::floatToNormalized(src->red); + } + + static void writeColor(R8 *dst, const gl::ColorUI *src) + { + dst->R = static_cast(src->red); + } + + static void average(R8 *dst, const R8 *src1, const R8 *src2) + { + dst->R = gl::average(src1->R, src2->R); + } +}; + +struct A8 +{ + unsigned char A; + + static void readColor(gl::ColorF *dst, const A8 *src) + { + dst->red = 0.0f; + dst->green = 0.0f; + dst->blue = 0.0f; + dst->alpha = gl::normalizedToFloat(src->A); + } + + static void writeColor(A8 *dst, const gl::ColorF *src) + { + dst->A = gl::floatToNormalized(src->alpha); + } + + static void average(A8 *dst, const A8 *src1, const A8 *src2) + { + dst->A = gl::average(src1->A, src2->A); + } +}; + +struct L8A8 +{ + unsigned char L; + unsigned char A; + + static void readColor(gl::ColorF *dst, const L8A8 *src) + { + const float lum = gl::normalizedToFloat(src->L); + dst->red = lum; + dst->green = lum; + dst->blue = lum; + dst->alpha = gl::normalizedToFloat(src->A); + } + + static void writeColor(L8A8 *dst, const gl::ColorF *src) + { + dst->L = gl::floatToNormalized((src->red + src->green + src->blue) / 3.0f); + dst->A = gl::floatToNormalized(src->alpha); + } + + static void average(L8A8 *dst, const L8A8 *src1, const L8A8 *src2) + { + *(unsigned short*)dst = (((*(unsigned short*)src1 ^ *(unsigned short*)src2) & 0xFEFE) >> 1) + (*(unsigned short*)src1 & *(unsigned short*)src2); + } +}; + +struct A8L8 +{ + unsigned char A; + unsigned char L; + + static void readColor(gl::ColorF *dst, const A8L8 *src) + { + const float lum = gl::normalizedToFloat(src->L); + dst->red = lum; + dst->green = lum; + dst->blue = lum; + dst->alpha = gl::normalizedToFloat(src->A); + } + + static void writeColor(A8L8 *dst, const gl::ColorF *src) + { + dst->L = gl::floatToNormalized((src->red + src->green + src->blue) / 3.0f); + dst->A = gl::floatToNormalized(src->alpha); + } + + static void average(A8L8 *dst, const A8L8 *src1, const A8L8 *src2) + { + *(unsigned short*)dst = (((*(unsigned short*)src1 ^ *(unsigned short*)src2) & 0xFEFE) >> 1) + (*(unsigned short*)src1 & *(unsigned short*)src2); + } +}; + +struct R8G8 +{ + unsigned char R; + unsigned char G; + + static void readColor(gl::ColorF *dst, const R8G8 *src) + { + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = 0.0f; + dst->alpha = 1.0f; + } + + static void readColor(gl::ColorUI *dst, const R8G8 *src) + { + dst->red = src->R; + dst->green = src->G; + dst->blue = 0; + dst->alpha = 1; + } + + static void writeColor(R8G8 *dst, const gl::ColorF *src) + { + dst->R = gl::floatToNormalized(src->red); + dst->G = gl::floatToNormalized(src->green); + } + + static void writeColor(R8G8 *dst, const gl::ColorUI *src) + { + dst->R = static_cast(src->red); + dst->G = static_cast(src->green); + } + + static void average(R8G8 *dst, const R8G8 *src1, const R8G8 *src2) + { + *(unsigned short*)dst = (((*(unsigned short*)src1 ^ *(unsigned short*)src2) & 0xFEFE) >> 1) + (*(unsigned short*)src1 & *(unsigned short*)src2); + } +}; + +struct R8G8B8 +{ + unsigned char R; + unsigned char G; + unsigned char B; + + static void readColor(gl::ColorF *dst, const R8G8B8 *src) + { + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = gl::normalizedToFloat(src->B); + dst->alpha = 1.0f; + } + + static void readColor(gl::ColorUI *dst, const R8G8B8 *src) + { + dst->red = src->R; + dst->green = src->G; + dst->blue = src->G; + dst->alpha = 1; + } + + static void writeColor(R8G8B8 *dst, const gl::ColorF *src) + { + dst->R = gl::floatToNormalized(src->red); + dst->G = gl::floatToNormalized(src->green); + dst->B = gl::floatToNormalized(src->blue); + } + + static void writeColor(R8G8B8 *dst, const gl::ColorUI *src) + { + dst->R = static_cast(src->red); + dst->G = static_cast(src->green); + dst->B = static_cast(src->blue); + } + + static void average(R8G8B8 *dst, const R8G8B8 *src1, const R8G8B8 *src2) + { + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); + dst->B = gl::average(src1->B, src2->B); + } +}; + +struct B8G8R8 +{ + unsigned char B; + unsigned char G; + unsigned char R; + + static void readColor(gl::ColorF *dst, const B8G8R8 *src) + { + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = gl::normalizedToFloat(src->B); + dst->alpha = 1.0f; + } + + static void readColor(gl::ColorUI *dst, const B8G8R8 *src) + { + dst->red = src->R; + dst->green = src->G; + dst->blue = src->G; + dst->alpha = 1; + } + + static void writeColor(B8G8R8 *dst, const gl::ColorF *src) + { + dst->R = gl::floatToNormalized(src->red); + dst->G = gl::floatToNormalized(src->green); + dst->B = gl::floatToNormalized(src->blue); + } + + static void writeColor(B8G8R8 *dst, const gl::ColorUI *src) + { + dst->R = static_cast(src->red); + dst->G = static_cast(src->green); + dst->B = static_cast(src->blue); + } + + static void average(B8G8R8 *dst, const B8G8R8 *src1, const B8G8R8 *src2) + { + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); + dst->B = gl::average(src1->B, src2->B); + } +}; + +struct R5G6B5 +{ + unsigned short RGB; + + static void readColor(gl::ColorF *dst, const R5G6B5 *src) + { + dst->red = gl::normalizedToFloat<5>(gl::getShiftedData<5, 11>(src->RGB)); + dst->green = gl::normalizedToFloat<6>(gl::getShiftedData<6, 5>(src->RGB)); + dst->blue = gl::normalizedToFloat<5>(gl::getShiftedData<5, 0>(src->RGB)); + dst->alpha = 1.0f; + } + + static void writeColor(R5G6B5 *dst, const gl::ColorF *src) + { + dst->RGB = gl::shiftData<5, 11>(gl::floatToNormalized<5, unsigned short>(src->red)) | + gl::shiftData<6, 5>(gl::floatToNormalized<6, unsigned short>(src->green)) | + gl::shiftData<5, 0>(gl::floatToNormalized<5, unsigned short>(src->blue)); + } + + static void average(R5G6B5 *dst, const R5G6B5 *src1, const R5G6B5 *src2) + { + dst->RGB = gl::shiftData<5, 11>(gl::average(gl::getShiftedData<5, 11>(src1->RGB), gl::getShiftedData<5, 11>(src2->RGB))) | + gl::shiftData<6, 5>(gl::average(gl::getShiftedData<6, 5>(src1->RGB), gl::getShiftedData<6, 5>(src2->RGB))) | + gl::shiftData<5, 0>(gl::average(gl::getShiftedData<5, 0>(src1->RGB), gl::getShiftedData<5, 0>(src2->RGB))); + } +}; + +struct A8R8G8B8 +{ + unsigned char A; + unsigned char R; + unsigned char G; + unsigned char B; + + static void readColor(gl::ColorF *dst, const A8R8G8B8 *src) + { + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = gl::normalizedToFloat(src->B); + dst->alpha = gl::normalizedToFloat(src->A); + } + + static void readColor(gl::ColorUI *dst, const A8R8G8B8 *src) + { + dst->red = src->R; + dst->green = src->G; + dst->blue = src->B; + dst->alpha = src->A; + } + + static void writeColor(A8R8G8B8 *dst, const gl::ColorF *src) + { + dst->R = gl::floatToNormalized(src->red); + dst->G = gl::floatToNormalized(src->green); + dst->B = gl::floatToNormalized(src->blue); + dst->A = gl::floatToNormalized(src->alpha); + } + + static void writeColor(A8R8G8B8 *dst, const gl::ColorUI *src) + { + dst->R = static_cast(src->red); + dst->G = static_cast(src->green); + dst->B = static_cast(src->blue); + dst->A = static_cast(src->alpha); + } + + static void average(A8R8G8B8 *dst, const A8R8G8B8 *src1, const A8R8G8B8 *src2) + { + *(unsigned int*)dst = (((*(unsigned int*)src1 ^ *(unsigned int*)src2) & 0xFEFEFEFE) >> 1) + (*(unsigned int*)src1 & *(unsigned int*)src2); + } +}; + +struct R8G8B8A8 +{ + unsigned char R; + unsigned char G; + unsigned char B; + unsigned char A; + + static void readColor(gl::ColorF *dst, const R8G8B8A8 *src) + { + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = gl::normalizedToFloat(src->B); + dst->alpha = gl::normalizedToFloat(src->A); + } + + static void readColor(gl::ColorUI *dst, const R8G8B8A8 *src) + { + dst->red = src->R; + dst->green = src->G; + dst->blue = src->B; + dst->alpha = src->A; + } + + static void writeColor(R8G8B8A8 *dst, const gl::ColorF *src) + { + dst->R = gl::floatToNormalized(src->red); + dst->G = gl::floatToNormalized(src->green); + dst->B = gl::floatToNormalized(src->blue); + dst->A = gl::floatToNormalized(src->alpha); + } + + static void writeColor(R8G8B8A8 *dst, const gl::ColorUI *src) + { + dst->R = static_cast(src->red); + dst->G = static_cast(src->green); + dst->B = static_cast(src->blue); + dst->A = static_cast(src->alpha); + } + + static void average(R8G8B8A8 *dst, const R8G8B8A8 *src1, const R8G8B8A8 *src2) + { + *(unsigned int*)dst = (((*(unsigned int*)src1 ^ *(unsigned int*)src2) & 0xFEFEFEFE) >> 1) + (*(unsigned int*)src1 & *(unsigned int*)src2); + } +}; + +struct B8G8R8A8 +{ + unsigned char B; + unsigned char G; + unsigned char R; + unsigned char A; + + static void readColor(gl::ColorF *dst, const B8G8R8A8 *src) + { + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = gl::normalizedToFloat(src->B); + dst->alpha = gl::normalizedToFloat(src->A); + } + + static void readColor(gl::ColorUI *dst, const B8G8R8A8 *src) + { + dst->red = src->R; + dst->green = src->G; + dst->blue = src->B; + dst->alpha = src->A; + } + + static void writeColor(B8G8R8A8 *dst, const gl::ColorF *src) + { + dst->R = gl::floatToNormalized(src->red); + dst->G = gl::floatToNormalized(src->green); + dst->B = gl::floatToNormalized(src->blue); + dst->A = gl::floatToNormalized(src->alpha); + } + + static void writeColor(B8G8R8A8 *dst, const gl::ColorUI *src) + { + dst->R = static_cast(src->red); + dst->G = static_cast(src->green); + dst->B = static_cast(src->blue); + dst->A = static_cast(src->alpha); + } + + static void average(B8G8R8A8 *dst, const B8G8R8A8 *src1, const B8G8R8A8 *src2) + { + *(unsigned int*)dst = (((*(unsigned int*)src1 ^ *(unsigned int*)src2) & 0xFEFEFEFE) >> 1) + (*(unsigned int*)src1 & *(unsigned int*)src2); + } +}; + +struct B8G8R8X8 +{ + unsigned char B; + unsigned char G; + unsigned char R; + unsigned char X; + + static void readColor(gl::ColorF *dst, const B8G8R8X8 *src) + { + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = gl::normalizedToFloat(src->B); + dst->alpha = 1.0f; + } + + static void readColor(gl::ColorUI *dst, const B8G8R8X8 *src) + { + dst->red = src->R; + dst->green = src->G; + dst->blue = src->B; + dst->alpha = 1; + } + + static void writeColor(B8G8R8X8 *dst, const gl::ColorF *src) + { + dst->R = gl::floatToNormalized(src->red); + dst->G = gl::floatToNormalized(src->green); + dst->B = gl::floatToNormalized(src->blue); + dst->X = 255; + } + + static void writeColor(B8G8R8X8 *dst, const gl::ColorUI *src) + { + dst->R = static_cast(src->red); + dst->G = static_cast(src->green); + dst->B = static_cast(src->blue); + dst->X = 255; + } + + static void average(B8G8R8X8 *dst, const B8G8R8X8 *src1, const B8G8R8X8 *src2) + { + *(unsigned int*)dst = (((*(unsigned int*)src1 ^ *(unsigned int*)src2) & 0xFEFEFEFE) >> 1) + (*(unsigned int*)src1 & *(unsigned int*)src2); + dst->X = 255; + } +}; + +struct B5G5R5A1 +{ + unsigned short BGRA; + + static void readColor(gl::ColorF *dst, const B5G5R5A1 *src) + { + dst->alpha = gl::normalizedToFloat<1>(gl::getShiftedData<1, 15>(src->BGRA)); + dst->red = gl::normalizedToFloat<5>(gl::getShiftedData<5, 10>(src->BGRA)); + dst->green = gl::normalizedToFloat<5>(gl::getShiftedData<5, 5>(src->BGRA)); + dst->blue = gl::normalizedToFloat<5>(gl::getShiftedData<5, 0>(src->BGRA)); + } + + static void writeColor(B5G5R5A1 *dst, const gl::ColorF *src) + { + dst->BGRA = gl::shiftData<1, 15>(gl::floatToNormalized<1, unsigned short>(src->alpha)) | + gl::shiftData<5, 10>(gl::floatToNormalized<5, unsigned short>(src->red)) | + gl::shiftData<5, 5>(gl::floatToNormalized<5, unsigned short>(src->green)) | + gl::shiftData<5, 0>(gl::floatToNormalized<5, unsigned short>(src->blue)); + } + + static void average(B5G5R5A1 *dst, const B5G5R5A1 *src1, const B5G5R5A1 *src2) + { + dst->BGRA = gl::shiftData<1, 15>(gl::average(gl::getShiftedData<1, 15>(src1->BGRA), gl::getShiftedData<1, 15>(src2->BGRA))) | + gl::shiftData<5, 10>(gl::average(gl::getShiftedData<5, 10>(src1->BGRA), gl::getShiftedData<5, 10>(src2->BGRA))) | + gl::shiftData<5, 5>(gl::average(gl::getShiftedData<5, 5>(src1->BGRA), gl::getShiftedData<5, 5>(src2->BGRA))) | + gl::shiftData<5, 0>(gl::average(gl::getShiftedData<5, 0>(src1->BGRA), gl::getShiftedData<5, 0>(src2->BGRA))); + } +}; + +struct R5G5B5A1 +{ + unsigned short RGBA; + + static void readColor(gl::ColorF *dst, const R5G5B5A1 *src) + { + dst->alpha = gl::normalizedToFloat<1>(gl::getShiftedData<1, 15>(src->RGBA)); + dst->blue = gl::normalizedToFloat<5>(gl::getShiftedData<5, 10>(src->RGBA)); + dst->green = gl::normalizedToFloat<5>(gl::getShiftedData<5, 5>(src->RGBA)); + dst->red = gl::normalizedToFloat<5>(gl::getShiftedData<5, 0>(src->RGBA)); + } + + static void writeColor(R5G5B5A1 *dst, const gl::ColorF *src) + { + dst->RGBA = gl::shiftData<1, 15>(gl::floatToNormalized<1, unsigned short>(src->alpha)) | + gl::shiftData<5, 10>(gl::floatToNormalized<5, unsigned short>(src->blue)) | + gl::shiftData<5, 5>(gl::floatToNormalized<5, unsigned short>(src->green)) | + gl::shiftData<5, 0>(gl::floatToNormalized<5, unsigned short>(src->red)); + } + + static void average(R5G5B5A1 *dst, const R5G5B5A1 *src1, const R5G5B5A1 *src2) + { + dst->RGBA = gl::shiftData<1, 15>(gl::average(gl::getShiftedData<1, 15>(src1->RGBA), gl::getShiftedData<1, 15>(src2->RGBA))) | + gl::shiftData<5, 10>(gl::average(gl::getShiftedData<5, 10>(src1->RGBA), gl::getShiftedData<5, 10>(src2->RGBA))) | + gl::shiftData<5, 5>(gl::average(gl::getShiftedData<5, 5>(src1->RGBA), gl::getShiftedData<5, 5>(src2->RGBA))) | + gl::shiftData<5, 0>(gl::average(gl::getShiftedData<5, 0>(src1->RGBA), gl::getShiftedData<5, 0>(src2->RGBA))); + } +}; + +struct R4G4B4A4 +{ + unsigned char R : 4; + unsigned char G : 4; + unsigned char B : 4; + unsigned char A : 4; + + static void readColor(gl::ColorF *dst, const R4G4B4A4 *src) + { + dst->red = gl::normalizedToFloat<4>(src->R); + dst->green = gl::normalizedToFloat<4>(src->G); + dst->blue = gl::normalizedToFloat<4>(src->B); + dst->alpha = gl::normalizedToFloat<4>(src->A); + } + + static void writeColor(R4G4B4A4 *dst, const gl::ColorF *src) + { + dst->R = gl::floatToNormalized<4, unsigned char>(src->red); + dst->G = gl::floatToNormalized<4, unsigned char>(src->green); + dst->B = gl::floatToNormalized<4, unsigned char>(src->blue); + dst->A = gl::floatToNormalized<4, unsigned char>(src->alpha); + } + + static void average(R4G4B4A4 *dst, const R4G4B4A4 *src1, const R4G4B4A4 *src2) + { + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); + dst->B = gl::average(src1->B, src2->B); + dst->A = gl::average(src1->A, src2->A); + } +}; + +struct A4R4G4B4 +{ + unsigned char A : 4; + unsigned char R : 4; + unsigned char G : 4; + unsigned char B : 4; + + static void readColor(gl::ColorF *dst, const A4R4G4B4 *src) + { + dst->red = gl::normalizedToFloat<4>(src->R); + dst->green = gl::normalizedToFloat<4>(src->G); + dst->blue = gl::normalizedToFloat<4>(src->B); + dst->alpha = gl::normalizedToFloat<4>(src->A); + } + + static void writeColor(A4R4G4B4 *dst, const gl::ColorF *src) + { + dst->R = gl::floatToNormalized<4, unsigned char>(src->red); + dst->G = gl::floatToNormalized<4, unsigned char>(src->green); + dst->B = gl::floatToNormalized<4, unsigned char>(src->blue); + dst->A = gl::floatToNormalized<4, unsigned char>(src->alpha); + } + + static void average(A4R4G4B4 *dst, const A4R4G4B4 *src1, const A4R4G4B4 *src2) + { + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); + dst->B = gl::average(src1->B, src2->B); + dst->A = gl::average(src1->A, src2->A); + } +}; + +struct B4G4R4A4 +{ + unsigned char B : 4; + unsigned char G : 4; + unsigned char R : 4; + unsigned char A : 4; + + static void readColor(gl::ColorF *dst, const B4G4R4A4 *src) + { + dst->red = gl::normalizedToFloat<4>(src->R); + dst->green = gl::normalizedToFloat<4>(src->G); + dst->blue = gl::normalizedToFloat<4>(src->B); + dst->alpha = gl::normalizedToFloat<4>(src->A); + } + + static void writeColor(B4G4R4A4 *dst, const gl::ColorF *src) + { + dst->R = gl::floatToNormalized<4, unsigned char>(src->red); + dst->G = gl::floatToNormalized<4, unsigned char>(src->green); + dst->B = gl::floatToNormalized<4, unsigned char>(src->blue); + dst->A = gl::floatToNormalized<4, unsigned char>(src->alpha); + } + + static void average(B4G4R4A4 *dst, const B4G4R4A4 *src1, const B4G4R4A4 *src2) + { + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); + dst->B = gl::average(src1->B, src2->B); + dst->A = gl::average(src1->A, src2->A); + } +}; + +struct R16 +{ + unsigned short R; + + static void readColor(gl::ColorF *dst, const R16 *src) + { + dst->red = gl::normalizedToFloat(src->R); + dst->green = 0.0f; + dst->blue = 0.0f; + dst->alpha = 1.0f; + } + + static void readColor(gl::ColorUI *dst, const R16 *src) + { + dst->red = src->R; + dst->green = 0; + dst->blue = 0; + dst->alpha = 1; + } + + static void writeColor(R16 *dst, const gl::ColorF *src) + { + dst->R = gl::floatToNormalized(src->red); + } + + static void writeColor(R16 *dst, const gl::ColorUI *src) + { + dst->R = static_cast(src->red); + } + + static void average(R16 *dst, const R16 *src1, const R16 *src2) + { + dst->R = gl::average(src1->R, src2->R); + } +}; + +struct R16G16 +{ + unsigned short R; + unsigned short G; + + static void readColor(gl::ColorF *dst, const R16G16 *src) + { + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = 0.0f; + dst->alpha = 1.0f; + } + + static void readColor(gl::ColorUI *dst, const R16G16 *src) + { + dst->red = src->R; + dst->green = src->G; + dst->blue = 0; + dst->alpha = 1; + } + + static void writeColor(R16G16 *dst, const gl::ColorF *src) + { + dst->R = gl::floatToNormalized(src->red); + dst->G = gl::floatToNormalized(src->green); + } + + static void writeColor(R16G16 *dst, const gl::ColorUI *src) + { + dst->R = static_cast(src->red); + dst->G = static_cast(src->green); + } + + static void average(R16G16 *dst, const R16G16 *src1, const R16G16 *src2) + { + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); + } +}; + +struct R16G16B16 +{ + unsigned short R; + unsigned short G; + unsigned short B; + + static void readColor(gl::ColorF *dst, const R16G16B16 *src) + { + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = gl::normalizedToFloat(src->B); + dst->alpha = 1.0f; + } + + static void readColor(gl::ColorUI *dst, const R16G16B16 *src) + { + dst->red = src->R; + dst->green = src->G; + dst->blue = src->B; + dst->alpha = 1; + } + + static void writeColor(R16G16B16 *dst, const gl::ColorF *src) + { + dst->R = gl::floatToNormalized(src->red); + dst->G = gl::floatToNormalized(src->green); + dst->B = gl::floatToNormalized(src->blue); + } + + static void writeColor(R16G16B16 *dst, const gl::ColorUI *src) + { + dst->R = static_cast(src->red); + dst->G = static_cast(src->green); + dst->B = static_cast(src->blue); + } + + static void average(R16G16B16 *dst, const R16G16B16 *src1, const R16G16B16 *src2) + { + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); + dst->B = gl::average(src1->B, src2->B); + } +}; + +struct R16G16B16A16 +{ + unsigned short R; + unsigned short G; + unsigned short B; + unsigned short A; + + static void readColor(gl::ColorF *dst, const R16G16B16A16 *src) + { + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = gl::normalizedToFloat(src->B); + dst->alpha = gl::normalizedToFloat(src->A); + } + + static void readColor(gl::ColorUI *dst, const R16G16B16A16 *src) + { + dst->red = src->R; + dst->green = src->G; + dst->blue = src->B; + dst->alpha = src->A; + } + + static void writeColor(R16G16B16A16 *dst, const gl::ColorF *src) + { + dst->R = gl::floatToNormalized(src->red); + dst->G = gl::floatToNormalized(src->green); + dst->B = gl::floatToNormalized(src->blue); + dst->A = gl::floatToNormalized(src->alpha); + } + + static void writeColor(R16G16B16A16 *dst, const gl::ColorUI *src) + { + dst->R = static_cast(src->red); + dst->G = static_cast(src->green); + dst->B = static_cast(src->blue); + dst->A = static_cast(src->alpha); + } + + static void average(R16G16B16A16 *dst, const R16G16B16A16 *src1, const R16G16B16A16 *src2) + { + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); + dst->B = gl::average(src1->B, src2->B); + dst->A = gl::average(src1->A, src2->A); + } +}; + +struct R32 +{ + unsigned int R; + + static void readColor(gl::ColorF *dst, const R32 *src) + { + dst->red = gl::normalizedToFloat(src->R); + dst->green = 0.0f; + dst->blue = 0.0f; + dst->alpha = 1.0f; + } + + static void readColor(gl::ColorUI *dst, const R32 *src) + { + dst->red = src->R; + dst->green = 0; + dst->blue = 0; + dst->alpha = 1; + } + + static void writeColor(R32 *dst, const gl::ColorF *src) + { + dst->R = gl::floatToNormalized(src->red); + } + + static void writeColor(R32 *dst, const gl::ColorUI *src) + { + dst->R = static_cast(src->red); + } + + static void average(R32 *dst, const R32 *src1, const R32 *src2) + { + dst->R = gl::average(src1->R, src2->R); + } +}; + +struct R32G32 +{ + unsigned int R; + unsigned int G; + + static void readColor(gl::ColorF *dst, const R32G32 *src) + { + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = 0.0f; + dst->alpha = 1.0f; + } + + static void readColor(gl::ColorUI *dst, const R32G32 *src) + { + dst->red = src->R; + dst->green = src->G; + dst->blue = 0; + dst->alpha = 1; + } + + static void writeColor(R32G32 *dst, const gl::ColorF *src) + { + dst->R = gl::floatToNormalized(src->red); + dst->G = gl::floatToNormalized(src->green); + } + + static void writeColor(R32G32 *dst, const gl::ColorUI *src) + { + dst->R = static_cast(src->red); + dst->G = static_cast(src->green); + } + + static void average(R32G32 *dst, const R32G32 *src1, const R32G32 *src2) + { + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); + } +}; + +struct R32G32B32 +{ + unsigned int R; + unsigned int G; + unsigned int B; + + static void readColor(gl::ColorF *dst, const R32G32B32 *src) + { + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = gl::normalizedToFloat(src->B); + dst->alpha = 1.0f; + } + + static void readColor(gl::ColorUI *dst, const R32G32B32 *src) + { + dst->red = src->R; + dst->green = src->G; + dst->blue = src->B; + dst->alpha = 1; + } + + static void writeColor(R32G32B32 *dst, const gl::ColorF *src) + { + dst->R = gl::floatToNormalized(src->red); + dst->G = gl::floatToNormalized(src->green); + dst->B = gl::floatToNormalized(src->blue); + } + + static void writeColor(R32G32B32 *dst, const gl::ColorUI *src) + { + dst->R = static_cast(src->red); + dst->G = static_cast(src->green); + dst->B = static_cast(src->blue); + } + + static void average(R32G32B32 *dst, const R32G32B32 *src1, const R32G32B32 *src2) + { + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); + dst->B = gl::average(src1->B, src2->B); + } +}; + +struct R32G32B32A32 +{ + unsigned int R; + unsigned int G; + unsigned int B; + unsigned int A; + + static void readColor(gl::ColorF *dst, const R32G32B32A32 *src) + { + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = gl::normalizedToFloat(src->B); + dst->alpha = gl::normalizedToFloat(src->A); + } + + static void readColor(gl::ColorUI *dst, const R32G32B32A32 *src) + { + dst->red = src->R; + dst->green = src->G; + dst->blue = src->B; + dst->alpha = src->A; + } + + static void writeColor(R32G32B32A32 *dst, const gl::ColorF *src) + { + dst->R = gl::floatToNormalized(src->red); + dst->G = gl::floatToNormalized(src->green); + dst->B = gl::floatToNormalized(src->blue); + dst->A = gl::floatToNormalized(src->alpha); + } + + static void writeColor(R32G32B32A32 *dst, const gl::ColorUI *src) + { + dst->R = static_cast(src->red); + dst->G = static_cast(src->green); + dst->B = static_cast(src->blue); + dst->A = static_cast(src->alpha); + } + + static void average(R32G32B32A32 *dst, const R32G32B32A32 *src1, const R32G32B32A32 *src2) + { + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); + dst->B = gl::average(src1->B, src2->B); + dst->A = gl::average(src1->A, src2->A); + } +}; + +struct R8S +{ + char R; + + static void readColor(gl::ColorF *dst, const R8S *src) + { + dst->red = gl::normalizedToFloat(src->R); + dst->green = 0.0f; + dst->blue = 0.0f; + dst->alpha = 1.0f; + } + + static void readColor(gl::ColorI *dst, const R8S *src) + { + dst->red = src->R; + dst->green = 0; + dst->blue = 0; + dst->alpha = 1; + } + + static void writeColor(R8S *dst, const gl::ColorF *src) + { + dst->R = gl::floatToNormalized(src->red); + } + + static void writeColor(R8S *dst, const gl::ColorI *src) + { + dst->R = static_cast(src->red); + } + + static void average(R8S *dst, const R8S *src1, const R8S *src2) + { + dst->R = gl::average(src1->R, src2->R); + } +}; + +struct R8G8S +{ + char R; + char G; + + static void readColor(gl::ColorF *dst, const R8G8S *src) + { + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = 0.0f; + dst->alpha = 1.0f; + } + + static void readColor(gl::ColorI *dst, const R8G8S *src) + { + dst->red = src->R; + dst->green = src->G; + dst->blue = 0; + dst->alpha = 1; + } + + static void writeColor(R8G8S *dst, const gl::ColorF *src) + { + dst->R = gl::floatToNormalized(src->red); + dst->G = gl::floatToNormalized(src->green); + } + + static void writeColor(R8G8S *dst, const gl::ColorI *src) + { + dst->R = static_cast(src->red); + dst->G = static_cast(src->green); + } + + static void average(R8G8S *dst, const R8G8S *src1, const R8G8S *src2) + { + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); + } +}; + +struct R8G8B8S +{ + char R; + char G; + char B; + + static void readColor(gl::ColorF *dst, const R8G8B8S *src) + { + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = gl::normalizedToFloat(src->B); + dst->alpha = 1.0f; + } + + static void readColor(gl::ColorI *dst, const R8G8B8S *src) + { + dst->red = src->R; + dst->green = src->G; + dst->blue = src->B; + dst->alpha = 1; + } + + static void writeColor(R8G8B8S *dst, const gl::ColorF *src) + { + dst->R = gl::floatToNormalized(src->red); + dst->G = gl::floatToNormalized(src->green); + dst->B = gl::floatToNormalized(src->blue); + } + + static void writeColor(R8G8B8S *dst, const gl::ColorI *src) + { + dst->R = static_cast(src->red); + dst->G = static_cast(src->green); + dst->B = static_cast(src->blue); + } + + static void average(R8G8B8S *dst, const R8G8B8S *src1, const R8G8B8S *src2) + { + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); + dst->B = gl::average(src1->B, src2->B); + } +}; + +struct R8G8B8A8S +{ + char R; + char G; + char B; + char A; + + static void readColor(gl::ColorF *dst, const R8G8B8A8S *src) + { + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = gl::normalizedToFloat(src->B); + dst->alpha = gl::normalizedToFloat(src->A); + } + + static void readColor(gl::ColorI *dst, const R8G8B8A8S *src) + { + dst->red = src->R; + dst->green = src->G; + dst->blue = src->B; + dst->alpha = src->A; + } + + static void writeColor(R8G8B8A8S *dst, const gl::ColorF *src) + { + dst->R = gl::floatToNormalized(src->red); + dst->G = gl::floatToNormalized(src->green); + dst->B = gl::floatToNormalized(src->blue); + dst->A = gl::floatToNormalized(src->alpha); + } + + static void writeColor(R8G8B8A8S *dst, const gl::ColorI *src) + { + dst->R = static_cast(src->red); + dst->G = static_cast(src->green); + dst->B = static_cast(src->blue); + dst->A = static_cast(src->alpha); + } + + static void average(R8G8B8A8S *dst, const R8G8B8A8S *src1, const R8G8B8A8S *src2) + { + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); + dst->B = gl::average(src1->B, src2->B); + dst->A = gl::average(src1->A, src2->A); + } +}; + +struct R16S +{ + short R; + + static void readColor(gl::ColorF *dst, const R16S *src) + { + dst->red = gl::normalizedToFloat(src->R); + dst->green = 0.0f; + dst->blue = 0.0f; + dst->alpha = 1.0f; + } + + static void readColor(gl::ColorI *dst, const R16S *src) + { + dst->red = src->R; + dst->green = 0; + dst->blue = 0; + dst->alpha = 1; + } + + static void writeColor(R16S *dst, const gl::ColorF *src) + { + dst->R = gl::floatToNormalized(src->red); + } + + static void writeColor(R16S *dst, const gl::ColorI *src) + { + dst->R = static_cast(src->red); + } + + static void average(R16S *dst, const R16S *src1, const R16S *src2) + { + dst->R = gl::average(src1->R, src2->R); + } +}; + +struct R16G16S +{ + short R; + short G; + + static void readColor(gl::ColorF *dst, const R16G16S *src) + { + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = 0.0f; + dst->alpha = 1.0f; + } + + static void readColor(gl::ColorI *dst, const R16G16S *src) + { + dst->red = src->R; + dst->green = src->G; + dst->blue = 0; + dst->alpha = 1; + } + + static void writeColor(R16G16S *dst, const gl::ColorF *src) + { + dst->R = gl::floatToNormalized(src->red); + dst->G = gl::floatToNormalized(src->green); + } + + static void writeColor(R16G16S *dst, const gl::ColorI *src) + { + dst->R = static_cast(src->red); + dst->G = static_cast(src->green); + } + + static void average(R16G16S *dst, const R16G16S *src1, const R16G16S *src2) + { + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); + } +}; + +struct R16G16B16S +{ + short R; + short G; + short B; + + static void readColor(gl::ColorF *dst, const R16G16B16S *src) + { + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = gl::normalizedToFloat(src->B); + dst->alpha = 1.0f; + } + + static void readColor(gl::ColorI *dst, const R16G16B16S *src) + { + dst->red = src->R; + dst->green = src->G; + dst->blue = src->B; + dst->alpha = 1; + } + + static void writeColor(R16G16B16S *dst, const gl::ColorF *src) + { + dst->R = gl::floatToNormalized(src->red); + dst->G = gl::floatToNormalized(src->green); + dst->B = gl::floatToNormalized(src->blue); + } + + static void writeColor(R16G16B16S *dst, const gl::ColorI *src) + { + dst->R = static_cast(src->red); + dst->G = static_cast(src->green); + dst->B = static_cast(src->blue); + } + + static void average(R16G16B16S *dst, const R16G16B16S *src1, const R16G16B16S *src2) + { + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); + dst->B = gl::average(src1->B, src2->B); + } +}; + +struct R16G16B16A16S +{ + short R; + short G; + short B; + short A; + + static void readColor(gl::ColorF *dst, const R16G16B16A16S *src) + { + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = gl::normalizedToFloat(src->B); + dst->alpha = gl::normalizedToFloat(src->A); + } + + static void readColor(gl::ColorI *dst, const R16G16B16A16S *src) + { + dst->red = src->R; + dst->green = src->G; + dst->blue = src->B; + dst->alpha = src->A; + } + + static void writeColor(R16G16B16A16S *dst, const gl::ColorF *src) + { + dst->R = gl::floatToNormalized(src->red); + dst->G = gl::floatToNormalized(src->green); + dst->B = gl::floatToNormalized(src->blue); + dst->A = gl::floatToNormalized(src->alpha); + } + + static void writeColor(R16G16B16A16S *dst, const gl::ColorI *src) + { + dst->R = static_cast(src->red); + dst->G = static_cast(src->green); + dst->B = static_cast(src->blue); + dst->A = static_cast(src->alpha); + } + + static void average(R16G16B16A16S *dst, const R16G16B16A16S *src1, const R16G16B16A16S *src2) + { + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); + dst->B = gl::average(src1->B, src2->B); + dst->A = gl::average(src1->A, src2->A); + } +}; + +struct R32S +{ + int R; + + static void readColor(gl::ColorF *dst, const R32S *src) + { + dst->red = gl::normalizedToFloat(src->R); + dst->green = 0.0f; + dst->blue = 0.0f; + dst->alpha = 1.0f; + } + + static void readColor(gl::ColorI *dst, const R32S *src) + { + dst->red = src->R; + dst->green = 0; + dst->blue = 0; + dst->alpha = 1; + } + + static void writeColor(R32S *dst, const gl::ColorF *src) + { + dst->R = gl::floatToNormalized(src->red); + } + + static void writeColor(R32S *dst, const gl::ColorI *src) + { + dst->R = static_cast(src->red); + } + + static void average(R32S *dst, const R32S *src1, const R32S *src2) + { + dst->R = gl::average(src1->R, src2->R); + } +}; + +struct R32G32S +{ + int R; + int G; + + static void readColor(gl::ColorF *dst, const R32G32S *src) + { + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = 0.0f; + dst->alpha = 1.0f; + } + + static void readColor(gl::ColorI *dst, const R32G32S *src) + { + dst->red = src->R; + dst->green = src->G; + dst->blue = 0; + dst->alpha = 1; + } + + static void writeColor(R32G32S *dst, const gl::ColorF *src) + { + dst->R = gl::floatToNormalized(src->red); + dst->G = gl::floatToNormalized(src->green); + } + + static void writeColor(R32G32S *dst, const gl::ColorI *src) + { + dst->R = static_cast(src->red); + dst->G = static_cast(src->green); + } + + static void average(R32G32S *dst, const R32G32S *src1, const R32G32S *src2) + { + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); + } +}; + +struct R32G32B32S +{ + int R; + int G; + int B; + + static void readColor(gl::ColorF *dst, const R32G32B32S *src) + { + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = gl::normalizedToFloat(src->B); + dst->alpha = 1.0f; + } + + static void readColor(gl::ColorI *dst, const R32G32B32S *src) + { + dst->red = src->R; + dst->green = src->G; + dst->blue = src->B; + dst->alpha = 1; + } + + static void writeColor(R32G32B32S *dst, const gl::ColorF *src) + { + dst->R = gl::floatToNormalized(src->red); + dst->G = gl::floatToNormalized(src->green); + dst->B = gl::floatToNormalized(src->blue); + } + + static void writeColor(R32G32B32S *dst, const gl::ColorI *src) + { + dst->R = static_cast(src->red); + dst->G = static_cast(src->green); + dst->B = static_cast(src->blue); + } + + static void average(R32G32B32S *dst, const R32G32B32S *src1, const R32G32B32S *src2) + { + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); + dst->B = gl::average(src1->B, src2->B); + } +}; + +struct R32G32B32A32S +{ + int R; + int G; + int B; + int A; + + static void readColor(gl::ColorF *dst, const R32G32B32A32S *src) + { + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = gl::normalizedToFloat(src->B); + dst->alpha = gl::normalizedToFloat(src->A); + } + + static void readColor(gl::ColorI *dst, const R32G32B32A32S *src) + { + dst->red = src->R; + dst->green = src->G; + dst->blue = src->B; + dst->alpha = src->A; + } + + static void writeColor(R32G32B32A32S *dst, const gl::ColorF *src) + { + dst->R = gl::floatToNormalized(src->red); + dst->G = gl::floatToNormalized(src->green); + dst->B = gl::floatToNormalized(src->blue); + dst->A = gl::floatToNormalized(src->alpha); + } + + static void writeColor(R32G32B32A32S *dst, const gl::ColorI *src) + { + dst->R = static_cast(src->red); + dst->G = static_cast(src->green); + dst->B = static_cast(src->blue); + dst->A = static_cast(src->alpha); + } + + static void average(R32G32B32A32S *dst, const R32G32B32A32S *src1, const R32G32B32A32S *src2) + { + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); + dst->B = gl::average(src1->B, src2->B); + dst->A = gl::average(src1->A, src2->A); + } +}; + +struct A16B16G16R16F +{ + unsigned short A; + unsigned short R; + unsigned short G; + unsigned short B; + + static void readColor(gl::ColorF *dst, const A16B16G16R16F *src) + { + dst->red = gl::float16ToFloat32(src->R); + dst->green = gl::float16ToFloat32(src->G); + dst->blue = gl::float16ToFloat32(src->B); + dst->alpha = gl::float16ToFloat32(src->A); + } + + static void writeColor(A16B16G16R16F *dst, const gl::ColorF *src) + { + dst->R = gl::float32ToFloat16(src->red); + dst->G = gl::float32ToFloat16(src->green); + dst->B = gl::float32ToFloat16(src->blue); + dst->A = gl::float32ToFloat16(src->alpha); + } + + static void average(A16B16G16R16F *dst, const A16B16G16R16F *src1, const A16B16G16R16F *src2) + { + dst->R = gl::averageHalfFloat(src1->R, src2->R); + dst->G = gl::averageHalfFloat(src1->G, src2->G); + dst->B = gl::averageHalfFloat(src1->B, src2->B); + dst->A = gl::averageHalfFloat(src1->A, src2->A); + } +}; + +struct R16G16B16A16F +{ + unsigned short R; + unsigned short G; + unsigned short B; + unsigned short A; + + static void readColor(gl::ColorF *dst, const R16G16B16A16F *src) + { + dst->red = gl::float16ToFloat32(src->R); + dst->green = gl::float16ToFloat32(src->G); + dst->blue = gl::float16ToFloat32(src->B); + dst->alpha = gl::float16ToFloat32(src->A); + } + + static void writeColor(R16G16B16A16F *dst, const gl::ColorF *src) + { + dst->R = gl::float32ToFloat16(src->red); + dst->G = gl::float32ToFloat16(src->green); + dst->B = gl::float32ToFloat16(src->blue); + dst->A = gl::float32ToFloat16(src->alpha); + } + + static void average(R16G16B16A16F *dst, const R16G16B16A16F *src1, const R16G16B16A16F *src2) + { + dst->R = gl::averageHalfFloat(src1->R, src2->R); + dst->G = gl::averageHalfFloat(src1->G, src2->G); + dst->B = gl::averageHalfFloat(src1->B, src2->B); + dst->A = gl::averageHalfFloat(src1->A, src2->A); + } +}; + +struct R16F +{ + unsigned short R; + + static void readColor(gl::ColorF *dst, const R16F *src) + { + dst->red = gl::float16ToFloat32(src->R); + dst->green = 0.0f; + dst->blue = 0.0f; + dst->alpha = 1.0f; + } + + static void writeColor(R16F *dst, const gl::ColorF *src) + { + dst->R = gl::float32ToFloat16(src->red); + } + + static void average(R16F *dst, const R16F *src1, const R16F *src2) + { + dst->R = gl::averageHalfFloat(src1->R, src2->R); + } +}; + +struct A16F +{ + unsigned short A; + + static void readColor(gl::ColorF *dst, const A16F *src) + { + dst->red = 0.0f; + dst->green = 0.0f; + dst->blue = 0.0f; + dst->alpha = gl::float16ToFloat32(src->A); + } + + static void writeColor(A16F *dst, const gl::ColorF *src) + { + dst->A = gl::float32ToFloat16(src->alpha); + } + + static void average(A16F *dst, const A16F *src1, const A16F *src2) + { + dst->A = gl::averageHalfFloat(src1->A, src2->A); + } +}; + +struct L16F +{ + unsigned short L; + + static void readColor(gl::ColorF *dst, const L16F *src) + { + float lum = gl::float16ToFloat32(src->L); + dst->red = lum; + dst->green = lum; + dst->blue = lum; + dst->alpha = 1.0f; + } + + static void writeColor(L16F *dst, const gl::ColorF *src) + { + dst->L = gl::float32ToFloat16((src->red + src->green + src->blue) / 3.0f); + } + + static void average(L16F *dst, const L16F *src1, const L16F *src2) + { + dst->L = gl::averageHalfFloat(src1->L, src2->L); + } +}; + +struct L16A16F +{ + unsigned short L; + unsigned short A; + + static void readColor(gl::ColorF *dst, const L16A16F *src) + { + float lum = gl::float16ToFloat32(src->L); + dst->red = lum; + dst->green = lum; + dst->blue = lum; + dst->alpha = gl::float16ToFloat32(src->A); + } + + static void writeColor(L16A16F *dst, const gl::ColorF *src) + { + dst->L = gl::float32ToFloat16((src->red + src->green + src->blue) / 3.0f); + dst->A = gl::float32ToFloat16(src->alpha); + } + + static void average(L16A16F *dst, const L16A16F *src1, const L16A16F *src2) + { + dst->L = gl::averageHalfFloat(src1->L, src2->L); + dst->A = gl::averageHalfFloat(src1->A, src2->A); + } +}; + +struct R16G16F +{ + unsigned short R; + unsigned short G; + + static void readColor(gl::ColorF *dst, const R16G16F *src) + { + dst->red = gl::float16ToFloat32(src->R); + dst->green = gl::float16ToFloat32(src->G); + dst->blue = 0.0f; + dst->alpha = 1.0f; + } + + static void writeColor(R16G16F *dst, const gl::ColorF *src) + { + dst->R = gl::float32ToFloat16(src->red); + dst->G = gl::float32ToFloat16(src->green); + } + + static void average(R16G16F *dst, const R16G16F *src1, const R16G16F *src2) + { + dst->R = gl::averageHalfFloat(src1->R, src2->R); + dst->G = gl::averageHalfFloat(src1->G, src2->G); + } +}; + +struct R16G16B16F +{ + unsigned short R; + unsigned short G; + unsigned short B; + + static void readColor(gl::ColorF *dst, const R16G16B16F *src) + { + dst->red = gl::float16ToFloat32(src->R); + dst->green = gl::float16ToFloat32(src->G); + dst->blue = gl::float16ToFloat32(src->B); + dst->alpha = 1.0f; + } + + static void writeColor(R16G16B16F *dst, const gl::ColorF *src) + { + dst->R = gl::float32ToFloat16(src->red); + dst->G = gl::float32ToFloat16(src->green); + dst->B = gl::float32ToFloat16(src->blue); + } + + static void average(R16G16B16F *dst, const R16G16B16F *src1, const R16G16B16F *src2) + { + dst->R = gl::averageHalfFloat(src1->R, src2->R); + dst->G = gl::averageHalfFloat(src1->G, src2->G); + dst->B = gl::averageHalfFloat(src1->B, src2->B); + } +}; + +struct A32B32G32R32F +{ + float A; + float R; + float G; + float B; + + static void readColor(gl::ColorF *dst, const A32B32G32R32F *src) + { + dst->red = src->R; + dst->green = src->G; + dst->blue = src->B; + dst->alpha = src->A; + } + + static void writeColor(A32B32G32R32F *dst, const gl::ColorF *src) + { + dst->R = src->red; + dst->G = src->green; + dst->B = src->blue; + dst->A = src->alpha; + } + + static void average(A32B32G32R32F *dst, const A32B32G32R32F *src1, const A32B32G32R32F *src2) + { + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); + dst->B = gl::average(src1->B, src2->B); + dst->A = gl::average(src1->A, src2->A); + } +}; + +struct R32G32B32A32F +{ + float R; + float G; + float B; + float A; + + static void readColor(gl::ColorF *dst, const R32G32B32A32F *src) + { + dst->red = src->R; + dst->green = src->G; + dst->blue = src->B; + dst->alpha = src->A; + } + + static void writeColor(R32G32B32A32F *dst, const gl::ColorF *src) + { + dst->R = src->red; + dst->G = src->green; + dst->B = src->blue; + dst->A = src->alpha; + } + + static void average(R32G32B32A32F *dst, const R32G32B32A32F *src1, const R32G32B32A32F *src2) + { + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); + dst->B = gl::average(src1->B, src2->B); + dst->A = gl::average(src1->A, src2->A); + } +}; + +struct R32F +{ + float R; + + static void readColor(gl::ColorF *dst, const R32F *src) + { + dst->red = src->R; + dst->green = 0.0f; + dst->blue = 0.0f; + dst->alpha = 1.0f; + } + + static void writeColor(R32F *dst, const gl::ColorF *src) + { + dst->R = src->red; + } + + static void average(R32F *dst, const R32F *src1, const R32F *src2) + { + dst->R = gl::average(src1->R, src2->R); + } +}; + +struct A32F +{ + float A; + + static void readColor(gl::ColorF *dst, const A32F *src) + { + dst->red = 0.0f; + dst->green = 0.0f; + dst->blue = 0.0f; + dst->alpha = src->A; + } + + static void writeColor(A32F *dst, const gl::ColorF *src) + { + dst->A = src->alpha; + } + + static void average(A32F *dst, const A32F *src1, const A32F *src2) + { + dst->A = gl::average(src1->A, src2->A); + } +}; + +struct L32F +{ + float L; + + static void readColor(gl::ColorF *dst, const L32F *src) + { + dst->red = src->L; + dst->green = src->L; + dst->blue = src->L; + dst->alpha = 1.0f; + } + + static void writeColor(L32F *dst, const gl::ColorF *src) + { + dst->L = (src->red + src->green + src->blue) / 3.0f; + } + + static void average(L32F *dst, const L32F *src1, const L32F *src2) + { + dst->L = gl::average(src1->L, src2->L); + } +}; + +struct L32A32F +{ + float L; + float A; + + static void readColor(gl::ColorF *dst, const L32A32F *src) + { + dst->red = src->L; + dst->green = src->L; + dst->blue = src->L; + dst->alpha = src->A; + } + + static void writeColor(L32A32F *dst, const gl::ColorF *src) + { + dst->L = (src->red + src->green + src->blue) / 3.0f; + dst->A = src->alpha; + } + + static void average(L32A32F *dst, const L32A32F *src1, const L32A32F *src2) + { + dst->L = gl::average(src1->L, src2->L); + dst->A = gl::average(src1->A, src2->A); + } +}; + +struct R32G32F +{ + float R; + float G; + + static void readColor(gl::ColorF *dst, const R32G32F *src) + { + dst->red = src->R; + dst->green = src->G; + dst->blue = 0.0f; + dst->alpha = 1.0f; + } + + static void writeColor(R32G32F *dst, const gl::ColorF *src) + { + dst->R = src->red; + dst->G = src->green; + } + + static void average(R32G32F *dst, const R32G32F *src1, const R32G32F *src2) + { + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); + } +}; + +struct R32G32B32F +{ + float R; + float G; + float B; + + static void readColor(gl::ColorF *dst, const R32G32B32F *src) + { + dst->red = src->R; + dst->green = src->G; + dst->blue = src->B; + dst->alpha = 1.0f; + } + + static void writeColor(R32G32B32F *dst, const gl::ColorF *src) + { + dst->R = src->red; + dst->G = src->green; + dst->B = src->blue; + } + + static void average(R32G32B32F *dst, const R32G32B32F *src1, const R32G32B32F *src2) + { + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); + dst->B = gl::average(src1->B, src2->B); + } +}; + +struct R10G10B10A2 +{ + unsigned int R : 10; + unsigned int G : 10; + unsigned int B : 10; + unsigned int A : 2; + + static void readColor(gl::ColorF *dst, const R10G10B10A2 *src) + { + dst->red = gl::normalizedToFloat<10>(src->R); + dst->green = gl::normalizedToFloat<10>(src->G); + dst->blue = gl::normalizedToFloat<10>(src->B); + dst->alpha = gl::normalizedToFloat< 2>(src->A); + } + + static void readColor(gl::ColorUI *dst, const R10G10B10A2 *src) + { + dst->red = src->R; + dst->green = src->G; + dst->blue = src->B; + dst->alpha = src->A; + } + + static void writeColor(R10G10B10A2 *dst, const gl::ColorF *src) + { + dst->R = gl::floatToNormalized<10, unsigned int>(src->red); + dst->G = gl::floatToNormalized<10, unsigned int>(src->green); + dst->B = gl::floatToNormalized<10, unsigned int>(src->blue); + dst->A = gl::floatToNormalized< 2, unsigned int>(src->alpha); + } + + static void writeColor(R10G10B10A2 *dst, const gl::ColorUI *src) + { + dst->R = static_cast(src->red); + dst->G = static_cast(src->green); + dst->B = static_cast(src->blue); + dst->A = static_cast(src->alpha); + } + + static void average(R10G10B10A2 *dst, const R10G10B10A2 *src1, const R10G10B10A2 *src2) + { + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); + dst->B = gl::average(src1->B, src2->B); + dst->A = gl::average(src1->A, src2->A); + } +}; + +struct R9G9B9E5 +{ + unsigned int R : 9; + unsigned int G : 9; + unsigned int B : 9; + unsigned int E : 5; + + static void readColor(gl::ColorF *dst, const R9G9B9E5 *src) + { + gl::convert999E5toRGBFloats(gl::bitCast(*src), &dst->red, &dst->green, &dst->blue); + dst->alpha = 1.0f; + } + + static void writeColor(R9G9B9E5 *dst, const gl::ColorF *src) + { + *reinterpret_cast(dst) = gl::convertRGBFloatsTo999E5(src->red, + src->green, + src->blue); + } + + static void average(R9G9B9E5 *dst, const R9G9B9E5 *src1, const R9G9B9E5 *src2) + { + float r1, g1, b1; + gl::convert999E5toRGBFloats(*reinterpret_cast(src1), &r1, &g1, &b1); + + float r2, g2, b2; + gl::convert999E5toRGBFloats(*reinterpret_cast(src2), &r2, &g2, &b2); + + *reinterpret_cast(dst) = gl::convertRGBFloatsTo999E5(gl::average(r1, r2), + gl::average(g1, g2), + gl::average(b1, b2)); + } +}; + +struct R11G11B10F +{ + unsigned int R : 11; + unsigned int G : 11; + unsigned int B : 10; + + static void readColor(gl::ColorF *dst, const R11G11B10F *src) + { + dst->red = gl::float11ToFloat32(src->R); + dst->green = gl::float11ToFloat32(src->G); + dst->blue = gl::float10ToFloat32(src->B); + dst->alpha = 1.0f; + } + + static void writeColor(R11G11B10F *dst, const gl::ColorF *src) + { + dst->R = gl::float32ToFloat11(src->red); + dst->G = gl::float32ToFloat11(src->green); + dst->B = gl::float32ToFloat10(src->blue); + } + + static void average(R11G11B10F *dst, const R11G11B10F *src1, const R11G11B10F *src2) + { + dst->R = gl::averageFloat11(src1->R, src2->R); + dst->G = gl::averageFloat11(src1->G, src2->G); + dst->B = gl::averageFloat10(src1->B, src2->B); + } +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_IMAGEFORMATS_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/loadimage.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/loadimage.cpp new file mode 100644 index 0000000000..172832b3e7 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/loadimage.cpp @@ -0,0 +1,662 @@ +// +// Copyright (c) 2013-2015 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// loadimage.cpp: Defines image loading functions. + +#include "libANGLE/renderer/d3d/loadimage.h" + +namespace rx +{ + +void LoadA8ToRGBA8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint8_t *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint32_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + dest[x] = static_cast(source[x]) << 24; + } + } + } +} + +void LoadA8ToBGRA8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + // Same as loading to RGBA + LoadA8ToRGBA8(width, height, depth, input, inputRowPitch, inputDepthPitch, output, outputRowPitch, outputDepthPitch); +} + +void LoadA32FToRGBA32F(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const float *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + float *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + dest[4 * x + 0] = 0.0f; + dest[4 * x + 1] = 0.0f; + dest[4 * x + 2] = 0.0f; + dest[4 * x + 3] = source[x]; + } + } + } +} + +void LoadA16FToRGBA16F(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint16_t *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint16_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + dest[4 * x + 0] = 0; + dest[4 * x + 1] = 0; + dest[4 * x + 2] = 0; + dest[4 * x + 3] = source[x]; + } + } + } +} + +void LoadL8ToRGBA8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint8_t *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint8_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + uint8_t sourceVal = source[x]; + dest[4 * x + 0] = sourceVal; + dest[4 * x + 1] = sourceVal; + dest[4 * x + 2] = sourceVal; + dest[4 * x + 3] = 0xFF; + } + } + } +} + +void LoadL8ToBGRA8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + // Same as loading to RGBA + LoadL8ToRGBA8(width, height, depth, input, inputRowPitch, inputDepthPitch, output, outputRowPitch, outputDepthPitch); +} + +void LoadL32FToRGBA32F(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const float *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + float *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + dest[4 * x + 0] = source[x]; + dest[4 * x + 1] = source[x]; + dest[4 * x + 2] = source[x]; + dest[4 * x + 3] = 1.0f; + } + } + } +} + +void LoadL16FToRGBA16F(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint16_t *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint16_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + dest[4 * x + 0] = source[x]; + dest[4 * x + 1] = source[x]; + dest[4 * x + 2] = source[x]; + dest[4 * x + 3] = gl::Float16One; + } + } + } +} + +void LoadLA8ToRGBA8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint8_t *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint8_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + dest[4 * x + 0] = source[2 * x + 0]; + dest[4 * x + 1] = source[2 * x + 0]; + dest[4 * x + 2] = source[2 * x + 0]; + dest[4 * x + 3] = source[2 * x + 1]; + } + } + } +} + +void LoadLA8ToBGRA8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + // Same as loading to RGBA + LoadLA8ToRGBA8(width, height, depth, input, inputRowPitch, inputDepthPitch, output, outputRowPitch, outputDepthPitch); +} + +void LoadLA32FToRGBA32F(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const float *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + float *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + dest[4 * x + 0] = source[2 * x + 0]; + dest[4 * x + 1] = source[2 * x + 0]; + dest[4 * x + 2] = source[2 * x + 0]; + dest[4 * x + 3] = source[2 * x + 1]; + } + } + } +} + +void LoadLA16FToRGBA16F(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint16_t *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint16_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + dest[4 * x + 0] = source[2 * x + 0]; + dest[4 * x + 1] = source[2 * x + 0]; + dest[4 * x + 2] = source[2 * x + 0]; + dest[4 * x + 3] = source[2 * x + 1]; + } + } + } +} + +void LoadRGB8ToBGRX8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint8_t *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint8_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + dest[4 * x + 0] = source[x * 3 + 2]; + dest[4 * x + 1] = source[x * 3 + 1]; + dest[4 * x + 2] = source[x * 3 + 0]; + dest[4 * x + 3] = 0xFF; + } + } + } +} + +void LoadRG8ToBGRX8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint8_t *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint8_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + dest[4 * x + 0] = 0x00; + dest[4 * x + 1] = source[x * 2 + 1]; + dest[4 * x + 2] = source[x * 2 + 0]; + dest[4 * x + 3] = 0xFF; + } + } + } +} + +void LoadR8ToBGRX8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint8_t *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint8_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + dest[4 * x + 0] = 0x00; + dest[4 * x + 1] = 0x00; + dest[4 * x + 2] = source[x]; + dest[4 * x + 3] = 0xFF; + } + } + } +} + +void LoadR5G6B5ToBGRA8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint16_t *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint8_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + uint16_t rgb = source[x]; + dest[4 * x + 0] = ((rgb & 0x001F) << 3) | ((rgb & 0x001F) >> 2); + dest[4 * x + 1] = ((rgb & 0x07E0) >> 3) | ((rgb & 0x07E0) >> 9); + dest[4 * x + 2] = ((rgb & 0xF800) >> 8) | ((rgb & 0xF800) >> 13); + dest[4 * x + 3] = 0xFF; + } + } + } +} + +void LoadR5G6B5ToRGBA8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint16_t *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint8_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + uint16_t rgb = source[x]; + dest[4 * x + 0] = ((rgb & 0xF800) >> 8) | ((rgb & 0xF800) >> 13); + dest[4 * x + 1] = ((rgb & 0x07E0) >> 3) | ((rgb & 0x07E0) >> 9); + dest[4 * x + 2] = ((rgb & 0x001F) << 3) | ((rgb & 0x001F) >> 2); + dest[4 * x + 3] = 0xFF; + } + } + } +} + +void LoadRGBA8ToBGRA8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint32_t *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint32_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + uint32_t rgba = source[x]; + dest[x] = (ANGLE_ROTL(rgba, 16) & 0x00ff00ff) | (rgba & 0xff00ff00); + } + } + } +} + +void LoadRGBA4ToBGRA8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint16_t *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint8_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + uint16_t rgba = source[x]; + dest[4 * x + 0] = ((rgba & 0x00F0) << 0) | ((rgba & 0x00F0) >> 4); + dest[4 * x + 1] = ((rgba & 0x0F00) >> 4) | ((rgba & 0x0F00) >> 8); + dest[4 * x + 2] = ((rgba & 0xF000) >> 8) | ((rgba & 0xF000) >> 12); + dest[4 * x + 3] = ((rgba & 0x000F) << 4) | ((rgba & 0x000F) >> 0); + } + } + } +} + +void LoadRGBA4ToRGBA8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint16_t *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint8_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + uint16_t rgba = source[x]; + dest[4 * x + 0] = ((rgba & 0xF000) >> 8) | ((rgba & 0xF000) >> 12); + dest[4 * x + 1] = ((rgba & 0x0F00) >> 4) | ((rgba & 0x0F00) >> 8); + dest[4 * x + 2] = ((rgba & 0x00F0) << 0) | ((rgba & 0x00F0) >> 4); + dest[4 * x + 3] = ((rgba & 0x000F) << 4) | ((rgba & 0x000F) >> 0); + } + } + } +} + +void LoadBGRA4ToBGRA8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint16_t *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint8_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + uint16_t bgra = source[x]; + dest[4 * x + 0] = ((bgra & 0xF000) >> 8) | ((bgra & 0xF000) >> 12); + dest[4 * x + 1] = ((bgra & 0x0F00) >> 4) | ((bgra & 0x0F00) >> 8); + dest[4 * x + 2] = ((bgra & 0x00F0) << 0) | ((bgra & 0x00F0) >> 4); + dest[4 * x + 3] = ((bgra & 0x000F) << 4) | ((bgra & 0x000F) >> 0); + } + } + } +} + +void LoadRGB5A1ToBGRA8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint16_t *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint8_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + uint16_t rgba = source[x]; + dest[4 * x + 0] = ((rgba & 0x003E) << 2) | ((rgba & 0x003E) >> 3); + dest[4 * x + 1] = ((rgba & 0x07C0) >> 3) | ((rgba & 0x07C0) >> 8); + dest[4 * x + 2] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13); + dest[4 * x + 3] = (rgba & 0x0001) ? 0xFF : 0; + } + } + } +} + +void LoadRGB5A1ToRGBA8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint16_t *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint8_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + uint16_t rgba = source[x]; + dest[4 * x + 0] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13); + dest[4 * x + 1] = ((rgba & 0x07C0) >> 3) | ((rgba & 0x07C0) >> 8); + dest[4 * x + 2] = ((rgba & 0x003E) << 2) | ((rgba & 0x003E) >> 3); + dest[4 * x + 3] = (rgba & 0x0001) ? 0xFF : 0; + } + } + } +} + + +void LoadBGR5A1ToBGRA8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint16_t *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint8_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + uint16_t bgra = source[x]; + dest[4 * x + 0] = ((bgra & 0xF800) >> 8) | ((bgra & 0xF800) >> 13); + dest[4 * x + 1] = ((bgra & 0x07C0) >> 3) | ((bgra & 0x07C0) >> 8); + dest[4 * x + 2] = ((bgra & 0x003E) << 2) | ((bgra & 0x003E) >> 3); + dest[4 * x + 3] = (bgra & 0x0001) ? 0xFF : 0; + } + } + } +} + +void LoadRGB10A2ToRGBA8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint32_t *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint8_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + uint32_t rgba = source[x]; + dest[4 * x + 0] = (rgba & 0x000003FF) >> 2; + dest[4 * x + 1] = (rgba & 0x000FFC00) >> 12; + dest[4 * x + 2] = (rgba & 0x3FF00000) >> 22; + dest[4 * x + 3] = ((rgba & 0xC0000000) >> 30) * 0x55; + } + } + } +} + +void LoadRGB16FToRGB9E5(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint16_t *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint32_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + dest[x] = gl::convertRGBFloatsTo999E5(gl::float16ToFloat32(source[x * 3 + 0]), + gl::float16ToFloat32(source[x * 3 + 1]), + gl::float16ToFloat32(source[x * 3 + 2])); + } + } + } +} + +void LoadRGB32FToRGB9E5(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const float *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint32_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + dest[x] = gl::convertRGBFloatsTo999E5(source[x * 3 + 0], source[x * 3 + 1], source[x * 3 + 2]); + } + } + } +} + +void LoadRGB16FToRG11B10F(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint16_t *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint32_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + dest[x] = (gl::float32ToFloat11(gl::float16ToFloat32(source[x * 3 + 0])) << 0) | + (gl::float32ToFloat11(gl::float16ToFloat32(source[x * 3 + 1])) << 11) | + (gl::float32ToFloat10(gl::float16ToFloat32(source[x * 3 + 2])) << 22); + } + } + } +} + +void LoadRGB32FToRG11B10F(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const float *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint32_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + dest[x] = (gl::float32ToFloat11(source[x * 3 + 0]) << 0) | + (gl::float32ToFloat11(source[x * 3 + 1]) << 11) | + (gl::float32ToFloat10(source[x * 3 + 2]) << 22); + } + } + } +} + +void LoadG8R24ToR24G8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint32_t *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint32_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + uint32_t d = source[x] >> 8; + uint8_t s = source[x] & 0xFF; + dest[x] = d | (s << 24); + } + } + } +} + +void LoadRGB32FToRGBA16F(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const float *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint16_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + dest[x * 4 + 0] = gl::float32ToFloat16(source[x * 3 + 0]); + dest[x * 4 + 1] = gl::float32ToFloat16(source[x * 3 + 1]); + dest[x * 4 + 2] = gl::float32ToFloat16(source[x * 3 + 2]); + dest[x * 4 + 3] = gl::Float16One; + } + } + } +} + +void LoadR32ToR16(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint32_t *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint16_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + dest[x] = source[x] >> 16; + } + } + } +} + +void LoadR32ToR24G8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint32_t *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint32_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + + for (size_t x = 0; x < width; x++) + { + dest[x] = source[x] >> 8; + } + } + } +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/loadimage.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/loadimage.h new file mode 100644 index 0000000000..6967dc868e --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/loadimage.h @@ -0,0 +1,193 @@ +// +// Copyright (c) 2013-2015 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// loadimage.h: Defines image loading functions + +#ifndef LIBANGLE_RENDERER_D3D_LOADIMAGE_H_ +#define LIBANGLE_RENDERER_D3D_LOADIMAGE_H_ + +#include "libANGLE/angletypes.h" + +#include + +namespace rx +{ + +void LoadA8ToRGBA8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadA8ToBGRA8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadA8ToBGRA8_SSE2(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadA32FToRGBA32F(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadA16FToRGBA16F(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadL8ToRGBA8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadL8ToBGRA8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadL32FToRGBA32F(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadL16FToRGBA16F(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadLA8ToRGBA8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadLA8ToBGRA8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadLA32FToRGBA32F(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadLA16FToRGBA16F(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadRGB8ToBGRX8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadRG8ToBGRX8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadR8ToBGRX8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadR5G6B5ToBGRA8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadR5G6B5ToRGBA8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadRGBA8ToBGRA8_SSE2(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadRGBA8ToBGRA8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadRGBA4ToBGRA8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadRGBA4ToRGBA8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadBGRA4ToBGRA8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadRGB5A1ToBGRA8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadRGB5A1ToRGBA8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadBGR5A1ToBGRA8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadRGB10A2ToRGBA8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadRGB16FToRGB9E5(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadRGB32FToRGB9E5(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadRGB16FToRG11B10F(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadRGB32FToRG11B10F(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadG8R24ToR24G8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +template +inline void LoadToNative(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +template +inline void LoadToNative3To4(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +template +inline void Load32FTo16F(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadRGB32FToRGBA16F(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +template +inline void LoadCompressedToNative(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadR32ToR16(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +template +inline void Initialize4ComponentData(size_t width, size_t height, size_t depth, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadR32ToR24G8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +template +inline T *OffsetDataPointer(uint8_t *data, size_t y, size_t z, size_t rowPitch, size_t depthPitch); + +template +inline const T *OffsetDataPointer(const uint8_t *data, size_t y, size_t z, size_t rowPitch, size_t depthPitch); + +} + +#include "loadimage.inl" + +#endif // LIBANGLE_RENDERER_D3D_LOADIMAGE_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/loadimage.inl b/src/3rdparty/angle/src/libANGLE/renderer/d3d/loadimage.inl new file mode 100644 index 0000000000..920e667db1 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/loadimage.inl @@ -0,0 +1,156 @@ +// +// Copyright (c) 2014-2015 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "common/mathutil.h" + +namespace rx +{ + +template +inline T *OffsetDataPointer(uint8_t *data, size_t y, size_t z, size_t rowPitch, size_t depthPitch) +{ + return reinterpret_cast(data + (y * rowPitch) + (z * depthPitch)); +} + +template +inline const T *OffsetDataPointer(const uint8_t *data, size_t y, size_t z, size_t rowPitch, size_t depthPitch) +{ + return reinterpret_cast(data + (y * rowPitch) + (z * depthPitch)); +} + +template +inline void LoadToNative(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + const size_t rowSize = width * sizeof(type) * componentCount; + const size_t layerSize = rowSize * height; + const size_t imageSize = layerSize * depth; + + if (layerSize == inputDepthPitch && layerSize == outputDepthPitch) + { + ASSERT(rowSize == inputRowPitch && rowSize == outputRowPitch); + memcpy(output, input, imageSize); + } + else if (rowSize == inputRowPitch && rowSize == outputRowPitch) + { + for (size_t z = 0; z < depth; z++) + { + const type *source = OffsetDataPointer(input, 0, z, inputRowPitch, inputDepthPitch); + type *dest = OffsetDataPointer(output, 0, z, outputRowPitch, outputDepthPitch); + + memcpy(dest, source, layerSize); + } + } + else + { + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const type *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + type *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + memcpy(dest, source, width * sizeof(type) * componentCount); + } + } + } +} + +template +inline void LoadToNative3To4(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + const type fourthValue = gl::bitCast(fourthComponentBits); + + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const type *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + type *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + dest[x * 4 + 0] = source[x * 3 + 0]; + dest[x * 4 + 1] = source[x * 3 + 1]; + dest[x * 4 + 2] = source[x * 3 + 2]; + dest[x * 4 + 3] = fourthValue; + } + } + } +} + +template +inline void Load32FTo16F(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + const size_t elementWidth = componentCount * width; + + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const float *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint16_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + + for (size_t x = 0; x < elementWidth; x++) + { + dest[x] = gl::float32ToFloat16(source[x]); + } + } + } +} + +template +inline void LoadCompressedToNative(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + const size_t columns = (width + (blockWidth - 1)) / blockWidth; + const size_t rows = (height + (blockHeight - 1)) / blockHeight; + + for (size_t z = 0; z < depth; ++z) + { + for (size_t y = 0; y < rows; ++y) + { + const uint8_t *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint8_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + memcpy(dest, source, columns * blockSize); + } + } +} + +template +inline void Initialize4ComponentData(size_t width, size_t height, size_t depth, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + type writeValues[4] = + { + gl::bitCast(firstBits), + gl::bitCast(secondBits), + gl::bitCast(thirdBits), + gl::bitCast(fourthBits), + }; + + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + type *destRow = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + type* destPixel = destRow + x * 4; + + // This could potentially be optimized by generating an entire row of initialization + // data and copying row by row instead of pixel by pixel. + memcpy(destPixel, writeValues, sizeof(type) * 4); + } + } + } +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/loadimageSSE2.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/loadimageSSE2.cpp new file mode 100644 index 0000000000..c87d35c82b --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/loadimageSSE2.cpp @@ -0,0 +1,125 @@ +// +// Copyright (c) 2002-2015 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// loadimageSSE2.cpp: Defines image loading functions. It's +// in a separated file for GCC, which can enable SSE usage only per-file, +// not for code blocks that use SSE2 explicitly. + +#include "libANGLE/renderer/d3d/loadimage.h" + +#include "common/platform.h" + +#ifdef ANGLE_USE_SSE +#include +#endif + +namespace rx +{ + +void LoadA8ToBGRA8_SSE2(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ +#if defined(ANGLE_USE_SSE) + __m128i zeroWide = _mm_setzero_si128(); + + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint8_t *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint32_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + + size_t x = 0; + + // Make output writes aligned + for (; ((reinterpret_cast(&dest[x]) & 0xF) != 0 && x < width); x++) + { + dest[x] = static_cast(source[x]) << 24; + } + + for (; x + 7 < width; x += 8) + { + __m128i sourceData = _mm_loadl_epi64(reinterpret_cast(&source[x])); + // Interleave each byte to 16bit, make the lower byte to zero + sourceData = _mm_unpacklo_epi8(zeroWide, sourceData); + // Interleave each 16bit to 32bit, make the lower 16bit to zero + __m128i lo = _mm_unpacklo_epi16(zeroWide, sourceData); + __m128i hi = _mm_unpackhi_epi16(zeroWide, sourceData); + + _mm_store_si128(reinterpret_cast<__m128i*>(&dest[x]), lo); + _mm_store_si128(reinterpret_cast<__m128i*>(&dest[x + 4]), hi); + } + + // Handle the remainder + for (; x < width; x++) + { + dest[x] = static_cast(source[x]) << 24; + } + } + } +#else + // Ensure that this function is reported as not implemented for ARM builds because + // the instructions below are not present for that architecture. + UNIMPLEMENTED(); + return; +#endif +} + +void LoadRGBA8ToBGRA8_SSE2(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ +#if defined(ANGLE_USE_SSE) + __m128i brMask = _mm_set1_epi32(0x00ff00ff); + + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint32_t *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint32_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + + size_t x = 0; + + // Make output writes aligned + for (; ((reinterpret_cast(&dest[x]) & 15) != 0) && x < width; x++) + { + uint32_t rgba = source[x]; + dest[x] = (ANGLE_ROTL(rgba, 16) & 0x00ff00ff) | (rgba & 0xff00ff00); + } + + for (; x + 3 < width; x += 4) + { + __m128i sourceData = _mm_loadu_si128(reinterpret_cast(&source[x])); + // Mask out g and a, which don't change + __m128i gaComponents = _mm_andnot_si128(brMask, sourceData); + // Mask out b and r + __m128i brComponents = _mm_and_si128(sourceData, brMask); + // Swap b and r + __m128i brSwapped = _mm_shufflehi_epi16(_mm_shufflelo_epi16(brComponents, _MM_SHUFFLE(2, 3, 0, 1)), _MM_SHUFFLE(2, 3, 0, 1)); + __m128i result = _mm_or_si128(gaComponents, brSwapped); + _mm_store_si128(reinterpret_cast<__m128i*>(&dest[x]), result); + } + + // Perform leftover writes + for (; x < width; x++) + { + uint32_t rgba = source[x]; + dest[x] = (ANGLE_ROTL(rgba, 16) & 0x00ff00ff) | (rgba & 0xff00ff00); + } + } + } +#else + // Ensure that this function is reported as not implemented for ARM builds because + // the instructions below are not present for that architecture. + UNIMPLEMENTED(); + return; +#endif +} + +} + diff --git a/src/3rdparty/angle/src/libANGLE/validationEGL.cpp b/src/3rdparty/angle/src/libANGLE/validationEGL.cpp new file mode 100644 index 0000000000..12ee6a2b93 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/validationEGL.cpp @@ -0,0 +1,503 @@ +// +// Copyright (c) 2015 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// validationEGL.cpp: Validation functions for generic EGL entry point parameters + +#include "libANGLE/validationEGL.h" + +#include "libANGLE/Config.h" +#include "libANGLE/Context.h" +#include "libANGLE/Display.h" +#include "libANGLE/Surface.h" + +#include + +namespace egl +{ + +Error ValidateDisplay(const Display *display) +{ + if (display == EGL_NO_DISPLAY) + { + return Error(EGL_BAD_DISPLAY); + } + + if (!display->isInitialized()) + { + return Error(EGL_NOT_INITIALIZED); + } + + return Error(EGL_SUCCESS); +} + +Error ValidateSurface(const Display *display, Surface *surface) +{ + Error error = ValidateDisplay(display); + if (error.isError()) + { + return error; + } + + if (!display->isValidSurface(surface)) + { + return Error(EGL_BAD_SURFACE); + } + + return Error(EGL_SUCCESS); +} + +Error ValidateConfig(const Display *display, const Config *config) +{ + Error error = ValidateDisplay(display); + if (error.isError()) + { + return error; + } + + if (!display->isValidConfig(config)) + { + return Error(EGL_BAD_CONFIG); + } + + return Error(EGL_SUCCESS); +} + +Error ValidateContext(const Display *display, gl::Context *context) +{ + Error error = ValidateDisplay(display); + if (error.isError()) + { + return error; + } + + if (!display->isValidContext(context)) + { + return Error(EGL_BAD_CONTEXT); + } + + return Error(EGL_SUCCESS); +} + +Error ValidateCreateContext(Display *display, Config *configuration, gl::Context *shareContext, + const AttributeMap& attributes) +{ + Error error = ValidateConfig(display, configuration); + if (error.isError()) + { + return error; + } + + // Get the requested client version (default is 1) and check it is 2 or 3. + EGLint clientMajorVersion = 1; + EGLint clientMinorVersion = 0; + EGLint contextFlags = 0; + bool resetNotification = false; + bool robustAccess = false; + for (AttributeMap::const_iterator attributeIter = attributes.begin(); attributeIter != attributes.end(); attributeIter++) + { + EGLint attribute = attributeIter->first; + EGLint value = attributeIter->second; + + switch (attribute) + { + case EGL_CONTEXT_CLIENT_VERSION: + clientMajorVersion = value; + break; + + case EGL_CONTEXT_MINOR_VERSION: + clientMinorVersion = value; + break; + + case EGL_CONTEXT_FLAGS_KHR: + contextFlags = value; + break; + + case EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR: + // Only valid for OpenGL (non-ES) contexts + return Error(EGL_BAD_ATTRIBUTE); + + case EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT: + if (!display->getExtensions().createContextRobustness) + { + return Error(EGL_BAD_ATTRIBUTE); + } + if (value != EGL_TRUE && value != EGL_FALSE) + { + return Error(EGL_BAD_ATTRIBUTE); + } + robustAccess = (value == EGL_TRUE); + break; + + case EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR: + static_assert(EGL_LOSE_CONTEXT_ON_RESET_EXT == EGL_LOSE_CONTEXT_ON_RESET_KHR, "EGL extension enums not equal."); + static_assert(EGL_NO_RESET_NOTIFICATION_EXT == EGL_NO_RESET_NOTIFICATION_KHR, "EGL extension enums not equal."); + // same as EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT, fall through + case EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT: + if (!display->getExtensions().createContextRobustness) + { + return Error(EGL_BAD_ATTRIBUTE); + } + if (value == EGL_LOSE_CONTEXT_ON_RESET_EXT) + { + resetNotification = true; + } + else if (value != EGL_NO_RESET_NOTIFICATION_EXT) + { + return Error(EGL_BAD_ATTRIBUTE); + } + break; + + default: + return Error(EGL_BAD_ATTRIBUTE); + } + } + + if ((clientMajorVersion != 2 && clientMajorVersion != 3) || clientMinorVersion != 0) + { + return Error(EGL_BAD_CONFIG); + } + + if (clientMajorVersion == 3 && !(configuration->conformant & EGL_OPENGL_ES3_BIT_KHR) && !(configuration->configCaveat & EGL_NON_CONFORMANT_CONFIG)) + { + return Error(EGL_BAD_CONFIG); + } + + // Note: EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR does not apply to ES + const EGLint validContextFlags = (EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR | + EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR); + if ((contextFlags & ~validContextFlags) != 0) + { + return Error(EGL_BAD_ATTRIBUTE); + } + + if ((contextFlags & EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR) > 0) + { + robustAccess = true; + } + + if (robustAccess) + { + // Unimplemented + return Error(EGL_BAD_CONFIG); + } + + if (shareContext) + { + // Shared context is invalid or is owned by another display + if (!display->isValidContext(shareContext)) + { + return Error(EGL_BAD_MATCH); + } + + if (shareContext->isResetNotificationEnabled() != resetNotification) + { + return Error(EGL_BAD_MATCH); + } + + if (shareContext->getClientVersion() != clientMajorVersion) + { + return Error(EGL_BAD_CONTEXT); + } + } + + return Error(EGL_SUCCESS); +} + +Error ValidateCreateWindowSurface(Display *display, Config *config, EGLNativeWindowType window, + const AttributeMap& attributes) +{ + Error error = ValidateConfig(display, config); + if (error.isError()) + { + return error; + } + + if (!display->isValidNativeWindow(window)) + { + return Error(EGL_BAD_NATIVE_WINDOW); + } + + const DisplayExtensions &displayExtensions = display->getExtensions(); + + for (AttributeMap::const_iterator attributeIter = attributes.begin(); attributeIter != attributes.end(); attributeIter++) + { + EGLint attribute = attributeIter->first; + EGLint value = attributeIter->second; + + switch (attribute) + { + case EGL_RENDER_BUFFER: + switch (value) + { + case EGL_BACK_BUFFER: + break; + case EGL_SINGLE_BUFFER: + return Error(EGL_BAD_MATCH); // Rendering directly to front buffer not supported + default: + return Error(EGL_BAD_ATTRIBUTE); + } + break; + + case EGL_POST_SUB_BUFFER_SUPPORTED_NV: + if (!displayExtensions.postSubBuffer) + { + return Error(EGL_BAD_ATTRIBUTE); + } + break; + + case EGL_WIDTH: + case EGL_HEIGHT: + if (!displayExtensions.windowFixedSize) + { + return Error(EGL_BAD_ATTRIBUTE); + } + if (value < 0) + { + return Error(EGL_BAD_PARAMETER); + } + break; + + case EGL_FIXED_SIZE_ANGLE: + if (!displayExtensions.windowFixedSize) + { + return Error(EGL_BAD_ATTRIBUTE); + } + break; + + case EGL_VG_COLORSPACE: + return Error(EGL_BAD_MATCH); + + case EGL_VG_ALPHA_FORMAT: + return Error(EGL_BAD_MATCH); + + default: + return Error(EGL_BAD_ATTRIBUTE); + } + } + + if (Display::hasExistingWindowSurface(window)) + { + return Error(EGL_BAD_ALLOC); + } + + return Error(EGL_SUCCESS); +} + +Error ValidateCreatePbufferSurface(Display *display, Config *config, const AttributeMap& attributes) +{ + Error error = ValidateConfig(display, config); + if (error.isError()) + { + return error; + } + + for (AttributeMap::const_iterator attributeIter = attributes.begin(); attributeIter != attributes.end(); attributeIter++) + { + EGLint attribute = attributeIter->first; + EGLint value = attributeIter->second; + + switch (attribute) + { + case EGL_WIDTH: + case EGL_HEIGHT: + if (value < 0) + { + return Error(EGL_BAD_PARAMETER); + } + break; + + case EGL_LARGEST_PBUFFER: + break; + + case EGL_TEXTURE_FORMAT: + switch (value) + { + case EGL_NO_TEXTURE: + case EGL_TEXTURE_RGB: + case EGL_TEXTURE_RGBA: + break; + default: + return Error(EGL_BAD_ATTRIBUTE); + } + break; + + case EGL_TEXTURE_TARGET: + switch (value) + { + case EGL_NO_TEXTURE: + case EGL_TEXTURE_2D: + break; + default: + return Error(EGL_BAD_ATTRIBUTE); + } + break; + + case EGL_MIPMAP_TEXTURE: + break; + + case EGL_VG_COLORSPACE: + break; + + case EGL_VG_ALPHA_FORMAT: + break; + + default: + return Error(EGL_BAD_ATTRIBUTE); + } + } + + if (!(config->surfaceType & EGL_PBUFFER_BIT)) + { + return Error(EGL_BAD_MATCH); + } + + const Caps &caps = display->getCaps(); + + EGLenum textureFormat = attributes.get(EGL_TEXTURE_FORMAT, EGL_NO_TEXTURE); + EGLenum textureTarget = attributes.get(EGL_TEXTURE_TARGET, EGL_NO_TEXTURE); + + if ((textureFormat != EGL_NO_TEXTURE && textureTarget == EGL_NO_TEXTURE) || + (textureFormat == EGL_NO_TEXTURE && textureTarget != EGL_NO_TEXTURE)) + { + return Error(EGL_BAD_MATCH); + } + + if ((textureFormat == EGL_TEXTURE_RGB && config->bindToTextureRGB != EGL_TRUE) || + (textureFormat == EGL_TEXTURE_RGBA && config->bindToTextureRGBA != EGL_TRUE)) + { + return Error(EGL_BAD_ATTRIBUTE); + } + + EGLint width = attributes.get(EGL_WIDTH, 0); + EGLint height = attributes.get(EGL_HEIGHT, 0); + if (textureFormat != EGL_NO_TEXTURE && !caps.textureNPOT && (!gl::isPow2(width) || !gl::isPow2(height))) + { + return Error(EGL_BAD_MATCH); + } + + return Error(EGL_SUCCESS); +} + +Error ValidateCreatePbufferFromClientBuffer(Display *display, EGLenum buftype, EGLClientBuffer buffer, + Config *config, const AttributeMap& attributes) +{ + Error error = ValidateConfig(display, config); + if (error.isError()) + { + return error; + } + + const DisplayExtensions &displayExtensions = display->getExtensions(); + + switch (buftype) + { + case EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE: + if (!displayExtensions.d3dShareHandleClientBuffer) + { + return Error(EGL_BAD_PARAMETER); + } + if (buffer == nullptr) + { + return Error(EGL_BAD_PARAMETER); + } + break; + + default: + return Error(EGL_BAD_PARAMETER); + } + + for (AttributeMap::const_iterator attributeIter = attributes.begin(); attributeIter != attributes.end(); attributeIter++) + { + EGLint attribute = attributeIter->first; + EGLint value = attributeIter->second; + + switch (attribute) + { + case EGL_WIDTH: + case EGL_HEIGHT: + if (!displayExtensions.d3dShareHandleClientBuffer) + { + return Error(EGL_BAD_PARAMETER); + } + if (value < 0) + { + return Error(EGL_BAD_PARAMETER); + } + break; + + case EGL_TEXTURE_FORMAT: + switch (value) + { + case EGL_NO_TEXTURE: + case EGL_TEXTURE_RGB: + case EGL_TEXTURE_RGBA: + break; + default: + return Error(EGL_BAD_ATTRIBUTE); + } + break; + + case EGL_TEXTURE_TARGET: + switch (value) + { + case EGL_NO_TEXTURE: + case EGL_TEXTURE_2D: + break; + default: + return Error(EGL_BAD_ATTRIBUTE); + } + break; + + case EGL_MIPMAP_TEXTURE: + break; + + default: + return Error(EGL_BAD_ATTRIBUTE); + } + } + + if (!(config->surfaceType & EGL_PBUFFER_BIT)) + { + return Error(EGL_BAD_MATCH); + } + + EGLenum textureFormat = attributes.get(EGL_TEXTURE_FORMAT, EGL_NO_TEXTURE); + EGLenum textureTarget = attributes.get(EGL_TEXTURE_TARGET, EGL_NO_TEXTURE); + if ((textureFormat != EGL_NO_TEXTURE && textureTarget == EGL_NO_TEXTURE) || + (textureFormat == EGL_NO_TEXTURE && textureTarget != EGL_NO_TEXTURE)) + { + return Error(EGL_BAD_MATCH); + } + + if ((textureFormat == EGL_TEXTURE_RGB && config->bindToTextureRGB != EGL_TRUE) || + (textureFormat == EGL_TEXTURE_RGBA && config->bindToTextureRGBA != EGL_TRUE)) + { + return Error(EGL_BAD_ATTRIBUTE); + } + + if (buftype == EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE) + { + EGLint width = attributes.get(EGL_WIDTH, 0); + EGLint height = attributes.get(EGL_HEIGHT, 0); + + if (width == 0 || height == 0) + { + return Error(EGL_BAD_ATTRIBUTE); + } + +#if !defined(ANGLE_ENABLE_WINDOWS_STORE) // On Windows Store, we know the originating texture came from D3D11, so bypass this check + const Caps &caps = display->getCaps(); + if (textureFormat != EGL_NO_TEXTURE && !caps.textureNPOT && (!gl::isPow2(width) || !gl::isPow2(height))) + { + return Error(EGL_BAD_MATCH); + } +#endif + } + + return Error(EGL_SUCCESS); +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/validationEGL.h b/src/3rdparty/angle/src/libANGLE/validationEGL.h new file mode 100644 index 0000000000..4daff791fd --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/validationEGL.h @@ -0,0 +1,49 @@ +// +// Copyright (c) 2015 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// validationEGL.h: Validation functions for generic EGL entry point parameters + +#ifndef LIBANGLE_VALIDATIONEGL_H_ +#define LIBANGLE_VALIDATIONEGL_H_ + +#include "libANGLE/Error.h" + +#include + +namespace gl +{ +class Context; +} + +namespace egl +{ + +class AttributeMap; +struct Config; +class Display; +class Surface; + +// Object validation +Error ValidateDisplay(const Display *display); +Error ValidateSurface(const Display *display, Surface *surface); +Error ValidateConfig(const Display *display, const Config *config); +Error ValidateContext(const Display *display, gl::Context *context); + +// Entry point validation +Error ValidateCreateContext(Display *display, Config *configuration, gl::Context *shareContext, + const AttributeMap& attributes); + +Error ValidateCreateWindowSurface(Display *display, Config *config, EGLNativeWindowType window, + const AttributeMap& attributes); + +Error ValidateCreatePbufferSurface(Display *display, Config *config, const AttributeMap& attributes); +Error ValidateCreatePbufferFromClientBuffer(Display *display, EGLenum buftype, EGLClientBuffer buffer, + Config *config, const AttributeMap& attributes); + + +} + +#endif // LIBANGLE_VALIDATIONEGL_H_ diff --git a/src/3rdparty/angle/src/libANGLE/validationES.cpp b/src/3rdparty/angle/src/libANGLE/validationES.cpp new file mode 100644 index 0000000000..d267cbf2e6 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/validationES.cpp @@ -0,0 +1,1882 @@ +// +// Copyright (c) 2013-2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// validationES.h: Validation functions for generic OpenGL ES entry point parameters + +#include "libANGLE/validationES.h" +#include "libANGLE/validationES2.h" +#include "libANGLE/validationES3.h" +#include "libANGLE/Context.h" +#include "libANGLE/Texture.h" +#include "libANGLE/Framebuffer.h" +#include "libANGLE/FramebufferAttachment.h" +#include "libANGLE/formatutils.h" +#include "libANGLE/Query.h" +#include "libANGLE/Program.h" +#include "libANGLE/Uniform.h" +#include "libANGLE/TransformFeedback.h" +#include "libANGLE/VertexArray.h" +#include "libANGLE/renderer/BufferImpl.h" + +#include "common/mathutil.h" +#include "common/utilities.h" + +namespace gl +{ + +bool ValidCap(const Context *context, GLenum cap) +{ + switch (cap) + { + case GL_CULL_FACE: + case GL_POLYGON_OFFSET_FILL: + case GL_SAMPLE_ALPHA_TO_COVERAGE: + case GL_SAMPLE_COVERAGE: + case GL_SCISSOR_TEST: + case GL_STENCIL_TEST: + case GL_DEPTH_TEST: + case GL_BLEND: + case GL_DITHER: + return true; + case GL_PRIMITIVE_RESTART_FIXED_INDEX: + case GL_RASTERIZER_DISCARD: + return (context->getClientVersion() >= 3); + default: + return false; + } +} + +bool ValidTextureTarget(const Context *context, GLenum target) +{ + switch (target) + { + case GL_TEXTURE_2D: + case GL_TEXTURE_CUBE_MAP: + return true; + + case GL_TEXTURE_3D: + case GL_TEXTURE_2D_ARRAY: + return (context->getClientVersion() >= 3); + + default: + return false; + } +} + +// This function differs from ValidTextureTarget in that the target must be +// usable as the destination of a 2D operation-- so a cube face is valid, but +// GL_TEXTURE_CUBE_MAP is not. +// Note: duplicate of IsInternalTextureTarget +bool ValidTexture2DDestinationTarget(const Context *context, GLenum target) +{ + switch (target) + { + case GL_TEXTURE_2D: + case GL_TEXTURE_CUBE_MAP_POSITIVE_X: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: + return true; + case GL_TEXTURE_2D_ARRAY: + case GL_TEXTURE_3D: + return (context->getClientVersion() >= 3); + default: + return false; + } +} + +bool ValidFramebufferTarget(GLenum target) +{ + static_assert(GL_DRAW_FRAMEBUFFER_ANGLE == GL_DRAW_FRAMEBUFFER && GL_READ_FRAMEBUFFER_ANGLE == GL_READ_FRAMEBUFFER, + "ANGLE framebuffer enums must equal the ES3 framebuffer enums."); + + switch (target) + { + case GL_FRAMEBUFFER: return true; + case GL_READ_FRAMEBUFFER: return true; + case GL_DRAW_FRAMEBUFFER: return true; + default: return false; + } +} + +bool ValidBufferTarget(const Context *context, GLenum target) +{ + switch (target) + { + case GL_ARRAY_BUFFER: + case GL_ELEMENT_ARRAY_BUFFER: + return true; + + case GL_PIXEL_PACK_BUFFER: + case GL_PIXEL_UNPACK_BUFFER: + return context->getExtensions().pixelBufferObject; + + case GL_COPY_READ_BUFFER: + case GL_COPY_WRITE_BUFFER: + case GL_TRANSFORM_FEEDBACK_BUFFER: + case GL_UNIFORM_BUFFER: + return (context->getClientVersion() >= 3); + + default: + return false; + } +} + +bool ValidBufferParameter(const Context *context, GLenum pname) +{ + switch (pname) + { + case GL_BUFFER_USAGE: + case GL_BUFFER_SIZE: + return true; + + // GL_BUFFER_MAP_POINTER is a special case, and may only be + // queried with GetBufferPointerv + case GL_BUFFER_ACCESS_FLAGS: + case GL_BUFFER_MAPPED: + case GL_BUFFER_MAP_OFFSET: + case GL_BUFFER_MAP_LENGTH: + return (context->getClientVersion() >= 3); + + default: + return false; + } +} + +bool ValidMipLevel(const Context *context, GLenum target, GLint level) +{ + size_t maxDimension = 0; + switch (target) + { + case GL_TEXTURE_2D: maxDimension = context->getCaps().max2DTextureSize; break; + case GL_TEXTURE_CUBE_MAP: + case GL_TEXTURE_CUBE_MAP_POSITIVE_X: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: maxDimension = context->getCaps().maxCubeMapTextureSize; break; + case GL_TEXTURE_3D: maxDimension = context->getCaps().max3DTextureSize; break; + case GL_TEXTURE_2D_ARRAY: maxDimension = context->getCaps().max2DTextureSize; break; + default: UNREACHABLE(); + } + + return level <= gl::log2(maxDimension); +} + +bool ValidImageSize(const Context *context, GLenum target, GLint level, + GLsizei width, GLsizei height, GLsizei depth) +{ + if (level < 0 || width < 0 || height < 0 || depth < 0) + { + return false; + } + + if (!context->getExtensions().textureNPOT && + (level != 0 && (!gl::isPow2(width) || !gl::isPow2(height) || !gl::isPow2(depth)))) + { + return false; + } + + if (!ValidMipLevel(context, target, level)) + { + return false; + } + + return true; +} + +bool ValidCompressedImageSize(const Context *context, GLenum internalFormat, GLsizei width, GLsizei height) +{ + const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat); + if (!formatInfo.compressed) + { + return false; + } + + if (width < 0 || (static_cast(width) > formatInfo.compressedBlockWidth && width % formatInfo.compressedBlockWidth != 0) || + height < 0 || (static_cast(height) > formatInfo.compressedBlockHeight && height % formatInfo.compressedBlockHeight != 0)) + { + return false; + } + + return true; +} + +bool ValidQueryType(const Context *context, GLenum queryType) +{ + static_assert(GL_ANY_SAMPLES_PASSED == GL_ANY_SAMPLES_PASSED_EXT, "GL extension enums not equal."); + static_assert(GL_ANY_SAMPLES_PASSED_CONSERVATIVE == GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, "GL extension enums not equal."); + + switch (queryType) + { + case GL_ANY_SAMPLES_PASSED: + case GL_ANY_SAMPLES_PASSED_CONSERVATIVE: + return true; + case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN: + return (context->getClientVersion() >= 3); + default: + return false; + } +} + +bool ValidProgram(Context *context, GLuint id) +{ + // ES3 spec (section 2.11.1) -- "Commands that accept shader or program object names will generate the + // error INVALID_VALUE if the provided name is not the name of either a shader or program object and + // INVALID_OPERATION if the provided name identifies an object that is not the expected type." + + if (context->getProgram(id) != NULL) + { + return true; + } + else if (context->getShader(id) != NULL) + { + // ID is the wrong type + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + else + { + // No shader/program object has this ID + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } +} + +bool ValidateAttachmentTarget(gl::Context *context, GLenum attachment) +{ + if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT) + { + const unsigned int colorAttachment = (attachment - GL_COLOR_ATTACHMENT0_EXT); + + if (colorAttachment >= context->getCaps().maxColorAttachments) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + } + else + { + switch (attachment) + { + case GL_DEPTH_ATTACHMENT: + case GL_STENCIL_ATTACHMENT: + break; + + case GL_DEPTH_STENCIL_ATTACHMENT: + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + break; + + default: + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + } + + return true; +} + +bool ValidateRenderbufferStorageParametersBase(gl::Context *context, GLenum target, GLsizei samples, + GLenum internalformat, GLsizei width, GLsizei height) +{ + switch (target) + { + case GL_RENDERBUFFER: + break; + default: + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + + if (width < 0 || height < 0 || samples < 0) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + + const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat); + if (!formatCaps.renderable) + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + + // ANGLE_framebuffer_multisample does not explicitly state that the internal format must be + // sized but it does state that the format must be in the ES2.0 spec table 4.5 which contains + // only sized internal formats. + const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat); + if (formatInfo.pixelBytes == 0) + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + + if (static_cast(std::max(width, height)) > context->getCaps().maxRenderbufferSize) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + + GLuint handle = context->getState().getRenderbufferId(); + if (handle == 0) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + return true; +} + +bool ValidateRenderbufferStorageParametersANGLE(gl::Context *context, GLenum target, GLsizei samples, + GLenum internalformat, GLsizei width, GLsizei height) +{ + ASSERT(samples == 0 || context->getExtensions().framebufferMultisample); + + // ANGLE_framebuffer_multisample states that the value of samples must be less than or equal + // to MAX_SAMPLES_ANGLE (Context::getExtensions().maxSamples) otherwise GL_INVALID_VALUE is + // generated. + if (static_cast(samples) > context->getExtensions().maxSamples) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + + // ANGLE_framebuffer_multisample states GL_OUT_OF_MEMORY is generated on a failure to create + // the specified storage. This is different than ES 3.0 in which a sample number higher + // than the maximum sample number supported by this format generates a GL_INVALID_VALUE. + const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat); + if (static_cast(samples) > formatCaps.getMaxSamples()) + { + context->recordError(Error(GL_OUT_OF_MEMORY)); + return false; + } + + return ValidateRenderbufferStorageParametersBase(context, target, samples, internalformat, width, height); +} + +bool ValidateFramebufferRenderbufferParameters(gl::Context *context, GLenum target, GLenum attachment, + GLenum renderbuffertarget, GLuint renderbuffer) +{ + if (!ValidFramebufferTarget(target)) + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + + gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target); + GLuint framebufferHandle = context->getState().getTargetFramebuffer(target)->id(); + + if (!framebuffer || (framebufferHandle == 0 && renderbuffer != 0)) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + if (!ValidateAttachmentTarget(context, attachment)) + { + return false; + } + + // [OpenGL ES 2.0.25] Section 4.4.3 page 112 + // [OpenGL ES 3.0.2] Section 4.4.2 page 201 + // 'renderbuffer' must be either zero or the name of an existing renderbuffer object of + // type 'renderbuffertarget', otherwise an INVALID_OPERATION error is generated. + if (renderbuffer != 0) + { + if (!context->getRenderbuffer(renderbuffer)) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + } + + return true; +} + +static bool IsPartialBlit(gl::Context *context, gl::FramebufferAttachment *readBuffer, gl::FramebufferAttachment *writeBuffer, + GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, + GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1) +{ + if (srcX0 != 0 || srcY0 != 0 || dstX0 != 0 || dstY0 != 0 || + dstX1 != writeBuffer->getWidth() || dstY1 != writeBuffer->getHeight() || + srcX1 != readBuffer->getWidth() || srcY1 != readBuffer->getHeight()) + { + return true; + } + else if (context->getState().isScissorTestEnabled()) + { + const Rectangle &scissor = context->getState().getScissor(); + + return scissor.x > 0 || scissor.y > 0 || + scissor.width < writeBuffer->getWidth() || + scissor.height < writeBuffer->getHeight(); + } + else + { + return false; + } +} + +bool ValidateBlitFramebufferParameters(gl::Context *context, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, + GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, + GLenum filter, bool fromAngleExtension) +{ + switch (filter) + { + case GL_NEAREST: + break; + case GL_LINEAR: + if (fromAngleExtension) + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + break; + default: + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + + if ((mask & ~(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)) != 0) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + + if (mask == 0) + { + // ES3.0 spec, section 4.3.2 specifies that a mask of zero is valid and no + // buffers are copied. + return false; + } + + if (fromAngleExtension && (srcX1 - srcX0 != dstX1 - dstX0 || srcY1 - srcY0 != dstY1 - dstY0)) + { + ERR("Scaling and flipping in BlitFramebufferANGLE not supported by this implementation."); + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + // ES3.0 spec, section 4.3.2 states that linear filtering is only available for the + // color buffer, leaving only nearest being unfiltered from above + if ((mask & ~GL_COLOR_BUFFER_BIT) != 0 && filter != GL_NEAREST) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + if (context->getState().getReadFramebuffer()->id() == context->getState().getDrawFramebuffer()->id()) + { + if (fromAngleExtension) + { + ERR("Blits with the same source and destination framebuffer are not supported by this " + "implementation."); + } + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + gl::Framebuffer *readFramebuffer = context->getState().getReadFramebuffer(); + gl::Framebuffer *drawFramebuffer = context->getState().getDrawFramebuffer(); + + if (!readFramebuffer || !drawFramebuffer) + { + context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION)); + return false; + } + + if (!readFramebuffer->checkStatus(context->getData())) + { + context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION)); + return false; + } + + if (!drawFramebuffer->checkStatus(context->getData())) + { + context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION)); + return false; + } + + if (drawFramebuffer->getSamples(context->getData()) != 0) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + bool sameBounds = srcX0 == dstX0 && srcY0 == dstY0 && srcX1 == dstX1 && srcY1 == dstY1; + + if (mask & GL_COLOR_BUFFER_BIT) + { + gl::FramebufferAttachment *readColorBuffer = readFramebuffer->getReadColorbuffer(); + gl::FramebufferAttachment *drawColorBuffer = drawFramebuffer->getFirstColorbuffer(); + + if (readColorBuffer && drawColorBuffer) + { + GLenum readInternalFormat = readColorBuffer->getInternalFormat(); + const InternalFormat &readFormatInfo = GetInternalFormatInfo(readInternalFormat); + + for (GLuint i = 0; i < context->getCaps().maxColorAttachments; i++) + { + if (drawFramebuffer->isEnabledColorAttachment(i)) + { + GLenum drawInternalFormat = drawFramebuffer->getColorbuffer(i)->getInternalFormat(); + const InternalFormat &drawFormatInfo = GetInternalFormatInfo(drawInternalFormat); + + // The GL ES 3.0.2 spec (pg 193) states that: + // 1) If the read buffer is fixed point format, the draw buffer must be as well + // 2) If the read buffer is an unsigned integer format, the draw buffer must be as well + // 3) If the read buffer is a signed integer format, the draw buffer must be as well + if ( (readFormatInfo.componentType == GL_UNSIGNED_NORMALIZED || readFormatInfo.componentType == GL_SIGNED_NORMALIZED) && + !(drawFormatInfo.componentType == GL_UNSIGNED_NORMALIZED || drawFormatInfo.componentType == GL_SIGNED_NORMALIZED)) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + if (readFormatInfo.componentType == GL_UNSIGNED_INT && drawFormatInfo.componentType != GL_UNSIGNED_INT) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + if (readFormatInfo.componentType == GL_INT && drawFormatInfo.componentType != GL_INT) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + if (readColorBuffer->getSamples() > 0 && (readInternalFormat != drawInternalFormat || !sameBounds)) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + } + } + + if ((readFormatInfo.componentType == GL_INT || readFormatInfo.componentType == GL_UNSIGNED_INT) && filter == GL_LINEAR) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + if (fromAngleExtension) + { + FramebufferAttachment *readColorAttachment = readFramebuffer->getReadColorbuffer(); + if (!readColorAttachment || + (!(readColorAttachment->type() == GL_TEXTURE && readColorAttachment->getTextureImageIndex()->type == GL_TEXTURE_2D) && + readColorAttachment->type() != GL_RENDERBUFFER && + readColorAttachment->type() != GL_FRAMEBUFFER_DEFAULT)) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + for (GLuint colorAttachment = 0; colorAttachment < context->getCaps().maxColorAttachments; ++colorAttachment) + { + if (drawFramebuffer->isEnabledColorAttachment(colorAttachment)) + { + FramebufferAttachment *attachment = drawFramebuffer->getColorbuffer(colorAttachment); + ASSERT(attachment); + + if (!(attachment->type() == GL_TEXTURE && attachment->getTextureImageIndex()->type == GL_TEXTURE_2D) && + attachment->type() != GL_RENDERBUFFER && + attachment->type() != GL_FRAMEBUFFER_DEFAULT) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + // Return an error if the destination formats do not match + if (attachment->getInternalFormat() != readColorBuffer->getInternalFormat()) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + } + } + + int readSamples = readFramebuffer->getSamples(context->getData()); + + if (readSamples != 0 && IsPartialBlit(context, readColorBuffer, drawColorBuffer, + srcX0, srcY0, srcX1, srcY1, + dstX0, dstY0, dstX1, dstY1)) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + } + } + } + + GLenum masks[] = {GL_DEPTH_BUFFER_BIT, GL_STENCIL_BUFFER_BIT}; + GLenum attachments[] = {GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT}; + for (size_t i = 0; i < 2; i++) + { + if (mask & masks[i]) + { + gl::FramebufferAttachment *readBuffer = readFramebuffer->getAttachment(attachments[i]); + gl::FramebufferAttachment *drawBuffer = drawFramebuffer->getAttachment(attachments[i]); + + if (readBuffer && drawBuffer) + { + if (readBuffer->getInternalFormat() != drawBuffer->getInternalFormat()) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + if (readBuffer->getSamples() > 0 && !sameBounds) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + if (fromAngleExtension) + { + if (IsPartialBlit(context, readBuffer, drawBuffer, + srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1)) + { + ERR("Only whole-buffer depth and stencil blits are supported by this implementation."); + context->recordError(Error(GL_INVALID_OPERATION)); // only whole-buffer copies are permitted + return false; + } + + if (readBuffer->getSamples() != 0 || drawBuffer->getSamples() != 0) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + } + } + } + } + + return true; +} + +bool ValidateGetVertexAttribParameters(Context *context, GLenum pname) +{ + switch (pname) + { + case GL_VERTEX_ATTRIB_ARRAY_ENABLED: + case GL_VERTEX_ATTRIB_ARRAY_SIZE: + case GL_VERTEX_ATTRIB_ARRAY_STRIDE: + case GL_VERTEX_ATTRIB_ARRAY_TYPE: + case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED: + case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING: + case GL_CURRENT_VERTEX_ATTRIB: + return true; + + case GL_VERTEX_ATTRIB_ARRAY_DIVISOR: + // Don't verify ES3 context because GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE uses + // the same constant. + static_assert(GL_VERTEX_ATTRIB_ARRAY_DIVISOR == GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE, + "ANGLE extension enums not equal to GL enums."); + return true; + + case GL_VERTEX_ATTRIB_ARRAY_INTEGER: + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + return true; + + default: + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } +} + +bool ValidateTexParamParameters(gl::Context *context, GLenum pname, GLint param) +{ + switch (pname) + { + case GL_TEXTURE_WRAP_R: + case GL_TEXTURE_SWIZZLE_R: + case GL_TEXTURE_SWIZZLE_G: + case GL_TEXTURE_SWIZZLE_B: + case GL_TEXTURE_SWIZZLE_A: + case GL_TEXTURE_BASE_LEVEL: + case GL_TEXTURE_MAX_LEVEL: + case GL_TEXTURE_COMPARE_MODE: + case GL_TEXTURE_COMPARE_FUNC: + case GL_TEXTURE_MIN_LOD: + case GL_TEXTURE_MAX_LOD: + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + break; + + default: break; + } + + switch (pname) + { + case GL_TEXTURE_WRAP_S: + case GL_TEXTURE_WRAP_T: + case GL_TEXTURE_WRAP_R: + switch (param) + { + case GL_REPEAT: + case GL_CLAMP_TO_EDGE: + case GL_MIRRORED_REPEAT: + return true; + default: + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + + case GL_TEXTURE_MIN_FILTER: + switch (param) + { + case GL_NEAREST: + case GL_LINEAR: + case GL_NEAREST_MIPMAP_NEAREST: + case GL_LINEAR_MIPMAP_NEAREST: + case GL_NEAREST_MIPMAP_LINEAR: + case GL_LINEAR_MIPMAP_LINEAR: + return true; + default: + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + break; + + case GL_TEXTURE_MAG_FILTER: + switch (param) + { + case GL_NEAREST: + case GL_LINEAR: + return true; + default: + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + break; + + case GL_TEXTURE_USAGE_ANGLE: + switch (param) + { + case GL_NONE: + case GL_FRAMEBUFFER_ATTACHMENT_ANGLE: + return true; + default: + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + break; + + case GL_TEXTURE_MAX_ANISOTROPY_EXT: + if (!context->getExtensions().textureFilterAnisotropic) + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + + // we assume the parameter passed to this validation method is truncated, not rounded + if (param < 1) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + return true; + + case GL_TEXTURE_MIN_LOD: + case GL_TEXTURE_MAX_LOD: + // any value is permissible + return true; + + case GL_TEXTURE_COMPARE_MODE: + // Acceptable mode parameters from GLES 3.0.2 spec, table 3.17 + switch (param) + { + case GL_NONE: + case GL_COMPARE_REF_TO_TEXTURE: + return true; + default: + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + break; + + case GL_TEXTURE_COMPARE_FUNC: + // Acceptable function parameters from GLES 3.0.2 spec, table 3.17 + switch (param) + { + case GL_LEQUAL: + case GL_GEQUAL: + case GL_LESS: + case GL_GREATER: + case GL_EQUAL: + case GL_NOTEQUAL: + case GL_ALWAYS: + case GL_NEVER: + return true; + default: + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + break; + + case GL_TEXTURE_SWIZZLE_R: + case GL_TEXTURE_SWIZZLE_G: + case GL_TEXTURE_SWIZZLE_B: + case GL_TEXTURE_SWIZZLE_A: + switch (param) + { + case GL_RED: + case GL_GREEN: + case GL_BLUE: + case GL_ALPHA: + case GL_ZERO: + case GL_ONE: + return true; + default: + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + break; + + case GL_TEXTURE_BASE_LEVEL: + case GL_TEXTURE_MAX_LEVEL: + if (param < 0) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + return true; + + default: + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } +} + +bool ValidateSamplerObjectParameter(gl::Context *context, GLenum pname) +{ + switch (pname) + { + case GL_TEXTURE_MIN_FILTER: + case GL_TEXTURE_MAG_FILTER: + case GL_TEXTURE_WRAP_S: + case GL_TEXTURE_WRAP_T: + case GL_TEXTURE_WRAP_R: + case GL_TEXTURE_MIN_LOD: + case GL_TEXTURE_MAX_LOD: + case GL_TEXTURE_COMPARE_MODE: + case GL_TEXTURE_COMPARE_FUNC: + return true; + + default: + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } +} + +bool ValidateReadPixelsParameters(gl::Context *context, GLint x, GLint y, GLsizei width, GLsizei height, + GLenum format, GLenum type, GLsizei *bufSize, GLvoid *pixels) +{ + gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer(); + ASSERT(framebuffer); + + if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE) + { + context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION)); + return false; + } + + if (context->getState().getReadFramebuffer()->id() != 0 && + framebuffer->getSamples(context->getData()) != 0) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + const FramebufferAttachment *readBuffer = framebuffer->getReadColorbuffer(); + if (!readBuffer) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + GLenum currentFormat = framebuffer->getImplementationColorReadFormat(); + GLenum currentType = framebuffer->getImplementationColorReadType(); + GLenum currentInternalFormat = readBuffer->getInternalFormat(); + GLuint clientVersion = context->getClientVersion(); + + bool validReadFormat = (clientVersion < 3) ? ValidES2ReadFormatType(context, format, type) : + ValidES3ReadFormatType(context, currentInternalFormat, format, type); + + if (!(currentFormat == format && currentType == type) && !validReadFormat) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + GLenum sizedInternalFormat = GetSizedInternalFormat(format, type); + const InternalFormat &sizedFormatInfo = GetInternalFormatInfo(sizedInternalFormat); + + GLsizei outputPitch = sizedFormatInfo.computeRowPitch(type, width, context->getState().getPackAlignment(), 0); + // sized query sanity check + if (bufSize) + { + int requiredSize = outputPitch * height; + if (requiredSize > *bufSize) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + } + + return true; +} + +bool ValidateBeginQuery(gl::Context *context, GLenum target, GLuint id) +{ + if (!ValidQueryType(context, target)) + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + + if (id == 0) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + // From EXT_occlusion_query_boolean: If BeginQueryEXT is called with an + // of zero, if the active query object name for is non-zero (for the + // targets ANY_SAMPLES_PASSED_EXT and ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, if + // the active query for either target is non-zero), if is the name of an + // existing query object whose type does not match , or if is the + // active query object name for any query type, the error INVALID_OPERATION is + // generated. + + // Ensure no other queries are active + // NOTE: If other queries than occlusion are supported, we will need to check + // separately that: + // a) The query ID passed is not the current active query for any target/type + // b) There are no active queries for the requested target (and in the case + // of GL_ANY_SAMPLES_PASSED_EXT and GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, + // no query may be active for either if glBeginQuery targets either. + if (context->getState().isQueryActive()) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + Query *queryObject = context->getQuery(id, true, target); + + // check that name was obtained with glGenQueries + if (!queryObject) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + // check for type mismatch + if (queryObject->getType() != target) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + return true; +} + +bool ValidateEndQuery(gl::Context *context, GLenum target) +{ + if (!ValidQueryType(context, target)) + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + + const Query *queryObject = context->getState().getActiveQuery(target); + + if (queryObject == NULL) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + return true; +} + +static bool ValidateUniformCommonBase(gl::Context *context, GLenum targetUniformType, + GLint location, GLsizei count, LinkedUniform **uniformOut) +{ + if (count < 0) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + + gl::Program *program = context->getState().getProgram(); + if (!program) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + if (location == -1) + { + // Silently ignore the uniform command + return false; + } + + if (!program->isValidUniformLocation(location)) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + LinkedUniform *uniform = program->getUniformByLocation(location); + + // attempting to write an array to a non-array uniform is an INVALID_OPERATION + if (uniform->elementCount() == 1 && count > 1) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + *uniformOut = uniform; + return true; +} + +bool ValidateUniform(gl::Context *context, GLenum uniformType, GLint location, GLsizei count) +{ + // Check for ES3 uniform entry points + if (VariableComponentType(uniformType) == GL_UNSIGNED_INT && context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + LinkedUniform *uniform = NULL; + if (!ValidateUniformCommonBase(context, uniformType, location, count, &uniform)) + { + return false; + } + + GLenum targetBoolType = VariableBoolVectorType(uniformType); + bool samplerUniformCheck = (IsSamplerType(uniform->type) && uniformType == GL_INT); + if (!samplerUniformCheck && uniformType != uniform->type && targetBoolType != uniform->type) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + return true; +} + +bool ValidateUniformMatrix(gl::Context *context, GLenum matrixType, GLint location, GLsizei count, + GLboolean transpose) +{ + // Check for ES3 uniform entry points + int rows = VariableRowCount(matrixType); + int cols = VariableColumnCount(matrixType); + if (rows != cols && context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + if (transpose != GL_FALSE && context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + + LinkedUniform *uniform = NULL; + if (!ValidateUniformCommonBase(context, matrixType, location, count, &uniform)) + { + return false; + } + + if (uniform->type != matrixType) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + return true; +} + +bool ValidateStateQuery(gl::Context *context, GLenum pname, GLenum *nativeType, unsigned int *numParams) +{ + if (!context->getQueryParameterInfo(pname, nativeType, numParams)) + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + + const Caps &caps = context->getCaps(); + + if (pname >= GL_DRAW_BUFFER0 && pname <= GL_DRAW_BUFFER15) + { + unsigned int colorAttachment = (pname - GL_DRAW_BUFFER0); + + if (colorAttachment >= caps.maxDrawBuffers) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + } + + switch (pname) + { + case GL_TEXTURE_BINDING_2D: + case GL_TEXTURE_BINDING_CUBE_MAP: + case GL_TEXTURE_BINDING_3D: + case GL_TEXTURE_BINDING_2D_ARRAY: + if (context->getState().getActiveSampler() >= caps.maxCombinedTextureImageUnits) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + break; + + case GL_IMPLEMENTATION_COLOR_READ_TYPE: + case GL_IMPLEMENTATION_COLOR_READ_FORMAT: + { + Framebuffer *framebuffer = context->getState().getReadFramebuffer(); + ASSERT(framebuffer); + if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + FramebufferAttachment *attachment = framebuffer->getReadColorbuffer(); + if (!attachment) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + } + break; + + default: + break; + } + + // pname is valid, but there are no parameters to return + if (numParams == 0) + { + return false; + } + + return true; +} + +bool ValidateCopyTexImageParametersBase(gl::Context* context, GLenum target, GLint level, GLenum internalformat, bool isSubImage, + GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, + GLint border, GLenum *textureFormatOut) +{ + + if (!ValidTexture2DDestinationTarget(context, target)) + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + + if (level < 0 || xoffset < 0 || yoffset < 0 || zoffset < 0 || width < 0 || height < 0) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + + if (std::numeric_limits::max() - xoffset < width || std::numeric_limits::max() - yoffset < height) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + + if (border != 0) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + + if (!ValidMipLevel(context, target, level)) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + + gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer(); + if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE) + { + context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION)); + return false; + } + + if (context->getState().getReadFramebuffer()->id() != 0 && framebuffer->getSamples(context->getData()) != 0) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + const gl::Caps &caps = context->getCaps(); + + GLuint maxDimension = 0; + switch (target) + { + case GL_TEXTURE_2D: + maxDimension = caps.max2DTextureSize; + break; + + case GL_TEXTURE_CUBE_MAP_POSITIVE_X: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: + maxDimension = caps.maxCubeMapTextureSize; + break; + + case GL_TEXTURE_2D_ARRAY: + maxDimension = caps.max2DTextureSize; + break; + + case GL_TEXTURE_3D: + maxDimension = caps.max3DTextureSize; + break; + + default: + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + + gl::Texture *texture = context->getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target); + if (!texture) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + if (texture->isImmutable() && !isSubImage) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat); + + if (formatInfo.depthBits > 0) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + if (formatInfo.compressed && !ValidCompressedImageSize(context, internalformat, width, height)) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + if (isSubImage) + { + if (static_cast(xoffset + width) > texture->getWidth(target, level) || + static_cast(yoffset + height) > texture->getHeight(target, level) || + static_cast(zoffset) >= texture->getDepth(target, level)) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + } + else + { + if (IsCubeMapTextureTarget(target) && width != height) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + + if (!formatInfo.textureSupport(context->getClientVersion(), context->getExtensions())) + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + + int maxLevelDimension = (maxDimension >> level); + if (static_cast(width) > maxLevelDimension || static_cast(height) > maxLevelDimension) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + } + + *textureFormatOut = texture->getInternalFormat(target, level); + return true; +} + +static bool ValidateDrawBase(Context *context, GLenum mode, GLsizei count, GLsizei maxVertex, GLsizei primcount) +{ + switch (mode) + { + case GL_POINTS: + case GL_LINES: + case GL_LINE_LOOP: + case GL_LINE_STRIP: + case GL_TRIANGLES: + case GL_TRIANGLE_STRIP: + case GL_TRIANGLE_FAN: + break; + default: + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + + if (count < 0) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + + const State &state = context->getState(); + + // Check for mapped buffers + if (state.hasMappedBuffer(GL_ARRAY_BUFFER)) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + const gl::DepthStencilState &depthStencilState = state.getDepthStencilState(); + if (depthStencilState.stencilWritemask != depthStencilState.stencilBackWritemask || + state.getStencilRef() != state.getStencilBackRef() || + depthStencilState.stencilMask != depthStencilState.stencilBackMask) + { + // Note: these separate values are not supported in WebGL, due to D3D's limitations. + // See Section 6.10 of the WebGL 1.0 spec + ERR("This ANGLE implementation does not support separate front/back stencil " + "writemasks, reference values, or stencil mask values."); + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + const gl::Framebuffer *fbo = state.getDrawFramebuffer(); + if (!fbo || fbo->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE) + { + context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION)); + return false; + } + + gl::Program *program = state.getProgram(); + if (!program) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + if (!program->validateSamplers(NULL, context->getCaps())) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + // Buffer validations + const VertexArray *vao = state.getVertexArray(); + for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++) + { + const VertexAttribute &attrib = vao->getVertexAttribute(attributeIndex); + bool attribActive = (program->getSemanticIndex(attributeIndex) != -1); + if (attribActive && attrib.enabled) + { + gl::Buffer *buffer = attrib.buffer.get(); + + if (buffer) + { + GLint64 attribStride = static_cast(ComputeVertexAttributeStride(attrib)); + GLint64 maxVertexElement = 0; + + if (attrib.divisor > 0) + { + maxVertexElement = static_cast(primcount) / static_cast(attrib.divisor); + } + else + { + maxVertexElement = static_cast(maxVertex); + } + + GLint64 attribDataSize = maxVertexElement * attribStride; + + // [OpenGL ES 3.0.2] section 2.9.4 page 40: + // We can return INVALID_OPERATION if our vertex attribute does not have + // enough backing data. + if (attribDataSize > buffer->getSize()) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + } + else if (attrib.pointer == NULL) + { + // This is an application error that would normally result in a crash, + // but we catch it and return an error + context->recordError(Error(GL_INVALID_OPERATION, "An enabled vertex array has no buffer and no pointer.")); + return false; + } + } + } + + // Uniform buffer validation + for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < program->getActiveUniformBlockCount(); uniformBlockIndex++) + { + const gl::UniformBlock *uniformBlock = program->getUniformBlockByIndex(uniformBlockIndex); + GLuint blockBinding = program->getUniformBlockBinding(uniformBlockIndex); + const gl::Buffer *uniformBuffer = state.getIndexedUniformBuffer(blockBinding); + + if (!uniformBuffer) + { + // undefined behaviour + context->recordError(Error(GL_INVALID_OPERATION, "It is undefined behaviour to have a used but unbound uniform buffer.")); + return false; + } + + size_t uniformBufferSize = state.getIndexedUniformBufferSize(blockBinding); + + if (uniformBufferSize == 0) + { + // Bind the whole buffer. + uniformBufferSize = uniformBuffer->getSize(); + } + + if (uniformBufferSize < uniformBlock->dataSize) + { + // undefined behaviour + context->recordError(Error(GL_INVALID_OPERATION, "It is undefined behaviour to use a uniform buffer that is too small.")); + return false; + } + } + + // No-op if zero count + return (count > 0); +} + +bool ValidateDrawArrays(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount) +{ + if (first < 0) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + + const State &state = context->getState(); + gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback(); + if (curTransformFeedback && curTransformFeedback->isStarted() && !curTransformFeedback->isPaused() && + curTransformFeedback->getDrawMode() != mode) + { + // It is an invalid operation to call DrawArrays or DrawArraysInstanced with a draw mode + // that does not match the current transform feedback object's draw mode (if transform feedback + // is active), (3.0.2, section 2.14, pg 86) + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + if (!ValidateDrawBase(context, mode, count, count, primcount)) + { + return false; + } + + return true; +} + +bool ValidateDrawArraysInstanced(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount) +{ + if (primcount < 0) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + + if (!ValidateDrawArrays(context, mode, first, count, primcount)) + { + return false; + } + + // No-op if zero primitive count + return (primcount > 0); +} + +static bool ValidateDrawInstancedANGLE(Context *context) +{ + // Verify there is at least one active attribute with a divisor of zero + const gl::State& state = context->getState(); + + gl::Program *program = state.getProgram(); + + const VertexArray *vao = state.getVertexArray(); + for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++) + { + const VertexAttribute &attrib = vao->getVertexAttribute(attributeIndex); + bool active = (program->getSemanticIndex(attributeIndex) != -1); + if (active && attrib.divisor == 0) + { + return true; + } + } + + context->recordError(Error(GL_INVALID_OPERATION, "ANGLE_instanced_arrays requires that at least one active attribute" + "has a divisor of zero.")); + return false; +} + +bool ValidateDrawArraysInstancedANGLE(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount) +{ + if (!ValidateDrawInstancedANGLE(context)) + { + return false; + } + + return ValidateDrawArraysInstanced(context, mode, first, count, primcount); +} + +bool ValidateDrawElements(Context *context, GLenum mode, GLsizei count, GLenum type, + const GLvoid* indices, GLsizei primcount, rx::RangeUI *indexRangeOut) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + case GL_UNSIGNED_SHORT: + break; + case GL_UNSIGNED_INT: + if (!context->getExtensions().elementIndexUint) + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + break; + default: + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + + const State &state = context->getState(); + + gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback(); + if (curTransformFeedback && curTransformFeedback->isStarted() && !curTransformFeedback->isPaused()) + { + // It is an invalid operation to call DrawElements, DrawRangeElements or DrawElementsInstanced + // while transform feedback is active, (3.0.2, section 2.14, pg 86) + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + // Check for mapped buffers + if (state.hasMappedBuffer(GL_ELEMENT_ARRAY_BUFFER)) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + const gl::VertexArray *vao = state.getVertexArray(); + gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer(); + if (!indices && !elementArrayBuffer) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + if (elementArrayBuffer) + { + const gl::Type &typeInfo = gl::GetTypeInfo(type); + + GLint64 offset = reinterpret_cast(indices); + GLint64 byteCount = static_cast(typeInfo.bytes) * static_cast(count)+offset; + + // check for integer overflows + if (static_cast(count) > (std::numeric_limits::max() / typeInfo.bytes) || + byteCount > static_cast(std::numeric_limits::max())) + { + context->recordError(Error(GL_OUT_OF_MEMORY)); + return false; + } + + // Check for reading past the end of the bound buffer object + if (byteCount > elementArrayBuffer->getSize()) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + } + else if (!indices) + { + // Catch this programming error here + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + // Use max index to validate if our vertex buffers are large enough for the pull. + // TODO: offer fast path, with disabled index validation. + // TODO: also disable index checking on back-ends that are robust to out-of-range accesses. + if (elementArrayBuffer) + { + uintptr_t offset = reinterpret_cast(indices); + if (!elementArrayBuffer->getIndexRangeCache()->findRange(type, offset, count, indexRangeOut)) + { + rx::BufferImpl *bufferImpl = elementArrayBuffer->getImplementation(); + const uint8_t *dataPointer = NULL; + Error error = bufferImpl->getData(&dataPointer); + if (error.isError()) + { + context->recordError(error); + return false; + } + + const uint8_t *offsetPointer = dataPointer + offset; + *indexRangeOut = rx::IndexRangeCache::ComputeRange(type, offsetPointer, count); + elementArrayBuffer->getIndexRangeCache()->addRange(type, offset, count, *indexRangeOut); + } + } + else + { + *indexRangeOut = rx::IndexRangeCache::ComputeRange(type, indices, count); + } + + if (!ValidateDrawBase(context, mode, count, static_cast(indexRangeOut->end), primcount)) + { + return false; + } + + return true; +} + +bool ValidateDrawElementsInstanced(Context *context, + GLenum mode, GLsizei count, GLenum type, + const GLvoid *indices, GLsizei primcount, + rx::RangeUI *indexRangeOut) +{ + if (primcount < 0) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + + if (!ValidateDrawElements(context, mode, count, type, indices, primcount, indexRangeOut)) + { + return false; + } + + // No-op zero primitive count + return (primcount > 0); +} + +bool ValidateDrawElementsInstancedANGLE(Context *context, GLenum mode, GLsizei count, GLenum type, + const GLvoid *indices, GLsizei primcount, rx::RangeUI *indexRangeOut) +{ + if (!ValidateDrawInstancedANGLE(context)) + { + return false; + } + + return ValidateDrawElementsInstanced(context, mode, count, type, indices, primcount, indexRangeOut); +} + +bool ValidateFramebufferTextureBase(Context *context, GLenum target, GLenum attachment, + GLuint texture, GLint level) +{ + if (!ValidFramebufferTarget(target)) + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + + if (!ValidateAttachmentTarget(context, attachment)) + { + return false; + } + + if (texture != 0) + { + gl::Texture *tex = context->getTexture(texture); + + if (tex == NULL) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + if (level < 0) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + } + + const gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target); + GLuint framebufferHandle = context->getState().getTargetFramebuffer(target)->id(); + + if (framebufferHandle == 0 || !framebuffer) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + return true; +} + +bool ValidateFramebufferTexture2D(Context *context, GLenum target, GLenum attachment, + GLenum textarget, GLuint texture, GLint level) +{ + // Attachments are required to be bound to level 0 in ES2 + if (context->getClientVersion() < 3 && level != 0) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + + if (!ValidateFramebufferTextureBase(context, target, attachment, texture, level)) + { + return false; + } + + if (texture != 0) + { + gl::Texture *tex = context->getTexture(texture); + ASSERT(tex); + + const gl::Caps &caps = context->getCaps(); + + switch (textarget) + { + case GL_TEXTURE_2D: + { + if (level > gl::log2(caps.max2DTextureSize)) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + if (tex->getTarget() != GL_TEXTURE_2D) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + } + break; + + case GL_TEXTURE_CUBE_MAP_POSITIVE_X: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: + { + if (level > gl::log2(caps.maxCubeMapTextureSize)) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + if (tex->getTarget() != GL_TEXTURE_CUBE_MAP) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + } + break; + + default: + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + + const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(tex->getInternalFormat(textarget, level)); + if (internalFormatInfo.compressed) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + } + + return true; +} + +bool ValidateGetUniformBase(Context *context, GLuint program, GLint location) +{ + if (program == 0) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + + if (!ValidProgram(context, program)) + { + return false; + } + + gl::Program *programObject = context->getProgram(program); + + if (!programObject || !programObject->isLinked()) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + if (!programObject->isValidUniformLocation(location)) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + return true; +} + +bool ValidateGetUniformfv(Context *context, GLuint program, GLint location, GLfloat* params) +{ + return ValidateGetUniformBase(context, program, location); +} + +bool ValidateGetUniformiv(Context *context, GLuint program, GLint location, GLint* params) +{ + return ValidateGetUniformBase(context, program, location); +} + +static bool ValidateSizedGetUniform(Context *context, GLuint program, GLint location, GLsizei bufSize) +{ + if (!ValidateGetUniformBase(context, program, location)) + { + return false; + } + + gl::Program *programObject = context->getProgram(program); + ASSERT(programObject); + + // sized queries -- ensure the provided buffer is large enough + LinkedUniform *uniform = programObject->getUniformByLocation(location); + size_t requiredBytes = VariableExternalSize(uniform->type); + if (static_cast(bufSize) < requiredBytes) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + return true; +} + +bool ValidateGetnUniformfvEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLfloat* params) +{ + return ValidateSizedGetUniform(context, program, location, bufSize); +} + +bool ValidateGetnUniformivEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLint* params) +{ + return ValidateSizedGetUniform(context, program, location, bufSize); +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/validationES.h b/src/3rdparty/angle/src/libANGLE/validationES.h new file mode 100644 index 0000000000..b0ccd8eecc --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/validationES.h @@ -0,0 +1,94 @@ +// +// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// validationES.h: Validation functions for generic OpenGL ES entry point parameters + +#ifndef LIBANGLE_VALIDATION_ES_H_ +#define LIBANGLE_VALIDATION_ES_H_ + +#include "common/mathutil.h" + +#include +#include + +namespace gl +{ + +class Context; + +bool ValidCap(const Context *context, GLenum cap); +bool ValidTextureTarget(const Context *context, GLenum target); +bool ValidTexture2DDestinationTarget(const Context *context, GLenum target); +bool ValidFramebufferTarget(GLenum target); +bool ValidBufferTarget(const Context *context, GLenum target); +bool ValidBufferParameter(const Context *context, GLenum pname); +bool ValidMipLevel(const Context *context, GLenum target, GLint level); +bool ValidImageSize(const Context *context, GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth); +bool ValidCompressedImageSize(const Context *context, GLenum internalFormat, GLsizei width, GLsizei height); +bool ValidQueryType(const Context *context, GLenum queryType); +bool ValidProgram(Context *context, GLuint id); + +bool ValidateAttachmentTarget(Context *context, GLenum attachment); +bool ValidateRenderbufferStorageParametersBase(Context *context, GLenum target, GLsizei samples, + GLenum internalformat, GLsizei width, GLsizei height); +bool ValidateRenderbufferStorageParametersANGLE(Context *context, GLenum target, GLsizei samples, + GLenum internalformat, GLsizei width, GLsizei height); + +bool ValidateFramebufferRenderbufferParameters(Context *context, GLenum target, GLenum attachment, + GLenum renderbuffertarget, GLuint renderbuffer); + +bool ValidateBlitFramebufferParameters(Context *context, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, + GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, + GLenum filter, bool fromAngleExtension); + +bool ValidateGetVertexAttribParameters(Context *context, GLenum pname); + +bool ValidateTexParamParameters(Context *context, GLenum pname, GLint param); + +bool ValidateSamplerObjectParameter(Context *context, GLenum pname); + +bool ValidateReadPixelsParameters(Context *context, GLint x, GLint y, GLsizei width, GLsizei height, + GLenum format, GLenum type, GLsizei *bufSize, GLvoid *pixels); + +bool ValidateBeginQuery(Context *context, GLenum target, GLuint id); +bool ValidateEndQuery(Context *context, GLenum target); + +bool ValidateUniform(Context *context, GLenum uniformType, GLint location, GLsizei count); +bool ValidateUniformMatrix(Context *context, GLenum matrixType, GLint location, GLsizei count, + GLboolean transpose); + +bool ValidateStateQuery(Context *context, GLenum pname, GLenum *nativeType, unsigned int *numParams); + +bool ValidateCopyTexImageParametersBase(Context* context, GLenum target, GLint level, GLenum internalformat, bool isSubImage, + GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, + GLint border, GLenum *textureInternalFormatOut); + +bool ValidateDrawArrays(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount); +bool ValidateDrawArraysInstanced(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount); +bool ValidateDrawArraysInstancedANGLE(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount); + +bool ValidateDrawElements(Context *context, GLenum mode, GLsizei count, GLenum type, + const GLvoid* indices, GLsizei primcount, rx::RangeUI *indexRangeOut); + +bool ValidateDrawElementsInstanced(Context *context, GLenum mode, GLsizei count, GLenum type, + const GLvoid *indices, GLsizei primcount, rx::RangeUI *indexRangeOut); +bool ValidateDrawElementsInstancedANGLE(Context *context, GLenum mode, GLsizei count, GLenum type, + const GLvoid *indices, GLsizei primcount, rx::RangeUI *indexRangeOut); + +bool ValidateFramebufferTextureBase(Context *context, GLenum target, GLenum attachment, + GLuint texture, GLint level); +bool ValidateFramebufferTexture2D(Context *context, GLenum target, GLenum attachment, + GLenum textarget, GLuint texture, GLint level); + +bool ValidateGetUniformBase(Context *context, GLuint program, GLint location); +bool ValidateGetUniformfv(Context *context, GLuint program, GLint location, GLfloat* params); +bool ValidateGetUniformiv(Context *context, GLuint program, GLint location, GLint* params); +bool ValidateGetnUniformfvEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLfloat* params); +bool ValidateGetnUniformivEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLint* params); + +} + +#endif // LIBANGLE_VALIDATION_ES_H_ diff --git a/src/3rdparty/angle/src/libANGLE/validationES2.cpp b/src/3rdparty/angle/src/libANGLE/validationES2.cpp new file mode 100644 index 0000000000..9eece1b54a --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/validationES2.cpp @@ -0,0 +1,882 @@ +// +// Copyright (c) 2013-2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// validationES2.cpp: Validation functions for OpenGL ES 2.0 entry point parameters + +#include "libANGLE/validationES2.h" +#include "libANGLE/validationES.h" +#include "libANGLE/Context.h" +#include "libANGLE/Texture.h" +#include "libANGLE/Framebuffer.h" +#include "libANGLE/Renderbuffer.h" +#include "libANGLE/formatutils.h" +#include "libANGLE/FramebufferAttachment.h" + +#include "common/mathutil.h" +#include "common/utilities.h" + +namespace gl +{ + +bool ValidateES2TexImageParameters(Context *context, GLenum target, GLint level, GLenum internalformat, bool isCompressed, bool isSubImage, + GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + GLint border, GLenum format, GLenum type, const GLvoid *pixels) +{ + if (!ValidTexture2DDestinationTarget(context, target)) + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + + if (!ValidImageSize(context, target, level, width, height, 1)) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + + if (level < 0 || xoffset < 0 || + std::numeric_limits::max() - xoffset < width || + std::numeric_limits::max() - yoffset < height) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + + if (!isSubImage && !isCompressed && internalformat != format) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + const gl::Caps &caps = context->getCaps(); + + if (target == GL_TEXTURE_2D) + { + if (static_cast(width) > (caps.max2DTextureSize >> level) || + static_cast(height) > (caps.max2DTextureSize >> level)) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + } + else if (IsCubeMapTextureTarget(target)) + { + if (!isSubImage && width != height) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + + if (static_cast(width) > (caps.maxCubeMapTextureSize >> level) || + static_cast(height) > (caps.maxCubeMapTextureSize >> level)) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + } + else + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + + gl::Texture *texture = context->getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target); + if (!texture) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + if (isSubImage) + { + if (format != GL_NONE) + { + if (gl::GetSizedInternalFormat(format, type) != texture->getInternalFormat(target, level)) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + } + + if (static_cast(xoffset + width) > texture->getWidth(target, level) || + static_cast(yoffset + height) > texture->getHeight(target, level)) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + } + else + { + if (texture->isImmutable()) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + } + + // Verify zero border + if (border != 0) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + + GLenum actualInternalFormat = isSubImage ? texture->getInternalFormat(target, level) : internalformat; + const InternalFormat &actualFormatInfo = GetInternalFormatInfo(actualInternalFormat); + + if (isCompressed != actualFormatInfo.compressed) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + if (isCompressed) + { + if (!ValidCompressedImageSize(context, actualInternalFormat, width, height)) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + switch (actualInternalFormat) + { + case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: + if (!context->getExtensions().textureCompressionDXT1) + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + break; + case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: + if (!context->getExtensions().textureCompressionDXT1) + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + break; + case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: + if (!context->getExtensions().textureCompressionDXT5) + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + break; + default: + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + } + else + { + // validate by itself (used as secondary key below) + switch (type) + { + case GL_UNSIGNED_BYTE: + case GL_UNSIGNED_SHORT_5_6_5: + case GL_UNSIGNED_SHORT_4_4_4_4: + case GL_UNSIGNED_SHORT_5_5_5_1: + case GL_UNSIGNED_SHORT: + case GL_UNSIGNED_INT: + case GL_UNSIGNED_INT_24_8_OES: + case GL_HALF_FLOAT_OES: + case GL_FLOAT: + break; + default: + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + + // validate + combinations + // - invalid -> sets INVALID_ENUM + // - invalid + combination -> sets INVALID_OPERATION + switch (format) + { + case GL_ALPHA: + case GL_LUMINANCE: + case GL_LUMINANCE_ALPHA: + switch (type) + { + case GL_UNSIGNED_BYTE: + case GL_FLOAT: + case GL_HALF_FLOAT_OES: + break; + default: + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + break; + case GL_RED: + case GL_RG: + if (!context->getExtensions().textureRG) + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + switch (type) + { + case GL_UNSIGNED_BYTE: + case GL_FLOAT: + case GL_HALF_FLOAT_OES: + break; + default: + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + break; + case GL_RGB: + switch (type) + { + case GL_UNSIGNED_BYTE: + case GL_UNSIGNED_SHORT_5_6_5: + case GL_FLOAT: + case GL_HALF_FLOAT_OES: + break; + default: + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + break; + case GL_RGBA: + switch (type) + { + case GL_UNSIGNED_BYTE: + case GL_UNSIGNED_SHORT_4_4_4_4: + case GL_UNSIGNED_SHORT_5_5_5_1: + case GL_FLOAT: + case GL_HALF_FLOAT_OES: + break; + default: + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + break; + case GL_BGRA_EXT: + switch (type) + { + case GL_UNSIGNED_BYTE: + break; + default: + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + break; + case GL_SRGB_EXT: + case GL_SRGB_ALPHA_EXT: + if (!context->getExtensions().sRGB) + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + switch (type) + { + case GL_UNSIGNED_BYTE: + break; + default: + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + break; + case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: // error cases for compressed textures are handled below + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: + case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: + case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: + break; + case GL_DEPTH_COMPONENT: + switch (type) + { + case GL_UNSIGNED_SHORT: + case GL_UNSIGNED_INT: + break; + default: + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + break; + case GL_DEPTH_STENCIL_OES: + switch (type) + { + case GL_UNSIGNED_INT_24_8_OES: + break; + default: + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + break; + default: + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + + switch (format) + { + case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: + if (context->getExtensions().textureCompressionDXT1) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + else + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + break; + case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: + if (context->getExtensions().textureCompressionDXT3) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + else + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + break; + case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: + if (context->getExtensions().textureCompressionDXT5) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + else + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + break; + case GL_DEPTH_COMPONENT: + case GL_DEPTH_STENCIL_OES: + if (!context->getExtensions().depthTextures) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + if (target != GL_TEXTURE_2D) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + // OES_depth_texture supports loading depth data and multiple levels, + // but ANGLE_depth_texture does not + if (pixels != NULL || level != 0) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + break; + default: + break; + } + + if (type == GL_FLOAT) + { + if (!context->getExtensions().textureFloat) + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + } + else if (type == GL_HALF_FLOAT_OES) + { + if (!context->getExtensions().textureHalfFloat) + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + } + } + + return true; +} + + + +bool ValidateES2CopyTexImageParameters(Context* context, GLenum target, GLint level, GLenum internalformat, bool isSubImage, + GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, + GLint border) +{ + GLenum textureInternalFormat = GL_NONE; + + if (!ValidateCopyTexImageParametersBase(context, target, level, internalformat, isSubImage, + xoffset, yoffset, 0, x, y, width, height, border, &textureInternalFormat)) + { + return false; + } + + gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer(); + GLenum colorbufferFormat = framebuffer->getReadColorbuffer()->getInternalFormat(); + const auto &internalFormatInfo = gl::GetInternalFormatInfo(textureInternalFormat); + GLenum textureFormat = internalFormatInfo.format; + + // [OpenGL ES 2.0.24] table 3.9 + if (isSubImage) + { + switch (textureFormat) + { + case GL_ALPHA: + if (colorbufferFormat != GL_ALPHA8_EXT && + colorbufferFormat != GL_RGBA4 && + colorbufferFormat != GL_RGB5_A1 && + colorbufferFormat != GL_RGBA8_OES) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + break; + case GL_LUMINANCE: + if (colorbufferFormat != GL_R8_EXT && + colorbufferFormat != GL_RG8_EXT && + colorbufferFormat != GL_RGB565 && + colorbufferFormat != GL_RGB8_OES && + colorbufferFormat != GL_RGBA4 && + colorbufferFormat != GL_RGB5_A1 && + colorbufferFormat != GL_RGBA8_OES) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + break; + case GL_RED_EXT: + if (colorbufferFormat != GL_R8_EXT && + colorbufferFormat != GL_RG8_EXT && + colorbufferFormat != GL_RGB565 && + colorbufferFormat != GL_RGB8_OES && + colorbufferFormat != GL_RGBA4 && + colorbufferFormat != GL_RGB5_A1 && + colorbufferFormat != GL_RGBA8_OES && + colorbufferFormat != GL_R32F && + colorbufferFormat != GL_RG32F && + colorbufferFormat != GL_RGB32F && + colorbufferFormat != GL_RGBA32F) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + break; + case GL_RG_EXT: + if (colorbufferFormat != GL_RG8_EXT && + colorbufferFormat != GL_RGB565 && + colorbufferFormat != GL_RGB8_OES && + colorbufferFormat != GL_RGBA4 && + colorbufferFormat != GL_RGB5_A1 && + colorbufferFormat != GL_RGBA8_OES && + colorbufferFormat != GL_RG32F && + colorbufferFormat != GL_RGB32F && + colorbufferFormat != GL_RGBA32F) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + break; + case GL_RGB: + if (colorbufferFormat != GL_RGB565 && + colorbufferFormat != GL_RGB8_OES && + colorbufferFormat != GL_RGBA4 && + colorbufferFormat != GL_RGB5_A1 && + colorbufferFormat != GL_RGBA8_OES && + colorbufferFormat != GL_RGB32F && + colorbufferFormat != GL_RGBA32F) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + break; + case GL_LUMINANCE_ALPHA: + case GL_RGBA: + if (colorbufferFormat != GL_RGBA4 && + colorbufferFormat != GL_RGB5_A1 && + colorbufferFormat != GL_RGBA8_OES && + colorbufferFormat != GL_RGBA32F) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + break; + case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: + case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: + case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + case GL_DEPTH_COMPONENT: + case GL_DEPTH_STENCIL_OES: + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + default: + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + if (internalFormatInfo.type == GL_FLOAT && + !context->getExtensions().textureFloat) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + } + else + { + switch (internalformat) + { + case GL_ALPHA: + if (colorbufferFormat != GL_ALPHA8_EXT && + colorbufferFormat != GL_RGBA4 && + colorbufferFormat != GL_RGB5_A1 && + colorbufferFormat != GL_BGRA8_EXT && + colorbufferFormat != GL_RGBA8_OES && + colorbufferFormat != GL_BGR5_A1_ANGLEX) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + break; + case GL_LUMINANCE: + if (colorbufferFormat != GL_R8_EXT && + colorbufferFormat != GL_RG8_EXT && + colorbufferFormat != GL_RGB565 && + colorbufferFormat != GL_RGB8_OES && + colorbufferFormat != GL_RGBA4 && + colorbufferFormat != GL_RGB5_A1 && + colorbufferFormat != GL_BGRA8_EXT && + colorbufferFormat != GL_RGBA8_OES && + colorbufferFormat != GL_BGR5_A1_ANGLEX) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + break; + case GL_RED_EXT: + if (colorbufferFormat != GL_R8_EXT && + colorbufferFormat != GL_RG8_EXT && + colorbufferFormat != GL_RGB565 && + colorbufferFormat != GL_RGB8_OES && + colorbufferFormat != GL_RGBA4 && + colorbufferFormat != GL_RGB5_A1 && + colorbufferFormat != GL_BGRA8_EXT && + colorbufferFormat != GL_RGBA8_OES && + colorbufferFormat != GL_BGR5_A1_ANGLEX) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + break; + case GL_RG_EXT: + if (colorbufferFormat != GL_RG8_EXT && + colorbufferFormat != GL_RGB565 && + colorbufferFormat != GL_RGB8_OES && + colorbufferFormat != GL_RGBA4 && + colorbufferFormat != GL_RGB5_A1 && + colorbufferFormat != GL_BGRA8_EXT && + colorbufferFormat != GL_RGBA8_OES && + colorbufferFormat != GL_BGR5_A1_ANGLEX) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + break; + case GL_RGB: + if (colorbufferFormat != GL_RGB565 && + colorbufferFormat != GL_RGB8_OES && + colorbufferFormat != GL_RGBA4 && + colorbufferFormat != GL_RGB5_A1 && + colorbufferFormat != GL_BGRA8_EXT && + colorbufferFormat != GL_RGBA8_OES && + colorbufferFormat != GL_BGR5_A1_ANGLEX) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + break; + case GL_LUMINANCE_ALPHA: + case GL_RGBA: + if (colorbufferFormat != GL_RGBA4 && + colorbufferFormat != GL_RGB5_A1 && + colorbufferFormat != GL_BGRA8_EXT && + colorbufferFormat != GL_RGBA8_OES && + colorbufferFormat != GL_BGR5_A1_ANGLEX) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + break; + case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: + if (context->getExtensions().textureCompressionDXT1) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + else + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + break; + case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: + if (context->getExtensions().textureCompressionDXT3) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + else + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + break; + case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: + if (context->getExtensions().textureCompressionDXT5) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + else + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + break; + case GL_DEPTH_COMPONENT: + case GL_DEPTH_COMPONENT16: + case GL_DEPTH_COMPONENT32_OES: + case GL_DEPTH_STENCIL_OES: + case GL_DEPTH24_STENCIL8_OES: + if (context->getExtensions().depthTextures) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + else + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + default: + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + } + + // If width or height is zero, it is a no-op. Return false without setting an error. + return (width > 0 && height > 0); +} + +bool ValidateES2TexStorageParameters(Context *context, GLenum target, GLsizei levels, GLenum internalformat, + GLsizei width, GLsizei height) +{ + if (target != GL_TEXTURE_2D && target != GL_TEXTURE_CUBE_MAP) + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + + if (width < 1 || height < 1 || levels < 1) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + + if (target == GL_TEXTURE_CUBE_MAP && width != height) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + + if (levels != 1 && levels != gl::log2(std::max(width, height)) + 1) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat); + if (formatInfo.format == GL_NONE || formatInfo.type == GL_NONE) + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + + const gl::Caps &caps = context->getCaps(); + + switch (target) + { + case GL_TEXTURE_2D: + if (static_cast(width) > caps.max2DTextureSize || + static_cast(height) > caps.max2DTextureSize) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + break; + case GL_TEXTURE_CUBE_MAP: + if (static_cast(width) > caps.maxCubeMapTextureSize || + static_cast(height) > caps.maxCubeMapTextureSize) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + break; + default: + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + + if (levels != 1 && !context->getExtensions().textureNPOT) + { + if (!gl::isPow2(width) || !gl::isPow2(height)) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + } + + switch (internalformat) + { + case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: + if (!context->getExtensions().textureCompressionDXT1) + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + break; + case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: + if (!context->getExtensions().textureCompressionDXT3) + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + break; + case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: + if (!context->getExtensions().textureCompressionDXT5) + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + break; + case GL_RGBA32F_EXT: + case GL_RGB32F_EXT: + case GL_ALPHA32F_EXT: + case GL_LUMINANCE32F_EXT: + case GL_LUMINANCE_ALPHA32F_EXT: + if (!context->getExtensions().textureFloat) + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + break; + case GL_RGBA16F_EXT: + case GL_RGB16F_EXT: + case GL_ALPHA16F_EXT: + case GL_LUMINANCE16F_EXT: + case GL_LUMINANCE_ALPHA16F_EXT: + if (!context->getExtensions().textureHalfFloat) + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + break; + case GL_R8_EXT: + case GL_RG8_EXT: + case GL_R16F_EXT: + case GL_RG16F_EXT: + case GL_R32F_EXT: + case GL_RG32F_EXT: + if (!context->getExtensions().textureRG) + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + break; + case GL_DEPTH_COMPONENT16: + case GL_DEPTH_COMPONENT32_OES: + case GL_DEPTH24_STENCIL8_OES: + if (!context->getExtensions().depthTextures) + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + if (target != GL_TEXTURE_2D) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + // ANGLE_depth_texture only supports 1-level textures + if (levels != 1) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + break; + default: + break; + } + + gl::Texture *texture = context->getTargetTexture(target); + if (!texture || texture->id() == 0) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + if (texture->isImmutable()) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + return true; +} + +// check for combinations of format and type that are valid for ReadPixels +bool ValidES2ReadFormatType(Context *context, GLenum format, GLenum type) +{ + switch (format) + { + case GL_RGBA: + switch (type) + { + case GL_UNSIGNED_BYTE: + break; + default: + return false; + } + break; + case GL_BGRA_EXT: + switch (type) + { + case GL_UNSIGNED_BYTE: + case GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT: + case GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT: + break; + default: + return false; + } + break; + case GL_RG_EXT: + case GL_RED_EXT: + if (!context->getExtensions().textureRG) + { + return false; + } + switch (type) + { + case GL_UNSIGNED_BYTE: + break; + default: + return false; + } + break; + + default: + return false; + } + return true; +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/validationES2.h b/src/3rdparty/angle/src/libANGLE/validationES2.h new file mode 100644 index 0000000000..b9c1fd3bc4 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/validationES2.h @@ -0,0 +1,34 @@ +// +// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// validationES2.h: Validation functions for OpenGL ES 2.0 entry point parameters + +#ifndef LIBANGLE_VALIDATION_ES2_H_ +#define LIBANGLE_VALIDATION_ES2_H_ + +#include + +namespace gl +{ + +class Context; + +bool ValidateES2TexImageParameters(Context *context, GLenum target, GLint level, GLenum internalformat, bool isCompressed, bool isSubImage, + GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + GLint border, GLenum format, GLenum type, const GLvoid *pixels); + +bool ValidateES2CopyTexImageParameters(Context* context, GLenum target, GLint level, GLenum internalformat, bool isSubImage, + GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, + GLint border); + +bool ValidateES2TexStorageParameters(Context *context, GLenum target, GLsizei levels, GLenum internalformat, + GLsizei width, GLsizei height); + +bool ValidES2ReadFormatType(Context *context, GLenum format, GLenum type); + +} + +#endif // LIBANGLE_VALIDATION_ES2_H_ diff --git a/src/3rdparty/angle/src/libANGLE/validationES3.cpp b/src/3rdparty/angle/src/libANGLE/validationES3.cpp new file mode 100644 index 0000000000..e141bb6ece --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/validationES3.cpp @@ -0,0 +1,1282 @@ +// +// Copyright (c) 2013-2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// validationES3.cpp: Validation functions for OpenGL ES 3.0 entry point parameters + +#include "libANGLE/validationES3.h" +#include "libANGLE/validationES.h" +#include "libANGLE/Context.h" +#include "libANGLE/Texture.h" +#include "libANGLE/Framebuffer.h" +#include "libANGLE/Renderbuffer.h" +#include "libANGLE/formatutils.h" +#include "libANGLE/FramebufferAttachment.h" + +#include "common/mathutil.h" +#include "common/utilities.h" + +namespace gl +{ + +struct ES3FormatCombination +{ + GLenum internalFormat; + GLenum format; + GLenum type; +}; + +bool operator<(const ES3FormatCombination& a, const ES3FormatCombination& b) +{ + return memcmp(&a, &b, sizeof(ES3FormatCombination)) < 0; +} + +typedef std::set ES3FormatCombinationSet; + +static inline void InsertES3FormatCombo(ES3FormatCombinationSet *set, GLenum internalFormat, GLenum format, GLenum type) +{ + ES3FormatCombination info; + info.internalFormat = internalFormat; + info.format = format; + info.type = type; + set->insert(info); +} + +ES3FormatCombinationSet BuildES3FormatSet() +{ + ES3FormatCombinationSet set; + + // Format combinations from ES 3.0.1 spec, table 3.2 + + // | Internal format | Format | Type | + // | | | | + InsertES3FormatCombo(&set, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE ); + InsertES3FormatCombo(&set, GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_BYTE ); + InsertES3FormatCombo(&set, GL_RGBA4, GL_RGBA, GL_UNSIGNED_BYTE ); + InsertES3FormatCombo(&set, GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE ); + InsertES3FormatCombo(&set, GL_RGBA8_SNORM, GL_RGBA, GL_BYTE ); + InsertES3FormatCombo(&set, GL_RGBA4, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4 ); + InsertES3FormatCombo(&set, GL_RGB10_A2, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV ); + InsertES3FormatCombo(&set, GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV ); + InsertES3FormatCombo(&set, GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1 ); + InsertES3FormatCombo(&set, GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT ); + InsertES3FormatCombo(&set, GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT_OES ); + InsertES3FormatCombo(&set, GL_RGBA32F, GL_RGBA, GL_FLOAT ); + InsertES3FormatCombo(&set, GL_RGBA16F, GL_RGBA, GL_FLOAT ); + InsertES3FormatCombo(&set, GL_RGBA8UI, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE ); + InsertES3FormatCombo(&set, GL_RGBA8I, GL_RGBA_INTEGER, GL_BYTE ); + InsertES3FormatCombo(&set, GL_RGBA16UI, GL_RGBA_INTEGER, GL_UNSIGNED_SHORT ); + InsertES3FormatCombo(&set, GL_RGBA16I, GL_RGBA_INTEGER, GL_SHORT ); + InsertES3FormatCombo(&set, GL_RGBA32UI, GL_RGBA_INTEGER, GL_UNSIGNED_INT ); + InsertES3FormatCombo(&set, GL_RGBA32I, GL_RGBA_INTEGER, GL_INT ); + InsertES3FormatCombo(&set, GL_RGB10_A2UI, GL_RGBA_INTEGER, GL_UNSIGNED_INT_2_10_10_10_REV ); + InsertES3FormatCombo(&set, GL_RGB8, GL_RGB, GL_UNSIGNED_BYTE ); + InsertES3FormatCombo(&set, GL_RGB565, GL_RGB, GL_UNSIGNED_BYTE ); + InsertES3FormatCombo(&set, GL_SRGB8, GL_RGB, GL_UNSIGNED_BYTE ); + InsertES3FormatCombo(&set, GL_RGB8_SNORM, GL_RGB, GL_BYTE ); + InsertES3FormatCombo(&set, GL_RGB565, GL_RGB, GL_UNSIGNED_SHORT_5_6_5 ); + InsertES3FormatCombo(&set, GL_R11F_G11F_B10F, GL_RGB, GL_UNSIGNED_INT_10F_11F_11F_REV ); + InsertES3FormatCombo(&set, GL_RGB9_E5, GL_RGB, GL_UNSIGNED_INT_5_9_9_9_REV ); + InsertES3FormatCombo(&set, GL_RGB16F, GL_RGB, GL_HALF_FLOAT ); + InsertES3FormatCombo(&set, GL_RGB16F, GL_RGB, GL_HALF_FLOAT_OES ); + InsertES3FormatCombo(&set, GL_R11F_G11F_B10F, GL_RGB, GL_HALF_FLOAT ); + InsertES3FormatCombo(&set, GL_R11F_G11F_B10F, GL_RGB, GL_HALF_FLOAT_OES ); + InsertES3FormatCombo(&set, GL_RGB9_E5, GL_RGB, GL_HALF_FLOAT ); + InsertES3FormatCombo(&set, GL_RGB9_E5, GL_RGB, GL_HALF_FLOAT_OES ); + InsertES3FormatCombo(&set, GL_RGB32F, GL_RGB, GL_FLOAT ); + InsertES3FormatCombo(&set, GL_RGB16F, GL_RGB, GL_FLOAT ); + InsertES3FormatCombo(&set, GL_R11F_G11F_B10F, GL_RGB, GL_FLOAT ); + InsertES3FormatCombo(&set, GL_RGB9_E5, GL_RGB, GL_FLOAT ); + InsertES3FormatCombo(&set, GL_RGB8UI, GL_RGB_INTEGER, GL_UNSIGNED_BYTE ); + InsertES3FormatCombo(&set, GL_RGB8I, GL_RGB_INTEGER, GL_BYTE ); + InsertES3FormatCombo(&set, GL_RGB16UI, GL_RGB_INTEGER, GL_UNSIGNED_SHORT ); + InsertES3FormatCombo(&set, GL_RGB16I, GL_RGB_INTEGER, GL_SHORT ); + InsertES3FormatCombo(&set, GL_RGB32UI, GL_RGB_INTEGER, GL_UNSIGNED_INT ); + InsertES3FormatCombo(&set, GL_RGB32I, GL_RGB_INTEGER, GL_INT ); + InsertES3FormatCombo(&set, GL_RG8, GL_RG, GL_UNSIGNED_BYTE ); + InsertES3FormatCombo(&set, GL_RG8_SNORM, GL_RG, GL_BYTE ); + InsertES3FormatCombo(&set, GL_RG16F, GL_RG, GL_HALF_FLOAT ); + InsertES3FormatCombo(&set, GL_RG16F, GL_RG, GL_HALF_FLOAT_OES ); + InsertES3FormatCombo(&set, GL_RG32F, GL_RG, GL_FLOAT ); + InsertES3FormatCombo(&set, GL_RG16F, GL_RG, GL_FLOAT ); + InsertES3FormatCombo(&set, GL_RG8UI, GL_RG_INTEGER, GL_UNSIGNED_BYTE ); + InsertES3FormatCombo(&set, GL_RG8I, GL_RG_INTEGER, GL_BYTE ); + InsertES3FormatCombo(&set, GL_RG16UI, GL_RG_INTEGER, GL_UNSIGNED_SHORT ); + InsertES3FormatCombo(&set, GL_RG16I, GL_RG_INTEGER, GL_SHORT ); + InsertES3FormatCombo(&set, GL_RG32UI, GL_RG_INTEGER, GL_UNSIGNED_INT ); + InsertES3FormatCombo(&set, GL_RG32I, GL_RG_INTEGER, GL_INT ); + InsertES3FormatCombo(&set, GL_R8, GL_RED, GL_UNSIGNED_BYTE ); + InsertES3FormatCombo(&set, GL_R8_SNORM, GL_RED, GL_BYTE ); + InsertES3FormatCombo(&set, GL_R16F, GL_RED, GL_HALF_FLOAT ); + InsertES3FormatCombo(&set, GL_R16F, GL_RED, GL_HALF_FLOAT_OES ); + InsertES3FormatCombo(&set, GL_R32F, GL_RED, GL_FLOAT ); + InsertES3FormatCombo(&set, GL_R16F, GL_RED, GL_FLOAT ); + InsertES3FormatCombo(&set, GL_R8UI, GL_RED_INTEGER, GL_UNSIGNED_BYTE ); + InsertES3FormatCombo(&set, GL_R8I, GL_RED_INTEGER, GL_BYTE ); + InsertES3FormatCombo(&set, GL_R16UI, GL_RED_INTEGER, GL_UNSIGNED_SHORT ); + InsertES3FormatCombo(&set, GL_R16I, GL_RED_INTEGER, GL_SHORT ); + InsertES3FormatCombo(&set, GL_R32UI, GL_RED_INTEGER, GL_UNSIGNED_INT ); + InsertES3FormatCombo(&set, GL_R32I, GL_RED_INTEGER, GL_INT ); + + // Unsized formats + InsertES3FormatCombo(&set, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE ); + InsertES3FormatCombo(&set, GL_RGBA, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4 ); + InsertES3FormatCombo(&set, GL_RGBA, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1 ); + InsertES3FormatCombo(&set, GL_RGB, GL_RGB, GL_UNSIGNED_BYTE ); + InsertES3FormatCombo(&set, GL_RGB, GL_RGB, GL_UNSIGNED_SHORT_5_6_5 ); + InsertES3FormatCombo(&set, GL_LUMINANCE_ALPHA, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE ); + InsertES3FormatCombo(&set, GL_LUMINANCE, GL_LUMINANCE, GL_UNSIGNED_BYTE ); + InsertES3FormatCombo(&set, GL_ALPHA, GL_ALPHA, GL_UNSIGNED_BYTE ); + InsertES3FormatCombo(&set, GL_SRGB_ALPHA_EXT, GL_SRGB_ALPHA_EXT, GL_UNSIGNED_BYTE ); + InsertES3FormatCombo(&set, GL_SRGB_EXT, GL_SRGB_EXT, GL_UNSIGNED_BYTE ); + + // Depth stencil formats + InsertES3FormatCombo(&set, GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT ); + InsertES3FormatCombo(&set, GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT ); + InsertES3FormatCombo(&set, GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT ); + InsertES3FormatCombo(&set, GL_DEPTH_COMPONENT32F, GL_DEPTH_COMPONENT, GL_FLOAT ); + InsertES3FormatCombo(&set, GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8 ); + InsertES3FormatCombo(&set, GL_DEPTH32F_STENCIL8, GL_DEPTH_STENCIL, GL_FLOAT_32_UNSIGNED_INT_24_8_REV); + + // From GL_EXT_sRGB + InsertES3FormatCombo(&set, GL_SRGB8_ALPHA8_EXT, GL_SRGB_ALPHA_EXT, GL_UNSIGNED_BYTE ); + InsertES3FormatCombo(&set, GL_SRGB8, GL_SRGB_EXT, GL_UNSIGNED_BYTE ); + + // From GL_OES_texture_float + InsertES3FormatCombo(&set, GL_LUMINANCE_ALPHA, GL_LUMINANCE_ALPHA, GL_FLOAT ); + InsertES3FormatCombo(&set, GL_LUMINANCE, GL_LUMINANCE, GL_FLOAT ); + InsertES3FormatCombo(&set, GL_ALPHA, GL_ALPHA, GL_FLOAT ); + + // From GL_OES_texture_half_float + InsertES3FormatCombo(&set, GL_LUMINANCE_ALPHA, GL_LUMINANCE_ALPHA, GL_HALF_FLOAT ); + InsertES3FormatCombo(&set, GL_LUMINANCE_ALPHA, GL_LUMINANCE_ALPHA, GL_HALF_FLOAT_OES ); + InsertES3FormatCombo(&set, GL_LUMINANCE, GL_LUMINANCE, GL_HALF_FLOAT ); + InsertES3FormatCombo(&set, GL_LUMINANCE, GL_LUMINANCE, GL_HALF_FLOAT_OES ); + InsertES3FormatCombo(&set, GL_ALPHA, GL_ALPHA, GL_HALF_FLOAT ); + InsertES3FormatCombo(&set, GL_ALPHA, GL_ALPHA, GL_HALF_FLOAT_OES ); + + // From GL_EXT_texture_format_BGRA8888 + InsertES3FormatCombo(&set, GL_BGRA_EXT, GL_BGRA_EXT, GL_UNSIGNED_BYTE ); + + // From GL_EXT_texture_storage + // | Internal format | Format | Type | + // | | | | + InsertES3FormatCombo(&set, GL_ALPHA8_EXT, GL_ALPHA, GL_UNSIGNED_BYTE ); + InsertES3FormatCombo(&set, GL_LUMINANCE8_EXT, GL_LUMINANCE, GL_UNSIGNED_BYTE ); + InsertES3FormatCombo(&set, GL_LUMINANCE8_ALPHA8_EXT, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE ); + InsertES3FormatCombo(&set, GL_ALPHA32F_EXT, GL_ALPHA, GL_FLOAT ); + InsertES3FormatCombo(&set, GL_LUMINANCE32F_EXT, GL_LUMINANCE, GL_FLOAT ); + InsertES3FormatCombo(&set, GL_LUMINANCE_ALPHA32F_EXT, GL_LUMINANCE_ALPHA, GL_FLOAT ); + InsertES3FormatCombo(&set, GL_ALPHA16F_EXT, GL_ALPHA, GL_HALF_FLOAT ); + InsertES3FormatCombo(&set, GL_ALPHA16F_EXT, GL_ALPHA, GL_HALF_FLOAT_OES ); + InsertES3FormatCombo(&set, GL_LUMINANCE16F_EXT, GL_LUMINANCE, GL_HALF_FLOAT ); + InsertES3FormatCombo(&set, GL_LUMINANCE16F_EXT, GL_LUMINANCE, GL_HALF_FLOAT_OES ); + InsertES3FormatCombo(&set, GL_LUMINANCE_ALPHA16F_EXT, GL_LUMINANCE_ALPHA, GL_HALF_FLOAT ); + InsertES3FormatCombo(&set, GL_LUMINANCE_ALPHA16F_EXT, GL_LUMINANCE_ALPHA, GL_HALF_FLOAT_OES ); + + // From GL_EXT_texture_storage and GL_EXT_texture_format_BGRA8888 + InsertES3FormatCombo(&set, GL_BGRA8_EXT, GL_BGRA_EXT, GL_UNSIGNED_BYTE ); + InsertES3FormatCombo(&set, GL_BGRA4_ANGLEX, GL_BGRA_EXT, GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT); + InsertES3FormatCombo(&set, GL_BGRA4_ANGLEX, GL_BGRA_EXT, GL_UNSIGNED_BYTE ); + InsertES3FormatCombo(&set, GL_BGR5_A1_ANGLEX, GL_BGRA_EXT, GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT); + InsertES3FormatCombo(&set, GL_BGR5_A1_ANGLEX, GL_BGRA_EXT, GL_UNSIGNED_BYTE ); + + // From GL_ANGLE_depth_texture + InsertES3FormatCombo(&set, GL_DEPTH_COMPONENT32_OES, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT_24_8_OES ); + + // Compressed formats + // From ES 3.0.1 spec, table 3.16 + // | Internal format | Format | Type | + // | | | | + InsertES3FormatCombo(&set, GL_COMPRESSED_R11_EAC, GL_COMPRESSED_R11_EAC, GL_UNSIGNED_BYTE); + InsertES3FormatCombo(&set, GL_COMPRESSED_R11_EAC, GL_COMPRESSED_R11_EAC, GL_UNSIGNED_BYTE); + InsertES3FormatCombo(&set, GL_COMPRESSED_SIGNED_R11_EAC, GL_COMPRESSED_SIGNED_R11_EAC, GL_UNSIGNED_BYTE); + InsertES3FormatCombo(&set, GL_COMPRESSED_RG11_EAC, GL_COMPRESSED_RG11_EAC, GL_UNSIGNED_BYTE); + InsertES3FormatCombo(&set, GL_COMPRESSED_SIGNED_RG11_EAC, GL_COMPRESSED_SIGNED_RG11_EAC, GL_UNSIGNED_BYTE); + InsertES3FormatCombo(&set, GL_COMPRESSED_RGB8_ETC2, GL_COMPRESSED_RGB8_ETC2, GL_UNSIGNED_BYTE); + InsertES3FormatCombo(&set, GL_COMPRESSED_SRGB8_ETC2, GL_COMPRESSED_SRGB8_ETC2, GL_UNSIGNED_BYTE); + InsertES3FormatCombo(&set, GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2, GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2, GL_UNSIGNED_BYTE); + InsertES3FormatCombo(&set, GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2, GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2, GL_UNSIGNED_BYTE); + InsertES3FormatCombo(&set, GL_COMPRESSED_RGBA8_ETC2_EAC, GL_COMPRESSED_RGBA8_ETC2_EAC, GL_UNSIGNED_BYTE); + InsertES3FormatCombo(&set, GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC, GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC, GL_UNSIGNED_BYTE); + + + // From GL_EXT_texture_compression_dxt1 + InsertES3FormatCombo(&set, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_UNSIGNED_BYTE); + InsertES3FormatCombo(&set, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, GL_UNSIGNED_BYTE); + + // From GL_ANGLE_texture_compression_dxt3 + InsertES3FormatCombo(&set, GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE, GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE, GL_UNSIGNED_BYTE); + + // From GL_ANGLE_texture_compression_dxt5 + InsertES3FormatCombo(&set, GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE, GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE, GL_UNSIGNED_BYTE); + + return set; +} + +static bool ValidateTexImageFormatCombination(gl::Context *context, GLenum internalFormat, GLenum format, GLenum type) +{ + // Note: dEQP 2013.4 expects an INVALID_VALUE error for TexImage3D with an invalid + // internal format. (dEQP-GLES3.functional.negative_api.texture.teximage3d) + const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat); + if (!formatInfo.textureSupport(context->getClientVersion(), context->getExtensions())) + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + + // The type and format are valid if any supported internal format has that type and format + bool formatSupported = false; + bool typeSupported = false; + + static const ES3FormatCombinationSet es3FormatSet = BuildES3FormatSet(); + for (ES3FormatCombinationSet::const_iterator i = es3FormatSet.begin(); i != es3FormatSet.end(); i++) + { + if (i->format == format || i->type == type) + { + const gl::InternalFormat &info = gl::GetInternalFormatInfo(i->internalFormat); + bool supported = info.textureSupport(context->getClientVersion(), context->getExtensions()); + if (supported && i->type == type) + { + typeSupported = true; + } + if (supported && i->format == format) + { + formatSupported = true; + } + + // Early-out if both type and format are supported now + if (typeSupported && formatSupported) + { + break; + } + } + } + + if (!typeSupported || !formatSupported) + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + + // Check if this is a valid format combination to load texture data + ES3FormatCombination searchFormat; + searchFormat.internalFormat = internalFormat; + searchFormat.format = format; + searchFormat.type = type; + + if (es3FormatSet.find(searchFormat) == es3FormatSet.end()) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + return true; +} + +bool ValidateES3TexImageParameters(Context *context, GLenum target, GLint level, GLenum internalformat, bool isCompressed, bool isSubImage, + GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, + GLint border, GLenum format, GLenum type, const GLvoid *pixels) +{ + if (!ValidTexture2DDestinationTarget(context, target)) + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + + // Validate image size + if (!ValidImageSize(context, target, level, width, height, depth)) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + + // Verify zero border + if (border != 0) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + + if (xoffset < 0 || yoffset < 0 || zoffset < 0 || + std::numeric_limits::max() - xoffset < width || + std::numeric_limits::max() - yoffset < height || + std::numeric_limits::max() - zoffset < depth) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + + const gl::Caps &caps = context->getCaps(); + + switch (target) + { + case GL_TEXTURE_2D: + if (static_cast(width) > (caps.max2DTextureSize >> level) || + static_cast(height) > (caps.max2DTextureSize >> level)) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + break; + + case GL_TEXTURE_CUBE_MAP_POSITIVE_X: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: + if (!isSubImage && width != height) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + + if (static_cast(width) > (caps.maxCubeMapTextureSize >> level)) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + break; + + case GL_TEXTURE_3D: + if (static_cast(width) > (caps.max3DTextureSize >> level) || + static_cast(height) > (caps.max3DTextureSize >> level) || + static_cast(depth) > (caps.max3DTextureSize >> level)) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + break; + + case GL_TEXTURE_2D_ARRAY: + if (static_cast(width) > (caps.max2DTextureSize >> level) || + static_cast(height) > (caps.max2DTextureSize >> level) || + static_cast(depth) > (caps.maxArrayTextureLayers >> level)) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + break; + + default: + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + + gl::Texture *texture = context->getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target); + if (!texture) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + if (texture->isImmutable() && !isSubImage) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + // Validate texture formats + GLenum actualInternalFormat = isSubImage ? texture->getInternalFormat(target, level) : internalformat; + const gl::InternalFormat &actualFormatInfo = gl::GetInternalFormatInfo(actualInternalFormat); + if (isCompressed) + { + if (!ValidCompressedImageSize(context, actualInternalFormat, width, height)) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + if (!actualFormatInfo.compressed) + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + + if (target == GL_TEXTURE_3D) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + } + else + { + if (!ValidateTexImageFormatCombination(context, actualInternalFormat, format, type)) + { + return false; + } + + if (target == GL_TEXTURE_3D && (format == GL_DEPTH_COMPONENT || format == GL_DEPTH_STENCIL)) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + } + + // Validate sub image parameters + if (isSubImage) + { + if (isCompressed != actualFormatInfo.compressed) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + if (width == 0 || height == 0 || depth == 0) + { + return false; + } + + if (xoffset < 0 || yoffset < 0 || zoffset < 0) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + + if (std::numeric_limits::max() - xoffset < width || + std::numeric_limits::max() - yoffset < height || + std::numeric_limits::max() - zoffset < depth) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + + if (static_cast(xoffset + width) > texture->getWidth(target, level) || + static_cast(yoffset + height) > texture->getHeight(target, level) || + static_cast(zoffset + depth) > texture->getDepth(target, level)) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + } + + // Check for pixel unpack buffer related API errors + gl::Buffer *pixelUnpackBuffer = context->getState().getTargetBuffer(GL_PIXEL_UNPACK_BUFFER); + if (pixelUnpackBuffer != NULL) + { + // ...the data would be unpacked from the buffer object such that the memory reads required + // would exceed the data store size. + size_t widthSize = static_cast(width); + size_t heightSize = static_cast(height); + size_t depthSize = static_cast(depth); + GLenum sizedFormat = GetSizedInternalFormat(actualInternalFormat, type); + + size_t pixelBytes = static_cast(gl::GetInternalFormatInfo(sizedFormat).pixelBytes); + + if (!rx::IsUnsignedMultiplicationSafe(widthSize, heightSize) || + !rx::IsUnsignedMultiplicationSafe(widthSize * heightSize, depthSize) || + !rx::IsUnsignedMultiplicationSafe(widthSize * heightSize * depthSize, pixelBytes)) + { + // Overflow past the end of the buffer + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(sizedFormat); + size_t copyBytes = formatInfo.computeBlockSize(type, width, height); + size_t offset = reinterpret_cast(pixels); + + if (!rx::IsUnsignedAdditionSafe(offset, copyBytes) || + ((offset + copyBytes) > static_cast(pixelUnpackBuffer->getSize()))) + { + // Overflow past the end of the buffer + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + // ...data is not evenly divisible into the number of bytes needed to store in memory a datum + // indicated by type. + if (!isCompressed) + { + size_t dataBytesPerPixel = static_cast(gl::GetTypeInfo(type).bytes); + + if ((offset % dataBytesPerPixel) != 0) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + } + + // ...the buffer object's data store is currently mapped. + if (pixelUnpackBuffer->isMapped()) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + } + + return true; +} + +struct EffectiveInternalFormatInfo +{ + GLenum mEffectiveFormat; + GLenum mDestFormat; + GLuint mMinRedBits; + GLuint mMaxRedBits; + GLuint mMinGreenBits; + GLuint mMaxGreenBits; + GLuint mMinBlueBits; + GLuint mMaxBlueBits; + GLuint mMinAlphaBits; + GLuint mMaxAlphaBits; + + EffectiveInternalFormatInfo(GLenum effectiveFormat, GLenum destFormat, GLuint minRedBits, GLuint maxRedBits, + GLuint minGreenBits, GLuint maxGreenBits, GLuint minBlueBits, GLuint maxBlueBits, + GLuint minAlphaBits, GLuint maxAlphaBits) + : mEffectiveFormat(effectiveFormat), mDestFormat(destFormat), mMinRedBits(minRedBits), + mMaxRedBits(maxRedBits), mMinGreenBits(minGreenBits), mMaxGreenBits(maxGreenBits), + mMinBlueBits(minBlueBits), mMaxBlueBits(maxBlueBits), mMinAlphaBits(minAlphaBits), + mMaxAlphaBits(maxAlphaBits) {}; +}; + +typedef std::vector EffectiveInternalFormatList; + +static EffectiveInternalFormatList BuildSizedEffectiveInternalFormatList() +{ + EffectiveInternalFormatList list; + + // OpenGL ES 3.0.3 Specification, Table 3.17, pg 141: Effective internal format coresponding to destination internal format and + // linear source buffer component sizes. + // | Source channel min/max sizes | + // Effective Internal Format | N/A | R | G | B | A | + list.push_back(EffectiveInternalFormatInfo(GL_ALPHA8_EXT, GL_NONE, 0, 0, 0, 0, 0, 0, 1, 8)); + list.push_back(EffectiveInternalFormatInfo(GL_R8, GL_NONE, 1, 8, 0, 0, 0, 0, 0, 0)); + list.push_back(EffectiveInternalFormatInfo(GL_RG8, GL_NONE, 1, 8, 1, 8, 0, 0, 0, 0)); + list.push_back(EffectiveInternalFormatInfo(GL_RGB565, GL_NONE, 1, 5, 1, 6, 1, 5, 0, 0)); + list.push_back(EffectiveInternalFormatInfo(GL_RGB8, GL_NONE, 6, 8, 7, 8, 6, 8, 0, 0)); + list.push_back(EffectiveInternalFormatInfo(GL_RGBA4, GL_NONE, 1, 4, 1, 4, 1, 4, 1, 4)); + list.push_back(EffectiveInternalFormatInfo(GL_RGB5_A1, GL_NONE, 5, 5, 5, 5, 5, 5, 1, 1)); + list.push_back(EffectiveInternalFormatInfo(GL_RGBA8, GL_NONE, 5, 8, 5, 8, 5, 8, 2, 8)); + list.push_back(EffectiveInternalFormatInfo(GL_RGB10_A2, GL_NONE, 9, 10, 9, 10, 9, 10, 2, 2)); + + return list; +} + +static EffectiveInternalFormatList BuildUnsizedEffectiveInternalFormatList() +{ + EffectiveInternalFormatList list; + + // OpenGL ES 3.0.3 Specification, Table 3.17, pg 141: Effective internal format coresponding to destination internal format and + // linear source buffer component sizes. + // | Source channel min/max sizes | + // Effective Internal Format | Dest Format | R | G | B | A | + list.push_back(EffectiveInternalFormatInfo(GL_ALPHA8_EXT, GL_ALPHA, 0, UINT_MAX, 0, UINT_MAX, 0, UINT_MAX, 1, 8)); + list.push_back(EffectiveInternalFormatInfo(GL_LUMINANCE8_EXT, GL_LUMINANCE, 1, 8, 0, UINT_MAX, 0, UINT_MAX, 0, UINT_MAX)); + list.push_back(EffectiveInternalFormatInfo(GL_LUMINANCE8_ALPHA8_EXT, GL_LUMINANCE_ALPHA, 1, 8, 0, UINT_MAX, 0, UINT_MAX, 1, 8)); + list.push_back(EffectiveInternalFormatInfo(GL_RGB565, GL_RGB, 1, 5, 1, 6, 1, 5, 0, UINT_MAX)); + list.push_back(EffectiveInternalFormatInfo(GL_RGB8, GL_RGB, 6, 8, 7, 8, 6, 8, 0, UINT_MAX)); + list.push_back(EffectiveInternalFormatInfo(GL_RGBA4, GL_RGBA, 1, 4, 1, 4, 1, 4, 1, 4)); + list.push_back(EffectiveInternalFormatInfo(GL_RGB5_A1, GL_RGBA, 5, 5, 5, 5, 5, 5, 1, 1)); + list.push_back(EffectiveInternalFormatInfo(GL_RGBA8, GL_RGBA, 5, 8, 5, 8, 5, 8, 5, 8)); + + return list; +} + +static bool GetEffectiveInternalFormat(const InternalFormat &srcFormat, const InternalFormat &destFormat, + GLenum *outEffectiveFormat) +{ + const EffectiveInternalFormatList *list = NULL; + GLenum targetFormat = GL_NONE; + + if (destFormat.pixelBytes > 0) + { + static const EffectiveInternalFormatList sizedList = BuildSizedEffectiveInternalFormatList(); + list = &sizedList; + } + else + { + static const EffectiveInternalFormatList unsizedList = BuildUnsizedEffectiveInternalFormatList(); + list = &unsizedList; + targetFormat = destFormat.format; + } + + for (size_t curFormat = 0; curFormat < list->size(); ++curFormat) + { + const EffectiveInternalFormatInfo& formatInfo = list->at(curFormat); + if ((formatInfo.mDestFormat == targetFormat) && + (formatInfo.mMinRedBits <= srcFormat.redBits && formatInfo.mMaxRedBits >= srcFormat.redBits) && + (formatInfo.mMinGreenBits <= srcFormat.greenBits && formatInfo.mMaxGreenBits >= srcFormat.greenBits) && + (formatInfo.mMinBlueBits <= srcFormat.blueBits && formatInfo.mMaxBlueBits >= srcFormat.blueBits) && + (formatInfo.mMinAlphaBits <= srcFormat.alphaBits && formatInfo.mMaxAlphaBits >= srcFormat.alphaBits)) + { + *outEffectiveFormat = formatInfo.mEffectiveFormat; + return true; + } + } + + return false; +} + +struct CopyConversion +{ + GLenum mTextureFormat; + GLenum mFramebufferFormat; + + CopyConversion(GLenum textureFormat, GLenum framebufferFormat) + : mTextureFormat(textureFormat), mFramebufferFormat(framebufferFormat) { } + + bool operator<(const CopyConversion& other) const + { + return memcmp(this, &other, sizeof(CopyConversion)) < 0; + } +}; + +typedef std::set CopyConversionSet; + +static CopyConversionSet BuildValidES3CopyTexImageCombinations() +{ + CopyConversionSet set; + + // From ES 3.0.1 spec, table 3.15 + set.insert(CopyConversion(GL_ALPHA, GL_RGBA)); + set.insert(CopyConversion(GL_LUMINANCE, GL_RED)); + set.insert(CopyConversion(GL_LUMINANCE, GL_RG)); + set.insert(CopyConversion(GL_LUMINANCE, GL_RGB)); + set.insert(CopyConversion(GL_LUMINANCE, GL_RGBA)); + set.insert(CopyConversion(GL_LUMINANCE_ALPHA, GL_RGBA)); + set.insert(CopyConversion(GL_RED, GL_RED)); + set.insert(CopyConversion(GL_RED, GL_RG)); + set.insert(CopyConversion(GL_RED, GL_RGB)); + set.insert(CopyConversion(GL_RED, GL_RGBA)); + set.insert(CopyConversion(GL_RG, GL_RG)); + set.insert(CopyConversion(GL_RG, GL_RGB)); + set.insert(CopyConversion(GL_RG, GL_RGBA)); + set.insert(CopyConversion(GL_RGB, GL_RGB)); + set.insert(CopyConversion(GL_RGB, GL_RGBA)); + set.insert(CopyConversion(GL_RGBA, GL_RGBA)); + + // Necessary for ANGLE back-buffers + set.insert(CopyConversion(GL_ALPHA, GL_BGRA_EXT)); + set.insert(CopyConversion(GL_LUMINANCE, GL_BGRA_EXT)); + set.insert(CopyConversion(GL_LUMINANCE_ALPHA, GL_BGRA_EXT)); + set.insert(CopyConversion(GL_RED, GL_BGRA_EXT)); + set.insert(CopyConversion(GL_RG, GL_BGRA_EXT)); + set.insert(CopyConversion(GL_RGB, GL_BGRA_EXT)); + set.insert(CopyConversion(GL_RGBA, GL_BGRA_EXT)); + + set.insert(CopyConversion(GL_RED_INTEGER, GL_RED_INTEGER)); + set.insert(CopyConversion(GL_RED_INTEGER, GL_RG_INTEGER)); + set.insert(CopyConversion(GL_RED_INTEGER, GL_RGB_INTEGER)); + set.insert(CopyConversion(GL_RED_INTEGER, GL_RGBA_INTEGER)); + set.insert(CopyConversion(GL_RG_INTEGER, GL_RG_INTEGER)); + set.insert(CopyConversion(GL_RG_INTEGER, GL_RGB_INTEGER)); + set.insert(CopyConversion(GL_RG_INTEGER, GL_RGBA_INTEGER)); + set.insert(CopyConversion(GL_RGB_INTEGER, GL_RGB_INTEGER)); + set.insert(CopyConversion(GL_RGB_INTEGER, GL_RGBA_INTEGER)); + set.insert(CopyConversion(GL_RGBA_INTEGER, GL_RGBA_INTEGER)); + + return set; +} + +static bool IsValidES3CopyTexImageCombination(GLenum textureInternalFormat, GLenum frameBufferInternalFormat, GLuint readBufferHandle) +{ + const InternalFormat &textureInternalFormatInfo = GetInternalFormatInfo(textureInternalFormat); + const InternalFormat &framebufferInternalFormatInfo = GetInternalFormatInfo(frameBufferInternalFormat); + + static const CopyConversionSet conversionSet = BuildValidES3CopyTexImageCombinations(); + if (conversionSet.find(CopyConversion(textureInternalFormatInfo.format, framebufferInternalFormatInfo.format)) != conversionSet.end()) + { + // Section 3.8.5 of the GLES 3.0.3 spec states that source and destination formats + // must both be signed, unsigned, or fixed point and both source and destinations + // must be either both SRGB or both not SRGB. EXT_color_buffer_float adds allowed + // conversion between fixed and floating point. + + if ((textureInternalFormatInfo.colorEncoding == GL_SRGB) != (framebufferInternalFormatInfo.colorEncoding == GL_SRGB)) + { + return false; + } + + if (((textureInternalFormatInfo.componentType == GL_INT) != (framebufferInternalFormatInfo.componentType == GL_INT )) || + ((textureInternalFormatInfo.componentType == GL_UNSIGNED_INT) != (framebufferInternalFormatInfo.componentType == GL_UNSIGNED_INT))) + { + return false; + } + + if ((textureInternalFormatInfo.componentType == GL_UNSIGNED_NORMALIZED || + textureInternalFormatInfo.componentType == GL_SIGNED_NORMALIZED || + textureInternalFormatInfo.componentType == GL_FLOAT) && + !(framebufferInternalFormatInfo.componentType == GL_UNSIGNED_NORMALIZED || + framebufferInternalFormatInfo.componentType == GL_SIGNED_NORMALIZED || + framebufferInternalFormatInfo.componentType == GL_FLOAT)) + { + return false; + } + + // GLES specification 3.0.3, sec 3.8.5, pg 139-140: + // The effective internal format of the source buffer is determined with the following rules applied in order: + // * If the source buffer is a texture or renderbuffer that was created with a sized internal format then the + // effective internal format is the source buffer's sized internal format. + // * If the source buffer is a texture that was created with an unsized base internal format, then the + // effective internal format is the source image array's effective internal format, as specified by table + // 3.12, which is determined from the and that were used when the source image array was + // specified by TexImage*. + // * Otherwise the effective internal format is determined by the row in table 3.17 or 3.18 where + // Destination Internal Format matches internalformat and where the [source channel sizes] are consistent + // with the values of the source buffer's [channel sizes]. Table 3.17 is used if the + // FRAMEBUFFER_ATTACHMENT_ENCODING is LINEAR and table 3.18 is used if the FRAMEBUFFER_ATTACHMENT_ENCODING + // is SRGB. + const InternalFormat *sourceEffectiveFormat = NULL; + if (readBufferHandle != 0) + { + // Not the default framebuffer, therefore the read buffer must be a user-created texture or renderbuffer + if (framebufferInternalFormatInfo.pixelBytes > 0) + { + sourceEffectiveFormat = &framebufferInternalFormatInfo; + } + else + { + // Renderbuffers cannot be created with an unsized internal format, so this must be an unsized-format + // texture. We can use the same table we use when creating textures to get its effective sized format. + GLenum sizedInternalFormat = GetSizedInternalFormat(framebufferInternalFormatInfo.format, framebufferInternalFormatInfo.type); + sourceEffectiveFormat = &GetInternalFormatInfo(sizedInternalFormat); + } + } + else + { + // The effective internal format must be derived from the source framebuffer's channel sizes. + // This is done in GetEffectiveInternalFormat for linear buffers (table 3.17) + if (framebufferInternalFormatInfo.colorEncoding == GL_LINEAR) + { + GLenum effectiveFormat; + if (GetEffectiveInternalFormat(framebufferInternalFormatInfo, textureInternalFormatInfo, &effectiveFormat)) + { + sourceEffectiveFormat = &GetInternalFormatInfo(effectiveFormat); + } + else + { + return false; + } + } + else if (framebufferInternalFormatInfo.colorEncoding == GL_SRGB) + { + // SRGB buffers can only be copied to sized format destinations according to table 3.18 + if ((textureInternalFormatInfo.pixelBytes > 0) && + (framebufferInternalFormatInfo.redBits >= 1 && framebufferInternalFormatInfo.redBits <= 8) && + (framebufferInternalFormatInfo.greenBits >= 1 && framebufferInternalFormatInfo.greenBits <= 8) && + (framebufferInternalFormatInfo.blueBits >= 1 && framebufferInternalFormatInfo.blueBits <= 8) && + (framebufferInternalFormatInfo.alphaBits >= 1 && framebufferInternalFormatInfo.alphaBits <= 8)) + { + sourceEffectiveFormat = &GetInternalFormatInfo(GL_SRGB8_ALPHA8); + } + else + { + return false; + } + } + else + { + UNREACHABLE(); + return false; + } + } + + if (textureInternalFormatInfo.pixelBytes > 0) + { + // Section 3.8.5 of the GLES 3.0.3 spec, pg 139, requires that, if the destination format is sized, + // component sizes of the source and destination formats must exactly match + if (textureInternalFormatInfo.redBits != sourceEffectiveFormat->redBits || + textureInternalFormatInfo.greenBits != sourceEffectiveFormat->greenBits || + textureInternalFormatInfo.blueBits != sourceEffectiveFormat->blueBits || + textureInternalFormatInfo.alphaBits != sourceEffectiveFormat->alphaBits) + { + return false; + } + } + + + return true; // A conversion function exists, and no rule in the specification has precluded conversion + // between these formats. + } + + return false; +} + +bool ValidateES3CopyTexImageParameters(Context *context, GLenum target, GLint level, GLenum internalformat, + bool isSubImage, GLint xoffset, GLint yoffset, GLint zoffset, + GLint x, GLint y, GLsizei width, GLsizei height, GLint border) +{ + GLenum textureInternalFormat; + if (!ValidateCopyTexImageParametersBase(context, target, level, internalformat, isSubImage, + xoffset, yoffset, zoffset, x, y, width, height, + border, &textureInternalFormat)) + { + return false; + } + + gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer(); + + if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE) + { + context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION)); + return false; + } + + if (context->getState().getReadFramebuffer()->id() != 0 && + framebuffer->getSamples(context->getData()) != 0) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + gl::FramebufferAttachment *source = framebuffer->getReadColorbuffer(); + GLenum colorbufferInternalFormat = source->getInternalFormat(); + + if (isSubImage) + { + if (!IsValidES3CopyTexImageCombination(textureInternalFormat, colorbufferInternalFormat, + context->getState().getReadFramebuffer()->id())) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + } + else + { + if (!gl::IsValidES3CopyTexImageCombination(internalformat, colorbufferInternalFormat, + context->getState().getReadFramebuffer()->id())) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + } + + // If width or height is zero, it is a no-op. Return false without setting an error. + return (width > 0 && height > 0); +} + +bool ValidateES3TexStorageParameters(Context *context, GLenum target, GLsizei levels, GLenum internalformat, + GLsizei width, GLsizei height, GLsizei depth) +{ + if (width < 1 || height < 1 || depth < 1 || levels < 1) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + + if (levels > gl::log2(std::max(std::max(width, height), depth)) + 1) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + const gl::Caps &caps = context->getCaps(); + + switch (target) + { + case GL_TEXTURE_2D: + { + if (static_cast(width) > caps.max2DTextureSize || + static_cast(height) > caps.max2DTextureSize) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + } + break; + + case GL_TEXTURE_CUBE_MAP: + { + if (width != height) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + + if (static_cast(width) > caps.maxCubeMapTextureSize) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + } + break; + + case GL_TEXTURE_3D: + { + if (static_cast(width) > caps.max3DTextureSize || + static_cast(height) > caps.max3DTextureSize || + static_cast(depth) > caps.max3DTextureSize) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + } + break; + + case GL_TEXTURE_2D_ARRAY: + { + if (static_cast(width) > caps.max2DTextureSize || + static_cast(height) > caps.max2DTextureSize || + static_cast(depth) > caps.maxArrayTextureLayers) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + } + break; + + default: + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + + gl::Texture *texture = context->getTargetTexture(target); + if (!texture || texture->id() == 0) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + if (texture->isImmutable()) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat); + if (!formatInfo.textureSupport(context->getClientVersion(), context->getExtensions())) + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + + if (formatInfo.pixelBytes == 0) + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + + return true; +} + +bool ValidateFramebufferTextureLayer(Context *context, GLenum target, GLenum attachment, + GLuint texture, GLint level, GLint layer) +{ + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + if (layer < 0) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + + if (!ValidateFramebufferTextureBase(context, target, attachment, texture, level)) + { + return false; + } + + const gl::Caps &caps = context->getCaps(); + if (texture != 0) + { + gl::Texture *tex = context->getTexture(texture); + ASSERT(tex); + + switch (tex->getTarget()) + { + case GL_TEXTURE_2D_ARRAY: + { + if (level > gl::log2(caps.max2DTextureSize)) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + + if (static_cast(layer) >= caps.maxArrayTextureLayers) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + } + break; + + case GL_TEXTURE_3D: + { + if (level > gl::log2(caps.max3DTextureSize)) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + + if (static_cast(layer) >= caps.max3DTextureSize) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + } + break; + + default: + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(tex->getInternalFormat(tex->getTarget(), level)); + if (internalFormatInfo.compressed) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + } + + return true; +} + +bool ValidES3ReadFormatType(Context *context, GLenum internalFormat, GLenum format, GLenum type) +{ + const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(internalFormat); + + switch (format) + { + case GL_RGBA: + switch (type) + { + case GL_UNSIGNED_BYTE: + break; + case GL_UNSIGNED_INT_2_10_10_10_REV: + if (internalFormat != GL_RGB10_A2) + { + return false; + } + break; + case GL_FLOAT: + if (internalFormatInfo.componentType != GL_FLOAT) + { + return false; + } + break; + default: + return false; + } + break; + case GL_RGBA_INTEGER: + switch (type) + { + case GL_INT: + if (internalFormatInfo.componentType != GL_INT) + { + return false; + } + break; + case GL_UNSIGNED_INT: + if (internalFormatInfo.componentType != GL_UNSIGNED_INT) + { + return false; + } + break; + default: + return false; + } + break; + case GL_BGRA_EXT: + switch (type) + { + case GL_UNSIGNED_BYTE: + case GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT: + case GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT: + break; + default: + return false; + } + break; + case GL_RG_EXT: + case GL_RED_EXT: + if (!context->getExtensions().textureRG) + { + return false; + } + switch (type) + { + case GL_UNSIGNED_BYTE: + break; + default: + return false; + } + break; + default: + return false; + } + return true; +} + +bool ValidateES3RenderbufferStorageParameters(gl::Context *context, GLenum target, GLsizei samples, + GLenum internalformat, GLsizei width, GLsizei height) +{ + if (!ValidateRenderbufferStorageParametersBase(context, target, samples, internalformat, width, height)) + { + return false; + } + + //The ES3 spec(section 4.4.2) states that the internal format must be sized and not an integer format if samples is greater than zero. + const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat); + if ((formatInfo.componentType == GL_UNSIGNED_INT || formatInfo.componentType == GL_INT) && samples > 0) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + // The behavior is different than the ANGLE version, which would generate a GL_OUT_OF_MEMORY. + const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat); + if (static_cast(samples) > formatCaps.getMaxSamples()) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + + return true; +} + +bool ValidateInvalidateFramebufferParameters(Context *context, GLenum target, GLsizei numAttachments, + const GLenum* attachments) +{ + bool defaultFramebuffer = false; + + switch (target) + { + case GL_DRAW_FRAMEBUFFER: + case GL_FRAMEBUFFER: + defaultFramebuffer = context->getState().getDrawFramebuffer()->id() == 0; + break; + case GL_READ_FRAMEBUFFER: + defaultFramebuffer = context->getState().getReadFramebuffer()->id() == 0; + break; + default: + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + + for (int i = 0; i < numAttachments; ++i) + { + if (attachments[i] >= GL_COLOR_ATTACHMENT0 && attachments[i] <= GL_COLOR_ATTACHMENT15) + { + if (defaultFramebuffer) + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + + if (attachments[i] >= GL_COLOR_ATTACHMENT0 + context->getCaps().maxColorAttachments) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + } + else + { + switch (attachments[i]) + { + case GL_DEPTH_ATTACHMENT: + case GL_STENCIL_ATTACHMENT: + case GL_DEPTH_STENCIL_ATTACHMENT: + if (defaultFramebuffer) + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + break; + case GL_COLOR: + case GL_DEPTH: + case GL_STENCIL: + if (!defaultFramebuffer) + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + break; + default: + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + } + } + + return true; +} + +bool ValidateClearBuffer(Context *context) +{ + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + const gl::Framebuffer *fbo = context->getState().getDrawFramebuffer(); + if (!fbo || fbo->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE) + { + context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION)); + return false; + } + + return true; +} + +bool ValidateGetUniformuiv(Context *context, GLuint program, GLint location, GLuint* params) +{ + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + return ValidateGetUniformBase(context, program, location); +} + +bool ValidateReadBuffer(Context *context, GLenum src) +{ + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + Framebuffer *readFBO = context->getState().getReadFramebuffer(); + + if (readFBO == nullptr) + { + context->recordError(gl::Error(GL_INVALID_OPERATION, "No active read framebuffer.")); + return false; + } + + if (src == GL_NONE) + { + return true; + } + + if (src != GL_BACK && (src < GL_COLOR_ATTACHMENT0 || src > GL_COLOR_ATTACHMENT15)) + { + context->recordError(gl::Error(GL_INVALID_ENUM, "Unknown enum for 'src' in ReadBuffer")); + return false; + } + + if (readFBO->id() == 0) + { + if (src != GL_BACK) + { + const char *errorMsg = "'src' must be GL_NONE or GL_BACK when reading from the default framebuffer."; + context->recordError(gl::Error(GL_INVALID_OPERATION, errorMsg)); + return false; + } + } + else + { + GLuint drawBuffer = static_cast(src - GL_COLOR_ATTACHMENT0); + + if (drawBuffer >= context->getCaps().maxDrawBuffers) + { + const char *errorMsg = "'src' is greater than MAX_DRAW_BUFFERS."; + context->recordError(gl::Error(GL_INVALID_OPERATION, errorMsg)); + return false; + } + } + + return true; +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/validationES3.h b/src/3rdparty/angle/src/libANGLE/validationES3.h new file mode 100644 index 0000000000..517cb5d27f --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/validationES3.h @@ -0,0 +1,49 @@ +// +// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// validationES3.h: Validation functions for OpenGL ES 3.0 entry point parameters + +#ifndef LIBANGLE_VALIDATION_ES3_H_ +#define LIBANGLE_VALIDATION_ES3_H_ + +#include + +namespace gl +{ + +class Context; + +bool ValidateES3TexImageParameters(Context *context, GLenum target, GLint level, GLenum internalformat, bool isCompressed, bool isSubImage, + GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, + GLint border, GLenum format, GLenum type, const GLvoid *pixels); + +bool ValidateES3CopyTexImageParameters(Context *context, GLenum target, GLint level, GLenum internalformat, + bool isSubImage, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, + GLsizei width, GLsizei height, GLint border); + +bool ValidateES3TexStorageParameters(Context *context, GLenum target, GLsizei levels, GLenum internalformat, + GLsizei width, GLsizei height, GLsizei depth); + +bool ValidateFramebufferTextureLayer(Context *context, GLenum target, GLenum attachment, + GLuint texture, GLint level, GLint layer); + +bool ValidES3ReadFormatType(Context *context, GLenum internalFormat, GLenum format, GLenum type); + +bool ValidateES3RenderbufferStorageParameters(Context *context, GLenum target, GLsizei samples, + GLenum internalformat, GLsizei width, GLsizei height); + +bool ValidateInvalidateFramebufferParameters(Context *context, GLenum target, GLsizei numAttachments, + const GLenum* attachments); + +bool ValidateClearBuffer(Context *context); + +bool ValidateGetUniformuiv(Context *context, GLuint program, GLint location, GLuint* params); + +bool ValidateReadBuffer(Context *context, GLenum mode); + +} + +#endif // LIBANGLE_VALIDATION_ES3_H_ -- cgit v1.2.3