From 0a7aebadfbb3534284546aa3ca8612314c08f136 Mon Sep 17 00:00:00 2001 From: Miguel Costa Date: Tue, 26 Jun 2018 16:56:45 +0200 Subject: Update ANGLE to chromium/3280 Change-Id: I0802c0d7486f772d361f87a544d6c5af937f4ca1 Reviewed-by: Friedemann Kleint --- src/3rdparty/angle/src/libANGLE/AttributeMap.cpp | 85 +- src/3rdparty/angle/src/libANGLE/AttributeMap.h | 22 +- src/3rdparty/angle/src/libANGLE/BinaryStream.h | 97 +- src/3rdparty/angle/src/libANGLE/Buffer.cpp | 187 +- src/3rdparty/angle/src/libANGLE/Buffer.h | 100 +- src/3rdparty/angle/src/libANGLE/Caps.cpp | 940 ++- src/3rdparty/angle/src/libANGLE/Caps.h | 291 +- src/3rdparty/angle/src/libANGLE/Compiler.cpp | 143 +- src/3rdparty/angle/src/libANGLE/Compiler.h | 20 +- src/3rdparty/angle/src/libANGLE/Config.cpp | 36 +- src/3rdparty/angle/src/libANGLE/Config.h | 11 +- src/3rdparty/angle/src/libANGLE/Constants.h | 40 +- src/3rdparty/angle/src/libANGLE/Context.cpp | 5714 ++++++++++++---- src/3rdparty/angle/src/libANGLE/Context.h | 1039 ++- src/3rdparty/angle/src/libANGLE/ContextState.cpp | 839 +++ src/3rdparty/angle/src/libANGLE/ContextState.h | 164 + src/3rdparty/angle/src/libANGLE/Data.cpp | 56 - src/3rdparty/angle/src/libANGLE/Data.h | 72 - src/3rdparty/angle/src/libANGLE/Debug.cpp | 24 + src/3rdparty/angle/src/libANGLE/Debug.h | 9 + src/3rdparty/angle/src/libANGLE/Device.cpp | 21 +- src/3rdparty/angle/src/libANGLE/Display.cpp | 812 ++- src/3rdparty/angle/src/libANGLE/Display.h | 124 +- src/3rdparty/angle/src/libANGLE/Error.cpp | 58 +- src/3rdparty/angle/src/libANGLE/Error.h | 205 +- src/3rdparty/angle/src/libANGLE/Error.inl | 32 +- src/3rdparty/angle/src/libANGLE/ErrorStrings.h | 173 + src/3rdparty/angle/src/libANGLE/Fence.cpp | 48 +- src/3rdparty/angle/src/libANGLE/Fence.h | 16 +- src/3rdparty/angle/src/libANGLE/Framebuffer.cpp | 2109 +++++- src/3rdparty/angle/src/libANGLE/Framebuffer.h | 319 +- .../angle/src/libANGLE/FramebufferAttachment.cpp | 227 +- .../angle/src/libANGLE/FramebufferAttachment.h | 186 +- .../angle/src/libANGLE/HandleAllocator.cpp | 34 +- src/3rdparty/angle/src/libANGLE/HandleAllocator.h | 8 +- .../angle/src/libANGLE/HandleRangeAllocator.cpp | 229 + .../angle/src/libANGLE/HandleRangeAllocator.h | 60 + src/3rdparty/angle/src/libANGLE/Image.cpp | 205 +- src/3rdparty/angle/src/libANGLE/Image.h | 66 +- src/3rdparty/angle/src/libANGLE/ImageIndex.cpp | 130 +- src/3rdparty/angle/src/libANGLE/ImageIndex.h | 14 +- .../angle/src/libANGLE/IndexRangeCache.cpp | 8 + src/3rdparty/angle/src/libANGLE/IndexRangeCache.h | 3 + .../angle/src/libANGLE/LoggingAnnotator.cpp | 44 + src/3rdparty/angle/src/libANGLE/LoggingAnnotator.h | 31 + .../angle/src/libANGLE/MemoryProgramCache.cpp | 772 +++ .../angle/src/libANGLE/MemoryProgramCache.h | 130 + src/3rdparty/angle/src/libANGLE/PackedGLEnums.h | 111 + .../angle/src/libANGLE/PackedGLEnums_autogen.cpp | 174 + .../angle/src/libANGLE/PackedGLEnums_autogen.h | 84 + src/3rdparty/angle/src/libANGLE/Path.cpp | 78 + src/3rdparty/angle/src/libANGLE/Path.h | 71 + src/3rdparty/angle/src/libANGLE/Platform.cpp | 56 +- src/3rdparty/angle/src/libANGLE/Program.cpp | 2897 ++++---- src/3rdparty/angle/src/libANGLE/Program.h | 641 +- .../angle/src/libANGLE/ProgramLinkedResources.cpp | 1040 +++ .../angle/src/libANGLE/ProgramLinkedResources.h | 274 + .../angle/src/libANGLE/ProgramPipeline.cpp | 65 + src/3rdparty/angle/src/libANGLE/ProgramPipeline.h | 65 + src/3rdparty/angle/src/libANGLE/Query.h | 3 +- src/3rdparty/angle/src/libANGLE/RefCountObject.cpp | 39 - src/3rdparty/angle/src/libANGLE/RefCountObject.h | 88 +- src/3rdparty/angle/src/libANGLE/Renderbuffer.cpp | 147 +- src/3rdparty/angle/src/libANGLE/Renderbuffer.h | 43 +- .../angle/src/libANGLE/ResourceManager.cpp | 603 +- src/3rdparty/angle/src/libANGLE/ResourceManager.h | 298 +- src/3rdparty/angle/src/libANGLE/ResourceMap.h | 305 + src/3rdparty/angle/src/libANGLE/Sampler.cpp | 73 +- src/3rdparty/angle/src/libANGLE/Sampler.h | 19 +- src/3rdparty/angle/src/libANGLE/Shader.cpp | 373 +- src/3rdparty/angle/src/libANGLE/Shader.h | 216 +- src/3rdparty/angle/src/libANGLE/SizedMRUCache.h | 174 + src/3rdparty/angle/src/libANGLE/State.cpp | 1260 +++- src/3rdparty/angle/src/libANGLE/State.h | 348 +- src/3rdparty/angle/src/libANGLE/Stream.cpp | 271 + src/3rdparty/angle/src/libANGLE/Stream.h | 143 + src/3rdparty/angle/src/libANGLE/Surface.cpp | 369 +- src/3rdparty/angle/src/libANGLE/Surface.h | 163 +- src/3rdparty/angle/src/libANGLE/Texture.cpp | 1509 +++-- src/3rdparty/angle/src/libANGLE/Texture.h | 359 +- src/3rdparty/angle/src/libANGLE/Thread.cpp | 91 + src/3rdparty/angle/src/libANGLE/Thread.h | 51 + .../angle/src/libANGLE/TransformFeedback.cpp | 159 +- .../angle/src/libANGLE/TransformFeedback.h | 61 +- src/3rdparty/angle/src/libANGLE/Uniform.cpp | 185 +- src/3rdparty/angle/src/libANGLE/Uniform.h | 100 +- src/3rdparty/angle/src/libANGLE/VaryingPacking.cpp | 408 ++ src/3rdparty/angle/src/libANGLE/VaryingPacking.h | 184 + src/3rdparty/angle/src/libANGLE/Version.h | 15 +- src/3rdparty/angle/src/libANGLE/Version.inl | 38 +- src/3rdparty/angle/src/libANGLE/VertexArray.cpp | 235 +- src/3rdparty/angle/src/libANGLE/VertexArray.h | 188 +- .../angle/src/libANGLE/VertexAttribute.cpp | 122 +- src/3rdparty/angle/src/libANGLE/VertexAttribute.h | 84 +- .../angle/src/libANGLE/VertexAttribute.inl | 47 +- src/3rdparty/angle/src/libANGLE/Workarounds.h | 29 + src/3rdparty/angle/src/libANGLE/WorkerThread.cpp | 157 + src/3rdparty/angle/src/libANGLE/WorkerThread.h | 284 + src/3rdparty/angle/src/libANGLE/angletypes.cpp | 162 +- src/3rdparty/angle/src/libANGLE/angletypes.h | 307 +- src/3rdparty/angle/src/libANGLE/angletypes.inl | 47 +- .../angle/src/libANGLE/entry_points_enum_autogen.h | 336 + .../src/libANGLE/es3_copy_conversion_formats.json | 44 + .../libANGLE/es3_copy_conversion_table_autogen.cpp | 171 + .../src/libANGLE/es3_format_type_combinations.json | 171 + src/3rdparty/angle/src/libANGLE/features.h | 12 + .../angle/src/libANGLE/format_map_autogen.cpp | 1570 +++++ .../angle/src/libANGLE/format_map_data.json | 142 + src/3rdparty/angle/src/libANGLE/formatutils.cpp | 1365 ++-- src/3rdparty/angle/src/libANGLE/formatutils.h | 141 +- src/3rdparty/angle/src/libANGLE/histogram_macros.h | 67 +- .../angle/src/libANGLE/packed_gl_enums.json | 35 + src/3rdparty/angle/src/libANGLE/params.cpp | 68 + src/3rdparty/angle/src/libANGLE/params.h | 228 + .../angle/src/libANGLE/queryconversions.cpp | 206 +- src/3rdparty/angle/src/libANGLE/queryconversions.h | 87 +- src/3rdparty/angle/src/libANGLE/queryutils.cpp | 1916 ++++++ src/3rdparty/angle/src/libANGLE/queryutils.h | 162 + .../angle/src/libANGLE/renderer/BufferImpl.h | 49 +- .../angle/src/libANGLE/renderer/BufferImpl_mock.h | 32 +- .../angle/src/libANGLE/renderer/ContextImpl.cpp | 119 + .../angle/src/libANGLE/renderer/ContextImpl.h | 186 + .../angle/src/libANGLE/renderer/DisplayImpl.cpp | 25 +- .../angle/src/libANGLE/renderer/DisplayImpl.h | 60 +- .../angle/src/libANGLE/renderer/EGLImplFactory.h | 68 + .../angle/src/libANGLE/renderer/FenceSyncImpl.h | 35 - src/3rdparty/angle/src/libANGLE/renderer/Format.h | 105 + .../src/libANGLE/renderer/Format_ID_autogen.inl | 147 + .../src/libANGLE/renderer/Format_table_autogen.cpp | 434 ++ .../renderer/FramebufferAttachmentObjectImpl.h | 54 + .../angle/src/libANGLE/renderer/FramebufferImpl.h | 65 +- .../src/libANGLE/renderer/FramebufferImpl_mock.h | 57 +- .../angle/src/libANGLE/renderer/GLImplFactory.h | 93 + src/3rdparty/angle/src/libANGLE/renderer/Image.h | 77 - .../angle/src/libANGLE/renderer/ImageImpl.h | 16 +- .../angle/src/libANGLE/renderer/ImageImpl_mock.h | 10 +- .../angle/src/libANGLE/renderer/ImplFactory.h | 74 - .../angle/src/libANGLE/renderer/PathImpl.h | 36 + .../angle/src/libANGLE/renderer/ProgramImpl.cpp | 152 - .../angle/src/libANGLE/renderer/ProgramImpl.h | 66 +- .../angle/src/libANGLE/renderer/ProgramImpl_mock.h | 27 +- .../src/libANGLE/renderer/ProgramPipelineImpl.h | 32 + .../src/libANGLE/renderer/RenderbufferImpl.cpp | 21 - .../angle/src/libANGLE/renderer/RenderbufferImpl.h | 24 +- .../src/libANGLE/renderer/RenderbufferImpl_mock.h | 15 +- .../angle/src/libANGLE/renderer/Renderer.cpp | 62 - .../angle/src/libANGLE/renderer/Renderer.h | 121 - .../angle/src/libANGLE/renderer/SamplerImpl.h | 20 +- .../angle/src/libANGLE/renderer/ShaderImpl.h | 12 +- .../src/libANGLE/renderer/StreamProducerImpl.h | 39 + .../angle/src/libANGLE/renderer/SurfaceImpl.cpp | 8 +- .../angle/src/libANGLE/renderer/SurfaceImpl.h | 35 +- .../angle/src/libANGLE/renderer/SyncImpl.h | 34 + .../angle/src/libANGLE/renderer/TextureImpl.cpp | 63 + .../angle/src/libANGLE/renderer/TextureImpl.h | 136 +- .../angle/src/libANGLE/renderer/TextureImpl_mock.h | 116 +- .../src/libANGLE/renderer/TransformFeedbackImpl.h | 9 +- .../libANGLE/renderer/TransformFeedbackImpl_mock.h | 8 +- .../angle/src/libANGLE/renderer/VertexArrayImpl.h | 14 +- .../angle/src/libANGLE/renderer/Workarounds.h | 74 - .../src/libANGLE/renderer/angle_format_data.json | 24 + .../src/libANGLE/renderer/angle_format_map.json | 132 + .../angle/src/libANGLE/renderer/d3d/BufferD3D.cpp | 208 +- .../angle/src/libANGLE/renderer/d3d/BufferD3D.h | 54 +- .../src/libANGLE/renderer/d3d/CompilerD3D.cpp | 10 + .../angle/src/libANGLE/renderer/d3d/CompilerD3D.h | 4 +- .../angle/src/libANGLE/renderer/d3d/DeviceD3D.cpp | 27 +- .../angle/src/libANGLE/renderer/d3d/DeviceD3D.h | 2 +- .../angle/src/libANGLE/renderer/d3d/DisplayD3D.cpp | 195 +- .../angle/src/libANGLE/renderer/d3d/DisplayD3D.h | 43 +- .../src/libANGLE/renderer/d3d/DynamicHLSL.cpp | 714 +- .../angle/src/libANGLE/renderer/d3d/DynamicHLSL.h | 123 +- .../src/libANGLE/renderer/d3d/EGLImageD3D.cpp | 89 +- .../angle/src/libANGLE/renderer/d3d/EGLImageD3D.h | 27 +- .../src/libANGLE/renderer/d3d/FramebufferD3D.cpp | 305 +- .../src/libANGLE/renderer/d3d/FramebufferD3D.h | 83 +- .../src/libANGLE/renderer/d3d/HLSLCompiler.cpp | 86 +- .../angle/src/libANGLE/renderer/d3d/HLSLCompiler.h | 12 +- .../angle/src/libANGLE/renderer/d3d/ImageD3D.cpp | 30 + .../angle/src/libANGLE/renderer/d3d/ImageD3D.h | 45 +- .../src/libANGLE/renderer/d3d/IndexBuffer.cpp | 27 +- .../angle/src/libANGLE/renderer/d3d/IndexBuffer.h | 4 +- .../src/libANGLE/renderer/d3d/IndexDataManager.cpp | 250 +- .../src/libANGLE/renderer/d3d/IndexDataManager.h | 42 +- .../src/libANGLE/renderer/d3d/NativeWindowD3D.cpp | 23 + .../src/libANGLE/renderer/d3d/NativeWindowD3D.h | 38 + .../angle/src/libANGLE/renderer/d3d/ProgramD3D.cpp | 2199 +++--- .../angle/src/libANGLE/renderer/d3d/ProgramD3D.h | 329 +- .../src/libANGLE/renderer/d3d/RenderTargetD3D.h | 6 +- .../src/libANGLE/renderer/d3d/RenderbufferD3D.cpp | 77 +- .../src/libANGLE/renderer/d3d/RenderbufferD3D.h | 25 +- .../src/libANGLE/renderer/d3d/RendererD3D.cpp | 703 +- .../angle/src/libANGLE/renderer/d3d/RendererD3D.h | 391 +- .../angle/src/libANGLE/renderer/d3d/SamplerD3D.h | 2 +- .../angle/src/libANGLE/renderer/d3d/ShaderD3D.cpp | 100 +- .../angle/src/libANGLE/renderer/d3d/ShaderD3D.h | 44 +- .../libANGLE/renderer/d3d/ShaderExecutableD3D.cpp | 16 +- .../libANGLE/renderer/d3d/ShaderExecutableD3D.h | 7 +- .../angle/src/libANGLE/renderer/d3d/SurfaceD3D.cpp | 274 +- .../angle/src/libANGLE/renderer/d3d/SurfaceD3D.h | 97 +- .../src/libANGLE/renderer/d3d/SwapChainD3D.cpp | 34 + .../angle/src/libANGLE/renderer/d3d/SwapChainD3D.h | 55 +- .../angle/src/libANGLE/renderer/d3d/TextureD3D.cpp | 3108 ++++++--- .../angle/src/libANGLE/renderer/d3d/TextureD3D.h | 864 ++- .../src/libANGLE/renderer/d3d/TextureStorage.cpp | 39 - .../src/libANGLE/renderer/d3d/TextureStorage.h | 44 +- .../libANGLE/renderer/d3d/TransformFeedbackD3D.cpp | 46 - .../libANGLE/renderer/d3d/TransformFeedbackD3D.h | 35 - .../src/libANGLE/renderer/d3d/VaryingPacking.cpp | 397 -- .../src/libANGLE/renderer/d3d/VaryingPacking.h | 175 - .../src/libANGLE/renderer/d3d/VertexBuffer.cpp | 347 +- .../angle/src/libANGLE/renderer/d3d/VertexBuffer.h | 116 +- .../libANGLE/renderer/d3d/VertexDataManager.cpp | 750 ++- .../src/libANGLE/renderer/d3d/VertexDataManager.h | 108 +- .../src/libANGLE/renderer/d3d/WorkaroundsD3D.h | 66 - .../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 | 2486 ++++--- .../angle/src/libANGLE/renderer/d3d/d3d11/Blit11.h | 230 +- .../src/libANGLE/renderer/d3d/d3d11/Buffer11.cpp | 1379 ++-- .../src/libANGLE/renderer/d3d/d3d11/Buffer11.h | 174 +- .../src/libANGLE/renderer/d3d/d3d11/Clear11.cpp | 1152 ++-- .../src/libANGLE/renderer/d3d/d3d11/Clear11.h | 105 +- .../src/libANGLE/renderer/d3d/d3d11/Context11.cpp | 405 ++ .../src/libANGLE/renderer/d3d/d3d11/Context11.h | 155 + .../renderer/d3d/d3d11/DebugAnnotator11.cpp | 47 +- .../libANGLE/renderer/d3d/d3d11/DebugAnnotator11.h | 6 +- .../src/libANGLE/renderer/d3d/d3d11/Fence11.cpp | 107 +- .../src/libANGLE/renderer/d3d/d3d11/Fence11.h | 11 +- .../libANGLE/renderer/d3d/d3d11/Framebuffer11.cpp | 461 +- .../libANGLE/renderer/d3d/d3d11/Framebuffer11.h | 78 +- .../src/libANGLE/renderer/d3d/d3d11/Image11.cpp | 591 +- .../src/libANGLE/renderer/d3d/d3d11/Image11.h | 67 +- .../libANGLE/renderer/d3d/d3d11/IndexBuffer11.cpp | 62 +- .../libANGLE/renderer/d3d/d3d11/IndexBuffer11.h | 23 +- .../renderer/d3d/d3d11/InputLayoutCache.cpp | 464 +- .../libANGLE/renderer/d3d/d3d11/InputLayoutCache.h | 142 +- .../src/libANGLE/renderer/d3d/d3d11/NativeWindow.h | 97 - .../libANGLE/renderer/d3d/d3d11/NativeWindow11.h | 38 + .../renderer/d3d/d3d11/PixelTransfer11.cpp | 205 +- .../libANGLE/renderer/d3d/d3d11/PixelTransfer11.h | 34 +- .../renderer/d3d/d3d11/ProgramPipeline11.cpp | 24 + .../renderer/d3d/d3d11/ProgramPipeline11.h | 27 + .../src/libANGLE/renderer/d3d/d3d11/Query11.cpp | 363 +- .../src/libANGLE/renderer/d3d/d3d11/Query11.h | 47 +- .../renderer/d3d/d3d11/RenderStateCache.cpp | 521 +- .../libANGLE/renderer/d3d/d3d11/RenderStateCache.h | 137 +- .../libANGLE/renderer/d3d/d3d11/RenderTarget11.cpp | 359 +- .../libANGLE/renderer/d3d/d3d11/RenderTarget11.h | 90 +- .../src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp | 4140 ++++++------ .../src/libANGLE/renderer/d3d/d3d11/Renderer11.h | 573 +- .../renderer/d3d/d3d11/ResourceManager11.cpp | 533 ++ .../renderer/d3d/d3d11/ResourceManager11.h | 366 + .../renderer/d3d/d3d11/ShaderExecutable11.cpp | 111 +- .../renderer/d3d/d3d11/ShaderExecutable11.h | 45 +- .../libANGLE/renderer/d3d/d3d11/StateManager11.cpp | 2817 ++++++-- .../libANGLE/renderer/d3d/d3d11/StateManager11.h | 484 +- .../renderer/d3d/d3d11/StreamProducerNV12.cpp | 102 + .../renderer/d3d/d3d11/StreamProducerNV12.h | 44 + .../libANGLE/renderer/d3d/d3d11/SwapChain11.cpp | 756 ++- .../src/libANGLE/renderer/d3d/d3d11/SwapChain11.h | 123 +- .../renderer/d3d/d3d11/TextureStorage11.cpp | 3713 ++++++----- .../libANGLE/renderer/d3d/d3d11/TextureStorage11.h | 555 +- .../renderer/d3d/d3d11/TransformFeedback11.cpp | 124 + .../renderer/d3d/d3d11/TransformFeedback11.h | 60 + .../src/libANGLE/renderer/d3d/d3d11/Trim11.cpp | 9 +- .../angle/src/libANGLE/renderer/d3d/d3d11/Trim11.h | 4 +- .../libANGLE/renderer/d3d/d3d11/VertexArray11.cpp | 413 ++ .../libANGLE/renderer/d3d/d3d11/VertexArray11.h | 82 +- .../libANGLE/renderer/d3d/d3d11/VertexBuffer11.cpp | 149 +- .../libANGLE/renderer/d3d/d3d11/VertexBuffer11.h | 25 +- .../src/libANGLE/renderer/d3d/d3d11/copyvertex.inl | 45 +- .../renderer/d3d/d3d11/dxgi_format_data.json | 118 + .../renderer/d3d/d3d11/dxgi_format_map_autogen.cpp | 516 ++ .../renderer/d3d/d3d11/dxgi_support_data.json | 623 +- .../renderer/d3d/d3d11/dxgi_support_table.cpp | 1902 +++++- .../renderer/d3d/d3d11/dxgi_support_table.h | 5 + .../libANGLE/renderer/d3d/d3d11/formatutils11.cpp | 1142 ++-- .../libANGLE/renderer/d3d/d3d11/formatutils11.h | 56 +- .../d3d/d3d11/gen_load_functions_table.cpp | 0 .../d3d11/internal_format_initializer_table.cpp | 170 - .../d3d/d3d11/internal_format_initializer_table.h | 31 - .../renderer/d3d/d3d11/load_functions_data.json | 1116 ---- .../renderer/d3d/d3d11/load_functions_table.h | 31 - .../d3d/d3d11/load_functions_table_autogen.cpp | 2098 ------ .../renderer/d3d/d3d11/renderer11_utils.cpp | 2667 +++++--- .../libANGLE/renderer/d3d/d3d11/renderer11_utils.h | 375 +- .../renderer/d3d/d3d11/shaders/Clear11.hlsl | 644 +- .../renderer/d3d/d3d11/shaders/MultiplyAlpha.hlsl | 131 + .../d3d/d3d11/shaders/Passthrough2D11.hlsl | 11 + .../d3d/d3d11/shaders/ResolveDepthStencil.hlsl | 56 + .../shaders/compiled/passthroughrgba2dms11ps.h | 155 + .../renderer/d3d/d3d11/swizzle_format_data.json | 77 - .../renderer/d3d/d3d11/swizzle_format_info.h | 51 - .../d3d/d3d11/swizzle_format_info_autogen.cpp | 203 - .../renderer/d3d/d3d11/texture_format_data.json | 1199 ++-- .../renderer/d3d/d3d11/texture_format_map.json | 78 + .../renderer/d3d/d3d11/texture_format_table.cpp | 35 + .../renderer/d3d/d3d11/texture_format_table.h | 89 +- .../d3d/d3d11/texture_format_table_autogen.cpp | 3037 +++++---- .../d3d/d3d11/texture_format_table_utils.h | 85 + .../renderer/d3d/d3d11/win32/NativeWindow.cpp | 220 - .../d3d/d3d11/win32/NativeWindow11Win32.cpp | 217 + .../renderer/d3d/d3d11/win32/NativeWindow11Win32.h | 53 + .../d3d/d3d11/winrt/CoreWindowNativeWindow.cpp | 67 +- .../d3d/d3d11/winrt/CoreWindowNativeWindow.h | 48 +- .../d3d/d3d11/winrt/InspectableNativeWindow.cpp | 131 +- .../d3d/d3d11/winrt/InspectableNativeWindow.h | 38 +- .../d3d/d3d11/winrt/NativeWindow11WinRT.cpp | 126 + .../renderer/d3d/d3d11/winrt/NativeWindow11WinRT.h | 51 + .../d3d/d3d11/winrt/SwapChainPanelNativeWindow.cpp | 63 +- .../d3d/d3d11/winrt/SwapChainPanelNativeWindow.h | 10 +- .../angle/src/libANGLE/renderer/d3d/d3d9/Blit9.cpp | 410 +- .../angle/src/libANGLE/renderer/d3d/d3d9/Blit9.h | 84 +- .../src/libANGLE/renderer/d3d/d3d9/Buffer9.cpp | 82 +- .../angle/src/libANGLE/renderer/d3d/d3d9/Buffer9.h | 46 +- .../src/libANGLE/renderer/d3d/d3d9/Context9.cpp | 303 + .../src/libANGLE/renderer/d3d/d3d9/Context9.h | 151 + .../libANGLE/renderer/d3d/d3d9/DebugAnnotator9.h | 4 +- .../src/libANGLE/renderer/d3d/d3d9/Fence9.cpp | 19 +- .../angle/src/libANGLE/renderer/d3d/d3d9/Fence9.h | 2 +- .../libANGLE/renderer/d3d/d3d9/Framebuffer9.cpp | 201 +- .../src/libANGLE/renderer/d3d/d3d9/Framebuffer9.h | 38 +- .../src/libANGLE/renderer/d3d/d3d9/Image9.cpp | 303 +- .../angle/src/libANGLE/renderer/d3d/d3d9/Image9.h | 50 +- .../libANGLE/renderer/d3d/d3d9/IndexBuffer9.cpp | 33 +- .../src/libANGLE/renderer/d3d/d3d9/IndexBuffer9.h | 16 +- .../libANGLE/renderer/d3d/d3d9/NativeWindow9.cpp | 39 + .../src/libANGLE/renderer/d3d/d3d9/NativeWindow9.h | 35 + .../src/libANGLE/renderer/d3d/d3d9/Query9.cpp | 76 +- .../angle/src/libANGLE/renderer/d3d/d3d9/Query9.h | 20 +- .../libANGLE/renderer/d3d/d3d9/RenderTarget9.cpp | 3 +- .../src/libANGLE/renderer/d3d/d3d9/RenderTarget9.h | 6 +- .../src/libANGLE/renderer/d3d/d3d9/Renderer9.cpp | 2164 +++--- .../src/libANGLE/renderer/d3d/d3d9/Renderer9.h | 407 +- .../src/libANGLE/renderer/d3d/d3d9/ShaderCache.h | 10 +- .../renderer/d3d/d3d9/ShaderExecutable9.cpp | 6 +- .../libANGLE/renderer/d3d/d3d9/ShaderExecutable9.h | 2 +- .../libANGLE/renderer/d3d/d3d9/StateManager9.cpp | 98 +- .../src/libANGLE/renderer/d3d/d3d9/StateManager9.h | 13 +- .../src/libANGLE/renderer/d3d/d3d9/SwapChain9.cpp | 123 +- .../src/libANGLE/renderer/d3d/d3d9/SwapChain9.h | 30 +- .../libANGLE/renderer/d3d/d3d9/TextureStorage9.cpp | 219 +- .../libANGLE/renderer/d3d/d3d9/TextureStorage9.h | 84 +- .../src/libANGLE/renderer/d3d/d3d9/VertexArray9.h | 24 +- .../libANGLE/renderer/d3d/d3d9/VertexBuffer9.cpp | 94 +- .../src/libANGLE/renderer/d3d/d3d9/VertexBuffer9.h | 18 +- .../renderer/d3d/d3d9/VertexDeclarationCache.cpp | 46 +- .../renderer/d3d/d3d9/VertexDeclarationCache.h | 1 + .../libANGLE/renderer/d3d/d3d9/formatutils9.cpp | 321 +- .../src/libANGLE/renderer/d3d/d3d9/formatutils9.h | 26 +- .../libANGLE/renderer/d3d/d3d9/renderer9_utils.cpp | 104 +- .../libANGLE/renderer/d3d/d3d9/renderer9_utils.h | 11 +- .../src/libANGLE/renderer/d3d/d3d9/shaders/Blit.ps | 34 + .../src/libANGLE/renderer/d3d/d3d9/shaders/Blit.vs | 18 +- .../src/libANGLE/renderer/d3d/formatutilsD3D.cpp | 147 - .../src/libANGLE/renderer/d3d/formatutilsD3D.h | 28 +- .../angle/src/libANGLE/renderer/d3d/generatemip.h | 28 - .../src/libANGLE/renderer/d3d/generatemip.inl | 266 - .../angle/src/libANGLE/renderer/d3d/imageformats.h | 1999 ------ .../angle/src/libANGLE/renderer/d3d/loadimage.cpp | 697 -- .../angle/src/libANGLE/renderer/d3d/loadimage.h | 201 - .../angle/src/libANGLE/renderer/d3d/loadimage.inl | 156 - .../src/libANGLE/renderer/d3d/loadimageSSE2.cpp | 125 - .../src/libANGLE/renderer/d3d/loadimage_etc.cpp | 1435 ---- .../src/libANGLE/renderer/d3d/loadimage_etc.h | 140 - .../angle/src/libANGLE/renderer/driver_utils.cpp | 120 + .../angle/src/libANGLE/renderer/driver_utils.h | 73 + .../src/libANGLE/renderer/load_functions_data.json | 602 ++ .../src/libANGLE/renderer/load_functions_table.h | 22 + .../renderer/load_functions_table_autogen.cpp | 2459 +++++++ .../angle/src/libANGLE/renderer/renderer_utils.cpp | 549 ++ .../angle/src/libANGLE/renderer/renderer_utils.h | 254 + src/3rdparty/angle/src/libANGLE/signal_utils.h | 187 + src/3rdparty/angle/src/libANGLE/validationEGL.cpp | 2019 +++++- src/3rdparty/angle/src/libANGLE/validationEGL.h | 119 +- src/3rdparty/angle/src/libANGLE/validationES.cpp | 6645 +++++++++++++----- src/3rdparty/angle/src/libANGLE/validationES.h | 573 +- src/3rdparty/angle/src/libANGLE/validationES2.cpp | 7047 ++++++++++++++++---- src/3rdparty/angle/src/libANGLE/validationES2.h | 607 +- src/3rdparty/angle/src/libANGLE/validationES3.cpp | 3580 +++++++--- src/3rdparty/angle/src/libANGLE/validationES3.h | 415 +- src/3rdparty/angle/src/libANGLE/validationES31.cpp | 1786 +++++ src/3rdparty/angle/src/libANGLE/validationES31.h | 325 + 385 files changed, 91766 insertions(+), 43654 deletions(-) create mode 100644 src/3rdparty/angle/src/libANGLE/ContextState.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/ContextState.h delete mode 100644 src/3rdparty/angle/src/libANGLE/Data.cpp delete mode 100644 src/3rdparty/angle/src/libANGLE/Data.h create mode 100644 src/3rdparty/angle/src/libANGLE/ErrorStrings.h create mode 100644 src/3rdparty/angle/src/libANGLE/HandleRangeAllocator.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/HandleRangeAllocator.h create mode 100644 src/3rdparty/angle/src/libANGLE/LoggingAnnotator.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/LoggingAnnotator.h create mode 100644 src/3rdparty/angle/src/libANGLE/MemoryProgramCache.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/MemoryProgramCache.h create mode 100644 src/3rdparty/angle/src/libANGLE/PackedGLEnums.h create mode 100644 src/3rdparty/angle/src/libANGLE/PackedGLEnums_autogen.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/PackedGLEnums_autogen.h create mode 100644 src/3rdparty/angle/src/libANGLE/Path.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/Path.h create mode 100644 src/3rdparty/angle/src/libANGLE/ProgramLinkedResources.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/ProgramLinkedResources.h create mode 100644 src/3rdparty/angle/src/libANGLE/ProgramPipeline.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/ProgramPipeline.h delete mode 100644 src/3rdparty/angle/src/libANGLE/RefCountObject.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/ResourceMap.h create mode 100644 src/3rdparty/angle/src/libANGLE/SizedMRUCache.h create mode 100644 src/3rdparty/angle/src/libANGLE/Stream.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/Stream.h create mode 100644 src/3rdparty/angle/src/libANGLE/Thread.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/Thread.h create mode 100644 src/3rdparty/angle/src/libANGLE/VaryingPacking.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/VaryingPacking.h create mode 100644 src/3rdparty/angle/src/libANGLE/Workarounds.h create mode 100644 src/3rdparty/angle/src/libANGLE/WorkerThread.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/WorkerThread.h create mode 100644 src/3rdparty/angle/src/libANGLE/entry_points_enum_autogen.h create mode 100644 src/3rdparty/angle/src/libANGLE/es3_copy_conversion_formats.json create mode 100644 src/3rdparty/angle/src/libANGLE/es3_copy_conversion_table_autogen.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/es3_format_type_combinations.json create mode 100644 src/3rdparty/angle/src/libANGLE/format_map_autogen.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/format_map_data.json create mode 100644 src/3rdparty/angle/src/libANGLE/packed_gl_enums.json create mode 100644 src/3rdparty/angle/src/libANGLE/params.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/params.h create mode 100644 src/3rdparty/angle/src/libANGLE/queryutils.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/queryutils.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/ContextImpl.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/ContextImpl.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/EGLImplFactory.h delete mode 100644 src/3rdparty/angle/src/libANGLE/renderer/FenceSyncImpl.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/Format.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/Format_ID_autogen.inl create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/Format_table_autogen.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/FramebufferAttachmentObjectImpl.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/GLImplFactory.h delete mode 100644 src/3rdparty/angle/src/libANGLE/renderer/Image.h delete mode 100644 src/3rdparty/angle/src/libANGLE/renderer/ImplFactory.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/PathImpl.h delete mode 100644 src/3rdparty/angle/src/libANGLE/renderer/ProgramImpl.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/ProgramPipelineImpl.h delete mode 100644 src/3rdparty/angle/src/libANGLE/renderer/RenderbufferImpl.cpp delete mode 100644 src/3rdparty/angle/src/libANGLE/renderer/Renderer.cpp delete mode 100644 src/3rdparty/angle/src/libANGLE/renderer/Renderer.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/StreamProducerImpl.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/SyncImpl.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/TextureImpl.cpp delete mode 100644 src/3rdparty/angle/src/libANGLE/renderer/Workarounds.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/angle_format_data.json create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/angle_format_map.json create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/NativeWindowD3D.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/NativeWindowD3D.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/SwapChainD3D.cpp delete mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/TextureStorage.cpp delete mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/TransformFeedbackD3D.cpp delete mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/TransformFeedbackD3D.h delete mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/VaryingPacking.cpp delete mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/VaryingPacking.h delete mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/WorkaroundsD3D.h delete mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/copyimage.cpp delete mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/copyimage.h delete mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/copyimage.inl create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Context11.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Context11.h delete mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/NativeWindow.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/NativeWindow11.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/ProgramPipeline11.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/ProgramPipeline11.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/ResourceManager11.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/ResourceManager11.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/StreamProducerNV12.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/StreamProducerNV12.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/TransformFeedback11.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/TransformFeedback11.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/VertexArray11.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/dxgi_format_data.json create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/dxgi_format_map_autogen.cpp delete mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/gen_load_functions_table.cpp delete mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/internal_format_initializer_table.cpp delete mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/internal_format_initializer_table.h delete mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/load_functions_data.json delete mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/load_functions_table.h delete mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/load_functions_table_autogen.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/shaders/MultiplyAlpha.hlsl create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/shaders/ResolveDepthStencil.hlsl create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrgba2dms11ps.h delete mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/swizzle_format_data.json delete mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/swizzle_format_info.h delete mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/swizzle_format_info_autogen.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/texture_format_map.json create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/texture_format_table.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/texture_format_table_utils.h delete mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/win32/NativeWindow.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/win32/NativeWindow11Win32.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/win32/NativeWindow11Win32.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/NativeWindow11WinRT.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/NativeWindow11WinRT.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Context9.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Context9.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/NativeWindow9.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/NativeWindow9.h delete mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/formatutilsD3D.cpp delete mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/generatemip.h delete mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/generatemip.inl delete mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/imageformats.h delete mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/loadimage.cpp delete mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/loadimage.h delete mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/loadimage.inl delete mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/loadimageSSE2.cpp delete mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/loadimage_etc.cpp delete mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/loadimage_etc.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/driver_utils.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/driver_utils.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/load_functions_data.json create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/load_functions_table.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/load_functions_table_autogen.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/renderer_utils.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/renderer_utils.h create mode 100644 src/3rdparty/angle/src/libANGLE/signal_utils.h create mode 100644 src/3rdparty/angle/src/libANGLE/validationES31.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/validationES31.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 index 651a012037..e10d3add7c 100644 --- a/src/3rdparty/angle/src/libANGLE/AttributeMap.cpp +++ b/src/3rdparty/angle/src/libANGLE/AttributeMap.cpp @@ -6,6 +6,8 @@ #include "libANGLE/AttributeMap.h" +#include "common/debug.h" + namespace egl { @@ -13,33 +15,61 @@ 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]); - } - } -} +AttributeMap::AttributeMap(const AttributeMap &other) = default; -void AttributeMap::insert(EGLint key, EGLint value) +AttributeMap::~AttributeMap() = default; + +void AttributeMap::insert(EGLAttrib key, EGLAttrib value) { mAttributes[key] = value; } -bool AttributeMap::contains(EGLint key) const +bool AttributeMap::contains(EGLAttrib key) const { return (mAttributes.find(key) != mAttributes.end()); } -EGLint AttributeMap::get(EGLint key, EGLint defaultValue) const +EGLAttrib AttributeMap::get(EGLAttrib key) const +{ + auto iter = mAttributes.find(key); + ASSERT(iter != mAttributes.end()); + return iter->second; +} + +EGLAttrib AttributeMap::get(EGLAttrib key, EGLAttrib defaultValue) const { - std::map::const_iterator iter = mAttributes.find(key); + auto iter = mAttributes.find(key); return (mAttributes.find(key) != mAttributes.end()) ? iter->second : defaultValue; } +EGLint AttributeMap::getAsInt(EGLAttrib key) const +{ + return static_cast(get(key)); +} + +EGLint AttributeMap::getAsInt(EGLAttrib key, EGLint defaultValue) const +{ + return static_cast(get(key, static_cast(defaultValue))); +} + +bool AttributeMap::isEmpty() const +{ + return mAttributes.empty(); +} + +std::vector AttributeMap::toIntVector() const +{ + std::vector ret; + for (const auto &pair : mAttributes) + { + ret.push_back(static_cast(pair.first)); + ret.push_back(static_cast(pair.second)); + } + ret.push_back(EGL_NONE); + + return ret; +} + AttributeMap::const_iterator AttributeMap::begin() const { return mAttributes.begin(); @@ -50,4 +80,31 @@ AttributeMap::const_iterator AttributeMap::end() const return mAttributes.end(); } +// static +AttributeMap AttributeMap::CreateFromIntArray(const EGLint *attributes) +{ + AttributeMap map; + if (attributes) + { + for (const EGLint *curAttrib = attributes; curAttrib[0] != EGL_NONE; curAttrib += 2) + { + map.insert(static_cast(curAttrib[0]), static_cast(curAttrib[1])); + } + } + return map; +} + +// static +AttributeMap AttributeMap::CreateFromAttribArray(const EGLAttrib *attributes) +{ + AttributeMap map; + if (attributes) + { + for (const EGLAttrib *curAttrib = attributes; curAttrib[0] != EGL_NONE; curAttrib += 2) + { + map.insert(curAttrib[0], curAttrib[1]); + } + } + return map; +} } diff --git a/src/3rdparty/angle/src/libANGLE/AttributeMap.h b/src/3rdparty/angle/src/libANGLE/AttributeMap.h index 56f1684415..eddc1b72d0 100644 --- a/src/3rdparty/angle/src/libANGLE/AttributeMap.h +++ b/src/3rdparty/angle/src/libANGLE/AttributeMap.h @@ -11,6 +11,7 @@ #include #include +#include namespace egl { @@ -19,19 +20,28 @@ class AttributeMap final { public: AttributeMap(); - explicit AttributeMap(const EGLint *attributes); + AttributeMap(const AttributeMap &other); + ~AttributeMap(); - void insert(EGLint key, EGLint value); - bool contains(EGLint key) const; - EGLint get(EGLint key, EGLint defaultValue) const; + void insert(EGLAttrib key, EGLAttrib value); + bool contains(EGLAttrib key) const; + EGLAttrib get(EGLAttrib key) const; + EGLAttrib get(EGLAttrib key, EGLAttrib defaultValue) const; + EGLint getAsInt(EGLAttrib key) const; + EGLint getAsInt(EGLAttrib key, EGLint defaultValue) const; + bool isEmpty() const; + std::vector toIntVector() const; - typedef std::map::const_iterator const_iterator; + typedef std::map::const_iterator const_iterator; const_iterator begin() const; const_iterator end() const; + static AttributeMap CreateFromIntArray(const EGLint *attributes); + static AttributeMap CreateFromAttribArray(const EGLAttrib *attributes); + private: - std::map mAttributes; + std::map mAttributes; }; } diff --git a/src/3rdparty/angle/src/libANGLE/BinaryStream.h b/src/3rdparty/angle/src/libANGLE/BinaryStream.h index 3e6ccc7446..3e4c0934cf 100644 --- a/src/3rdparty/angle/src/libANGLE/BinaryStream.h +++ b/src/3rdparty/angle/src/libANGLE/BinaryStream.h @@ -9,25 +9,13 @@ #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 -} +#include "common/angleutils.h" +#include "common/mathutil.h" namespace gl { @@ -58,6 +46,16 @@ class BinaryInputStream : angle::NonCopyable *outValue = readInt(); } + template + void readIntVector(std::vector *param) + { + unsigned int size = readInt(); + for (unsigned int index = 0; index < size; ++index) + { + param->push_back(readInt()); + } + } + bool readBool() { int value = 0; @@ -92,25 +90,31 @@ class BinaryInputStream : angle::NonCopyable return; } - if (!rx::IsUnsignedAdditionSafe(mOffset, length) || mOffset + length > mLength) + angle::CheckedNumeric checkedOffset(mOffset); + checkedOffset += length; + + if (!checkedOffset.IsValid() || mOffset + length > mLength) { mError = true; return; } v->assign(reinterpret_cast(mData) + mOffset, length); - mOffset += length; + mOffset = checkedOffset.ValueOrDie(); } void skip(size_t length) { - if (!rx::IsUnsignedAdditionSafe(mOffset, length) || mOffset + length > mLength) + angle::CheckedNumeric checkedOffset(mOffset); + checkedOffset += length; + + if (!checkedOffset.IsValid() || mOffset + length > mLength) { mError = true; return; } - mOffset += length; + mOffset = checkedOffset.ValueOrDie(); } size_t offset() const @@ -142,24 +146,27 @@ class BinaryInputStream : angle::NonCopyable template void read(T *v, size_t num) { - StaticAssertIsFundamental(); + static_assert(std::is_fundamental::value, "T must be a fundamental type."); - if (!rx::IsUnsignedMultiplicationSafe(num, sizeof(T))) + angle::CheckedNumeric checkedLength(num); + checkedLength *= sizeof(T); + if (!checkedLength.IsValid()) { mError = true; return; } - size_t length = num * sizeof(T); + angle::CheckedNumeric checkedOffset(mOffset); + checkedOffset += checkedLength; - if (!rx::IsUnsignedAdditionSafe(mOffset, length) || mOffset + length > mLength) + if (!checkedOffset.IsValid() || checkedOffset.ValueOrDie() > mLength) { mError = true; return; } - memcpy(v, mData + mOffset, length); - mOffset += length; + memcpy(v, mData + mOffset, checkedLength.ValueOrDie()); + mOffset = checkedOffset.ValueOrDie(); } template @@ -173,19 +180,42 @@ class BinaryInputStream : angle::NonCopyable class BinaryOutputStream : angle::NonCopyable { public: - BinaryOutputStream() - { - } + BinaryOutputStream(); + ~BinaryOutputStream(); // writeInt also handles bool types template void writeInt(IntT param) { - ASSERT(rx::IsIntegerCastSafe(param)); + ASSERT(angle::IsValueInRangeForNumericType(param)); int intValue = static_cast(param); write(&intValue, 1); } + // Specialized writeInt for values that can also be exactly -1. + template + void writeIntOrNegOne(UintT param) + { + if (param == static_cast(-1)) + { + writeInt(-1); + } + else + { + writeInt(param); + } + } + + template + void writeIntVector(std::vector param) + { + writeInt(param.size()); + for (IntT element : param) + { + writeIntOrNegOne(element); + } + } + void writeString(const std::string &v) { writeInt(v.length()); @@ -204,7 +234,7 @@ class BinaryOutputStream : angle::NonCopyable const void* data() const { - return mData.size() ? &mData[0] : NULL; + return mData.size() ? &mData[0] : nullptr; } private: @@ -213,12 +243,19 @@ class BinaryOutputStream : angle::NonCopyable template void write(const T *v, size_t num) { - StaticAssertIsFundamental(); + static_assert(std::is_fundamental::value, "T must be a fundamental type."); const char *asBytes = reinterpret_cast(v); mData.insert(mData.end(), asBytes, asBytes + num * sizeof(T)); } }; + +inline BinaryOutputStream::BinaryOutputStream() +{ } +inline BinaryOutputStream::~BinaryOutputStream() = default; + +} // namespace gl + #endif // LIBANGLE_BINARYSTREAM_H_ diff --git a/src/3rdparty/angle/src/libANGLE/Buffer.cpp b/src/3rdparty/angle/src/libANGLE/Buffer.cpp index 589735c5a8..a1ebfc1acb 100644 --- a/src/3rdparty/angle/src/libANGLE/Buffer.cpp +++ b/src/3rdparty/angle/src/libANGLE/Buffer.cpp @@ -9,123 +9,148 @@ // [OpenGL ES 2.0.24] section 2.9 page 21. #include "libANGLE/Buffer.h" + +#include "libANGLE/Context.h" #include "libANGLE/renderer/BufferImpl.h" -#include "libANGLE/renderer/Renderer.h" +#include "libANGLE/renderer/GLImplFactory.h" namespace gl { -Buffer::Buffer(rx::BufferImpl *impl, GLuint id) - : RefCountObject(id), - mBuffer(impl), - mLabel(), - mUsage(GL_STATIC_DRAW), +BufferState::BufferState() + : mLabel(), + mUsage(BufferUsage::StaticDraw), mSize(0), mAccessFlags(0), mAccess(GL_WRITE_ONLY_OES), mMapped(GL_FALSE), - mMapPointer(NULL), + mMapPointer(nullptr), mMapOffset(0), mMapLength(0) { } +BufferState::~BufferState() +{ +} + +Buffer::Buffer(rx::GLImplFactory *factory, GLuint id) + : RefCountObject(id), mImpl(factory->createBuffer(mState)) +{ +} + Buffer::~Buffer() { - SafeDelete(mBuffer); + SafeDelete(mImpl); +} + +Error Buffer::onDestroy(const Context *context) +{ + // In tests, mImpl might be null. + if (mImpl) + mImpl->destroy(context); + return NoError(); } void Buffer::setLabel(const std::string &label) { - mLabel = label; + mState.mLabel = label; } const std::string &Buffer::getLabel() const { - return mLabel; + return mState.mLabel; } -Error Buffer::bufferData(const void *data, GLsizeiptr size, GLenum usage) +Error Buffer::bufferData(const Context *context, + BufferBinding target, + const void *data, + GLsizeiptr size, + BufferUsage usage) { - gl::Error error = mBuffer->setData(data, size, usage); - if (error.isError()) + const void *dataForImpl = data; + + // If we are using robust resource init, make sure the buffer starts cleared. + // Note: the Context is checked for nullptr because of some testing code. + // TODO(jmadill): Investigate lazier clearing. + if (context && context->getGLState().isRobustResourceInitEnabled() && !data && size > 0) { - return error; + angle::MemoryBuffer *scratchBuffer = nullptr; + ANGLE_TRY(context->getZeroFilledBuffer(static_cast(size), &scratchBuffer)); + dataForImpl = scratchBuffer->data(); } + ANGLE_TRY(mImpl->setData(context, target, dataForImpl, size, usage)); + mIndexRangeCache.clear(); - mUsage = usage; - mSize = size; + mState.mUsage = usage; + mState.mSize = size; - return error; + return NoError(); } -Error Buffer::bufferSubData(const void *data, GLsizeiptr size, GLintptr offset) +Error Buffer::bufferSubData(const Context *context, + BufferBinding target, + const void *data, + GLsizeiptr size, + GLintptr offset) { - gl::Error error = mBuffer->setSubData(data, size, offset); - if (error.isError()) - { - return error; - } + ANGLE_TRY(mImpl->setSubData(context, target, data, size, offset)); mIndexRangeCache.invalidateRange(static_cast(offset), static_cast(size)); - return error; + return NoError(); } -Error Buffer::copyBufferSubData(Buffer* source, GLintptr sourceOffset, GLintptr destOffset, GLsizeiptr size) +Error Buffer::copyBufferSubData(const Context *context, + Buffer *source, + GLintptr sourceOffset, + GLintptr destOffset, + GLsizeiptr size) { - gl::Error error = mBuffer->copySubData(source->getImplementation(), sourceOffset, destOffset, size); - if (error.isError()) - { - return error; - } + ANGLE_TRY( + mImpl->copySubData(context, source->getImplementation(), sourceOffset, destOffset, size)); mIndexRangeCache.invalidateRange(static_cast(destOffset), static_cast(size)); - return error; + return NoError(); } -Error Buffer::map(GLenum access) +Error Buffer::map(const Context *context, GLenum access) { - ASSERT(!mMapped); + ASSERT(!mState.mMapped); - Error error = mBuffer->map(access, &mMapPointer); - if (error.isError()) - { - mMapPointer = NULL; - return error; - } + mState.mMapPointer = nullptr; + ANGLE_TRY(mImpl->map(context, access, &mState.mMapPointer)); ASSERT(access == GL_WRITE_ONLY_OES); - mMapped = GL_TRUE; - mMapOffset = 0; - mMapLength = mSize; - mAccess = access; - mAccessFlags = GL_MAP_WRITE_BIT; + mState.mMapped = GL_TRUE; + mState.mMapOffset = 0; + mState.mMapLength = mState.mSize; + mState.mAccess = access; + mState.mAccessFlags = GL_MAP_WRITE_BIT; mIndexRangeCache.clear(); - return error; + return NoError(); } -Error Buffer::mapRange(GLintptr offset, GLsizeiptr length, GLbitfield access) +Error Buffer::mapRange(const Context *context, + GLintptr offset, + GLsizeiptr length, + GLbitfield access) { - ASSERT(!mMapped); - ASSERT(offset + length <= mSize); + ASSERT(!mState.mMapped); + ASSERT(offset + length <= mState.mSize); - Error error = mBuffer->mapRange(offset, length, access, &mMapPointer); - if (error.isError()) - { - mMapPointer = NULL; - return error; - } + mState.mMapPointer = nullptr; + ANGLE_TRY(mImpl->mapRange(context, offset, length, access, &mState.mMapPointer)); - mMapped = GL_TRUE; - mMapOffset = static_cast(offset); - mMapLength = static_cast(length); - mAccess = GL_WRITE_ONLY_OES; - mAccessFlags = access; + mState.mMapped = GL_TRUE; + mState.mMapOffset = static_cast(offset); + mState.mMapLength = static_cast(length); + mState.mAccess = GL_WRITE_ONLY_OES; + mState.mAccessFlags = access; // The OES_mapbuffer extension states that GL_WRITE_ONLY_OES is the only valid // value for GL_BUFFER_ACCESS_OES because it was written against ES2. Since there is @@ -137,28 +162,24 @@ Error Buffer::mapRange(GLintptr offset, GLsizeiptr length, GLbitfield access) mIndexRangeCache.invalidateRange(static_cast(offset), static_cast(length)); } - return error; + return NoError(); } -Error Buffer::unmap(GLboolean *result) +Error Buffer::unmap(const Context *context, GLboolean *result) { - ASSERT(mMapped); + ASSERT(mState.mMapped); - Error error = mBuffer->unmap(result); - if (error.isError()) - { - *result = GL_FALSE; - return error; - } + *result = GL_FALSE; + ANGLE_TRY(mImpl->unmap(context, result)); - mMapped = GL_FALSE; - mMapPointer = NULL; - mMapOffset = 0; - mMapLength = 0; - mAccess = GL_WRITE_ONLY_OES; - mAccessFlags = 0; + mState.mMapped = GL_FALSE; + mState.mMapPointer = nullptr; + mState.mMapOffset = 0; + mState.mMapLength = 0; + mState.mAccess = GL_WRITE_ONLY_OES; + mState.mAccessFlags = 0; - return error; + return NoError(); } void Buffer::onTransformFeedback() @@ -171,7 +192,8 @@ void Buffer::onPixelUnpack() mIndexRangeCache.clear(); } -Error Buffer::getIndexRange(GLenum type, +Error Buffer::getIndexRange(const gl::Context *context, + GLenum type, size_t offset, size_t count, bool primitiveRestartEnabled, @@ -179,18 +201,15 @@ Error Buffer::getIndexRange(GLenum type, { if (mIndexRangeCache.findRange(type, offset, count, primitiveRestartEnabled, outRange)) { - return gl::Error(GL_NO_ERROR); + return NoError(); } - Error error = mBuffer->getIndexRange(type, offset, count, primitiveRestartEnabled, outRange); - if (error.isError()) - { - return error; - } + ANGLE_TRY( + mImpl->getIndexRange(context, type, offset, count, primitiveRestartEnabled, outRange)); mIndexRangeCache.addRange(type, offset, count, primitiveRestartEnabled, *outRange); - return Error(GL_NO_ERROR); + return NoError(); } -} +} // namespace gl diff --git a/src/3rdparty/angle/src/libANGLE/Buffer.h b/src/3rdparty/angle/src/libANGLE/Buffer.h index 6c951ef586..86d4a9fd6f 100644 --- a/src/3rdparty/angle/src/libANGLE/Buffer.h +++ b/src/3rdparty/angle/src/libANGLE/Buffer.h @@ -15,69 +15,109 @@ #include "libANGLE/Debug.h" #include "libANGLE/Error.h" #include "libANGLE/IndexRangeCache.h" +#include "libANGLE/PackedGLEnums.h" #include "libANGLE/RefCountObject.h" namespace rx { class BufferImpl; +class GLImplFactory; }; namespace gl { +class Buffer; +class Context; -class Buffer final : public RefCountObject, public LabeledObject +class BufferState final : angle::NonCopyable { public: - Buffer(rx::BufferImpl *impl, GLuint id); - virtual ~Buffer(); + BufferState(); + ~BufferState(); - void setLabel(const std::string &label) override; - const std::string &getLabel() const override; + const std::string &getLabel(); - 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 map(GLenum access); - Error mapRange(GLintptr offset, GLsizeiptr length, GLbitfield access); - Error unmap(GLboolean *result); - - void onTransformFeedback(); - void onPixelUnpack(); - - Error getIndexRange(GLenum type, - size_t offset, - size_t count, - bool primitiveRestartEnabled, - IndexRange *outRange) const; - - GLenum getUsage() const { return mUsage; } + BufferUsage getUsage() const { return mUsage; } GLbitfield getAccessFlags() const { return mAccessFlags; } GLenum getAccess() const { return mAccess; } GLboolean isMapped() const { return mMapped; } - GLvoid *getMapPointer() const { return mMapPointer; } + void *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; } - private: - rx::BufferImpl *mBuffer; + friend class Buffer; std::string mLabel; - GLenum mUsage; + BufferUsage mUsage; GLint64 mSize; GLbitfield mAccessFlags; GLenum mAccess; GLboolean mMapped; - GLvoid *mMapPointer; + void *mMapPointer; GLint64 mMapOffset; GLint64 mMapLength; +}; + +class Buffer final : public RefCountObject, public LabeledObject +{ + public: + Buffer(rx::GLImplFactory *factory, GLuint id); + ~Buffer() override; + Error onDestroy(const Context *context) override; + + void setLabel(const std::string &label) override; + const std::string &getLabel() const override; + + Error bufferData(const Context *context, + BufferBinding target, + const void *data, + GLsizeiptr size, + BufferUsage usage); + Error bufferSubData(const Context *context, + BufferBinding target, + const void *data, + GLsizeiptr size, + GLintptr offset); + Error copyBufferSubData(const Context *context, + Buffer *source, + GLintptr sourceOffset, + GLintptr destOffset, + GLsizeiptr size); + Error map(const Context *context, GLenum access); + Error mapRange(const Context *context, GLintptr offset, GLsizeiptr length, GLbitfield access); + Error unmap(const Context *context, GLboolean *result); + + void onTransformFeedback(); + void onPixelUnpack(); + + Error getIndexRange(const gl::Context *context, + GLenum type, + size_t offset, + size_t count, + bool primitiveRestartEnabled, + IndexRange *outRange) const; + + BufferUsage getUsage() const { return mState.mUsage; } + GLbitfield getAccessFlags() const { return mState.mAccessFlags; } + GLenum getAccess() const { return mState.mAccess; } + GLboolean isMapped() const { return mState.mMapped; } + void *getMapPointer() const { return mState.mMapPointer; } + GLint64 getMapOffset() const { return mState.mMapOffset; } + GLint64 getMapLength() const { return mState.mMapLength; } + GLint64 getSize() const { return mState.mSize; } + + rx::BufferImpl *getImplementation() const { return mImpl; } + + private: + BufferState mState; + rx::BufferImpl *mImpl; mutable IndexRangeCache mIndexRangeCache; }; -} +} // namespace gl -#endif // LIBANGLE_BUFFER_H_ +#endif // LIBANGLE_BUFFER_H_ diff --git a/src/3rdparty/angle/src/libANGLE/Caps.cpp b/src/3rdparty/angle/src/libANGLE/Caps.cpp index 1eb54a1589..44da2bbe27 100644 --- a/src/3rdparty/angle/src/libANGLE/Caps.cpp +++ b/src/3rdparty/angle/src/libANGLE/Caps.cpp @@ -5,9 +5,12 @@ // #include "libANGLE/Caps.h" + #include "common/debug.h" #include "common/angleutils.h" +#include "libANGLE/formatutils.h" + #include "angle_gl.h" #include @@ -32,6 +35,10 @@ TextureCaps::TextureCaps() { } +TextureCaps::TextureCaps(const TextureCaps &other) = default; + +TextureCaps::~TextureCaps() = default; + GLuint TextureCaps::getMaxSamples() const { return !sampleCounts.empty() ? *sampleCounts.rbegin() : 0; @@ -56,40 +63,80 @@ GLuint TextureCaps::getNearestSamples(GLuint requestedSamples) const return 0; } +TextureCaps GenerateMinimumTextureCaps(GLenum sizedInternalFormat, + const Version &clientVersion, + const Extensions &extensions) +{ + TextureCaps caps; + + const InternalFormat &internalFormatInfo = GetSizedInternalFormatInfo(sizedInternalFormat); + caps.texturable = internalFormatInfo.textureSupport(clientVersion, extensions); + caps.renderable = internalFormatInfo.renderSupport(clientVersion, extensions); + caps.filterable = internalFormatInfo.filterSupport(clientVersion, extensions); + + caps.sampleCounts.insert(0); + if (internalFormatInfo.isRequiredRenderbufferFormat(clientVersion)) + { + if ((clientVersion.major >= 3 && clientVersion.minor >= 1) || + (clientVersion.major >= 3 && internalFormatInfo.componentType != GL_UNSIGNED_INT && + internalFormatInfo.componentType != GL_INT)) + { + caps.sampleCounts.insert(4); + } + } + + return caps; +} + +TextureCapsMap::TextureCapsMap() +{ +} + +TextureCapsMap::~TextureCapsMap() +{ +} + void TextureCapsMap::insert(GLenum internalFormat, const TextureCaps &caps) { - mCapsMap[internalFormat] = caps; + angle::Format::ID formatID = angle::Format::InternalFormatToID(internalFormat); + get(formatID) = caps; } -void TextureCapsMap::remove(GLenum internalFormat) +void TextureCapsMap::clear() { - InternalFormatToCapsMap::iterator i = mCapsMap.find(internalFormat); - if (i != mCapsMap.end()) - { - mCapsMap.erase(i); - } + mFormatData.fill(TextureCaps()); } const TextureCaps &TextureCapsMap::get(GLenum internalFormat) const { - static TextureCaps defaultUnsupportedTexture; - InternalFormatToCapsMap::const_iterator iter = mCapsMap.find(internalFormat); - return (iter != mCapsMap.end()) ? iter->second : defaultUnsupportedTexture; + angle::Format::ID formatID = angle::Format::InternalFormatToID(internalFormat); + return get(formatID); } -TextureCapsMap::const_iterator TextureCapsMap::begin() const +const TextureCaps &TextureCapsMap::get(angle::Format::ID formatID) const { - return mCapsMap.begin(); + return mFormatData[static_cast(formatID)]; } -TextureCapsMap::const_iterator TextureCapsMap::end() const +TextureCaps &TextureCapsMap::get(angle::Format::ID formatID) { - return mCapsMap.end(); + return mFormatData[static_cast(formatID)]; } -size_t TextureCapsMap::size() const +void TextureCapsMap::set(angle::Format::ID formatID, const TextureCaps &caps) { - return mCapsMap.size(); + get(formatID) = caps; +} + +void InitMinimumTextureCapsMap(const Version &clientVersion, + const Extensions &extensions, + TextureCapsMap *capsMap) +{ + for (GLenum internalFormat : GetAllSizedInternalFormats()) + { + capsMap->insert(internalFormat, + GenerateMinimumTextureCaps(internalFormat, clientVersion, extensions)); + } } Extensions::Extensions() @@ -111,23 +158,25 @@ Extensions::Extensions() textureCompressionDXT1(false), textureCompressionDXT3(false), textureCompressionDXT5(false), + textureCompressionS3TCsRGB(false), textureCompressionASTCHDR(false), textureCompressionASTCLDR(false), compressedETC1RGB8Texture(false), + sRGB(false), depthTextures(false), depth32(false), textureStorage(false), textureNPOT(false), drawBuffers(false), textureFilterAnisotropic(false), - maxTextureAnisotropy(false), + maxTextureAnisotropy(0.0f), occlusionQueryBoolean(false), fence(false), - timerQuery(false), disjointTimerQuery(false), queryCounterBitsTimeElapsed(0), queryCounterBitsTimestamp(0), robustness(false), + robustBufferAccessBehavior(false), blendMinMax(false), framebufferBlit(false), framebufferMultisample(false), @@ -135,10 +184,9 @@ Extensions::Extensions() packReverseRowOrder(false), standardDerivatives(false), shaderTextureLOD(false), - shaderFramebufferFetch(false), - ARMshaderFramebufferFetch(false), - NVshaderFramebufferFetch(false), fragDepth(false), + multiview(false), + maxViews(1u), textureUsage(false), translatedShaderSource(false), fboRenderMipmap(false), @@ -147,6 +195,7 @@ Extensions::Extensions() eglImage(false), eglImageExternal(false), eglImageExternalEssl3(false), + eglStreamConsumerExternal(false), unpackSubimage(false), packSubimage(false), vertexArrayObject(false), @@ -157,7 +206,31 @@ Extensions::Extensions() maxLabelLength(0), noError(false), lossyETCDecode(false), - colorBufferFloat(false) + bindUniformLocation(false), + syncQuery(false), + copyTexture(false), + copyCompressedTexture(false), + webglCompatibility(false), + requestExtension(false), + bindGeneratesResource(false), + robustClientMemory(false), + textureSRGBDecode(false), + sRGBWriteControl(false), + colorBufferFloatRGB(false), + colorBufferFloatRGBA(false), + colorBufferFloat(false), + multisampleCompatibility(false), + framebufferMixedSamples(false), + textureNorm16(false), + pathRendering(false), + surfacelessContext(false), + clientArrays(false), + robustResourceInitialization(false), + programCacheControl(false), + textureRectangle(false), + geometryShader(false), + maxGeometryOutputVertices(0), + maxGeometryShaderInvocations(0) { } @@ -165,70 +238,13 @@ std::vector Extensions::getStrings() const { std::vector extensionStrings; - // clang-format off - // | 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_EXT_color_buffer_half_float", colorBufferHalfFloat, &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_KHR_texture_compression_astc_hdr", textureCompressionASTCHDR, &extensionStrings); - InsertExtensionString("GL_KHR_texture_compression_astc_ldr", textureCompressionASTCLDR, &extensionStrings); - InsertExtensionString("GL_OES_compressed_ETC1_RGB8_texture", compressedETC1RGB8Texture, &extensionStrings); - InsertExtensionString("GL_EXT_sRGB", sRGB, &extensionStrings); - InsertExtensionString("GL_ANGLE_depth_texture", depthTextures, &extensionStrings); - InsertExtensionString("GL_OES_depth32", depth32, &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_disjoint_timer_query", disjointTimerQuery, &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_OES_fbo_render_mipmap", fboRenderMipmap, &extensionStrings); - InsertExtensionString("GL_EXT_discard_framebuffer", discardFramebuffer, &extensionStrings); - InsertExtensionString("GL_EXT_debug_marker", debugMarker, &extensionStrings); - InsertExtensionString("GL_OES_EGL_image", eglImage, &extensionStrings); - InsertExtensionString("GL_OES_EGL_image_external", eglImageExternal, &extensionStrings); - InsertExtensionString("GL_OES_EGL_image_external_essl3", eglImageExternalEssl3, &extensionStrings); - InsertExtensionString("GL_EXT_unpack_subimage", unpackSubimage, &extensionStrings); - InsertExtensionString("GL_NV_pack_subimage", packSubimage, &extensionStrings); - InsertExtensionString("GL_EXT_color_buffer_float", colorBufferFloat, &extensionStrings); - InsertExtensionString("GL_OES_vertex_array_object", vertexArrayObject, &extensionStrings); - InsertExtensionString("GL_KHR_debug", debug, &extensionStrings); - // TODO(jmadill): Enable this when complete. - //InsertExtensionString("GL_KHR_no_error", noError, &extensionStrings); - - InsertExtensionString("GL_ANGLE_lossy_etc_decode", lossyETCDecode, &extensionStrings); - // clang-format on + for (const auto &extensionInfo : GetExtensionInfoMap()) + { + if (this->*(extensionInfo.second.ExtensionsMember)) + { + extensionStrings.push_back(extensionInfo.first); + } + } return extensionStrings; } @@ -243,10 +259,14 @@ Limitations::Limitations() { } -static bool GetFormatSupport(const TextureCapsMap &textureCaps, const std::vector &requiredFormats, - bool requiresTexturing, bool requiresFiltering, bool requiresRendering) +static bool GetFormatSupportBase(const TextureCapsMap &textureCaps, + const GLenum *requiredFormats, + size_t requiredFormatsSize, + bool requiresTexturing, + bool requiresFiltering, + bool requiresRendering) { - for (size_t i = 0; i < requiredFormats.size(); i++) + for (size_t i = 0; i < requiredFormatsSize; i++) { const TextureCaps &cap = textureCaps.get(requiredFormats[i]); @@ -269,11 +289,23 @@ static bool GetFormatSupport(const TextureCapsMap &textureCaps, const std::vecto return true; } +template +static bool GetFormatSupport(const TextureCapsMap &textureCaps, + const GLenum (&requiredFormats)[N], + bool requiresTexturing, + bool requiresFiltering, + bool requiresRendering) +{ + return GetFormatSupportBase(textureCaps, requiredFormats, N, requiresTexturing, + requiresFiltering, requiresRendering); +} + // Check for GL_OES_packed_depth_stencil static bool DeterminePackedDepthStencilSupport(const TextureCapsMap &textureCaps) { - std::vector requiredFormats; - requiredFormats.push_back(GL_DEPTH24_STENCIL8); + constexpr GLenum requiredFormats[] = { + GL_DEPTH24_STENCIL8, + }; return GetFormatSupport(textureCaps, requiredFormats, false, false, true); } @@ -281,9 +313,9 @@ static bool DeterminePackedDepthStencilSupport(const TextureCapsMap &textureCaps // 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); + constexpr GLenum requiredFormats[] = { + GL_RGB8, GL_RGBA8, + }; return GetFormatSupport(textureCaps, requiredFormats, true, true, true); } @@ -291,8 +323,9 @@ static bool DetermineRGB8AndRGBA8TextureSupport(const TextureCapsMap &textureCap // Checks for GL_EXT_texture_format_BGRA8888 support static bool DetermineBGRA8TextureSupport(const TextureCapsMap &textureCaps) { - std::vector requiredFormats; - requiredFormats.push_back(GL_BGRA8_EXT); + constexpr GLenum requiredFormats[] = { + GL_BGRA8_EXT, + }; return GetFormatSupport(textureCaps, requiredFormats, true, true, true); } @@ -300,11 +333,9 @@ static bool DetermineBGRA8TextureSupport(const TextureCapsMap &textureCaps) // Checks for GL_OES_color_buffer_half_float support static bool DetermineColorBufferHalfFloatSupport(const TextureCapsMap &textureCaps) { - std::vector requiredFormats; - requiredFormats.push_back(GL_RGBA16F); - requiredFormats.push_back(GL_RGB16F); - requiredFormats.push_back(GL_RG16F); - requiredFormats.push_back(GL_R16F); + constexpr GLenum requiredFormats[] = { + GL_RGBA16F, GL_RGB16F, GL_RG16F, GL_R16F, + }; return GetFormatSupport(textureCaps, requiredFormats, true, false, true); } @@ -312,19 +343,19 @@ static bool DetermineColorBufferHalfFloatSupport(const TextureCapsMap &textureCa // 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); + constexpr GLenum requiredFormats[] = { + GL_RGB16F, GL_RGBA16F, + }; - return GetFormatSupport(textureCaps, requiredFormats, true, false, true); + return GetFormatSupport(textureCaps, requiredFormats, true, false, false); } // 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); + constexpr GLenum requiredFormats[] = { + GL_RGB16F, GL_RGBA16F, + }; return DetermineHalfFloatTextureSupport(textureCaps) && GetFormatSupport(textureCaps, requiredFormats, true, true, false); @@ -333,50 +364,65 @@ static bool DetermineHalfFloatTextureFilteringSupport(const TextureCapsMap &text // 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); + constexpr GLenum requiredFormats[] = { + GL_RGB32F, GL_RGBA32F, + }; - return GetFormatSupport(textureCaps, requiredFormats, true, false, true); + return GetFormatSupport(textureCaps, requiredFormats, true, false, false); } // 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); + constexpr GLenum requiredFormats[] = { + GL_RGB32F, GL_RGBA32F, + }; return DetermineFloatTextureSupport(textureCaps) && GetFormatSupport(textureCaps, requiredFormats, true, true, false); } // Checks for GL_EXT_texture_rg support +static bool DetermineRGHalfFloatTextureSupport(const TextureCapsMap &textureCaps) +{ + constexpr GLenum requiredFormats[] = { + GL_R16F, GL_RG16F, + }; + return GetFormatSupport(textureCaps, requiredFormats, true, true, false); +} + +static bool DetermineRGFloatTextureSupport(const TextureCapsMap &textureCaps) +{ + constexpr GLenum requiredFormats[] = { + GL_R32F, GL_RG32F, + }; + return GetFormatSupport(textureCaps, requiredFormats, true, true, false); +} + 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) + if (checkHalfFloatFormats && !DetermineRGHalfFloatTextureSupport(textureCaps)) { - requiredFormats.push_back(GL_R16F); - requiredFormats.push_back(GL_RG16F); + return false; } - if (checkFloatFormats) + + if (checkFloatFormats && !DetermineRGFloatTextureSupport(textureCaps)) { - requiredFormats.push_back(GL_R32F); - requiredFormats.push_back(GL_RG32F); + return false; } + constexpr GLenum requiredFormats[] = { + GL_R8, GL_RG8, + }; 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); + constexpr GLenum requiredFormats[] = { + GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, + }; return GetFormatSupport(textureCaps, requiredFormats, true, true, false); } @@ -384,8 +430,9 @@ static bool DetermineDXT1TextureSupport(const TextureCapsMap &textureCaps) // 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); + constexpr GLenum requiredFormats[] = { + GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE, + }; return GetFormatSupport(textureCaps, requiredFormats, true, true, false); } @@ -393,8 +440,20 @@ static bool DetermineDXT3TextureSupport(const TextureCapsMap &textureCaps) // 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); + constexpr GLenum requiredFormats[] = { + GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE, + }; + + return GetFormatSupport(textureCaps, requiredFormats, true, true, false); +} + +// Check for GL_EXT_texture_compression_s3tc_srgb +static bool DetermineS3TCsRGBTextureSupport(const TextureCapsMap &textureCaps) +{ + constexpr GLenum requiredFormats[] = { + GL_COMPRESSED_SRGB_S3TC_DXT1_EXT, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT, + GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, + }; return GetFormatSupport(textureCaps, requiredFormats, true, true, false); } @@ -402,35 +461,22 @@ static bool DetermineDXT5TextureSupport(const TextureCapsMap &textureCaps) // Check for GL_KHR_texture_compression_astc_hdr and GL_KHR_texture_compression_astc_ldr static bool DetermineASTCTextureSupport(const TextureCapsMap &textureCaps) { - std::vector requiredFormats; - requiredFormats.push_back(GL_COMPRESSED_RGBA_ASTC_4x4_KHR); - requiredFormats.push_back(GL_COMPRESSED_RGBA_ASTC_5x4_KHR); - requiredFormats.push_back(GL_COMPRESSED_RGBA_ASTC_5x5_KHR); - requiredFormats.push_back(GL_COMPRESSED_RGBA_ASTC_6x5_KHR); - requiredFormats.push_back(GL_COMPRESSED_RGBA_ASTC_6x6_KHR); - requiredFormats.push_back(GL_COMPRESSED_RGBA_ASTC_8x5_KHR); - requiredFormats.push_back(GL_COMPRESSED_RGBA_ASTC_8x6_KHR); - requiredFormats.push_back(GL_COMPRESSED_RGBA_ASTC_8x8_KHR); - requiredFormats.push_back(GL_COMPRESSED_RGBA_ASTC_10x5_KHR); - requiredFormats.push_back(GL_COMPRESSED_RGBA_ASTC_10x6_KHR); - requiredFormats.push_back(GL_COMPRESSED_RGBA_ASTC_10x8_KHR); - requiredFormats.push_back(GL_COMPRESSED_RGBA_ASTC_10x10_KHR); - requiredFormats.push_back(GL_COMPRESSED_RGBA_ASTC_12x10_KHR); - requiredFormats.push_back(GL_COMPRESSED_RGBA_ASTC_12x12_KHR); - requiredFormats.push_back(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR); - requiredFormats.push_back(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR); - requiredFormats.push_back(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR); - requiredFormats.push_back(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR); - requiredFormats.push_back(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR); - requiredFormats.push_back(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR); - requiredFormats.push_back(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR); - requiredFormats.push_back(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR); - requiredFormats.push_back(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR); - requiredFormats.push_back(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR); - requiredFormats.push_back(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR); - requiredFormats.push_back(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR); - requiredFormats.push_back(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR); - requiredFormats.push_back(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR); + constexpr GLenum requiredFormats[] = { + GL_COMPRESSED_RGBA_ASTC_4x4_KHR, GL_COMPRESSED_RGBA_ASTC_5x4_KHR, + GL_COMPRESSED_RGBA_ASTC_5x5_KHR, GL_COMPRESSED_RGBA_ASTC_6x5_KHR, + GL_COMPRESSED_RGBA_ASTC_6x6_KHR, GL_COMPRESSED_RGBA_ASTC_8x5_KHR, + GL_COMPRESSED_RGBA_ASTC_8x6_KHR, GL_COMPRESSED_RGBA_ASTC_8x8_KHR, + GL_COMPRESSED_RGBA_ASTC_10x5_KHR, GL_COMPRESSED_RGBA_ASTC_10x6_KHR, + GL_COMPRESSED_RGBA_ASTC_10x8_KHR, GL_COMPRESSED_RGBA_ASTC_10x10_KHR, + GL_COMPRESSED_RGBA_ASTC_12x10_KHR, GL_COMPRESSED_RGBA_ASTC_12x12_KHR, + GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR, + GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR, + GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR, + GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR, + GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR, + GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR, + GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR, + }; return GetFormatSupport(textureCaps, requiredFormats, true, true, false); } @@ -438,8 +484,9 @@ static bool DetermineASTCTextureSupport(const TextureCapsMap &textureCaps) // Check for GL_ETC1_RGB8_OES static bool DetermineETC1RGB8TextureSupport(const TextureCapsMap &textureCaps) { - std::vector requiredFormats; - requiredFormats.push_back(GL_ETC1_RGB8_OES); + constexpr GLenum requiredFormats[] = { + GL_ETC1_RGB8_OES, + }; return GetFormatSupport(textureCaps, requiredFormats, true, true, false); } @@ -447,12 +494,13 @@ static bool DetermineETC1RGB8TextureSupport(const TextureCapsMap &textureCaps) // 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); + constexpr GLenum requiredFilterFormats[] = { + GL_SRGB8, GL_SRGB8_ALPHA8, + }; - std::vector requiredRenderFormats; - requiredRenderFormats.push_back(GL_SRGB8_ALPHA8); + constexpr GLenum requiredRenderFormats[] = { + GL_SRGB8_ALPHA8, + }; return GetFormatSupport(textureCaps, requiredFilterFormats, true, true, false) && GetFormatSupport(textureCaps, requiredRenderFormats, true, false, true); @@ -461,10 +509,9 @@ static bool DetermineSRGBTextureSupport(const TextureCapsMap &textureCaps) // 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); + constexpr GLenum requiredFormats[] = { + GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT32_OES, GL_DEPTH24_STENCIL8_OES, + }; return GetFormatSupport(textureCaps, requiredFormats, true, true, true); } @@ -472,27 +519,59 @@ static bool DetermineDepthTextureSupport(const TextureCapsMap &textureCaps) // Check for GL_OES_depth32 static bool DetermineDepth32Support(const TextureCapsMap &textureCaps) { - std::vector requiredFormats; - requiredFormats.push_back(GL_DEPTH_COMPONENT32_OES); + constexpr GLenum requiredFormats[] = { + GL_DEPTH_COMPONENT32_OES, + }; return GetFormatSupport(textureCaps, requiredFormats, false, false, true); } +// Check for GL_CHROMIUM_color_buffer_float_rgb +static bool DetermineColorBufferFloatRGBSupport(const TextureCapsMap &textureCaps) +{ + constexpr GLenum requiredFormats[] = { + GL_RGB32F, + }; + + return GetFormatSupport(textureCaps, requiredFormats, true, false, true); +} + +// Check for GL_CHROMIUM_color_buffer_float_rgba +static bool DetermineColorBufferFloatRGBASupport(const TextureCapsMap &textureCaps) +{ + constexpr GLenum requiredFormats[] = { + GL_RGBA32F, + }; + + return GetFormatSupport(textureCaps, requiredFormats, true, false, 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); + constexpr GLenum requiredFormats[] = { + GL_R16F, GL_RG16F, GL_RGBA16F, GL_R32F, GL_RG32F, GL_RGBA32F, GL_R11F_G11F_B10F, + }; return GetFormatSupport(textureCaps, requiredFormats, true, false, true); } +// Check for GL_EXT_texture_norm16 +static bool DetermineTextureNorm16Support(const TextureCapsMap &textureCaps) +{ + constexpr GLenum requiredFilterFormats[] = { + GL_R16_EXT, GL_RG16_EXT, GL_RGB16_EXT, GL_RGBA16_EXT, + GL_R16_SNORM_EXT, GL_RG16_SNORM_EXT, GL_RGB16_SNORM_EXT, GL_RGBA16_SNORM_EXT, + }; + + constexpr GLenum requiredRenderFormats[] = { + GL_R16_EXT, GL_RG16_EXT, GL_RGBA16_EXT, + }; + + return GetFormatSupport(textureCaps, requiredFilterFormats, true, true, false) && + GetFormatSupport(textureCaps, requiredRenderFormats, true, false, true); +} + void Extensions::setTextureExtensionSupport(const TextureCapsMap &textureCaps) { packedDepthStencil = DeterminePackedDepthStencilSupport(textureCaps); @@ -507,47 +586,161 @@ void Extensions::setTextureExtensionSupport(const TextureCapsMap &textureCaps) textureCompressionDXT1 = DetermineDXT1TextureSupport(textureCaps); textureCompressionDXT3 = DetermineDXT3TextureSupport(textureCaps); textureCompressionDXT5 = DetermineDXT5TextureSupport(textureCaps); + textureCompressionS3TCsRGB = DetermineS3TCsRGBTextureSupport(textureCaps); textureCompressionASTCHDR = DetermineASTCTextureSupport(textureCaps); textureCompressionASTCLDR = textureCompressionASTCHDR; compressedETC1RGB8Texture = DetermineETC1RGB8TextureSupport(textureCaps); sRGB = DetermineSRGBTextureSupport(textureCaps); depthTextures = DetermineDepthTextureSupport(textureCaps); depth32 = DetermineDepth32Support(textureCaps); + colorBufferFloatRGB = DetermineColorBufferFloatRGBSupport(textureCaps); + colorBufferFloatRGBA = DetermineColorBufferFloatRGBASupport(textureCaps); colorBufferFloat = DetermineColorBufferFloatSupport(textureCaps); + textureNorm16 = DetermineTextureNorm16Support(textureCaps); } -TypePrecision::TypePrecision() +const ExtensionInfoMap &GetExtensionInfoMap() { - range[0] = 0; - range[1] = 0; - precision = 0; + auto buildExtensionInfoMap = []() { + auto enableableExtension = [](ExtensionInfo::ExtensionBool member) { + ExtensionInfo info; + info.Requestable = true; + info.ExtensionsMember = member; + return info; + }; + + auto esOnlyExtension = [](ExtensionInfo::ExtensionBool member) { + ExtensionInfo info; + info.ExtensionsMember = member; + return info; + }; + + // clang-format off + ExtensionInfoMap map; + map["GL_OES_element_index_uint"] = enableableExtension(&Extensions::elementIndexUint); + map["GL_OES_packed_depth_stencil"] = esOnlyExtension(&Extensions::packedDepthStencil); + map["GL_OES_get_program_binary"] = enableableExtension(&Extensions::getProgramBinary); + map["GL_OES_rgb8_rgba8"] = enableableExtension(&Extensions::rgb8rgba8); + map["GL_EXT_texture_format_BGRA8888"] = enableableExtension(&Extensions::textureFormatBGRA8888); + map["GL_EXT_read_format_bgra"] = esOnlyExtension(&Extensions::readFormatBGRA); + map["GL_NV_pixel_buffer_object"] = enableableExtension(&Extensions::pixelBufferObject); + map["GL_OES_mapbuffer"] = enableableExtension(&Extensions::mapBuffer); + map["GL_EXT_map_buffer_range"] = enableableExtension(&Extensions::mapBufferRange); + map["GL_EXT_color_buffer_half_float"] = enableableExtension(&Extensions::colorBufferHalfFloat); + map["GL_OES_texture_half_float"] = enableableExtension(&Extensions::textureHalfFloat); + map["GL_OES_texture_half_float_linear"] = enableableExtension(&Extensions::textureHalfFloatLinear); + map["GL_OES_texture_float"] = enableableExtension(&Extensions::textureFloat); + map["GL_OES_texture_float_linear"] = enableableExtension(&Extensions::textureFloatLinear); + map["GL_EXT_texture_rg"] = enableableExtension(&Extensions::textureRG); + map["GL_EXT_texture_compression_dxt1"] = enableableExtension(&Extensions::textureCompressionDXT1); + map["GL_ANGLE_texture_compression_dxt3"] = enableableExtension(&Extensions::textureCompressionDXT3); + map["GL_ANGLE_texture_compression_dxt5"] = enableableExtension(&Extensions::textureCompressionDXT5); + map["GL_EXT_texture_compression_s3tc_srgb"] = enableableExtension(&Extensions::textureCompressionS3TCsRGB); + map["GL_KHR_texture_compression_astc_hdr"] = enableableExtension(&Extensions::textureCompressionASTCHDR); + map["GL_KHR_texture_compression_astc_ldr"] = enableableExtension(&Extensions::textureCompressionASTCLDR); + map["GL_OES_compressed_ETC1_RGB8_texture"] = enableableExtension(&Extensions::compressedETC1RGB8Texture); + map["GL_EXT_sRGB"] = enableableExtension(&Extensions::sRGB); + map["GL_ANGLE_depth_texture"] = esOnlyExtension(&Extensions::depthTextures); + map["GL_OES_depth32"] = esOnlyExtension(&Extensions::depth32); + map["GL_EXT_texture_storage"] = esOnlyExtension(&Extensions::textureStorage); + map["GL_OES_texture_npot"] = enableableExtension(&Extensions::textureNPOT); + map["GL_EXT_draw_buffers"] = enableableExtension(&Extensions::drawBuffers); + map["GL_EXT_texture_filter_anisotropic"] = enableableExtension(&Extensions::textureFilterAnisotropic); + map["GL_EXT_occlusion_query_boolean"] = enableableExtension(&Extensions::occlusionQueryBoolean); + map["GL_NV_fence"] = esOnlyExtension(&Extensions::fence); + map["GL_EXT_disjoint_timer_query"] = enableableExtension(&Extensions::disjointTimerQuery); + map["GL_EXT_robustness"] = esOnlyExtension(&Extensions::robustness); + map["GL_KHR_robust_buffer_access_behavior"] = esOnlyExtension(&Extensions::robustBufferAccessBehavior); + map["GL_EXT_blend_minmax"] = enableableExtension(&Extensions::blendMinMax); + map["GL_ANGLE_framebuffer_blit"] = enableableExtension(&Extensions::framebufferBlit); + map["GL_ANGLE_framebuffer_multisample"] = enableableExtension(&Extensions::framebufferMultisample); + map["GL_ANGLE_instanced_arrays"] = enableableExtension(&Extensions::instancedArrays); + map["GL_ANGLE_pack_reverse_row_order"] = enableableExtension(&Extensions::packReverseRowOrder); + map["GL_OES_standard_derivatives"] = enableableExtension(&Extensions::standardDerivatives); + map["GL_EXT_shader_texture_lod"] = enableableExtension(&Extensions::shaderTextureLOD); + map["GL_EXT_frag_depth"] = enableableExtension(&Extensions::fragDepth); + map["GL_ANGLE_multiview"] = enableableExtension(&Extensions::multiview); + map["GL_ANGLE_texture_usage"] = enableableExtension(&Extensions::textureUsage); + map["GL_ANGLE_translated_shader_source"] = esOnlyExtension(&Extensions::translatedShaderSource); + map["GL_OES_fbo_render_mipmap"] = enableableExtension(&Extensions::fboRenderMipmap); + map["GL_EXT_discard_framebuffer"] = esOnlyExtension(&Extensions::discardFramebuffer); + map["GL_EXT_debug_marker"] = esOnlyExtension(&Extensions::debugMarker); + map["GL_OES_EGL_image"] = esOnlyExtension(&Extensions::eglImage); + map["GL_OES_EGL_image_external"] = esOnlyExtension(&Extensions::eglImageExternal); + map["GL_OES_EGL_image_external_essl3"] = esOnlyExtension(&Extensions::eglImageExternalEssl3); + map["GL_NV_EGL_stream_consumer_external"] = esOnlyExtension(&Extensions::eglStreamConsumerExternal); + map["GL_EXT_unpack_subimage"] = enableableExtension(&Extensions::unpackSubimage); + map["GL_NV_pack_subimage"] = enableableExtension(&Extensions::packSubimage); + map["GL_EXT_color_buffer_float"] = enableableExtension(&Extensions::colorBufferFloat); + map["GL_OES_vertex_array_object"] = esOnlyExtension(&Extensions::vertexArrayObject); + map["GL_KHR_debug"] = esOnlyExtension(&Extensions::debug); + // TODO(jmadill): Enable this when complete. + //map["GL_KHR_no_error"] = esOnlyExtension(&Extensions::noError); + map["GL_ANGLE_lossy_etc_decode"] = enableableExtension(&Extensions::lossyETCDecode); + map["GL_CHROMIUM_bind_uniform_location"] = esOnlyExtension(&Extensions::bindUniformLocation); + map["GL_CHROMIUM_sync_query"] = enableableExtension(&Extensions::syncQuery); + map["GL_CHROMIUM_copy_texture"] = esOnlyExtension(&Extensions::copyTexture); + map["GL_CHROMIUM_copy_compressed_texture"] = esOnlyExtension(&Extensions::copyCompressedTexture); + map["GL_ANGLE_webgl_compatibility"] = esOnlyExtension(&Extensions::webglCompatibility); + map["GL_ANGLE_request_extension"] = esOnlyExtension(&Extensions::requestExtension); + map["GL_CHROMIUM_bind_generates_resource"] = esOnlyExtension(&Extensions::bindGeneratesResource); + map["GL_ANGLE_robust_client_memory"] = esOnlyExtension(&Extensions::robustClientMemory); + map["GL_EXT_texture_sRGB_decode"] = esOnlyExtension(&Extensions::textureSRGBDecode); + map["GL_EXT_sRGB_write_control"] = esOnlyExtension(&Extensions::sRGBWriteControl); + map["GL_CHROMIUM_color_buffer_float_rgb"] = enableableExtension(&Extensions::colorBufferFloatRGB); + map["GL_CHROMIUM_color_buffer_float_rgba"] = enableableExtension(&Extensions::colorBufferFloatRGBA); + map["GL_EXT_multisample_compatibility"] = esOnlyExtension(&Extensions::multisampleCompatibility); + map["GL_CHROMIUM_framebuffer_mixed_samples"] = esOnlyExtension(&Extensions::framebufferMixedSamples); + map["GL_EXT_texture_norm16"] = esOnlyExtension(&Extensions::textureNorm16); + map["GL_CHROMIUM_path_rendering"] = esOnlyExtension(&Extensions::pathRendering); + map["GL_OES_surfaceless_context"] = esOnlyExtension(&Extensions::surfacelessContext); + map["GL_ANGLE_client_arrays"] = esOnlyExtension(&Extensions::clientArrays); + map["GL_ANGLE_robust_resource_initialization"] = esOnlyExtension(&Extensions::robustResourceInitialization); + map["GL_ANGLE_program_cache_control"] = esOnlyExtension(&Extensions::programCacheControl); + map["GL_ANGLE_texture_rectangle"] = enableableExtension(&Extensions::textureRectangle); + map["GL_EXT_geometry_shader"] = enableableExtension(&Extensions::geometryShader); + // clang-format on + + return map; + }; + + static const ExtensionInfoMap extensionInfo = buildExtensionInfoMap(); + return extensionInfo; } +TypePrecision::TypePrecision() : range({{0, 0}}), precision(0) +{ +} + +TypePrecision::TypePrecision(const TypePrecision &other) = default; + void TypePrecision::setIEEEFloat() { - range[0] = 127; - range[1] = 127; + range = {{127, 127}}; precision = 23; } void TypePrecision::setTwosComplementInt(unsigned int bits) { - range[0] = GLint(bits) - 1; - range[1] = GLint(bits) - 2; + range = {{static_cast(bits) - 1, static_cast(bits) - 2}}; precision = 0; } +void TypePrecision::setSimulatedFloat(unsigned int r, unsigned int p) +{ + range = {{static_cast(r), static_cast(r)}}; + precision = static_cast(p); +} + void TypePrecision::setSimulatedInt(unsigned int r) { - range[0] = GLint(r); - range[1] = GLint(r); + range = {{static_cast(r), static_cast(r)}}; precision = 0; } void TypePrecision::get(GLint *returnRange, GLint *returnPrecision) const { - returnRange[0] = range[0]; - returnRange[1] = range[1]; + std::copy(range.begin(), range.end(), returnRange); *returnPrecision = precision; } @@ -555,37 +748,77 @@ Caps::Caps() : maxElementIndex(0), max3DTextureSize(0), max2DTextureSize(0), + maxRectangleTextureSize(0), maxArrayTextureLayers(0), maxLODBias(0), maxCubeMapTextureSize(0), maxRenderbufferSize(0), + minAliasedPointSize(0), + maxAliasedPointSize(0), + minAliasedLineWidth(0), + maxAliasedLineWidth(0), + + // Table 20.40 maxDrawBuffers(0), + maxFramebufferWidth(0), + maxFramebufferHeight(0), + maxFramebufferSamples(0), maxColorAttachments(0), maxViewportWidth(0), maxViewportHeight(0), - minAliasedPointSize(0), - maxAliasedPointSize(0), - minAliasedLineWidth(0), - // Table 6.29 + maxSampleMaskWords(0), + maxColorTextureSamples(0), + maxDepthTextureSamples(0), + maxIntegerSamples(0), + maxServerWaitTimeout(0), + + // Table 20.41 + maxVertexAttribRelativeOffset(0), + maxVertexAttribBindings(0), + maxVertexAttribStride(0), maxElementsIndices(0), maxElementsVertices(0), - maxServerWaitTimeout(0), - // Table 6.31 + + // Table 20.43 maxVertexAttributes(0), maxVertexUniformComponents(0), maxVertexUniformVectors(0), maxVertexUniformBlocks(0), maxVertexOutputComponents(0), maxVertexTextureImageUnits(0), - // Table 6.32 + maxVertexAtomicCounterBuffers(0), + maxVertexAtomicCounters(0), + maxVertexImageUniforms(0), + maxVertexShaderStorageBlocks(0), + + // Table 20.44 maxFragmentUniformComponents(0), maxFragmentUniformVectors(0), maxFragmentUniformBlocks(0), maxFragmentInputComponents(0), maxTextureImageUnits(0), + maxFragmentAtomicCounterBuffers(0), + maxFragmentAtomicCounters(0), + maxFragmentImageUniforms(0), + maxFragmentShaderStorageBlocks(0), + minProgramTextureGatherOffset(0), + maxProgramTextureGatherOffset(0), minProgramTexelOffset(0), maxProgramTexelOffset(0), - // Table 6.33 + + // Table 20.45 + maxComputeWorkGroupInvocations(0), + maxComputeUniformBlocks(0), + maxComputeTextureImageUnits(0), + maxComputeSharedMemorySize(0), + maxComputeUniformComponents(0), + maxComputeAtomicCounterBuffers(0), + maxComputeAtomicCounters(0), + maxComputeImageUniforms(0), + maxCombinedComputeUniformComponents(0), + maxComputeShaderStorageBlocks(0), + + // Table 20.46 maxUniformBufferBindings(0), maxUniformBlockSize(0), uniformBufferOffsetAlignment(0), @@ -595,15 +828,233 @@ Caps::Caps() maxVaryingComponents(0), maxVaryingVectors(0), maxCombinedTextureImageUnits(0), - // Table 6.34 + maxCombinedShaderOutputResources(0), + + // Table 20.47 + maxUniformLocations(0), + maxAtomicCounterBufferBindings(0), + maxAtomicCounterBufferSize(0), + maxCombinedAtomicCounterBuffers(0), + maxCombinedAtomicCounters(0), + maxImageUnits(0), + maxCombinedImageUniforms(0), + maxShaderStorageBufferBindings(0), + maxShaderStorageBlockSize(0), + maxCombinedShaderStorageBlocks(0), + shaderStorageBufferOffsetAlignment(0), + + // Table 20.48 maxTransformFeedbackInterleavedComponents(0), maxTransformFeedbackSeparateAttributes(0), maxTransformFeedbackSeparateComponents(0), - // Table 6.35 + + // Table 20.49 maxSamples(0) { + for (size_t i = 0; i < 3; ++i) + { + maxComputeWorkGroupCount[i] = 0; + maxComputeWorkGroupSize[i] = 0; + } } +Caps::Caps(const Caps &other) = default; +Caps::~Caps() = default; + +Caps GenerateMinimumCaps(const Version &clientVersion, const Extensions &extensions) +{ + Caps caps; + + if (clientVersion >= Version(2, 0)) + { + // Table 6.18 + caps.max2DTextureSize = 64; + caps.maxCubeMapTextureSize = 16; + caps.maxViewportWidth = caps.max2DTextureSize; + caps.maxViewportHeight = caps.max2DTextureSize; + caps.minAliasedPointSize = 1; + caps.maxAliasedPointSize = 1; + caps.minAliasedLineWidth = 1; + caps.maxAliasedLineWidth = 1; + + // Table 6.19 + caps.vertexHighpFloat.setSimulatedFloat(62, 16); + caps.vertexMediumpFloat.setSimulatedFloat(14, 10); + caps.vertexLowpFloat.setSimulatedFloat(1, 8); + caps.vertexHighpInt.setSimulatedInt(16); + caps.vertexMediumpInt.setSimulatedInt(10); + caps.vertexLowpInt.setSimulatedInt(8); + caps.fragmentHighpFloat.setSimulatedFloat(62, 16); + caps.fragmentMediumpFloat.setSimulatedFloat(14, 10); + caps.fragmentLowpFloat.setSimulatedFloat(1, 8); + caps.fragmentHighpInt.setSimulatedInt(16); + caps.fragmentMediumpInt.setSimulatedInt(10); + caps.fragmentLowpInt.setSimulatedInt(8); + + // Table 6.20 + caps.maxVertexAttributes = 8; + caps.maxVertexUniformVectors = 128; + caps.maxVaryingVectors = 8; + caps.maxCombinedTextureImageUnits = 8; + caps.maxTextureImageUnits = 8; + caps.maxFragmentUniformVectors = 16; + caps.maxRenderbufferSize = 1; + } + + if (clientVersion >= Version(3, 0)) + { + // Table 6.28 + caps.maxElementIndex = (1 << 24) - 1; + caps.max3DTextureSize = 256; + caps.max2DTextureSize = 2048; + caps.maxArrayTextureLayers = 256; + caps.maxLODBias = 2.0f; + caps.maxCubeMapTextureSize = 2048; + caps.maxRenderbufferSize = 2048; + caps.maxDrawBuffers = 4; + caps.maxColorAttachments = 4; + caps.maxViewportWidth = caps.max2DTextureSize; + caps.maxViewportHeight = caps.max2DTextureSize; + + // Table 6.29 + caps.compressedTextureFormats.push_back(GL_COMPRESSED_R11_EAC); + caps.compressedTextureFormats.push_back(GL_COMPRESSED_SIGNED_R11_EAC); + caps.compressedTextureFormats.push_back(GL_COMPRESSED_RG11_EAC); + caps.compressedTextureFormats.push_back(GL_COMPRESSED_SIGNED_RG11_EAC); + caps.compressedTextureFormats.push_back(GL_COMPRESSED_RGB8_ETC2); + caps.compressedTextureFormats.push_back(GL_COMPRESSED_SRGB8_ETC2); + caps.compressedTextureFormats.push_back(GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2); + caps.compressedTextureFormats.push_back(GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2); + caps.compressedTextureFormats.push_back(GL_COMPRESSED_RGBA8_ETC2_EAC); + caps.compressedTextureFormats.push_back(GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC); + caps.vertexHighpFloat.setIEEEFloat(); + caps.vertexHighpInt.setTwosComplementInt(32); + caps.vertexMediumpInt.setTwosComplementInt(16); + caps.vertexLowpInt.setTwosComplementInt(8); + caps.fragmentHighpFloat.setIEEEFloat(); + caps.fragmentHighpInt.setSimulatedInt(32); + caps.fragmentMediumpInt.setTwosComplementInt(16); + caps.fragmentLowpInt.setTwosComplementInt(8); + caps.maxServerWaitTimeout = 0; + + // Table 6.31 + caps.maxVertexAttributes = 16; + caps.maxVertexUniformComponents = 1024; + caps.maxVertexUniformVectors = 256; + caps.maxVertexUniformBlocks = 12; + caps.maxVertexOutputComponents = 64; + caps.maxVertexTextureImageUnits = 16; + + // Table 6.32 + caps.maxFragmentUniformComponents = 896; + caps.maxFragmentUniformVectors = 224; + caps.maxFragmentUniformBlocks = 12; + caps.maxFragmentInputComponents = 60; + caps.maxTextureImageUnits = 16; + caps.minProgramTexelOffset = -8; + caps.maxProgramTexelOffset = 7; + + // Table 6.33 + caps.maxUniformBufferBindings = 24; + caps.maxUniformBlockSize = 16384; + caps.uniformBufferOffsetAlignment = 256; + caps.maxCombinedUniformBlocks = 24; + caps.maxCombinedVertexUniformComponents = + caps.maxVertexUniformBlocks * (caps.maxUniformBlockSize / 4) + + caps.maxVertexUniformComponents; + caps.maxCombinedFragmentUniformComponents = + caps.maxFragmentUniformBlocks * (caps.maxUniformBlockSize / 4) + + caps.maxFragmentUniformComponents; + caps.maxVaryingComponents = 60; + caps.maxVaryingVectors = 15; + caps.maxCombinedTextureImageUnits = 32; + + // Table 6.34 + caps.maxTransformFeedbackInterleavedComponents = 64; + caps.maxTransformFeedbackSeparateAttributes = 4; + caps.maxTransformFeedbackSeparateComponents = 4; + + // Table 3.35 + caps.maxSamples = 4; + } + + if (clientVersion >= Version(3, 1)) + { + // Table 20.40 + caps.maxFramebufferWidth = 2048; + caps.maxFramebufferHeight = 2048; + caps.maxFramebufferSamples = 4; + caps.maxSampleMaskWords = 1; + caps.maxColorTextureSamples = 1; + caps.maxDepthTextureSamples = 1; + caps.maxIntegerSamples = 1; + + // Table 20.41 + caps.maxVertexAttribRelativeOffset = 2047; + caps.maxVertexAttribBindings = 16; + caps.maxVertexAttribStride = 2048; + + // Table 20.43 + caps.maxVertexAtomicCounterBuffers = 0; + caps.maxVertexAtomicCounters = 0; + caps.maxVertexImageUniforms = 0; + caps.maxVertexShaderStorageBlocks = 0; + + // Table 20.44 + caps.maxFragmentUniformComponents = 1024; + caps.maxFragmentUniformVectors = 256; + caps.maxFragmentAtomicCounterBuffers = 0; + caps.maxFragmentAtomicCounters = 0; + caps.maxFragmentImageUniforms = 0; + caps.maxFragmentShaderStorageBlocks = 0; + caps.minProgramTextureGatherOffset = 0; + caps.maxProgramTextureGatherOffset = 0; + + // Table 20.45 + caps.maxComputeWorkGroupCount = {{65535, 65535, 65535}}; + caps.maxComputeWorkGroupSize = {{128, 128, 64}}; + caps.maxComputeWorkGroupInvocations = 12; + caps.maxComputeUniformBlocks = 12; + caps.maxComputeTextureImageUnits = 16; + caps.maxComputeSharedMemorySize = 16384; + caps.maxComputeUniformComponents = 1024; + caps.maxComputeAtomicCounterBuffers = 1; + caps.maxComputeAtomicCounters = 8; + caps.maxComputeImageUniforms = 4; + caps.maxCombinedComputeUniformComponents = + caps.maxComputeUniformBlocks * static_cast(caps.maxUniformBlockSize / 4) + + caps.maxComputeUniformComponents; + caps.maxComputeShaderStorageBlocks = 4; + + // Table 20.46 + caps.maxUniformBufferBindings = 36; + caps.maxCombinedFragmentUniformComponents = + caps.maxFragmentUniformBlocks * (caps.maxUniformBlockSize / 4) + + caps.maxFragmentUniformComponents; + caps.maxCombinedTextureImageUnits = 48; + caps.maxCombinedShaderOutputResources = 4; + + // Table 20.47 + caps.maxUniformLocations = 1024; + caps.maxAtomicCounterBufferBindings = 1; + caps.maxAtomicCounterBufferSize = 32; + caps.maxCombinedAtomicCounterBuffers = 1; + caps.maxCombinedAtomicCounters = 8; + caps.maxImageUnits = 4; + caps.maxCombinedImageUniforms = 4; + caps.maxShaderStorageBufferBindings = 4; + caps.maxShaderStorageBlockSize = 1 << 27; + caps.maxCombinedShaderStorageBlocks = 4; + caps.shaderStorageBufferOffsetAlignment = 256; + } + + if (extensions.textureRectangle) + { + caps.maxRectangleTextureSize = 64; + } + + return caps; +} } namespace egl @@ -617,6 +1068,7 @@ Caps::Caps() DisplayExtensions::DisplayExtensions() : createContextRobustness(false), d3dShareHandleClientBuffer(false), + d3dTextureClientBuffer(false), surfaceD3DTexture2DShareHandle(false), querySurfacePointer(false), windowFixedSize(false), @@ -635,7 +1087,21 @@ DisplayExtensions::DisplayExtensions() getAllProcAddresses(false), flexibleSurfaceCompatibility(false), directComposition(false), - createContextNoError(false) + createContextNoError(false), + stream(false), + streamConsumerGLTexture(false), + streamConsumerGLTextureYUV(false), + streamProducerD3DTextureNV12(false), + createContextWebGLCompatibility(false), + createContextBindGeneratesResource(false), + getSyncValues(false), + swapBuffersWithDamage(false), + pixelFormatFloat(false), + surfacelessContext(false), + displayTextureShareGroup(false), + createContextClientArrays(false), + programCacheControl(false), + robustResourceInitialization(false) { } @@ -644,29 +1110,44 @@ std::vector DisplayExtensions::getStrings() const std::vector extensionStrings; // clang-format off - // | 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_ANGLE_keyed_mutex", keyedMutex, &extensionStrings); - InsertExtensionString("EGL_ANGLE_surface_orientation", surfaceOrientation, &extensionStrings); - InsertExtensionString("EGL_ANGLE_direct_composition", directComposition, &extensionStrings); - InsertExtensionString("EGL_NV_post_sub_buffer", postSubBuffer, &extensionStrings); - InsertExtensionString("EGL_KHR_create_context", createContext, &extensionStrings); - InsertExtensionString("EGL_EXT_device_query", deviceQuery, &extensionStrings); - InsertExtensionString("EGL_KHR_image", image, &extensionStrings); - InsertExtensionString("EGL_KHR_image_base", imageBase, &extensionStrings); - InsertExtensionString("EGL_KHR_image_pixmap", imagePixmap, &extensionStrings); - InsertExtensionString("EGL_KHR_gl_texture_2D_image", glTexture2DImage, &extensionStrings); - InsertExtensionString("EGL_KHR_gl_texture_cubemap_image", glTextureCubemapImage, &extensionStrings); - InsertExtensionString("EGL_KHR_gl_texture_3D_image", glTexture3DImage, &extensionStrings); - InsertExtensionString("EGL_KHR_gl_renderbuffer_image", glRenderbufferImage, &extensionStrings); - InsertExtensionString("EGL_KHR_get_all_proc_addresses", getAllProcAddresses, &extensionStrings); - InsertExtensionString("EGL_ANGLE_flexible_surface_compatibility", flexibleSurfaceCompatibility, &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_d3d_texture_client_buffer", d3dTextureClientBuffer, &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_ANGLE_keyed_mutex", keyedMutex, &extensionStrings); + InsertExtensionString("EGL_ANGLE_surface_orientation", surfaceOrientation, &extensionStrings); + InsertExtensionString("EGL_ANGLE_direct_composition", directComposition, &extensionStrings); + InsertExtensionString("EGL_NV_post_sub_buffer", postSubBuffer, &extensionStrings); + InsertExtensionString("EGL_KHR_create_context", createContext, &extensionStrings); + InsertExtensionString("EGL_EXT_device_query", deviceQuery, &extensionStrings); + InsertExtensionString("EGL_KHR_image", image, &extensionStrings); + InsertExtensionString("EGL_KHR_image_base", imageBase, &extensionStrings); + InsertExtensionString("EGL_KHR_image_pixmap", imagePixmap, &extensionStrings); + InsertExtensionString("EGL_KHR_gl_texture_2D_image", glTexture2DImage, &extensionStrings); + InsertExtensionString("EGL_KHR_gl_texture_cubemap_image", glTextureCubemapImage, &extensionStrings); + InsertExtensionString("EGL_KHR_gl_texture_3D_image", glTexture3DImage, &extensionStrings); + InsertExtensionString("EGL_KHR_gl_renderbuffer_image", glRenderbufferImage, &extensionStrings); + InsertExtensionString("EGL_KHR_get_all_proc_addresses", getAllProcAddresses, &extensionStrings); + InsertExtensionString("EGL_KHR_stream", stream, &extensionStrings); + InsertExtensionString("EGL_KHR_stream_consumer_gltexture", streamConsumerGLTexture, &extensionStrings); + InsertExtensionString("EGL_NV_stream_consumer_gltexture_yuv", streamConsumerGLTextureYUV, &extensionStrings); + InsertExtensionString("EGL_ANGLE_flexible_surface_compatibility", flexibleSurfaceCompatibility, &extensionStrings); + InsertExtensionString("EGL_ANGLE_stream_producer_d3d_texture_nv12", streamProducerD3DTextureNV12, &extensionStrings); + InsertExtensionString("EGL_ANGLE_create_context_webgl_compatibility", createContextWebGLCompatibility, &extensionStrings); + InsertExtensionString("EGL_CHROMIUM_create_context_bind_generates_resource", createContextBindGeneratesResource, &extensionStrings); + InsertExtensionString("EGL_CHROMIUM_sync_control", getSyncValues, &extensionStrings); + InsertExtensionString("EGL_EXT_swap_buffers_with_damage", swapBuffersWithDamage, &extensionStrings); + InsertExtensionString("EGL_EXT_pixel_format_float", pixelFormatFloat, &extensionStrings); + InsertExtensionString("EGL_KHR_surfaceless_context", surfacelessContext, &extensionStrings); + InsertExtensionString("EGL_ANGLE_display_texture_share_group", displayTextureShareGroup, &extensionStrings); + InsertExtensionString("EGL_ANGLE_create_context_client_arrays", createContextClientArrays, &extensionStrings); + InsertExtensionString("EGL_ANGLE_program_cache_control", programCacheControl, &extensionStrings); + InsertExtensionString("EGL_ANGLE_robust_resource_initialization", robustResourceInitialization, &extensionStrings); // TODO(jmadill): Enable this when complete. - //InsertExtensionString("KHR_create_context_no_error", createContextNoError, &extensionStrings); + //InsertExtensionString("KHR_create_context_no_error", createContextNoError, &extensionStrings); // clang-format on return extensionStrings; @@ -694,6 +1175,7 @@ ClientExtensions::ClientExtensions() platformANGLE(false), platformANGLED3D(false), platformANGLEOpenGL(false), + platformANGLEVulkan(false), deviceCreation(false), deviceCreationD3D11(false), x11Visual(false), @@ -702,6 +1184,8 @@ ClientExtensions::ClientExtensions() { } +ClientExtensions::ClientExtensions(const ClientExtensions &other) = default; + std::vector ClientExtensions::getStrings() const { std::vector extensionStrings; @@ -714,6 +1198,8 @@ std::vector ClientExtensions::getStrings() const InsertExtensionString("EGL_ANGLE_platform_angle", platformANGLE, &extensionStrings); InsertExtensionString("EGL_ANGLE_platform_angle_d3d", platformANGLED3D, &extensionStrings); InsertExtensionString("EGL_ANGLE_platform_angle_opengl", platformANGLEOpenGL, &extensionStrings); + InsertExtensionString("EGL_ANGLE_platform_angle_null", platformANGLENULL, &extensionStrings); + InsertExtensionString("EGL_ANGLE_platform_angle_vulkan", platformANGLEVulkan, &extensionStrings); InsertExtensionString("EGL_ANGLE_device_creation", deviceCreation, &extensionStrings); InsertExtensionString("EGL_ANGLE_device_creation_d3d11", deviceCreationD3D11, &extensionStrings); InsertExtensionString("EGL_ANGLE_x11_visual", x11Visual, &extensionStrings); @@ -724,4 +1210,4 @@ std::vector ClientExtensions::getStrings() const return extensionStrings; } -} +} // namespace egl diff --git a/src/3rdparty/angle/src/libANGLE/Caps.h b/src/3rdparty/angle/src/libANGLE/Caps.h index d0e839a2ba..64bdf97112 100644 --- a/src/3rdparty/angle/src/libANGLE/Caps.h +++ b/src/3rdparty/angle/src/libANGLE/Caps.h @@ -8,21 +8,28 @@ #define LIBANGLE_CAPS_H_ #include "angle_gl.h" +#include "libANGLE/Version.h" #include "libANGLE/angletypes.h" +#include "libANGLE/renderer/Format.h" #include #include #include #include +#include namespace gl { +struct Extensions; + typedef std::set SupportedSampleSet; struct TextureCaps { TextureCaps(); + TextureCaps(const TextureCaps &other); + ~TextureCaps(); // Supports for basic texturing: glTexImage, glTexSubImage, etc bool texturable; @@ -44,26 +51,37 @@ struct TextureCaps GLuint getNearestSamples(GLuint requestedSamples) const; }; -class TextureCapsMap +TextureCaps GenerateMinimumTextureCaps(GLenum internalFormat, + const Version &clientVersion, + const Extensions &extensions); + +class TextureCapsMap final : angle::NonCopyable { public: - typedef std::map::const_iterator const_iterator; + TextureCapsMap(); + ~TextureCapsMap(); + // These methods are deprecated. Please use angle::Format for new features. 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; + void clear(); - size_t size() const; + // Prefer using angle::Format methods. + const TextureCaps &get(angle::Format::ID formatID) const; + void set(angle::Format::ID formatID, const TextureCaps &caps); private: - typedef std::map InternalFormatToCapsMap; - InternalFormatToCapsMap mCapsMap; + TextureCaps &get(angle::Format::ID formatID); + + // Indexed by angle::Format::ID + std::array mFormatData; }; +void InitMinimumTextureCapsMap(const Version &clientVersion, + const Extensions &extensions, + TextureCapsMap *capsMap); + struct Extensions { Extensions(); @@ -87,6 +105,7 @@ struct Extensions // GL_EXT_sRGB // GL_ANGLE_depth_texture, GL_OES_depth32 // GL_EXT_color_buffer_float + // GL_EXT_texture_norm16 void setTextureExtensionSupport(const TextureCapsMap &textureCaps); // ES2 Extension support @@ -141,12 +160,18 @@ struct Extensions 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 + // Implies that TextureCaps exist 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_texture_compression_s3tc_srgb + // Implies that TextureCaps exist for GL_COMPRESSED_SRGB_S3TC_DXT1_EXT, + // GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT, and + // GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT + bool textureCompressionS3TCsRGB; + // GL_KHR_texture_compression_astc_hdr bool textureCompressionASTCHDR; @@ -188,9 +213,6 @@ struct Extensions // GL_NV_fence bool fence; - // GL_ANGLE_timer_query - bool timerQuery; - // GL_EXT_disjoint_timer_query bool disjointTimerQuery; GLuint queryCounterBitsTimeElapsed; @@ -199,6 +221,9 @@ struct Extensions // GL_EXT_robustness bool robustness; + // GL_KHR_robust_buffer_access_behavior + bool robustBufferAccessBehavior; + // GL_EXT_blend_minmax bool blendMinMax; @@ -220,18 +245,13 @@ struct Extensions // 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; + // ANGLE_multiview + bool multiview; + GLuint maxViews; + // GL_ANGLE_texture_usage bool textureUsage; @@ -256,6 +276,9 @@ struct Extensions // GL_OES_EGL_image_external_essl3 bool eglImageExternalEssl3; + // NV_EGL_stream_consumer_external + bool eglStreamConsumerExternal; + // EXT_unpack_subimage bool unpackSubimage; @@ -278,12 +301,98 @@ struct Extensions // GL_ANGLE_lossy_etc_decode bool lossyETCDecode; + // GL_CHROMIUM_bind_uniform_location + bool bindUniformLocation; + + // GL_CHROMIUM_sync_query + bool syncQuery; + + // GL_CHROMIUM_copy_texture + bool copyTexture; + + // GL_CHROMIUM_copy_compressed_texture + bool copyCompressedTexture; + + // GL_ANGLE_webgl_compatibility + bool webglCompatibility; + + // GL_ANGLE_request_extension + bool requestExtension; + + // GL_CHROMIUM_bind_generates_resource + bool bindGeneratesResource; + + // GL_ANGLE_robust_client_memory + bool robustClientMemory; + + // GL_EXT_texture_sRGB_decode + bool textureSRGBDecode; + + // GL_EXT_sRGB_write_control + bool sRGBWriteControl; + + // GL_CHROMIUM_color_buffer_float_rgb + bool colorBufferFloatRGB; + + // GL_CHROMIUM_color_buffer_float_rgba + bool colorBufferFloatRGBA; + // ES3 Extension support // GL_EXT_color_buffer_float bool colorBufferFloat; + + // GL_EXT_multisample_compatibility. + // written against ES 3.1 but can apply to earlier versions. + bool multisampleCompatibility; + + // GL_CHROMIUM_framebuffer_mixed_samples + bool framebufferMixedSamples; + + // GL_EXT_texture_norm16 + // written against ES 3.1 but can apply to ES 3.0 as well. + bool textureNorm16; + + // GL_CHROMIUM_path_rendering + bool pathRendering; + + // GL_OES_surfaceless_context + bool surfacelessContext; + + // GL_ANGLE_client_arrays + bool clientArrays; + + // GL_ANGLE_robust_resource_initialization + bool robustResourceInitialization; + + // GL_ANGLE_program_cache_control + bool programCacheControl; + + // GL_ANGLE_texture_rectangle + bool textureRectangle; + + // GL_EXT_geometry_shader + bool geometryShader; + // GL_EXT_geometry_shader (May 31, 2016) Table 20.43gs: Implementation dependent geometry shader + // limits + // TODO(jiawei.shao@intel.com): add all implementation dependent geometry shader limits. + GLuint maxGeometryOutputVertices; + GLuint maxGeometryShaderInvocations; }; +struct ExtensionInfo +{ + // If this extension can be enabled with glRequestExtension (GL_ANGLE_request_extension) + bool Requestable = false; + + // Pointer to a boolean member of the Extensions struct + typedef bool(Extensions::*ExtensionBool); + ExtensionBool ExtensionsMember = nullptr; +}; + +using ExtensionInfoMap = std::map; +const ExtensionInfoMap &GetExtensionInfoMap(); + struct Limitations { Limitations(); @@ -311,39 +420,57 @@ struct Limitations struct TypePrecision { TypePrecision(); + TypePrecision(const TypePrecision &other); void setIEEEFloat(); void setTwosComplementInt(unsigned int bits); + void setSimulatedFloat(unsigned int range, unsigned int precision); void setSimulatedInt(unsigned int range); void get(GLint *returnRange, GLint *returnPrecision) const; - GLint range[2]; + std::array range; GLint precision; }; struct Caps { Caps(); + Caps(const Caps &other); + ~Caps(); - // Table 6.28, implementation dependent values + // ES 3.1 (April 29, 2015) 20.39: implementation dependent values GLuint64 maxElementIndex; GLuint max3DTextureSize; GLuint max2DTextureSize; + GLuint maxRectangleTextureSize; 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.) + // ES 3.1 (April 29, 2015) 20.40: implementation dependent values (cont.) + GLuint maxDrawBuffers; + GLuint maxFramebufferWidth; + GLuint maxFramebufferHeight; + GLuint maxFramebufferSamples; + GLuint maxColorAttachments; + GLuint maxViewportWidth; + GLuint maxViewportHeight; + GLuint maxSampleMaskWords; + GLuint maxColorTextureSamples; + GLuint maxDepthTextureSamples; + GLuint maxIntegerSamples; + GLuint64 maxServerWaitTimeout; + + // ES 3.1 (April 29, 2015) Table 20.41: Implementation dependent values (cont.) + GLint maxVertexAttribRelativeOffset; + GLuint maxVertexAttribBindings; + GLint maxVertexAttribStride; GLuint maxElementsIndices; GLuint maxElementsVertices; std::vector compressedTextureFormats; @@ -361,26 +488,49 @@ struct Caps TypePrecision fragmentHighpInt; TypePrecision fragmentMediumpInt; TypePrecision fragmentLowpInt; - GLuint64 maxServerWaitTimeout; - // Table 6.31, implementation dependent vertex shader limits + // ES 3.1 (April 29, 2015) Table 20.43: Implementation dependent Vertex shader limits GLuint maxVertexAttributes; GLuint maxVertexUniformComponents; GLuint maxVertexUniformVectors; GLuint maxVertexUniformBlocks; GLuint maxVertexOutputComponents; GLuint maxVertexTextureImageUnits; + GLuint maxVertexAtomicCounterBuffers; + GLuint maxVertexAtomicCounters; + GLuint maxVertexImageUniforms; + GLuint maxVertexShaderStorageBlocks; - // Table 6.32, implementation dependent fragment shader limits + // ES 3.1 (April 29, 2015) Table 20.44: Implementation dependent Fragment shader limits GLuint maxFragmentUniformComponents; GLuint maxFragmentUniformVectors; GLuint maxFragmentUniformBlocks; GLuint maxFragmentInputComponents; GLuint maxTextureImageUnits; + GLuint maxFragmentAtomicCounterBuffers; + GLuint maxFragmentAtomicCounters; + GLuint maxFragmentImageUniforms; + GLuint maxFragmentShaderStorageBlocks; + GLint minProgramTextureGatherOffset; + GLuint maxProgramTextureGatherOffset; GLint minProgramTexelOffset; GLint maxProgramTexelOffset; - // Table 6.33, implementation dependent aggregate shader limits + // ES 3.1 (April 29, 2015) Table 20.45: implementation dependent compute shader limits + std::array maxComputeWorkGroupCount; + std::array maxComputeWorkGroupSize; + GLuint maxComputeWorkGroupInvocations; + GLuint maxComputeUniformBlocks; + GLuint maxComputeTextureImageUnits; + GLuint maxComputeSharedMemorySize; + GLuint maxComputeUniformComponents; + GLuint maxComputeAtomicCounterBuffers; + GLuint maxComputeAtomicCounters; + GLuint maxComputeImageUniforms; + GLuint maxCombinedComputeUniformComponents; + GLuint maxComputeShaderStorageBlocks; + + // ES 3.1 (April 29, 2015) Table 20.46: implementation dependent aggregate shader limits GLuint maxUniformBufferBindings; GLuint64 maxUniformBlockSize; GLuint uniformBufferOffsetAlignment; @@ -390,16 +540,31 @@ struct Caps GLuint maxVaryingComponents; GLuint maxVaryingVectors; GLuint maxCombinedTextureImageUnits; - - // Table 6.34, implementation dependent transform feedback limits + GLuint maxCombinedShaderOutputResources; + + // ES 3.1 (April 29, 2015) Table 20.47: implementation dependent aggregate shader limits (cont.) + GLuint maxUniformLocations; + GLuint maxAtomicCounterBufferBindings; + GLuint maxAtomicCounterBufferSize; + GLuint maxCombinedAtomicCounterBuffers; + GLuint maxCombinedAtomicCounters; + GLuint maxImageUnits; + GLuint maxCombinedImageUniforms; + GLuint maxShaderStorageBufferBindings; + GLuint64 maxShaderStorageBlockSize; + GLuint maxCombinedShaderStorageBlocks; + GLuint shaderStorageBufferOffsetAlignment; + + // ES 3.1 (April 29, 2015) Table 20.48: implementation dependent transform feedback limits GLuint maxTransformFeedbackInterleavedComponents; GLuint maxTransformFeedbackSeparateAttributes; GLuint maxTransformFeedbackSeparateComponents; - // Table 6.35, Framebuffer Dependent Values + // ES 3.1 (April 29, 2015) Table 20.49: Framebuffer Dependent Values GLuint maxSamples; }; +Caps GenerateMinimumCaps(const Version &clientVersion, const Extensions &extensions); } namespace egl @@ -426,6 +591,9 @@ struct DisplayExtensions // EGL_ANGLE_d3d_share_handle_client_buffer bool d3dShareHandleClientBuffer; + // EGL_ANGLE_d3d_texture_client_buffer + bool d3dTextureClientBuffer; + // EGL_ANGLE_surface_d3d_texture_2d_share_handle bool surfaceD3DTexture2DShareHandle; @@ -482,6 +650,48 @@ struct DisplayExtensions // KHR_create_context_no_error bool createContextNoError; + + // EGL_KHR_stream + bool stream; + + // EGL_KHR_stream_consumer_gltexture + bool streamConsumerGLTexture; + + // EGL_NV_stream_consumer_gltexture_yuv + bool streamConsumerGLTextureYUV; + + // EGL_ANGLE_stream_producer_d3d_texture_nv12 + bool streamProducerD3DTextureNV12; + + // EGL_ANGLE_create_context_webgl_compatibility + bool createContextWebGLCompatibility; + + // EGL_CHROMIUM_create_context_bind_generates_resource + bool createContextBindGeneratesResource; + + // EGL_CHROMIUM_get_sync_values + bool getSyncValues; + + // EGL_EXT_swap_buffers_with_damage + bool swapBuffersWithDamage; + + // EGL_EXT_pixel_format_float + bool pixelFormatFloat; + + // EGL_KHR_surfaceless_context + bool surfacelessContext; + + // EGL_ANGLE_display_texture_share_group + bool displayTextureShareGroup; + + // EGL_ANGLE_create_context_client_arrays + bool createContextClientArrays; + + // EGL_ANGLE_program_cache_control + bool programCacheControl; + + // EGL_ANGLE_robust_resource_initialization + bool robustResourceInitialization; }; struct DeviceExtensions @@ -498,6 +708,7 @@ struct DeviceExtensions struct ClientExtensions { ClientExtensions(); + ClientExtensions(const ClientExtensions &other); // Generate a vector of supported extension strings std::vector getStrings() const; @@ -520,6 +731,12 @@ struct ClientExtensions // EGL_ANGLE_platform_angle_opengl bool platformANGLEOpenGL; + // EGL_ANGLE_platform_angle_null + bool platformANGLENULL; + + // EGL_ANGLE_platform_angle_vulkan + bool platformANGLEVulkan; + // EGL_ANGLE_device_creation bool deviceCreation; @@ -536,6 +753,6 @@ struct ClientExtensions bool clientGetAllProcAddresses; }; -} +} // namespace egl #endif // LIBANGLE_CAPS_H_ diff --git a/src/3rdparty/angle/src/libANGLE/Compiler.cpp b/src/3rdparty/angle/src/libANGLE/Compiler.cpp index 348c41bef3..236c7e1fc2 100644 --- a/src/3rdparty/angle/src/libANGLE/Compiler.cpp +++ b/src/3rdparty/angle/src/libANGLE/Compiler.cpp @@ -9,9 +9,9 @@ #include "libANGLE/Compiler.h" #include "common/debug.h" -#include "libANGLE/Data.h" +#include "libANGLE/ContextState.h" #include "libANGLE/renderer/CompilerImpl.h" -#include "libANGLE/renderer/ImplFactory.h" +#include "libANGLE/renderer/GLImplFactory.h" namespace gl { @@ -19,26 +19,46 @@ namespace gl namespace { -// Global count of active shader compiler handles. Needed to know when to call ShInitialize and -// ShFinalize. +// Global count of active shader compiler handles. Needed to know when to call sh::Initialize and +// sh::Finalize. size_t activeCompilerHandles = 0; +ShShaderSpec SelectShaderSpec(GLint majorVersion, GLint minorVersion, bool isWebGL) +{ + if (majorVersion >= 3) + { + if (minorVersion == 1) + { + return isWebGL ? SH_WEBGL3_SPEC : SH_GLES3_1_SPEC; + } + else + { + return isWebGL ? SH_WEBGL2_SPEC : SH_GLES3_SPEC; + } + } + return isWebGL ? SH_WEBGL_SPEC : SH_GLES2_SPEC; +} + } // anonymous namespace -Compiler::Compiler(rx::ImplFactory *implFactory, const gl::Data &data) +Compiler::Compiler(rx::GLImplFactory *implFactory, const ContextState &state) : mImplementation(implFactory->createCompiler()), - mSpec(data.clientVersion > 2 ? SH_GLES3_SPEC : SH_GLES2_SPEC), + mSpec(SelectShaderSpec(state.getClientMajorVersion(), + state.getClientMinorVersion(), + state.getExtensions().webglCompatibility)), mOutputType(mImplementation->getTranslatorOutputType()), mResources(), mFragmentCompiler(nullptr), - mVertexCompiler(nullptr) + mVertexCompiler(nullptr), + mComputeCompiler(nullptr), + mGeometryCompiler(nullptr) { - ASSERT(data.clientVersion == 2 || data.clientVersion == 3); + ASSERT(state.getClientMajorVersion() == 2 || state.getClientMajorVersion() == 3); - const gl::Caps &caps = *data.caps; - const gl::Extensions &extensions = *data.extensions; + const gl::Caps &caps = state.getCaps(); + const gl::Extensions &extensions = state.getExtensions(); - ShInitBuiltInResources(&mResources); + sh::InitBuiltInResources(&mResources); mResources.MaxVertexAttribs = caps.maxVertexAttributes; mResources.MaxVertexUniformVectors = caps.maxVertexUniformVectors; mResources.MaxVaryingVectors = caps.maxVaryingVectors; @@ -50,30 +70,79 @@ Compiler::Compiler(rx::ImplFactory *implFactory, const gl::Data &data) mResources.OES_standard_derivatives = extensions.standardDerivatives; mResources.EXT_draw_buffers = extensions.drawBuffers; mResources.EXT_shader_texture_lod = extensions.shaderTextureLOD; - // TODO: disabled until the extension is actually supported. - mResources.OES_EGL_image_external = 0; + mResources.OES_EGL_image_external = extensions.eglImageExternal; + mResources.OES_EGL_image_external_essl3 = extensions.eglImageExternalEssl3; + mResources.NV_EGL_stream_consumer_external = extensions.eglStreamConsumerExternal; + mResources.ARB_texture_rectangle = extensions.textureRectangle; // TODO: use shader precision caps to determine if high precision is supported? mResources.FragmentPrecisionHigh = 1; mResources.EXT_frag_depth = extensions.fragDepth; + // OVR_multiview state + mResources.OVR_multiview = extensions.multiview; + mResources.MaxViewsOVR = extensions.maxViews; + // GLSL ES 3.0 constants mResources.MaxVertexOutputVectors = caps.maxVertexOutputComponents / 4; mResources.MaxFragmentInputVectors = caps.maxFragmentInputComponents / 4; mResources.MinProgramTexelOffset = caps.minProgramTexelOffset; mResources.MaxProgramTexelOffset = caps.maxProgramTexelOffset; -} -Compiler::~Compiler() -{ - release(); - SafeDelete(mImplementation); + // GLSL ES 3.1 constants + mResources.MaxProgramTextureGatherOffset = caps.maxProgramTextureGatherOffset; + mResources.MinProgramTextureGatherOffset = caps.minProgramTextureGatherOffset; + mResources.MaxImageUnits = caps.maxImageUnits; + mResources.MaxVertexImageUniforms = caps.maxVertexImageUniforms; + mResources.MaxFragmentImageUniforms = caps.maxFragmentImageUniforms; + mResources.MaxComputeImageUniforms = caps.maxComputeImageUniforms; + mResources.MaxCombinedImageUniforms = caps.maxCombinedImageUniforms; + mResources.MaxCombinedShaderOutputResources = caps.maxCombinedShaderOutputResources; + mResources.MaxUniformLocations = caps.maxUniformLocations; + + for (size_t index = 0u; index < 3u; ++index) + { + mResources.MaxComputeWorkGroupCount[index] = caps.maxComputeWorkGroupCount[index]; + mResources.MaxComputeWorkGroupSize[index] = caps.maxComputeWorkGroupSize[index]; + } + + mResources.MaxComputeUniformComponents = caps.maxComputeUniformComponents; + mResources.MaxComputeTextureImageUnits = caps.maxComputeTextureImageUnits; + + mResources.MaxComputeAtomicCounters = caps.maxComputeAtomicCounters; + mResources.MaxComputeAtomicCounterBuffers = caps.maxComputeAtomicCounterBuffers; + + mResources.MaxVertexAtomicCounters = caps.maxVertexAtomicCounters; + mResources.MaxFragmentAtomicCounters = caps.maxFragmentAtomicCounters; + mResources.MaxCombinedAtomicCounters = caps.maxCombinedAtomicCounters; + mResources.MaxAtomicCounterBindings = caps.maxAtomicCounterBufferBindings; + mResources.MaxVertexAtomicCounterBuffers = caps.maxVertexAtomicCounterBuffers; + mResources.MaxFragmentAtomicCounterBuffers = caps.maxFragmentAtomicCounterBuffers; + mResources.MaxCombinedAtomicCounterBuffers = caps.maxCombinedAtomicCounterBuffers; + mResources.MaxAtomicCounterBufferSize = caps.maxAtomicCounterBufferSize; + + mResources.MaxUniformBufferBindings = caps.maxUniformBufferBindings; + mResources.MaxShaderStorageBufferBindings = caps.maxShaderStorageBufferBindings; + + // Needed by point size clamping workaround + mResources.MaxPointSize = caps.maxAliasedPointSize; + + if (state.getClientMajorVersion() == 2 && !extensions.drawBuffers) + { + mResources.MaxDrawBuffers = 1; + } + + // Geometry Shader constants + mResources.OES_geometry_shader = extensions.geometryShader; + // TODO(jiawei.shao@intel.com): initialize all implementation dependent geometry shader limits. + mResources.MaxGeometryOutputVertices = extensions.maxGeometryOutputVertices; + mResources.MaxGeometryShaderInvocations = extensions.maxGeometryShaderInvocations; } -Error Compiler::release() +Compiler::~Compiler() { if (mFragmentCompiler) { - ShDestruct(mFragmentCompiler); + sh::Destruct(mFragmentCompiler); mFragmentCompiler = nullptr; ASSERT(activeCompilerHandles > 0); @@ -82,21 +151,28 @@ Error Compiler::release() if (mVertexCompiler) { - ShDestruct(mVertexCompiler); + sh::Destruct(mVertexCompiler); mVertexCompiler = nullptr; ASSERT(activeCompilerHandles > 0); activeCompilerHandles--; } - if (activeCompilerHandles == 0) + if (mComputeCompiler) { - ShFinalize(); + sh::Destruct(mComputeCompiler); + mComputeCompiler = nullptr; + + ASSERT(activeCompilerHandles > 0); + activeCompilerHandles--; } - mImplementation->release(); + if (activeCompilerHandles == 0) + { + sh::Finalize(); + } - return gl::Error(GL_NO_ERROR); + ANGLE_SWALLOW_ERR(mImplementation->release()); } ShHandle Compiler::getCompilerHandle(GLenum type) @@ -111,7 +187,12 @@ ShHandle Compiler::getCompilerHandle(GLenum type) case GL_FRAGMENT_SHADER: compiler = &mFragmentCompiler; break; - + case GL_COMPUTE_SHADER: + compiler = &mComputeCompiler; + break; + case GL_GEOMETRY_SHADER_EXT: + compiler = &mGeometryCompiler; + break; default: UNREACHABLE(); return nullptr; @@ -121,14 +202,20 @@ ShHandle Compiler::getCompilerHandle(GLenum type) { if (activeCompilerHandles == 0) { - ShInitialize(); + sh::Initialize(); } - *compiler = ShConstructCompiler(type, mSpec, mOutputType, &mResources); + *compiler = sh::ConstructCompiler(type, mSpec, mOutputType, &mResources); + ASSERT(*compiler); activeCompilerHandles++; } return *compiler; } +const std::string &Compiler::getBuiltinResourcesString(GLenum type) +{ + return sh::GetBuiltInResourcesString(getCompilerHandle(type)); +} + } // namespace gl diff --git a/src/3rdparty/angle/src/libANGLE/Compiler.h b/src/3rdparty/angle/src/libANGLE/Compiler.h index 8634e39a45..b7f7e9f31b 100644 --- a/src/3rdparty/angle/src/libANGLE/Compiler.h +++ b/src/3rdparty/angle/src/libANGLE/Compiler.h @@ -10,38 +10,40 @@ #ifndef LIBANGLE_COMPILER_H_ #define LIBANGLE_COMPILER_H_ -#include "libANGLE/Error.h" #include "GLSLANG/ShaderLang.h" +#include "libANGLE/Error.h" +#include "libANGLE/RefCountObject.h" namespace rx { class CompilerImpl; -class ImplFactory; +class GLImplFactory; } namespace gl { -struct Data; +class ContextState; -class Compiler final : angle::NonCopyable +class Compiler final : public RefCountObjectNoID { public: - Compiler(rx::ImplFactory *implFactory, const Data &data); - ~Compiler(); - - Error release(); + Compiler(rx::GLImplFactory *implFactory, const ContextState &data); ShHandle getCompilerHandle(GLenum type); ShShaderOutput getShaderOutputType() const { return mOutputType; } + const std::string &getBuiltinResourcesString(GLenum type); private: - rx::CompilerImpl *mImplementation; + ~Compiler() override; + std::unique_ptr mImplementation; ShShaderSpec mSpec; ShShaderOutput mOutputType; ShBuiltInResources mResources; ShHandle mFragmentCompiler; ShHandle mVertexCompiler; + ShHandle mComputeCompiler; + ShHandle mGeometryCompiler; }; } // namespace gl diff --git a/src/3rdparty/angle/src/libANGLE/Config.cpp b/src/3rdparty/angle/src/libANGLE/Config.cpp index d511df3a69..172c312ae0 100644 --- a/src/3rdparty/angle/src/libANGLE/Config.cpp +++ b/src/3rdparty/angle/src/libANGLE/Config.cpp @@ -58,10 +58,27 @@ Config::Config() transparentRedValue(0), transparentGreenValue(0), transparentBlueValue(0), - optimalOrientation(0) + optimalOrientation(0), + colorComponentType(EGL_COLOR_COMPONENT_TYPE_FIXED_EXT) { } +Config::~Config() +{ +} + +Config::Config(const Config &other) = default; + +Config &Config::operator=(const Config &other) = default; + +ConfigSet::ConfigSet() = default; + +ConfigSet::ConfigSet(const ConfigSet &other) = default; + +ConfigSet &ConfigSet::operator=(const ConfigSet &other) = default; + +ConfigSet::~ConfigSet() = default; + 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) @@ -134,6 +151,10 @@ class ConfigSorter static_assert(EGL_NONE < EGL_SLOW_CONFIG && EGL_SLOW_CONFIG < EGL_NON_CONFORMANT_CONFIG, "Unexpected EGL enum value."); SORT(configCaveat); + static_assert(EGL_COLOR_COMPONENT_TYPE_FIXED_EXT < EGL_COLOR_COMPONENT_TYPE_FLOAT_EXT, + "Unexpected order of EGL enums."); + SORT(colorComponentType); + static_assert(EGL_RGB_BUFFER < EGL_LUMINANCE_BUFFER, "Unexpected EGL enum value."); SORT(colorBufferType); @@ -160,6 +181,7 @@ class ConfigSorter } private: + void scanForWantedComponents(const AttributeMap &attributeMap) { // [EGL 1.5] section 3.4.1.2 page 30 @@ -215,8 +237,13 @@ std::vector ConfigSet::filter(const AttributeMap &attributeMap) c for (auto attribIter = attributeMap.begin(); attribIter != attributeMap.end(); attribIter++) { - EGLint attributeKey = attribIter->first; - EGLint attributeValue = attribIter->second; + EGLAttrib attributeKey = attribIter->first; + EGLAttrib attributeValue = attribIter->second; + + if (attributeValue == EGL_DONT_CARE) + { + continue; + } switch (attributeKey) { @@ -255,6 +282,9 @@ std::vector ConfigSet::filter(const AttributeMap &attributeMap) c case EGL_OPTIMAL_SURFACE_ORIENTATION_ANGLE: match = config.optimalOrientation == attributeValue; break; + case EGL_COLOR_COMPONENT_TYPE_EXT: + match = config.colorComponentType == static_cast(attributeValue); + break; default: UNREACHABLE(); } diff --git a/src/3rdparty/angle/src/libANGLE/Config.h b/src/3rdparty/angle/src/libANGLE/Config.h index 00f5673b59..f2fbe8b95a 100644 --- a/src/3rdparty/angle/src/libANGLE/Config.h +++ b/src/3rdparty/angle/src/libANGLE/Config.h @@ -27,6 +27,9 @@ namespace egl struct Config { Config(); + ~Config(); + Config(const Config &other); + Config &operator=(const Config &other); GLenum renderTargetFormat; // TODO(geofflang): remove this GLenum depthStencilFormat; // TODO(geofflang): remove this @@ -65,11 +68,17 @@ struct Config EGLint transparentGreenValue; // Transparent green value EGLint transparentBlueValue; // Transparent blue value EGLint optimalOrientation; // Optimal window surface orientation + EGLenum colorComponentType; // Color component type }; class ConfigSet { public: + ConfigSet(); + ConfigSet(const ConfigSet &other); + ~ConfigSet(); + ConfigSet &operator=(const ConfigSet &other); + EGLint add(const Config &config); const Config &get(EGLint id) const; @@ -83,7 +92,7 @@ class ConfigSet std::vector filter(const AttributeMap &attributeMap) const; private: - typedef std::map ConfigMap; + typedef std::map ConfigMap; ConfigMap mConfigs; }; diff --git a/src/3rdparty/angle/src/libANGLE/Constants.h b/src/3rdparty/angle/src/libANGLE/Constants.h index dc8f9555b8..2fe921af38 100644 --- a/src/3rdparty/angle/src/libANGLE/Constants.h +++ b/src/3rdparty/angle/src/libANGLE/Constants.h @@ -9,36 +9,54 @@ #ifndef LIBANGLE_CONSTANTS_H_ #define LIBANGLE_CONSTANTS_H_ +#include "common/platform.h" + namespace gl { +// The binary cache is currently left disable by default, and the application can enable it. +const size_t kDefaultMaxProgramCacheMemoryBytes = 0; + enum { - MAX_VERTEX_ATTRIBS = 16, + // Implementation upper limits, real maximums depend on the hardware + MAX_SAMPLE_MASK_WORDS = 2, + + MAX_VERTEX_ATTRIBS = 16, + MAX_VERTEX_ATTRIB_BINDINGS = 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_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_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_COMBINED_SHADER_UNIFORM_BUFFERS = + IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS + + IMPLEMENTATION_MAX_FRAGMENT_SHADER_UNIFORM_BUFFERS, IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS = 4, + // Maximum number of views which are supported by the implementation of ANGLE_multiview. + IMPLEMENTATION_ANGLE_MULTIVIEW_MAX_VIEWS = 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_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 -}; + // 1+log2 of max of MAX_*_TEXTURE_SIZE + IMPLEMENTATION_MAX_TEXTURE_LEVELS = 15, + // Limit active textures so we can use fast bitsets. + IMPLEMENTATION_MAX_SHADER_TEXTURES = 32, + IMPLEMENTATION_MAX_ACTIVE_TEXTURES = IMPLEMENTATION_MAX_SHADER_TEXTURES * 2, +}; } #endif // LIBANGLE_CONSTANTS_H_ diff --git a/src/3rdparty/angle/src/libANGLE/Context.cpp b/src/3rdparty/angle/src/libANGLE/Context.cpp index 26f2970068..f638beda58 100644 --- a/src/3rdparty/angle/src/libANGLE/Context.cpp +++ b/src/3rdparty/angle/src/libANGLE/Context.cpp @@ -9,18 +9,24 @@ #include "libANGLE/Context.h" +#include #include #include +#include +#include "common/matrix_utils.h" #include "common/platform.h" #include "common/utilities.h" +#include "common/version.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/Path.h" #include "libANGLE/Program.h" +#include "libANGLE/ProgramPipeline.h" #include "libANGLE/Query.h" #include "libANGLE/Renderbuffer.h" #include "libANGLE/ResourceManager.h" @@ -29,36 +35,97 @@ #include "libANGLE/Texture.h" #include "libANGLE/TransformFeedback.h" #include "libANGLE/VertexArray.h" +#include "libANGLE/Workarounds.h" #include "libANGLE/formatutils.h" +#include "libANGLE/queryconversions.h" +#include "libANGLE/queryutils.h" +#include "libANGLE/renderer/ContextImpl.h" +#include "libANGLE/renderer/EGLImplFactory.h" +#include "libANGLE/renderer/Format.h" #include "libANGLE/validationES.h" -#include "libANGLE/renderer/Renderer.h" namespace { +#define ANGLE_HANDLE_ERR(X) \ + handleError(X); \ + return; +#define ANGLE_CONTEXT_TRY(EXPR) ANGLE_TRY_TEMPLATE(EXPR, ANGLE_HANDLE_ERR); + +template +std::vector GatherPaths(gl::PathManager &resourceManager, + GLsizei numPaths, + const void *paths, + GLuint pathBase) +{ + std::vector ret; + ret.reserve(numPaths); + + const auto *nameArray = static_cast(paths); + + for (GLsizei i = 0; i < numPaths; ++i) + { + const GLuint pathName = nameArray[i] + pathBase; + + ret.push_back(resourceManager.getPath(pathName)); + } + + return ret; +} + +std::vector GatherPaths(gl::PathManager &resourceManager, + GLsizei numPaths, + GLenum pathNameType, + const void *paths, + GLuint pathBase) +{ + switch (pathNameType) + { + case GL_UNSIGNED_BYTE: + return GatherPaths(resourceManager, numPaths, paths, pathBase); + + case GL_BYTE: + return GatherPaths(resourceManager, numPaths, paths, pathBase); + + case GL_UNSIGNED_SHORT: + return GatherPaths(resourceManager, numPaths, paths, pathBase); + + case GL_SHORT: + return GatherPaths(resourceManager, numPaths, paths, pathBase); + + case GL_UNSIGNED_INT: + return GatherPaths(resourceManager, numPaths, paths, pathBase); + + case GL_INT: + return GatherPaths(resourceManager, numPaths, paths, pathBase); + } + + UNREACHABLE(); + return std::vector(); +} + template -gl::Error GetQueryObjectParameter(gl::Context *context, GLuint id, GLenum pname, T *params) +gl::Error GetQueryObjectParameter(gl::Query *query, GLenum pname, T *params) { - gl::Query *queryObject = context->getQuery(id, false, GL_NONE); - ASSERT(queryObject != nullptr); + ASSERT(query != nullptr); switch (pname) { case GL_QUERY_RESULT_EXT: - return queryObject->getResult(params); + return query->getResult(params); case GL_QUERY_RESULT_AVAILABLE_EXT: { bool available; - gl::Error error = queryObject->isResultAvailable(&available); + gl::Error error = query->isResultAvailable(&available); if (!error.isError()) { - *params = static_cast(available ? GL_TRUE : GL_FALSE); + *params = gl::CastFromStateValue(pname, static_cast(available)); } return error; } default: UNREACHABLE(); - return gl::Error(GL_INVALID_OPERATION, "Unreachable Error"); + return gl::InternalError() << "Unreachable Error"; } } @@ -69,7 +136,7 @@ void MarkTransformFeedbackBufferUsage(gl::TransformFeedback *transformFeedback) for (size_t tfBufferIndex = 0; tfBufferIndex < transformFeedback->getIndexedBufferCount(); tfBufferIndex++) { - const OffsetBindingPointer &buffer = + const gl::OffsetBindingPointer &buffer = transformFeedback->getIndexedBuffer(tfBufferIndex); if (buffer.get() != nullptr) { @@ -80,15 +147,25 @@ void MarkTransformFeedbackBufferUsage(gl::TransformFeedback *transformFeedback) } // Attribute map queries. -EGLint GetClientVersion(const egl::AttributeMap &attribs) +EGLint GetClientMajorVersion(const egl::AttributeMap &attribs) +{ + return static_cast(attribs.get(EGL_CONTEXT_CLIENT_VERSION, 1)); +} + +EGLint GetClientMinorVersion(const egl::AttributeMap &attribs) +{ + return static_cast(attribs.get(EGL_CONTEXT_MINOR_VERSION, 0)); +} + +gl::Version GetClientVersion(const egl::AttributeMap &attribs) { - return attribs.get(EGL_CONTEXT_CLIENT_VERSION, 1); + return gl::Version(GetClientMajorVersion(attribs), GetClientMinorVersion(attribs)); } GLenum GetResetStrategy(const egl::AttributeMap &attribs) { - EGLenum attrib = attribs.get(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT, - EGL_NO_RESET_NOTIFICATION_EXT); + EGLAttrib attrib = attribs.get(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT, + EGL_NO_RESET_NOTIFICATION); switch (attrib) { case EGL_NO_RESET_NOTIFICATION: @@ -103,12 +180,15 @@ GLenum GetResetStrategy(const egl::AttributeMap &attribs) bool GetRobustAccess(const egl::AttributeMap &attribs) { - return (attribs.get(EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT, EGL_FALSE) == EGL_TRUE); + return (attribs.get(EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT, EGL_FALSE) == EGL_TRUE) || + ((attribs.get(EGL_CONTEXT_FLAGS_KHR, 0) & EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR) != + 0); } bool GetDebug(const egl::AttributeMap &attribs) { - return (attribs.get(EGL_CONTEXT_OPENGL_DEBUG, EGL_FALSE) == EGL_TRUE); + return (attribs.get(EGL_CONTEXT_OPENGL_DEBUG, EGL_FALSE) == EGL_TRUE) || + ((attribs.get(EGL_CONTEXT_FLAGS_KHR, 0) & EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR) != 0); } bool GetNoError(const egl::AttributeMap &attribs) @@ -116,504 +196,657 @@ bool GetNoError(const egl::AttributeMap &attribs) return (attribs.get(EGL_CONTEXT_OPENGL_NO_ERROR_KHR, EGL_FALSE) == EGL_TRUE); } +bool GetWebGLContext(const egl::AttributeMap &attribs) +{ + return (attribs.get(EGL_CONTEXT_WEBGL_COMPATIBILITY_ANGLE, EGL_FALSE) == EGL_TRUE); +} + +bool GetBindGeneratesResource(const egl::AttributeMap &attribs) +{ + return (attribs.get(EGL_CONTEXT_BIND_GENERATES_RESOURCE_CHROMIUM, EGL_TRUE) == EGL_TRUE); +} + +bool GetClientArraysEnabled(const egl::AttributeMap &attribs) +{ + return (attribs.get(EGL_CONTEXT_CLIENT_ARRAYS_ENABLED_ANGLE, EGL_TRUE) == EGL_TRUE); +} + +bool GetRobustResourceInit(const egl::AttributeMap &attribs) +{ + return (attribs.get(EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE, EGL_FALSE) == EGL_TRUE); +} + +std::string GetObjectLabelFromPointer(GLsizei length, const GLchar *label) +{ + std::string labelName; + if (label != nullptr) + { + size_t labelLength = length < 0 ? strlen(label) : length; + labelName = std::string(label, labelLength); + } + return labelName; +} + +void GetObjectLabelBase(const std::string &objectLabel, + GLsizei bufSize, + GLsizei *length, + GLchar *label) +{ + size_t writeLength = objectLabel.length(); + if (label != nullptr && bufSize > 0) + { + writeLength = std::min(static_cast(bufSize) - 1, objectLabel.length()); + std::copy(objectLabel.begin(), objectLabel.begin() + writeLength, label); + label[writeLength] = '\0'; + } + + if (length != nullptr) + { + *length = static_cast(writeLength); + } +} + +template +void LimitCap(CapT *cap, MaxT maximum) +{ + *cap = std::min(*cap, static_cast(maximum)); +} + } // anonymous namespace namespace gl { -Context::Context(const egl::Config *config, +Context::Context(rx::EGLImplFactory *implFactory, + const egl::Config *config, const Context *shareContext, - rx::Renderer *renderer, - const egl::AttributeMap &attribs) - : ValidationContext(GetClientVersion(attribs), - mState, + TextureManager *shareTextures, + MemoryProgramCache *memoryProgramCache, + const egl::AttributeMap &attribs, + const egl::DisplayExtensions &displayExtensions) + + : ValidationContext(shareContext, + shareTextures, + GetClientVersion(attribs), + &mGLState, mCaps, mTextureCaps, mExtensions, - nullptr, mLimitations, GetNoError(attribs)), - mCompiler(nullptr), - mRenderer(renderer), - mClientVersion(GetClientVersion(attribs)), + mImplementation(implFactory->createContext(mState)), + mCompiler(), mConfig(config), mClientType(EGL_OPENGL_ES_API), mHasBeenCurrent(false), mContextLost(false), mResetStatus(GL_NO_ERROR), + mContextLostForced(false), mResetStrategy(GetResetStrategy(attribs)), mRobustAccess(GetRobustAccess(attribs)), - mCurrentSurface(nullptr), - mResourceManager(nullptr) + mCurrentSurface(static_cast(EGL_NO_SURFACE)), + mCurrentDisplay(static_cast(EGL_NO_DISPLAY)), + mSurfacelessFramebuffer(nullptr), + mWebGLContext(GetWebGLContext(attribs)), + mMemoryProgramCache(memoryProgramCache), + mScratchBuffer(1000u), + mZeroFilledBuffer(1000u) { - ASSERT(!mRobustAccess); // Unimplemented + mImplementation->setMemoryProgramCache(memoryProgramCache); - initCaps(mClientVersion); + bool robustResourceInit = GetRobustResourceInit(attribs); + initCaps(displayExtensions, robustResourceInit); + initWorkarounds(); - mState.initialize(mCaps, mExtensions, mClientVersion, GetDebug(attribs)); + mGLState.initialize(this, GetDebug(attribs), GetBindGeneratesResource(attribs), + GetClientArraysEnabled(attribs), robustResourceInit, + mMemoryProgramCache != nullptr); mFenceNVHandleAllocator.setBaseHandle(0); - if (shareContext != NULL) - { - mResourceManager = shareContext->mResourceManager; - mResourceManager->addRef(); - } - else - { - mResourceManager = new ResourceManager(mRenderer); - } - - mData.resourceManager = mResourceManager; - // [OpenGL ES 2.0.24] section 3.7 page 83: - // In the initial state, TEXTURE_2D and TEXTURE_CUBE_MAP have twodimensional + // In the initial state, TEXTURE_2D and TEXTURE_CUBE_MAP have two-dimensional // 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 *zeroTexture2D = new Texture(mImplementation.get(), 0, GL_TEXTURE_2D); + mZeroTextures[GL_TEXTURE_2D].set(this, zeroTexture2D); - Texture *zeroTextureCube = new Texture(mRenderer->createTexture(GL_TEXTURE_CUBE_MAP), 0, GL_TEXTURE_CUBE_MAP); - mZeroTextures[GL_TEXTURE_CUBE_MAP].set(zeroTextureCube); + Texture *zeroTextureCube = new Texture(mImplementation.get(), 0, GL_TEXTURE_CUBE_MAP); + mZeroTextures[GL_TEXTURE_CUBE_MAP].set(this, zeroTextureCube); - if (mClientVersion >= 3) + if (getClientVersion() >= Version(3, 0)) { // 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 *zeroTexture3D = new Texture(mImplementation.get(), 0, GL_TEXTURE_3D); + mZeroTextures[GL_TEXTURE_3D].set(this, zeroTexture3D); - Texture *zeroTexture2DArray = new Texture(mRenderer->createTexture(GL_TEXTURE_2D_ARRAY), 0, GL_TEXTURE_2D_ARRAY); - mZeroTextures[GL_TEXTURE_2D_ARRAY].set(zeroTexture2DArray); + Texture *zeroTexture2DArray = new Texture(mImplementation.get(), 0, GL_TEXTURE_2D_ARRAY); + mZeroTextures[GL_TEXTURE_2D_ARRAY].set(this, zeroTexture2DArray); } + if (getClientVersion() >= Version(3, 1)) + { + Texture *zeroTexture2DMultisample = + new Texture(mImplementation.get(), 0, GL_TEXTURE_2D_MULTISAMPLE); + mZeroTextures[GL_TEXTURE_2D_MULTISAMPLE].set(this, zeroTexture2DMultisample); - mState.initializeZeroTextures(mZeroTextures); + for (unsigned int i = 0; i < mCaps.maxAtomicCounterBufferBindings; i++) + { + bindBufferRange(BufferBinding::AtomicCounter, 0, i, 0, 0); + } - bindVertexArray(0); - bindArrayBuffer(0); - bindElementArrayBuffer(0); + for (unsigned int i = 0; i < mCaps.maxShaderStorageBufferBindings; i++) + { + bindBufferRange(BufferBinding::ShaderStorage, i, 0, 0, 0); + } + } - bindRenderbuffer(0); + const Extensions &nativeExtensions = mImplementation->getNativeExtensions(); + if (nativeExtensions.textureRectangle) + { + Texture *zeroTextureRectangle = + new Texture(mImplementation.get(), 0, GL_TEXTURE_RECTANGLE_ANGLE); + mZeroTextures[GL_TEXTURE_RECTANGLE_ANGLE].set(this, zeroTextureRectangle); + } - bindGenericUniformBuffer(0); - for (unsigned int i = 0; i < mCaps.maxCombinedUniformBlocks; i++) + if (nativeExtensions.eglImageExternal || nativeExtensions.eglStreamConsumerExternal) { - bindIndexedUniformBuffer(0, i, 0, -1); + Texture *zeroTextureExternal = + new Texture(mImplementation.get(), 0, GL_TEXTURE_EXTERNAL_OES); + mZeroTextures[GL_TEXTURE_EXTERNAL_OES].set(this, zeroTextureExternal); } - bindCopyReadBuffer(0); - bindCopyWriteBuffer(0); - bindPixelPackBuffer(0); - bindPixelUnpackBuffer(0); + mGLState.initializeZeroTextures(this, mZeroTextures); - if (mClientVersion >= 3) + bindVertexArray(0); + + if (getClientVersion() >= Version(3, 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 - bindTransformFeedback(0); + bindTransformFeedback(GL_TRANSFORM_FEEDBACK, 0); } - mCompiler = new Compiler(mRenderer, getData()); -} + for (auto type : angle::AllEnums()) + { + bindBuffer(type, 0); + } -Context::~Context() -{ - mState.reset(); + bindRenderbuffer(GL_RENDERBUFFER, 0); - for (auto framebuffer : mFramebufferMap) + for (unsigned int i = 0; i < mCaps.maxUniformBufferBindings; i++) { - // Default framebuffer are owned by their respective Surface - if (framebuffer.second != nullptr && framebuffer.second->id() != 0) - { - SafeDelete(framebuffer.second); - } + bindBufferRange(BufferBinding::Uniform, i, 0, 0, -1); } + // Initialize dirty bit masks + mTexImageDirtyBits.set(State::DIRTY_BIT_UNPACK_STATE); + mTexImageDirtyBits.set(State::DIRTY_BIT_UNPACK_BUFFER_BINDING); + // No dirty objects. + + // Readpixels uses the pack state and read FBO + mReadPixelsDirtyBits.set(State::DIRTY_BIT_PACK_STATE); + mReadPixelsDirtyBits.set(State::DIRTY_BIT_PACK_BUFFER_BINDING); + mReadPixelsDirtyObjects.set(State::DIRTY_OBJECT_READ_FRAMEBUFFER); + + mClearDirtyBits.set(State::DIRTY_BIT_RASTERIZER_DISCARD_ENABLED); + mClearDirtyBits.set(State::DIRTY_BIT_SCISSOR_TEST_ENABLED); + mClearDirtyBits.set(State::DIRTY_BIT_SCISSOR); + mClearDirtyBits.set(State::DIRTY_BIT_VIEWPORT); + mClearDirtyBits.set(State::DIRTY_BIT_CLEAR_COLOR); + mClearDirtyBits.set(State::DIRTY_BIT_CLEAR_DEPTH); + mClearDirtyBits.set(State::DIRTY_BIT_CLEAR_STENCIL); + mClearDirtyBits.set(State::DIRTY_BIT_COLOR_MASK); + mClearDirtyBits.set(State::DIRTY_BIT_DEPTH_MASK); + mClearDirtyBits.set(State::DIRTY_BIT_STENCIL_WRITEMASK_FRONT); + mClearDirtyBits.set(State::DIRTY_BIT_STENCIL_WRITEMASK_BACK); + mClearDirtyObjects.set(State::DIRTY_OBJECT_DRAW_FRAMEBUFFER); + + mBlitDirtyBits.set(State::DIRTY_BIT_SCISSOR_TEST_ENABLED); + mBlitDirtyBits.set(State::DIRTY_BIT_SCISSOR); + mBlitDirtyBits.set(State::DIRTY_BIT_FRAMEBUFFER_SRGB); + mBlitDirtyObjects.set(State::DIRTY_OBJECT_READ_FRAMEBUFFER); + mBlitDirtyObjects.set(State::DIRTY_OBJECT_DRAW_FRAMEBUFFER); + + handleError(mImplementation->initialize()); +} + +egl::Error Context::onDestroy(const egl::Display *display) +{ for (auto fence : mFenceNVMap) { SafeDelete(fence.second); } + mFenceNVMap.clear(); for (auto query : mQueryMap) { if (query.second != nullptr) { - query.second->release(); + query.second->release(this); } } + mQueryMap.clear(); for (auto vertexArray : mVertexArrayMap) { - SafeDelete(vertexArray.second); + if (vertexArray.second) + { + vertexArray.second->onDestroy(this); + } } + mVertexArrayMap.clear(); for (auto transformFeedback : mTransformFeedbackMap) { if (transformFeedback.second != nullptr) { - transformFeedback.second->release(); + transformFeedback.second->release(this); } } + mTransformFeedbackMap.clear(); for (auto &zeroTexture : mZeroTextures) { - zeroTexture.second.set(NULL); + ANGLE_TRY(zeroTexture.second->onDestroy(this)); + zeroTexture.second.set(this, nullptr); } mZeroTextures.clear(); - if (mCurrentSurface != nullptr) - { - releaseSurface(); - } + SafeDelete(mSurfacelessFramebuffer); - if (mResourceManager) - { - mResourceManager->release(); - } + ANGLE_TRY(releaseSurface(display)); + releaseShaderCompiler(); + + mGLState.reset(this); - SafeDelete(mCompiler); + mState.mBuffers->release(this); + mState.mShaderPrograms->release(this); + mState.mTextures->release(this); + mState.mRenderbuffers->release(this); + mState.mSamplers->release(this); + mState.mSyncs->release(this); + mState.mPaths->release(this); + mState.mFramebuffers->release(this); + mState.mPipelines->release(this); + + mImplementation->onDestroy(this); + + return egl::NoError(); +} + +Context::~Context() +{ } -void Context::makeCurrent(egl::Surface *surface) +egl::Error Context::makeCurrent(egl::Display *display, egl::Surface *surface) { - ASSERT(surface != nullptr); + mCurrentDisplay = display; if (!mHasBeenCurrent) { initRendererString(); + initVersionStrings(); initExtensionStrings(); - mState.setViewportParams(0, 0, surface->getWidth(), surface->getHeight()); - mState.setScissorParams(0, 0, surface->getWidth(), surface->getHeight()); + int width = 0; + int height = 0; + if (surface != nullptr) + { + width = surface->getWidth(); + height = surface->getHeight(); + } + + mGLState.setViewportParams(0, 0, width, height); + mGLState.setScissorParams(0, 0, width, height); mHasBeenCurrent = true; } // TODO(jmadill): Rework this when we support ContextImpl - mState.setAllDirtyBits(); + mGLState.setAllDirtyBits(); + mGLState.setAllDirtyObjects(); - if (mCurrentSurface) + ANGLE_TRY(releaseSurface(display)); + + Framebuffer *newDefault = nullptr; + if (surface != nullptr) + { + ANGLE_TRY(surface->setIsCurrent(this, true)); + mCurrentSurface = surface; + newDefault = surface->getDefaultFramebuffer(); + } + else { - releaseSurface(); + if (mSurfacelessFramebuffer == nullptr) + { + mSurfacelessFramebuffer = new Framebuffer(mImplementation.get()); + } + + newDefault = mSurfacelessFramebuffer; } - surface->setIsCurrent(true); - mCurrentSurface = surface; // Update default framebuffer, the binding of the previous default // framebuffer (or lack of) will have a nullptr. { - Framebuffer *newDefault = surface->getDefaultFramebuffer(); - if (mState.getReadFramebuffer() == nullptr) + if (mGLState.getReadFramebuffer() == nullptr) { - mState.setReadFramebufferBinding(newDefault); + mGLState.setReadFramebufferBinding(newDefault); } - if (mState.getDrawFramebuffer() == nullptr) + if (mGLState.getDrawFramebuffer() == nullptr) { - mState.setDrawFramebufferBinding(newDefault); + mGLState.setDrawFramebufferBinding(newDefault); } - mFramebufferMap[0] = newDefault; + mState.mFramebuffers->setDefaultFramebuffer(newDefault); } // Notify the renderer of a context switch - mRenderer->onMakeCurrent(getData()); + mImplementation->onMakeCurrent(this); + return egl::NoError(); } -void Context::releaseSurface() +egl::Error Context::releaseSurface(const egl::Display *display) { - ASSERT(mCurrentSurface != nullptr); - // Remove the default framebuffer + Framebuffer *currentDefault = nullptr; + if (mCurrentSurface != nullptr) { - Framebuffer *currentDefault = mCurrentSurface->getDefaultFramebuffer(); - if (mState.getReadFramebuffer() == currentDefault) - { - mState.setReadFramebufferBinding(nullptr); - } - if (mState.getDrawFramebuffer() == currentDefault) - { - mState.setDrawFramebufferBinding(nullptr); - } - mFramebufferMap.erase(0); + currentDefault = mCurrentSurface->getDefaultFramebuffer(); + } + else if (mSurfacelessFramebuffer != nullptr) + { + currentDefault = mSurfacelessFramebuffer; } - mCurrentSurface->setIsCurrent(false); - mCurrentSurface = nullptr; -} + if (mGLState.getReadFramebuffer() == currentDefault) + { + mGLState.setReadFramebufferBinding(nullptr); + } + if (mGLState.getDrawFramebuffer() == currentDefault) + { + mGLState.setDrawFramebufferBinding(nullptr); + } + mState.mFramebuffers->setDefaultFramebuffer(nullptr); -// 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; -} + if (mCurrentSurface) + { + ANGLE_TRY(mCurrentSurface->setIsCurrent(this, false)); + mCurrentSurface = nullptr; + } -bool Context::isContextLost() -{ - return mContextLost; + return egl::NoError(); } GLuint Context::createBuffer() { - return mResourceManager->createBuffer(); + return mState.mBuffers->createBuffer(); } GLuint Context::createProgram() { - return mResourceManager->createProgram(); + return mState.mShaderPrograms->createProgram(mImplementation.get()); } GLuint Context::createShader(GLenum type) { - return mResourceManager->createShader(mRenderer->getRendererLimitations(), type); + return mState.mShaderPrograms->createShader(mImplementation.get(), mLimitations, type); } GLuint Context::createTexture() { - return mResourceManager->createTexture(); + return mState.mTextures->createTexture(); } GLuint Context::createRenderbuffer() { - return mResourceManager->createRenderbuffer(); -} - -GLsync Context::createFenceSync() -{ - GLuint handle = mResourceManager->createFenceSync(); - - return reinterpret_cast(static_cast(handle)); -} - -GLuint Context::createVertexArray() -{ - GLuint vertexArray = mVertexArrayHandleAllocator.allocate(); - mVertexArrayMap[vertexArray] = nullptr; - return vertexArray; -} - -GLuint Context::createSampler() -{ - return mResourceManager->createSampler(); + return mState.mRenderbuffers->createRenderbuffer(); } -GLuint Context::createTransformFeedback() +GLuint Context::createPaths(GLsizei range) { - GLuint transformFeedback = mTransformFeedbackAllocator.allocate(); - mTransformFeedbackMap[transformFeedback] = nullptr; - return transformFeedback; + auto resultOrError = mState.mPaths->createPaths(mImplementation.get(), range); + if (resultOrError.isError()) + { + handleError(resultOrError.getError()); + return 0; + } + return resultOrError.getResult(); } // Returns an unused framebuffer name GLuint Context::createFramebuffer() { - GLuint handle = mFramebufferHandleAllocator.allocate(); - - mFramebufferMap[handle] = NULL; - - return handle; + return mState.mFramebuffers->createFramebuffer(); } GLuint Context::createFenceNV() { GLuint handle = mFenceNVHandleAllocator.allocate(); - - mFenceNVMap[handle] = new FenceNV(mRenderer->createFenceNV()); - + mFenceNVMap.assign(handle, new FenceNV(mImplementation->createFenceNV())); return handle; } -// Returns an unused query name -GLuint Context::createQuery() +GLuint Context::createProgramPipeline() { - GLuint handle = mQueryHandleAllocator.allocate(); - - mQueryMap[handle] = NULL; + return mState.mPipelines->createProgramPipeline(); +} - return handle; +GLuint Context::createShaderProgramv(GLenum type, GLsizei count, const GLchar *const *strings) +{ + UNIMPLEMENTED(); + return 0u; } void Context::deleteBuffer(GLuint buffer) { - if (mResourceManager->getBuffer(buffer)) + if (mState.mBuffers->getBuffer(buffer)) { detachBuffer(buffer); } - mResourceManager->deleteBuffer(buffer); + mState.mBuffers->deleteObject(this, buffer); } void Context::deleteShader(GLuint shader) { - mResourceManager->deleteShader(shader); + mState.mShaderPrograms->deleteShader(this, shader); } void Context::deleteProgram(GLuint program) { - mResourceManager->deleteProgram(program); + mState.mShaderPrograms->deleteProgram(this, program); } void Context::deleteTexture(GLuint texture) { - if (mResourceManager->getTexture(texture)) + if (mState.mTextures->getTexture(texture)) { detachTexture(texture); } - mResourceManager->deleteTexture(texture); + mState.mTextures->deleteObject(this, texture); } void Context::deleteRenderbuffer(GLuint renderbuffer) { - if (mResourceManager->getRenderbuffer(renderbuffer)) + if (mState.mRenderbuffers->getRenderbuffer(renderbuffer)) { detachRenderbuffer(renderbuffer); } - mResourceManager->deleteRenderbuffer(renderbuffer); + mState.mRenderbuffers->deleteObject(this, renderbuffer); } -void Context::deleteFenceSync(GLsync fenceSync) +void Context::deleteSync(GLsync sync) { // 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(static_cast(reinterpret_cast(fenceSync))); + mState.mSyncs->deleteObject(this, static_cast(reinterpret_cast(sync))); } -void Context::deleteVertexArray(GLuint vertexArray) +void Context::deleteProgramPipeline(GLuint pipeline) { - auto iter = mVertexArrayMap.find(vertexArray); - if (iter != mVertexArrayMap.end()) + if (mState.mPipelines->getProgramPipeline(pipeline)) { - VertexArray *vertexArrayObject = iter->second; - if (vertexArrayObject != nullptr) - { - detachVertexArray(vertexArray); - delete vertexArrayObject; - } - - mVertexArrayMap.erase(iter); - mVertexArrayHandleAllocator.release(vertexArray); + detachProgramPipeline(pipeline); } + + mState.mPipelines->deleteObject(this, pipeline); } -void Context::deleteSampler(GLuint sampler) +void Context::deletePaths(GLuint first, GLsizei range) { - if (mResourceManager->getSampler(sampler)) - { - detachSampler(sampler); - } - - mResourceManager->deleteSampler(sampler); + mState.mPaths->deletePaths(first, range); } -void Context::deleteTransformFeedback(GLuint transformFeedback) +bool Context::hasPathData(GLuint path) const { - auto iter = mTransformFeedbackMap.find(transformFeedback); - if (iter != mTransformFeedbackMap.end()) - { - TransformFeedback *transformFeedbackObject = iter->second; - if (transformFeedbackObject != nullptr) - { - detachTransformFeedback(transformFeedback); - transformFeedbackObject->release(); - } + const auto *pathObj = mState.mPaths->getPath(path); + if (pathObj == nullptr) + return false; - mTransformFeedbackMap.erase(iter); - mTransformFeedbackAllocator.release(transformFeedback); - } + return pathObj->hasPathData(); } -void Context::deleteFramebuffer(GLuint framebuffer) +bool Context::hasPath(GLuint path) const { - FramebufferMap::iterator framebufferObject = mFramebufferMap.find(framebuffer); + return mState.mPaths->hasPath(path); +} - if (framebufferObject != mFramebufferMap.end()) - { - detachFramebuffer(framebuffer); +void Context::setPathCommands(GLuint path, + GLsizei numCommands, + const GLubyte *commands, + GLsizei numCoords, + GLenum coordType, + const void *coords) +{ + auto *pathObject = mState.mPaths->getPath(path); - mFramebufferHandleAllocator.release(framebufferObject->first); - delete framebufferObject->second; - mFramebufferMap.erase(framebufferObject); - } + handleError(pathObject->setCommands(numCommands, commands, numCoords, coordType, coords)); } -void Context::deleteFenceNV(GLuint fence) +void Context::setPathParameterf(GLuint path, GLenum pname, GLfloat value) { - FenceNVMap::iterator fenceObject = mFenceNVMap.find(fence); + auto *pathObj = mState.mPaths->getPath(path); - if (fenceObject != mFenceNVMap.end()) + switch (pname) { - mFenceNVHandleAllocator.release(fenceObject->first); - delete fenceObject->second; - mFenceNVMap.erase(fenceObject); + case GL_PATH_STROKE_WIDTH_CHROMIUM: + pathObj->setStrokeWidth(value); + break; + case GL_PATH_END_CAPS_CHROMIUM: + pathObj->setEndCaps(static_cast(value)); + break; + case GL_PATH_JOIN_STYLE_CHROMIUM: + pathObj->setJoinStyle(static_cast(value)); + break; + case GL_PATH_MITER_LIMIT_CHROMIUM: + pathObj->setMiterLimit(value); + break; + case GL_PATH_STROKE_BOUND_CHROMIUM: + pathObj->setStrokeBound(value); + break; + default: + UNREACHABLE(); + break; } } -void Context::deleteQuery(GLuint query) +void Context::getPathParameterfv(GLuint path, GLenum pname, GLfloat *value) const { - QueryMap::iterator queryObject = mQueryMap.find(query); - if (queryObject != mQueryMap.end()) + const auto *pathObj = mState.mPaths->getPath(path); + + switch (pname) { - mQueryHandleAllocator.release(queryObject->first); - if (queryObject->second) - { - queryObject->second->release(); - } - mQueryMap.erase(queryObject); + case GL_PATH_STROKE_WIDTH_CHROMIUM: + *value = pathObj->getStrokeWidth(); + break; + case GL_PATH_END_CAPS_CHROMIUM: + *value = static_cast(pathObj->getEndCaps()); + break; + case GL_PATH_JOIN_STYLE_CHROMIUM: + *value = static_cast(pathObj->getJoinStyle()); + break; + case GL_PATH_MITER_LIMIT_CHROMIUM: + *value = pathObj->getMiterLimit(); + break; + case GL_PATH_STROKE_BOUND_CHROMIUM: + *value = pathObj->getStrokeBound(); + break; + default: + UNREACHABLE(); + break; } } -Buffer *Context::getBuffer(GLuint handle) const +void Context::setPathStencilFunc(GLenum func, GLint ref, GLuint mask) +{ + mGLState.setPathStencilFunc(func, ref, mask); +} + +void Context::deleteFramebuffer(GLuint framebuffer) { - return mResourceManager->getBuffer(handle); + if (mState.mFramebuffers->getFramebuffer(framebuffer)) + { + detachFramebuffer(framebuffer); + } + + mState.mFramebuffers->deleteObject(this, framebuffer); } -Shader *Context::getShader(GLuint handle) const +void Context::deleteFenceNV(GLuint fence) { - return mResourceManager->getShader(handle); + FenceNV *fenceObject = nullptr; + if (mFenceNVMap.erase(fence, &fenceObject)) + { + mFenceNVHandleAllocator.release(fence); + delete fenceObject; + } } -Program *Context::getProgram(GLuint handle) const +Buffer *Context::getBuffer(GLuint handle) const { - return mResourceManager->getProgram(handle); + return mState.mBuffers->getBuffer(handle); } Texture *Context::getTexture(GLuint handle) const { - return mResourceManager->getTexture(handle); + return mState.mTextures->getTexture(handle); } Renderbuffer *Context::getRenderbuffer(GLuint handle) const { - return mResourceManager->getRenderbuffer(handle); + return mState.mRenderbuffers->getRenderbuffer(handle); } -FenceSync *Context::getFenceSync(GLsync handle) const +Sync *Context::getSync(GLsync handle) const { - return mResourceManager->getFenceSync(static_cast(reinterpret_cast(handle))); + return mState.mSyncs->getSync(static_cast(reinterpret_cast(handle))); } VertexArray *Context::getVertexArray(GLuint handle) const { - auto vertexArray = mVertexArrayMap.find(handle); - return (vertexArray != mVertexArrayMap.end()) ? vertexArray->second : nullptr; + return mVertexArrayMap.query(handle); } Sampler *Context::getSampler(GLuint handle) const { - return mResourceManager->getSampler(handle); + return mState.mSamplers->getSampler(handle); } TransformFeedback *Context::getTransformFeedback(GLuint handle) const { - auto iter = mTransformFeedbackMap.find(handle); - return (iter != mTransformFeedbackMap.end()) ? iter->second : nullptr; + return mTransformFeedbackMap.query(handle); +} + +ProgramPipeline *Context::getProgramPipeline(GLuint handle) const +{ + return mState.mPipelines->getProgramPipeline(handle); } LabeledObject *Context::getLabeledObject(GLenum identifier, GLuint name) const @@ -648,31 +881,64 @@ LabeledObject *Context::getLabeledObject(GLenum identifier, GLuint name) const LabeledObject *Context::getLabeledObjectFromPtr(const void *ptr) const { - return getFenceSync(reinterpret_cast(const_cast(ptr))); + return getSync(reinterpret_cast(const_cast(ptr))); } -bool Context::isSampler(GLuint samplerName) const +void Context::objectLabel(GLenum identifier, GLuint name, GLsizei length, const GLchar *label) +{ + LabeledObject *object = getLabeledObject(identifier, name); + ASSERT(object != nullptr); + + std::string labelName = GetObjectLabelFromPointer(length, label); + object->setLabel(labelName); + + // TODO(jmadill): Determine if the object is dirty based on 'name'. Conservatively assume the + // specified object is active until we do this. + mGLState.setObjectDirty(identifier); +} + +void Context::objectPtrLabel(const void *ptr, GLsizei length, const GLchar *label) { - return mResourceManager->isSampler(samplerName); + LabeledObject *object = getLabeledObjectFromPtr(ptr); + ASSERT(object != nullptr); + + std::string labelName = GetObjectLabelFromPointer(length, label); + object->setLabel(labelName); } -void Context::bindArrayBuffer(unsigned int buffer) +void Context::getObjectLabel(GLenum identifier, + GLuint name, + GLsizei bufSize, + GLsizei *length, + GLchar *label) const { - mResourceManager->checkBufferAllocation(buffer); + LabeledObject *object = getLabeledObject(identifier, name); + ASSERT(object != nullptr); - mState.setArrayBufferBinding(getBuffer(buffer)); + const std::string &objectLabel = object->getLabel(); + GetObjectLabelBase(objectLabel, bufSize, length, label); } -void Context::bindElementArrayBuffer(unsigned int buffer) +void Context::getObjectPtrLabel(const void *ptr, + GLsizei bufSize, + GLsizei *length, + GLchar *label) const { - mResourceManager->checkBufferAllocation(buffer); + LabeledObject *object = getLabeledObjectFromPtr(ptr); + ASSERT(object != nullptr); - mState.getVertexArray()->setElementArrayBuffer(getBuffer(buffer)); + const std::string &objectLabel = object->getLabel(); + GetObjectLabelBase(objectLabel, bufSize, length, label); +} + +bool Context::isSampler(GLuint samplerName) const +{ + return mState.mSamplers->isSampler(samplerName); } void Context::bindTexture(GLenum target, GLuint handle) { - Texture *texture = NULL; + Texture *texture = nullptr; if (handle == 0) { @@ -680,164 +946,126 @@ void Context::bindTexture(GLenum target, GLuint handle) } else { - mResourceManager->checkTextureAllocation(handle, target); - texture = getTexture(handle); + texture = mState.mTextures->checkTextureAllocation(mImplementation.get(), handle, target); } ASSERT(texture); - - mState.setSamplerTexture(target, texture); + mGLState.setSamplerTexture(this, target, texture); } void Context::bindReadFramebuffer(GLuint framebufferHandle) { - Framebuffer *framebuffer = checkFramebufferAllocation(framebufferHandle); - mState.setReadFramebufferBinding(framebuffer); + Framebuffer *framebuffer = mState.mFramebuffers->checkFramebufferAllocation( + mImplementation.get(), mCaps, framebufferHandle); + mGLState.setReadFramebufferBinding(framebuffer); } void Context::bindDrawFramebuffer(GLuint framebufferHandle) { - Framebuffer *framebuffer = checkFramebufferAllocation(framebufferHandle); - mState.setDrawFramebufferBinding(framebuffer); + Framebuffer *framebuffer = mState.mFramebuffers->checkFramebufferAllocation( + mImplementation.get(), mCaps, framebufferHandle); + mGLState.setDrawFramebufferBinding(framebuffer); } -void Context::bindRenderbuffer(GLuint renderbuffer) +void Context::bindVertexArray(GLuint vertexArrayHandle) { - mResourceManager->checkRenderbufferAllocation(renderbuffer); - - mState.setRenderbufferBinding(getRenderbuffer(renderbuffer)); + VertexArray *vertexArray = checkVertexArrayAllocation(vertexArrayHandle); + mGLState.setVertexArrayBinding(vertexArray); } -void Context::bindVertexArray(GLuint vertexArray) +void Context::bindVertexBuffer(GLuint bindingIndex, + GLuint bufferHandle, + GLintptr offset, + GLsizei stride) { - checkVertexArrayAllocation(vertexArray); - - mState.setVertexArrayBinding(getVertexArray(vertexArray)); + Buffer *buffer = mState.mBuffers->checkBufferAllocation(mImplementation.get(), bufferHandle); + mGLState.bindVertexBuffer(this, bindingIndex, buffer, offset, stride); } -void Context::bindSampler(GLuint textureUnit, GLuint sampler) +void Context::bindSampler(GLuint textureUnit, GLuint samplerHandle) { ASSERT(textureUnit < mCaps.maxCombinedTextureImageUnits); - mResourceManager->checkSamplerAllocation(sampler); - - mState.setSamplerBinding(textureUnit, getSampler(sampler)); + Sampler *sampler = + mState.mSamplers->checkSamplerAllocation(mImplementation.get(), samplerHandle); + mGLState.setSamplerBinding(this, textureUnit, sampler); } -void Context::bindGenericUniformBuffer(GLuint buffer) +void Context::bindImageTexture(GLuint unit, + GLuint texture, + GLint level, + GLboolean layered, + GLint layer, + GLenum access, + GLenum format) { - mResourceManager->checkBufferAllocation(buffer); - - mState.setGenericUniformBufferBinding(getBuffer(buffer)); + Texture *tex = mState.mTextures->getTexture(texture); + mGLState.setImageUnit(this, unit, tex, level, layered, layer, access, format); } -void Context::bindIndexedUniformBuffer(GLuint buffer, GLuint index, GLintptr offset, GLsizeiptr size) +void Context::useProgram(GLuint program) { - mResourceManager->checkBufferAllocation(buffer); - - mState.setIndexedUniformBufferBinding(index, getBuffer(buffer), offset, size); + mGLState.setProgram(this, getProgram(program)); } -void Context::bindGenericTransformFeedbackBuffer(GLuint buffer) +void Context::useProgramStages(GLuint pipeline, GLbitfield stages, GLuint program) { - mResourceManager->checkBufferAllocation(buffer); - - mState.getCurrentTransformFeedback()->bindGenericBuffer(getBuffer(buffer)); + UNIMPLEMENTED(); } -void Context::bindIndexedTransformFeedbackBuffer(GLuint buffer, GLuint index, GLintptr offset, GLsizeiptr size) +void Context::bindTransformFeedback(GLenum target, GLuint transformFeedbackHandle) { - mResourceManager->checkBufferAllocation(buffer); - - mState.getCurrentTransformFeedback()->bindIndexedBuffer(index, getBuffer(buffer), offset, size); + ASSERT(target == GL_TRANSFORM_FEEDBACK); + TransformFeedback *transformFeedback = + checkTransformFeedbackAllocation(transformFeedbackHandle); + mGLState.setTransformFeedbackBinding(this, transformFeedback); } -void Context::bindCopyReadBuffer(GLuint buffer) +void Context::bindProgramPipeline(GLuint pipelineHandle) { - mResourceManager->checkBufferAllocation(buffer); - - mState.setCopyReadBufferBinding(getBuffer(buffer)); + ProgramPipeline *pipeline = + mState.mPipelines->checkProgramPipelineAllocation(mImplementation.get(), pipelineHandle); + mGLState.setProgramPipelineBinding(this, pipeline); } -void Context::bindCopyWriteBuffer(GLuint buffer) +void Context::beginQuery(GLenum target, GLuint query) { - mResourceManager->checkBufferAllocation(buffer); - - mState.setCopyWriteBufferBinding(getBuffer(buffer)); -} + Query *queryObject = getQuery(query, true, target); + ASSERT(queryObject); -void Context::bindPixelPackBuffer(GLuint buffer) -{ - mResourceManager->checkBufferAllocation(buffer); + // begin query + ANGLE_CONTEXT_TRY(queryObject->begin()); - mState.setPixelPackBufferBinding(getBuffer(buffer)); + // set query as active for specified target only if begin succeeded + mGLState.setActiveQuery(this, target, queryObject); } -void Context::bindPixelUnpackBuffer(GLuint buffer) +void Context::endQuery(GLenum target) { - mResourceManager->checkBufferAllocation(buffer); + Query *queryObject = mGLState.getActiveQuery(target); + ASSERT(queryObject); - mState.setPixelUnpackBufferBinding(getBuffer(buffer)); -} + handleError(queryObject->end()); -void Context::useProgram(GLuint program) -{ - mState.setProgram(getProgram(program)); + // Always unbind the query, even if there was an error. This may delete the query object. + mGLState.setActiveQuery(this, target, nullptr); } -void Context::bindTransformFeedback(GLuint transformFeedback) +void Context::queryCounter(GLuint id, GLenum target) { - checkTransformFeedbackAllocation(transformFeedback); + ASSERT(target == GL_TIMESTAMP_EXT); + + Query *queryObject = getQuery(id, true, target); + ASSERT(queryObject); - mState.setTransformFeedbackBinding(getTransformFeedback(transformFeedback)); + handleError(queryObject->queryCounter()); } -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; -} - -Error Context::queryCounter(GLuint id, GLenum target) -{ - ASSERT(target == GL_TIMESTAMP_EXT); - - Query *queryObject = getQuery(id, true, target); - ASSERT(queryObject); - - return queryObject->queryCounter(); -} - -void Context::getQueryiv(GLenum target, GLenum pname, GLint *params) +void Context::getQueryiv(GLenum target, GLenum pname, GLint *params) { switch (pname) { case GL_CURRENT_QUERY_EXT: - params[0] = getState().getActiveQueryId(target); + params[0] = mGLState.getActiveQueryId(target); break; case GL_QUERY_COUNTER_BITS_EXT: switch (target) @@ -860,763 +1088,992 @@ void Context::getQueryiv(GLenum target, GLenum pname, GLint *params) } } -Error Context::getQueryObjectiv(GLuint id, GLenum pname, GLint *params) +void Context::getQueryObjectiv(GLuint id, GLenum pname, GLint *params) { - return GetQueryObjectParameter(this, id, pname, params); + handleError(GetQueryObjectParameter(getQuery(id), pname, params)); } -Error Context::getQueryObjectuiv(GLuint id, GLenum pname, GLuint *params) +void Context::getQueryObjectuiv(GLuint id, GLenum pname, GLuint *params) { - return GetQueryObjectParameter(this, id, pname, params); + handleError(GetQueryObjectParameter(getQuery(id), pname, params)); } -Error Context::getQueryObjecti64v(GLuint id, GLenum pname, GLint64 *params) +void Context::getQueryObjecti64v(GLuint id, GLenum pname, GLint64 *params) { - return GetQueryObjectParameter(this, id, pname, params); + handleError(GetQueryObjectParameter(getQuery(id), pname, params)); } -Error Context::getQueryObjectui64v(GLuint id, GLenum pname, GLuint64 *params) +void Context::getQueryObjectui64v(GLuint id, GLenum pname, GLuint64 *params) { - return GetQueryObjectParameter(this, id, pname, params); + handleError(GetQueryObjectParameter(getQuery(id), pname, params)); } -Framebuffer *Context::getFramebuffer(unsigned int handle) const +Framebuffer *Context::getFramebuffer(GLuint handle) const { - auto framebufferIt = mFramebufferMap.find(handle); - return ((framebufferIt == mFramebufferMap.end()) ? nullptr : framebufferIt->second); + return mState.mFramebuffers->getFramebuffer(handle); } -FenceNV *Context::getFenceNV(unsigned int handle) +FenceNV *Context::getFenceNV(GLuint handle) { - FenceNVMap::iterator fence = mFenceNVMap.find(handle); - - if (fence == mFenceNVMap.end()) - { - return NULL; - } - else - { - return fence->second; - } + return mFenceNVMap.query(handle); } -Query *Context::getQuery(unsigned int handle, bool create, GLenum type) +Query *Context::getQuery(GLuint handle, bool create, GLenum type) { - QueryMap::iterator query = mQueryMap.find(handle); - - if (query == mQueryMap.end()) + if (!mQueryMap.contains(handle)) { - return NULL; + return nullptr; } - else + + Query *query = mQueryMap.query(handle); + if (!query && create) { - if (!query->second && create) - { - query->second = new Query(mRenderer->createQuery(type), handle); - query->second->addRef(); - } - return query->second; + query = new Query(mImplementation->createQuery(type), handle); + query->addRef(); + mQueryMap.assign(handle, query); } + return query; } Query *Context::getQuery(GLuint handle) const { - auto iter = mQueryMap.find(handle); - return (iter != mQueryMap.end()) ? iter->second : nullptr; + return mQueryMap.query(handle); } Texture *Context::getTargetTexture(GLenum target) const { - ASSERT(ValidTextureTarget(this, target)); - return mState.getTargetTexture(target); + ASSERT(ValidTextureTarget(this, target) || ValidTextureExternalTarget(this, target)); + return mGLState.getTargetTexture(target); } Texture *Context::getSamplerTexture(unsigned int sampler, GLenum type) const { - return mState.getSamplerTexture(sampler, type); + return mGLState.getSamplerTexture(sampler, type); } Compiler *Context::getCompiler() const { - return mCompiler; + if (mCompiler.get() == nullptr) + { + mCompiler.set(this, new Compiler(mImplementation.get(), mState)); + } + return mCompiler.get(); } -void Context::getBooleanv(GLenum pname, GLboolean *params) +void Context::getBooleanvImpl(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; + case GL_SHADER_COMPILER: + *params = GL_TRUE; + break; + case GL_CONTEXT_ROBUST_ACCESS_EXT: + *params = mRobustAccess ? GL_TRUE : GL_FALSE; + break; + default: + mGLState.getBooleanv(pname, params); + break; } } -void Context::getFloatv(GLenum pname, GLfloat *params) +void Context::getFloatvImpl(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; - case GL_MAX_TEXTURE_LOD_BIAS: - *params = mCaps.maxLODBias; - break; - default: - mState.getFloatv(pname, params); + 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; + case GL_MAX_TEXTURE_LOD_BIAS: + *params = mCaps.maxLODBias; + break; + + case GL_PATH_MODELVIEW_MATRIX_CHROMIUM: + case GL_PATH_PROJECTION_MATRIX_CHROMIUM: + { + ASSERT(mExtensions.pathRendering); + const GLfloat *m = mGLState.getPathRenderingMatrix(pname); + memcpy(params, m, 16 * sizeof(GLfloat)); + } break; + + default: + mGLState.getFloatv(pname, params); + break; } } -void Context::getIntegerv(GLenum pname, GLint *params) +void Context::getIntegervImpl(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.maxFragmentUniformComponents; 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_MAX_VERTEX_OUTPUT_COMPONENTS: *params = mCaps.maxVertexOutputComponents; break; - case GL_MAX_FRAGMENT_INPUT_COMPONENTS: *params = mCaps.maxFragmentInputComponents; break; - case GL_MIN_PROGRAM_TEXEL_OFFSET: *params = mCaps.minProgramTexelOffset; break; - case GL_MAX_PROGRAM_TEXEL_OFFSET: *params = mCaps.maxProgramTexelOffset; 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 = static_cast(mCaps.compressedTextureFormats.size()); - break; - case GL_MAX_SAMPLES_ANGLE: *params = mCaps.maxSamples; break; - case GL_MAX_VIEWPORT_DIMS: + 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.maxFragmentUniformComponents; + 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_RECTANGLE_TEXTURE_SIZE_ANGLE: + *params = mCaps.maxRectangleTextureSize; + 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_MAX_VERTEX_OUTPUT_COMPONENTS: + *params = mCaps.maxVertexOutputComponents; + break; + case GL_MAX_FRAGMENT_INPUT_COMPONENTS: + *params = mCaps.maxFragmentInputComponents; + break; + case GL_MIN_PROGRAM_TEXEL_OFFSET: + *params = mCaps.minProgramTexelOffset; + break; + case GL_MAX_PROGRAM_TEXEL_OFFSET: + *params = mCaps.maxProgramTexelOffset; + break; + case GL_MAJOR_VERSION: + *params = getClientVersion().major; + break; + case GL_MINOR_VERSION: + *params = getClientVersion().minor; + 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 = static_cast(mCaps.compressedTextureFormats.size()); + break; + case GL_MAX_SAMPLES_ANGLE: + *params = mCaps.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 = static_cast(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 = static_cast(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; + 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 = static_cast(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 = static_cast(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; - // GL_KHR_debug - case GL_MAX_DEBUG_MESSAGE_LENGTH: - *params = mExtensions.maxDebugMessageLength; - break; - case GL_MAX_DEBUG_LOGGED_MESSAGES: - *params = mExtensions.maxDebugLoggedMessages; - break; - case GL_MAX_DEBUG_GROUP_STACK_DEPTH: - *params = mExtensions.maxDebugGroupStackDepth; - break; - case GL_MAX_LABEL_LENGTH: - *params = mExtensions.maxLabelLength; - break; - - // GL_EXT_disjoint_timer_query - case GL_GPU_DISJOINT_EXT: - *params = mRenderer->getGPUDisjoint(); - break; - - default: - mState.getIntegerv(getData(), pname, params); - break; + // GL_KHR_debug + case GL_MAX_DEBUG_MESSAGE_LENGTH: + *params = mExtensions.maxDebugMessageLength; + break; + case GL_MAX_DEBUG_LOGGED_MESSAGES: + *params = mExtensions.maxDebugLoggedMessages; + break; + case GL_MAX_DEBUG_GROUP_STACK_DEPTH: + *params = mExtensions.maxDebugGroupStackDepth; + break; + case GL_MAX_LABEL_LENGTH: + *params = mExtensions.maxLabelLength; + break; + + // GL_ANGLE_multiview + case GL_MAX_VIEWS_ANGLE: + *params = mExtensions.maxViews; + break; + + // GL_EXT_disjoint_timer_query + case GL_GPU_DISJOINT_EXT: + *params = mImplementation->getGPUDisjoint(); + break; + case GL_MAX_FRAMEBUFFER_WIDTH: + *params = mCaps.maxFramebufferWidth; + break; + case GL_MAX_FRAMEBUFFER_HEIGHT: + *params = mCaps.maxFramebufferHeight; + break; + case GL_MAX_FRAMEBUFFER_SAMPLES: + *params = mCaps.maxFramebufferSamples; + break; + case GL_MAX_SAMPLE_MASK_WORDS: + *params = mCaps.maxSampleMaskWords; + break; + case GL_MAX_COLOR_TEXTURE_SAMPLES: + *params = mCaps.maxColorTextureSamples; + break; + case GL_MAX_DEPTH_TEXTURE_SAMPLES: + *params = mCaps.maxDepthTextureSamples; + break; + case GL_MAX_INTEGER_SAMPLES: + *params = mCaps.maxIntegerSamples; + break; + case GL_MAX_VERTEX_ATTRIB_RELATIVE_OFFSET: + *params = mCaps.maxVertexAttribRelativeOffset; + break; + case GL_MAX_VERTEX_ATTRIB_BINDINGS: + *params = mCaps.maxVertexAttribBindings; + break; + case GL_MAX_VERTEX_ATTRIB_STRIDE: + *params = mCaps.maxVertexAttribStride; + break; + case GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS: + *params = mCaps.maxVertexAtomicCounterBuffers; + break; + case GL_MAX_VERTEX_ATOMIC_COUNTERS: + *params = mCaps.maxVertexAtomicCounters; + break; + case GL_MAX_VERTEX_IMAGE_UNIFORMS: + *params = mCaps.maxVertexImageUniforms; + break; + case GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS: + *params = mCaps.maxVertexShaderStorageBlocks; + break; + case GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS: + *params = mCaps.maxFragmentAtomicCounterBuffers; + break; + case GL_MAX_FRAGMENT_ATOMIC_COUNTERS: + *params = mCaps.maxFragmentAtomicCounters; + break; + case GL_MAX_FRAGMENT_IMAGE_UNIFORMS: + *params = mCaps.maxFragmentImageUniforms; + break; + case GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS: + *params = mCaps.maxFragmentShaderStorageBlocks; + break; + case GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET: + *params = mCaps.minProgramTextureGatherOffset; + break; + case GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET: + *params = mCaps.maxProgramTextureGatherOffset; + break; + case GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS: + *params = mCaps.maxComputeWorkGroupInvocations; + break; + case GL_MAX_COMPUTE_UNIFORM_BLOCKS: + *params = mCaps.maxComputeUniformBlocks; + break; + case GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS: + *params = mCaps.maxComputeTextureImageUnits; + break; + case GL_MAX_COMPUTE_SHARED_MEMORY_SIZE: + *params = mCaps.maxComputeSharedMemorySize; + break; + case GL_MAX_COMPUTE_UNIFORM_COMPONENTS: + *params = mCaps.maxComputeUniformComponents; + break; + case GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS: + *params = mCaps.maxComputeAtomicCounterBuffers; + break; + case GL_MAX_COMPUTE_ATOMIC_COUNTERS: + *params = mCaps.maxComputeAtomicCounters; + break; + case GL_MAX_COMPUTE_IMAGE_UNIFORMS: + *params = mCaps.maxComputeImageUniforms; + break; + case GL_MAX_COMBINED_COMPUTE_UNIFORM_COMPONENTS: + *params = mCaps.maxCombinedComputeUniformComponents; + break; + case GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS: + *params = mCaps.maxComputeShaderStorageBlocks; + break; + case GL_MAX_COMBINED_SHADER_OUTPUT_RESOURCES: + *params = mCaps.maxCombinedShaderOutputResources; + break; + case GL_MAX_UNIFORM_LOCATIONS: + *params = mCaps.maxUniformLocations; + break; + case GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS: + *params = mCaps.maxAtomicCounterBufferBindings; + break; + case GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE: + *params = mCaps.maxAtomicCounterBufferSize; + break; + case GL_MAX_COMBINED_ATOMIC_COUNTER_BUFFERS: + *params = mCaps.maxCombinedAtomicCounterBuffers; + break; + case GL_MAX_COMBINED_ATOMIC_COUNTERS: + *params = mCaps.maxCombinedAtomicCounters; + break; + case GL_MAX_IMAGE_UNITS: + *params = mCaps.maxImageUnits; + break; + case GL_MAX_COMBINED_IMAGE_UNIFORMS: + *params = mCaps.maxCombinedImageUniforms; + break; + case GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS: + *params = mCaps.maxShaderStorageBufferBindings; + break; + case GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS: + *params = mCaps.maxCombinedShaderStorageBlocks; + break; + case GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT: + *params = mCaps.shaderStorageBufferOffsetAlignment; + break; + default: + mGLState.getIntegerv(this, pname, params); + break; } } -void Context::getInteger64v(GLenum pname, GLint64 *params) +void Context::getInteger64vImpl(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; + 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; - // GL_EXT_disjoint_timer_query - case GL_TIMESTAMP_EXT: - *params = mRenderer->getTimestamp(); - break; - default: - UNREACHABLE(); - break; + // GL_EXT_disjoint_timer_query + case GL_TIMESTAMP_EXT: + *params = mImplementation->getTimestamp(); + break; + + case GL_MAX_SHADER_STORAGE_BLOCK_SIZE: + *params = mCaps.maxShaderStorageBlockSize; + break; + default: + UNREACHABLE(); + break; } } void Context::getPointerv(GLenum pname, void **params) const { - mState.getPointerv(pname, params); + mGLState.getPointerv(pname, params); } -bool Context::getIndexedIntegerv(GLenum target, GLuint index, GLint *data) +void Context::getIntegeri_v(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); + + GLenum nativeType; + unsigned int numParams; + bool queryStatus = getIndexedQueryParameterInfo(target, &nativeType, &numParams); + ASSERT(queryStatus); + + if (nativeType == GL_INT) + { + switch (target) + { + case GL_MAX_COMPUTE_WORK_GROUP_COUNT: + ASSERT(index < 3u); + *data = mCaps.maxComputeWorkGroupCount[index]; + break; + case GL_MAX_COMPUTE_WORK_GROUP_SIZE: + ASSERT(index < 3u); + *data = mCaps.maxComputeWorkGroupSize[index]; + break; + default: + mGLState.getIntegeri_v(target, index, data); + } + } + else + { + CastIndexedStateValues(this, nativeType, target, index, numParams, data); + } } -bool Context::getIndexedInteger64v(GLenum target, GLuint index, GLint64 *data) +void Context::getInteger64i_v(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); + + GLenum nativeType; + unsigned int numParams; + bool queryStatus = getIndexedQueryParameterInfo(target, &nativeType, &numParams); + ASSERT(queryStatus); + + if (nativeType == GL_INT_64_ANGLEX) + { + mGLState.getInteger64i_v(target, index, data); + } + else + { + CastIndexedStateValues(this, nativeType, target, index, numParams, data); + } } -bool Context::getQueryParameterInfo(GLenum pname, GLenum *type, unsigned int *numParams) +void Context::getBooleani_v(GLenum target, GLuint index, GLboolean *data) { - if (pname >= GL_DRAW_BUFFER0_EXT && pname <= GL_DRAW_BUFFER15_EXT) + // Queries about context capabilities and maximums are answered by Context. + // Queries about current GL state values are answered by State. + + GLenum nativeType; + unsigned int numParams; + bool queryStatus = getIndexedQueryParameterInfo(target, &nativeType, &numParams); + ASSERT(queryStatus); + + if (nativeType == GL_BOOL) { - *type = GL_INT; - *numParams = 1; - return true; + mGLState.getBooleani_v(target, index, data); } - - // 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) + else { - case GL_COMPRESSED_TEXTURE_FORMATS: - { - *type = GL_INT; - *numParams = static_cast(mCaps.compressedTextureFormats.size()); - } - return true; - case GL_PROGRAM_BINARY_FORMATS_OES: - { - *type = GL_INT; - *numParams = static_cast(mCaps.programBinaryFormats.size()); - } - return true; - case GL_SHADER_BINARY_FORMATS: - { - *type = GL_INT; - *numParams = static_cast(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_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; - case GL_TIMESTAMP_EXT: - if (!mExtensions.disjointTimerQuery) - { - return false; - } - *type = GL_INT_64_ANGLEX; - *numParams = 1; - return true; - case GL_GPU_DISJOINT_EXT: - if (!mExtensions.disjointTimerQuery) - { - return false; - } - *type = GL_INT; - *numParams = 1; - return true; - } - - if (mExtensions.debug) - { - switch (pname) - { - case GL_DEBUG_LOGGED_MESSAGES: - case GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH: - case GL_DEBUG_GROUP_STACK_DEPTH: - case GL_MAX_DEBUG_MESSAGE_LENGTH: - case GL_MAX_DEBUG_LOGGED_MESSAGES: - case GL_MAX_DEBUG_GROUP_STACK_DEPTH: - case GL_MAX_LABEL_LENGTH: - *type = GL_INT; - *numParams = 1; - return true; - - case GL_DEBUG_OUTPUT_SYNCHRONOUS: - case GL_DEBUG_OUTPUT: - *type = GL_BOOL; - *numParams = 1; - return true; - } + CastIndexedStateValues(this, nativeType, target, index, numParams, data); } +} - // Check for ES3.0+ parameter names which are also exposed as ES2 extensions - switch (pname) - { - case GL_PACK_ROW_LENGTH: - case GL_PACK_SKIP_ROWS: - case GL_PACK_SKIP_PIXELS: - if ((mClientVersion < 3) && !mExtensions.packSubimage) - { - return false; - } - *type = GL_INT; - *numParams = 1; - return true; - case GL_UNPACK_ROW_LENGTH: - case GL_UNPACK_SKIP_ROWS: - case GL_UNPACK_SKIP_PIXELS: - if ((mClientVersion < 3) && !mExtensions.unpackSubimage) - { - return false; - } - *type = GL_INT; - *numParams = 1; - return true; - case GL_VERTEX_ARRAY_BINDING: - if ((mClientVersion < 3) && !mExtensions.vertexArrayObject) - { - return false; - } - *type = GL_INT; - *numParams = 1; - return true; - case GL_PIXEL_PACK_BUFFER_BINDING: - case GL_PIXEL_UNPACK_BUFFER_BINDING: - if ((mClientVersion < 3) && !mExtensions.pixelBufferObject) - { - return false; - } - *type = GL_INT; - *numParams = 1; - return true; - } +void Context::getBufferParameteriv(BufferBinding target, GLenum pname, GLint *params) +{ + Buffer *buffer = mGLState.getTargetBuffer(target); + QueryBufferParameteriv(buffer, pname, params); +} - if (mClientVersion < 3) - { - return false; - } +void Context::getFramebufferAttachmentParameteriv(GLenum target, + GLenum attachment, + GLenum pname, + GLint *params) +{ + const Framebuffer *framebuffer = mGLState.getTargetFramebuffer(target); + QueryFramebufferAttachmentParameteriv(framebuffer, attachment, pname, params); +} - // 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_TRANSFORM_FEEDBACK_BUFFER_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_VERTEX_OUTPUT_COMPONENTS: - case GL_MAX_FRAGMENT_INPUT_COMPONENTS: - case GL_MAX_VARYING_COMPONENTS: - case GL_MAX_VERTEX_UNIFORM_COMPONENTS: - case GL_MAX_FRAGMENT_UNIFORM_COMPONENTS: - case GL_MIN_PROGRAM_TEXEL_OFFSET: - case GL_MAX_PROGRAM_TEXEL_OFFSET: - 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: - case GL_UNPACK_IMAGE_HEIGHT: - case GL_UNPACK_SKIP_IMAGES: - { - *type = GL_INT; - *numParams = 1; - } - return true; +void Context::getRenderbufferParameteriv(GLenum target, GLenum pname, GLint *params) +{ + Renderbuffer *renderbuffer = mGLState.getCurrentRenderbuffer(); + QueryRenderbufferiv(this, renderbuffer, pname, params); +} - 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; +void Context::getTexParameterfv(GLenum target, GLenum pname, GLfloat *params) +{ + Texture *texture = getTargetTexture(target); + QueryTexParameterfv(texture, pname, params); +} - case GL_TRANSFORM_FEEDBACK_ACTIVE: - case GL_TRANSFORM_FEEDBACK_PAUSED: - case GL_PRIMITIVE_RESTART_FIXED_INDEX: - case GL_RASTERIZER_DISCARD: - { - *type = GL_BOOL; - *numParams = 1; - } - return true; +void Context::getTexParameteriv(GLenum target, GLenum pname, GLint *params) +{ + Texture *texture = getTargetTexture(target); + QueryTexParameteriv(texture, pname, params); +} - case GL_MAX_TEXTURE_LOD_BIAS: - { - *type = GL_FLOAT; - *numParams = 1; - } - return true; - } +void Context::getTexLevelParameteriv(GLenum target, GLint level, GLenum pname, GLint *params) +{ + Texture *texture = + getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target); + QueryTexLevelParameteriv(texture, target, level, pname, params); +} - return false; +void Context::getTexLevelParameterfv(GLenum target, GLint level, GLenum pname, GLfloat *params) +{ + Texture *texture = + getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target); + QueryTexLevelParameterfv(texture, target, level, pname, params); } -bool Context::getIndexedQueryParameterInfo(GLenum target, GLenum *type, unsigned int *numParams) +void Context::texParameterf(GLenum target, GLenum pname, GLfloat param) { - if (mClientVersion < 3) - { - return false; - } + Texture *texture = getTargetTexture(target); + SetTexParameterf(this, texture, pname, param); + onTextureChange(texture); +} - 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; - } - } +void Context::texParameterfv(GLenum target, GLenum pname, const GLfloat *params) +{ + Texture *texture = getTargetTexture(target); + SetTexParameterfv(this, texture, pname, params); + onTextureChange(texture); +} - return false; +void Context::texParameteri(GLenum target, GLenum pname, GLint param) +{ + Texture *texture = getTargetTexture(target); + SetTexParameteri(this, texture, pname, param); + onTextureChange(texture); +} + +void Context::texParameteriv(GLenum target, GLenum pname, const GLint *params) +{ + Texture *texture = getTargetTexture(target); + SetTexParameteriv(this, texture, pname, params); + onTextureChange(texture); +} + +void Context::drawArrays(GLenum mode, GLint first, GLsizei count) +{ + ANGLE_CONTEXT_TRY(prepareForDraw()); + ANGLE_CONTEXT_TRY(mImplementation->drawArrays(this, mode, first, count)); + MarkTransformFeedbackBufferUsage(mGLState.getCurrentTransformFeedback()); +} + +void Context::drawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei instanceCount) +{ + ANGLE_CONTEXT_TRY(prepareForDraw()); + ANGLE_CONTEXT_TRY( + mImplementation->drawArraysInstanced(this, mode, first, count, instanceCount)); + MarkTransformFeedbackBufferUsage(mGLState.getCurrentTransformFeedback()); +} + +void Context::drawElements(GLenum mode, GLsizei count, GLenum type, const void *indices) +{ + ANGLE_CONTEXT_TRY(prepareForDraw()); + ANGLE_CONTEXT_TRY(mImplementation->drawElements(this, mode, count, type, indices)); +} + +void Context::drawElementsInstanced(GLenum mode, + GLsizei count, + GLenum type, + const void *indices, + GLsizei instances) +{ + ANGLE_CONTEXT_TRY(prepareForDraw()); + ANGLE_CONTEXT_TRY( + mImplementation->drawElementsInstanced(this, mode, count, type, indices, instances)); +} + +void Context::drawRangeElements(GLenum mode, + GLuint start, + GLuint end, + GLsizei count, + GLenum type, + const void *indices) +{ + ANGLE_CONTEXT_TRY(prepareForDraw()); + ANGLE_CONTEXT_TRY( + mImplementation->drawRangeElements(this, mode, start, end, count, type, indices)); +} + +void Context::drawArraysIndirect(GLenum mode, const void *indirect) +{ + ANGLE_CONTEXT_TRY(prepareForDraw()); + ANGLE_CONTEXT_TRY(mImplementation->drawArraysIndirect(this, mode, indirect)); +} + +void Context::drawElementsIndirect(GLenum mode, GLenum type, const void *indirect) +{ + ANGLE_CONTEXT_TRY(prepareForDraw()); + ANGLE_CONTEXT_TRY(mImplementation->drawElementsIndirect(this, mode, type, indirect)); +} + +void Context::flush() +{ + handleError(mImplementation->flush(this)); +} + +void Context::finish() +{ + handleError(mImplementation->finish(this)); +} + +void Context::insertEventMarker(GLsizei length, const char *marker) +{ + ASSERT(mImplementation); + mImplementation->insertEventMarker(length, marker); +} + +void Context::pushGroupMarker(GLsizei length, const char *marker) +{ + ASSERT(mImplementation); + mImplementation->pushGroupMarker(length, marker); +} + +void Context::popGroupMarker() +{ + ASSERT(mImplementation); + mImplementation->popGroupMarker(); } -Error Context::drawArrays(GLenum mode, GLint first, GLsizei count) +void Context::bindUniformLocation(GLuint program, GLint location, const GLchar *name) { + Program *programObject = getProgram(program); + ASSERT(programObject); + + programObject->bindUniformLocation(location, name); +} + +void Context::setCoverageModulation(GLenum components) +{ + mGLState.setCoverageModulation(components); +} + +void Context::loadPathRenderingMatrix(GLenum matrixMode, const GLfloat *matrix) +{ + mGLState.loadPathRenderingMatrix(matrixMode, matrix); +} + +void Context::loadPathRenderingIdentityMatrix(GLenum matrixMode) +{ + GLfloat I[16]; + angle::Matrix::setToIdentity(I); + + mGLState.loadPathRenderingMatrix(matrixMode, I); +} + +void Context::stencilFillPath(GLuint path, GLenum fillMode, GLuint mask) +{ + const auto *pathObj = mState.mPaths->getPath(path); + if (!pathObj) + return; + + // TODO(svaisanen@nvidia.com): maybe sync only state required for path rendering? syncRendererState(); - Error error = mRenderer->drawArrays(getData(), mode, first, count); - if (error.isError()) - { - return error; - } - MarkTransformFeedbackBufferUsage(mState.getCurrentTransformFeedback()); + mImplementation->stencilFillPath(pathObj, fillMode, mask); +} + +void Context::stencilStrokePath(GLuint path, GLint reference, GLuint mask) +{ + const auto *pathObj = mState.mPaths->getPath(path); + if (!pathObj) + return; + + // TODO(svaisanen@nvidia.com): maybe sync only state required for path rendering? + syncRendererState(); - return Error(GL_NO_ERROR); + mImplementation->stencilStrokePath(pathObj, reference, mask); } -Error Context::drawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei instanceCount) +void Context::coverFillPath(GLuint path, GLenum coverMode) { + const auto *pathObj = mState.mPaths->getPath(path); + if (!pathObj) + return; + + // TODO(svaisanen@nvidia.com): maybe sync only state required for path rendering? syncRendererState(); - Error error = mRenderer->drawArraysInstanced(getData(), mode, first, count, instanceCount); - if (error.isError()) - { - return error; - } - MarkTransformFeedbackBufferUsage(mState.getCurrentTransformFeedback()); + mImplementation->coverFillPath(pathObj, coverMode); +} + +void Context::coverStrokePath(GLuint path, GLenum coverMode) +{ + const auto *pathObj = mState.mPaths->getPath(path); + if (!pathObj) + return; - return Error(GL_NO_ERROR); + // TODO(svaisanen@nvidia.com): maybe sync only state required for path rendering? + syncRendererState(); + + mImplementation->coverStrokePath(pathObj, coverMode); } -Error Context::drawElements(GLenum mode, - GLsizei count, - GLenum type, - const GLvoid *indices, - const IndexRange &indexRange) +void Context::stencilThenCoverFillPath(GLuint path, GLenum fillMode, GLuint mask, GLenum coverMode) { + const auto *pathObj = mState.mPaths->getPath(path); + if (!pathObj) + return; + + // TODO(svaisanen@nvidia.com): maybe sync only state required for path rendering? syncRendererState(); - return mRenderer->drawElements(getData(), mode, count, type, indices, indexRange); + + mImplementation->stencilThenCoverFillPath(pathObj, fillMode, mask, coverMode); } -Error Context::drawElementsInstanced(GLenum mode, - GLsizei count, - GLenum type, - const GLvoid *indices, - GLsizei instances, - const IndexRange &indexRange) +void Context::stencilThenCoverStrokePath(GLuint path, + GLint reference, + GLuint mask, + GLenum coverMode) { + const auto *pathObj = mState.mPaths->getPath(path); + if (!pathObj) + return; + + // TODO(svaisanen@nvidia.com): maybe sync only state required for path rendering? syncRendererState(); - return mRenderer->drawElementsInstanced(getData(), mode, count, type, indices, instances, - indexRange); + + mImplementation->stencilThenCoverStrokePath(pathObj, reference, mask, coverMode); } -Error Context::drawRangeElements(GLenum mode, - GLuint start, - GLuint end, - GLsizei count, - GLenum type, - const GLvoid *indices, - const IndexRange &indexRange) +void Context::coverFillPathInstanced(GLsizei numPaths, + GLenum pathNameType, + const void *paths, + GLuint pathBase, + GLenum coverMode, + GLenum transformType, + const GLfloat *transformValues) { + const auto &pathObjects = GatherPaths(*mState.mPaths, numPaths, pathNameType, paths, pathBase); + + // TODO(svaisanen@nvidia.com): maybe sync only state required for path rendering? syncRendererState(); - return mRenderer->drawRangeElements(getData(), mode, start, end, count, type, indices, - indexRange); + + mImplementation->coverFillPathInstanced(pathObjects, coverMode, transformType, transformValues); } -Error Context::flush() +void Context::coverStrokePathInstanced(GLsizei numPaths, + GLenum pathNameType, + const void *paths, + GLuint pathBase, + GLenum coverMode, + GLenum transformType, + const GLfloat *transformValues) { - return mRenderer->flush(); + const auto &pathObjects = GatherPaths(*mState.mPaths, numPaths, pathNameType, paths, pathBase); + + // TODO(svaisanen@nvidia.com): maybe sync only state required for path rendering? + syncRendererState(); + + mImplementation->coverStrokePathInstanced(pathObjects, coverMode, transformType, + transformValues); } -Error Context::finish() +void Context::stencilFillPathInstanced(GLsizei numPaths, + GLenum pathNameType, + const void *paths, + GLuint pathBase, + GLenum fillMode, + GLuint mask, + GLenum transformType, + const GLfloat *transformValues) { - return mRenderer->finish(); + const auto &pathObjects = GatherPaths(*mState.mPaths, numPaths, pathNameType, paths, pathBase); + + // TODO(svaisanen@nvidia.com): maybe sync only state required for path rendering? + syncRendererState(); + + mImplementation->stencilFillPathInstanced(pathObjects, fillMode, mask, transformType, + transformValues); } -void Context::insertEventMarker(GLsizei length, const char *marker) +void Context::stencilStrokePathInstanced(GLsizei numPaths, + GLenum pathNameType, + const void *paths, + GLuint pathBase, + GLint reference, + GLuint mask, + GLenum transformType, + const GLfloat *transformValues) { - ASSERT(mRenderer); - mRenderer->insertEventMarker(length, marker); + const auto &pathObjects = GatherPaths(*mState.mPaths, numPaths, pathNameType, paths, pathBase); + + // TODO(svaisanen@nvidia.com): maybe sync only state required for path rendering? + syncRendererState(); + + mImplementation->stencilStrokePathInstanced(pathObjects, reference, mask, transformType, + transformValues); } -void Context::pushGroupMarker(GLsizei length, const char *marker) +void Context::stencilThenCoverFillPathInstanced(GLsizei numPaths, + GLenum pathNameType, + const void *paths, + GLuint pathBase, + GLenum fillMode, + GLuint mask, + GLenum coverMode, + GLenum transformType, + const GLfloat *transformValues) { - ASSERT(mRenderer); - mRenderer->pushGroupMarker(length, marker); + const auto &pathObjects = GatherPaths(*mState.mPaths, numPaths, pathNameType, paths, pathBase); + + // TODO(svaisanen@nvidia.com): maybe sync only state required for path rendering? + syncRendererState(); + + mImplementation->stencilThenCoverFillPathInstanced(pathObjects, coverMode, fillMode, mask, + transformType, transformValues); } -void Context::popGroupMarker() +void Context::stencilThenCoverStrokePathInstanced(GLsizei numPaths, + GLenum pathNameType, + const void *paths, + GLuint pathBase, + GLint reference, + GLuint mask, + GLenum coverMode, + GLenum transformType, + const GLfloat *transformValues) { - ASSERT(mRenderer); - mRenderer->popGroupMarker(); + const auto &pathObjects = GatherPaths(*mState.mPaths, numPaths, pathNameType, paths, pathBase); + + // TODO(svaisanen@nvidia.com): maybe sync only state required for path rendering? + syncRendererState(); + + mImplementation->stencilThenCoverStrokePathInstanced(pathObjects, coverMode, reference, mask, + transformType, transformValues); +} + +void Context::bindFragmentInputLocation(GLuint program, GLint location, const GLchar *name) +{ + auto *programObject = getProgram(program); + + programObject->bindFragmentInputLocation(location, name); +} + +void Context::programPathFragmentInputGen(GLuint program, + GLint location, + GLenum genMode, + GLint components, + const GLfloat *coeffs) +{ + auto *programObject = getProgram(program); + + programObject->pathFragmentInputGen(this, location, genMode, components, coeffs); +} + +GLuint Context::getProgramResourceIndex(GLuint program, GLenum programInterface, const GLchar *name) +{ + const auto *programObject = getProgram(program); + return QueryProgramResourceIndex(programObject, programInterface, name); +} + +void Context::getProgramResourceName(GLuint program, + GLenum programInterface, + GLuint index, + GLsizei bufSize, + GLsizei *length, + GLchar *name) +{ + const auto *programObject = getProgram(program); + QueryProgramResourceName(programObject, programInterface, index, bufSize, length, name); +} + +GLint Context::getProgramResourceLocation(GLuint program, + GLenum programInterface, + const GLchar *name) +{ + const auto *programObject = getProgram(program); + return QueryProgramResourceLocation(programObject, programInterface, name); +} + +void Context::getProgramResourceiv(GLuint program, + GLenum programInterface, + GLuint index, + GLsizei propCount, + const GLenum *props, + GLsizei bufSize, + GLsizei *length, + GLint *params) +{ + const auto *programObject = getProgram(program); + QueryProgramResourceiv(programObject, programInterface, index, propCount, props, bufSize, + length, params); +} + +void Context::getProgramInterfaceiv(GLuint program, + GLenum programInterface, + GLenum pname, + GLint *params) +{ + const auto *programObject = getProgram(program); + QueryProgramInterfaceiv(programObject, programInterface, pname, params); } -void Context::recordError(const Error &error) +void Context::handleError(const Error &error) { if (error.isError()) { - mErrors.insert(error.getCode()); - - if (!error.getMessage().empty()) + GLenum code = error.getCode(); + mErrors.insert(code); + if (code == GL_OUT_OF_MEMORY && getWorkarounds().loseContextOnOutOfMemory) { - auto &debug = mState.getDebug(); - debug.insertMessage(GL_DEBUG_SOURCE_API, GL_DEBUG_TYPE_ERROR, error.getID(), - GL_DEBUG_SEVERITY_HIGH, error.getMessage()); + markContextLost(); } + + ASSERT(!error.getMessage().empty()); + mGLState.getDebug().insertMessage(GL_DEBUG_SOURCE_API, GL_DEBUG_TYPE_ERROR, error.getID(), + GL_DEBUG_SEVERITY_HIGH, error.getMessage()); } } @@ -1636,32 +2093,61 @@ GLenum Context::getError() } } +// 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; + mContextLostForced = true; + } + mContextLost = true; +} + +bool Context::isContextLost() +{ + return mContextLost; +} + GLenum Context::getResetStatus() { - //TODO(jmadill): needs MANGLE reworking - if (mResetStatus == GL_NO_ERROR && !mContextLost) + // Even if the application doesn't want to know about resets, we want to know + // as it will allow us to skip all the calls. + if (mResetStrategy == GL_NO_RESET_NOTIFICATION_EXT) { - // mResetStatus will be set by the markContextLost callback - // in the case a notification is sent - if (mRenderer->testDeviceLost()) + if (!mContextLost && mImplementation->getResetStatus() != GL_NO_ERROR) { - mRenderer->notifyDeviceLost(); + mContextLost = true; } - } - GLenum status = mResetStatus; + // EXT_robustness, section 2.6: If the reset notification behavior is + // NO_RESET_NOTIFICATION_EXT, then the implementation will never deliver notification of + // reset events, and GetGraphicsResetStatusEXT will always return NO_ERROR. + return GL_NO_ERROR; + } - if (mResetStatus != GL_NO_ERROR) + // The GL_EXT_robustness spec says that if a reset is encountered, a reset + // status should be returned at least once, and GL_NO_ERROR should be returned + // once the device has finished resetting. + if (!mContextLost) { - ASSERT(mContextLost); + ASSERT(mResetStatus == GL_NO_ERROR); + mResetStatus = mImplementation->getResetStatus(); - if (mRenderer->testDeviceResettable()) + if (mResetStatus != GL_NO_ERROR) { - mResetStatus = GL_NO_ERROR; + mContextLost = true; } } + else if (!mContextLostForced && mResetStatus != GL_NO_ERROR) + { + // If markContextLost was used to mark the context lost then + // assume that is not recoverable, and continue to report the + // lost reset status for the lifetime of this context. + mResetStatus = mImplementation->getResetStatus(); + } - return status; + return mResetStatus; } bool Context::isResetNotificationEnabled() @@ -1681,73 +2167,57 @@ EGLenum Context::getClientType() const EGLenum Context::getRenderBuffer() const { - auto framebufferIt = mFramebufferMap.find(0); - if (framebufferIt != mFramebufferMap.end()) - { - const Framebuffer *framebuffer = framebufferIt->second; - const FramebufferAttachment *backAttachment = framebuffer->getAttachment(GL_BACK); - - ASSERT(backAttachment != nullptr); - return backAttachment->getSurface()->getRenderBuffer(); - } - else + const Framebuffer *framebuffer = mState.mFramebuffers->getFramebuffer(0); + if (framebuffer == nullptr) { return EGL_NONE; } -} -void Context::checkVertexArrayAllocation(GLuint vertexArray) -{ - // Only called after a prior call to Gen. - if (!getVertexArray(vertexArray)) - { - VertexArray *vertexArrayObject = - new VertexArray(mRenderer, vertexArray, MAX_VERTEX_ATTRIBS); - mVertexArrayMap[vertexArray] = vertexArrayObject; - } + const FramebufferAttachment *backAttachment = framebuffer->getAttachment(GL_BACK); + ASSERT(backAttachment != nullptr); + return backAttachment->getSurface()->getRenderBuffer(); } -void Context::checkTransformFeedbackAllocation(GLuint transformFeedback) +VertexArray *Context::checkVertexArrayAllocation(GLuint vertexArrayHandle) { // Only called after a prior call to Gen. - if (!getTransformFeedback(transformFeedback)) + VertexArray *vertexArray = getVertexArray(vertexArrayHandle); + if (!vertexArray) { - TransformFeedback *transformFeedbackObject = - new TransformFeedback(mRenderer->createTransformFeedback(), transformFeedback, mCaps); - transformFeedbackObject->addRef(); - mTransformFeedbackMap[transformFeedback] = transformFeedbackObject; + vertexArray = new VertexArray(mImplementation.get(), vertexArrayHandle, + mCaps.maxVertexAttributes, mCaps.maxVertexAttribBindings); + + mVertexArrayMap.assign(vertexArrayHandle, vertexArray); } + + return vertexArray; } -Framebuffer *Context::checkFramebufferAllocation(GLuint framebuffer) +TransformFeedback *Context::checkTransformFeedbackAllocation(GLuint transformFeedbackHandle) { - // Can be called from Bind without a prior call to Gen. - auto framebufferIt = mFramebufferMap.find(framebuffer); - bool neverCreated = framebufferIt == mFramebufferMap.end(); - if (neverCreated || framebufferIt->second == nullptr) + // Only called after a prior call to Gen. + TransformFeedback *transformFeedback = getTransformFeedback(transformFeedbackHandle); + if (!transformFeedback) { - Framebuffer *newFBO = new Framebuffer(mCaps, mRenderer, framebuffer); - if (neverCreated) - { - mFramebufferHandleAllocator.reserve(framebuffer); - mFramebufferMap[framebuffer] = newFBO; - return newFBO; - } - - framebufferIt->second = newFBO; + transformFeedback = + new TransformFeedback(mImplementation.get(), transformFeedbackHandle, mCaps); + transformFeedback->addRef(); + mTransformFeedbackMap.assign(transformFeedbackHandle, transformFeedback); } - return framebufferIt->second; + return transformFeedback; } bool Context::isVertexArrayGenerated(GLuint vertexArray) { - return mVertexArrayMap.find(vertexArray) != mVertexArrayMap.end(); + ASSERT(mVertexArrayMap.contains(0)); + return mVertexArrayMap.contains(vertexArray); } bool Context::isTransformFeedbackGenerated(GLuint transformFeedback) { - return mTransformFeedbackMap.find(transformFeedback) != mTransformFeedbackMap.end(); + ASSERT(mTransformFeedbackMap.contains(0)); + return mTransformFeedbackMap.contains(transformFeedback); } void Context::detachTexture(GLuint texture) @@ -1756,7 +2226,7 @@ void Context::detachTexture(GLuint texture) // 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); + mGLState.detachTexture(this, mZeroTextures, texture); } void Context::detachBuffer(GLuint buffer) @@ -1769,7 +2239,7 @@ void Context::detachBuffer(GLuint buffer) // Attachments to unbound container objects, such as // deletion of a buffer attached to a vertex array object which is not bound to the context, // are not affected and continue to act as references on the deleted object - mState.detachBuffer(buffer); + mGLState.detachBuffer(this, buffer); } void Context::detachFramebuffer(GLuint framebuffer) @@ -1779,15 +2249,16 @@ void Context::detachFramebuffer(GLuint framebuffer) // 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 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) + if (mGLState.removeReadFramebufferBinding(framebuffer) && framebuffer != 0) { bindReadFramebuffer(0); } - if (mState.removeDrawFramebufferBinding(framebuffer) && framebuffer != 0) + if (mGLState.removeDrawFramebufferBinding(framebuffer) && framebuffer != 0) { bindDrawFramebuffer(0); } @@ -1795,7 +2266,7 @@ void Context::detachFramebuffer(GLuint framebuffer) void Context::detachRenderbuffer(GLuint renderbuffer) { - mState.detachRenderbuffer(renderbuffer); + mGLState.detachRenderbuffer(this, renderbuffer); } void Context::detachVertexArray(GLuint vertexArray) @@ -1807,7 +2278,7 @@ void Context::detachVertexArray(GLuint vertexArray) // [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)) + if (mGLState.removeVertexArrayBinding(vertexArray)) { bindVertexArray(0); } @@ -1815,151 +2286,188 @@ void Context::detachVertexArray(GLuint vertexArray) void Context::detachTransformFeedback(GLuint transformFeedback) { - mState.detachTransformFeedback(transformFeedback); + // Transform feedback detachment is handled by Context, because 0 is a valid + // transform feedback, and a pointer to it must be passed from Context to State at + // binding time. + + // The OpenGL specification doesn't mention what should happen when the currently bound + // transform feedback object is deleted. Since it is a container object, we treat it like + // VAOs and FBOs and set the current bound transform feedback back to 0. + if (mGLState.removeTransformFeedbackBinding(this, transformFeedback)) + { + bindTransformFeedback(GL_TRANSFORM_FEEDBACK, 0); + } } void Context::detachSampler(GLuint sampler) { - mState.detachSampler(sampler); + mGLState.detachSampler(this, sampler); } -void Context::setVertexAttribDivisor(GLuint index, GLuint divisor) +void Context::detachProgramPipeline(GLuint pipeline) { - mState.setVertexAttribDivisor(index, divisor); + mGLState.detachProgramPipeline(this, pipeline); } -void Context::samplerParameteri(GLuint sampler, GLenum pname, GLint param) +void Context::vertexAttribDivisor(GLuint index, GLuint divisor) { - mResourceManager->checkSamplerAllocation(sampler); + mGLState.setVertexAttribDivisor(this, index, divisor); +} - Sampler *samplerObject = getSampler(sampler); - ASSERT(samplerObject); +void Context::samplerParameteri(GLuint sampler, GLenum pname, GLint param) +{ + Sampler *samplerObject = + mState.mSamplers->checkSamplerAllocation(mImplementation.get(), sampler); + SetSamplerParameteri(samplerObject, pname, param); + mGLState.setObjectDirty(GL_SAMPLER); +} - // clang-format off - 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_MAX_ANISOTROPY_EXT: samplerObject->setMaxAnisotropy(std::min(static_cast(param), getExtensions().maxTextureAnisotropy)); 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->setCompareMode(static_cast(param)); break; - case GL_TEXTURE_COMPARE_FUNC: samplerObject->setCompareFunc(static_cast(param)); break; - default: UNREACHABLE(); break; - } - // clang-format on +void Context::samplerParameteriv(GLuint sampler, GLenum pname, const GLint *param) +{ + Sampler *samplerObject = + mState.mSamplers->checkSamplerAllocation(mImplementation.get(), sampler); + SetSamplerParameteriv(samplerObject, pname, param); + mGLState.setObjectDirty(GL_SAMPLER); } void Context::samplerParameterf(GLuint sampler, GLenum pname, GLfloat param) { - mResourceManager->checkSamplerAllocation(sampler); - - Sampler *samplerObject = getSampler(sampler); - ASSERT(samplerObject); - - // clang-format off - 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_MAX_ANISOTROPY_EXT: samplerObject->setMaxAnisotropy(std::min(param, getExtensions().maxTextureAnisotropy)); 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->setCompareMode(uiround(param)); break; - case GL_TEXTURE_COMPARE_FUNC: samplerObject->setCompareFunc(uiround(param)); break; - default: UNREACHABLE(); break; - } - // clang-format on + Sampler *samplerObject = + mState.mSamplers->checkSamplerAllocation(mImplementation.get(), sampler); + SetSamplerParameterf(samplerObject, pname, param); + mGLState.setObjectDirty(GL_SAMPLER); } -GLint Context::getSamplerParameteri(GLuint sampler, GLenum pname) +void Context::samplerParameterfv(GLuint sampler, GLenum pname, const GLfloat *param) { - mResourceManager->checkSamplerAllocation(sampler); - - Sampler *samplerObject = getSampler(sampler); - ASSERT(samplerObject); - - // clang-format off - 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_MAX_ANISOTROPY_EXT: return static_cast(samplerObject->getMaxAnisotropy()); - 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->getCompareMode()); - case GL_TEXTURE_COMPARE_FUNC: return static_cast(samplerObject->getCompareFunc()); - default: UNREACHABLE(); return 0; - } - // clang-format on + Sampler *samplerObject = + mState.mSamplers->checkSamplerAllocation(mImplementation.get(), sampler); + SetSamplerParameterfv(samplerObject, pname, param); + mGLState.setObjectDirty(GL_SAMPLER); } -GLfloat Context::getSamplerParameterf(GLuint sampler, GLenum pname) +void Context::getSamplerParameteriv(GLuint sampler, GLenum pname, GLint *params) { - mResourceManager->checkSamplerAllocation(sampler); + const Sampler *samplerObject = + mState.mSamplers->checkSamplerAllocation(mImplementation.get(), sampler); + QuerySamplerParameteriv(samplerObject, pname, params); + mGLState.setObjectDirty(GL_SAMPLER); +} - Sampler *samplerObject = getSampler(sampler); - ASSERT(samplerObject); +void Context::getSamplerParameterfv(GLuint sampler, GLenum pname, GLfloat *params) +{ + const Sampler *samplerObject = + mState.mSamplers->checkSamplerAllocation(mImplementation.get(), sampler); + QuerySamplerParameterfv(samplerObject, pname, params); + mGLState.setObjectDirty(GL_SAMPLER); +} - // clang-format off - 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_MAX_ANISOTROPY_EXT: return samplerObject->getMaxAnisotropy(); - 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->getCompareMode()); - case GL_TEXTURE_COMPARE_FUNC: return static_cast(samplerObject->getCompareFunc()); - default: UNREACHABLE(); return 0; - } - // clang-format on +void Context::programParameteri(GLuint program, GLenum pname, GLint value) +{ + gl::Program *programObject = getProgram(program); + SetProgramParameteri(programObject, pname, value); } void Context::initRendererString() { std::ostringstream rendererString; rendererString << "ANGLE ("; - rendererString << mRenderer->getRendererDescription(); + rendererString << mImplementation->getRendererDescription(); rendererString << ")"; mRendererString = MakeStaticString(rendererString.str()); } -const std::string &Context::getRendererString() const +void Context::initVersionStrings() { - return mRendererString; + const Version &clientVersion = getClientVersion(); + + std::ostringstream versionString; + versionString << "OpenGL ES " << clientVersion.major << "." << clientVersion.minor << " (ANGLE " + << ANGLE_VERSION_STRING << ")"; + mVersionString = MakeStaticString(versionString.str()); + + std::ostringstream shadingLanguageVersionString; + shadingLanguageVersionString << "OpenGL ES GLSL ES " + << (clientVersion.major == 2 ? 1 : clientVersion.major) << "." + << clientVersion.minor << "0 (ANGLE " << ANGLE_VERSION_STRING + << ")"; + mShadingLanguageString = MakeStaticString(shadingLanguageVersionString.str()); } void Context::initExtensionStrings() { - mExtensionStrings = mExtensions.getStrings(); + auto mergeExtensionStrings = [](const std::vector &strings) { + std::ostringstream combinedStringStream; + std::copy(strings.begin(), strings.end(), + std::ostream_iterator(combinedStringStream, " ")); + return MakeStaticString(combinedStringStream.str()); + }; - std::ostringstream combinedStringStream; - std::copy(mExtensionStrings.begin(), mExtensionStrings.end(), std::ostream_iterator(combinedStringStream, " ")); - mExtensionString = combinedStringStream.str(); + mExtensionStrings.clear(); + for (const auto &extensionString : mExtensions.getStrings()) + { + mExtensionStrings.push_back(MakeStaticString(extensionString)); + } + mExtensionString = mergeExtensionStrings(mExtensionStrings); + + const gl::Extensions &nativeExtensions = mImplementation->getNativeExtensions(); + + mRequestableExtensionStrings.clear(); + for (const auto &extensionInfo : GetExtensionInfoMap()) + { + if (extensionInfo.second.Requestable && + !(mExtensions.*(extensionInfo.second.ExtensionsMember)) && + nativeExtensions.*(extensionInfo.second.ExtensionsMember)) + { + mRequestableExtensionStrings.push_back(MakeStaticString(extensionInfo.first)); + } + } + mRequestableExtensionString = mergeExtensionStrings(mRequestableExtensionStrings); } -const std::string &Context::getExtensionString() const +const GLubyte *Context::getString(GLenum name) const { - return mExtensionString; + switch (name) + { + case GL_VENDOR: + return reinterpret_cast("Google Inc."); + + case GL_RENDERER: + return reinterpret_cast(mRendererString); + + case GL_VERSION: + return reinterpret_cast(mVersionString); + + case GL_SHADING_LANGUAGE_VERSION: + return reinterpret_cast(mShadingLanguageString); + + case GL_EXTENSIONS: + return reinterpret_cast(mExtensionString); + + case GL_REQUESTABLE_EXTENSIONS_ANGLE: + return reinterpret_cast(mRequestableExtensionString); + + default: + UNREACHABLE(); + return nullptr; + } } -const std::string &Context::getExtensionString(size_t idx) const +const GLubyte *Context::getStringi(GLenum name, GLuint index) const { - return mExtensionStrings[idx]; + switch (name) + { + case GL_EXTENSIONS: + return reinterpret_cast(mExtensionStrings[index]); + + case GL_REQUESTABLE_EXTENSIONS_ANGLE: + return reinterpret_cast(mRequestableExtensionStrings[index]); + + default: + UNREACHABLE(); + return nullptr; + } } size_t Context::getExtensionStringCount() const @@ -1967,26 +2475,117 @@ size_t Context::getExtensionStringCount() const return mExtensionStrings.size(); } -void Context::initCaps(GLuint clientVersion) +bool Context::isExtensionRequestable(const char *name) +{ + const ExtensionInfoMap &extensionInfos = GetExtensionInfoMap(); + auto extension = extensionInfos.find(name); + + const Extensions &nativeExtensions = mImplementation->getNativeExtensions(); + return extension != extensionInfos.end() && extension->second.Requestable && + nativeExtensions.*(extension->second.ExtensionsMember); +} + +void Context::requestExtension(const char *name) +{ + const ExtensionInfoMap &extensionInfos = GetExtensionInfoMap(); + ASSERT(extensionInfos.find(name) != extensionInfos.end()); + const auto &extension = extensionInfos.at(name); + ASSERT(extension.Requestable); + ASSERT(mImplementation->getNativeExtensions().*(extension.ExtensionsMember)); + + if (mExtensions.*(extension.ExtensionsMember)) + { + // Extension already enabled + return; + } + + mExtensions.*(extension.ExtensionsMember) = true; + updateCaps(); + initExtensionStrings(); + + // Release the shader compiler so it will be re-created with the requested extensions enabled. + releaseShaderCompiler(); + + // Invalidate all textures and framebuffer. Some extensions make new formats renderable or + // sampleable. + mState.mTextures->signalAllTexturesDirty(); + for (auto &zeroTexture : mZeroTextures) + { + zeroTexture.second->signalDirty(InitState::Initialized); + } + + mState.mFramebuffers->invalidateFramebufferComplenessCache(); +} + +size_t Context::getRequestableExtensionStringCount() const +{ + return mRequestableExtensionStrings.size(); +} + +void Context::beginTransformFeedback(GLenum primitiveMode) +{ + TransformFeedback *transformFeedback = mGLState.getCurrentTransformFeedback(); + ASSERT(transformFeedback != nullptr); + ASSERT(!transformFeedback->isPaused()); + + transformFeedback->begin(this, primitiveMode, mGLState.getProgram()); +} + +bool Context::hasActiveTransformFeedback(GLuint program) const +{ + for (auto pair : mTransformFeedbackMap) + { + if (pair.second != nullptr && pair.second->hasBoundProgram(program)) + { + return true; + } + } + return false; +} + +void Context::initCaps(const egl::DisplayExtensions &displayExtensions, bool robustResourceInit) { - mCaps = mRenderer->getRendererCaps(); + mCaps = mImplementation->getNativeCaps(); - mExtensions = mRenderer->getRendererExtensions(); + mExtensions = mImplementation->getNativeExtensions(); - mLimitations = mRenderer->getRendererLimitations(); + mLimitations = mImplementation->getNativeLimitations(); - if (clientVersion < 3) + if (getClientVersion() < Version(3, 0)) { // Disable ES3+ extensions - mExtensions.colorBufferFloat = false; + mExtensions.colorBufferFloat = false; + mExtensions.eglImageExternalEssl3 = false; + mExtensions.textureNorm16 = false; + mExtensions.multiview = false; + mExtensions.maxViews = 1u; } - if (clientVersion > 2) + if (getClientVersion() < ES_3_1) + { + // Disable ES3.1+ extensions + mExtensions.geometryShader = false; + } + + if (getClientVersion() > Version(2, 0)) { // FIXME(geofflang): Don't support EXT_sRGB in non-ES2 contexts - //mExtensions.sRGB = false; + // mExtensions.sRGB = false; } + // Some extensions are always available because they are implemented in the GL layer. + mExtensions.bindUniformLocation = true; + mExtensions.vertexArrayObject = true; + mExtensions.bindGeneratesResource = true; + mExtensions.clientArrays = true; + mExtensions.requestExtension = true; + + // Enable the no error extension if the context was created with the flag. + mExtensions.noError = mSkipValidation; + + // Enable surfaceless to advertise we'll have the correct behavior when there is no default FBO + mExtensions.surfacelessContext = displayExtensions.surfacelessContext; + // Explicitly enable GL_KHR_debug mExtensions.debug = true; mExtensions.maxDebugMessageLength = 1024; @@ -1994,64 +2593,186 @@ void Context::initCaps(GLuint clientVersion) mExtensions.maxDebugGroupStackDepth = 1024; mExtensions.maxLabelLength = 1024; + // Explicitly enable GL_ANGLE_robust_client_memory + mExtensions.robustClientMemory = true; + + // Determine robust resource init availability from EGL. + mExtensions.robustResourceInitialization = robustResourceInit; + + // mExtensions.robustBufferAccessBehavior is true only if robust access is true and the backend + // supports it. + mExtensions.robustBufferAccessBehavior = + mRobustAccess && mExtensions.robustBufferAccessBehavior; + + // Enable the cache control query unconditionally. + mExtensions.programCacheControl = true; + // 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); + LimitCap(&mCaps.maxVertexAttributes, MAX_VERTEX_ATTRIBS); + + if (getClientVersion() < ES_3_1) + { + mCaps.maxVertexAttribBindings = mCaps.maxVertexAttributes; + } + else + { + LimitCap(&mCaps.maxVertexAttribBindings, MAX_VERTEX_ATTRIB_BINDINGS); + } - mCaps.maxFragmentInputComponents = std::min(mCaps.maxFragmentInputComponents, IMPLEMENTATION_MAX_VARYING_VECTORS * 4); + LimitCap(&mCaps.maxVertexUniformBlocks, IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS); + LimitCap(&mCaps.maxVertexOutputComponents, IMPLEMENTATION_MAX_VARYING_VECTORS * 4); + LimitCap(&mCaps.maxFragmentInputComponents, IMPLEMENTATION_MAX_VARYING_VECTORS * 4); - mCaps.compressedTextureFormats.clear(); + // Limit textures as well, so we can use fast bitsets with texture bindings. + LimitCap(&mCaps.maxCombinedTextureImageUnits, IMPLEMENTATION_MAX_ACTIVE_TEXTURES); + LimitCap(&mCaps.maxVertexTextureImageUnits, IMPLEMENTATION_MAX_ACTIVE_TEXTURES / 2); + LimitCap(&mCaps.maxTextureImageUnits, IMPLEMENTATION_MAX_ACTIVE_TEXTURES / 2); + + mCaps.maxSampleMaskWords = std::min(mCaps.maxSampleMaskWords, MAX_SAMPLE_MASK_WORDS); - const TextureCapsMap &rendererFormats = mRenderer->getRendererTextureCaps(); - for (TextureCapsMap::const_iterator i = rendererFormats.begin(); i != rendererFormats.end(); i++) + // WebGL compatibility + mExtensions.webglCompatibility = mWebGLContext; + for (const auto &extensionInfo : GetExtensionInfoMap()) { - GLenum format = i->first; - TextureCaps formatCaps = i->second; + // If this context is for WebGL, disable all enableable extensions + if (mWebGLContext && extensionInfo.second.Requestable) + { + mExtensions.*(extensionInfo.second.ExtensionsMember) = false; + } + } + + // Generate texture caps + updateCaps(); +} + +void Context::updateCaps() +{ + mCaps.compressedTextureFormats.clear(); + mTextureCaps.clear(); - const InternalFormat &formatInfo = GetInternalFormatInfo(format); + for (GLenum sizedInternalFormat : GetAllSizedInternalFormats()) + { + TextureCaps formatCaps = mImplementation->getNativeTextureCaps().get(sizedInternalFormat); + const InternalFormat &formatInfo = GetSizedInternalFormatInfo(sizedInternalFormat); // Update the format caps based on the client version and extensions. // Caps are AND'd with the renderer caps because some core formats are still unsupported in // ES3. formatCaps.texturable = - formatCaps.texturable && formatInfo.textureSupport(clientVersion, mExtensions); + formatCaps.texturable && formatInfo.textureSupport(getClientVersion(), mExtensions); formatCaps.renderable = - formatCaps.renderable && formatInfo.renderSupport(clientVersion, mExtensions); + formatCaps.renderable && formatInfo.renderSupport(getClientVersion(), mExtensions); formatCaps.filterable = - formatCaps.filterable && formatInfo.filterSupport(clientVersion, mExtensions); + formatCaps.filterable && formatInfo.filterSupport(getClientVersion(), mExtensions); - // OpenGL ES does not support multisampling with integer formats - if (!formatInfo.renderSupport || formatInfo.componentType == GL_INT || formatInfo.componentType == GL_UNSIGNED_INT) + // OpenGL ES does not support multisampling with non-rendererable formats + // OpenGL ES 3.0 or prior does not support multisampling with integer formats + if (!formatCaps.renderable || + (getClientVersion() < ES_3_1 && + (formatInfo.componentType == GL_INT || formatInfo.componentType == GL_UNSIGNED_INT))) { formatCaps.sampleCounts.clear(); } + else + { + // We may have limited the max samples for some required renderbuffer formats due to + // non-conformant formats. In this case MAX_SAMPLES needs to be lowered accordingly. + GLuint formatMaxSamples = formatCaps.getMaxSamples(); + + // GLES 3.0.5 section 4.4.2.2: "Implementations must support creation of renderbuffers + // in these required formats with up to the value of MAX_SAMPLES multisamples, with the + // exception of signed and unsigned integer formats." + if (formatInfo.componentType != GL_INT && formatInfo.componentType != GL_UNSIGNED_INT && + formatInfo.isRequiredRenderbufferFormat(getClientVersion())) + { + ASSERT(getClientVersion() < ES_3_0 || formatMaxSamples >= 4); + mCaps.maxSamples = std::min(mCaps.maxSamples, formatMaxSamples); + } + + // Handle GLES 3.1 MAX_*_SAMPLES values similarly to MAX_SAMPLES. + if (getClientVersion() >= ES_3_1) + { + // GLES 3.1 section 9.2.5: "Implementations must support creation of renderbuffers + // in these required formats with up to the value of MAX_SAMPLES multisamples, with + // the exception that the signed and unsigned integer formats are required only to + // support creation of renderbuffers with up to the value of MAX_INTEGER_SAMPLES + // multisamples, which must be at least one." + if (formatInfo.componentType == GL_INT || + formatInfo.componentType == GL_UNSIGNED_INT) + { + mCaps.maxIntegerSamples = std::min(mCaps.maxIntegerSamples, formatMaxSamples); + } + + // GLES 3.1 section 19.3.1. + if (formatCaps.texturable) + { + if (formatInfo.depthBits > 0) + { + mCaps.maxDepthTextureSamples = + std::min(mCaps.maxDepthTextureSamples, formatMaxSamples); + } + else if (formatInfo.redBits > 0) + { + mCaps.maxColorTextureSamples = + std::min(mCaps.maxColorTextureSamples, formatMaxSamples); + } + } + } + } if (formatCaps.texturable && formatInfo.compressed) { - mCaps.compressedTextureFormats.push_back(format); + mCaps.compressedTextureFormats.push_back(sizedInternalFormat); } - mTextureCaps.insert(format, formatCaps); + mTextureCaps.insert(sizedInternalFormat, formatCaps); + } + + // If program binary is disabled, blank out the memory cache pointer. + if (!mImplementation->getNativeExtensions().getProgramBinary) + { + mMemoryProgramCache = nullptr; } } -void Context::syncRendererState() +void Context::initWorkarounds() +{ + // Apply back-end workarounds. + mImplementation->applyNativeWorkarounds(&mWorkarounds); + + // Lose the context upon out of memory error if the application is + // expecting to watch for those events. + mWorkarounds.loseContextOnOutOfMemory = (mResetStrategy == GL_LOSE_CONTEXT_ON_RESET_EXT); +} + +Error Context::prepareForDraw() { - const State::DirtyBits &dirtyBits = mState.getDirtyBits(); - mRenderer->syncState(mState, dirtyBits); - mState.clearDirtyBits(); - mState.syncDirtyObjects(); + syncRendererState(); + + if (isRobustResourceInitEnabled()) + { + ANGLE_TRY(mGLState.clearUnclearedActiveTextures(this)); + ANGLE_TRY(mGLState.getDrawFramebuffer()->ensureDrawAttachmentsInitialized(this)); + } + + return NoError(); } -void Context::syncRendererState(const State::DirtyBits &bitMask) +void Context::syncRendererState() { - const State::DirtyBits &dirtyBits = (mState.getDirtyBits() & bitMask); - mRenderer->syncState(mState, dirtyBits); - mState.clearDirtyBits(dirtyBits); + mGLState.syncDirtyObjects(this); + const State::DirtyBits &dirtyBits = mGLState.getDirtyBits(); + mImplementation->syncState(this, dirtyBits); + mGLState.clearDirtyBits(); +} - // TODO(jmadill): Filter objects by bitMask somehow? - mState.syncDirtyObjects(); +void Context::syncRendererState(const State::DirtyBits &bitMask, + const State::DirtyObjects &objectMask) +{ + mGLState.syncDirtyObjects(this, objectMask); + const State::DirtyBits &dirtyBits = (mGLState.getDirtyBits() & bitMask); + mImplementation->syncState(this, dirtyBits); + mGLState.clearDirtyBits(dirtyBits); } void Context::blitFramebuffer(GLint srcX0, @@ -2065,76 +2786,44 @@ void Context::blitFramebuffer(GLint srcX0, GLbitfield mask, GLenum filter) { - Framebuffer *readFramebuffer = mState.getReadFramebuffer(); - ASSERT(readFramebuffer); - - Framebuffer *drawFramebuffer = mState.getDrawFramebuffer(); + Framebuffer *drawFramebuffer = mGLState.getDrawFramebuffer(); ASSERT(drawFramebuffer); Rectangle srcArea(srcX0, srcY0, srcX1 - srcX0, srcY1 - srcY0); Rectangle dstArea(dstX0, dstY0, dstX1 - dstX0, dstY1 - dstY0); - syncRendererState(mState.blitStateBitMask()); + syncStateForBlit(); - Error error = drawFramebuffer->blit(mState, srcArea, dstArea, mask, filter, readFramebuffer); - if (error.isError()) - { - recordError(error); - return; - } + handleError(drawFramebuffer->blit(this, srcArea, dstArea, mask, filter)); } void Context::clear(GLbitfield mask) { - // Sync the clear state - syncRendererState(mState.clearStateBitMask()); - - Error error = mState.getDrawFramebuffer()->clear(mData, mask); - if (error.isError()) - { - recordError(error); - } + syncStateForClear(); + handleError(mGLState.getDrawFramebuffer()->clear(this, mask)); } void Context::clearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat *values) { - // Sync the clear state - syncRendererState(mState.clearStateBitMask()); - - Error error = mState.getDrawFramebuffer()->clearBufferfv(mData, buffer, drawbuffer, values); - if (error.isError()) - { - recordError(error); - } + syncStateForClear(); + handleError(mGLState.getDrawFramebuffer()->clearBufferfv(this, buffer, drawbuffer, values)); } void Context::clearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint *values) { - // Sync the clear state - syncRendererState(mState.clearStateBitMask()); - - Error error = mState.getDrawFramebuffer()->clearBufferuiv(mData, buffer, drawbuffer, values); - if (error.isError()) - { - recordError(error); - } + syncStateForClear(); + handleError(mGLState.getDrawFramebuffer()->clearBufferuiv(this, buffer, drawbuffer, values)); } void Context::clearBufferiv(GLenum buffer, GLint drawbuffer, const GLint *values) { - // Sync the clear state - syncRendererState(mState.clearStateBitMask()); - - Error error = mState.getDrawFramebuffer()->clearBufferiv(mData, buffer, drawbuffer, values); - if (error.isError()) - { - recordError(error); - } + syncStateForClear(); + handleError(mGLState.getDrawFramebuffer()->clearBufferiv(this, buffer, drawbuffer, values)); } void Context::clearBufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil) { - Framebuffer *framebufferObject = mState.getDrawFramebuffer(); + Framebuffer *framebufferObject = mGLState.getDrawFramebuffer(); ASSERT(framebufferObject); // If a buffer is not present, the clear has no effect @@ -2144,14 +2833,8 @@ void Context::clearBufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, GLin return; } - // Sync the clear state - syncRendererState(mState.clearStateBitMask()); - - Error error = framebufferObject->clearBufferfi(mData, buffer, drawbuffer, depth, stencil); - if (error.isError()) - { - recordError(error); - } + syncStateForClear(); + handleError(framebufferObject->clearBufferfi(this, buffer, drawbuffer, depth, stencil)); } void Context::readPixels(GLint x, @@ -2160,20 +2843,20 @@ void Context::readPixels(GLint x, GLsizei height, GLenum format, GLenum type, - GLvoid *pixels) + void *pixels) { - // Sync pack state - syncRendererState(mState.packStateBitMask()); + if (width == 0 || height == 0) + { + return; + } - Framebuffer *framebufferObject = mState.getReadFramebuffer(); - ASSERT(framebufferObject); + syncStateForReadPixels(); + + Framebuffer *readFBO = mGLState.getReadFramebuffer(); + ASSERT(readFBO); Rectangle area(x, y, width, height); - Error error = framebufferObject->readPixels(mState, area, format, type, pixels); - if (error.isError()) - { - recordError(error); - } + handleError(readFBO->readPixels(this, area, format, type, pixels)); } void Context::copyTexImage2D(GLenum target, @@ -2186,18 +2869,14 @@ void Context::copyTexImage2D(GLenum target, GLint border) { // Only sync the read FBO - mState.syncDirtyObject(GL_READ_FRAMEBUFFER); + mGLState.syncDirtyObject(this, GL_READ_FRAMEBUFFER); Rectangle sourceArea(x, y, width, height); - const Framebuffer *framebuffer = mState.getReadFramebuffer(); + Framebuffer *framebuffer = mGLState.getReadFramebuffer(); Texture *texture = getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target); - Error error = texture->copyImage(target, level, sourceArea, internalformat, framebuffer); - if (error.isError()) - { - recordError(error); - } + handleError(texture->copyImage(this, target, level, sourceArea, internalformat, framebuffer)); } void Context::copyTexSubImage2D(GLenum target, @@ -2209,20 +2888,21 @@ void Context::copyTexSubImage2D(GLenum target, GLsizei width, GLsizei height) { + if (width == 0 || height == 0) + { + return; + } + // Only sync the read FBO - mState.syncDirtyObject(GL_READ_FRAMEBUFFER); + mGLState.syncDirtyObject(this, GL_READ_FRAMEBUFFER); Offset destOffset(xoffset, yoffset, 0); Rectangle sourceArea(x, y, width, height); - const Framebuffer *framebuffer = mState.getReadFramebuffer(); + Framebuffer *framebuffer = mGLState.getReadFramebuffer(); Texture *texture = getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target); - Error error = texture->copySubImage(target, level, destOffset, sourceArea, framebuffer); - if (error.isError()) - { - recordError(error); - } + handleError(texture->copySubImage(this, target, level, destOffset, sourceArea, framebuffer)); } void Context::copyTexSubImage3D(GLenum target, @@ -2235,19 +2915,20 @@ void Context::copyTexSubImage3D(GLenum target, GLsizei width, GLsizei height) { + if (width == 0 || height == 0) + { + return; + } + // Only sync the read FBO - mState.syncDirtyObject(GL_READ_FRAMEBUFFER); + mGLState.syncDirtyObject(this, GL_READ_FRAMEBUFFER); Offset destOffset(xoffset, yoffset, zoffset); Rectangle sourceArea(x, y, width, height); - const Framebuffer *framebuffer = mState.getReadFramebuffer(); - Texture *texture = getTargetTexture(target); - Error error = texture->copySubImage(target, level, destOffset, sourceArea, framebuffer); - if (error.isError()) - { - recordError(error); - } + Framebuffer *framebuffer = mGLState.getReadFramebuffer(); + Texture *texture = getTargetTexture(target); + handleError(texture->copySubImage(this, target, level, destOffset, sourceArea, framebuffer)); } void Context::framebufferTexture2D(GLenum target, @@ -2256,7 +2937,7 @@ void Context::framebufferTexture2D(GLenum target, GLuint texture, GLint level) { - Framebuffer *framebuffer = mState.getTargetFramebuffer(target); + Framebuffer *framebuffer = mGLState.getTargetFramebuffer(target); ASSERT(framebuffer); if (texture != 0) @@ -2269,20 +2950,29 @@ void Context::framebufferTexture2D(GLenum target, { index = ImageIndex::Make2D(level); } + else if (textarget == GL_TEXTURE_RECTANGLE_ANGLE) + { + index = ImageIndex::MakeRectangle(level); + } + else if (textarget == GL_TEXTURE_2D_MULTISAMPLE) + { + ASSERT(level == 0); + index = ImageIndex::Make2DMultisample(); + } else { ASSERT(IsCubeMapTextureTarget(textarget)); index = ImageIndex::MakeCube(textarget, level); } - framebuffer->setAttachment(GL_TEXTURE, attachment, index, textureObj); + framebuffer->setAttachment(this, GL_TEXTURE, attachment, index, textureObj); } else { - framebuffer->resetAttachment(attachment); + framebuffer->resetAttachment(this, attachment); } - mState.setObjectDirty(target); + mGLState.setObjectDirty(target); } void Context::framebufferRenderbuffer(GLenum target, @@ -2290,21 +2980,22 @@ void Context::framebufferRenderbuffer(GLenum target, GLenum renderbuffertarget, GLuint renderbuffer) { - Framebuffer *framebuffer = mState.getTargetFramebuffer(target); + Framebuffer *framebuffer = mGLState.getTargetFramebuffer(target); ASSERT(framebuffer); if (renderbuffer != 0) { Renderbuffer *renderbufferObject = getRenderbuffer(renderbuffer); - framebuffer->setAttachment(GL_RENDERBUFFER, attachment, gl::ImageIndex::MakeInvalid(), + + framebuffer->setAttachment(this, GL_RENDERBUFFER, attachment, gl::ImageIndex::MakeInvalid(), renderbufferObject); } else { - framebuffer->resetAttachment(attachment); + framebuffer->resetAttachment(this, attachment); } - mState.setObjectDirty(target); + mGLState.setObjectDirty(target); } void Context::framebufferTextureLayer(GLenum target, @@ -2313,7 +3004,7 @@ void Context::framebufferTextureLayer(GLenum target, GLint level, GLint layer) { - Framebuffer *framebuffer = mState.getTargetFramebuffer(target); + Framebuffer *framebuffer = mGLState.getTargetFramebuffer(target); ASSERT(framebuffer); if (texture != 0) @@ -2332,46 +3023,94 @@ void Context::framebufferTextureLayer(GLenum target, index = ImageIndex::Make2DArray(level, layer); } - framebuffer->setAttachment(GL_TEXTURE, attachment, index, textureObject); + framebuffer->setAttachment(this, GL_TEXTURE, attachment, index, textureObject); + } + else + { + framebuffer->resetAttachment(this, attachment); + } + + mGLState.setObjectDirty(target); +} + +void Context::framebufferTextureMultiviewLayeredANGLE(GLenum target, + GLenum attachment, + GLuint texture, + GLint level, + GLint baseViewIndex, + GLsizei numViews) +{ + Framebuffer *framebuffer = mGLState.getTargetFramebuffer(target); + ASSERT(framebuffer); + + if (texture != 0) + { + Texture *textureObj = getTexture(texture); + + ImageIndex index = ImageIndex::Make2DArrayRange(level, baseViewIndex, numViews); + framebuffer->setAttachmentMultiviewLayered(this, GL_TEXTURE, attachment, index, textureObj, + numViews, baseViewIndex); + } + else + { + framebuffer->resetAttachment(this, attachment); + } + + mGLState.setObjectDirty(target); +} + +void Context::framebufferTextureMultiviewSideBySideANGLE(GLenum target, + GLenum attachment, + GLuint texture, + GLint level, + GLsizei numViews, + const GLint *viewportOffsets) +{ + Framebuffer *framebuffer = mGLState.getTargetFramebuffer(target); + ASSERT(framebuffer); + + if (texture != 0) + { + Texture *textureObj = getTexture(texture); + + ImageIndex index = ImageIndex::Make2D(level); + framebuffer->setAttachmentMultiviewSideBySide(this, GL_TEXTURE, attachment, index, + textureObj, numViews, viewportOffsets); } else { - framebuffer->resetAttachment(attachment); + framebuffer->resetAttachment(this, attachment); } - mState.setObjectDirty(target); + mGLState.setObjectDirty(target); } void Context::drawBuffers(GLsizei n, const GLenum *bufs) { - Framebuffer *framebuffer = mState.getDrawFramebuffer(); + Framebuffer *framebuffer = mGLState.getDrawFramebuffer(); ASSERT(framebuffer); framebuffer->setDrawBuffers(n, bufs); - mState.setObjectDirty(GL_DRAW_FRAMEBUFFER); + mGLState.setObjectDirty(GL_DRAW_FRAMEBUFFER); } void Context::readBuffer(GLenum mode) { - Framebuffer *readFBO = mState.getReadFramebuffer(); + Framebuffer *readFBO = mGLState.getReadFramebuffer(); readFBO->setReadBuffer(mode); - mState.setObjectDirty(GL_READ_FRAMEBUFFER); + mGLState.setObjectDirty(GL_READ_FRAMEBUFFER); } void Context::discardFramebuffer(GLenum target, GLsizei numAttachments, const GLenum *attachments) { // Only sync the FBO - mState.syncDirtyObject(target); + mGLState.syncDirtyObject(this, target); - Framebuffer *framebuffer = mState.getTargetFramebuffer(target); + Framebuffer *framebuffer = mGLState.getTargetFramebuffer(target); ASSERT(framebuffer); // The specification isn't clear what should be done when the framebuffer isn't complete. // We leave it up to the framebuffer implementation to decide what to do. - Error error = framebuffer->discard(numAttachments, attachments); - if (error.isError()) - { - recordError(error); - } + handleError(framebuffer->discard(this, numAttachments, attachments)); } void Context::invalidateFramebuffer(GLenum target, @@ -2379,20 +3118,17 @@ void Context::invalidateFramebuffer(GLenum target, const GLenum *attachments) { // Only sync the FBO - mState.syncDirtyObject(target); + mGLState.syncDirtyObject(this, target); - Framebuffer *framebuffer = mState.getTargetFramebuffer(target); + Framebuffer *framebuffer = mGLState.getTargetFramebuffer(target); ASSERT(framebuffer); - if (framebuffer->checkStatus(mData) == GL_FRAMEBUFFER_COMPLETE) + if (framebuffer->checkStatus(this) != GL_FRAMEBUFFER_COMPLETE) { - Error error = framebuffer->invalidate(numAttachments, attachments); - if (error.isError()) - { - recordError(error); - return; - } + return; } + + handleError(framebuffer->invalidate(this, numAttachments, attachments)); } void Context::invalidateSubFramebuffer(GLenum target, @@ -2404,21 +3140,2419 @@ void Context::invalidateSubFramebuffer(GLenum target, GLsizei height) { // Only sync the FBO - mState.syncDirtyObject(target); + mGLState.syncDirtyObject(this, target); - Framebuffer *framebuffer = mState.getTargetFramebuffer(target); + Framebuffer *framebuffer = mGLState.getTargetFramebuffer(target); ASSERT(framebuffer); - if (framebuffer->checkStatus(mData) == GL_FRAMEBUFFER_COMPLETE) + if (framebuffer->checkStatus(this) != GL_FRAMEBUFFER_COMPLETE) { - Rectangle area(x, y, width, height); - Error error = framebuffer->invalidateSub(numAttachments, attachments, area); - if (error.isError()) - { - recordError(error); - return; - } + return; + } + + Rectangle area(x, y, width, height); + handleError(framebuffer->invalidateSub(this, numAttachments, attachments, area)); +} + +void Context::texImage2D(GLenum target, + GLint level, + GLint internalformat, + GLsizei width, + GLsizei height, + GLint border, + GLenum format, + GLenum type, + const void *pixels) +{ + syncStateForTexImage(); + + Extents size(width, height, 1); + Texture *texture = + getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target); + handleError(texture->setImage(this, mGLState.getUnpackState(), target, level, internalformat, + size, format, type, reinterpret_cast(pixels))); +} + +void Context::texImage3D(GLenum target, + GLint level, + GLint internalformat, + GLsizei width, + GLsizei height, + GLsizei depth, + GLint border, + GLenum format, + GLenum type, + const void *pixels) +{ + syncStateForTexImage(); + + Extents size(width, height, depth); + Texture *texture = getTargetTexture(target); + handleError(texture->setImage(this, mGLState.getUnpackState(), target, level, internalformat, + size, format, type, reinterpret_cast(pixels))); +} + +void Context::texSubImage2D(GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLsizei width, + GLsizei height, + GLenum format, + GLenum type, + const void *pixels) +{ + // Zero sized uploads are valid but no-ops + if (width == 0 || height == 0) + { + return; + } + + syncStateForTexImage(); + + Box area(xoffset, yoffset, 0, width, height, 1); + Texture *texture = + getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target); + handleError(texture->setSubImage(this, mGLState.getUnpackState(), target, level, area, format, + type, reinterpret_cast(pixels))); +} + +void Context::texSubImage3D(GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLint zoffset, + GLsizei width, + GLsizei height, + GLsizei depth, + GLenum format, + GLenum type, + const void *pixels) +{ + // Zero sized uploads are valid but no-ops + if (width == 0 || height == 0 || depth == 0) + { + return; } + + syncStateForTexImage(); + + Box area(xoffset, yoffset, zoffset, width, height, depth); + Texture *texture = getTargetTexture(target); + handleError(texture->setSubImage(this, mGLState.getUnpackState(), target, level, area, format, + type, reinterpret_cast(pixels))); +} + +void Context::compressedTexImage2D(GLenum target, + GLint level, + GLenum internalformat, + GLsizei width, + GLsizei height, + GLint border, + GLsizei imageSize, + const void *data) +{ + syncStateForTexImage(); + + Extents size(width, height, 1); + Texture *texture = + getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target); + handleError(texture->setCompressedImage(this, mGLState.getUnpackState(), target, level, + internalformat, size, imageSize, + reinterpret_cast(data))); +} + +void Context::compressedTexImage3D(GLenum target, + GLint level, + GLenum internalformat, + GLsizei width, + GLsizei height, + GLsizei depth, + GLint border, + GLsizei imageSize, + const void *data) +{ + syncStateForTexImage(); + + Extents size(width, height, depth); + Texture *texture = getTargetTexture(target); + handleError(texture->setCompressedImage(this, mGLState.getUnpackState(), target, level, + internalformat, size, imageSize, + reinterpret_cast(data))); +} + +void Context::compressedTexSubImage2D(GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLsizei width, + GLsizei height, + GLenum format, + GLsizei imageSize, + const void *data) +{ + syncStateForTexImage(); + + Box area(xoffset, yoffset, 0, width, height, 1); + Texture *texture = + getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target); + handleError(texture->setCompressedSubImage(this, mGLState.getUnpackState(), target, level, area, + format, imageSize, + reinterpret_cast(data))); +} + +void Context::compressedTexSubImage3D(GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLint zoffset, + GLsizei width, + GLsizei height, + GLsizei depth, + GLenum format, + GLsizei imageSize, + const void *data) +{ + // Zero sized uploads are valid but no-ops + if (width == 0 || height == 0) + { + return; + } + + syncStateForTexImage(); + + Box area(xoffset, yoffset, zoffset, width, height, depth); + Texture *texture = getTargetTexture(target); + handleError(texture->setCompressedSubImage(this, mGLState.getUnpackState(), target, level, area, + format, imageSize, + reinterpret_cast(data))); +} + +void Context::generateMipmap(GLenum target) +{ + Texture *texture = getTargetTexture(target); + handleError(texture->generateMipmap(this)); +} + +void Context::copyTextureCHROMIUM(GLuint sourceId, + GLint sourceLevel, + GLenum destTarget, + GLuint destId, + GLint destLevel, + GLint internalFormat, + GLenum destType, + GLboolean unpackFlipY, + GLboolean unpackPremultiplyAlpha, + GLboolean unpackUnmultiplyAlpha) +{ + syncStateForTexImage(); + + gl::Texture *sourceTexture = getTexture(sourceId); + gl::Texture *destTexture = getTexture(destId); + handleError(destTexture->copyTexture(this, destTarget, destLevel, internalFormat, destType, + sourceLevel, ConvertToBool(unpackFlipY), + ConvertToBool(unpackPremultiplyAlpha), + ConvertToBool(unpackUnmultiplyAlpha), sourceTexture)); +} + +void Context::copySubTextureCHROMIUM(GLuint sourceId, + GLint sourceLevel, + GLenum destTarget, + GLuint destId, + GLint destLevel, + GLint xoffset, + GLint yoffset, + GLint x, + GLint y, + GLsizei width, + GLsizei height, + GLboolean unpackFlipY, + GLboolean unpackPremultiplyAlpha, + GLboolean unpackUnmultiplyAlpha) +{ + // Zero sized copies are valid but no-ops + if (width == 0 || height == 0) + { + return; + } + + syncStateForTexImage(); + + gl::Texture *sourceTexture = getTexture(sourceId); + gl::Texture *destTexture = getTexture(destId); + Offset offset(xoffset, yoffset, 0); + Rectangle area(x, y, width, height); + handleError(destTexture->copySubTexture(this, destTarget, destLevel, offset, sourceLevel, area, + ConvertToBool(unpackFlipY), + ConvertToBool(unpackPremultiplyAlpha), + ConvertToBool(unpackUnmultiplyAlpha), sourceTexture)); +} + +void Context::compressedCopyTextureCHROMIUM(GLuint sourceId, GLuint destId) +{ + syncStateForTexImage(); + + gl::Texture *sourceTexture = getTexture(sourceId); + gl::Texture *destTexture = getTexture(destId); + handleError(destTexture->copyCompressedTexture(this, sourceTexture)); +} + +void Context::getBufferPointerv(BufferBinding target, GLenum pname, void **params) +{ + Buffer *buffer = mGLState.getTargetBuffer(target); + ASSERT(buffer); + + QueryBufferPointerv(buffer, pname, params); +} + +void *Context::mapBuffer(BufferBinding target, GLenum access) +{ + Buffer *buffer = mGLState.getTargetBuffer(target); + ASSERT(buffer); + + Error error = buffer->map(this, access); + if (error.isError()) + { + handleError(error); + return nullptr; + } + + return buffer->getMapPointer(); +} + +GLboolean Context::unmapBuffer(BufferBinding target) +{ + Buffer *buffer = mGLState.getTargetBuffer(target); + ASSERT(buffer); + + GLboolean result; + Error error = buffer->unmap(this, &result); + if (error.isError()) + { + handleError(error); + return GL_FALSE; + } + + return result; +} + +void *Context::mapBufferRange(BufferBinding target, + GLintptr offset, + GLsizeiptr length, + GLbitfield access) +{ + Buffer *buffer = mGLState.getTargetBuffer(target); + ASSERT(buffer); + + Error error = buffer->mapRange(this, offset, length, access); + if (error.isError()) + { + handleError(error); + return nullptr; + } + + return buffer->getMapPointer(); +} + +void Context::flushMappedBufferRange(BufferBinding /*target*/, + GLintptr /*offset*/, + GLsizeiptr /*length*/) +{ + // We do not currently support a non-trivial implementation of FlushMappedBufferRange +} + +void Context::syncStateForReadPixels() +{ + syncRendererState(mReadPixelsDirtyBits, mReadPixelsDirtyObjects); +} + +void Context::syncStateForTexImage() +{ + syncRendererState(mTexImageDirtyBits, mTexImageDirtyObjects); +} + +void Context::syncStateForClear() +{ + syncRendererState(mClearDirtyBits, mClearDirtyObjects); +} + +void Context::syncStateForBlit() +{ + syncRendererState(mBlitDirtyBits, mBlitDirtyObjects); +} + +void Context::activeShaderProgram(GLuint pipeline, GLuint program) +{ + UNIMPLEMENTED(); +} + +void Context::activeTexture(GLenum texture) +{ + mGLState.setActiveSampler(texture - GL_TEXTURE0); +} + +void Context::blendColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) +{ + mGLState.setBlendColor(clamp01(red), clamp01(green), clamp01(blue), clamp01(alpha)); +} + +void Context::blendEquation(GLenum mode) +{ + mGLState.setBlendEquation(mode, mode); +} + +void Context::blendEquationSeparate(GLenum modeRGB, GLenum modeAlpha) +{ + mGLState.setBlendEquation(modeRGB, modeAlpha); +} + +void Context::blendFunc(GLenum sfactor, GLenum dfactor) +{ + mGLState.setBlendFactors(sfactor, dfactor, sfactor, dfactor); +} + +void Context::blendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) +{ + mGLState.setBlendFactors(srcRGB, dstRGB, srcAlpha, dstAlpha); +} + +void Context::clearColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) +{ + mGLState.setColorClearValue(red, green, blue, alpha); +} + +void Context::clearDepthf(GLfloat depth) +{ + mGLState.setDepthClearValue(depth); +} + +void Context::clearStencil(GLint s) +{ + mGLState.setStencilClearValue(s); +} + +void Context::colorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) +{ + mGLState.setColorMask(ConvertToBool(red), ConvertToBool(green), ConvertToBool(blue), + ConvertToBool(alpha)); +} + +void Context::cullFace(CullFaceMode mode) +{ + mGLState.setCullMode(mode); +} + +void Context::depthFunc(GLenum func) +{ + mGLState.setDepthFunc(func); +} + +void Context::depthMask(GLboolean flag) +{ + mGLState.setDepthMask(ConvertToBool(flag)); +} + +void Context::depthRangef(GLfloat zNear, GLfloat zFar) +{ + mGLState.setDepthRange(zNear, zFar); +} + +void Context::disable(GLenum cap) +{ + mGLState.setEnableFeature(cap, false); +} + +void Context::disableVertexAttribArray(GLuint index) +{ + mGLState.setEnableVertexAttribArray(index, false); +} + +void Context::enable(GLenum cap) +{ + mGLState.setEnableFeature(cap, true); +} + +void Context::enableVertexAttribArray(GLuint index) +{ + mGLState.setEnableVertexAttribArray(index, true); +} + +void Context::frontFace(GLenum mode) +{ + mGLState.setFrontFace(mode); +} + +void Context::hint(GLenum target, GLenum mode) +{ + switch (target) + { + case GL_GENERATE_MIPMAP_HINT: + mGLState.setGenerateMipmapHint(mode); + break; + + case GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES: + mGLState.setFragmentShaderDerivativeHint(mode); + break; + + default: + UNREACHABLE(); + return; + } +} + +void Context::lineWidth(GLfloat width) +{ + mGLState.setLineWidth(width); +} + +void Context::pixelStorei(GLenum pname, GLint param) +{ + switch (pname) + { + case GL_UNPACK_ALIGNMENT: + mGLState.setUnpackAlignment(param); + break; + + case GL_PACK_ALIGNMENT: + mGLState.setPackAlignment(param); + break; + + case GL_PACK_REVERSE_ROW_ORDER_ANGLE: + mGLState.setPackReverseRowOrder(param != 0); + break; + + case GL_UNPACK_ROW_LENGTH: + ASSERT((getClientMajorVersion() >= 3) || getExtensions().unpackSubimage); + mGLState.setUnpackRowLength(param); + break; + + case GL_UNPACK_IMAGE_HEIGHT: + ASSERT(getClientMajorVersion() >= 3); + mGLState.setUnpackImageHeight(param); + break; + + case GL_UNPACK_SKIP_IMAGES: + ASSERT(getClientMajorVersion() >= 3); + mGLState.setUnpackSkipImages(param); + break; + + case GL_UNPACK_SKIP_ROWS: + ASSERT((getClientMajorVersion() >= 3) || getExtensions().unpackSubimage); + mGLState.setUnpackSkipRows(param); + break; + + case GL_UNPACK_SKIP_PIXELS: + ASSERT((getClientMajorVersion() >= 3) || getExtensions().unpackSubimage); + mGLState.setUnpackSkipPixels(param); + break; + + case GL_PACK_ROW_LENGTH: + ASSERT((getClientMajorVersion() >= 3) || getExtensions().packSubimage); + mGLState.setPackRowLength(param); + break; + + case GL_PACK_SKIP_ROWS: + ASSERT((getClientMajorVersion() >= 3) || getExtensions().packSubimage); + mGLState.setPackSkipRows(param); + break; + + case GL_PACK_SKIP_PIXELS: + ASSERT((getClientMajorVersion() >= 3) || getExtensions().packSubimage); + mGLState.setPackSkipPixels(param); + break; + + default: + UNREACHABLE(); + return; + } +} + +void Context::polygonOffset(GLfloat factor, GLfloat units) +{ + mGLState.setPolygonOffsetParams(factor, units); +} + +void Context::sampleCoverage(GLfloat value, GLboolean invert) +{ + mGLState.setSampleCoverageParams(clamp01(value), ConvertToBool(invert)); +} + +void Context::sampleMaski(GLuint maskNumber, GLbitfield mask) +{ + mGLState.setSampleMaskParams(maskNumber, mask); +} + +void Context::scissor(GLint x, GLint y, GLsizei width, GLsizei height) +{ + mGLState.setScissorParams(x, y, width, height); +} + +void Context::stencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask) +{ + if (face == GL_FRONT || face == GL_FRONT_AND_BACK) + { + mGLState.setStencilParams(func, ref, mask); + } + + if (face == GL_BACK || face == GL_FRONT_AND_BACK) + { + mGLState.setStencilBackParams(func, ref, mask); + } +} + +void Context::stencilMaskSeparate(GLenum face, GLuint mask) +{ + if (face == GL_FRONT || face == GL_FRONT_AND_BACK) + { + mGLState.setStencilWritemask(mask); + } + + if (face == GL_BACK || face == GL_FRONT_AND_BACK) + { + mGLState.setStencilBackWritemask(mask); + } +} + +void Context::stencilOpSeparate(GLenum face, GLenum fail, GLenum zfail, GLenum zpass) +{ + if (face == GL_FRONT || face == GL_FRONT_AND_BACK) + { + mGLState.setStencilOperations(fail, zfail, zpass); + } + + if (face == GL_BACK || face == GL_FRONT_AND_BACK) + { + mGLState.setStencilBackOperations(fail, zfail, zpass); + } +} + +void Context::vertexAttrib1f(GLuint index, GLfloat x) +{ + GLfloat vals[4] = {x, 0, 0, 1}; + mGLState.setVertexAttribf(index, vals); +} + +void Context::vertexAttrib1fv(GLuint index, const GLfloat *values) +{ + GLfloat vals[4] = {values[0], 0, 0, 1}; + mGLState.setVertexAttribf(index, vals); +} + +void Context::vertexAttrib2f(GLuint index, GLfloat x, GLfloat y) +{ + GLfloat vals[4] = {x, y, 0, 1}; + mGLState.setVertexAttribf(index, vals); +} + +void Context::vertexAttrib2fv(GLuint index, const GLfloat *values) +{ + GLfloat vals[4] = {values[0], values[1], 0, 1}; + mGLState.setVertexAttribf(index, vals); +} + +void Context::vertexAttrib3f(GLuint index, GLfloat x, GLfloat y, GLfloat z) +{ + GLfloat vals[4] = {x, y, z, 1}; + mGLState.setVertexAttribf(index, vals); +} + +void Context::vertexAttrib3fv(GLuint index, const GLfloat *values) +{ + GLfloat vals[4] = {values[0], values[1], values[2], 1}; + mGLState.setVertexAttribf(index, vals); +} + +void Context::vertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w) +{ + GLfloat vals[4] = {x, y, z, w}; + mGLState.setVertexAttribf(index, vals); +} + +void Context::vertexAttrib4fv(GLuint index, const GLfloat *values) +{ + mGLState.setVertexAttribf(index, values); +} + +void Context::vertexAttribPointer(GLuint index, + GLint size, + GLenum type, + GLboolean normalized, + GLsizei stride, + const void *ptr) +{ + mGLState.setVertexAttribPointer(this, index, mGLState.getTargetBuffer(BufferBinding::Array), + size, type, ConvertToBool(normalized), false, stride, ptr); +} + +void Context::vertexAttribFormat(GLuint attribIndex, + GLint size, + GLenum type, + GLboolean normalized, + GLuint relativeOffset) +{ + mGLState.setVertexAttribFormat(attribIndex, size, type, ConvertToBool(normalized), false, + relativeOffset); +} + +void Context::vertexAttribIFormat(GLuint attribIndex, + GLint size, + GLenum type, + GLuint relativeOffset) +{ + mGLState.setVertexAttribFormat(attribIndex, size, type, false, true, relativeOffset); +} + +void Context::vertexAttribBinding(GLuint attribIndex, GLuint bindingIndex) +{ + mGLState.setVertexAttribBinding(this, attribIndex, bindingIndex); +} + +void Context::vertexBindingDivisor(GLuint bindingIndex, GLuint divisor) +{ + mGLState.setVertexBindingDivisor(bindingIndex, divisor); +} + +void Context::viewport(GLint x, GLint y, GLsizei width, GLsizei height) +{ + mGLState.setViewportParams(x, y, width, height); +} + +void Context::vertexAttribIPointer(GLuint index, + GLint size, + GLenum type, + GLsizei stride, + const void *pointer) +{ + mGLState.setVertexAttribPointer(this, index, mGLState.getTargetBuffer(BufferBinding::Array), + size, type, false, true, stride, pointer); +} + +void Context::vertexAttribI4i(GLuint index, GLint x, GLint y, GLint z, GLint w) +{ + GLint vals[4] = {x, y, z, w}; + mGLState.setVertexAttribi(index, vals); +} + +void Context::vertexAttribI4ui(GLuint index, GLuint x, GLuint y, GLuint z, GLuint w) +{ + GLuint vals[4] = {x, y, z, w}; + mGLState.setVertexAttribu(index, vals); +} + +void Context::vertexAttribI4iv(GLuint index, const GLint *v) +{ + mGLState.setVertexAttribi(index, v); +} + +void Context::vertexAttribI4uiv(GLuint index, const GLuint *v) +{ + mGLState.setVertexAttribu(index, v); +} + +void Context::getVertexAttribiv(GLuint index, GLenum pname, GLint *params) +{ + const VertexAttribCurrentValueData ¤tValues = + getGLState().getVertexAttribCurrentValue(index); + const VertexArray *vao = getGLState().getVertexArray(); + QueryVertexAttribiv(vao->getVertexAttribute(index), vao->getBindingFromAttribIndex(index), + currentValues, pname, params); +} + +void Context::getVertexAttribfv(GLuint index, GLenum pname, GLfloat *params) +{ + const VertexAttribCurrentValueData ¤tValues = + getGLState().getVertexAttribCurrentValue(index); + const VertexArray *vao = getGLState().getVertexArray(); + QueryVertexAttribfv(vao->getVertexAttribute(index), vao->getBindingFromAttribIndex(index), + currentValues, pname, params); +} + +void Context::getVertexAttribIiv(GLuint index, GLenum pname, GLint *params) +{ + const VertexAttribCurrentValueData ¤tValues = + getGLState().getVertexAttribCurrentValue(index); + const VertexArray *vao = getGLState().getVertexArray(); + QueryVertexAttribIiv(vao->getVertexAttribute(index), vao->getBindingFromAttribIndex(index), + currentValues, pname, params); +} + +void Context::getVertexAttribIuiv(GLuint index, GLenum pname, GLuint *params) +{ + const VertexAttribCurrentValueData ¤tValues = + getGLState().getVertexAttribCurrentValue(index); + const VertexArray *vao = getGLState().getVertexArray(); + QueryVertexAttribIuiv(vao->getVertexAttribute(index), vao->getBindingFromAttribIndex(index), + currentValues, pname, params); +} + +void Context::getVertexAttribPointerv(GLuint index, GLenum pname, void **pointer) +{ + const VertexAttribute &attrib = getGLState().getVertexArray()->getVertexAttribute(index); + QueryVertexAttribPointerv(attrib, pname, pointer); +} + +void Context::debugMessageControl(GLenum source, + GLenum type, + GLenum severity, + GLsizei count, + const GLuint *ids, + GLboolean enabled) +{ + std::vector idVector(ids, ids + count); + mGLState.getDebug().setMessageControl(source, type, severity, std::move(idVector), + ConvertToBool(enabled)); +} + +void Context::debugMessageInsert(GLenum source, + GLenum type, + GLuint id, + GLenum severity, + GLsizei length, + const GLchar *buf) +{ + std::string msg(buf, (length > 0) ? static_cast(length) : strlen(buf)); + mGLState.getDebug().insertMessage(source, type, id, severity, std::move(msg)); +} + +void Context::debugMessageCallback(GLDEBUGPROCKHR callback, const void *userParam) +{ + mGLState.getDebug().setCallback(callback, userParam); +} + +GLuint Context::getDebugMessageLog(GLuint count, + GLsizei bufSize, + GLenum *sources, + GLenum *types, + GLuint *ids, + GLenum *severities, + GLsizei *lengths, + GLchar *messageLog) +{ + return static_cast(mGLState.getDebug().getMessages(count, bufSize, sources, types, ids, + severities, lengths, messageLog)); +} + +void Context::pushDebugGroup(GLenum source, GLuint id, GLsizei length, const GLchar *message) +{ + std::string msg(message, (length > 0) ? static_cast(length) : strlen(message)); + mGLState.getDebug().pushGroup(source, id, std::move(msg)); + mImplementation->pushDebugGroup(source, id, length, message); +} + +void Context::popDebugGroup() +{ + mGLState.getDebug().popGroup(); + mImplementation->popDebugGroup(); +} + +void Context::bufferData(BufferBinding target, GLsizeiptr size, const void *data, BufferUsage usage) +{ + Buffer *buffer = mGLState.getTargetBuffer(target); + ASSERT(buffer); + handleError(buffer->bufferData(this, target, data, size, usage)); +} + +void Context::bufferSubData(BufferBinding target, + GLintptr offset, + GLsizeiptr size, + const void *data) +{ + if (data == nullptr) + { + return; + } + + Buffer *buffer = mGLState.getTargetBuffer(target); + ASSERT(buffer); + handleError(buffer->bufferSubData(this, target, data, size, offset)); +} + +void Context::attachShader(GLuint program, GLuint shader) +{ + Program *programObject = mState.mShaderPrograms->getProgram(program); + Shader *shaderObject = mState.mShaderPrograms->getShader(shader); + ASSERT(programObject && shaderObject); + programObject->attachShader(shaderObject); +} + +const Workarounds &Context::getWorkarounds() const +{ + return mWorkarounds; +} + +void Context::copyBufferSubData(BufferBinding readTarget, + BufferBinding writeTarget, + GLintptr readOffset, + GLintptr writeOffset, + GLsizeiptr size) +{ + // if size is zero, the copy is a successful no-op + if (size == 0) + { + return; + } + + // TODO(jmadill): cache these. + Buffer *readBuffer = mGLState.getTargetBuffer(readTarget); + Buffer *writeBuffer = mGLState.getTargetBuffer(writeTarget); + + handleError(writeBuffer->copyBufferSubData(this, readBuffer, readOffset, writeOffset, size)); +} + +void Context::bindAttribLocation(GLuint program, GLuint index, const GLchar *name) +{ + Program *programObject = getProgram(program); + // TODO(jmadill): Re-use this from the validation if possible. + ASSERT(programObject); + programObject->bindAttributeLocation(index, name); +} + +void Context::bindBuffer(BufferBinding target, GLuint buffer) +{ + Buffer *bufferObject = mState.mBuffers->checkBufferAllocation(mImplementation.get(), buffer); + mGLState.setBufferBinding(this, target, bufferObject); +} + +void Context::bindBufferBase(BufferBinding target, GLuint index, GLuint buffer) +{ + bindBufferRange(target, index, buffer, 0, 0); +} + +void Context::bindBufferRange(BufferBinding target, + GLuint index, + GLuint buffer, + GLintptr offset, + GLsizeiptr size) +{ + Buffer *bufferObject = mState.mBuffers->checkBufferAllocation(mImplementation.get(), buffer); + mGLState.setIndexedBufferBinding(this, target, index, bufferObject, offset, size); +} + +void Context::bindFramebuffer(GLenum target, GLuint framebuffer) +{ + if (target == GL_READ_FRAMEBUFFER || target == GL_FRAMEBUFFER) + { + bindReadFramebuffer(framebuffer); + } + + if (target == GL_DRAW_FRAMEBUFFER || target == GL_FRAMEBUFFER) + { + bindDrawFramebuffer(framebuffer); + } +} + +void Context::bindRenderbuffer(GLenum target, GLuint renderbuffer) +{ + ASSERT(target == GL_RENDERBUFFER); + Renderbuffer *object = + mState.mRenderbuffers->checkRenderbufferAllocation(mImplementation.get(), renderbuffer); + mGLState.setRenderbufferBinding(this, object); +} + +void Context::texStorage2DMultisample(GLenum target, + GLsizei samples, + GLenum internalformat, + GLsizei width, + GLsizei height, + GLboolean fixedsamplelocations) +{ + Extents size(width, height, 1); + Texture *texture = getTargetTexture(target); + handleError(texture->setStorageMultisample(this, target, samples, internalformat, size, + ConvertToBool(fixedsamplelocations))); +} + +void Context::getMultisamplefv(GLenum pname, GLuint index, GLfloat *val) +{ + // According to spec 3.1 Table 20.49: Framebuffer Dependent Values, + // the sample position should be queried by DRAW_FRAMEBUFFER. + mGLState.syncDirtyObject(this, GL_DRAW_FRAMEBUFFER); + const Framebuffer *framebuffer = mGLState.getDrawFramebuffer(); + + switch (pname) + { + case GL_SAMPLE_POSITION: + handleError(framebuffer->getSamplePosition(index, val)); + break; + default: + UNREACHABLE(); + } +} + +void Context::renderbufferStorage(GLenum target, + GLenum internalformat, + GLsizei width, + GLsizei height) +{ + // Hack for the special WebGL 1 "DEPTH_STENCIL" internal format. + GLenum convertedInternalFormat = getConvertedRenderbufferFormat(internalformat); + + Renderbuffer *renderbuffer = mGLState.getCurrentRenderbuffer(); + handleError(renderbuffer->setStorage(this, convertedInternalFormat, width, height)); +} + +void Context::renderbufferStorageMultisample(GLenum target, + GLsizei samples, + GLenum internalformat, + GLsizei width, + GLsizei height) +{ + // Hack for the special WebGL 1 "DEPTH_STENCIL" internal format. + GLenum convertedInternalFormat = getConvertedRenderbufferFormat(internalformat); + + Renderbuffer *renderbuffer = mGLState.getCurrentRenderbuffer(); + handleError( + renderbuffer->setStorageMultisample(this, samples, convertedInternalFormat, width, height)); +} + +void Context::getSynciv(GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values) +{ + const Sync *syncObject = getSync(sync); + handleError(QuerySynciv(syncObject, pname, bufSize, length, values)); +} + +void Context::getFramebufferParameteriv(GLenum target, GLenum pname, GLint *params) +{ + Framebuffer *framebuffer = mGLState.getTargetFramebuffer(target); + QueryFramebufferParameteriv(framebuffer, pname, params); +} + +void Context::framebufferParameteri(GLenum target, GLenum pname, GLint param) +{ + Framebuffer *framebuffer = mGLState.getTargetFramebuffer(target); + SetFramebufferParameteri(framebuffer, pname, param); +} + +Error Context::getScratchBuffer(size_t requstedSizeBytes, + angle::MemoryBuffer **scratchBufferOut) const +{ + if (!mScratchBuffer.get(requstedSizeBytes, scratchBufferOut)) + { + return OutOfMemory() << "Failed to allocate internal buffer."; + } + return NoError(); +} + +Error Context::getZeroFilledBuffer(size_t requstedSizeBytes, + angle::MemoryBuffer **zeroBufferOut) const +{ + if (!mZeroFilledBuffer.getInitialized(requstedSizeBytes, zeroBufferOut, 0)) + { + return OutOfMemory() << "Failed to allocate internal buffer."; + } + return NoError(); +} + +void Context::dispatchCompute(GLuint numGroupsX, GLuint numGroupsY, GLuint numGroupsZ) +{ + if (numGroupsX == 0u || numGroupsY == 0u || numGroupsZ == 0u) + { + return; + } + + // TODO(jmadill): Dirty bits for compute. + if (isRobustResourceInitEnabled()) + { + ANGLE_CONTEXT_TRY(mGLState.clearUnclearedActiveTextures(this)); + } + + handleError(mImplementation->dispatchCompute(this, numGroupsX, numGroupsY, numGroupsZ)); +} + +void Context::dispatchComputeIndirect(GLintptr indirect) +{ + UNIMPLEMENTED(); +} + +void Context::texStorage2D(GLenum target, + GLsizei levels, + GLenum internalFormat, + GLsizei width, + GLsizei height) +{ + Extents size(width, height, 1); + Texture *texture = getTargetTexture(target); + handleError(texture->setStorage(this, target, levels, internalFormat, size)); +} + +void Context::texStorage3D(GLenum target, + GLsizei levels, + GLenum internalFormat, + GLsizei width, + GLsizei height, + GLsizei depth) +{ + Extents size(width, height, depth); + Texture *texture = getTargetTexture(target); + handleError(texture->setStorage(this, target, levels, internalFormat, size)); +} + +void Context::memoryBarrier(GLbitfield barriers) +{ + UNIMPLEMENTED(); +} + +void Context::memoryBarrierByRegion(GLbitfield barriers) +{ + UNIMPLEMENTED(); +} + +GLenum Context::checkFramebufferStatus(GLenum target) +{ + Framebuffer *framebuffer = mGLState.getTargetFramebuffer(target); + ASSERT(framebuffer); + + return framebuffer->checkStatus(this); +} + +void Context::compileShader(GLuint shader) +{ + Shader *shaderObject = GetValidShader(this, shader); + if (!shaderObject) + { + return; + } + shaderObject->compile(this); +} + +void Context::deleteBuffers(GLsizei n, const GLuint *buffers) +{ + for (int i = 0; i < n; i++) + { + deleteBuffer(buffers[i]); + } +} + +void Context::deleteFramebuffers(GLsizei n, const GLuint *framebuffers) +{ + for (int i = 0; i < n; i++) + { + if (framebuffers[i] != 0) + { + deleteFramebuffer(framebuffers[i]); + } + } +} + +void Context::deleteRenderbuffers(GLsizei n, const GLuint *renderbuffers) +{ + for (int i = 0; i < n; i++) + { + deleteRenderbuffer(renderbuffers[i]); + } +} + +void Context::deleteTextures(GLsizei n, const GLuint *textures) +{ + for (int i = 0; i < n; i++) + { + if (textures[i] != 0) + { + deleteTexture(textures[i]); + } + } +} + +void Context::detachShader(GLuint program, GLuint shader) +{ + Program *programObject = getProgram(program); + ASSERT(programObject); + + Shader *shaderObject = getShader(shader); + ASSERT(shaderObject); + + programObject->detachShader(this, shaderObject); +} + +void Context::genBuffers(GLsizei n, GLuint *buffers) +{ + for (int i = 0; i < n; i++) + { + buffers[i] = createBuffer(); + } +} + +void Context::genFramebuffers(GLsizei n, GLuint *framebuffers) +{ + for (int i = 0; i < n; i++) + { + framebuffers[i] = createFramebuffer(); + } +} + +void Context::genRenderbuffers(GLsizei n, GLuint *renderbuffers) +{ + for (int i = 0; i < n; i++) + { + renderbuffers[i] = createRenderbuffer(); + } +} + +void Context::genTextures(GLsizei n, GLuint *textures) +{ + for (int i = 0; i < n; i++) + { + textures[i] = createTexture(); + } +} + +void Context::getActiveAttrib(GLuint program, + GLuint index, + GLsizei bufsize, + GLsizei *length, + GLint *size, + GLenum *type, + GLchar *name) +{ + Program *programObject = getProgram(program); + ASSERT(programObject); + programObject->getActiveAttribute(index, bufsize, length, size, type, name); +} + +void Context::getActiveUniform(GLuint program, + GLuint index, + GLsizei bufsize, + GLsizei *length, + GLint *size, + GLenum *type, + GLchar *name) +{ + Program *programObject = getProgram(program); + ASSERT(programObject); + programObject->getActiveUniform(index, bufsize, length, size, type, name); +} + +void Context::getAttachedShaders(GLuint program, GLsizei maxcount, GLsizei *count, GLuint *shaders) +{ + Program *programObject = getProgram(program); + ASSERT(programObject); + programObject->getAttachedShaders(maxcount, count, shaders); +} + +GLint Context::getAttribLocation(GLuint program, const GLchar *name) +{ + Program *programObject = getProgram(program); + ASSERT(programObject); + return programObject->getAttributeLocation(name); +} + +void Context::getBooleanv(GLenum pname, GLboolean *params) +{ + GLenum nativeType; + unsigned int numParams = 0; + getQueryParameterInfo(pname, &nativeType, &numParams); + + if (nativeType == GL_BOOL) + { + getBooleanvImpl(pname, params); + } + else + { + CastStateValues(this, nativeType, pname, numParams, params); + } +} + +void Context::getFloatv(GLenum pname, GLfloat *params) +{ + GLenum nativeType; + unsigned int numParams = 0; + getQueryParameterInfo(pname, &nativeType, &numParams); + + if (nativeType == GL_FLOAT) + { + getFloatvImpl(pname, params); + } + else + { + CastStateValues(this, nativeType, pname, numParams, params); + } +} + +void Context::getIntegerv(GLenum pname, GLint *params) +{ + GLenum nativeType; + unsigned int numParams = 0; + getQueryParameterInfo(pname, &nativeType, &numParams); + + if (nativeType == GL_INT) + { + getIntegervImpl(pname, params); + } + else + { + CastStateValues(this, nativeType, pname, numParams, params); + } +} + +void Context::getProgramiv(GLuint program, GLenum pname, GLint *params) +{ + Program *programObject = getProgram(program); + ASSERT(programObject); + QueryProgramiv(this, programObject, pname, params); +} + +void Context::getProgramPipelineiv(GLuint pipeline, GLenum pname, GLint *params) +{ + UNIMPLEMENTED(); +} + +void Context::getProgramInfoLog(GLuint program, GLsizei bufsize, GLsizei *length, GLchar *infolog) +{ + Program *programObject = getProgram(program); + ASSERT(programObject); + programObject->getInfoLog(bufsize, length, infolog); +} + +void Context::getProgramPipelineInfoLog(GLuint pipeline, + GLsizei bufSize, + GLsizei *length, + GLchar *infoLog) +{ + UNIMPLEMENTED(); +} + +void Context::getShaderiv(GLuint shader, GLenum pname, GLint *params) +{ + Shader *shaderObject = getShader(shader); + ASSERT(shaderObject); + QueryShaderiv(this, shaderObject, pname, params); +} + +void Context::getShaderInfoLog(GLuint shader, GLsizei bufsize, GLsizei *length, GLchar *infolog) +{ + Shader *shaderObject = getShader(shader); + ASSERT(shaderObject); + shaderObject->getInfoLog(this, bufsize, length, infolog); +} + +void Context::getShaderPrecisionFormat(GLenum shadertype, + GLenum precisiontype, + GLint *range, + GLint *precision) +{ + // TODO(jmadill): Compute shaders. + + switch (shadertype) + { + case GL_VERTEX_SHADER: + switch (precisiontype) + { + case GL_LOW_FLOAT: + mCaps.vertexLowpFloat.get(range, precision); + break; + case GL_MEDIUM_FLOAT: + mCaps.vertexMediumpFloat.get(range, precision); + break; + case GL_HIGH_FLOAT: + mCaps.vertexHighpFloat.get(range, precision); + break; + + case GL_LOW_INT: + mCaps.vertexLowpInt.get(range, precision); + break; + case GL_MEDIUM_INT: + mCaps.vertexMediumpInt.get(range, precision); + break; + case GL_HIGH_INT: + mCaps.vertexHighpInt.get(range, precision); + break; + + default: + UNREACHABLE(); + return; + } + break; + + case GL_FRAGMENT_SHADER: + switch (precisiontype) + { + case GL_LOW_FLOAT: + mCaps.fragmentLowpFloat.get(range, precision); + break; + case GL_MEDIUM_FLOAT: + mCaps.fragmentMediumpFloat.get(range, precision); + break; + case GL_HIGH_FLOAT: + mCaps.fragmentHighpFloat.get(range, precision); + break; + + case GL_LOW_INT: + mCaps.fragmentLowpInt.get(range, precision); + break; + case GL_MEDIUM_INT: + mCaps.fragmentMediumpInt.get(range, precision); + break; + case GL_HIGH_INT: + mCaps.fragmentHighpInt.get(range, precision); + break; + + default: + UNREACHABLE(); + return; + } + break; + + default: + UNREACHABLE(); + return; + } +} + +void Context::getShaderSource(GLuint shader, GLsizei bufsize, GLsizei *length, GLchar *source) +{ + Shader *shaderObject = getShader(shader); + ASSERT(shaderObject); + shaderObject->getSource(bufsize, length, source); +} + +void Context::getUniformfv(GLuint program, GLint location, GLfloat *params) +{ + Program *programObject = getProgram(program); + ASSERT(programObject); + programObject->getUniformfv(this, location, params); +} + +void Context::getUniformiv(GLuint program, GLint location, GLint *params) +{ + Program *programObject = getProgram(program); + ASSERT(programObject); + programObject->getUniformiv(this, location, params); +} + +GLint Context::getUniformLocation(GLuint program, const GLchar *name) +{ + Program *programObject = getProgram(program); + ASSERT(programObject); + return programObject->getUniformLocation(name); +} + +GLboolean Context::isBuffer(GLuint buffer) +{ + if (buffer == 0) + { + return GL_FALSE; + } + + return (getBuffer(buffer) ? GL_TRUE : GL_FALSE); +} + +GLboolean Context::isEnabled(GLenum cap) +{ + return mGLState.getEnableFeature(cap); +} + +GLboolean Context::isFramebuffer(GLuint framebuffer) +{ + if (framebuffer == 0) + { + return GL_FALSE; + } + + return (getFramebuffer(framebuffer) ? GL_TRUE : GL_FALSE); +} + +GLboolean Context::isProgram(GLuint program) +{ + if (program == 0) + { + return GL_FALSE; + } + + return (getProgram(program) ? GL_TRUE : GL_FALSE); +} + +GLboolean Context::isRenderbuffer(GLuint renderbuffer) +{ + if (renderbuffer == 0) + { + return GL_FALSE; + } + + return (getRenderbuffer(renderbuffer) ? GL_TRUE : GL_FALSE); +} + +GLboolean Context::isShader(GLuint shader) +{ + if (shader == 0) + { + return GL_FALSE; + } + + return (getShader(shader) ? GL_TRUE : GL_FALSE); +} + +GLboolean Context::isTexture(GLuint texture) +{ + if (texture == 0) + { + return GL_FALSE; + } + + return (getTexture(texture) ? GL_TRUE : GL_FALSE); +} + +void Context::linkProgram(GLuint program) +{ + Program *programObject = getProgram(program); + ASSERT(programObject); + handleError(programObject->link(this)); + mGLState.onProgramExecutableChange(programObject); +} + +void Context::releaseShaderCompiler() +{ + mCompiler.set(this, nullptr); +} + +void Context::shaderBinary(GLsizei n, + const GLuint *shaders, + GLenum binaryformat, + const void *binary, + GLsizei length) +{ + // No binary shader formats are supported. + UNIMPLEMENTED(); +} + +void Context::shaderSource(GLuint shader, + GLsizei count, + const GLchar *const *string, + const GLint *length) +{ + Shader *shaderObject = getShader(shader); + ASSERT(shaderObject); + shaderObject->setSource(count, string, length); +} + +void Context::stencilFunc(GLenum func, GLint ref, GLuint mask) +{ + stencilFuncSeparate(GL_FRONT_AND_BACK, func, ref, mask); +} + +void Context::stencilMask(GLuint mask) +{ + stencilMaskSeparate(GL_FRONT_AND_BACK, mask); +} + +void Context::stencilOp(GLenum fail, GLenum zfail, GLenum zpass) +{ + stencilOpSeparate(GL_FRONT_AND_BACK, fail, zfail, zpass); +} + +void Context::uniform1f(GLint location, GLfloat x) +{ + Program *program = mGLState.getProgram(); + program->setUniform1fv(location, 1, &x); +} + +void Context::uniform1fv(GLint location, GLsizei count, const GLfloat *v) +{ + Program *program = mGLState.getProgram(); + program->setUniform1fv(location, count, v); +} + +void Context::uniform1i(GLint location, GLint x) +{ + Program *program = mGLState.getProgram(); + if (program->setUniform1iv(location, 1, &x) == Program::SetUniformResult::SamplerChanged) + { + mGLState.setObjectDirty(GL_PROGRAM); + } +} + +void Context::uniform1iv(GLint location, GLsizei count, const GLint *v) +{ + Program *program = mGLState.getProgram(); + if (program->setUniform1iv(location, count, v) == Program::SetUniformResult::SamplerChanged) + { + mGLState.setObjectDirty(GL_PROGRAM); + } +} + +void Context::uniform2f(GLint location, GLfloat x, GLfloat y) +{ + GLfloat xy[2] = {x, y}; + Program *program = mGLState.getProgram(); + program->setUniform2fv(location, 1, xy); +} + +void Context::uniform2fv(GLint location, GLsizei count, const GLfloat *v) +{ + Program *program = mGLState.getProgram(); + program->setUniform2fv(location, count, v); +} + +void Context::uniform2i(GLint location, GLint x, GLint y) +{ + GLint xy[2] = {x, y}; + Program *program = mGLState.getProgram(); + program->setUniform2iv(location, 1, xy); +} + +void Context::uniform2iv(GLint location, GLsizei count, const GLint *v) +{ + Program *program = mGLState.getProgram(); + program->setUniform2iv(location, count, v); +} + +void Context::uniform3f(GLint location, GLfloat x, GLfloat y, GLfloat z) +{ + GLfloat xyz[3] = {x, y, z}; + Program *program = mGLState.getProgram(); + program->setUniform3fv(location, 1, xyz); +} + +void Context::uniform3fv(GLint location, GLsizei count, const GLfloat *v) +{ + Program *program = mGLState.getProgram(); + program->setUniform3fv(location, count, v); +} + +void Context::uniform3i(GLint location, GLint x, GLint y, GLint z) +{ + GLint xyz[3] = {x, y, z}; + Program *program = mGLState.getProgram(); + program->setUniform3iv(location, 1, xyz); +} + +void Context::uniform3iv(GLint location, GLsizei count, const GLint *v) +{ + Program *program = mGLState.getProgram(); + program->setUniform3iv(location, count, v); +} + +void Context::uniform4f(GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w) +{ + GLfloat xyzw[4] = {x, y, z, w}; + Program *program = mGLState.getProgram(); + program->setUniform4fv(location, 1, xyzw); +} + +void Context::uniform4fv(GLint location, GLsizei count, const GLfloat *v) +{ + Program *program = mGLState.getProgram(); + program->setUniform4fv(location, count, v); +} + +void Context::uniform4i(GLint location, GLint x, GLint y, GLint z, GLint w) +{ + GLint xyzw[4] = {x, y, z, w}; + Program *program = mGLState.getProgram(); + program->setUniform4iv(location, 1, xyzw); +} + +void Context::uniform4iv(GLint location, GLsizei count, const GLint *v) +{ + Program *program = mGLState.getProgram(); + program->setUniform4iv(location, count, v); +} + +void Context::uniformMatrix2fv(GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + Program *program = mGLState.getProgram(); + program->setUniformMatrix2fv(location, count, transpose, value); +} + +void Context::uniformMatrix3fv(GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + Program *program = mGLState.getProgram(); + program->setUniformMatrix3fv(location, count, transpose, value); +} + +void Context::uniformMatrix4fv(GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + Program *program = mGLState.getProgram(); + program->setUniformMatrix4fv(location, count, transpose, value); +} + +void Context::validateProgram(GLuint program) +{ + Program *programObject = getProgram(program); + ASSERT(programObject); + programObject->validate(mCaps); +} + +void Context::validateProgramPipeline(GLuint pipeline) +{ + UNIMPLEMENTED(); +} + +void Context::getProgramBinary(GLuint program, + GLsizei bufSize, + GLsizei *length, + GLenum *binaryFormat, + void *binary) +{ + Program *programObject = getProgram(program); + ASSERT(programObject != nullptr); + + handleError(programObject->saveBinary(this, binaryFormat, binary, bufSize, length)); +} + +void Context::programBinary(GLuint program, GLenum binaryFormat, const void *binary, GLsizei length) +{ + Program *programObject = getProgram(program); + ASSERT(programObject != nullptr); + + handleError(programObject->loadBinary(this, binaryFormat, binary, length)); +} + +void Context::uniform1ui(GLint location, GLuint v0) +{ + Program *program = mGLState.getProgram(); + program->setUniform1uiv(location, 1, &v0); +} + +void Context::uniform2ui(GLint location, GLuint v0, GLuint v1) +{ + Program *program = mGLState.getProgram(); + const GLuint xy[] = {v0, v1}; + program->setUniform2uiv(location, 1, xy); +} + +void Context::uniform3ui(GLint location, GLuint v0, GLuint v1, GLuint v2) +{ + Program *program = mGLState.getProgram(); + const GLuint xyz[] = {v0, v1, v2}; + program->setUniform3uiv(location, 1, xyz); +} + +void Context::uniform4ui(GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3) +{ + Program *program = mGLState.getProgram(); + const GLuint xyzw[] = {v0, v1, v2, v3}; + program->setUniform4uiv(location, 1, xyzw); +} + +void Context::uniform1uiv(GLint location, GLsizei count, const GLuint *value) +{ + Program *program = mGLState.getProgram(); + program->setUniform1uiv(location, count, value); +} +void Context::uniform2uiv(GLint location, GLsizei count, const GLuint *value) +{ + Program *program = mGLState.getProgram(); + program->setUniform2uiv(location, count, value); +} + +void Context::uniform3uiv(GLint location, GLsizei count, const GLuint *value) +{ + Program *program = mGLState.getProgram(); + program->setUniform3uiv(location, count, value); +} + +void Context::uniform4uiv(GLint location, GLsizei count, const GLuint *value) +{ + Program *program = mGLState.getProgram(); + program->setUniform4uiv(location, count, value); +} + +void Context::genQueries(GLsizei n, GLuint *ids) +{ + for (GLsizei i = 0; i < n; i++) + { + GLuint handle = mQueryHandleAllocator.allocate(); + mQueryMap.assign(handle, nullptr); + ids[i] = handle; + } +} + +void Context::deleteQueries(GLsizei n, const GLuint *ids) +{ + for (int i = 0; i < n; i++) + { + GLuint query = ids[i]; + + Query *queryObject = nullptr; + if (mQueryMap.erase(query, &queryObject)) + { + mQueryHandleAllocator.release(query); + if (queryObject) + { + queryObject->release(this); + } + } + } +} + +GLboolean Context::isQuery(GLuint id) +{ + return (getQuery(id, false, GL_NONE) != nullptr) ? GL_TRUE : GL_FALSE; +} + +void Context::uniformMatrix2x3fv(GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + Program *program = mGLState.getProgram(); + program->setUniformMatrix2x3fv(location, count, transpose, value); +} + +void Context::uniformMatrix3x2fv(GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + Program *program = mGLState.getProgram(); + program->setUniformMatrix3x2fv(location, count, transpose, value); +} + +void Context::uniformMatrix2x4fv(GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + Program *program = mGLState.getProgram(); + program->setUniformMatrix2x4fv(location, count, transpose, value); +} + +void Context::uniformMatrix4x2fv(GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + Program *program = mGLState.getProgram(); + program->setUniformMatrix4x2fv(location, count, transpose, value); +} + +void Context::uniformMatrix3x4fv(GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + Program *program = mGLState.getProgram(); + program->setUniformMatrix3x4fv(location, count, transpose, value); +} + +void Context::uniformMatrix4x3fv(GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + Program *program = mGLState.getProgram(); + program->setUniformMatrix4x3fv(location, count, transpose, value); +} + +void Context::deleteVertexArrays(GLsizei n, const GLuint *arrays) +{ + for (int arrayIndex = 0; arrayIndex < n; arrayIndex++) + { + GLuint vertexArray = arrays[arrayIndex]; + + if (arrays[arrayIndex] != 0) + { + VertexArray *vertexArrayObject = nullptr; + if (mVertexArrayMap.erase(vertexArray, &vertexArrayObject)) + { + if (vertexArrayObject != nullptr) + { + detachVertexArray(vertexArray); + vertexArrayObject->onDestroy(this); + } + + mVertexArrayHandleAllocator.release(vertexArray); + } + } + } +} + +void Context::genVertexArrays(GLsizei n, GLuint *arrays) +{ + for (int arrayIndex = 0; arrayIndex < n; arrayIndex++) + { + GLuint vertexArray = mVertexArrayHandleAllocator.allocate(); + mVertexArrayMap.assign(vertexArray, nullptr); + arrays[arrayIndex] = vertexArray; + } +} + +bool Context::isVertexArray(GLuint array) +{ + if (array == 0) + { + return GL_FALSE; + } + + VertexArray *vao = getVertexArray(array); + return (vao != nullptr ? GL_TRUE : GL_FALSE); +} + +void Context::endTransformFeedback() +{ + TransformFeedback *transformFeedback = mGLState.getCurrentTransformFeedback(); + transformFeedback->end(this); +} + +void Context::transformFeedbackVaryings(GLuint program, + GLsizei count, + const GLchar *const *varyings, + GLenum bufferMode) +{ + Program *programObject = getProgram(program); + ASSERT(programObject); + programObject->setTransformFeedbackVaryings(count, varyings, bufferMode); +} + +void Context::getTransformFeedbackVarying(GLuint program, + GLuint index, + GLsizei bufSize, + GLsizei *length, + GLsizei *size, + GLenum *type, + GLchar *name) +{ + Program *programObject = getProgram(program); + ASSERT(programObject); + programObject->getTransformFeedbackVarying(index, bufSize, length, size, type, name); +} + +void Context::deleteTransformFeedbacks(GLsizei n, const GLuint *ids) +{ + for (int i = 0; i < n; i++) + { + GLuint transformFeedback = ids[i]; + if (transformFeedback == 0) + { + continue; + } + + TransformFeedback *transformFeedbackObject = nullptr; + if (mTransformFeedbackMap.erase(transformFeedback, &transformFeedbackObject)) + { + if (transformFeedbackObject != nullptr) + { + detachTransformFeedback(transformFeedback); + transformFeedbackObject->release(this); + } + + mTransformFeedbackHandleAllocator.release(transformFeedback); + } + } +} + +void Context::genTransformFeedbacks(GLsizei n, GLuint *ids) +{ + for (int i = 0; i < n; i++) + { + GLuint transformFeedback = mTransformFeedbackHandleAllocator.allocate(); + mTransformFeedbackMap.assign(transformFeedback, nullptr); + ids[i] = transformFeedback; + } +} + +bool Context::isTransformFeedback(GLuint id) +{ + if (id == 0) + { + // The 3.0.4 spec [section 6.1.11] states that if ID is zero, IsTransformFeedback + // returns FALSE + return GL_FALSE; + } + + const TransformFeedback *transformFeedback = getTransformFeedback(id); + return ((transformFeedback != nullptr) ? GL_TRUE : GL_FALSE); +} + +void Context::pauseTransformFeedback() +{ + TransformFeedback *transformFeedback = mGLState.getCurrentTransformFeedback(); + transformFeedback->pause(); +} + +void Context::resumeTransformFeedback() +{ + TransformFeedback *transformFeedback = mGLState.getCurrentTransformFeedback(); + transformFeedback->resume(); +} + +void Context::getUniformuiv(GLuint program, GLint location, GLuint *params) +{ + const Program *programObject = getProgram(program); + programObject->getUniformuiv(this, location, params); +} + +GLint Context::getFragDataLocation(GLuint program, const GLchar *name) +{ + const Program *programObject = getProgram(program); + return programObject->getFragDataLocation(name); +} + +void Context::getUniformIndices(GLuint program, + GLsizei uniformCount, + const GLchar *const *uniformNames, + GLuint *uniformIndices) +{ + const Program *programObject = getProgram(program); + if (!programObject->isLinked()) + { + for (int uniformId = 0; uniformId < uniformCount; uniformId++) + { + uniformIndices[uniformId] = GL_INVALID_INDEX; + } + } + else + { + for (int uniformId = 0; uniformId < uniformCount; uniformId++) + { + uniformIndices[uniformId] = programObject->getUniformIndex(uniformNames[uniformId]); + } + } +} + +void Context::getActiveUniformsiv(GLuint program, + GLsizei uniformCount, + const GLuint *uniformIndices, + GLenum pname, + GLint *params) +{ + const Program *programObject = getProgram(program); + for (int uniformId = 0; uniformId < uniformCount; uniformId++) + { + const GLuint index = uniformIndices[uniformId]; + params[uniformId] = GetUniformResourceProperty(programObject, index, pname); + } +} + +GLuint Context::getUniformBlockIndex(GLuint program, const GLchar *uniformBlockName) +{ + const Program *programObject = getProgram(program); + return programObject->getUniformBlockIndex(uniformBlockName); +} + +void Context::getActiveUniformBlockiv(GLuint program, + GLuint uniformBlockIndex, + GLenum pname, + GLint *params) +{ + const Program *programObject = getProgram(program); + QueryActiveUniformBlockiv(programObject, uniformBlockIndex, pname, params); +} + +void Context::getActiveUniformBlockName(GLuint program, + GLuint uniformBlockIndex, + GLsizei bufSize, + GLsizei *length, + GLchar *uniformBlockName) +{ + const Program *programObject = getProgram(program); + programObject->getActiveUniformBlockName(uniformBlockIndex, bufSize, length, uniformBlockName); +} + +void Context::uniformBlockBinding(GLuint program, + GLuint uniformBlockIndex, + GLuint uniformBlockBinding) +{ + Program *programObject = getProgram(program); + programObject->bindUniformBlock(uniformBlockIndex, uniformBlockBinding); +} + +GLsync Context::fenceSync(GLenum condition, GLbitfield flags) +{ + GLuint handle = mState.mSyncs->createSync(mImplementation.get()); + GLsync syncHandle = reinterpret_cast(static_cast(handle)); + + Sync *syncObject = getSync(syncHandle); + Error error = syncObject->set(condition, flags); + if (error.isError()) + { + deleteSync(syncHandle); + handleError(error); + return nullptr; + } + + return syncHandle; +} + +GLboolean Context::isSync(GLsync sync) +{ + return (getSync(sync) != nullptr); +} + +GLenum Context::clientWaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout) +{ + Sync *syncObject = getSync(sync); + + GLenum result = GL_WAIT_FAILED; + handleError(syncObject->clientWait(flags, timeout, &result)); + return result; +} + +void Context::waitSync(GLsync sync, GLbitfield flags, GLuint64 timeout) +{ + Sync *syncObject = getSync(sync); + handleError(syncObject->serverWait(flags, timeout)); +} + +void Context::getInteger64v(GLenum pname, GLint64 *params) +{ + GLenum nativeType = GL_NONE; + unsigned int numParams = 0; + getQueryParameterInfo(pname, &nativeType, &numParams); + + if (nativeType == GL_INT_64_ANGLEX) + { + getInteger64vImpl(pname, params); + } + else + { + CastStateValues(this, nativeType, pname, numParams, params); + } +} + +void Context::getBufferParameteri64v(BufferBinding target, GLenum pname, GLint64 *params) +{ + Buffer *buffer = mGLState.getTargetBuffer(target); + QueryBufferParameteri64v(buffer, pname, params); +} + +void Context::genSamplers(GLsizei count, GLuint *samplers) +{ + for (int i = 0; i < count; i++) + { + samplers[i] = mState.mSamplers->createSampler(); + } +} + +void Context::deleteSamplers(GLsizei count, const GLuint *samplers) +{ + for (int i = 0; i < count; i++) + { + GLuint sampler = samplers[i]; + + if (mState.mSamplers->getSampler(sampler)) + { + detachSampler(sampler); + } + + mState.mSamplers->deleteObject(this, sampler); + } +} + +void Context::getInternalformativ(GLenum target, + GLenum internalformat, + GLenum pname, + GLsizei bufSize, + GLint *params) +{ + const TextureCaps &formatCaps = mTextureCaps.get(internalformat); + QueryInternalFormativ(formatCaps, pname, bufSize, params); +} + +void Context::programUniform1i(GLuint program, GLint location, GLint v0) +{ + programUniform1iv(program, location, 1, &v0); +} + +void Context::programUniform2i(GLuint program, GLint location, GLint v0, GLint v1) +{ + GLint xy[2] = {v0, v1}; + programUniform2iv(program, location, 1, xy); +} + +void Context::programUniform3i(GLuint program, GLint location, GLint v0, GLint v1, GLint v2) +{ + GLint xyz[3] = {v0, v1, v2}; + programUniform3iv(program, location, 1, xyz); +} + +void Context::programUniform4i(GLuint program, + GLint location, + GLint v0, + GLint v1, + GLint v2, + GLint v3) +{ + GLint xyzw[4] = {v0, v1, v2, v3}; + programUniform4iv(program, location, 1, xyzw); +} + +void Context::programUniform1ui(GLuint program, GLint location, GLuint v0) +{ + programUniform1uiv(program, location, 1, &v0); +} + +void Context::programUniform2ui(GLuint program, GLint location, GLuint v0, GLuint v1) +{ + GLuint xy[2] = {v0, v1}; + programUniform2uiv(program, location, 1, xy); +} + +void Context::programUniform3ui(GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2) +{ + GLuint xyz[3] = {v0, v1, v2}; + programUniform3uiv(program, location, 1, xyz); +} + +void Context::programUniform4ui(GLuint program, + GLint location, + GLuint v0, + GLuint v1, + GLuint v2, + GLuint v3) +{ + GLuint xyzw[4] = {v0, v1, v2, v3}; + programUniform4uiv(program, location, 1, xyzw); +} + +void Context::programUniform1f(GLuint program, GLint location, GLfloat v0) +{ + programUniform1fv(program, location, 1, &v0); +} + +void Context::programUniform2f(GLuint program, GLint location, GLfloat v0, GLfloat v1) +{ + GLfloat xy[2] = {v0, v1}; + programUniform2fv(program, location, 1, xy); +} + +void Context::programUniform3f(GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2) +{ + GLfloat xyz[3] = {v0, v1, v2}; + programUniform3fv(program, location, 1, xyz); +} + +void Context::programUniform4f(GLuint program, + GLint location, + GLfloat v0, + GLfloat v1, + GLfloat v2, + GLfloat v3) +{ + GLfloat xyzw[4] = {v0, v1, v2, v3}; + programUniform4fv(program, location, 1, xyzw); +} + +void Context::programUniform1iv(GLuint program, GLint location, GLsizei count, const GLint *value) +{ + Program *programObject = getProgram(program); + ASSERT(programObject); + if (programObject->setUniform1iv(location, count, value) == + Program::SetUniformResult::SamplerChanged) + { + mGLState.setObjectDirty(GL_PROGRAM); + } +} + +void Context::programUniform2iv(GLuint program, GLint location, GLsizei count, const GLint *value) +{ + Program *programObject = getProgram(program); + ASSERT(programObject); + programObject->setUniform2iv(location, count, value); +} + +void Context::programUniform3iv(GLuint program, GLint location, GLsizei count, const GLint *value) +{ + Program *programObject = getProgram(program); + ASSERT(programObject); + programObject->setUniform3iv(location, count, value); +} + +void Context::programUniform4iv(GLuint program, GLint location, GLsizei count, const GLint *value) +{ + Program *programObject = getProgram(program); + ASSERT(programObject); + programObject->setUniform4iv(location, count, value); +} + +void Context::programUniform1uiv(GLuint program, GLint location, GLsizei count, const GLuint *value) +{ + Program *programObject = getProgram(program); + ASSERT(programObject); + programObject->setUniform1uiv(location, count, value); +} + +void Context::programUniform2uiv(GLuint program, GLint location, GLsizei count, const GLuint *value) +{ + Program *programObject = getProgram(program); + ASSERT(programObject); + programObject->setUniform2uiv(location, count, value); +} + +void Context::programUniform3uiv(GLuint program, GLint location, GLsizei count, const GLuint *value) +{ + Program *programObject = getProgram(program); + ASSERT(programObject); + programObject->setUniform3uiv(location, count, value); +} + +void Context::programUniform4uiv(GLuint program, GLint location, GLsizei count, const GLuint *value) +{ + Program *programObject = getProgram(program); + ASSERT(programObject); + programObject->setUniform4uiv(location, count, value); +} + +void Context::programUniform1fv(GLuint program, GLint location, GLsizei count, const GLfloat *value) +{ + Program *programObject = getProgram(program); + ASSERT(programObject); + programObject->setUniform1fv(location, count, value); +} + +void Context::programUniform2fv(GLuint program, GLint location, GLsizei count, const GLfloat *value) +{ + Program *programObject = getProgram(program); + ASSERT(programObject); + programObject->setUniform2fv(location, count, value); +} + +void Context::programUniform3fv(GLuint program, GLint location, GLsizei count, const GLfloat *value) +{ + Program *programObject = getProgram(program); + ASSERT(programObject); + programObject->setUniform3fv(location, count, value); +} + +void Context::programUniform4fv(GLuint program, GLint location, GLsizei count, const GLfloat *value) +{ + Program *programObject = getProgram(program); + ASSERT(programObject); + programObject->setUniform4fv(location, count, value); +} + +void Context::programUniformMatrix2fv(GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + Program *programObject = getProgram(program); + ASSERT(programObject); + programObject->setUniformMatrix2fv(location, count, transpose, value); +} + +void Context::programUniformMatrix3fv(GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + Program *programObject = getProgram(program); + ASSERT(programObject); + programObject->setUniformMatrix3fv(location, count, transpose, value); +} + +void Context::programUniformMatrix4fv(GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + Program *programObject = getProgram(program); + ASSERT(programObject); + programObject->setUniformMatrix4fv(location, count, transpose, value); +} + +void Context::programUniformMatrix2x3fv(GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + Program *programObject = getProgram(program); + ASSERT(programObject); + programObject->setUniformMatrix2x3fv(location, count, transpose, value); +} + +void Context::programUniformMatrix3x2fv(GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + Program *programObject = getProgram(program); + ASSERT(programObject); + programObject->setUniformMatrix3x2fv(location, count, transpose, value); +} + +void Context::programUniformMatrix2x4fv(GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + Program *programObject = getProgram(program); + ASSERT(programObject); + programObject->setUniformMatrix2x4fv(location, count, transpose, value); +} + +void Context::programUniformMatrix4x2fv(GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + Program *programObject = getProgram(program); + ASSERT(programObject); + programObject->setUniformMatrix4x2fv(location, count, transpose, value); +} + +void Context::programUniformMatrix3x4fv(GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + Program *programObject = getProgram(program); + ASSERT(programObject); + programObject->setUniformMatrix3x4fv(location, count, transpose, value); +} + +void Context::programUniformMatrix4x3fv(GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + Program *programObject = getProgram(program); + ASSERT(programObject); + programObject->setUniformMatrix4x3fv(location, count, transpose, value); +} + +void Context::onTextureChange(const Texture *texture) +{ + // Conservatively assume all textures are dirty. + // TODO(jmadill): More fine-grained update. + mGLState.setObjectDirty(GL_TEXTURE); +} + +void Context::genProgramPipelines(GLsizei count, GLuint *pipelines) +{ + for (int i = 0; i < count; i++) + { + pipelines[i] = createProgramPipeline(); + } +} + +void Context::deleteProgramPipelines(GLsizei count, const GLuint *pipelines) +{ + for (int i = 0; i < count; i++) + { + if (pipelines[i] != 0) + { + deleteProgramPipeline(pipelines[i]); + } + } +} + +GLboolean Context::isProgramPipeline(GLuint pipeline) +{ + if (pipeline == 0) + { + return GL_FALSE; + } + + return (getProgramPipeline(pipeline) ? GL_TRUE : GL_FALSE); } } // namespace gl diff --git a/src/3rdparty/angle/src/libANGLE/Context.h b/src/3rdparty/angle/src/libANGLE/Context.h index 6b82eb7cb9..38c4e7b4d1 100644 --- a/src/3rdparty/angle/src/libANGLE/Context.h +++ b/src/3rdparty/angle/src/libANGLE/Context.h @@ -10,25 +10,28 @@ #ifndef LIBANGLE_CONTEXT_H_ #define LIBANGLE_CONTEXT_H_ +#include +#include + +#include "angle_gl.h" +#include "common/MemoryBuffer.h" #include "common/angleutils.h" -#include "libANGLE/RefCountObject.h" #include "libANGLE/Caps.h" #include "libANGLE/Constants.h" -#include "libANGLE/Data.h" +#include "libANGLE/ContextState.h" #include "libANGLE/Error.h" #include "libANGLE/HandleAllocator.h" +#include "libANGLE/PackedGLEnums.h" +#include "libANGLE/RefCountObject.h" +#include "libANGLE/ResourceMap.h" #include "libANGLE/VertexAttribute.h" +#include "libANGLE/Workarounds.h" #include "libANGLE/angletypes.h" -#include "angle_gl.h" - -#include -#include -#include - namespace rx { -class Renderer; +class ContextImpl; +class EGLImplFactory; } namespace egl @@ -36,41 +39,44 @@ namespace egl class AttributeMap; class Surface; struct Config; +class Thread; } namespace gl { +class Buffer; class Compiler; -class Shader; -class Program; -class Texture; -class Framebuffer; -class Renderbuffer; class FenceNV; -class FenceSync; +class Sync; +class Framebuffer; +class MemoryProgramCache; +class Program; class Query; -class ResourceManager; -class Buffer; -struct VertexAttribute; -class VertexArray; +class Renderbuffer; class Sampler; +class Shader; +class Texture; class TransformFeedback; +class VertexArray; +struct VertexAttribute; +class ProgramPipeline; class Context final : public ValidationContext { public: - Context(const egl::Config *config, + Context(rx::EGLImplFactory *implFactory, + const egl::Config *config, const Context *shareContext, - rx::Renderer *renderer, - const egl::AttributeMap &attribs); - - virtual ~Context(); + TextureManager *shareTextures, + MemoryProgramCache *memoryProgramCache, + const egl::AttributeMap &attribs, + const egl::DisplayExtensions &displayExtensions); - void makeCurrent(egl::Surface *surface); - void releaseSurface(); + egl::Error onDestroy(const egl::Display *display); + ~Context() override; - virtual void markContextLost(); - bool isContextLost(); + egl::Error makeCurrent(egl::Display *display, egl::Surface *surface); + egl::Error releaseSurface(const egl::Display *display); // These create and destroy methods are merely pass-throughs to // ResourceManager, which owns these object types @@ -79,18 +85,30 @@ class Context final : public ValidationContext GLuint createProgram(); GLuint createTexture(); GLuint createRenderbuffer(); - GLuint createSampler(); - GLuint createTransformFeedback(); - GLsync createFenceSync(); + GLuint createPaths(GLsizei range); + GLuint createProgramPipeline(); + GLuint createShaderProgramv(GLenum type, GLsizei count, const GLchar *const *strings); 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); + void deletePaths(GLuint first, GLsizei range); + void deleteProgramPipeline(GLuint pipeline); + + // CHROMIUM_path_rendering + bool hasPathData(GLuint path) const; + bool hasPath(GLuint path) const; + void setPathCommands(GLuint path, + GLsizei numCommands, + const GLubyte *commands, + GLsizei numCoords, + GLenum coordType, + const void *coords); + void setPathParameterf(GLuint path, GLenum pname, GLfloat value); + void getPathParameterfv(GLuint path, GLenum pname, GLfloat *value) const; + void setPathStencilFunc(GLenum func, GLint ref, GLuint mask); // Framebuffers are owned by the Context, so these methods do not pass through GLuint createFramebuffer(); @@ -100,54 +118,90 @@ class Context final : public ValidationContext 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 framebufferHandle); void bindDrawFramebuffer(GLuint framebufferHandle); - 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 bindVertexArray(GLuint vertexArrayHandle); + void bindVertexBuffer(GLuint bindingIndex, + GLuint bufferHandle, + GLintptr offset, + GLsizei stride); + void bindSampler(GLuint textureUnit, GLuint samplerHandle); + void bindImageTexture(GLuint unit, + GLuint texture, + GLint level, + GLboolean layered, + GLint layer, + GLenum access, + GLenum format); void useProgram(GLuint program); - void bindTransformFeedback(GLuint transformFeedback); + void useProgramStages(GLuint pipeline, GLbitfield stages, GLuint program); + void bindTransformFeedback(GLenum target, GLuint transformFeedbackHandle); + void bindProgramPipeline(GLuint pipelineHandle); - Error beginQuery(GLenum target, GLuint query); - Error endQuery(GLenum target); - Error queryCounter(GLuint id, GLenum target); + void beginQuery(GLenum target, GLuint query); + void endQuery(GLenum target); + void queryCounter(GLuint id, GLenum target); void getQueryiv(GLenum target, GLenum pname, GLint *params); - Error getQueryObjectiv(GLuint id, GLenum pname, GLint *params); - Error getQueryObjectuiv(GLuint id, GLenum pname, GLuint *params); - Error getQueryObjecti64v(GLuint id, GLenum pname, GLint64 *params); - Error getQueryObjectui64v(GLuint id, GLenum pname, GLuint64 *params); - - void setVertexAttribDivisor(GLuint index, GLuint divisor); + void getQueryObjectiv(GLuint id, GLenum pname, GLint *params); + void getQueryObjectuiv(GLuint id, GLenum pname, GLuint *params); + void getQueryObjecti64v(GLuint id, GLenum pname, GLint64 *params); + void getQueryObjectui64v(GLuint id, GLenum pname, GLuint64 *params); + + void vertexAttribDivisor(GLuint index, GLuint divisor); + void vertexBindingDivisor(GLuint bindingIndex, GLuint divisor); + + void getBufferParameteriv(BufferBinding target, GLenum pname, GLint *params); + void getFramebufferAttachmentParameteriv(GLenum target, + GLenum attachment, + GLenum pname, + GLint *params); + void getRenderbufferParameteriv(GLenum target, GLenum pname, GLint *params); + + void getTexParameterfv(GLenum target, GLenum pname, GLfloat *params); + void getTexParameteriv(GLenum target, GLenum pname, GLint *params); + void getTexLevelParameteriv(GLenum target, GLint level, GLenum pname, GLint *params); + void getTexLevelParameterfv(GLenum target, GLint level, GLenum pname, GLfloat *params); + void texParameterf(GLenum target, GLenum pname, GLfloat param); + void texParameterfv(GLenum target, GLenum pname, const GLfloat *params); + void texParameteri(GLenum target, GLenum pname, GLint param); + void texParameteriv(GLenum target, GLenum pname, const GLint *params); void samplerParameteri(GLuint sampler, GLenum pname, GLint param); + void samplerParameteriv(GLuint sampler, GLenum pname, const GLint *param); void samplerParameterf(GLuint sampler, GLenum pname, GLfloat param); - GLint getSamplerParameteri(GLuint sampler, GLenum pname); - GLfloat getSamplerParameterf(GLuint sampler, GLenum pname); + void samplerParameterfv(GLuint sampler, GLenum pname, const GLfloat *param); + + void getSamplerParameteriv(GLuint sampler, GLenum pname, GLint *params); + void getSamplerParameterfv(GLuint sampler, GLenum pname, GLfloat *params); + + void programParameteri(GLuint program, GLenum pname, GLint value); + + GLuint getProgramResourceIndex(GLuint program, GLenum programInterface, const GLchar *name); + void getProgramResourceName(GLuint program, + GLenum programInterface, + GLuint index, + GLsizei bufSize, + GLsizei *length, + GLchar *name); + GLint getProgramResourceLocation(GLuint program, GLenum programInterface, const GLchar *name); + void getProgramResourceiv(GLuint program, + GLenum programInterface, + GLuint index, + GLsizei propCount, + const GLenum *props, + GLsizei bufSize, + GLsizei *length, + GLint *params); + + void getProgramInterfaceiv(GLuint program, + GLenum programInterface, + GLenum pname, + GLint *params); Buffer *getBuffer(GLuint handle) const; FenceNV *getFenceNV(GLuint handle); - FenceSync *getFenceSync(GLsync handle) const; - Shader *getShader(GLuint handle) const; - Program *getProgram(GLuint handle) const; + Sync *getSync(GLsync handle) const; Texture *getTexture(GLuint handle) const; Framebuffer *getFramebuffer(GLuint handle) const; Renderbuffer *getRenderbuffer(GLuint handle) const; @@ -156,8 +210,16 @@ class Context final : public ValidationContext Query *getQuery(GLuint handle, bool create, GLenum type); Query *getQuery(GLuint handle) const; TransformFeedback *getTransformFeedback(GLuint handle) const; - LabeledObject *getLabeledObject(GLenum identifier, GLuint name) const; - LabeledObject *getLabeledObjectFromPtr(const void *ptr) const; + ProgramPipeline *getProgramPipeline(GLuint handle) const; + + void objectLabel(GLenum identifier, GLuint name, GLsizei length, const GLchar *label); + void objectPtrLabel(const void *ptr, GLsizei length, const GLchar *label); + void getObjectLabel(GLenum identifier, + GLuint name, + GLsizei bufSize, + GLsizei *length, + GLchar *label) const; + void getObjectPtrLabel(const void *ptr, GLsizei bufSize, GLsizei *length, GLchar *label) const; Texture *getTargetTexture(GLenum target) const; Texture *getSamplerTexture(unsigned int sampler, GLenum type) const; @@ -170,16 +232,108 @@ class Context final : public ValidationContext bool isTransformFeedbackGenerated(GLuint vertexArray); void getBooleanv(GLenum pname, GLboolean *params); + void getBooleanvImpl(GLenum pname, GLboolean *params); void getFloatv(GLenum pname, GLfloat *params); + void getFloatvImpl(GLenum pname, GLfloat *params); void getIntegerv(GLenum pname, GLint *params); - void getInteger64v(GLenum pname, GLint64 *params); + void getIntegervImpl(GLenum pname, GLint *params); + void getInteger64vImpl(GLenum pname, GLint64 *params); void getPointerv(GLenum pname, void **params) const; - - 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); + void getBooleani_v(GLenum target, GLuint index, GLboolean *data); + void getIntegeri_v(GLenum target, GLuint index, GLint *data); + void getInteger64i_v(GLenum target, GLuint index, GLint64 *data); + + void activeShaderProgram(GLuint pipeline, GLuint program); + void activeTexture(GLenum texture); + void blendColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); + void blendEquation(GLenum mode); + void blendEquationSeparate(GLenum modeRGB, GLenum modeAlpha); + void blendFunc(GLenum sfactor, GLenum dfactor); + void blendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); + void clearColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); + void clearDepthf(GLfloat depth); + void clearStencil(GLint s); + void colorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); + void cullFace(CullFaceMode mode); + void depthFunc(GLenum func); + void depthMask(GLboolean flag); + void depthRangef(GLfloat zNear, GLfloat zFar); + void disable(GLenum cap); + void disableVertexAttribArray(GLuint index); + void enable(GLenum cap); + void enableVertexAttribArray(GLuint index); + void frontFace(GLenum mode); + void hint(GLenum target, GLenum mode); + void lineWidth(GLfloat width); + void pixelStorei(GLenum pname, GLint param); + void polygonOffset(GLfloat factor, GLfloat units); + void sampleCoverage(GLfloat value, GLboolean invert); + void sampleMaski(GLuint maskNumber, GLbitfield mask); + void scissor(GLint x, GLint y, GLsizei width, GLsizei height); + void stencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask); + void stencilMaskSeparate(GLenum face, GLuint mask); + void stencilOpSeparate(GLenum face, GLenum fail, GLenum zfail, GLenum zpass); + void vertexAttrib1f(GLuint index, GLfloat x); + void vertexAttrib1fv(GLuint index, const GLfloat *values); + void vertexAttrib2f(GLuint index, GLfloat x, GLfloat y); + void vertexAttrib2fv(GLuint index, const GLfloat *values); + void vertexAttrib3f(GLuint index, GLfloat x, GLfloat y, GLfloat z); + void vertexAttrib3fv(GLuint index, const GLfloat *values); + void vertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); + void vertexAttrib4fv(GLuint index, const GLfloat *values); + void vertexAttribFormat(GLuint attribIndex, + GLint size, + GLenum type, + GLboolean normalized, + GLuint relativeOffset); + void vertexAttribIFormat(GLuint attribIndex, GLint size, GLenum type, GLuint relativeOffset); + void vertexAttribBinding(GLuint attribIndex, GLuint bindingIndex); + void vertexAttribPointer(GLuint index, + GLint size, + GLenum type, + GLboolean normalized, + GLsizei stride, + const void *ptr); + void vertexAttribIPointer(GLuint index, + GLint size, + GLenum type, + GLsizei stride, + const void *pointer); + void viewport(GLint x, GLint y, GLsizei width, GLsizei height); + + void vertexAttribI4i(GLuint index, GLint x, GLint y, GLint z, GLint w); + void vertexAttribI4ui(GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); + void vertexAttribI4iv(GLuint index, const GLint *v); + void vertexAttribI4uiv(GLuint index, const GLuint *v); + void getVertexAttribiv(GLuint index, GLenum pname, GLint *params); + void getVertexAttribfv(GLuint index, GLenum pname, GLfloat *params); + void getVertexAttribIiv(GLuint index, GLenum pname, GLint *params); + void getVertexAttribIuiv(GLuint index, GLenum pname, GLuint *params); + void getVertexAttribPointerv(GLuint index, GLenum pname, void **pointer); + + void debugMessageControl(GLenum source, + GLenum type, + GLenum severity, + GLsizei count, + const GLuint *ids, + GLboolean enabled); + void debugMessageInsert(GLenum source, + GLenum type, + GLuint id, + GLenum severity, + GLsizei length, + const GLchar *buf); + void debugMessageCallback(GLDEBUGPROCKHR callback, const void *userParam); + GLuint getDebugMessageLog(GLuint count, + GLsizei bufSize, + GLenum *sources, + GLenum *types, + GLuint *ids, + GLenum *severities, + GLsizei *lengths, + GLchar *messageLog); + void pushDebugGroup(GLenum source, GLuint id, GLsizei length, const GLchar *message); + void popDebugGroup(); void clear(GLbitfield mask); void clearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat *values); @@ -187,27 +341,23 @@ class Context final : public ValidationContext void clearBufferiv(GLenum buffer, GLint drawbuffer, const GLint *values); void clearBufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil); - Error drawArrays(GLenum mode, GLint first, GLsizei count); - Error drawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei instanceCount); - - Error drawElements(GLenum mode, - GLsizei count, - GLenum type, - const GLvoid *indices, - const IndexRange &indexRange); - Error drawElementsInstanced(GLenum mode, - GLsizei count, - GLenum type, - const GLvoid *indices, - GLsizei instances, - const IndexRange &indexRange); - Error drawRangeElements(GLenum mode, - GLuint start, - GLuint end, - GLsizei count, - GLenum type, - const GLvoid *indices, - const IndexRange &indexRange); + void drawArrays(GLenum mode, GLint first, GLsizei count); + void drawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei instanceCount); + + void drawElements(GLenum mode, GLsizei count, GLenum type, const void *indices); + void drawElementsInstanced(GLenum mode, + GLsizei count, + GLenum type, + const void *indices, + GLsizei instances); + void drawRangeElements(GLenum mode, + GLuint start, + GLuint end, + GLsizei count, + GLenum type, + const void *indices); + void drawArraysIndirect(GLenum mode, const void *indirect); + void drawElementsIndirect(GLenum mode, GLenum type, const void *indirect); void blitFramebuffer(GLint srcX0, GLint srcY0, @@ -226,7 +376,7 @@ class Context final : public ValidationContext GLsizei height, GLenum format, GLenum type, - GLvoid *pixels); + void *pixels); void copyTexImage2D(GLenum target, GLint level, @@ -272,6 +422,18 @@ class Context final : public ValidationContext GLuint texture, GLint level, GLint layer); + void framebufferTextureMultiviewLayeredANGLE(GLenum target, + GLenum attachment, + GLuint texture, + GLint level, + GLint baseViewIndex, + GLsizei numViews); + void framebufferTextureMultiviewSideBySideANGLE(GLenum target, + GLenum attachment, + GLuint texture, + GLint level, + GLsizei numViews, + const GLint *viewportOffsets); void drawBuffers(GLsizei n, const GLenum *bufs); void readBuffer(GLenum mode); @@ -286,40 +448,596 @@ class Context final : public ValidationContext GLsizei width, GLsizei height); - Error flush(); - Error finish(); + void texImage2D(GLenum target, + GLint level, + GLint internalformat, + GLsizei width, + GLsizei height, + GLint border, + GLenum format, + GLenum type, + const void *pixels); + void texImage3D(GLenum target, + GLint level, + GLint internalformat, + GLsizei width, + GLsizei height, + GLsizei depth, + GLint border, + GLenum format, + GLenum type, + const void *pixels); + void texSubImage2D(GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLsizei width, + GLsizei height, + GLenum format, + GLenum type, + const void *pixels); + void texSubImage3D(GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLint zoffset, + GLsizei width, + GLsizei height, + GLsizei depth, + GLenum format, + GLenum type, + const void *pixels); + void compressedTexImage2D(GLenum target, + GLint level, + GLenum internalformat, + GLsizei width, + GLsizei height, + GLint border, + GLsizei imageSize, + const void *data); + void compressedTexImage3D(GLenum target, + GLint level, + GLenum internalformat, + GLsizei width, + GLsizei height, + GLsizei depth, + GLint border, + GLsizei imageSize, + const void *data); + void compressedTexSubImage2D(GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLsizei width, + GLsizei height, + GLenum format, + GLsizei imageSize, + const void *data); + void compressedTexSubImage3D(GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLint zoffset, + GLsizei width, + GLsizei height, + GLsizei depth, + GLenum format, + GLsizei imageSize, + const void *data); + void copyTextureCHROMIUM(GLuint sourceId, + GLint sourceLevel, + GLenum destTarget, + GLuint destId, + GLint destLevel, + GLint internalFormat, + GLenum destType, + GLboolean unpackFlipY, + GLboolean unpackPremultiplyAlpha, + GLboolean unpackUnmultiplyAlpha); + void copySubTextureCHROMIUM(GLuint sourceId, + GLint sourceLevel, + GLenum destTarget, + GLuint destId, + GLint destLevel, + GLint xoffset, + GLint yoffset, + GLint x, + GLint y, + GLsizei width, + GLsizei height, + GLboolean unpackFlipY, + GLboolean unpackPremultiplyAlpha, + GLboolean unpackUnmultiplyAlpha); + void compressedCopyTextureCHROMIUM(GLuint sourceId, GLuint destId); + + void generateMipmap(GLenum target); + + void flush(); + void finish(); + + void getBufferPointerv(BufferBinding target, GLenum pname, void **params); + void *mapBuffer(BufferBinding target, GLenum access); + GLboolean unmapBuffer(BufferBinding target); + void *mapBufferRange(BufferBinding target, + GLintptr offset, + GLsizeiptr length, + GLbitfield access); + void flushMappedBufferRange(BufferBinding target, GLintptr offset, GLsizeiptr length); + + void beginTransformFeedback(GLenum primitiveMode); + + bool hasActiveTransformFeedback(GLuint program) const; void insertEventMarker(GLsizei length, const char *marker); void pushGroupMarker(GLsizei length, const char *marker); void popGroupMarker(); - void recordError(const Error &error) override; + void bindUniformLocation(GLuint program, GLint location, const GLchar *name); + void renderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height); + void renderbufferStorageMultisample(GLenum target, + GLsizei samples, + GLenum internalformat, + GLsizei width, + GLsizei height); + + void getSynciv(GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values); + + // CHROMIUM_framebuffer_mixed_samples + void setCoverageModulation(GLenum components); + + // CHROMIUM_path_rendering + void loadPathRenderingMatrix(GLenum matrixMode, const GLfloat *matrix); + void loadPathRenderingIdentityMatrix(GLenum matrixMode); + void stencilFillPath(GLuint path, GLenum fillMode, GLuint mask); + void stencilStrokePath(GLuint path, GLint reference, GLuint mask); + void coverFillPath(GLuint path, GLenum coverMode); + void coverStrokePath(GLuint path, GLenum coverMode); + void stencilThenCoverFillPath(GLuint path, GLenum fillMode, GLuint mask, GLenum coverMode); + void stencilThenCoverStrokePath(GLuint path, GLint reference, GLuint mask, GLenum coverMode); + void coverFillPathInstanced(GLsizei numPaths, + GLenum pathNameType, + const void *paths, + GLuint pathBase, + GLenum coverMode, + GLenum transformType, + const GLfloat *transformValues); + void coverStrokePathInstanced(GLsizei numPaths, + GLenum pathNameType, + const void *paths, + GLuint pathBase, + GLenum coverMode, + GLenum transformType, + const GLfloat *transformValues); + void stencilFillPathInstanced(GLsizei numPaths, + GLenum pathNameType, + const void *paths, + GLuint pathBAse, + GLenum fillMode, + GLuint mask, + GLenum transformType, + const GLfloat *transformValues); + void stencilStrokePathInstanced(GLsizei numPaths, + GLenum pathNameType, + const void *paths, + GLuint pathBase, + GLint reference, + GLuint mask, + GLenum transformType, + const GLfloat *transformValues); + void stencilThenCoverFillPathInstanced(GLsizei numPaths, + GLenum pathNameType, + const void *paths, + GLuint pathBase, + GLenum fillMode, + GLuint mask, + GLenum coverMode, + GLenum transformType, + const GLfloat *transformValues); + void stencilThenCoverStrokePathInstanced(GLsizei numPaths, + GLenum pathNameType, + const void *paths, + GLuint pathBase, + GLint reference, + GLuint mask, + GLenum coverMode, + GLenum transformType, + const GLfloat *transformValues); + void bindFragmentInputLocation(GLuint program, GLint location, const GLchar *name); + void programPathFragmentInputGen(GLuint program, + GLint location, + GLenum genMode, + GLint components, + const GLfloat *coeffs); + + void bufferData(BufferBinding target, GLsizeiptr size, const void *data, BufferUsage usage); + void bufferSubData(BufferBinding target, GLintptr offset, GLsizeiptr size, const void *data); + void attachShader(GLuint program, GLuint shader); + void bindAttribLocation(GLuint program, GLuint index, const GLchar *name); + void bindBuffer(BufferBinding target, GLuint buffer); + void bindBufferBase(BufferBinding target, GLuint index, GLuint buffer); + void bindBufferRange(BufferBinding target, + GLuint index, + GLuint buffer, + GLintptr offset, + GLsizeiptr size); + void bindFramebuffer(GLenum target, GLuint framebuffer); + void bindRenderbuffer(GLenum target, GLuint renderbuffer); + + void texStorage2DMultisample(GLenum target, + GLsizei samples, + GLenum internalformat, + GLsizei width, + GLsizei height, + GLboolean fixedsamplelocations); + + void getMultisamplefv(GLenum pname, GLuint index, GLfloat *val); + + void copyBufferSubData(BufferBinding readTarget, + BufferBinding writeTarget, + GLintptr readOffset, + GLintptr writeOffset, + GLsizeiptr size); + + GLenum checkFramebufferStatus(GLenum target); + void compileShader(GLuint shader); + void deleteBuffers(GLsizei n, const GLuint *buffers); + void deleteFramebuffers(GLsizei n, const GLuint *framebuffers); + void deleteRenderbuffers(GLsizei n, const GLuint *renderbuffers); + void deleteTextures(GLsizei n, const GLuint *textures); + void detachShader(GLuint program, GLuint shader); + void genBuffers(GLsizei n, GLuint *buffers); + void genFramebuffers(GLsizei n, GLuint *framebuffers); + void genRenderbuffers(GLsizei n, GLuint *renderbuffers); + void genTextures(GLsizei n, GLuint *textures); + void getActiveAttrib(GLuint program, + GLuint index, + GLsizei bufsize, + GLsizei *length, + GLint *size, + GLenum *type, + GLchar *name); + void getActiveUniform(GLuint program, + GLuint index, + GLsizei bufsize, + GLsizei *length, + GLint *size, + GLenum *type, + GLchar *name); + void getAttachedShaders(GLuint program, GLsizei maxcount, GLsizei *count, GLuint *shaders); + GLint getAttribLocation(GLuint program, const GLchar *name); + void getProgramiv(GLuint program, GLenum pname, GLint *params); + void getProgramPipelineiv(GLuint pipeline, GLenum pname, GLint *params); + void getProgramInfoLog(GLuint program, GLsizei bufsize, GLsizei *length, GLchar *infolog); + void getProgramPipelineInfoLog(GLuint pipeline, + GLsizei bufSize, + GLsizei *length, + GLchar *infoLog); + void getShaderiv(GLuint shader, GLenum pname, GLint *params); + void getShaderInfoLog(GLuint shader, GLsizei bufsize, GLsizei *length, GLchar *infolog); + void getShaderPrecisionFormat(GLenum shadertype, + GLenum precisiontype, + GLint *range, + GLint *precision); + void getShaderSource(GLuint shader, GLsizei bufsize, GLsizei *length, GLchar *source); + void getUniformfv(GLuint program, GLint location, GLfloat *params); + void getUniformiv(GLuint program, GLint location, GLint *params); + GLint getUniformLocation(GLuint program, const GLchar *name); + GLboolean isBuffer(GLuint buffer); + GLboolean isEnabled(GLenum cap); + GLboolean isFramebuffer(GLuint framebuffer); + GLboolean isProgram(GLuint program); + GLboolean isRenderbuffer(GLuint renderbuffer); + GLboolean isShader(GLuint shader); + GLboolean isTexture(GLuint texture); + void linkProgram(GLuint program); + void releaseShaderCompiler(); + void shaderBinary(GLsizei n, + const GLuint *shaders, + GLenum binaryformat, + const void *binary, + GLsizei length); + void shaderSource(GLuint shader, + GLsizei count, + const GLchar *const *string, + const GLint *length); + void stencilFunc(GLenum func, GLint ref, GLuint mask); + void stencilMask(GLuint mask); + void stencilOp(GLenum fail, GLenum zfail, GLenum zpass); + void uniform1f(GLint location, GLfloat x); + void uniform1fv(GLint location, GLsizei count, const GLfloat *v); + void uniform1i(GLint location, GLint x); + void uniform1iv(GLint location, GLsizei count, const GLint *v); + void uniform2f(GLint location, GLfloat x, GLfloat y); + void uniform2fv(GLint location, GLsizei count, const GLfloat *v); + void uniform2i(GLint location, GLint x, GLint y); + void uniform2iv(GLint location, GLsizei count, const GLint *v); + void uniform3f(GLint location, GLfloat x, GLfloat y, GLfloat z); + void uniform3fv(GLint location, GLsizei count, const GLfloat *v); + void uniform3i(GLint location, GLint x, GLint y, GLint z); + void uniform3iv(GLint location, GLsizei count, const GLint *v); + void uniform4f(GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w); + void uniform4fv(GLint location, GLsizei count, const GLfloat *v); + void uniform4i(GLint location, GLint x, GLint y, GLint z, GLint w); + void uniform4iv(GLint location, GLsizei count, const GLint *v); + void uniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); + void uniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); + void uniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); + void validateProgram(GLuint program); + void validateProgramPipeline(GLuint pipeline); + + void genQueries(GLsizei n, GLuint *ids); + void deleteQueries(GLsizei n, const GLuint *ids); + GLboolean isQuery(GLuint id); + + void uniform1ui(GLint location, GLuint v0); + void uniform2ui(GLint location, GLuint v0, GLuint v1); + void uniform3ui(GLint location, GLuint v0, GLuint v1, GLuint v2); + void uniform4ui(GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); + void uniform1uiv(GLint location, GLsizei count, const GLuint *value); + void uniform2uiv(GLint location, GLsizei count, const GLuint *value); + void uniform3uiv(GLint location, GLsizei count, const GLuint *value); + void uniform4uiv(GLint location, GLsizei count, const GLuint *value); + + void uniformMatrix2x3fv(GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value); + void uniformMatrix3x2fv(GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value); + void uniformMatrix2x4fv(GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value); + void uniformMatrix4x2fv(GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value); + void uniformMatrix3x4fv(GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value); + void uniformMatrix4x3fv(GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value); + + void deleteVertexArrays(GLsizei n, const GLuint *arrays); + void genVertexArrays(GLsizei n, GLuint *arrays); + bool isVertexArray(GLuint array); + + void endTransformFeedback(); + void transformFeedbackVaryings(GLuint program, + GLsizei count, + const GLchar *const *varyings, + GLenum bufferMode); + void getTransformFeedbackVarying(GLuint program, + GLuint index, + GLsizei bufSize, + GLsizei *length, + GLsizei *size, + GLenum *type, + GLchar *name); + + void deleteTransformFeedbacks(GLsizei n, const GLuint *ids); + void genTransformFeedbacks(GLsizei n, GLuint *ids); + bool isTransformFeedback(GLuint id); + void pauseTransformFeedback(); + void resumeTransformFeedback(); + + void getProgramBinary(GLuint program, + GLsizei bufSize, + GLsizei *length, + GLenum *binaryFormat, + void *binary); + void programBinary(GLuint program, GLenum binaryFormat, const void *binary, GLsizei length); + + void getUniformuiv(GLuint program, GLint location, GLuint *params); + GLint getFragDataLocation(GLuint program, const GLchar *name); + void getUniformIndices(GLuint program, + GLsizei uniformCount, + const GLchar *const *uniformNames, + GLuint *uniformIndices); + void getActiveUniformsiv(GLuint program, + GLsizei uniformCount, + const GLuint *uniformIndices, + GLenum pname, + GLint *params); + GLuint getUniformBlockIndex(GLuint program, const GLchar *uniformBlockName); + void getActiveUniformBlockiv(GLuint program, + GLuint uniformBlockIndex, + GLenum pname, + GLint *params); + void getActiveUniformBlockName(GLuint program, + GLuint uniformBlockIndex, + GLsizei bufSize, + GLsizei *length, + GLchar *uniformBlockName); + void uniformBlockBinding(GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding); + + GLsync fenceSync(GLenum condition, GLbitfield flags); + GLboolean isSync(GLsync sync); + void deleteSync(GLsync sync); + GLenum clientWaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout); + void waitSync(GLsync sync, GLbitfield flags, GLuint64 timeout); + void getInteger64v(GLenum pname, GLint64 *params); + + void getBufferParameteri64v(BufferBinding target, GLenum pname, GLint64 *params); + void genSamplers(GLsizei count, GLuint *samplers); + void deleteSamplers(GLsizei count, const GLuint *samplers); + void getInternalformativ(GLenum target, + GLenum internalformat, + GLenum pname, + GLsizei bufSize, + GLint *params); + + void programUniform1i(GLuint program, GLint location, GLint v0); + void programUniform2i(GLuint program, GLint location, GLint v0, GLint v1); + void programUniform3i(GLuint program, GLint location, GLint v0, GLint v1, GLint v2); + void programUniform4i(GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3); + void programUniform1ui(GLuint program, GLint location, GLuint v0); + void programUniform2ui(GLuint program, GLint location, GLuint v0, GLuint v1); + void programUniform3ui(GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2); + void programUniform4ui(GLuint program, + GLint location, + GLuint v0, + GLuint v1, + GLuint v2, + GLuint v3); + void programUniform1f(GLuint program, GLint location, GLfloat v0); + void programUniform2f(GLuint program, GLint location, GLfloat v0, GLfloat v1); + void programUniform3f(GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2); + void programUniform4f(GLuint program, + GLint location, + GLfloat v0, + GLfloat v1, + GLfloat v2, + GLfloat v3); + void programUniform1iv(GLuint program, GLint location, GLsizei count, const GLint *value); + void programUniform2iv(GLuint program, GLint location, GLsizei count, const GLint *value); + void programUniform3iv(GLuint program, GLint location, GLsizei count, const GLint *value); + void programUniform4iv(GLuint program, GLint location, GLsizei count, const GLint *value); + void programUniform1uiv(GLuint program, GLint location, GLsizei count, const GLuint *value); + void programUniform2uiv(GLuint program, GLint location, GLsizei count, const GLuint *value); + void programUniform3uiv(GLuint program, GLint location, GLsizei count, const GLuint *value); + void programUniform4uiv(GLuint program, GLint location, GLsizei count, const GLuint *value); + void programUniform1fv(GLuint program, GLint location, GLsizei count, const GLfloat *value); + void programUniform2fv(GLuint program, GLint location, GLsizei count, const GLfloat *value); + void programUniform3fv(GLuint program, GLint location, GLsizei count, const GLfloat *value); + void programUniform4fv(GLuint program, GLint location, GLsizei count, const GLfloat *value); + + void programUniformMatrix2fv(GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value); + + void programUniformMatrix3fv(GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value); + + void programUniformMatrix4fv(GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value); + + void programUniformMatrix2x3fv(GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value); + + void programUniformMatrix3x2fv(GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value); + + void programUniformMatrix2x4fv(GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value); + + void programUniformMatrix4x2fv(GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value); + + void programUniformMatrix3x4fv(GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value); + + void programUniformMatrix4x3fv(GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value); + + void deleteProgramPipelines(GLsizei n, const GLuint *pipelines); + void genProgramPipelines(GLsizei n, GLuint *pipelines); + GLboolean isProgramPipeline(GLuint pipeline); + + // Consumes the error. + void handleError(const Error &error) override; GLenum getError(); + void markContextLost(); + bool isContextLost(); GLenum getResetStatus(); - virtual bool isResetNotificationEnabled(); + bool isResetNotificationEnabled(); const egl::Config *getConfig() const; EGLenum getClientType() const; EGLenum getRenderBuffer() const; - const std::string &getRendererString() const; + const GLubyte *getString(GLenum name) const; + const GLubyte *getStringi(GLenum name, GLuint index) const; - const std::string &getExtensionString() const; - const std::string &getExtensionString(size_t idx) const; size_t getExtensionStringCount() const; - rx::Renderer *getRenderer() { return mRenderer; } + bool isExtensionRequestable(const char *name); + void requestExtension(const char *name); + size_t getRequestableExtensionStringCount() const; - State &getState() { return mState; } + rx::ContextImpl *getImplementation() const { return mImplementation.get(); } + const Workarounds &getWorkarounds() const; - void syncRendererState(); - void syncRendererState(const State::DirtyBits &bitMask); + void getFramebufferParameteriv(GLenum target, GLenum pname, GLint *params); + void framebufferParameteri(GLenum target, GLenum pname, GLint param); + + Error getScratchBuffer(size_t requestedSizeBytes, angle::MemoryBuffer **scratchBufferOut) const; + Error getZeroFilledBuffer(size_t requstedSizeBytes, angle::MemoryBuffer **zeroBufferOut) const; + + void dispatchCompute(GLuint numGroupsX, GLuint numGroupsY, GLuint numGroupsZ); + void dispatchComputeIndirect(GLintptr indirect); + + MemoryProgramCache *getMemoryProgramCache() const { return mMemoryProgramCache; } + + template + void gatherParams(ParamsT &&... params); + + void texStorage2D(GLenum target, + GLsizei levels, + GLenum internalFormat, + GLsizei width, + GLsizei height); + void texStorage3D(GLenum target, + GLsizei levels, + GLenum internalFormat, + GLsizei width, + GLsizei height, + GLsizei depth); + + void memoryBarrier(GLbitfield barriers); + void memoryBarrierByRegion(GLbitfield barriers); + + // Notification for a state change in a Texture. + void onTextureChange(const Texture *texture); + + egl::Display *getCurrentDisplay() const { return mCurrentDisplay; } + egl::Surface *getCurrentDrawSurface() const { return mCurrentSurface; } + egl::Surface *getCurrentReadSurface() const { return mCurrentSurface; } + + bool isRobustResourceInitEnabled() const { return mGLState.isRobustResourceInitEnabled(); } private: - void checkVertexArrayAllocation(GLuint vertexArray); - void checkTransformFeedbackAllocation(GLuint transformFeedback); - Framebuffer *checkFramebufferAllocation(GLuint framebufferHandle); + Error prepareForDraw(); + void syncRendererState(); + void syncRendererState(const State::DirtyBits &bitMask, const State::DirtyObjects &objectMask); + void syncStateForReadPixels(); + void syncStateForTexImage(); + void syncStateForClear(); + void syncStateForBlit(); + VertexArray *checkVertexArrayAllocation(GLuint vertexArrayHandle); + TransformFeedback *checkTransformFeedbackAllocation(GLuint transformFeedback); void detachBuffer(GLuint buffer); void detachTexture(GLuint texture); @@ -328,11 +1046,20 @@ class Context final : public ValidationContext void detachVertexArray(GLuint vertexArray); void detachTransformFeedback(GLuint transformFeedback); void detachSampler(GLuint sampler); + void detachProgramPipeline(GLuint pipeline); void initRendererString(); + void initVersionStrings(); void initExtensionStrings(); - void initCaps(GLuint clientVersion); + void initCaps(const egl::DisplayExtensions &displayExtensions, bool robustResourceInit); + void updateCaps(); + void initWorkarounds(); + + LabeledObject *getLabeledObject(GLenum identifier, GLuint name) const; + LabeledObject *getLabeledObjectFromPtr(const void *ptr) const; + + std::unique_ptr mImplementation; // Caps to use for validation Caps mCaps; @@ -340,42 +1067,35 @@ class Context final : public ValidationContext Extensions mExtensions; Limitations mLimitations; - // Shader compiler - Compiler *mCompiler; - - rx::Renderer *const mRenderer; - State mState; + // Shader compiler. Lazily initialized hence the mutable value. + mutable BindingPointer mCompiler; - int mClientVersion; + State mGLState; const egl::Config *mConfig; EGLenum mClientType; TextureMap mZeroTextures; - typedef std::map FramebufferMap; - FramebufferMap mFramebufferMap; - HandleAllocator mFramebufferHandleAllocator; - - typedef std::map FenceNVMap; - FenceNVMap mFenceNVMap; + ResourceMap mFenceNVMap; HandleAllocator mFenceNVHandleAllocator; - typedef std::map QueryMap; - QueryMap mQueryMap; + ResourceMap mQueryMap; HandleAllocator mQueryHandleAllocator; - typedef std::map VertexArrayMap; - VertexArrayMap mVertexArrayMap; + ResourceMap mVertexArrayMap; HandleAllocator mVertexArrayHandleAllocator; - typedef std::map TransformFeedbackMap; - TransformFeedbackMap mTransformFeedbackMap; - HandleAllocator mTransformFeedbackAllocator; + ResourceMap mTransformFeedbackMap; + HandleAllocator mTransformFeedbackHandleAllocator; - std::string mRendererString; - std::string mExtensionString; - std::vector mExtensionStrings; + const char *mVersionString; + const char *mShadingLanguageString; + const char *mRendererString; + const char *mExtensionString; + std::vector mExtensionStrings; + const char *mRequestableExtensionString; + std::vector mRequestableExtensionStrings; // Recorded errors typedef std::set ErrorSet; @@ -385,13 +1105,50 @@ class Context final : public ValidationContext bool mHasBeenCurrent; bool mContextLost; GLenum mResetStatus; + bool mContextLostForced; GLenum mResetStrategy; bool mRobustAccess; egl::Surface *mCurrentSurface; - - ResourceManager *mResourceManager; + egl::Display *mCurrentDisplay; + Framebuffer *mSurfacelessFramebuffer; + bool mWebGLContext; + MemoryProgramCache *mMemoryProgramCache; + + State::DirtyBits mTexImageDirtyBits; + State::DirtyObjects mTexImageDirtyObjects; + State::DirtyBits mReadPixelsDirtyBits; + State::DirtyObjects mReadPixelsDirtyObjects; + State::DirtyBits mClearDirtyBits; + State::DirtyObjects mClearDirtyObjects; + State::DirtyBits mBlitDirtyBits; + State::DirtyObjects mBlitDirtyObjects; + + Workarounds mWorkarounds; + + // Not really a property of context state. The size and contexts change per-api-call. + mutable angle::ScratchBuffer mScratchBuffer; + mutable angle::ScratchBuffer mZeroFilledBuffer; }; +template +ANGLE_INLINE void Context::gatherParams(ArgsT &&... args) +{ + static_assert(sizeof(EntryPointParamType) <= kParamsBufferSize, + "Params struct too large, please increase kParamsBufferSize."); + + mSavedArgsType = &EntryPointParamType::TypeInfo; + + // Skip doing any work for ParamsBase/Invalid type. + if (!EntryPointParamType::TypeInfo.isValid()) + { + return; + } + + EntryPointParamType *objBuffer = + reinterpret_cast *>(mParamsBuffer.data()); + EntryPointParamType::template Factory(objBuffer, this, std::forward(args)...); +} + } // namespace gl -#endif // LIBANGLE_CONTEXT_H_ +#endif // LIBANGLE_CONTEXT_H_ diff --git a/src/3rdparty/angle/src/libANGLE/ContextState.cpp b/src/3rdparty/angle/src/libANGLE/ContextState.cpp new file mode 100644 index 0000000000..d109cca76d --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/ContextState.cpp @@ -0,0 +1,839 @@ +// +// 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/ContextState.h" + +#include "libANGLE/Framebuffer.h" +#include "libANGLE/ResourceManager.h" + +namespace gl +{ + +namespace +{ + +template +using ContextStateMember = T *(ContextState::*); + +template +T *AllocateOrGetSharedResourceManager(const ContextState *shareContextState, + ContextStateMember member) +{ + if (shareContextState) + { + T *resourceManager = (*shareContextState).*member; + resourceManager->addRef(); + return resourceManager; + } + else + { + return new T(); + } +} + +TextureManager *AllocateOrGetSharedTextureManager(const ContextState *shareContextState, + TextureManager *shareTextures, + ContextStateMember member) +{ + if (shareContextState) + { + TextureManager *textureManager = (*shareContextState).*member; + ASSERT(shareTextures == nullptr || textureManager == shareTextures); + textureManager->addRef(); + return textureManager; + } + else if (shareTextures) + { + TextureManager *textureManager = shareTextures; + textureManager->addRef(); + return textureManager; + } + else + { + return new TextureManager(); + } +} + +} // anonymous namespace + +ContextState::ContextState(ContextID contextIn, + const ContextState *shareContextState, + TextureManager *shareTextures, + const Version &clientVersion, + State *stateIn, + const Caps &capsIn, + const TextureCapsMap &textureCapsIn, + const Extensions &extensionsIn, + const Limitations &limitationsIn) + : mClientVersion(clientVersion), + mContext(contextIn), + mState(stateIn), + mCaps(capsIn), + mTextureCaps(textureCapsIn), + mExtensions(extensionsIn), + mLimitations(limitationsIn), + mBuffers(AllocateOrGetSharedResourceManager(shareContextState, &ContextState::mBuffers)), + mShaderPrograms( + AllocateOrGetSharedResourceManager(shareContextState, &ContextState::mShaderPrograms)), + mTextures(AllocateOrGetSharedTextureManager(shareContextState, + shareTextures, + &ContextState::mTextures)), + mRenderbuffers( + AllocateOrGetSharedResourceManager(shareContextState, &ContextState::mRenderbuffers)), + mSamplers(AllocateOrGetSharedResourceManager(shareContextState, &ContextState::mSamplers)), + mSyncs(AllocateOrGetSharedResourceManager(shareContextState, &ContextState::mSyncs)), + mPaths(AllocateOrGetSharedResourceManager(shareContextState, &ContextState::mPaths)), + mFramebuffers(new FramebufferManager()), + mPipelines(new ProgramPipelineManager()) +{ +} + +ContextState::~ContextState() +{ + // Handles are released by the Context. +} + +bool ContextState::isWebGL() const +{ + return mExtensions.webglCompatibility; +} + +bool ContextState::isWebGL1() const +{ + return (isWebGL() && mClientVersion.major == 2); +} + +const TextureCaps &ContextState::getTextureCap(GLenum internalFormat) const +{ + return mTextureCaps.get(internalFormat); +} + +ValidationContext::ValidationContext(const ValidationContext *shareContext, + TextureManager *shareTextures, + const Version &clientVersion, + State *state, + const Caps &caps, + const TextureCapsMap &textureCaps, + const Extensions &extensions, + const Limitations &limitations, + bool skipValidation) + : mState(reinterpret_cast(this), + shareContext ? &shareContext->mState : nullptr, + shareTextures, + clientVersion, + state, + caps, + textureCaps, + extensions, + limitations), + mSkipValidation(skipValidation), + mDisplayTextureShareGroup(shareTextures != nullptr) +{ +} + +ValidationContext::~ValidationContext() +{ +} + +bool ValidationContext::getQueryParameterInfo(GLenum pname, GLenum *type, unsigned int *numParams) +{ + // 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 = static_cast(getCaps().compressedTextureFormats.size()); + return true; + } + case GL_SHADER_BINARY_FORMATS: + { + *type = GL_INT; + *numParams = static_cast(getCaps().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_NUM_SHADER_BINARY_FORMATS: + case GL_NUM_COMPRESSED_TEXTURE_FORMATS: + case GL_ARRAY_BUFFER_BINDING: + case GL_FRAMEBUFFER_BINDING: + case GL_RENDERBUFFER_BINDING: + case GL_CURRENT_PROGRAM: + case GL_PACK_ALIGNMENT: + case GL_UNPACK_ALIGNMENT: + case GL_GENERATE_MIPMAP_HINT: + 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: + { + *type = GL_INT; + *numParams = 1; + return true; + } + case GL_PACK_REVERSE_ROW_ORDER_ANGLE: + { + if (!getExtensions().packReverseRowOrder) + { + return false; + } + *type = GL_INT; + *numParams = 1; + return true; + } + case GL_MAX_RECTANGLE_TEXTURE_SIZE_ANGLE: + case GL_TEXTURE_BINDING_RECTANGLE_ANGLE: + { + if (!getExtensions().textureRectangle) + { + return false; + } + *type = GL_INT; + *numParams = 1; + return true; + } + case GL_MAX_DRAW_BUFFERS_EXT: + case GL_MAX_COLOR_ATTACHMENTS_EXT: + { + if ((getClientMajorVersion() < 3) && !getExtensions().drawBuffers) + { + return false; + } + *type = GL_INT; + *numParams = 1; + 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 (!getExtensions().textureFilterAnisotropic) + { + return false; + } + *type = GL_FLOAT; + *numParams = 1; + return true; + case GL_TIMESTAMP_EXT: + if (!getExtensions().disjointTimerQuery) + { + return false; + } + *type = GL_INT_64_ANGLEX; + *numParams = 1; + return true; + case GL_GPU_DISJOINT_EXT: + if (!getExtensions().disjointTimerQuery) + { + return false; + } + *type = GL_INT; + *numParams = 1; + return true; + case GL_COVERAGE_MODULATION_CHROMIUM: + if (!getExtensions().framebufferMixedSamples) + { + return false; + } + *type = GL_INT; + *numParams = 1; + return true; + case GL_TEXTURE_BINDING_EXTERNAL_OES: + if (!getExtensions().eglStreamConsumerExternal && !getExtensions().eglImageExternal) + { + return false; + } + *type = GL_INT; + *numParams = 1; + return true; + } + + if (getExtensions().debug) + { + switch (pname) + { + case GL_DEBUG_LOGGED_MESSAGES: + case GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH: + case GL_DEBUG_GROUP_STACK_DEPTH: + case GL_MAX_DEBUG_MESSAGE_LENGTH: + case GL_MAX_DEBUG_LOGGED_MESSAGES: + case GL_MAX_DEBUG_GROUP_STACK_DEPTH: + case GL_MAX_LABEL_LENGTH: + *type = GL_INT; + *numParams = 1; + return true; + + case GL_DEBUG_OUTPUT_SYNCHRONOUS: + case GL_DEBUG_OUTPUT: + *type = GL_BOOL; + *numParams = 1; + return true; + } + } + + if (getExtensions().multisampleCompatibility) + { + switch (pname) + { + case GL_MULTISAMPLE_EXT: + case GL_SAMPLE_ALPHA_TO_ONE_EXT: + *type = GL_BOOL; + *numParams = 1; + return true; + } + } + + if (getExtensions().pathRendering) + { + switch (pname) + { + case GL_PATH_MODELVIEW_MATRIX_CHROMIUM: + case GL_PATH_PROJECTION_MATRIX_CHROMIUM: + *type = GL_FLOAT; + *numParams = 16; + return true; + } + } + + if (getExtensions().bindGeneratesResource) + { + switch (pname) + { + case GL_BIND_GENERATES_RESOURCE_CHROMIUM: + *type = GL_BOOL; + *numParams = 1; + return true; + } + } + + if (getExtensions().clientArrays) + { + switch (pname) + { + case GL_CLIENT_ARRAYS_ANGLE: + *type = GL_BOOL; + *numParams = 1; + return true; + } + } + + if (getExtensions().sRGBWriteControl) + { + switch (pname) + { + case GL_FRAMEBUFFER_SRGB_EXT: + *type = GL_BOOL; + *numParams = 1; + return true; + } + } + + if (getExtensions().robustResourceInitialization && + pname == GL_ROBUST_RESOURCE_INITIALIZATION_ANGLE) + { + *type = GL_BOOL; + *numParams = 1; + return true; + } + + if (getExtensions().programCacheControl && pname == GL_PROGRAM_CACHE_ENABLED_ANGLE) + { + *type = GL_BOOL; + *numParams = 1; + return true; + } + + // Check for ES3.0+ parameter names which are also exposed as ES2 extensions + switch (pname) + { + // case GL_DRAW_FRAMEBUFFER_BINDING_ANGLE // equivalent to FRAMEBUFFER_BINDING + case GL_READ_FRAMEBUFFER_BINDING_ANGLE: + if ((getClientMajorVersion() < 3) && !getExtensions().framebufferBlit) + { + return false; + } + *type = GL_INT; + *numParams = 1; + return true; + + case GL_NUM_PROGRAM_BINARY_FORMATS_OES: + if ((getClientMajorVersion() < 3) && !getExtensions().getProgramBinary) + { + return false; + } + *type = GL_INT; + *numParams = 1; + return true; + + case GL_PROGRAM_BINARY_FORMATS_OES: + if ((getClientMajorVersion() < 3) && !getExtensions().getProgramBinary) + { + return false; + } + *type = GL_INT; + *numParams = static_cast(getCaps().programBinaryFormats.size()); + return true; + + case GL_PACK_ROW_LENGTH: + case GL_PACK_SKIP_ROWS: + case GL_PACK_SKIP_PIXELS: + if ((getClientMajorVersion() < 3) && !getExtensions().packSubimage) + { + return false; + } + *type = GL_INT; + *numParams = 1; + return true; + case GL_UNPACK_ROW_LENGTH: + case GL_UNPACK_SKIP_ROWS: + case GL_UNPACK_SKIP_PIXELS: + if ((getClientMajorVersion() < 3) && !getExtensions().unpackSubimage) + { + return false; + } + *type = GL_INT; + *numParams = 1; + return true; + case GL_VERTEX_ARRAY_BINDING: + if ((getClientMajorVersion() < 3) && !getExtensions().vertexArrayObject) + { + return false; + } + *type = GL_INT; + *numParams = 1; + return true; + case GL_PIXEL_PACK_BUFFER_BINDING: + case GL_PIXEL_UNPACK_BUFFER_BINDING: + if ((getClientMajorVersion() < 3) && !getExtensions().pixelBufferObject) + { + return false; + } + *type = GL_INT; + *numParams = 1; + return true; + case GL_MAX_SAMPLES: + { + static_assert(GL_MAX_SAMPLES_ANGLE == GL_MAX_SAMPLES, + "GL_MAX_SAMPLES_ANGLE not equal to GL_MAX_SAMPLES"); + if ((getClientMajorVersion() < 3) && !getExtensions().framebufferMultisample) + { + return false; + } + *type = GL_INT; + *numParams = 1; + return true; + + case GL_FRAGMENT_SHADER_DERIVATIVE_HINT: + if ((getClientMajorVersion() < 3) && !getExtensions().standardDerivatives) + { + return false; + } + *type = GL_INT; + *numParams = 1; + return true; + } + } + + if (pname >= GL_DRAW_BUFFER0_EXT && pname <= GL_DRAW_BUFFER15_EXT) + { + if ((getClientVersion() < Version(3, 0)) && !getExtensions().drawBuffers) + { + return false; + } + *type = GL_INT; + *numParams = 1; + return true; + } + + if (getExtensions().multiview && pname == GL_MAX_VIEWS_ANGLE) + { + *type = GL_INT; + *numParams = 1; + return true; + } + + if (getClientVersion() < Version(3, 0)) + { + 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_TRANSFORM_FEEDBACK_BUFFER_BINDING: + case GL_COPY_READ_BUFFER_BINDING: + case GL_COPY_WRITE_BUFFER_BINDING: + case GL_SAMPLER_BINDING: + case GL_READ_BUFFER: + 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_VERTEX_OUTPUT_COMPONENTS: + case GL_MAX_FRAGMENT_INPUT_COMPONENTS: + case GL_MAX_VARYING_COMPONENTS: + case GL_MAX_VERTEX_UNIFORM_COMPONENTS: + case GL_MAX_FRAGMENT_UNIFORM_COMPONENTS: + case GL_MIN_PROGRAM_TEXEL_OFFSET: + case GL_MAX_PROGRAM_TEXEL_OFFSET: + 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: + case GL_UNPACK_IMAGE_HEIGHT: + case GL_UNPACK_SKIP_IMAGES: + { + *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: + case GL_PRIMITIVE_RESTART_FIXED_INDEX: + case GL_RASTERIZER_DISCARD: + { + *type = GL_BOOL; + *numParams = 1; + return true; + } + + case GL_MAX_TEXTURE_LOD_BIAS: + { + *type = GL_FLOAT; + *numParams = 1; + return true; + } + } + + if (getExtensions().requestExtension) + { + switch (pname) + { + case GL_NUM_REQUESTABLE_EXTENSIONS_ANGLE: + *type = GL_INT; + *numParams = 1; + return true; + } + } + + if (getClientVersion() < Version(3, 1)) + { + return false; + } + + switch (pname) + { + case GL_ATOMIC_COUNTER_BUFFER_BINDING: + case GL_DRAW_INDIRECT_BUFFER_BINDING: + case GL_MAX_FRAMEBUFFER_WIDTH: + case GL_MAX_FRAMEBUFFER_HEIGHT: + case GL_MAX_FRAMEBUFFER_SAMPLES: + case GL_MAX_SAMPLE_MASK_WORDS: + case GL_MAX_COLOR_TEXTURE_SAMPLES: + case GL_MAX_DEPTH_TEXTURE_SAMPLES: + case GL_MAX_INTEGER_SAMPLES: + case GL_MAX_VERTEX_ATTRIB_RELATIVE_OFFSET: + case GL_MAX_VERTEX_ATTRIB_BINDINGS: + case GL_MAX_VERTEX_ATTRIB_STRIDE: + case GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS: + case GL_MAX_VERTEX_ATOMIC_COUNTERS: + case GL_MAX_VERTEX_IMAGE_UNIFORMS: + case GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS: + case GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS: + case GL_MAX_FRAGMENT_ATOMIC_COUNTERS: + case GL_MAX_FRAGMENT_IMAGE_UNIFORMS: + case GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS: + case GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET: + case GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET: + case GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS: + case GL_MAX_COMPUTE_UNIFORM_BLOCKS: + case GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS: + case GL_MAX_COMPUTE_SHARED_MEMORY_SIZE: + case GL_MAX_COMPUTE_UNIFORM_COMPONENTS: + case GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS: + case GL_MAX_COMPUTE_ATOMIC_COUNTERS: + case GL_MAX_COMPUTE_IMAGE_UNIFORMS: + case GL_MAX_COMBINED_COMPUTE_UNIFORM_COMPONENTS: + case GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS: + case GL_MAX_COMBINED_SHADER_OUTPUT_RESOURCES: + case GL_MAX_UNIFORM_LOCATIONS: + case GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS: + case GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE: + case GL_MAX_COMBINED_ATOMIC_COUNTER_BUFFERS: + case GL_MAX_COMBINED_ATOMIC_COUNTERS: + case GL_MAX_IMAGE_UNITS: + case GL_MAX_COMBINED_IMAGE_UNIFORMS: + case GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS: + case GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS: + case GL_SHADER_STORAGE_BUFFER_BINDING: + case GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT: + case GL_TEXTURE_BINDING_2D_MULTISAMPLE: + *type = GL_INT; + *numParams = 1; + return true; + case GL_MAX_SHADER_STORAGE_BLOCK_SIZE: + *type = GL_INT_64_ANGLEX; + *numParams = 1; + return true; + case GL_SAMPLE_MASK: + *type = GL_BOOL; + *numParams = 1; + return true; + } + + return false; +} + +bool ValidationContext::getIndexedQueryParameterInfo(GLenum target, + GLenum *type, + unsigned int *numParams) +{ + if (getClientVersion() < Version(3, 0)) + { + 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 true; + } + } + + if (getClientVersion() < Version(3, 1)) + { + return false; + } + + switch (target) + { + case GL_MAX_COMPUTE_WORK_GROUP_COUNT: + case GL_MAX_COMPUTE_WORK_GROUP_SIZE: + case GL_ATOMIC_COUNTER_BUFFER_BINDING: + case GL_SHADER_STORAGE_BUFFER_BINDING: + case GL_VERTEX_BINDING_BUFFER: + case GL_VERTEX_BINDING_DIVISOR: + case GL_VERTEX_BINDING_OFFSET: + case GL_VERTEX_BINDING_STRIDE: + case GL_SAMPLE_MASK_VALUE: + { + *type = GL_INT; + *numParams = 1; + return true; + } + case GL_ATOMIC_COUNTER_BUFFER_START: + case GL_ATOMIC_COUNTER_BUFFER_SIZE: + case GL_SHADER_STORAGE_BUFFER_START: + case GL_SHADER_STORAGE_BUFFER_SIZE: + { + *type = GL_INT_64_ANGLEX; + *numParams = 1; + return true; + } + } + + return false; +} + +Program *ValidationContext::getProgram(GLuint handle) const +{ + return mState.mShaderPrograms->getProgram(handle); +} + +Shader *ValidationContext::getShader(GLuint handle) const +{ + return mState.mShaderPrograms->getShader(handle); +} + +bool ValidationContext::isTextureGenerated(GLuint texture) const +{ + return mState.mTextures->isHandleGenerated(texture); +} + +bool ValidationContext::isBufferGenerated(GLuint buffer) const +{ + return mState.mBuffers->isHandleGenerated(buffer); +} + +bool ValidationContext::isRenderbufferGenerated(GLuint renderbuffer) const +{ + return mState.mRenderbuffers->isHandleGenerated(renderbuffer); +} + +bool ValidationContext::isFramebufferGenerated(GLuint framebuffer) const +{ + return mState.mFramebuffers->isHandleGenerated(framebuffer); +} + +bool ValidationContext::isProgramPipelineGenerated(GLuint pipeline) const +{ + return mState.mPipelines->isHandleGenerated(pipeline); +} + +bool ValidationContext::usingDisplayTextureShareGroup() const +{ + return mDisplayTextureShareGroup; +} + +GLenum ValidationContext::getConvertedRenderbufferFormat(GLenum internalformat) const +{ + return mState.mExtensions.webglCompatibility && mState.mClientVersion.major == 2 && + internalformat == GL_DEPTH_STENCIL + ? GL_DEPTH24_STENCIL8 + : internalformat; +} + +} // namespace gl diff --git a/src/3rdparty/angle/src/libANGLE/ContextState.h b/src/3rdparty/angle/src/libANGLE/ContextState.h new file mode 100644 index 0000000000..e6e9f4c6b0 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/ContextState.h @@ -0,0 +1,164 @@ +// +// 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. +// + +// ContextState: Container class for all GL context state, caps and objects. + +#ifndef LIBANGLE_CONTEXTSTATE_H_ +#define LIBANGLE_CONTEXTSTATE_H_ + +#include "common/MemoryBuffer.h" +#include "common/angleutils.h" +#include "libANGLE/State.h" +#include "libANGLE/Version.h" +#include "libANGLE/params.h" + +namespace gl +{ +class BufferManager; +class ContextState; +class FramebufferManager; +class PathManager; +class ProgramPipelineManager; +class RenderbufferManager; +class SamplerManager; +class ShaderProgramManager; +class SyncManager; +class TextureManager; +class ValidationContext; + +static constexpr Version ES_2_0 = Version(2, 0); +static constexpr Version ES_3_0 = Version(3, 0); +static constexpr Version ES_3_1 = Version(3, 1); + +using ContextID = uintptr_t; + +class ContextState final : angle::NonCopyable +{ + public: + ContextState(ContextID context, + const ContextState *shareContextState, + TextureManager *shareTextures, + const Version &clientVersion, + State *state, + const Caps &caps, + const TextureCapsMap &textureCaps, + const Extensions &extensions, + const Limitations &limitations); + ~ContextState(); + + ContextID getContextID() const { return mContext; } + GLint getClientMajorVersion() const { return mClientVersion.major; } + GLint getClientMinorVersion() const { return mClientVersion.minor; } + const Version &getClientVersion() const { return mClientVersion; } + const State &getState() const { return *mState; } + const Caps &getCaps() const { return mCaps; } + const TextureCapsMap &getTextureCaps() const { return mTextureCaps; } + const Extensions &getExtensions() const { return mExtensions; } + const Limitations &getLimitations() const { return mLimitations; } + + const TextureCaps &getTextureCap(GLenum internalFormat) const; + + bool usingDisplayTextureShareGroup() const; + + bool isWebGL() const; + bool isWebGL1() const; + + private: + friend class Context; + friend class ValidationContext; + + Version mClientVersion; + ContextID mContext; + State *mState; + const Caps &mCaps; + const TextureCapsMap &mTextureCaps; + const Extensions &mExtensions; + const Limitations &mLimitations; + + BufferManager *mBuffers; + ShaderProgramManager *mShaderPrograms; + TextureManager *mTextures; + RenderbufferManager *mRenderbuffers; + SamplerManager *mSamplers; + SyncManager *mSyncs; + PathManager *mPaths; + FramebufferManager *mFramebuffers; + ProgramPipelineManager *mPipelines; +}; + +class ValidationContext : angle::NonCopyable +{ + public: + ValidationContext(const ValidationContext *shareContext, + TextureManager *shareTextures, + const Version &clientVersion, + State *state, + const Caps &caps, + const TextureCapsMap &textureCaps, + const Extensions &extensions, + const Limitations &limitations, + bool skipValidation); + virtual ~ValidationContext(); + + virtual void handleError(const Error &error) = 0; + + const ContextState &getContextState() const { return mState; } + GLint getClientMajorVersion() const { return mState.getClientMajorVersion(); } + GLint getClientMinorVersion() const { return mState.getClientMinorVersion(); } + const Version &getClientVersion() const { return mState.getClientVersion(); } + const State &getGLState() const { return mState.getState(); } + const Caps &getCaps() const { return mState.getCaps(); } + const TextureCapsMap &getTextureCaps() const { return mState.getTextureCaps(); } + const Extensions &getExtensions() const { return mState.getExtensions(); } + const Limitations &getLimitations() const { return mState.getLimitations(); } + bool skipValidation() const { return mSkipValidation; } + + // Specific methods needed for validation. + bool getQueryParameterInfo(GLenum pname, GLenum *type, unsigned int *numParams); + bool getIndexedQueryParameterInfo(GLenum target, GLenum *type, unsigned int *numParams); + + Program *getProgram(GLuint handle) const; + Shader *getShader(GLuint handle) const; + + bool isTextureGenerated(GLuint texture) const; + bool isBufferGenerated(GLuint buffer) const; + bool isRenderbufferGenerated(GLuint renderbuffer) const; + bool isFramebufferGenerated(GLuint framebuffer) const; + bool isProgramPipelineGenerated(GLuint pipeline) const; + + bool usingDisplayTextureShareGroup() const; + + // Hack for the special WebGL 1 "DEPTH_STENCIL" internal format. + GLenum getConvertedRenderbufferFormat(GLenum internalformat) const; + + bool isWebGL() const { return mState.isWebGL(); } + bool isWebGL1() const { return mState.isWebGL1(); } + + template + const T &getParams() const; + + protected: + ContextState mState; + bool mSkipValidation; + bool mDisplayTextureShareGroup; + + // Caches entry point parameters and values re-used between layers. + mutable const ParamTypeInfo *mSavedArgsType; + static constexpr size_t kParamsBufferSize = 64u; + mutable std::array mParamsBuffer; +}; + +template +const T &ValidationContext::getParams() const +{ + const T *params = reinterpret_cast(mParamsBuffer.data()); + ASSERT(mSavedArgsType->hasDynamicType(T::TypeInfo)); + return *params; +} + +} // namespace gl + +#endif // LIBANGLE_CONTEXTSTATE_H_ diff --git a/src/3rdparty/angle/src/libANGLE/Data.cpp b/src/3rdparty/angle/src/libANGLE/Data.cpp deleted file mode 100644 index 83f04b5a0b..0000000000 --- a/src/3rdparty/angle/src/libANGLE/Data.cpp +++ /dev/null @@ -1,56 +0,0 @@ -// -// 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(uintptr_t contextIn, - GLint clientVersionIn, - const State &stateIn, - const Caps &capsIn, - const TextureCapsMap &textureCapsIn, - const Extensions &extensionsIn, - const ResourceManager *resourceManagerIn, - const Limitations &limitationsIn) - : context(contextIn), - clientVersion(clientVersionIn), - state(&stateIn), - caps(&capsIn), - textureCaps(&textureCapsIn), - extensions(&extensionsIn), - resourceManager(resourceManagerIn), - limitations(&limitationsIn) -{} - -Data::~Data() -{ -} - -ValidationContext::ValidationContext(GLint clientVersion, - const State &state, - const Caps &caps, - const TextureCapsMap &textureCaps, - const Extensions &extensions, - const ResourceManager *resourceManager, - const Limitations &limitations, - bool skipValidation) - : mData(reinterpret_cast(this), - clientVersion, - state, - caps, - textureCaps, - extensions, - resourceManager, - limitations), - mSkipValidation(skipValidation) -{ -} -} // namespace gl diff --git a/src/3rdparty/angle/src/libANGLE/Data.h b/src/3rdparty/angle/src/libANGLE/Data.h deleted file mode 100644 index f7230d74bc..0000000000 --- a/src/3rdparty/angle/src/libANGLE/Data.h +++ /dev/null @@ -1,72 +0,0 @@ -// -// 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 "common/angleutils.h" -#include "libANGLE/State.h" - -namespace gl -{ - -struct Data final : public angle::NonCopyable -{ - public: - Data(uintptr_t context, - GLint clientVersion, - const State &state, - const Caps &caps, - const TextureCapsMap &textureCaps, - const Extensions &extensions, - const ResourceManager *resourceManager, - const Limitations &limitations); - ~Data(); - - uintptr_t context; - GLint clientVersion; - const State *state; - const Caps *caps; - const TextureCapsMap *textureCaps; - const Extensions *extensions; - const ResourceManager *resourceManager; - const Limitations *limitations; -}; - -class ValidationContext : angle::NonCopyable -{ - public: - ValidationContext(GLint clientVersion, - const State &state, - const Caps &caps, - const TextureCapsMap &textureCaps, - const Extensions &extensions, - const ResourceManager *resourceManager, - const Limitations &limitations, - bool skipValidation); - virtual ~ValidationContext() {} - - virtual void recordError(const Error &error) = 0; - - const Data &getData() const { return mData; } - int getClientVersion() const { return mData.clientVersion; } - const State &getState() const { return *mData.state; } - const Caps &getCaps() const { return *mData.caps; } - const TextureCapsMap &getTextureCaps() const { return *mData.textureCaps; } - const Extensions &getExtensions() const { return *mData.extensions; } - const Limitations &getLimitations() const { return *mData.limitations; } - bool skipValidation() const { return mSkipValidation; } - - protected: - Data mData; - bool mSkipValidation; -}; - -} - -#endif // LIBANGLE_DATA_H_ diff --git a/src/3rdparty/angle/src/libANGLE/Debug.cpp b/src/3rdparty/angle/src/libANGLE/Debug.cpp index 30321f4160..96f30df98c 100644 --- a/src/3rdparty/angle/src/libANGLE/Debug.cpp +++ b/src/3rdparty/angle/src/libANGLE/Debug.cpp @@ -16,6 +16,26 @@ namespace gl { +Debug::Control::Control() +{ +} + +Debug::Control::~Control() +{ +} + +Debug::Control::Control(const Control &other) = default; + +Debug::Group::Group() +{ +} + +Debug::Group::~Group() +{ +} + +Debug::Group::Group(const Group &other) = default; + Debug::Debug() : mOutputEnabled(false), mCallbackFunction(nullptr), @@ -28,6 +48,10 @@ Debug::Debug() pushDefaultGroup(); } +Debug::~Debug() +{ +} + void Debug::setMaxLoggedMessages(GLuint maxLoggedMessages) { mMaxLoggedMessages = maxLoggedMessages; diff --git a/src/3rdparty/angle/src/libANGLE/Debug.h b/src/3rdparty/angle/src/libANGLE/Debug.h index f545b815e4..2c15c25e9a 100644 --- a/src/3rdparty/angle/src/libANGLE/Debug.h +++ b/src/3rdparty/angle/src/libANGLE/Debug.h @@ -31,6 +31,7 @@ class Debug : angle::NonCopyable { public: Debug(); + ~Debug(); void setMaxLoggedMessages(GLuint maxLoggedMessages); @@ -91,6 +92,10 @@ class Debug : angle::NonCopyable struct Control { + Control(); + ~Control(); + Control(const Control &other); + GLenum source; GLenum type; GLenum severity; @@ -100,6 +105,10 @@ class Debug : angle::NonCopyable struct Group { + Group(); + ~Group(); + Group(const Group &other); + GLenum source; GLuint id; std::string message; diff --git a/src/3rdparty/angle/src/libANGLE/Device.cpp b/src/3rdparty/angle/src/libANGLE/Device.cpp index eb30b2023f..3ebf48b919 100644 --- a/src/3rdparty/angle/src/libANGLE/Device.cpp +++ b/src/3rdparty/angle/src/libANGLE/Device.cpp @@ -45,33 +45,28 @@ static DeviceSet *GetDeviceSet() // Static factory methods egl::Error Device::CreateDevice(void *devicePointer, EGLint deviceType, Device **outDevice) { + *outDevice = nullptr; + #if defined(ANGLE_ENABLE_D3D11) if (deviceType == EGL_D3D11_DEVICE_ANGLE) { - rx::DeviceD3D *deviceD3D = new rx::DeviceD3D(); - egl::Error error = deviceD3D->initialize(devicePointer, deviceType, EGL_TRUE); - if (error.isError()) - { - *outDevice = nullptr; - return error; - } - - *outDevice = new Device(nullptr, deviceD3D); + std::unique_ptr deviceD3D(new rx::DeviceD3D()); + ANGLE_TRY(deviceD3D->initialize(devicePointer, deviceType, EGL_TRUE)); + *outDevice = new Device(nullptr, deviceD3D.release()); GetDeviceSet()->insert(*outDevice); - return egl::Error(EGL_SUCCESS); + return NoError(); } #endif // Note that creating an EGL device from inputted D3D9 parameters isn't currently supported - *outDevice = nullptr; - return egl::Error(EGL_BAD_ATTRIBUTE); + return EglBadAttribute(); } egl::Error Device::CreateDevice(Display *owningDisplay, rx::DeviceImpl *impl, Device **outDevice) { *outDevice = new Device(owningDisplay, impl); GetDeviceSet()->insert(*outDevice); - return egl::Error(EGL_SUCCESS); + return NoError(); } bool Device::IsValidDevice(Device *device) diff --git a/src/3rdparty/angle/src/libANGLE/Display.cpp b/src/3rdparty/angle/src/libANGLE/Display.cpp index 486c74abc0..735b472787 100644 --- a/src/3rdparty/angle/src/libANGLE/Display.cpp +++ b/src/3rdparty/angle/src/libANGLE/Display.cpp @@ -28,6 +28,8 @@ #include "libANGLE/histogram_macros.h" #include "libANGLE/Image.h" #include "libANGLE/Surface.h" +#include "libANGLE/Stream.h" +#include "libANGLE/ResourceManager.h" #include "libANGLE/renderer/DisplayImpl.h" #include "libANGLE/renderer/ImageImpl.h" #include "third_party/trace_event/trace_event.h" @@ -43,38 +45,34 @@ # include "libANGLE/renderer/gl/glx/DisplayGLX.h" # elif defined(ANGLE_PLATFORM_APPLE) # include "libANGLE/renderer/gl/cgl/DisplayCGL.h" +# elif defined(ANGLE_USE_OZONE) +# include "libANGLE/renderer/gl/egl/ozone/DisplayOzone.h" +# elif defined(ANGLE_PLATFORM_ANDROID) +# include "libANGLE/renderer/gl/egl/android/DisplayAndroid.h" # else # error Unsupported OpenGL platform. # endif #endif -namespace egl -{ +#if defined(ANGLE_ENABLE_NULL) +#include "libANGLE/renderer/null/DisplayNULL.h" +#endif // defined(ANGLE_ENABLE_NULL) -namespace -{ +#if defined(ANGLE_ENABLE_VULKAN) +#if defined(ANGLE_PLATFORM_WINDOWS) +#include "libANGLE/renderer/vulkan/win32/DisplayVkWin32.h" +#elif defined(ANGLE_PLATFORM_LINUX) +#include "libANGLE/renderer/vulkan/xcb/DisplayVkXcb.h" +#else +#error Unsupported Vulkan platform. +#endif +#endif // defined(ANGLE_ENABLE_VULKAN) -class DefaultPlatform : public angle::Platform +namespace egl { -public: - DefaultPlatform() {} - ~DefaultPlatform() override {} -}; -DefaultPlatform *defaultPlatform = nullptr; - -void InitDefaultPlatformImpl() +namespace { - if (ANGLEPlatformCurrent() == nullptr) - { - if (defaultPlatform == nullptr) - { - defaultPlatform = new DefaultPlatform(); - } - - ANGLEPlatformInitialize(defaultPlatform); - } -} typedef std::map WindowSurfaceMap; // Get a map of all EGL window surfaces to validate that no window has more than one EGL surface @@ -99,7 +97,7 @@ static DevicePlatformDisplayMap *GetDevicePlatformDisplayMap() return &displays; } -rx::DisplayImpl *CreateDisplayFromDevice(Device *eglDevice) +rx::DisplayImpl *CreateDisplayFromDevice(Device *eglDevice, const DisplayState &state) { rx::DisplayImpl *impl = nullptr; @@ -107,7 +105,7 @@ rx::DisplayImpl *CreateDisplayFromDevice(Device *eglDevice) { #if defined(ANGLE_ENABLE_D3D11) case EGL_D3D11_DEVICE_ANGLE: - impl = new rx::DisplayD3D(); + impl = new rx::DisplayD3D(state); break; #endif #if defined(ANGLE_ENABLE_D3D9) @@ -130,86 +128,162 @@ rx::DisplayImpl *CreateDisplayFromDevice(Device *eglDevice) return impl; } -rx::DisplayImpl *CreateDisplayFromAttribs(const AttributeMap &attribMap) +rx::DisplayImpl *CreateDisplayFromAttribs(const AttributeMap &attribMap, const DisplayState &state) { rx::DisplayImpl *impl = nullptr; - EGLint displayType = attribMap.get(EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE); + EGLAttrib displayType = + attribMap.get(EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE); switch (displayType) { - case EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE: + case EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE: #if defined(ANGLE_ENABLE_D3D9) || defined(ANGLE_ENABLE_D3D11) - // Default to D3D displays - impl = new rx::DisplayD3D(); + // Default to D3D displays + impl = new rx::DisplayD3D(state); #elif defined(ANGLE_USE_X11) - impl = new rx::DisplayGLX(); + impl = new rx::DisplayGLX(state); #elif defined(ANGLE_PLATFORM_APPLE) - impl = new rx::DisplayCGL(); + impl = new rx::DisplayCGL(state); +#elif defined(ANGLE_USE_OZONE) + impl = new rx::DisplayOzone(state); +#elif defined(ANGLE_PLATFORM_ANDROID) + impl = new rx::DisplayAndroid(state); #else - // No display available - UNREACHABLE(); + // No display available + UNREACHABLE(); #endif - break; + break; - case EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE: - case EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE: + 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(); + impl = new rx::DisplayD3D(state); #else - // A D3D display was requested on a platform that doesn't support it - UNREACHABLE(); + // A D3D display was requested on a platform that doesn't support it + UNREACHABLE(); #endif - break; + break; - case EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE: + case EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE: #if defined(ANGLE_ENABLE_OPENGL) #if defined(ANGLE_PLATFORM_WINDOWS) - impl = new rx::DisplayWGL(); + impl = new rx::DisplayWGL(state); #elif defined(ANGLE_USE_X11) - impl = new rx::DisplayGLX(); + impl = new rx::DisplayGLX(state); #elif defined(ANGLE_PLATFORM_APPLE) - impl = new rx::DisplayCGL(); + impl = new rx::DisplayCGL(state); +#elif defined(ANGLE_USE_OZONE) + // This might work but has never been tried, so disallow for now. + impl = nullptr; +#elif defined(ANGLE_PLATFORM_ANDROID) + // No GL support on this platform, fail display creation. + impl = nullptr; #else #error Unsupported OpenGL platform. #endif #else - UNREACHABLE(); -#endif - break; + // No display available + UNREACHABLE(); +#endif // defined(ANGLE_ENABLE_OPENGL) + break; + case EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE: #if defined(ANGLE_ENABLE_OPENGL) - case EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE: #if defined(ANGLE_PLATFORM_WINDOWS) - impl = new rx::DisplayWGL(); + impl = new rx::DisplayWGL(state); #elif defined(ANGLE_USE_X11) - impl = new rx::DisplayGLX(); + impl = new rx::DisplayGLX(state); +#elif defined(ANGLE_USE_OZONE) + impl = new rx::DisplayOzone(state); +#elif defined(ANGLE_PLATFORM_ANDROID) + impl = new rx::DisplayAndroid(state); #else - // No GLES support on this platform, fail display creation. - impl = nullptr; + // No GLES support on this platform, fail display creation. + impl = nullptr; #endif - break; +#endif // defined(ANGLE_ENABLE_OPENGL) + break; + + case EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE: +#if defined(ANGLE_ENABLE_VULKAN) +#if defined(ANGLE_PLATFORM_WINDOWS) + impl = new rx::DisplayVkWin32(state); +#elif defined(ANGLE_PLATFORM_LINUX) + impl = new rx::DisplayVkXcb(state); +#else +#error Unsupported Vulkan platform. #endif +#else + // No display available + UNREACHABLE(); +#endif // defined(ANGLE_ENABLE_VULKAN) + break; - default: - UNREACHABLE(); - break; + case EGL_PLATFORM_ANGLE_TYPE_NULL_ANGLE: +#if defined(ANGLE_ENABLE_NULL) + impl = new rx::DisplayNULL(state); +#else + // No display available + UNREACHABLE(); +#endif // defined(ANGLE_ENABLE_NULL) + break; + + default: + UNREACHABLE(); + break; } return impl; } +void Display_logError(angle::PlatformMethods *platform, const char *errorMessage) +{ + gl::Trace(gl::LOG_ERR, errorMessage); } -Display *Display::GetDisplayFromAttribs(void *native_display, const AttributeMap &attribMap) +void Display_logWarning(angle::PlatformMethods *platform, const char *warningMessage) { - // Initialize the global platform if not already - InitDefaultPlatformImpl(); + gl::Trace(gl::LOG_WARN, warningMessage); +} - Display *display = nullptr; +void Display_logInfo(angle::PlatformMethods *platform, const char *infoMessage) +{ + // Uncomment to get info spam + // gl::Trace(gl::LOG_WARN, infoMessage); +} + +void ANGLESetDefaultDisplayPlatform(angle::EGLDisplayType display) +{ + angle::PlatformMethods *platformMethods = ANGLEPlatformCurrent(); + if (platformMethods->logError != angle::DefaultLogError) + { + // Don't reset pre-set Platform to Default + return; + } + + ANGLEResetDisplayPlatform(display); + platformMethods->logError = Display_logError; + platformMethods->logWarning = Display_logWarning; + platformMethods->logInfo = Display_logInfo; +} + +} // anonymous namespace - EGLNativeDisplayType displayId = reinterpret_cast(native_display); +DisplayState::DisplayState() +{ +} + +DisplayState::~DisplayState() +{ +} - ANGLEPlatformDisplayMap *displays = GetANGLEPlatformDisplayMap(); - ANGLEPlatformDisplayMap::const_iterator iter = displays->find(displayId); +// static +Display *Display::GetDisplayFromNativeDisplay(EGLNativeDisplayType nativeDisplay, + const AttributeMap &attribMap) +{ + Display *display = nullptr; + + ANGLEPlatformDisplayMap *displays = GetANGLEPlatformDisplayMap(); + const auto &iter = displays->find(nativeDisplay); if (iter != displays->end()) { display = iter->second; @@ -218,19 +292,19 @@ Display *Display::GetDisplayFromAttribs(void *native_display, const AttributeMap if (display == nullptr) { // Validate the native display - if (!Display::isValidNativeDisplay(displayId)) + if (!Display::isValidNativeDisplay(nativeDisplay)) { - return NULL; + return nullptr; } - display = new Display(EGL_PLATFORM_ANGLE_ANGLE, displayId, nullptr); - displays->insert(std::make_pair(displayId, display)); + display = new Display(EGL_PLATFORM_ANGLE_ANGLE, nativeDisplay, nullptr); + displays->insert(std::make_pair(nativeDisplay, display)); } // Apply new attributes if the display is not initialized yet. if (!display->isInitialized()) { - rx::DisplayImpl *impl = CreateDisplayFromAttribs(attribMap); + rx::DisplayImpl *impl = CreateDisplayFromAttribs(attribMap, display->getState()); if (impl == nullptr) { // No valid display implementation for these attributes @@ -243,15 +317,12 @@ Display *Display::GetDisplayFromAttribs(void *native_display, const AttributeMap return display; } -Display *Display::GetDisplayFromDevice(void *native_display) +// static +Display *Display::GetDisplayFromDevice(Device *device, const AttributeMap &attribMap) { - // Initialize the global platform if not already - InitDefaultPlatformImpl(); - Display *display = nullptr; - Device *eglDevice = reinterpret_cast(native_display); - ASSERT(Device::IsValidDevice(eglDevice)); + ASSERT(Device::IsValidDevice(device)); ANGLEPlatformDisplayMap *anglePlatformDisplays = GetANGLEPlatformDisplayMap(); DevicePlatformDisplayMap *devicePlatformDisplays = GetDevicePlatformDisplayMap(); @@ -260,7 +331,7 @@ Display *Display::GetDisplayFromDevice(void *native_display) for (auto &displayMapEntry : *anglePlatformDisplays) { egl::Display *iterDisplay = displayMapEntry.second; - if (iterDisplay->getDevice() == eglDevice) + if (iterDisplay->getDevice() == device) { display = iterDisplay; } @@ -269,7 +340,7 @@ Display *Display::GetDisplayFromDevice(void *native_display) if (display == nullptr) { // See if the eglDevice is in use by a Display created using the DEVICE platform - DevicePlatformDisplayMap::const_iterator iter = devicePlatformDisplays->find(eglDevice); + const auto &iter = devicePlatformDisplays->find(device); if (iter != devicePlatformDisplays->end()) { display = iter->second; @@ -279,15 +350,15 @@ Display *Display::GetDisplayFromDevice(void *native_display) if (display == nullptr) { // Otherwise create a new Display - display = new Display(EGL_PLATFORM_DEVICE_EXT, 0, eglDevice); - devicePlatformDisplays->insert(std::make_pair(eglDevice, display)); + display = new Display(EGL_PLATFORM_DEVICE_EXT, 0, device); + devicePlatformDisplays->insert(std::make_pair(device, display)); } // Apply new attributes if the display is not initialized yet. if (!display->isInitialized()) { - rx::DisplayImpl *impl = CreateDisplayFromDevice(eglDevice); - display->setAttributes(impl, egl::AttributeMap()); + rx::DisplayImpl *impl = CreateDisplayFromDevice(device, display->getState()); + display->setAttributes(impl, attribMap); } return display; @@ -299,19 +370,26 @@ Display::Display(EGLenum platform, EGLNativeDisplayType displayId, Device *eglDe mAttributeMap(), mConfigSet(), mContextSet(), + mStreamSet(), mInitialized(false), + mDeviceLost(false), mCaps(), mDisplayExtensions(), mDisplayExtensionString(), mVendorString(), mDevice(eglDevice), - mPlatform(platform) + mPlatform(platform), + mTextureManager(nullptr), + mMemoryProgramCache(gl::kDefaultMaxProgramCacheMemoryBytes), + mGlobalTextureShareGroupUsers(0), + mProxyContext(this) { } Display::~Display() { - terminate(); + // TODO(jmadill): When is this called? + // terminate(); if (mPlatform == EGL_PLATFORM_ANGLE_ANGLE) { @@ -336,6 +414,8 @@ Display::~Display() UNREACHABLE(); } + mProxyContext.reset(nullptr); + SafeDelete(mDevice); SafeDelete(mImplementation); } @@ -353,8 +433,20 @@ void Display::setAttributes(rx::DisplayImpl *impl, const AttributeMap &attribMap Error Display::initialize() { - // Re-initialize default platform if it's needed - InitDefaultPlatformImpl(); + // TODO(jmadill): Store Platform in Display and init here. + const angle::PlatformMethods *platformMethods = + reinterpret_cast( + mAttributeMap.get(EGL_PLATFORM_ANGLE_PLATFORM_METHODS_ANGLEX, 0)); + if (platformMethods != nullptr) + { + *ANGLEPlatformCurrent() = *platformMethods; + } + else + { + ANGLESetDefaultDisplayPlatform(this); + } + + gl::InitializeDebugAnnotations(&mAnnotator); SCOPED_ANGLE_HISTOGRAM_TIMER("GPU.ANGLE.DisplayInitializeMS"); TRACE_EVENT0("gpu.angle", "egl::Display::initialize"); @@ -363,17 +455,14 @@ Error Display::initialize() if (isInitialized()) { - return Error(EGL_SUCCESS); + return NoError(); } Error error = mImplementation->initialize(this); if (error.isError()) { // Log extended error message here - std::stringstream errorStream; - errorStream << "ANGLE Display::initialize error " << error.getID() << ": " - << error.getMessage(); - ANGLEPlatformCurrent()->logError(errorStream.str().c_str()); + ERR() << "ANGLE Display::initialize error " << error.getID() << ": " << error.getMessage(); return error; } @@ -383,7 +472,7 @@ Error Display::initialize() if (mConfigSet.size() == 0) { mImplementation->terminate(); - return Error(EGL_NOT_INITIALIZED); + return EglNotInitialized(); } initDisplayExtensions(); @@ -395,17 +484,8 @@ Error Display::initialize() if (mDisplayExtensions.deviceQuery) { rx::DeviceImpl *impl = nullptr; - error = mImplementation->getDevice(&impl); - if (error.isError()) - { - return error; - } - - error = Device::CreateDevice(this, impl, &mDevice); - if (error.isError()) - { - return error; - } + ANGLE_TRY(mImplementation->getDevice(&impl)); + ANGLE_TRY(Device::CreateDevice(this, impl, &mDevice)); } else { @@ -419,28 +499,45 @@ Error Display::initialize() ASSERT(mDevice != nullptr); } + mProxyContext.reset(nullptr); + gl::Context *proxyContext = new gl::Context(mImplementation, nullptr, nullptr, nullptr, nullptr, + egl::AttributeMap(), mDisplayExtensions); + mProxyContext.reset(proxyContext); + mInitialized = true; - return Error(EGL_SUCCESS); + return NoError(); } -void Display::terminate() +Error Display::terminate() { - makeCurrent(nullptr, nullptr, nullptr); + ANGLE_TRY(makeCurrent(nullptr, nullptr, nullptr)); + + mMemoryProgramCache.clear(); + + mProxyContext.reset(nullptr); while (!mContextSet.empty()) { - destroyContext(*mContextSet.begin()); + ANGLE_TRY(destroyContext(*mContextSet.begin())); } + // The global texture manager should be deleted with the last context that uses it. + ASSERT(mGlobalTextureShareGroupUsers == 0 && mTextureManager == nullptr); + while (!mImageSet.empty()) { destroyImage(*mImageSet.begin()); } - while (!mImplementation->getSurfaceSet().empty()) + while (!mStreamSet.empty()) { - destroySurface(*mImplementation->getSurfaceSet().begin()); + destroyStream(*mStreamSet.begin()); + } + + while (!mState.surfaceSet.empty()) + { + ANGLE_TRY(destroySurface(*mState.surfaceSet.begin())); } mConfigSet.clear(); @@ -454,9 +551,16 @@ void Display::terminate() mImplementation->terminate(); + mDeviceLost = false; + mInitialized = false; - // Never de-init default platform.. terminate is not that final. + gl::UninitializeDebugAnnotations(); + + // TODO(jmadill): Store Platform in Display and deinit here. + ANGLEResetDisplayPlatform(this); + + return NoError(); } std::vector Display::getConfigs(const egl::AttributeMap &attribs) const @@ -464,189 +568,100 @@ std::vector Display::getConfigs(const egl::AttributeMap &attribs) 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_ID: *value = configuration->nativeVisualID; 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; - - case EGL_OPTIMAL_SURFACE_ORIENTATION_ANGLE: - if (!getExtensions().surfaceOrientation) - { - return false; - } - *value = configuration->optimalOrientation; - break; - - default: - return false; - } - - return true; -} - -Error Display::createWindowSurface(const Config *configuration, EGLNativeWindowType window, const AttributeMap &attribs, +Error Display::createWindowSurface(const Config *configuration, + EGLNativeWindowType window, + const AttributeMap &attribs, Surface **outSurface) { if (mImplementation->testDeviceLost()) { - Error error = restoreLostDevice(); - if (error.isError()) - { - return error; - } + ANGLE_TRY(restoreLostDevice()); } - rx::SurfaceImpl *surfaceImpl = mImplementation->createWindowSurface(configuration, window, attribs); - ASSERT(surfaceImpl != nullptr); - - Error error = surfaceImpl->initialize(); - if (error.isError()) - { - SafeDelete(surfaceImpl); - return error; - } + SurfacePointer surface(new WindowSurface(mImplementation, configuration, window, attribs), + this); + ANGLE_TRY(surface->initialize(this)); - Surface *surface = new Surface(surfaceImpl, EGL_WINDOW_BIT, configuration, attribs); - mImplementation->getSurfaceSet().insert(surface); + ASSERT(outSurface != nullptr); + *outSurface = surface.release(); + mState.surfaceSet.insert(*outSurface); WindowSurfaceMap *windowSurfaces = GetWindowSurfaces(); ASSERT(windowSurfaces && windowSurfaces->find(window) == windowSurfaces->end()); - windowSurfaces->insert(std::make_pair(window, surface)); + windowSurfaces->insert(std::make_pair(window, *outSurface)); - ASSERT(outSurface != nullptr); - *outSurface = surface; - return Error(EGL_SUCCESS); + return NoError(); } -Error Display::createPbufferSurface(const Config *configuration, const AttributeMap &attribs, Surface **outSurface) +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 = mImplementation->createPbufferSurface(configuration, attribs); - ASSERT(surfaceImpl != nullptr); - - Error error = surfaceImpl->initialize(); - if (error.isError()) - { - SafeDelete(surfaceImpl); - return error; + ANGLE_TRY(restoreLostDevice()); } - Surface *surface = new Surface(surfaceImpl, EGL_PBUFFER_BIT, configuration, attribs); - mImplementation->getSurfaceSet().insert(surface); + SurfacePointer surface(new PbufferSurface(mImplementation, configuration, attribs), this); + ANGLE_TRY(surface->initialize(this)); ASSERT(outSurface != nullptr); - *outSurface = surface; - return Error(EGL_SUCCESS); + *outSurface = surface.release(); + mState.surfaceSet.insert(*outSurface); + + return NoError(); } -Error Display::createPbufferFromClientBuffer(const Config *configuration, EGLClientBuffer shareHandle, - const AttributeMap &attribs, Surface **outSurface) +Error Display::createPbufferFromClientBuffer(const Config *configuration, + EGLenum buftype, + EGLClientBuffer clientBuffer, + const AttributeMap &attribs, + Surface **outSurface) { ASSERT(isInitialized()); if (mImplementation->testDeviceLost()) { - Error error = restoreLostDevice(); - if (error.isError()) - { - return error; - } - } - - rx::SurfaceImpl *surfaceImpl = mImplementation->createPbufferFromClientBuffer(configuration, shareHandle, attribs); - ASSERT(surfaceImpl != nullptr); - - Error error = surfaceImpl->initialize(); - if (error.isError()) - { - SafeDelete(surfaceImpl); - return error; + ANGLE_TRY(restoreLostDevice()); } - Surface *surface = new Surface(surfaceImpl, EGL_PBUFFER_BIT, configuration, attribs); - mImplementation->getSurfaceSet().insert(surface); + SurfacePointer surface( + new PbufferSurface(mImplementation, configuration, buftype, clientBuffer, attribs), this); + ANGLE_TRY(surface->initialize(this)); ASSERT(outSurface != nullptr); - *outSurface = surface; - return Error(EGL_SUCCESS); + *outSurface = surface.release(); + mState.surfaceSet.insert(*outSurface); + + return NoError(); } -Error Display::createPixmapSurface(const Config *configuration, NativePixmapType nativePixmap, const AttributeMap &attribs, +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; - } + ANGLE_TRY(restoreLostDevice()); } - rx::SurfaceImpl *surfaceImpl = mImplementation->createPixmapSurface(configuration, nativePixmap, attribs); - ASSERT(surfaceImpl != nullptr); - - Error error = surfaceImpl->initialize(); - if (error.isError()) - { - SafeDelete(surfaceImpl); - return error; - } - - Surface *surface = new Surface(surfaceImpl, EGL_PIXMAP_BIT, configuration, attribs); - mImplementation->getSurfaceSet().insert(surface); + SurfacePointer surface(new PixmapSurface(mImplementation, configuration, nativePixmap, attribs), + this); + ANGLE_TRY(surface->initialize(this)); ASSERT(outSurface != nullptr); - *outSurface = surface; - return Error(EGL_SUCCESS); + *outSurface = surface.release(); + mState.surfaceSet.insert(*outSurface); + + return NoError(); } -Error Display::createImage(gl::Context *context, +Error Display::createImage(const gl::Context *context, EGLenum target, EGLClientBuffer buffer, const AttributeMap &attribs, @@ -656,11 +671,7 @@ Error Display::createImage(gl::Context *context, if (mImplementation->testDeviceLost()) { - Error error = restoreLostDevice(); - if (error.isError()) - { - return error; - } + ANGLE_TRY(restoreLostDevice()); } egl::ImageSibling *sibling = nullptr; @@ -678,16 +689,11 @@ Error Display::createImage(gl::Context *context, } ASSERT(sibling != nullptr); - rx::ImageImpl *imageImpl = mImplementation->createImage(target, sibling, attribs); - ASSERT(imageImpl != nullptr); + angle::UniqueObjectPointer imagePtr( + new Image(mImplementation, target, sibling, attribs), context); + ANGLE_TRY(imagePtr->initialize()); - Error error = imageImpl->initialize(); - if (error.isError()) - { - return error; - } - - Image *image = new Image(imageImpl, target, sibling, attribs); + Image *image = imagePtr.release(); ASSERT(outImage != nullptr); *outImage = image; @@ -696,49 +702,92 @@ Error Display::createImage(gl::Context *context, image->addRef(); mImageSet.insert(image); - return Error(EGL_SUCCESS); + return NoError(); +} + +Error Display::createStream(const AttributeMap &attribs, Stream **outStream) +{ + ASSERT(isInitialized()); + + Stream *stream = new Stream(this, attribs); + + ASSERT(stream != nullptr); + mStreamSet.insert(stream); + + ASSERT(outStream != nullptr); + *outStream = stream; + + return NoError(); } -Error Display::createContext(const Config *configuration, gl::Context *shareContext, const AttributeMap &attribs, +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()) + ANGLE_TRY(restoreLostDevice()); + } + + // This display texture sharing will allow the first context to create the texture share group. + bool usingDisplayTextureShareGroup = + attribs.get(EGL_DISPLAY_TEXTURE_SHARE_GROUP_ANGLE, EGL_FALSE) == EGL_TRUE; + gl::TextureManager *shareTextures = nullptr; + + if (usingDisplayTextureShareGroup) + { + ASSERT((mTextureManager == nullptr) == (mGlobalTextureShareGroupUsers == 0)); + if (mTextureManager == nullptr) { - return error; + mTextureManager = new gl::TextureManager(); } + + mGlobalTextureShareGroupUsers++; + shareTextures = mTextureManager; } - gl::Context *context = *outContext = - mImplementation->createContext(configuration, shareContext, attribs); + gl::MemoryProgramCache *cachePointer = &mMemoryProgramCache; + + // Check context creation attributes to see if we should enable the cache. + if (mAttributeMap.get(EGL_CONTEXT_PROGRAM_BINARY_CACHE_ENABLED_ANGLE, EGL_TRUE) == EGL_FALSE) + { + cachePointer = nullptr; + } + + // A program cache size of zero indicates it should be disabled. + if (mMemoryProgramCache.maxSize() == 0) + { + cachePointer = nullptr; + } + + gl::Context *context = + new gl::Context(mImplementation, configuration, shareContext, shareTextures, cachePointer, + attribs, mDisplayExtensions); ASSERT(context != nullptr); mContextSet.insert(context); ASSERT(outContext != nullptr); *outContext = context; - return Error(EGL_SUCCESS); + return NoError(); } -Error Display::makeCurrent(egl::Surface *drawSurface, egl::Surface *readSurface, gl::Context *context) +Error Display::makeCurrent(egl::Surface *drawSurface, + egl::Surface *readSurface, + gl::Context *context) { - Error error = mImplementation->makeCurrent(drawSurface, readSurface, context); - if (error.isError()) - { - return error; - } + ANGLE_TRY(mImplementation->makeCurrent(drawSurface, readSurface, context)); - if (context != nullptr && drawSurface != nullptr) + if (context != nullptr) { ASSERT(readSurface == drawSurface); - context->makeCurrent(drawSurface); + ANGLE_TRY(context->makeCurrent(this, drawSurface)); } - return egl::Error(EGL_SUCCESS); + return NoError(); } Error Display::restoreLostDevice() @@ -748,14 +797,14 @@ Error Display::restoreLostDevice() if ((*ctx)->isResetNotificationEnabled()) { // If reset notifications have been requested, application must delete all contexts first - return Error(EGL_CONTEXT_LOST); + return EglContextLost(); } } - return mImplementation->restoreLostDevice(); + return mImplementation->restoreLostDevice(this); } -void Display::destroySurface(Surface *surface) +Error Display::destroySurface(Surface *surface) { if (surface->getType() == EGL_WINDOW_BIT) { @@ -774,54 +823,89 @@ void Display::destroySurface(Surface *surface) } ASSERT(surfaceRemoved); - UNUSED_ASSERTION_VARIABLE(surfaceRemoved); } - mImplementation->destroySurface(surface); + mState.surfaceSet.erase(surface); + ANGLE_TRY(surface->onDestroy(this)); + return NoError(); } void Display::destroyImage(egl::Image *image) { auto iter = mImageSet.find(image); ASSERT(iter != mImageSet.end()); - (*iter)->release(); + (*iter)->release(mProxyContext.get()); mImageSet.erase(iter); } -void Display::destroyContext(gl::Context *context) +void Display::destroyStream(egl::Stream *stream) { + mStreamSet.erase(stream); + SafeDelete(stream); +} + +Error Display::destroyContext(gl::Context *context) +{ + if (context->usingDisplayTextureShareGroup()) + { + ASSERT(mGlobalTextureShareGroupUsers >= 1 && mTextureManager != nullptr); + if (mGlobalTextureShareGroupUsers == 1) + { + // If this is the last context using the global share group, destroy the global texture + // manager so that the textures can be destroyed while a context still exists + mTextureManager->release(context); + mTextureManager = nullptr; + } + mGlobalTextureShareGroupUsers--; + } + + ANGLE_TRY(context->onDestroy(this)); mContextSet.erase(context); SafeDelete(context); + return NoError(); } bool Display::isDeviceLost() const { ASSERT(isInitialized()); - return mImplementation->isDeviceLost(); + return mDeviceLost; } bool Display::testDeviceLost() { ASSERT(isInitialized()); - return mImplementation->testDeviceLost(); + + if (!mDeviceLost && mImplementation->testDeviceLost()) + { + notifyDeviceLost(); + } + + return mDeviceLost; } void Display::notifyDeviceLost() { + if (mDeviceLost) + { + return; + } + for (ContextSet::iterator context = mContextSet.begin(); context != mContextSet.end(); context++) { (*context)->markContextLost(); } + + mDeviceLost = true; } -Error Display::waitClient() const +Error Display::waitClient(const gl::Context *context) const { - return mImplementation->waitClient(); + return mImplementation->waitClient(context); } -Error Display::waitNative(EGLint engine, egl::Surface *drawSurface, egl::Surface *readSurface) const +Error Display::waitNative(const gl::Context *context, EGLint engine) const { - return mImplementation->waitNative(engine, drawSurface, readSurface); + return mImplementation->waitNative(context, engine); } const Caps &Display::getCaps() const @@ -839,14 +923,14 @@ bool Display::isValidConfig(const Config *config) const return mConfigSet.contains(config); } -bool Display::isValidContext(gl::Context *context) const +bool Display::isValidContext(const gl::Context *context) const { - return mContextSet.find(context) != mContextSet.end(); + return mContextSet.find(const_cast(context)) != mContextSet.end(); } -bool Display::isValidSurface(Surface *surface) const +bool Display::isValidSurface(const Surface *surface) const { - return mImplementation->getSurfaceSet().find(surface) != mImplementation->getSurfaceSet().end(); + return mState.surfaceSet.find(const_cast(surface)) != mState.surfaceSet.end(); } bool Display::isValidImage(const Image *image) const @@ -854,6 +938,11 @@ bool Display::isValidImage(const Image *image) const return mImageSet.find(const_cast(image)) != mImageSet.end(); } +bool Display::isValidStream(const Stream *stream) const +{ + return mStreamSet.find(const_cast(stream)) != mStreamSet.end(); +} + bool Display::hasExistingWindowSurface(EGLNativeWindowType window) { WindowSurfaceMap *windowSurfaces = GetWindowSurfaces(); @@ -879,12 +968,20 @@ static ClientExtensions GenerateClientExtensions() extensions.platformANGLEOpenGL = true; #endif +#if defined(ANGLE_ENABLE_NULL) + extensions.platformANGLENULL = true; +#endif + #if defined(ANGLE_ENABLE_D3D11) extensions.deviceCreation = true; extensions.deviceCreationD3D11 = true; extensions.experimentalPresentPath = true; #endif +#if defined(ANGLE_ENABLE_VULKAN) + extensions.platformANGLEVulkan = true; +#endif + #if defined(ANGLE_USE_X11) extensions.x11Visual = true; #endif @@ -904,15 +1001,18 @@ static std::string GenerateExtensionsString(const T &extensions) return stream.str(); } -const ClientExtensions &Display::getClientExtensions() +// static +const ClientExtensions &Display::GetClientExtensions() { static const ClientExtensions clientExtensions = GenerateClientExtensions(); return clientExtensions; } -const std::string &Display::getClientExtensionString() +// static +const std::string &Display::GetClientExtensionString() { - static const std::string clientExtensionsString = GenerateExtensionsString(getClientExtensions()); + static const std::string clientExtensionsString = + GenerateExtensionsString(GetClientExtensions()); return clientExtensionsString; } @@ -920,9 +1020,20 @@ void Display::initDisplayExtensions() { mDisplayExtensions = mImplementation->getExtensions(); + // Some extensions are always available because they are implemented in the EGL layer. + mDisplayExtensions.createContext = true; + mDisplayExtensions.createContextNoError = true; + mDisplayExtensions.createContextWebGLCompatibility = true; + mDisplayExtensions.createContextBindGeneratesResource = true; + mDisplayExtensions.createContextClientArrays = true; + mDisplayExtensions.pixelFormatFloat = true; + // Force EGL_KHR_get_all_proc_addresses on. mDisplayExtensions.getAllProcAddresses = true; + // Enable program cache control since it is not back-end dependent. + mDisplayExtensions.programCacheControl = true; + mDisplayExtensionString = GenerateExtensionsString(mDisplayExtensions); } @@ -931,6 +1042,14 @@ bool Display::isValidNativeWindow(EGLNativeWindowType window) const return mImplementation->isValidNativeWindow(window); } +Error Display::validateClientBuffer(const Config *configuration, + EGLenum buftype, + EGLClientBuffer clientBuffer, + const AttributeMap &attribs) +{ + return mImplementation->validateClientBuffer(configuration, buftype, clientBuffer, attribs); +} + bool Display::isValidDisplay(const egl::Display *display) { const ANGLEPlatformDisplayMap *anglePlatformDisplayMap = GetANGLEPlatformDisplayMap(); @@ -969,7 +1088,7 @@ bool Display::isValidNativeDisplay(EGLNativeDisplayType display) { return true; } - return (WindowFromDC(display) != NULL); + return (WindowFromDC(display) != nullptr); #else return true; #endif @@ -1000,4 +1119,105 @@ Device *Display::getDevice() const return mDevice; } +gl::Version Display::getMaxSupportedESVersion() const +{ + return mImplementation->getMaxSupportedESVersion(); } + +EGLint Display::programCacheGetAttrib(EGLenum attrib) const +{ + switch (attrib) + { + case EGL_PROGRAM_CACHE_KEY_LENGTH_ANGLE: + return static_cast(gl::kProgramHashLength); + + case EGL_PROGRAM_CACHE_SIZE_ANGLE: + return static_cast(mMemoryProgramCache.entryCount()); + + default: + UNREACHABLE(); + return 0; + } +} + +Error Display::programCacheQuery(EGLint index, + void *key, + EGLint *keysize, + void *binary, + EGLint *binarysize) +{ + ASSERT(index >= 0 && index < static_cast(mMemoryProgramCache.entryCount())); + + const angle::MemoryBuffer *programBinary = nullptr; + gl::ProgramHash programHash; + // TODO(jmadill): Make this thread-safe. + bool result = + mMemoryProgramCache.getAt(static_cast(index), &programHash, &programBinary); + if (!result) + { + return EglBadAccess() << "Program binary not accessible."; + } + + ASSERT(keysize && binarysize); + + if (key) + { + ASSERT(*keysize == static_cast(gl::kProgramHashLength)); + memcpy(key, programHash.data(), gl::kProgramHashLength); + } + + if (binary) + { + // Note: we check the size here instead of in the validation code, since we need to + // access the cache as atomically as possible. It's possible that the cache contents + // could change between the validation size check and the retrieval. + if (programBinary->size() > static_cast(*binarysize)) + { + return EglBadAccess() << "Program binary too large or changed during access."; + } + + memcpy(binary, programBinary->data(), programBinary->size()); + } + + *binarysize = static_cast(programBinary->size()); + *keysize = static_cast(gl::kProgramHashLength); + + return NoError(); +} + +Error Display::programCachePopulate(const void *key, + EGLint keysize, + const void *binary, + EGLint binarysize) +{ + ASSERT(keysize == static_cast(gl::kProgramHashLength)); + + gl::ProgramHash programHash; + memcpy(programHash.data(), key, gl::kProgramHashLength); + + mMemoryProgramCache.putBinary(programHash, reinterpret_cast(binary), + static_cast(binarysize)); + return NoError(); +} + +EGLint Display::programCacheResize(EGLint limit, EGLenum mode) +{ + switch (mode) + { + case EGL_PROGRAM_CACHE_RESIZE_ANGLE: + { + size_t initialSize = mMemoryProgramCache.size(); + mMemoryProgramCache.resize(static_cast(limit)); + return static_cast(initialSize); + } + + case EGL_PROGRAM_CACHE_TRIM_ANGLE: + return static_cast(mMemoryProgramCache.trim(static_cast(limit))); + + default: + UNREACHABLE(); + return 0; + } +} + +} // namespace egl diff --git a/src/3rdparty/angle/src/libANGLE/Display.h b/src/3rdparty/angle/src/libANGLE/Display.h index f80e308347..aa1d1c3b37 100644 --- a/src/3rdparty/angle/src/libANGLE/Display.h +++ b/src/3rdparty/angle/src/libANGLE/Display.h @@ -14,15 +14,18 @@ #include #include -#include "libANGLE/Error.h" +#include "libANGLE/AttributeMap.h" #include "libANGLE/Caps.h" #include "libANGLE/Config.h" -#include "libANGLE/AttributeMap.h" -#include "libANGLE/renderer/Renderer.h" +#include "libANGLE/Error.h" +#include "libANGLE/LoggingAnnotator.h" +#include "libANGLE/MemoryProgramCache.h" +#include "libANGLE/Version.h" namespace gl { class Context; +class TextureManager; } namespace rx @@ -35,6 +38,21 @@ namespace egl class Device; class Image; class Surface; +class Stream; +class Thread; + +using SurfaceSet = std::set; + +struct DisplayState final : private angle::NonCopyable +{ + DisplayState(); + ~DisplayState(); + + SurfaceSet surfaceSet; +}; + +// Constant coded here as a sanity limit. +constexpr EGLAttrib kProgramCacheSizeAbsoluteMax = 0x4000000; class Display final : angle::NonCopyable { @@ -42,48 +60,68 @@ class Display final : angle::NonCopyable ~Display(); Error initialize(); - void terminate(); + Error terminate(); - static egl::Display *GetDisplayFromDevice(void *native_display); - static egl::Display *GetDisplayFromAttribs(void *native_display, const AttributeMap &attribMap); + static Display *GetDisplayFromDevice(Device *device, const AttributeMap &attribMap); + static Display *GetDisplayFromNativeDisplay(EGLNativeDisplayType nativeDisplay, + const AttributeMap &attribMap); - static const ClientExtensions &getClientExtensions(); - static const std::string &getClientExtensionString(); + 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); + std::vector getConfigs(const AttributeMap &attribs) const; - Error createWindowSurface(const Config *configuration, EGLNativeWindowType window, const AttributeMap &attribs, + 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, + Error createPbufferSurface(const Config *configuration, + const AttributeMap &attribs, + Surface **outSurface); + Error createPbufferFromClientBuffer(const Config *configuration, + EGLenum buftype, + EGLClientBuffer clientBuffer, + const AttributeMap &attribs, Surface **outSurface); - Error createPixmapSurface(const Config *configuration, NativePixmapType nativePixmap, const AttributeMap &attribs, + Error createPixmapSurface(const Config *configuration, + NativePixmapType nativePixmap, + const AttributeMap &attribs, Surface **outSurface); - Error createImage(gl::Context *context, + Error createImage(const gl::Context *context, EGLenum target, EGLClientBuffer buffer, const AttributeMap &attribs, Image **outImage); - Error createContext(const Config *configuration, gl::Context *shareContext, const AttributeMap &attribs, + Error createStream(const AttributeMap &attribs, Stream **outStream); + + 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); + Error makeCurrent(Surface *drawSurface, Surface *readSurface, gl::Context *context); - void destroySurface(egl::Surface *surface); - void destroyImage(egl::Image *image); - void destroyContext(gl::Context *context); + Error destroySurface(Surface *surface); + void destroyImage(Image *image); + void destroyStream(Stream *stream); + Error 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 isValidContext(const gl::Context *context) const; + bool isValidSurface(const Surface *surface) const; bool isValidImage(const Image *image) const; + bool isValidStream(const Stream *stream) const; bool isValidNativeWindow(EGLNativeWindowType window) const; - static bool isValidDisplay(const egl::Display *display); + Error validateClientBuffer(const Config *configuration, + EGLenum buftype, + EGLClientBuffer clientBuffer, + const AttributeMap &attribs); + + static bool isValidDisplay(const Display *display); static bool isValidNativeDisplay(EGLNativeDisplayType display); static bool hasExistingWindowSurface(EGLNativeWindowType window); @@ -91,8 +129,8 @@ class Display final : angle::NonCopyable bool testDeviceLost(); void notifyDeviceLost(); - Error waitClient() const; - Error waitNative(EGLint engine, egl::Surface *drawSurface, egl::Surface *readSurface) const; + Error waitClient(const gl::Context *context) const; + Error waitNative(const gl::Context *context, EGLint engine) const; const Caps &getCaps() const; @@ -100,13 +138,31 @@ class Display final : angle::NonCopyable const std::string &getExtensionString() const; const std::string &getVendorString() const; + EGLint programCacheGetAttrib(EGLenum attrib) const; + Error programCacheQuery(EGLint index, + void *key, + EGLint *keysize, + void *binary, + EGLint *binarysize); + Error programCachePopulate(const void *key, + EGLint keysize, + const void *binary, + EGLint binarysize); + EGLint programCacheResize(EGLint limit, EGLenum mode); + const AttributeMap &getAttributeMap() const { return mAttributeMap; } EGLNativeDisplayType getNativeDisplayId() const { return mDisplayId; } - rx::DisplayImpl *getImplementation() { return mImplementation; } + rx::DisplayImpl *getImplementation() const { return mImplementation; } Device *getDevice() const; EGLenum getPlatform() const { return mPlatform; } + gl::Version getMaxSupportedESVersion() const; + + const DisplayState &getState() const { return mState; } + + gl::Context *getProxyContext() const { return mProxyContext.get(); } + private: Display(EGLenum platform, EGLNativeDisplayType displayId, Device *eglDevice); @@ -117,6 +173,7 @@ class Display final : angle::NonCopyable void initDisplayExtensions(); void initVendorString(); + DisplayState mState; rx::DisplayImpl *mImplementation; EGLNativeDisplayType mDisplayId; @@ -130,7 +187,11 @@ class Display final : angle::NonCopyable typedef std::set ImageSet; ImageSet mImageSet; + typedef std::set StreamSet; + StreamSet mStreamSet; + bool mInitialized; + bool mDeviceLost; Caps mCaps; @@ -141,8 +202,17 @@ class Display final : angle::NonCopyable Device *mDevice; EGLenum mPlatform; + angle::LoggingAnnotator mAnnotator; + + gl::TextureManager *mTextureManager; + gl::MemoryProgramCache mMemoryProgramCache; + size_t mGlobalTextureShareGroupUsers; + + // This gl::Context is a simple proxy to the Display for the GL back-end entry points + // that need access to implementation-specific data, like a Renderer object. + angle::UniqueObjectPointer mProxyContext; }; -} +} // namespace egl #endif // LIBANGLE_DISPLAY_H_ diff --git a/src/3rdparty/angle/src/libANGLE/Error.cpp b/src/3rdparty/angle/src/libANGLE/Error.cpp index fed1594972..388f0259fa 100644 --- a/src/3rdparty/angle/src/libANGLE/Error.cpp +++ b/src/3rdparty/angle/src/libANGLE/Error.cpp @@ -10,35 +10,38 @@ #include "libANGLE/Error.h" #include "common/angleutils.h" +#include "common/debug.h" +#include "common/utilities.h" #include +namespace +{ +std::unique_ptr EmplaceErrorString(std::string &&message) +{ + return message.empty() ? std::unique_ptr() + : std::unique_ptr(new std::string(std::move(message))); +} +} // anonymous namespace + namespace gl { -Error::Error(GLenum errorCode, const char *msg, ...) : mCode(errorCode), mID(errorCode) +Error::Error(GLenum errorCode, std::string &&message) + : mCode(errorCode), mID(errorCode), mMessage(EmplaceErrorString(std::move(message))) { - va_list vararg; - va_start(vararg, msg); - createMessageString(); - *mMessage = FormatString(msg, vararg); - va_end(vararg); } -Error::Error(GLenum errorCode, GLuint id, const char *msg, ...) : mCode(errorCode), mID(id) +Error::Error(GLenum errorCode, GLuint id, std::string &&message) + : mCode(errorCode), mID(id), mMessage(EmplaceErrorString(std::move(message))) { - va_list vararg; - va_start(vararg, msg); - createMessageString(); - *mMessage = FormatString(msg, vararg); - va_end(vararg); } void Error::createMessageString() const { if (!mMessage) { - mMessage.reset(new std::string); + mMessage.reset(new std::string(GetGenericErrorMessage(mCode))); } } @@ -64,34 +67,32 @@ bool Error::operator!=(const Error &other) const { return !(*this == other); } + +std::ostream &operator<<(std::ostream &os, const Error &err) +{ + return gl::FmtHexShort(os, err.getCode()); } +} // namespace gl + namespace egl { -Error::Error(EGLint errorCode, const char *msg, ...) : mCode(errorCode), mID(0) +Error::Error(EGLint errorCode, std::string &&message) + : mCode(errorCode), mID(errorCode), mMessage(EmplaceErrorString(std::move(message))) { - 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) +Error::Error(EGLint errorCode, EGLint id, std::string &&message) + : mCode(errorCode), mID(id), mMessage(EmplaceErrorString(std::move(message))) { - va_list vararg; - va_start(vararg, msg); - createMessageString(); - *mMessage = FormatString(msg, vararg); - va_end(vararg); } void Error::createMessageString() const { if (!mMessage) { - mMessage.reset(new std::string); + mMessage.reset(new std::string(GetGenericErrorMessage(mCode))); } } @@ -101,4 +102,9 @@ const std::string &Error::getMessage() const return *mMessage; } +std::ostream &operator<<(std::ostream &os, const Error &err) +{ + return gl::FmtHexShort(os, err.getCode()); } + +} // namespace egl diff --git a/src/3rdparty/angle/src/libANGLE/Error.h b/src/3rdparty/angle/src/libANGLE/Error.h index a5f760956a..1d57bb8707 100644 --- a/src/3rdparty/angle/src/libANGLE/Error.h +++ b/src/3rdparty/angle/src/libANGLE/Error.h @@ -9,23 +9,89 @@ #ifndef LIBANGLE_ERROR_H_ #define LIBANGLE_ERROR_H_ -#include "angle_gl.h" #include +#include +#include "angle_gl.h" +#include "common/angleutils.h" +#include "common/debug.h" -#include #include +#include +#include + +namespace angle +{ +template +class ANGLE_NO_DISCARD ErrorOrResultBase +{ + public: + ErrorOrResultBase(const ErrorT &error) : mError(error) {} + ErrorOrResultBase(ErrorT &&error) : mError(std::move(error)) {} + + ErrorOrResultBase(ResultT &&result) : mError(NoErrorVal), mResult(std::forward(result)) + { + } + + ErrorOrResultBase(const ResultT &result) : mError(NoErrorVal), mResult(result) {} + + bool isError() const { return mError.isError(); } + const ErrorT &getError() const { return mError; } + ResultT &&getResult() { return std::move(mResult); } + + private: + ErrorT mError; + ResultT mResult; +}; + +template +class ErrorStreamBase : angle::NonCopyable +{ + public: + ErrorStreamBase() : mID(EnumT) {} + ErrorStreamBase(GLuint id) : mID(id) {} + + template + ErrorStreamBase &operator<<(T value) + { + mErrorStream << value; + return *this; + } + + operator ErrorT() { return ErrorT(EnumT, mID, mErrorStream.str()); } + + template + operator ErrorOrResultBase() + { + return static_cast(*this); + } + + private: + GLuint mID; + std::ostringstream mErrorStream; +}; +} // namespace angle + +namespace egl +{ +class Error; +} // namespace egl namespace gl { -class Error final +class ANGLE_NO_DISCARD Error final { public: explicit inline Error(GLenum errorCode); - Error(GLenum errorCode, const char *msg, ...); - Error(GLenum errorCode, GLuint id, const char *msg, ...); + Error(GLenum errorCode, std::string &&message); + Error(GLenum errorCode, GLuint id, std::string &&message); inline Error(const Error &other); inline Error(Error &&other); + inline ~Error() = default; + + // automatic error type conversion + inline Error(egl::Error &&eglErr); + inline Error(egl::Error eglErr); inline Error &operator=(const Error &other); inline Error &operator=(Error &&other); @@ -43,40 +109,60 @@ class Error final private: void createMessageString() const; + friend std::ostream &operator<<(std::ostream &os, const Error &err); + friend class egl::Error; + GLenum mCode; GLuint mID; mutable std::unique_ptr mMessage; }; -template -class ErrorOrResult +template +using ErrorOrResult = angle::ErrorOrResultBase; + +namespace priv { - public: - ErrorOrResult(const gl::Error &error) : mError(error) {} - ErrorOrResult(T &&result) : mError(GL_NO_ERROR), mResult(std::move(result)) {} - bool isError() const { return mError.isError(); } - const gl::Error &getError() const { return mError; } - T &&getResult() { return std::move(mResult); } +template +using ErrorStream = angle::ErrorStreamBase; - private: - Error mError; - T mResult; -}; +} // namespace priv + +using InternalError = priv::ErrorStream; + +using InvalidEnum = priv::ErrorStream; +using InvalidValue = priv::ErrorStream; +using InvalidOperation = priv::ErrorStream; +using StackOverflow = priv::ErrorStream; +using StackUnderflow = priv::ErrorStream; +using OutOfMemory = priv::ErrorStream; +using InvalidFramebufferOperation = priv::ErrorStream; + +inline Error NoError() +{ + return Error(GL_NO_ERROR); +} + +using LinkResult = ErrorOrResult; } // namespace gl namespace egl { -class Error final +class ANGLE_NO_DISCARD Error final { public: explicit inline Error(EGLint errorCode); - Error(EGLint errorCode, const char *msg, ...); - Error(EGLint errorCode, EGLint id, const char *msg, ...); + Error(EGLint errorCode, std::string &&message); + Error(EGLint errorCode, EGLint id, std::string &&message); inline Error(const Error &other); inline Error(Error &&other); + inline ~Error() = default; + + // automatic error type conversion + inline Error(gl::Error &&glErr); + inline Error(gl::Error glErr); inline Error &operator=(const Error &other); inline Error &operator=(Error &&other); @@ -90,13 +176,92 @@ class Error final private: void createMessageString() const; + friend std::ostream &operator<<(std::ostream &os, const Error &err); + friend class gl::Error; + EGLint mCode; EGLint mID; mutable std::unique_ptr mMessage; }; +template +using ErrorOrResult = angle::ErrorOrResultBase; + +namespace priv +{ + +template +using ErrorStream = angle::ErrorStreamBase; + +} // namespace priv + +using EglNotInitialized = priv::ErrorStream; +using EglBadAccess = priv::ErrorStream; +using EglBadAlloc = priv::ErrorStream; +using EglBadAttribute = priv::ErrorStream; +using EglBadConfig = priv::ErrorStream; +using EglBadContext = priv::ErrorStream; +using EglBadCurrentSurface = priv::ErrorStream; +using EglBadDisplay = priv::ErrorStream; +using EglBadMatch = priv::ErrorStream; +using EglBadNativeWindow = priv::ErrorStream; +using EglBadParameter = priv::ErrorStream; +using EglBadSurface = priv::ErrorStream; +using EglContextLost = priv::ErrorStream; +using EglBadStream = priv::ErrorStream; +using EglBadState = priv::ErrorStream; +using EglBadDevice = priv::ErrorStream; + +inline Error NoError() +{ + return Error(EGL_SUCCESS); +} + } // namespace egl +#define ANGLE_CONCAT1(x, y) x##y +#define ANGLE_CONCAT2(x, y) ANGLE_CONCAT1(x, y) +#define ANGLE_LOCAL_VAR ANGLE_CONCAT2(_localVar, __LINE__) + +#define ANGLE_TRY_TEMPLATE(EXPR, FUNC) \ + { \ + auto ANGLE_LOCAL_VAR = EXPR; \ + if (ANGLE_LOCAL_VAR.isError()) \ + { \ + FUNC(ANGLE_LOCAL_VAR); \ + } \ + } \ + ANGLE_EMPTY_STATEMENT + +#define ANGLE_RETURN(X) return X; +#define ANGLE_TRY(EXPR) ANGLE_TRY_TEMPLATE(EXPR, ANGLE_RETURN); + +#define ANGLE_TRY_RESULT(EXPR, RESULT) \ + { \ + auto ANGLE_LOCAL_VAR = EXPR; \ + if (ANGLE_LOCAL_VAR.isError()) \ + { \ + return ANGLE_LOCAL_VAR.getError(); \ + } \ + RESULT = ANGLE_LOCAL_VAR.getResult(); \ + } \ + ANGLE_EMPTY_STATEMENT + +// TODO(jmadill): Introduce way to store errors to a const Context. +#define ANGLE_SWALLOW_ERR(EXPR) \ + { \ + auto ANGLE_LOCAL_VAR = EXPR; \ + if (ANGLE_LOCAL_VAR.isError()) \ + { \ + ERR() << "Unhandled internal error: " << ANGLE_LOCAL_VAR; \ + } \ + } \ + ANGLE_EMPTY_STATEMENT + +#undef ANGLE_LOCAL_VAR +#undef ANGLE_CONCAT2 +#undef ANGLE_CONCAT1 + #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 index 900fc5fd03..4632830ce0 100644 --- a/src/3rdparty/angle/src/libANGLE/Error.inl +++ b/src/3rdparty/angle/src/libANGLE/Error.inl @@ -37,6 +37,21 @@ Error::Error(Error &&other) { } +// automatic error type conversion +Error::Error(egl::Error &&eglErr) + : mCode(GL_INVALID_OPERATION), + mID(0), + mMessage(std::move(eglErr.mMessage)) +{ +} + +Error::Error(egl::Error eglErr) + : mCode(GL_INVALID_OPERATION), + mID(0), + mMessage(std::move(eglErr.mMessage)) +{ +} + Error &Error::operator=(const Error &other) { mCode = other.mCode; @@ -82,7 +97,7 @@ bool Error::isError() const return (mCode != GL_NO_ERROR); } -} +} // namespace gl namespace egl { @@ -111,6 +126,21 @@ Error::Error(Error &&other) { } +// automatic error type conversion +Error::Error(gl::Error &&glErr) + : mCode(EGL_BAD_ACCESS), + mID(0), + mMessage(std::move(glErr.mMessage)) +{ +} + +Error::Error(gl::Error glErr) + : mCode(EGL_BAD_ACCESS), + mID(0), + mMessage(std::move(glErr.mMessage)) +{ +} + Error &Error::operator=(const Error &other) { mCode = other.mCode; diff --git a/src/3rdparty/angle/src/libANGLE/ErrorStrings.h b/src/3rdparty/angle/src/libANGLE/ErrorStrings.h new file mode 100644 index 0000000000..93d64482d9 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/ErrorStrings.h @@ -0,0 +1,173 @@ +// +// Copyright (c) 2017 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. +// + +// ErrorStrings.h: Contains mapping of commonly used error messages + +#ifndef LIBANGLE_ERRORSTRINGS_H_ +#define LIBANGLE_ERRORSTRINGS_H_ + +#define ERRMSG(name, message) \ + static const constexpr char *kError##name = static_cast(message); +#define ANGLE_VALIDATION_ERR(context, error, errorName) \ + context->handleError(error << kError##errorName) + +namespace gl +{ +ERRMSG(BufferNotBound, "A buffer must be bound."); +ERRMSG(CompressedTextureDimensionsMustMatchData, + "Compressed texture dimensions must exactly match the dimensions of the data passed in."); +ERRMSG(CompressedTexturesNotAttachable, "Compressed textures cannot be attached to a framebuffer."); +ERRMSG(CubemapFacesEqualDimensions, "Each cubemap face must have equal width and height."); +ERRMSG(CubemapIncomplete, + "Texture is not cubemap complete. All cubemaps faces must be defined and be the same size."); +ERRMSG(DefaultFramebufferInvalidAttachment, + "Invalid attachment when the default framebuffer is bound."); +ERRMSG(DefaultFramebufferTarget, "It is invalid to change default FBO's attachments"); +ERRMSG(EnumNotSupported, "Enum is not currently supported."); +ERRMSG(EnumRequiresGLES31, "Enum requires GLES 3.1"); +ERRMSG(ES31Required, "OpenGL ES 3.1 Required"); +ERRMSG(ES3Required, "OpenGL ES 3.0 Required."); +ERRMSG(ExceedsMaxElement, "Element value exceeds maximum element index."); +ERRMSG(ExpectedProgramName, "Expected a program name, but found a shader name."); +ERRMSG(ExpectedShaderName, "Expected a shader name, but found a program name."); +ERRMSG(ExtensionNotEnabled, "Extension is not enabled."); +ERRMSG(FeedbackLoop, "Feedback loop formed between Framebuffer and active Texture."); +ERRMSG(FramebufferIncompleteAttachment, + "Attachment type must be compatible with attachment object."); +ERRMSG(GenerateMipmapNotAllowed, "Texture format does not support mipmap generation."); +ERRMSG(IndexExceedsMaxActiveUniform, "Index exceeds program active uniform count."); +ERRMSG(IndexExceedsMaxDrawBuffer, "Index exceeds MAX_DRAW_BUFFERS."); +ERRMSG(IndexExceedsMaxVertexAttribute, "Index exceeds MAX_VERTEX_ATTRIBS."); +ERRMSG(InsufficientBufferSize, "Insufficient buffer size."); +ERRMSG(InsufficientVertexBufferSize, "Vertex buffer is not big enough for the draw call"); +ERRMSG(IntegerOverflow, "Integer overflow."); +ERRMSG(InvalidAttachment, "Invalid Attachment Type."); +ERRMSG(InvalidBlendEquation, "Invalid blend equation."); +ERRMSG(InvalidBlendFunction, "Invalid blend function."); +ERRMSG(InvalidBorder, "Border must be 0."); +ERRMSG(InvalidBufferTypes, "Invalid buffer target enum."); +ERRMSG(InvalidBufferUsage, "Invalid buffer usage enum."); +ERRMSG(InvalidClearMask, "Invalid mask bits."); +ERRMSG(InvalidConstantColor, + "CONSTANT_COLOR (or ONE_MINUS_CONSTANT_COLOR) and CONSTANT_ALPHA (or " + "ONE_MINUS_CONSTANT_ALPHA) cannot be used together as source and destination factors in the " + "blend function."); +ERRMSG(InvalidCoverMode, "Invalid cover mode."); +ERRMSG(InvalidCullMode, "Cull mode not recognized."); +ERRMSG(InvalidDebugSeverity, "Invalid debug severity."); +ERRMSG(InvalidDebugSource, "Invalid debug source."); +ERRMSG(InvalidDebugType, "Invalid debug type."); +ERRMSG(InvalidDepthRange, "Near value cannot be greater than far."); +ERRMSG(InvalidDrawMode, "Invalid draw mode."); +ERRMSG(InvalidDrawModeTransformFeedback, + "Draw mode must match current transform feedback object's draw mode."); +ERRMSG(InvalidFillMode, "Invalid fill mode."); +ERRMSG(InvalidFilterTexture, "Texture only supports NEAREST and LINEAR filtering."); +ERRMSG(InvalidFormat, "Invalid format."); +ERRMSG(InvalidFramebufferTarget, "Invalid framebuffer target."); +ERRMSG(InvalidFramebufferTextureLevel, "Mipmap level must be 0 when attaching a texture."); +ERRMSG(InvalidFramebufferAttachmentParameter, "Invalid parameter name for framebuffer attachment."); +ERRMSG(InvalidInternalFormat, "Invalid internal format."); +ERRMSG(InvalidMatrixMode, "Invalid matrix mode."); +ERRMSG(InvalidMipLevel, "Level of detail outside of range."); +ERRMSG(InvalidName, "Invalid name."); +ERRMSG(InvalidNameCharacters, "Name contains invalid characters."); +ERRMSG(InvalidPname, "Invalid pname."); +ERRMSG(InvalidPrecision, "Invalid or unsupported precision type."); +ERRMSG(InvalidProgramName, "Program object expected."); +ERRMSG(InvalidQueryId, "Invalid query Id."); +ERRMSG(InvalidQueryTarget, "Invalid query target."); +ERRMSG(InvalidQueryType, "Invalid query type."); +ERRMSG(InvalidRange, "Invalid range."); +ERRMSG(InvalidRenderbufferInternalFormat, "Invalid renderbuffer internalformat."); +ERRMSG(InvalidRenderbufferTarget, "Invalid renderbuffer target."); +ERRMSG(InvalidRenderbufferTextureParameter, "Invalid parameter name for renderbuffer attachment."); +ERRMSG(InvalidRenderbufferWidthHeight, + "Renderbuffer width and height cannot be negative and cannot exceed maximum texture size."); +ERRMSG(InvalidSampleMaskNumber, + "MaskNumber cannot be greater than or equal to the value of MAX_SAMPLE_MASK_WORDS."); +ERRMSG(InvalidSampler, "Sampler is not valid"); +ERRMSG(InvalidShaderName, "Shader object expected."); +ERRMSG(InvalidShaderType, "Invalid shader type."); +ERRMSG(InvalidStencil, "Invalid stencil."); +ERRMSG(InvalidStencilBitMask, "Invalid stencil bit mask."); +ERRMSG(InvalidTarget, "Invalid target."); +ERRMSG(InvalidTextureFilterParam, "Texture filter not recognized."); +ERRMSG(InvalidTextureRange, "Cannot be less than 0 or greater than maximum number of textures."); +ERRMSG(InvalidTextureTarget, "Invalid or unsupported texture target."); +ERRMSG(InvalidTextureWrap, "Texture wrap mode not recognized."); +ERRMSG(InvalidType, "Invalid type."); +ERRMSG(InvalidTypePureInt, "Invalid type, should be integer"); +ERRMSG(InvalidUnpackAlignment, "Unpack alignment must be 1, 2, 4, or 8."); +ERRMSG(InvalidVertexAttrSize, "Vertex attribute size must be 1, 2, 3, or 4."); +ERRMSG(InvalidWidth, "Invalid width."); +ERRMSG(InvalidWrapModeTexture, "Invalid wrap mode for texture type."); +ERRMSG(LevelNotZero, "Texture level must be zero."); +ERRMSG(MismatchedByteCountType, "Buffer size does not align with data type."); +ERRMSG(MismatchedFormat, "Format must match internal format."); +ERRMSG(MismatchedTargetAndFormat, "Invalid texture target and format combination."); +ERRMSG(MismatchedTypeAndFormat, "Invalid format and type combination."); +ERRMSG(MismatchedVariableProgram, "Variable is not part of the current program."); +ERRMSG(MissingReadAttachment, "Missing read attachment."); +ERRMSG(MustHaveElementArrayBinding, "Must have element array buffer binding."); +ERRMSG(NameBeginsWithGL, "Attributes that begin with 'gl_' are not allowed."); +ERRMSG(NegativeAttachments, "Negative number of attachments."); +ERRMSG(NegativeBufferSize, "Negative buffer size."); +ERRMSG(NegativeCount, "Negative count."); +ERRMSG(NegativeLength, "Negative length."); +ERRMSG(NegativeMaxCount, "Negative maxcount."); +ERRMSG(NegativeOffset, "Negative offset."); +ERRMSG(NegativePrimcount, "Primcount must be greater than or equal to zero."); +ERRMSG(NegativeSize, "Cannot have negative height or width."); +ERRMSG(NegativeStart, "Cannot have negative start."); +ERRMSG(NegativeStride, "Cannot have negative stride."); +ERRMSG(NoSuchPath, "No such path object."); +ERRMSG(NoTransformFeedbackOutputVariables, + "The active program has specified no output variables to record."); +ERRMSG(NoZeroDivisor, "At least one enabled attribute must have a divisor of zero."); +ERRMSG(ObjectNotGenerated, "Object cannot be used because it has not been generated."); +ERRMSG(OffsetMustBeMultipleOfType, "Offset must be a multiple of the passed in datatype."); +ERRMSG(OutsideOfBounds, "Parameter outside of bounds."); +ERRMSG(ParamOverflow, "The provided parameters overflow with the provided buffer."); +ERRMSG(PixelDataNotNull, "Pixel data must be null."); +ERRMSG(PixelDataNull, "Pixel data cannot be null."); +ERRMSG(ProgramDoesNotExist, "Program doesn't exist."); +ERRMSG(ProgramNotBound, "A program must be bound."); +ERRMSG(ProgramNotLinked, "Program not linked."); +ERRMSG(QueryActive, "Query is active."); +ERRMSG(QueryExtensionNotEnabled, "Query extension not enabled."); +ERRMSG(ReadBufferNone, "Read buffer is GL_NONE."); +ERRMSG(RenderbufferNotBound, "A renderbuffer must be bound."); +ERRMSG(ResourceMaxTextureSize, "Desired resource size is greater than max texture size."); +ERRMSG(ShaderAttachmentHasShader, "Shader attachment already has a shader."); +ERRMSG(ShaderSourceInvalidCharacters, "Shader source contains invalid characters."); +ERRMSG(ShaderToDetachMustBeAttached, + "Shader to be detached must be currently attached to the program."); +ERRMSG(SourceTextureTooSmall, "The specified dimensions are outside of the bounds of the texture."); +ERRMSG(StencilReferenceMaskOrMismatch, + "Stencil reference and mask values must be the same for front facing and back facing " + "triangles."); +ERRMSG(StrideMustBeMultipleOfType, "Stride must be a multiple of the passed in datatype."); +ERRMSG(TextureNotBound, "A texture must be bound."); +ERRMSG(TextureNotPow2, "The texture is a non-power-of-two texture."); +ERRMSG(TransformFeedbackDoesNotExist, "Transform feedback object that does not exist."); +ERRMSG(TypeMismatch, + "Passed in texture target and format must match the one originally used to define the " + "texture."); +ERRMSG(TypeNotUnsignedShortByte, "Only UNSIGNED_SHORT and UNSIGNED_BYTE types are supported."); +ERRMSG(UniformSizeMismatch, "Uniform size does not match uniform method."); +ERRMSG(UnknownParameter, "Unknown parameter value."); +ERRMSG(VertexArrayNoBuffer, "An enabled vertex array has no buffer."); +ERRMSG(VertexArrayNoBufferPointer, "An enabled vertex array has no buffer and no pointer."); +ERRMSG(ViewportNegativeSize, "Viewport size cannot be negative."); +ERRMSG(Webgl2NameLengthLimitExceeded, "Location lengths must not be greater than 1024 characters."); +ERRMSG(WebglBindAttribLocationReservedPrefix, + "Attributes that begin with 'webgl_', or '_webgl_' are not allowed."); +ERRMSG(WebglNameLengthLimitExceeded, + "Location name lengths must not be greater than 256 characters."); +} +#undef ERRMSG +#endif // LIBANGLE_ERRORSTRINGS_H_ diff --git a/src/3rdparty/angle/src/libANGLE/Fence.cpp b/src/3rdparty/angle/src/libANGLE/Fence.cpp index ff32f4bbe9..9c4d381673 100644 --- a/src/3rdparty/angle/src/libANGLE/Fence.cpp +++ b/src/3rdparty/angle/src/libANGLE/Fence.cpp @@ -4,18 +4,17 @@ // found in the LICENSE file. // -// Fence.cpp: Implements the gl::FenceNV and gl::FenceSync classes, which support the GL_NV_fence +// Fence.cpp: Implements the gl::FenceNV and gl::Sync 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" +#include "common/utilities.h" +#include "libANGLE/renderer/FenceNVImpl.h" +#include "libANGLE/renderer/SyncImpl.h" + namespace gl { @@ -44,7 +43,7 @@ Error FenceNV::set(GLenum condition) mStatus = GL_FALSE; mIsSet = true; - return Error(GL_NO_ERROR); + return NoError(); } Error FenceNV::test(GLboolean *outResult) @@ -57,7 +56,7 @@ Error FenceNV::test(GLboolean *outResult) } *outResult = mStatus; - return Error(GL_NO_ERROR); + return NoError(); } Error FenceNV::finish() @@ -72,30 +71,39 @@ Error FenceNV::finish() mStatus = GL_TRUE; - return Error(GL_NO_ERROR); + return NoError(); } -FenceSync::FenceSync(rx::FenceSyncImpl *impl, GLuint id) - : RefCountObject(id), mFence(impl), mLabel(), mCondition(GL_NONE), mFlags(0) +Sync::Sync(rx::SyncImpl *impl, GLuint id) + : RefCountObject(id), + mFence(impl), + mLabel(), + mCondition(GL_SYNC_GPU_COMMANDS_COMPLETE), + mFlags(0) { } -FenceSync::~FenceSync() +Error Sync::onDestroy(const Context *context) +{ + return NoError(); +} + +Sync::~Sync() { SafeDelete(mFence); } -void FenceSync::setLabel(const std::string &label) +void Sync::setLabel(const std::string &label) { mLabel = label; } -const std::string &FenceSync::getLabel() const +const std::string &Sync::getLabel() const { return mLabel; } -Error FenceSync::set(GLenum condition, GLbitfield flags) +Error Sync::set(GLenum condition, GLbitfield flags) { Error error = mFence->set(condition, flags); if (error.isError()) @@ -105,23 +113,23 @@ Error FenceSync::set(GLenum condition, GLbitfield flags) mCondition = condition; mFlags = flags; - return Error(GL_NO_ERROR); + return NoError(); } -Error FenceSync::clientWait(GLbitfield flags, GLuint64 timeout, GLenum *outResult) +Error Sync::clientWait(GLbitfield flags, GLuint64 timeout, GLenum *outResult) { ASSERT(mCondition != GL_NONE); return mFence->clientWait(flags, timeout, outResult); } -Error FenceSync::serverWait(GLbitfield flags, GLuint64 timeout) +Error Sync::serverWait(GLbitfield flags, GLuint64 timeout) { return mFence->serverWait(flags, timeout); } -Error FenceSync::getStatus(GLint *outResult) const +Error Sync::getStatus(GLint *outResult) const { return mFence->getStatus(outResult); } -} +} // namespace gl diff --git a/src/3rdparty/angle/src/libANGLE/Fence.h b/src/3rdparty/angle/src/libANGLE/Fence.h index b2daed6f0e..24bc689ca3 100644 --- a/src/3rdparty/angle/src/libANGLE/Fence.h +++ b/src/3rdparty/angle/src/libANGLE/Fence.h @@ -4,7 +4,7 @@ // found in the LICENSE file. // -// Fence.h: Defines the gl::FenceNV and gl::FenceSync classes, which support the GL_NV_fence +// Fence.h: Defines the gl::FenceNV and gl::Sync classes, which support the GL_NV_fence // extension and GLES3 sync objects. #ifndef LIBANGLE_FENCE_H_ @@ -19,7 +19,7 @@ namespace rx { class FenceNVImpl; -class FenceSyncImpl; +class SyncImpl; } namespace gl @@ -48,11 +48,13 @@ class FenceNV final : angle::NonCopyable GLenum mCondition; }; -class FenceSync final : public RefCountObject, public LabeledObject +class Sync final : public RefCountObject, public LabeledObject { public: - FenceSync(rx::FenceSyncImpl *impl, GLuint id); - virtual ~FenceSync(); + Sync(rx::SyncImpl *impl, GLuint id); + ~Sync() override; + + Error onDestroy(const Context *context) override; void setLabel(const std::string &label) override; const std::string &getLabel() const override; @@ -66,7 +68,7 @@ class FenceSync final : public RefCountObject, public LabeledObject GLbitfield getFlags() const { return mFlags; } private: - rx::FenceSyncImpl *mFence; + rx::SyncImpl *mFence; std::string mLabel; @@ -74,6 +76,6 @@ class FenceSync final : public RefCountObject, public LabeledObject GLbitfield mFlags; }; -} +} // namespace gl #endif // LIBANGLE_FENCE_H_ diff --git a/src/3rdparty/angle/src/libANGLE/Framebuffer.cpp b/src/3rdparty/angle/src/libANGLE/Framebuffer.cpp index 3def57b87e..48e71685b3 100644 --- a/src/3rdparty/angle/src/libANGLE/Framebuffer.cpp +++ b/src/3rdparty/angle/src/libANGLE/Framebuffer.cpp @@ -10,72 +10,349 @@ #include "libANGLE/Framebuffer.h" #include "common/Optional.h" +#include "common/bitset_utils.h" #include "common/utilities.h" #include "libANGLE/Config.h" #include "libANGLE/Context.h" +#include "libANGLE/Display.h" #include "libANGLE/FramebufferAttachment.h" #include "libANGLE/Renderbuffer.h" #include "libANGLE/Surface.h" #include "libANGLE/Texture.h" #include "libANGLE/formatutils.h" +#include "libANGLE/renderer/ContextImpl.h" #include "libANGLE/renderer/FramebufferImpl.h" -#include "libANGLE/renderer/ImplFactory.h" +#include "libANGLE/renderer/GLImplFactory.h" #include "libANGLE/renderer/RenderbufferImpl.h" #include "libANGLE/renderer/SurfaceImpl.h" +using namespace angle; + namespace gl { namespace { -void DetachMatchingAttachment(FramebufferAttachment *attachment, GLenum matchType, GLuint matchId) + +void BindResourceChannel(OnAttachmentDirtyBinding *binding, FramebufferAttachmentObject *resource) +{ + binding->bind(resource ? resource->getDirtyChannel() : nullptr); +} + +bool CheckMultiviewStateMatchesForCompleteness(const FramebufferAttachment *firstAttachment, + const FramebufferAttachment *secondAttachment) +{ + ASSERT(firstAttachment && secondAttachment); + ASSERT(firstAttachment->isAttached() && secondAttachment->isAttached()); + + if (firstAttachment->getNumViews() != secondAttachment->getNumViews()) + { + return false; + } + if (firstAttachment->getBaseViewIndex() != secondAttachment->getBaseViewIndex()) + { + return false; + } + if (firstAttachment->getMultiviewLayout() != secondAttachment->getMultiviewLayout()) + { + return false; + } + if (firstAttachment->getMultiviewViewportOffsets() != + secondAttachment->getMultiviewViewportOffsets()) + { + return false; + } + return true; +} + +bool CheckAttachmentCompleteness(const Context *context, const FramebufferAttachment &attachment) +{ + ASSERT(attachment.isAttached()); + + const Extents &size = attachment.getSize(); + if (size.width == 0 || size.height == 0) + { + return false; + } + + const InternalFormat &format = *attachment.getFormat().info; + if (!format.renderSupport(context->getClientVersion(), context->getExtensions())) + { + return false; + } + + if (attachment.type() == GL_TEXTURE) + { + if (attachment.layer() >= size.depth) + { + return false; + } + + // ES3 specifies that cube map texture attachments must be cube complete. + // This language is missing from the ES2 spec, but we enforce it here because some + // desktop OpenGL drivers also enforce this validation. + // TODO(jmadill): Check if OpenGL ES2 drivers enforce cube completeness. + const Texture *texture = attachment.getTexture(); + ASSERT(texture); + if (texture->getTarget() == GL_TEXTURE_CUBE_MAP && + !texture->getTextureState().isCubeComplete()) + { + return false; + } + + if (!texture->getImmutableFormat()) + { + GLuint attachmentMipLevel = static_cast(attachment.mipLevel()); + + // From the ES 3.0 spec, pg 213: + // If the value of FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE is TEXTURE and the value of + // FRAMEBUFFER_ATTACHMENT_OBJECT_NAME does not name an immutable-format texture, + // then the value of FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL must be in the + // range[levelbase, q], where levelbase is the value of TEXTURE_BASE_LEVEL and q is + // the effective maximum texture level defined in the Mipmapping discussion of + // section 3.8.10.4. + if (attachmentMipLevel < texture->getBaseLevel() || + attachmentMipLevel > texture->getMipmapMaxLevel()) + { + return false; + } + + // Form the ES 3.0 spec, pg 213/214: + // If the value of FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE is TEXTURE and the value of + // FRAMEBUFFER_ATTACHMENT_OBJECT_NAME does not name an immutable-format texture and + // the value of FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL is not levelbase, then the + // texture must be mipmap complete, and if FRAMEBUFFER_ATTACHMENT_OBJECT_NAME names + // a cubemap texture, the texture must also be cube complete. + if (attachmentMipLevel != texture->getBaseLevel() && !texture->isMipmapComplete()) + { + return false; + } + } + } + + return true; +}; + +bool CheckAttachmentSampleCompleteness(const Context *context, + const FramebufferAttachment &attachment, + bool colorAttachment, + Optional *samples, + Optional *fixedSampleLocations) +{ + ASSERT(attachment.isAttached()); + + if (attachment.type() == GL_TEXTURE) + { + const Texture *texture = attachment.getTexture(); + ASSERT(texture); + + const ImageIndex &attachmentImageIndex = attachment.getTextureImageIndex(); + + // ES3.1 (section 9.4) requires that the value of TEXTURE_FIXED_SAMPLE_LOCATIONS should be + // the same for all attached textures. + bool fixedSampleloc = texture->getFixedSampleLocations(attachmentImageIndex.type, + attachmentImageIndex.mipIndex); + if (fixedSampleLocations->valid() && fixedSampleloc != fixedSampleLocations->value()) + { + return false; + } + else + { + *fixedSampleLocations = fixedSampleloc; + } + } + + if (samples->valid()) + { + if (attachment.getSamples() != samples->value()) + { + if (colorAttachment) + { + // 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. + return false; + } + else + { + // CHROMIUM_framebuffer_mixed_samples allows a framebuffer to be considered complete + // when its depth or stencil samples are a multiple of the number of color samples. + if (!context->getExtensions().framebufferMixedSamples) + { + return false; + } + + if ((attachment.getSamples() % std::max(samples->value(), 1)) != 0) + { + return false; + } + } + } + } + else + { + *samples = attachment.getSamples(); + } + + return true; +} + +// Needed to index into the attachment arrays/bitsets. +static_assert(static_cast(IMPLEMENTATION_MAX_FRAMEBUFFER_ATTACHMENTS) == + gl::Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_MAX, + "Framebuffer Dirty bit mismatch"); +static_assert(static_cast(IMPLEMENTATION_MAX_FRAMEBUFFER_ATTACHMENTS) == + gl::Framebuffer::DIRTY_BIT_DEPTH_ATTACHMENT, + "Framebuffer Dirty bit mismatch"); +static_assert(static_cast(IMPLEMENTATION_MAX_FRAMEBUFFER_ATTACHMENTS + 1) == + gl::Framebuffer::DIRTY_BIT_STENCIL_ATTACHMENT, + "Framebuffer Dirty bit mismatch"); + +Error InitAttachment(const Context *context, FramebufferAttachment *attachment) { - if (attachment->isAttached() && - attachment->type() == matchType && - attachment->id() == matchId) + ASSERT(attachment->isAttached()); + if (attachment->initState() == InitState::MayNeedInit) { - attachment->detach(); + ANGLE_TRY(attachment->initializeContents(context)); } + return NoError(); +} + +bool IsColorMaskedOut(const BlendState &blend) +{ + return (!blend.colorMaskRed && !blend.colorMaskGreen && !blend.colorMaskBlue && + !blend.colorMaskAlpha); +} + +bool IsDepthMaskedOut(const DepthStencilState &depthStencil) +{ + return !depthStencil.depthMask; +} + +bool IsStencilMaskedOut(const DepthStencilState &depthStencil) +{ + return ((depthStencil.stencilMask & depthStencil.stencilWritemask) == 0); } + +bool IsClearBufferMaskedOut(const Context *context, GLenum buffer) +{ + switch (buffer) + { + case GL_COLOR: + return IsColorMaskedOut(context->getGLState().getBlendState()); + case GL_DEPTH: + return IsDepthMaskedOut(context->getGLState().getDepthStencilState()); + case GL_STENCIL: + return IsStencilMaskedOut(context->getGLState().getDepthStencilState()); + case GL_DEPTH_STENCIL: + return IsDepthMaskedOut(context->getGLState().getDepthStencilState()) && + IsStencilMaskedOut(context->getGLState().getDepthStencilState()); + default: + UNREACHABLE(); + return true; + } } -Framebuffer::Data::Data() +} // anonymous namespace + +// This constructor is only used for default framebuffers. +FramebufferState::FramebufferState() : mLabel(), mColorAttachments(1), - mDrawBufferStates(1, GL_NONE), - mReadBufferState(GL_COLOR_ATTACHMENT0_EXT) + mDrawBufferStates(1, GL_BACK), + mReadBufferState(GL_BACK), + mDefaultWidth(0), + mDefaultHeight(0), + mDefaultSamples(0), + mDefaultFixedSampleLocations(GL_FALSE), + mWebGLDepthStencilConsistent(true) { - mDrawBufferStates[0] = GL_COLOR_ATTACHMENT0_EXT; + ASSERT(mDrawBufferStates.size() > 0); + mEnabledDrawBuffers.set(0); } -Framebuffer::Data::Data(const Caps &caps) +FramebufferState::FramebufferState(const Caps &caps) : mLabel(), mColorAttachments(caps.maxColorAttachments), mDrawBufferStates(caps.maxDrawBuffers, GL_NONE), - mReadBufferState(GL_COLOR_ATTACHMENT0_EXT) + mReadBufferState(GL_COLOR_ATTACHMENT0_EXT), + mDefaultWidth(0), + mDefaultHeight(0), + mDefaultSamples(0), + mDefaultFixedSampleLocations(GL_FALSE), + mWebGLDepthStencilConsistent(true) { ASSERT(mDrawBufferStates.size() > 0); mDrawBufferStates[0] = GL_COLOR_ATTACHMENT0_EXT; } -Framebuffer::Data::~Data() +FramebufferState::~FramebufferState() { } -const std::string &Framebuffer::Data::getLabel() +const std::string &FramebufferState::getLabel() { return mLabel; } -const FramebufferAttachment *Framebuffer::Data::getReadAttachment() const +const FramebufferAttachment *FramebufferState::getAttachment(GLenum attachment) const +{ + if (attachment >= GL_COLOR_ATTACHMENT0 && attachment <= GL_COLOR_ATTACHMENT15) + { + return getColorAttachment(attachment - GL_COLOR_ATTACHMENT0); + } + + switch (attachment) + { + case GL_COLOR: + case GL_BACK: + return getColorAttachment(0); + case GL_DEPTH: + case GL_DEPTH_ATTACHMENT: + return getDepthAttachment(); + case GL_STENCIL: + case GL_STENCIL_ATTACHMENT: + return getStencilAttachment(); + case GL_DEPTH_STENCIL: + case GL_DEPTH_STENCIL_ATTACHMENT: + return getDepthStencilAttachment(); + default: + UNREACHABLE(); + return nullptr; + } +} + +size_t FramebufferState::getReadIndex() 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(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 readIndex; +} + +const FramebufferAttachment *FramebufferState::getReadAttachment() const +{ + if (mReadBufferState == GL_NONE) + { + return nullptr; + } + size_t readIndex = getReadIndex(); return mColorAttachments[readIndex].isAttached() ? &mColorAttachments[readIndex] : nullptr; } -const FramebufferAttachment *Framebuffer::Data::getFirstColorAttachment() const +const FramebufferAttachment *FramebufferState::getFirstNonNullAttachment() const +{ + auto *colorAttachment = getFirstColorAttachment(); + if (colorAttachment) + { + return colorAttachment; + } + return getDepthOrStencilAttachment(); +} + +const FramebufferAttachment *FramebufferState::getFirstColorAttachment() const { for (const FramebufferAttachment &colorAttachment : mColorAttachments) { @@ -88,7 +365,7 @@ const FramebufferAttachment *Framebuffer::Data::getFirstColorAttachment() const return nullptr; } -const FramebufferAttachment *Framebuffer::Data::getDepthOrStencilAttachment() const +const FramebufferAttachment *FramebufferState::getDepthOrStencilAttachment() const { if (mDepthAttachment.isAttached()) { @@ -101,31 +378,38 @@ const FramebufferAttachment *Framebuffer::Data::getDepthOrStencilAttachment() co return nullptr; } -const FramebufferAttachment *Framebuffer::Data::getColorAttachment(size_t colorAttachment) const +const FramebufferAttachment *FramebufferState::getStencilOrDepthStencilAttachment() const +{ + if (mStencilAttachment.isAttached()) + { + return &mStencilAttachment; + } + return getDepthStencilAttachment(); +} + +const FramebufferAttachment *FramebufferState::getColorAttachment(size_t colorAttachment) const { ASSERT(colorAttachment < mColorAttachments.size()); - return mColorAttachments[colorAttachment].isAttached() ? - &mColorAttachments[colorAttachment] : - nullptr; + return mColorAttachments[colorAttachment].isAttached() ? &mColorAttachments[colorAttachment] + : nullptr; } -const FramebufferAttachment *Framebuffer::Data::getDepthAttachment() const +const FramebufferAttachment *FramebufferState::getDepthAttachment() const { return mDepthAttachment.isAttached() ? &mDepthAttachment : nullptr; } -const FramebufferAttachment *Framebuffer::Data::getStencilAttachment() const +const FramebufferAttachment *FramebufferState::getStencilAttachment() const { return mStencilAttachment.isAttached() ? &mStencilAttachment : nullptr; } -const FramebufferAttachment *Framebuffer::Data::getDepthStencilAttachment() const +const FramebufferAttachment *FramebufferState::getDepthStencilAttachment() const { // A valid depth-stencil attachment has the same resource bound to both the // depth and stencil attachment points. if (mDepthAttachment.isAttached() && mStencilAttachment.isAttached() && - mDepthAttachment.type() == mStencilAttachment.type() && - mDepthAttachment.id() == mStencilAttachment.id()) + mDepthAttachment == mStencilAttachment) { return &mDepthAttachment; } @@ -133,12 +417,11 @@ const FramebufferAttachment *Framebuffer::Data::getDepthStencilAttachment() cons return nullptr; } -bool Framebuffer::Data::attachmentsHaveSameDimensions() const +bool FramebufferState::attachmentsHaveSameDimensions() const { Optional attachmentSize; - auto hasMismatchedSize = [&attachmentSize](const FramebufferAttachment &attachment) - { + auto hasMismatchedSize = [&attachmentSize](const FramebufferAttachment &attachment) { if (!attachment.isAttached()) { return false; @@ -150,7 +433,9 @@ bool Framebuffer::Data::attachmentsHaveSameDimensions() const return false; } - return (attachment.getSize() != attachmentSize.value()); + const auto &prevSize = attachmentSize.value(); + const auto &curSize = attachment.getSize(); + return (curSize.width != prevSize.width || curSize.height != prevSize.height); }; for (const auto &attachment : mColorAttachments) @@ -169,210 +454,414 @@ bool Framebuffer::Data::attachmentsHaveSameDimensions() const return !hasMismatchedSize(mStencilAttachment); } -Framebuffer::Framebuffer(const Caps &caps, rx::ImplFactory *factory, GLuint id) - : mData(caps), mImpl(factory->createFramebuffer(mData)), mId(id) +const gl::FramebufferAttachment *FramebufferState::getDrawBuffer(size_t drawBufferIdx) const { - ASSERT(mId != 0); - ASSERT(mImpl != nullptr); + ASSERT(drawBufferIdx < mDrawBufferStates.size()); + if (mDrawBufferStates[drawBufferIdx] != GL_NONE) + { + // ES3 spec: "If the GL is bound to a draw framebuffer object, the ith buffer listed in bufs + // must be COLOR_ATTACHMENTi or NONE" + ASSERT(mDrawBufferStates[drawBufferIdx] == GL_COLOR_ATTACHMENT0 + drawBufferIdx || + (drawBufferIdx == 0 && mDrawBufferStates[drawBufferIdx] == GL_BACK)); + return getAttachment(mDrawBufferStates[drawBufferIdx]); + } + else + { + return nullptr; + } } -Framebuffer::Framebuffer(rx::SurfaceImpl *surface) - : mData(), mImpl(surface->createDefaultFramebuffer(mData)), mId(0) +size_t FramebufferState::getDrawBufferCount() const { - ASSERT(mImpl != nullptr); + return mDrawBufferStates.size(); } -Framebuffer::~Framebuffer() +bool FramebufferState::colorAttachmentsAreUniqueImages() const { - SafeDelete(mImpl); + for (size_t firstAttachmentIdx = 0; firstAttachmentIdx < mColorAttachments.size(); + firstAttachmentIdx++) + { + const gl::FramebufferAttachment &firstAttachment = mColorAttachments[firstAttachmentIdx]; + if (!firstAttachment.isAttached()) + { + continue; + } + + for (size_t secondAttachmentIdx = firstAttachmentIdx + 1; + secondAttachmentIdx < mColorAttachments.size(); secondAttachmentIdx++) + { + const gl::FramebufferAttachment &secondAttachment = + mColorAttachments[secondAttachmentIdx]; + if (!secondAttachment.isAttached()) + { + continue; + } + + if (firstAttachment == secondAttachment) + { + return false; + } + } + } + + return true; } -void Framebuffer::setLabel(const std::string &label) +bool FramebufferState::hasDepth() const { - mData.mLabel = label; + return (mDepthAttachment.isAttached() && mDepthAttachment.getDepthSize() > 0); } -const std::string &Framebuffer::getLabel() const +bool FramebufferState::hasStencil() const { - return mData.mLabel; + return (mStencilAttachment.isAttached() && mStencilAttachment.getStencilSize() > 0); } -void Framebuffer::detachTexture(GLuint textureId) +GLsizei FramebufferState::getNumViews() const { - detachResourceById(GL_TEXTURE, textureId); + const FramebufferAttachment *attachment = getFirstNonNullAttachment(); + if (attachment == nullptr) + { + return FramebufferAttachment::kDefaultNumViews; + } + return attachment->getNumViews(); } -void Framebuffer::detachRenderbuffer(GLuint renderbufferId) +const std::vector *FramebufferState::getViewportOffsets() const { - detachResourceById(GL_RENDERBUFFER, renderbufferId); + const FramebufferAttachment *attachment = getFirstNonNullAttachment(); + if (attachment == nullptr) + { + return nullptr; + } + return &attachment->getMultiviewViewportOffsets(); } -void Framebuffer::detachResourceById(GLenum resourceType, GLuint resourceId) +GLenum FramebufferState::getMultiviewLayout() const { - for (auto &colorAttachment : mData.mColorAttachments) + const FramebufferAttachment *attachment = getFirstNonNullAttachment(); + if (attachment == nullptr) { - DetachMatchingAttachment(&colorAttachment, resourceType, resourceId); + return GL_NONE; } - - DetachMatchingAttachment(&mData.mDepthAttachment, resourceType, resourceId); - DetachMatchingAttachment(&mData.mStencilAttachment, resourceType, resourceId); + return attachment->getMultiviewLayout(); } -const FramebufferAttachment *Framebuffer::getColorbuffer(size_t colorAttachment) const +int FramebufferState::getBaseViewIndex() const { - return mData.getColorAttachment(colorAttachment); + const FramebufferAttachment *attachment = getFirstNonNullAttachment(); + if (attachment == nullptr) + { + return GL_NONE; + } + return attachment->getBaseViewIndex(); } -const FramebufferAttachment *Framebuffer::getDepthbuffer() const +Box FramebufferState::getDimensions() const { - return mData.getDepthAttachment(); + ASSERT(attachmentsHaveSameDimensions()); + ASSERT(getFirstNonNullAttachment() != nullptr); + Extents extents = getFirstNonNullAttachment()->getSize(); + return Box(0, 0, 0, extents.width, extents.height, extents.depth); } -const FramebufferAttachment *Framebuffer::getStencilbuffer() const +Framebuffer::Framebuffer(const Caps &caps, rx::GLImplFactory *factory, GLuint id) + : mState(caps), + mImpl(factory->createFramebuffer(mState)), + mId(id), + mCachedStatus(), + mDirtyDepthAttachmentBinding(this, DIRTY_BIT_DEPTH_ATTACHMENT), + mDirtyStencilAttachmentBinding(this, DIRTY_BIT_STENCIL_ATTACHMENT) { - return mData.getStencilAttachment(); + ASSERT(mId != 0); + ASSERT(mImpl != nullptr); + ASSERT(mState.mColorAttachments.size() == static_cast(caps.maxColorAttachments)); + + for (uint32_t colorIndex = 0; + colorIndex < static_cast(mState.mColorAttachments.size()); ++colorIndex) + { + mDirtyColorAttachmentBindings.emplace_back(this, DIRTY_BIT_COLOR_ATTACHMENT_0 + colorIndex); + } } -const FramebufferAttachment *Framebuffer::getDepthStencilBuffer() const +Framebuffer::Framebuffer(const egl::Display *display, egl::Surface *surface) + : mState(), + mImpl(surface->getImplementation()->createDefaultFramebuffer(mState)), + mId(0), + mCachedStatus(GL_FRAMEBUFFER_COMPLETE), + mDirtyDepthAttachmentBinding(this, DIRTY_BIT_DEPTH_ATTACHMENT), + mDirtyStencilAttachmentBinding(this, DIRTY_BIT_STENCIL_ATTACHMENT) { - return mData.getDepthStencilAttachment(); + ASSERT(mImpl != nullptr); + mDirtyColorAttachmentBindings.emplace_back(this, DIRTY_BIT_COLOR_ATTACHMENT_0); + + const Context *proxyContext = display->getProxyContext(); + + setAttachmentImpl(proxyContext, GL_FRAMEBUFFER_DEFAULT, GL_BACK, gl::ImageIndex::MakeInvalid(), + surface, FramebufferAttachment::kDefaultNumViews, + FramebufferAttachment::kDefaultBaseViewIndex, + FramebufferAttachment::kDefaultMultiviewLayout, + FramebufferAttachment::kDefaultViewportOffsets); + + if (surface->getConfig()->depthSize > 0) + { + setAttachmentImpl( + proxyContext, GL_FRAMEBUFFER_DEFAULT, GL_DEPTH, gl::ImageIndex::MakeInvalid(), surface, + FramebufferAttachment::kDefaultNumViews, FramebufferAttachment::kDefaultBaseViewIndex, + FramebufferAttachment::kDefaultMultiviewLayout, + FramebufferAttachment::kDefaultViewportOffsets); + } + + if (surface->getConfig()->stencilSize > 0) + { + setAttachmentImpl(proxyContext, GL_FRAMEBUFFER_DEFAULT, GL_STENCIL, + gl::ImageIndex::MakeInvalid(), surface, + FramebufferAttachment::kDefaultNumViews, + FramebufferAttachment::kDefaultBaseViewIndex, + FramebufferAttachment::kDefaultMultiviewLayout, + FramebufferAttachment::kDefaultViewportOffsets); + } } -const FramebufferAttachment *Framebuffer::getDepthOrStencilbuffer() const +Framebuffer::Framebuffer(rx::GLImplFactory *factory) + : mState(), + mImpl(factory->createFramebuffer(mState)), + mId(0), + mCachedStatus(GL_FRAMEBUFFER_UNDEFINED_OES), + mDirtyDepthAttachmentBinding(this, DIRTY_BIT_DEPTH_ATTACHMENT), + mDirtyStencilAttachmentBinding(this, DIRTY_BIT_STENCIL_ATTACHMENT) { - return mData.getDepthOrStencilAttachment(); + mDirtyColorAttachmentBindings.emplace_back(this, DIRTY_BIT_COLOR_ATTACHMENT_0); } -const FramebufferAttachment *Framebuffer::getReadColorbuffer() const +Framebuffer::~Framebuffer() { - return mData.getReadAttachment(); + SafeDelete(mImpl); } -GLenum Framebuffer::getReadColorbufferType() const +void Framebuffer::onDestroy(const Context *context) { - const FramebufferAttachment *readAttachment = mData.getReadAttachment(); - return (readAttachment != nullptr ? readAttachment->type() : GL_NONE); + for (auto &attachment : mState.mColorAttachments) + { + attachment.detach(context); + } + mState.mDepthAttachment.detach(context); + mState.mStencilAttachment.detach(context); + mState.mWebGLDepthAttachment.detach(context); + mState.mWebGLStencilAttachment.detach(context); + mState.mWebGLDepthStencilAttachment.detach(context); + + mImpl->destroy(context); } -const FramebufferAttachment *Framebuffer::getFirstColorbuffer() const +void Framebuffer::destroyDefault(const egl::Display *display) { - return mData.getFirstColorAttachment(); + mImpl->destroyDefault(display); } -const FramebufferAttachment *Framebuffer::getAttachment(GLenum attachment) const +void Framebuffer::setLabel(const std::string &label) { - if (attachment >= GL_COLOR_ATTACHMENT0 && attachment <= GL_COLOR_ATTACHMENT15) - { - return mData.getColorAttachment(attachment - GL_COLOR_ATTACHMENT0); - } - else - { - switch (attachment) - { - case GL_COLOR: - case GL_BACK: - return mData.getColorAttachment(0); - case GL_DEPTH: - case GL_DEPTH_ATTACHMENT: - return mData.getDepthAttachment(); - case GL_STENCIL: - case GL_STENCIL_ATTACHMENT: - return mData.getStencilAttachment(); - case GL_DEPTH_STENCIL: - case GL_DEPTH_STENCIL_ATTACHMENT: - return getDepthStencilBuffer(); - default: - UNREACHABLE(); - return nullptr; - } - } + mState.mLabel = label; } -size_t Framebuffer::getDrawbufferStateCount() const +const std::string &Framebuffer::getLabel() const { - return mData.mDrawBufferStates.size(); + return mState.mLabel; } -GLenum Framebuffer::getDrawBufferState(size_t drawBuffer) const +bool Framebuffer::detachTexture(const Context *context, GLuint textureId) { - ASSERT(drawBuffer < mData.mDrawBufferStates.size()); - return mData.mDrawBufferStates[drawBuffer]; + return detachResourceById(context, GL_TEXTURE, textureId); } -void Framebuffer::setDrawBuffers(size_t count, const GLenum *buffers) +bool Framebuffer::detachRenderbuffer(const Context *context, GLuint renderbufferId) { - auto &drawStates = mData.mDrawBufferStates; - - ASSERT(count <= drawStates.size()); - std::copy(buffers, buffers + count, drawStates.begin()); - std::fill(drawStates.begin() + count, drawStates.end(), GL_NONE); - mDirtyBits.set(DIRTY_BIT_DRAW_BUFFERS); + return detachResourceById(context, GL_RENDERBUFFER, renderbufferId); } -const FramebufferAttachment *Framebuffer::getDrawBuffer(size_t drawBuffer) const +bool Framebuffer::detachResourceById(const Context *context, GLenum resourceType, GLuint resourceId) { - ASSERT(drawBuffer < mData.mDrawBufferStates.size()); - if (mData.mDrawBufferStates[drawBuffer] != GL_NONE) + bool found = false; + + for (size_t colorIndex = 0; colorIndex < mState.mColorAttachments.size(); ++colorIndex) { - // ES3 spec: "If the GL is bound to a draw framebuffer object, the ith buffer listed in bufs - // must be COLOR_ATTACHMENTi or NONE" - ASSERT(mData.mDrawBufferStates[drawBuffer] == GL_COLOR_ATTACHMENT0 + drawBuffer || - (drawBuffer == 0 && mData.mDrawBufferStates[drawBuffer] == GL_BACK)); - return getAttachment(mData.mDrawBufferStates[drawBuffer]); + if (detachMatchingAttachment(context, &mState.mColorAttachments[colorIndex], resourceType, + resourceId, DIRTY_BIT_COLOR_ATTACHMENT_0 + colorIndex)) + { + found = true; + } + } + + if (context->isWebGL1()) + { + const std::array attachments = { + {&mState.mWebGLDepthStencilAttachment, &mState.mWebGLDepthAttachment, + &mState.mWebGLStencilAttachment}}; + for (FramebufferAttachment *attachment : attachments) + { + if (attachment->isAttached() && attachment->type() == resourceType && + attachment->id() == resourceId) + { + resetAttachment(context, attachment->getBinding()); + found = true; + } + } } else { - return nullptr; + if (detachMatchingAttachment(context, &mState.mDepthAttachment, resourceType, resourceId, + DIRTY_BIT_DEPTH_ATTACHMENT)) + { + found = true; + } + if (detachMatchingAttachment(context, &mState.mStencilAttachment, resourceType, resourceId, + DIRTY_BIT_STENCIL_ATTACHMENT)) + { + found = true; + } } + + return found; } -bool Framebuffer::hasEnabledDrawBuffer() const +bool Framebuffer::detachMatchingAttachment(const Context *context, + FramebufferAttachment *attachment, + GLenum matchType, + GLuint matchId, + size_t dirtyBit) { - for (size_t drawbufferIdx = 0; drawbufferIdx < mData.mDrawBufferStates.size(); ++drawbufferIdx) + if (attachment->isAttached() && attachment->type() == matchType && attachment->id() == matchId) { - if (getDrawBuffer(drawbufferIdx) != nullptr) - { - return true; - } + attachment->detach(context); + mDirtyBits.set(dirtyBit); + mState.mResourceNeedsInit.set(dirtyBit, false); + return true; } return false; } -GLenum Framebuffer::getReadBufferState() const +const FramebufferAttachment *Framebuffer::getColorbuffer(size_t colorAttachment) const { - return mData.mReadBufferState; + return mState.getColorAttachment(colorAttachment); } -void Framebuffer::setReadBuffer(GLenum buffer) +const FramebufferAttachment *Framebuffer::getDepthbuffer() const { - ASSERT(buffer == GL_BACK || buffer == GL_NONE || - (buffer >= GL_COLOR_ATTACHMENT0 && - (buffer - GL_COLOR_ATTACHMENT0) < mData.mColorAttachments.size())); - mData.mReadBufferState = buffer; - mDirtyBits.set(DIRTY_BIT_READ_BUFFER); + return mState.getDepthAttachment(); } -size_t Framebuffer::getNumColorBuffers() const +const FramebufferAttachment *Framebuffer::getStencilbuffer() const { - return mData.mColorAttachments.size(); + return mState.getStencilAttachment(); } -bool Framebuffer::hasDepth() const +const FramebufferAttachment *Framebuffer::getDepthStencilBuffer() const { - return (mData.mDepthAttachment.isAttached() && mData.mDepthAttachment.getDepthSize() > 0); + return mState.getDepthStencilAttachment(); } -bool Framebuffer::hasStencil() const +const FramebufferAttachment *Framebuffer::getDepthOrStencilbuffer() const { - return (mData.mStencilAttachment.isAttached() && mData.mStencilAttachment.getStencilSize() > 0); + return mState.getDepthOrStencilAttachment(); } -bool Framebuffer::usingExtendedDrawBuffers() const +const FramebufferAttachment *Framebuffer::getStencilOrDepthStencilAttachment() const { - for (size_t drawbufferIdx = 1; drawbufferIdx < mData.mDrawBufferStates.size(); ++drawbufferIdx) - { - if (getDrawBuffer(drawbufferIdx) != nullptr) + return mState.getStencilOrDepthStencilAttachment(); +} + +const FramebufferAttachment *Framebuffer::getReadColorbuffer() const +{ + return mState.getReadAttachment(); +} + +GLenum Framebuffer::getReadColorbufferType() const +{ + const FramebufferAttachment *readAttachment = mState.getReadAttachment(); + return (readAttachment != nullptr ? readAttachment->type() : GL_NONE); +} + +const FramebufferAttachment *Framebuffer::getFirstColorbuffer() const +{ + return mState.getFirstColorAttachment(); +} + +const FramebufferAttachment *Framebuffer::getFirstNonNullAttachment() const +{ + return mState.getFirstNonNullAttachment(); +} + +const FramebufferAttachment *Framebuffer::getAttachment(GLenum attachment) const +{ + return mState.getAttachment(attachment); +} + +size_t Framebuffer::getDrawbufferStateCount() const +{ + return mState.mDrawBufferStates.size(); +} + +GLenum Framebuffer::getDrawBufferState(size_t drawBuffer) const +{ + ASSERT(drawBuffer < mState.mDrawBufferStates.size()); + return mState.mDrawBufferStates[drawBuffer]; +} + +const std::vector &Framebuffer::getDrawBufferStates() const +{ + return mState.getDrawBufferStates(); +} + +void Framebuffer::setDrawBuffers(size_t count, const GLenum *buffers) +{ + auto &drawStates = mState.mDrawBufferStates; + + ASSERT(count <= drawStates.size()); + std::copy(buffers, buffers + count, drawStates.begin()); + std::fill(drawStates.begin() + count, drawStates.end(), GL_NONE); + mDirtyBits.set(DIRTY_BIT_DRAW_BUFFERS); + + mState.mEnabledDrawBuffers.reset(); + for (size_t index = 0; index < count; ++index) + { + if (drawStates[index] != GL_NONE && mState.mColorAttachments[index].isAttached()) + { + mState.mEnabledDrawBuffers.set(index); + } + } +} + +const FramebufferAttachment *Framebuffer::getDrawBuffer(size_t drawBuffer) const +{ + return mState.getDrawBuffer(drawBuffer); +} + +GLenum Framebuffer::getDrawbufferWriteType(size_t drawBuffer) const +{ + const FramebufferAttachment *attachment = mState.getDrawBuffer(drawBuffer); + if (attachment == nullptr) + { + return GL_NONE; + } + + GLenum componentType = attachment->getFormat().info->componentType; + switch (componentType) + { + case GL_INT: + case GL_UNSIGNED_INT: + return componentType; + + default: + return GL_FLOAT; + } +} + +bool Framebuffer::hasEnabledDrawBuffer() const +{ + for (size_t drawbufferIdx = 0; drawbufferIdx < mState.mDrawBufferStates.size(); ++drawbufferIdx) + { + if (getDrawBuffer(drawbufferIdx) != nullptr) { return true; } @@ -381,210 +870,276 @@ bool Framebuffer::usingExtendedDrawBuffers() const return false; } -GLenum Framebuffer::checkStatus(const gl::Data &data) const +GLenum Framebuffer::getReadBufferState() const +{ + return mState.mReadBufferState; +} + +void Framebuffer::setReadBuffer(GLenum buffer) +{ + ASSERT(buffer == GL_BACK || buffer == GL_NONE || + (buffer >= GL_COLOR_ATTACHMENT0 && + (buffer - GL_COLOR_ATTACHMENT0) < mState.mColorAttachments.size())); + mState.mReadBufferState = buffer; + mDirtyBits.set(DIRTY_BIT_READ_BUFFER); +} + +size_t Framebuffer::getNumColorBuffers() const +{ + return mState.mColorAttachments.size(); +} + +bool Framebuffer::hasDepth() const +{ + return mState.hasDepth(); +} + +bool Framebuffer::hasStencil() const +{ + return mState.hasStencil(); +} + +bool Framebuffer::usingExtendedDrawBuffers() const +{ + for (size_t drawbufferIdx = 1; drawbufferIdx < mState.mDrawBufferStates.size(); ++drawbufferIdx) + { + if (getDrawBuffer(drawbufferIdx) != nullptr) + { + return true; + } + } + + return false; +} + +void Framebuffer::invalidateCompletenessCache() +{ + if (mId != 0) + { + mCachedStatus.reset(); + } +} + +GLenum Framebuffer::checkStatus(const Context *context) { - // 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. + // The default framebuffer is always complete except when it is surfaceless in which + // case it is always unsupported. We return early because the default framebuffer may + // not be subject to the same rules as application FBOs. ie, it could have 0x0 size. if (mId == 0) { - return GL_FRAMEBUFFER_COMPLETE; + ASSERT(mCachedStatus.valid()); + ASSERT(mCachedStatus.value() == GL_FRAMEBUFFER_COMPLETE || + mCachedStatus.value() == GL_FRAMEBUFFER_UNDEFINED_OES); + return mCachedStatus.value(); } - unsigned int colorbufferSize = 0; - int samples = -1; - bool missingAttachment = true; + if (hasAnyDirtyBit() || !mCachedStatus.valid()) + { + mCachedStatus = checkStatusImpl(context); + } + + return mCachedStatus.value(); +} + +GLenum Framebuffer::checkStatusImpl(const Context *context) +{ + const ContextState &state = context->getContextState(); + + ASSERT(mId != 0); + + bool hasAttachments = false; + Optional colorbufferSize; + Optional samples; + Optional fixedSampleLocations; + bool hasRenderbuffer = false; + + const FramebufferAttachment *firstAttachment = getFirstNonNullAttachment(); - for (const FramebufferAttachment &colorAttachment : mData.mColorAttachments) + for (const FramebufferAttachment &colorAttachment : mState.mColorAttachments) { if (colorAttachment.isAttached()) { - const Extents &size = colorAttachment.getSize(); - if (size.width == 0 || size.height == 0) + if (!CheckAttachmentCompleteness(context, colorAttachment)) { 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) + const InternalFormat &format = *colorAttachment.getFormat().info; + if (format.depthBits > 0 || format.stencilBits > 0) { - if (!formatCaps.renderable) - { - return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; - } - - if (formatInfo.depthBits > 0 || formatInfo.stencilBits > 0) - { - return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; - } - - if (colorAttachment.layer() >= size.depth) - { - return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; - } - - // ES3 specifies that cube map texture attachments must be cube complete. - // This language is missing from the ES2 spec, but we enforce it here because some - // desktop OpenGL drivers also enforce this validation. - // TODO(jmadill): Check if OpenGL ES2 drivers enforce cube completeness. - const Texture *texture = colorAttachment.getTexture(); - ASSERT(texture); - if (texture->getTarget() == GL_TEXTURE_CUBE_MAP && !texture->isCubeComplete()) - { - return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; - } + return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; } - else if (colorAttachment.type() == GL_RENDERBUFFER) + + if (!CheckAttachmentSampleCompleteness(context, colorAttachment, true, &samples, + &fixedSampleLocations)) { - if (!formatCaps.renderable || formatInfo.depthBits > 0 || formatInfo.stencilBits > 0) - { - return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; - } + return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE; } - if (!missingAttachment) + // 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 (state.getClientMajorVersion() < 3) { - // 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 (colorbufferSize.valid()) { - if (formatInfo.pixelBytes != colorbufferSize) + if (format.pixelBytes != colorbufferSize.value()) { return GL_FRAMEBUFFER_UNSUPPORTED; } } + else + { + colorbufferSize = format.pixelBytes; + } } - else + + if (!CheckMultiviewStateMatchesForCompleteness(firstAttachment, &colorAttachment)) { - samples = colorAttachment.getSamples(); - colorbufferSize = formatInfo.pixelBytes; - missingAttachment = false; + return GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_ANGLE; } + + hasRenderbuffer = hasRenderbuffer || (colorAttachment.type() == GL_RENDERBUFFER); + hasAttachments = true; } } - const FramebufferAttachment &depthAttachment = mData.mDepthAttachment; + const FramebufferAttachment &depthAttachment = mState.mDepthAttachment; if (depthAttachment.isAttached()) { - const Extents &size = depthAttachment.getSize(); - if (size.width == 0 || size.height == 0) + if (!CheckAttachmentCompleteness(context, depthAttachment)) { 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) + const InternalFormat &format = *depthAttachment.getFormat().info; + if (format.depthBits == 0) { - // depth texture attachments require OES/ANGLE_depth_texture - if (!data.extensions->depthTextures) - { - return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; - } + return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; + } - if (!formatCaps.renderable) - { - return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; - } + if (!CheckAttachmentSampleCompleteness(context, depthAttachment, false, &samples, + &fixedSampleLocations)) + { + return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE; + } - if (formatInfo.depthBits == 0) - { - return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; - } + if (!CheckMultiviewStateMatchesForCompleteness(firstAttachment, &depthAttachment)) + { + return GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_ANGLE; } - else if (depthAttachment.type() == GL_RENDERBUFFER) + + hasRenderbuffer = hasRenderbuffer || (depthAttachment.type() == GL_RENDERBUFFER); + hasAttachments = true; + } + + const FramebufferAttachment &stencilAttachment = mState.mStencilAttachment; + if (stencilAttachment.isAttached()) + { + if (!CheckAttachmentCompleteness(context, stencilAttachment)) { - if (!formatCaps.renderable || formatInfo.depthBits == 0) - { - return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; - } + return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; + } + + const InternalFormat &format = *stencilAttachment.getFormat().info; + if (format.stencilBits == 0) + { + return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; } - if (missingAttachment) + if (!CheckAttachmentSampleCompleteness(context, stencilAttachment, false, &samples, + &fixedSampleLocations)) { - samples = depthAttachment.getSamples(); - missingAttachment = false; + return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE; } - else if (samples != depthAttachment.getSamples()) + + if (!CheckMultiviewStateMatchesForCompleteness(firstAttachment, &stencilAttachment)) { - return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE; + return GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_ANGLE; } + + hasRenderbuffer = hasRenderbuffer || (stencilAttachment.type() == GL_RENDERBUFFER); + hasAttachments = true; } - const FramebufferAttachment &stencilAttachment = mData.mStencilAttachment; - if (stencilAttachment.isAttached()) + // Starting from ES 3.0 stencil and depth, if present, should be the same image + if (state.getClientMajorVersion() >= 3 && depthAttachment.isAttached() && + stencilAttachment.isAttached() && stencilAttachment != depthAttachment) + { + return GL_FRAMEBUFFER_UNSUPPORTED; + } + + // Special additional validation for WebGL 1 DEPTH/STENCIL/DEPTH_STENCIL. + if (state.isWebGL1()) { - const Extents &size = stencilAttachment.getSize(); - if (size.width == 0 || size.height == 0) + if (!mState.mWebGLDepthStencilConsistent) { - return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; + return GL_FRAMEBUFFER_UNSUPPORTED; } - GLenum internalformat = stencilAttachment.getInternalFormat(); - const TextureCaps &formatCaps = data.textureCaps->get(internalformat); - const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat); - if (stencilAttachment.type() == GL_TEXTURE) + if (mState.mWebGLDepthStencilAttachment.isAttached()) { - // 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) + if (mState.mWebGLDepthStencilAttachment.getDepthSize() == 0 || + mState.mWebGLDepthStencilAttachment.getStencilSize() == 0) { return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; } - if (formatInfo.stencilBits == 0) - { - return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; - } - } - else if (stencilAttachment.type() == GL_RENDERBUFFER) - { - if (!formatCaps.renderable || formatInfo.stencilBits == 0) + if (!CheckMultiviewStateMatchesForCompleteness(firstAttachment, + &mState.mWebGLDepthStencilAttachment)) { - return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; + return GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_ANGLE; } } - - if (missingAttachment) + else if (mState.mStencilAttachment.isAttached() && + mState.mStencilAttachment.getDepthSize() > 0) { - samples = stencilAttachment.getSamples(); - missingAttachment = false; + return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; } - else if (samples != stencilAttachment.getSamples()) + else if (mState.mDepthAttachment.isAttached() && + mState.mDepthAttachment.getStencilSize() > 0) { - return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE; + return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; } } - // we need to have at least one attachment to be complete - if (missingAttachment) + // ES3.1(section 9.4) requires that if no image is attached to the framebuffer, and either the + // value of the framebuffer's FRAMEBUFFER_DEFAULT_WIDTH or FRAMEBUFFER_DEFAULT_HEIGHT parameters + // is zero, the framebuffer is considered incomplete. + GLint defaultWidth = mState.getDefaultWidth(); + GLint defaultHeight = mState.getDefaultHeight(); + if (!hasAttachments && (defaultWidth == 0 || defaultHeight == 0)) { return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT; } - // In ES 2.0, all color attachments must have the same width and height. + // In ES 2.0 and WebGL, all color attachments must have the same width and height. // In ES 3.0, there is no such restriction. - if (data.clientVersion < 3 && !mData.attachmentsHaveSameDimensions()) + if ((state.getClientMajorVersion() < 3 || state.getExtensions().webglCompatibility) && + !mState.attachmentsHaveSameDimensions()) { return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS; } - syncState(); - if (!mImpl->checkStatus()) + // ES3.1(section 9.4) requires that if the attached images are a mix of renderbuffers and + // textures, the value of TEXTURE_FIXED_SAMPLE_LOCATIONS must be TRUE for all attached textures. + if (fixedSampleLocations.valid() && hasRenderbuffer && !fixedSampleLocations.value()) + { + return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE; + } + + // The WebGL conformance tests implicitly define that all framebuffer + // attachments must be unique. For example, the same level of a texture can + // not be attached to two different color attachments. + if (state.getExtensions().webglCompatibility) + { + if (!mState.colorAttachmentsAreUniqueImages()) + { + return GL_FRAMEBUFFER_UNSUPPORTED; + } + } + + syncState(context); + if (!mImpl->checkStatus(context)) { return GL_FRAMEBUFFER_UNSUPPORTED; } @@ -592,216 +1147,1036 @@ GLenum Framebuffer::checkStatus(const gl::Data &data) const return GL_FRAMEBUFFER_COMPLETE; } -Error Framebuffer::discard(size_t count, const GLenum *attachments) +Error Framebuffer::discard(const Context *context, size_t count, const GLenum *attachments) +{ + // Back-ends might make the contents of the FBO undefined. In WebGL 2.0, invalidate operations + // can be no-ops, so we should probably do that to ensure consistency. + // TODO(jmadill): WebGL behaviour, and robust resource init behaviour without WebGL. + + return mImpl->discard(context, count, attachments); +} + +Error Framebuffer::invalidate(const Context *context, size_t count, const GLenum *attachments) { - return mImpl->discard(count, attachments); + // Back-ends might make the contents of the FBO undefined. In WebGL 2.0, invalidate operations + // can be no-ops, so we should probably do that to ensure consistency. + // TODO(jmadill): WebGL behaviour, and robust resource init behaviour without WebGL. + + return mImpl->invalidate(context, count, attachments); } -Error Framebuffer::invalidate(size_t count, const GLenum *attachments) +bool Framebuffer::partialClearNeedsInit(const Context *context, + bool color, + bool depth, + bool stencil) { - return mImpl->invalidate(count, attachments); + const auto &glState = context->getGLState(); + + if (!glState.isRobustResourceInitEnabled()) + { + return false; + } + + // Scissors can affect clearing. + // TODO(jmadill): Check for complete scissor overlap. + if (glState.isScissorTestEnabled()) + { + return true; + } + + // If colors masked, we must clear before we clear. Do a simple check. + // TODO(jmadill): Filter out unused color channels from the test. + if (color) + { + const auto &blend = glState.getBlendState(); + if (!(blend.colorMaskRed && blend.colorMaskGreen && blend.colorMaskBlue && + blend.colorMaskAlpha)) + { + return true; + } + } + + const auto &depthStencil = glState.getDepthStencilState(); + ASSERT(depthStencil.stencilBackMask == depthStencil.stencilMask); + if (stencil && depthStencil.stencilMask != depthStencil.stencilWritemask) + { + return true; + } + + return false; } -Error Framebuffer::invalidateSub(size_t count, const GLenum *attachments, const gl::Rectangle &area) +Error Framebuffer::invalidateSub(const Context *context, + size_t count, + const GLenum *attachments, + const gl::Rectangle &area) { - return mImpl->invalidateSub(count, attachments, area); + // Back-ends might make the contents of the FBO undefined. In WebGL 2.0, invalidate operations + // can be no-ops, so we should probably do that to ensure consistency. + // TODO(jmadill): Make a invalidate no-op in WebGL 2.0. + + return mImpl->invalidateSub(context, count, attachments, area); } -Error Framebuffer::clear(const gl::Data &data, GLbitfield mask) +Error Framebuffer::clear(const gl::Context *context, GLbitfield mask) { - if (data.state->isRasterizerDiscardEnabled()) + const auto &glState = context->getGLState(); + if (glState.isRasterizerDiscardEnabled()) + { + return NoError(); + } + + const auto &blend = glState.getBlendState(); + const auto &depthStencil = glState.getDepthStencilState(); + + bool color = (mask & GL_COLOR_BUFFER_BIT) != 0 && !IsColorMaskedOut(blend); + bool depth = (mask & GL_DEPTH_BUFFER_BIT) != 0 && !IsDepthMaskedOut(depthStencil); + bool stencil = (mask & GL_STENCIL_BUFFER_BIT) != 0 && !IsStencilMaskedOut(depthStencil); + + if (partialClearNeedsInit(context, color, depth, stencil)) { - return gl::Error(GL_NO_ERROR); + ANGLE_TRY(ensureDrawAttachmentsInitialized(context)); } - return mImpl->clear(data, mask); + ANGLE_TRY(mImpl->clear(context, mask)); + + if (glState.isRobustResourceInitEnabled()) + { + markDrawAttachmentsInitialized(color, depth, stencil); + } + + return NoError(); } -Error Framebuffer::clearBufferfv(const gl::Data &data, +Error Framebuffer::clearBufferfv(const gl::Context *context, GLenum buffer, GLint drawbuffer, const GLfloat *values) { - if (data.state->isRasterizerDiscardEnabled()) + if (context->getGLState().isRasterizerDiscardEnabled() || + IsClearBufferMaskedOut(context, buffer)) { - return gl::Error(GL_NO_ERROR); + return NoError(); } - return mImpl->clearBufferfv(data, buffer, drawbuffer, values); + if (partialBufferClearNeedsInit(context, buffer)) + { + ANGLE_TRY(ensureBufferInitialized(context, buffer, drawbuffer)); + } + + ANGLE_TRY(mImpl->clearBufferfv(context, buffer, drawbuffer, values)); + + if (context->isRobustResourceInitEnabled()) + { + markBufferInitialized(buffer, drawbuffer); + } + return NoError(); } -Error Framebuffer::clearBufferuiv(const gl::Data &data, +Error Framebuffer::clearBufferuiv(const gl::Context *context, GLenum buffer, GLint drawbuffer, const GLuint *values) { - if (data.state->isRasterizerDiscardEnabled()) + if (context->getGLState().isRasterizerDiscardEnabled() || + IsClearBufferMaskedOut(context, buffer)) + { + return NoError(); + } + + if (partialBufferClearNeedsInit(context, buffer)) { - return gl::Error(GL_NO_ERROR); + ANGLE_TRY(ensureBufferInitialized(context, buffer, drawbuffer)); } - return mImpl->clearBufferuiv(data, buffer, drawbuffer, values); + ANGLE_TRY(mImpl->clearBufferuiv(context, buffer, drawbuffer, values)); + + if (context->isRobustResourceInitEnabled()) + { + markBufferInitialized(buffer, drawbuffer); + } + return NoError(); } -Error Framebuffer::clearBufferiv(const gl::Data &data, +Error Framebuffer::clearBufferiv(const gl::Context *context, GLenum buffer, GLint drawbuffer, const GLint *values) { - if (data.state->isRasterizerDiscardEnabled()) + if (context->getGLState().isRasterizerDiscardEnabled() || + IsClearBufferMaskedOut(context, buffer)) { - return gl::Error(GL_NO_ERROR); + return NoError(); } - return mImpl->clearBufferiv(data, buffer, drawbuffer, values); + if (partialBufferClearNeedsInit(context, buffer)) + { + ANGLE_TRY(ensureBufferInitialized(context, buffer, drawbuffer)); + } + + ANGLE_TRY(mImpl->clearBufferiv(context, buffer, drawbuffer, values)); + + if (context->isRobustResourceInitEnabled()) + { + markBufferInitialized(buffer, drawbuffer); + } + return NoError(); } -Error Framebuffer::clearBufferfi(const gl::Data &data, +Error Framebuffer::clearBufferfi(const gl::Context *context, GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil) { - if (data.state->isRasterizerDiscardEnabled()) + if (context->getGLState().isRasterizerDiscardEnabled() || + IsClearBufferMaskedOut(context, buffer)) + { + return NoError(); + } + + if (partialBufferClearNeedsInit(context, buffer)) { - return gl::Error(GL_NO_ERROR); + ANGLE_TRY(ensureBufferInitialized(context, buffer, drawbuffer)); } - return mImpl->clearBufferfi(data, buffer, drawbuffer, depth, stencil); + ANGLE_TRY(mImpl->clearBufferfi(context, buffer, drawbuffer, depth, stencil)); + + if (context->isRobustResourceInitEnabled()) + { + markBufferInitialized(buffer, drawbuffer); + } + return NoError(); } -GLenum Framebuffer::getImplementationColorReadFormat() const +GLenum Framebuffer::getImplementationColorReadFormat(const Context *context) const { - return mImpl->getImplementationColorReadFormat(); + return mImpl->getImplementationColorReadFormat(context); } -GLenum Framebuffer::getImplementationColorReadType() const +GLenum Framebuffer::getImplementationColorReadType(const Context *context) const { - return mImpl->getImplementationColorReadType(); + return mImpl->getImplementationColorReadType(context); } -Error Framebuffer::readPixels(const State &state, +Error Framebuffer::readPixels(const gl::Context *context, const Rectangle &area, GLenum format, GLenum type, - GLvoid *pixels) const + void *pixels) { - Error error = mImpl->readPixels(state, area, format, type, pixels); - if (error.isError()) - { - return error; - } + ANGLE_TRY(ensureReadAttachmentInitialized(context, GL_COLOR_BUFFER_BIT)); + ANGLE_TRY(mImpl->readPixels(context, area, format, type, pixels)); - Buffer *unpackBuffer = state.getUnpackState().pixelBuffer.get(); + Buffer *unpackBuffer = context->getGLState().getTargetBuffer(gl::BufferBinding::PixelUnpack); if (unpackBuffer) { unpackBuffer->onPixelUnpack(); } - return Error(GL_NO_ERROR); + return NoError(); } -Error Framebuffer::blit(const State &state, +Error Framebuffer::blit(const gl::Context *context, const Rectangle &sourceArea, const Rectangle &destArea, GLbitfield mask, - GLenum filter, - const Framebuffer *sourceFramebuffer) + GLenum filter) { - return mImpl->blit(state, sourceArea, destArea, mask, filter, sourceFramebuffer); -} + GLbitfield blitMask = mask; -int Framebuffer::getSamples(const gl::Data &data) const -{ - if (checkStatus(data) == GL_FRAMEBUFFER_COMPLETE) + // Note that blitting is called against draw framebuffer. + // See the code in gl::Context::blitFramebuffer. + if ((mask & GL_COLOR_BUFFER_BIT) && !hasEnabledDrawBuffer()) { - // for a complete framebuffer, all attachments must have the same sample count - // in this case return the first nonzero sample size - for (const FramebufferAttachment &colorAttachment : mData.mColorAttachments) - { - if (colorAttachment.isAttached()) - { - return colorAttachment.getSamples(); - } - } + blitMask &= ~GL_COLOR_BUFFER_BIT; + } + + if ((mask & GL_STENCIL_BUFFER_BIT) && mState.getStencilAttachment() == nullptr) + { + blitMask &= ~GL_STENCIL_BUFFER_BIT; + } + + if ((mask & GL_DEPTH_BUFFER_BIT) && mState.getDepthAttachment() == nullptr) + { + blitMask &= ~GL_DEPTH_BUFFER_BIT; + } + + if (!blitMask) + { + return NoError(); + } + + auto *sourceFBO = context->getGLState().getReadFramebuffer(); + ANGLE_TRY(sourceFBO->ensureReadAttachmentInitialized(context, blitMask)); + + // TODO(jmadill): Only clear if not the full FBO dimensions, and only specified bitmask. + ANGLE_TRY(ensureDrawAttachmentsInitialized(context)); + + return mImpl->blit(context, sourceArea, destArea, blitMask, filter); +} + +int Framebuffer::getSamples(const Context *context) +{ + if (complete(context)) + { + return getCachedSamples(context); } return 0; } +int Framebuffer::getCachedSamples(const Context *context) +{ + // For a complete framebuffer, all attachments must have the same sample count. + // In this case return the first nonzero sample size. + const auto *firstNonNullAttachment = mState.getFirstNonNullAttachment(); + if (firstNonNullAttachment) + { + ASSERT(firstNonNullAttachment->isAttached()); + return firstNonNullAttachment->getSamples(); + } + + // No attachments found. + return 0; +} + +Error Framebuffer::getSamplePosition(size_t index, GLfloat *xy) const +{ + ANGLE_TRY(mImpl->getSamplePosition(index, xy)); + return NoError(); +} + bool Framebuffer::hasValidDepthStencil() const { - return mData.getDepthStencilAttachment() != nullptr; + return mState.getDepthStencilAttachment() != nullptr; } -void Framebuffer::setAttachment(GLenum type, +void Framebuffer::setAttachment(const Context *context, + GLenum type, GLenum binding, const ImageIndex &textureIndex, FramebufferAttachmentObject *resource) { - if (binding == GL_DEPTH_STENCIL || binding == GL_DEPTH_STENCIL_ATTACHMENT) + setAttachment(context, type, binding, textureIndex, resource, + FramebufferAttachment::kDefaultNumViews, + FramebufferAttachment::kDefaultBaseViewIndex, + FramebufferAttachment::kDefaultMultiviewLayout, + FramebufferAttachment::kDefaultViewportOffsets); +} + +void Framebuffer::setAttachment(const Context *context, + GLenum type, + GLenum binding, + const ImageIndex &textureIndex, + FramebufferAttachmentObject *resource, + GLsizei numViews, + GLuint baseViewIndex, + GLenum multiviewLayout, + const GLint *viewportOffsets) +{ + // Context may be null in unit tests. + if (!context || !context->isWebGL1()) + { + setAttachmentImpl(context, type, binding, textureIndex, resource, numViews, baseViewIndex, + multiviewLayout, viewportOffsets); + return; + } + + switch (binding) + { + case GL_DEPTH_STENCIL: + case GL_DEPTH_STENCIL_ATTACHMENT: + mState.mWebGLDepthStencilAttachment.attach(context, type, binding, textureIndex, + resource, numViews, baseViewIndex, + multiviewLayout, viewportOffsets); + break; + case GL_DEPTH: + case GL_DEPTH_ATTACHMENT: + mState.mWebGLDepthAttachment.attach(context, type, binding, textureIndex, resource, + numViews, baseViewIndex, multiviewLayout, + viewportOffsets); + break; + case GL_STENCIL: + case GL_STENCIL_ATTACHMENT: + mState.mWebGLStencilAttachment.attach(context, type, binding, textureIndex, resource, + numViews, baseViewIndex, multiviewLayout, + viewportOffsets); + break; + default: + setAttachmentImpl(context, type, binding, textureIndex, resource, numViews, + baseViewIndex, multiviewLayout, viewportOffsets); + return; + } + + commitWebGL1DepthStencilIfConsistent(context, numViews, baseViewIndex, multiviewLayout, + viewportOffsets); +} + +void Framebuffer::setAttachmentMultiviewLayered(const Context *context, + GLenum type, + GLenum binding, + const ImageIndex &textureIndex, + FramebufferAttachmentObject *resource, + GLsizei numViews, + GLint baseViewIndex) +{ + setAttachment(context, type, binding, textureIndex, resource, numViews, baseViewIndex, + GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE, + FramebufferAttachment::kDefaultViewportOffsets); +} + +void Framebuffer::setAttachmentMultiviewSideBySide(const Context *context, + GLenum type, + GLenum binding, + const ImageIndex &textureIndex, + FramebufferAttachmentObject *resource, + GLsizei numViews, + const GLint *viewportOffsets) +{ + setAttachment(context, type, binding, textureIndex, resource, numViews, + FramebufferAttachment::kDefaultBaseViewIndex, + GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE, viewportOffsets); +} + +void Framebuffer::commitWebGL1DepthStencilIfConsistent(const Context *context, + GLsizei numViews, + GLuint baseViewIndex, + GLenum multiviewLayout, + const GLint *viewportOffsets) +{ + int count = 0; + + std::array attachments = {{&mState.mWebGLDepthStencilAttachment, + &mState.mWebGLDepthAttachment, + &mState.mWebGLStencilAttachment}}; + for (FramebufferAttachment *attachment : attachments) { - // ensure this is a legitimate depth+stencil format - FramebufferAttachmentObject *attachmentObj = resource; - if (resource) + if (attachment->isAttached()) { - FramebufferAttachment::Target target(binding, textureIndex); - GLenum internalFormat = resource->getAttachmentInternalFormat(target); - const InternalFormat &formatInfo = GetInternalFormatInfo(internalFormat); - if (formatInfo.depthBits == 0 || formatInfo.stencilBits == 0) - { - // Attaching nullptr detaches the current attachment. - attachmentObj = nullptr; - } + count++; + } + } + + mState.mWebGLDepthStencilConsistent = (count <= 1); + if (!mState.mWebGLDepthStencilConsistent) + { + // Inconsistent. + return; + } + + auto getImageIndexIfTextureAttachment = [](const FramebufferAttachment &attachment) { + if (attachment.type() == GL_TEXTURE) + { + return attachment.getTextureImageIndex(); + } + else + { + return ImageIndex::MakeInvalid(); } + }; - mData.mDepthAttachment.attach(type, binding, textureIndex, attachmentObj); - mData.mStencilAttachment.attach(type, binding, textureIndex, attachmentObj); - mDirtyBits.set(DIRTY_BIT_DEPTH_ATTACHMENT); - mDirtyBits.set(DIRTY_BIT_STENCIL_ATTACHMENT); + if (mState.mWebGLDepthAttachment.isAttached()) + { + const auto &depth = mState.mWebGLDepthAttachment; + setAttachmentImpl(context, depth.type(), GL_DEPTH_ATTACHMENT, + getImageIndexIfTextureAttachment(depth), depth.getResource(), numViews, + baseViewIndex, multiviewLayout, viewportOffsets); + setAttachmentImpl(context, GL_NONE, GL_STENCIL_ATTACHMENT, ImageIndex::MakeInvalid(), + nullptr, numViews, baseViewIndex, multiviewLayout, viewportOffsets); + } + else if (mState.mWebGLStencilAttachment.isAttached()) + { + const auto &stencil = mState.mWebGLStencilAttachment; + setAttachmentImpl(context, GL_NONE, GL_DEPTH_ATTACHMENT, ImageIndex::MakeInvalid(), nullptr, + numViews, baseViewIndex, multiviewLayout, viewportOffsets); + setAttachmentImpl(context, stencil.type(), GL_STENCIL_ATTACHMENT, + getImageIndexIfTextureAttachment(stencil), stencil.getResource(), + numViews, baseViewIndex, multiviewLayout, viewportOffsets); + } + else if (mState.mWebGLDepthStencilAttachment.isAttached()) + { + const auto &depthStencil = mState.mWebGLDepthStencilAttachment; + setAttachmentImpl(context, depthStencil.type(), GL_DEPTH_ATTACHMENT, + getImageIndexIfTextureAttachment(depthStencil), + depthStencil.getResource(), numViews, baseViewIndex, multiviewLayout, + viewportOffsets); + setAttachmentImpl(context, depthStencil.type(), GL_STENCIL_ATTACHMENT, + getImageIndexIfTextureAttachment(depthStencil), + depthStencil.getResource(), numViews, baseViewIndex, multiviewLayout, + viewportOffsets); } else { - switch (binding) + setAttachmentImpl(context, GL_NONE, GL_DEPTH_ATTACHMENT, ImageIndex::MakeInvalid(), nullptr, + numViews, baseViewIndex, multiviewLayout, viewportOffsets); + setAttachmentImpl(context, GL_NONE, GL_STENCIL_ATTACHMENT, ImageIndex::MakeInvalid(), + nullptr, numViews, baseViewIndex, multiviewLayout, viewportOffsets); + } +} + +void Framebuffer::setAttachmentImpl(const Context *context, + GLenum type, + GLenum binding, + const ImageIndex &textureIndex, + FramebufferAttachmentObject *resource, + GLsizei numViews, + GLuint baseViewIndex, + GLenum multiviewLayout, + const GLint *viewportOffsets) +{ + switch (binding) + { + case GL_DEPTH_STENCIL: + case GL_DEPTH_STENCIL_ATTACHMENT: { - case GL_DEPTH: - case GL_DEPTH_ATTACHMENT: - mData.mDepthAttachment.attach(type, binding, textureIndex, resource); - mDirtyBits.set(DIRTY_BIT_DEPTH_ATTACHMENT); + // ensure this is a legitimate depth+stencil format + FramebufferAttachmentObject *attachmentObj = resource; + if (resource) + { + const Format &format = resource->getAttachmentFormat(binding, textureIndex); + if (format.info->depthBits == 0 || format.info->stencilBits == 0) + { + // Attaching nullptr detaches the current attachment. + attachmentObj = nullptr; + } + } + + updateAttachment(context, &mState.mDepthAttachment, DIRTY_BIT_DEPTH_ATTACHMENT, + &mDirtyDepthAttachmentBinding, type, binding, textureIndex, + attachmentObj, numViews, baseViewIndex, multiviewLayout, + viewportOffsets); + updateAttachment(context, &mState.mStencilAttachment, DIRTY_BIT_STENCIL_ATTACHMENT, + &mDirtyStencilAttachmentBinding, type, binding, textureIndex, + attachmentObj, numViews, baseViewIndex, multiviewLayout, + viewportOffsets); break; - case GL_STENCIL: - case GL_STENCIL_ATTACHMENT: - mData.mStencilAttachment.attach(type, binding, textureIndex, resource); - mDirtyBits.set(DIRTY_BIT_STENCIL_ATTACHMENT); + } + + case GL_DEPTH: + case GL_DEPTH_ATTACHMENT: + updateAttachment(context, &mState.mDepthAttachment, DIRTY_BIT_DEPTH_ATTACHMENT, + &mDirtyDepthAttachmentBinding, type, binding, textureIndex, resource, + numViews, baseViewIndex, multiviewLayout, viewportOffsets); break; - case GL_BACK: - mData.mColorAttachments[0].attach(type, binding, textureIndex, resource); - mDirtyBits.set(DIRTY_BIT_COLOR_ATTACHMENT_0); + + case GL_STENCIL: + case GL_STENCIL_ATTACHMENT: + updateAttachment(context, &mState.mStencilAttachment, DIRTY_BIT_STENCIL_ATTACHMENT, + &mDirtyStencilAttachmentBinding, type, binding, textureIndex, resource, + numViews, baseViewIndex, multiviewLayout, viewportOffsets); + break; + + case GL_BACK: + mState.mColorAttachments[0].attach(context, type, binding, textureIndex, resource, + numViews, baseViewIndex, multiviewLayout, + viewportOffsets); + mDirtyBits.set(DIRTY_BIT_COLOR_ATTACHMENT_0); + // No need for a resource binding for the default FBO, it's always complete. break; + + default: + { + size_t colorIndex = binding - GL_COLOR_ATTACHMENT0; + ASSERT(colorIndex < mState.mColorAttachments.size()); + size_t dirtyBit = DIRTY_BIT_COLOR_ATTACHMENT_0 + colorIndex; + updateAttachment(context, &mState.mColorAttachments[colorIndex], dirtyBit, + &mDirtyColorAttachmentBindings[colorIndex], type, binding, + textureIndex, resource, numViews, baseViewIndex, multiviewLayout, + viewportOffsets); + + // TODO(jmadill): ASSERT instead of checking the attachment exists in + // formsRenderingFeedbackLoopWith + bool enabled = (type != GL_NONE && getDrawBufferState(colorIndex) != GL_NONE); + mState.mEnabledDrawBuffers.set(colorIndex, enabled); + } + break; + } + + mAttachedTextures.reset(); +} + +void Framebuffer::updateAttachment(const Context *context, + FramebufferAttachment *attachment, + size_t dirtyBit, + OnAttachmentDirtyBinding *onDirtyBinding, + GLenum type, + GLenum binding, + const ImageIndex &textureIndex, + FramebufferAttachmentObject *resource, + GLsizei numViews, + GLuint baseViewIndex, + GLenum multiviewLayout, + const GLint *viewportOffsets) +{ + attachment->attach(context, type, binding, textureIndex, resource, numViews, baseViewIndex, + multiviewLayout, viewportOffsets); + mDirtyBits.set(dirtyBit); + mState.mResourceNeedsInit.set(dirtyBit, attachment->initState() == InitState::MayNeedInit); + BindResourceChannel(onDirtyBinding, resource); +} + +void Framebuffer::resetAttachment(const Context *context, GLenum binding) +{ + setAttachment(context, GL_NONE, binding, ImageIndex::MakeInvalid(), nullptr); +} + +void Framebuffer::syncState(const Context *context) +{ + if (mDirtyBits.any()) + { + mImpl->syncState(context, mDirtyBits); + mDirtyBits.reset(); + if (mId != 0) + { + mCachedStatus.reset(); + } + } +} + +void Framebuffer::signal(size_t dirtyBit, InitState state) +{ + // TOOD(jmadill): Make this only update individual attachments to do less work. + mCachedStatus.reset(); + + // Mark the appropriate init flag. + mState.mResourceNeedsInit.set(dirtyBit, state == InitState::MayNeedInit); +} + +bool Framebuffer::complete(const Context *context) +{ + return (checkStatus(context) == GL_FRAMEBUFFER_COMPLETE); +} + +bool Framebuffer::cachedComplete() const +{ + return (mCachedStatus.valid() && mCachedStatus == GL_FRAMEBUFFER_COMPLETE); +} + +bool Framebuffer::formsRenderingFeedbackLoopWith(const State &state) const +{ + const Program *program = state.getProgram(); + + // TODO(jmadill): Default framebuffer feedback loops. + if (mId == 0) + { + return false; + } + + // The bitset will skip inactive draw buffers. + for (size_t drawIndex : mState.mEnabledDrawBuffers) + { + const FramebufferAttachment &attachment = mState.mColorAttachments[drawIndex]; + ASSERT(attachment.isAttached()); + if (attachment.type() == GL_TEXTURE) + { + // Validate the feedback loop. + if (program->samplesFromTexture(state, attachment.id())) + { + return true; + } + } + } + + // Validate depth-stencil feedback loop. + const auto &dsState = state.getDepthStencilState(); + + // We can skip the feedback loop checks if depth/stencil is masked out or disabled. + const FramebufferAttachment *depth = getDepthbuffer(); + if (depth && depth->type() == GL_TEXTURE && dsState.depthTest && dsState.depthMask) + { + if (program->samplesFromTexture(state, depth->id())) + { + return true; + } + } + + // Note: we assume the front and back masks are the same for WebGL. + const FramebufferAttachment *stencil = getStencilbuffer(); + ASSERT(dsState.stencilBackWritemask == dsState.stencilWritemask); + if (stencil && stencil->type() == GL_TEXTURE && dsState.stencilTest && + dsState.stencilWritemask != 0) + { + // Skip the feedback loop check if depth/stencil point to the same resource. + if (!depth || *stencil != *depth) + { + if (program->samplesFromTexture(state, stencil->id())) + { + return true; + } + } + } + + return false; +} + +bool Framebuffer::formsCopyingFeedbackLoopWith(GLuint copyTextureID, + GLint copyTextureLevel, + GLint copyTextureLayer) const +{ + if (mId == 0) + { + // It seems impossible to form a texture copying feedback loop with the default FBO. + return false; + } + + const FramebufferAttachment *readAttachment = getReadColorbuffer(); + ASSERT(readAttachment); + + if (readAttachment->isTextureWithId(copyTextureID)) + { + const auto &imageIndex = readAttachment->getTextureImageIndex(); + if (imageIndex.mipIndex == copyTextureLevel) + { + // Check 3D/Array texture layers. + return imageIndex.layerIndex == ImageIndex::ENTIRE_LEVEL || + copyTextureLayer == ImageIndex::ENTIRE_LEVEL || + imageIndex.layerIndex == copyTextureLayer; + } + } + return false; +} + +GLint Framebuffer::getDefaultWidth() const +{ + return mState.getDefaultWidth(); +} + +GLint Framebuffer::getDefaultHeight() const +{ + return mState.getDefaultHeight(); +} + +GLint Framebuffer::getDefaultSamples() const +{ + return mState.getDefaultSamples(); +} + +bool Framebuffer::getDefaultFixedSampleLocations() const +{ + return mState.getDefaultFixedSampleLocations(); +} + +void Framebuffer::setDefaultWidth(GLint defaultWidth) +{ + mState.mDefaultWidth = defaultWidth; + mDirtyBits.set(DIRTY_BIT_DEFAULT_WIDTH); +} + +void Framebuffer::setDefaultHeight(GLint defaultHeight) +{ + mState.mDefaultHeight = defaultHeight; + mDirtyBits.set(DIRTY_BIT_DEFAULT_HEIGHT); +} + +void Framebuffer::setDefaultSamples(GLint defaultSamples) +{ + mState.mDefaultSamples = defaultSamples; + mDirtyBits.set(DIRTY_BIT_DEFAULT_SAMPLES); +} + +void Framebuffer::setDefaultFixedSampleLocations(bool defaultFixedSampleLocations) +{ + mState.mDefaultFixedSampleLocations = defaultFixedSampleLocations; + mDirtyBits.set(DIRTY_BIT_DEFAULT_FIXED_SAMPLE_LOCATIONS); +} + +// TODO(jmadill): Remove this kludge. +GLenum Framebuffer::checkStatus(const ValidationContext *context) +{ + return checkStatus(static_cast(context)); +} + +int Framebuffer::getSamples(const ValidationContext *context) +{ + return getSamples(static_cast(context)); +} + +GLsizei Framebuffer::getNumViews() const +{ + return mState.getNumViews(); +} + +GLint Framebuffer::getBaseViewIndex() const +{ + return mState.getBaseViewIndex(); +} + +const std::vector *Framebuffer::getViewportOffsets() const +{ + return mState.getViewportOffsets(); +} + +GLenum Framebuffer::getMultiviewLayout() const +{ + return mState.getMultiviewLayout(); +} + +Error Framebuffer::ensureDrawAttachmentsInitialized(const Context *context) +{ + if (!context->isRobustResourceInitEnabled()) + { + return NoError(); + } + + // Note: we don't actually filter by the draw attachment enum. Just init everything. + for (size_t bit : mState.mResourceNeedsInit) + { + switch (bit) + { + case DIRTY_BIT_DEPTH_ATTACHMENT: + ANGLE_TRY(InitAttachment(context, &mState.mDepthAttachment)); + break; + case DIRTY_BIT_STENCIL_ATTACHMENT: + ANGLE_TRY(InitAttachment(context, &mState.mStencilAttachment)); + break; default: + ANGLE_TRY(InitAttachment(context, &mState.mColorAttachments[bit])); + break; + } + } + + mState.mResourceNeedsInit.reset(); + return NoError(); +} + +Error Framebuffer::ensureReadAttachmentInitialized(const Context *context, GLbitfield blitMask) +{ + if (!context->isRobustResourceInitEnabled() || mState.mResourceNeedsInit.none()) + { + return NoError(); + } + + if ((blitMask & GL_COLOR_BUFFER_BIT) != 0 && mState.mReadBufferState != GL_NONE) + { + size_t readIndex = mState.getReadIndex(); + if (mState.mResourceNeedsInit[readIndex]) + { + ANGLE_TRY(InitAttachment(context, &mState.mColorAttachments[readIndex])); + mState.mResourceNeedsInit.reset(readIndex); + } + } + + if ((blitMask & GL_DEPTH_BUFFER_BIT) != 0 && hasDepth()) + { + if (mState.mResourceNeedsInit[DIRTY_BIT_DEPTH_ATTACHMENT]) + { + ANGLE_TRY(InitAttachment(context, &mState.mDepthAttachment)); + mState.mResourceNeedsInit.reset(DIRTY_BIT_DEPTH_ATTACHMENT); + } + } + + if ((blitMask & GL_STENCIL_BUFFER_BIT) != 0 && hasStencil()) + { + if (mState.mResourceNeedsInit[DIRTY_BIT_STENCIL_ATTACHMENT]) + { + ANGLE_TRY(InitAttachment(context, &mState.mStencilAttachment)); + mState.mResourceNeedsInit.reset(DIRTY_BIT_STENCIL_ATTACHMENT); + } + } + + return NoError(); +} + +void Framebuffer::markDrawAttachmentsInitialized(bool color, bool depth, bool stencil) +{ + // Mark attachments as initialized. + if (color) + { + for (auto colorIndex : mState.mEnabledDrawBuffers) + { + auto &colorAttachment = mState.mColorAttachments[colorIndex]; + ASSERT(colorAttachment.isAttached()); + colorAttachment.setInitState(InitState::Initialized); + mState.mResourceNeedsInit.reset(colorIndex); + } + } + + if (depth && mState.mDepthAttachment.isAttached()) + { + mState.mDepthAttachment.setInitState(InitState::Initialized); + mState.mResourceNeedsInit.reset(DIRTY_BIT_DEPTH_ATTACHMENT); + } + + if (stencil && mState.mStencilAttachment.isAttached()) + { + mState.mStencilAttachment.setInitState(InitState::Initialized); + mState.mResourceNeedsInit.reset(DIRTY_BIT_STENCIL_ATTACHMENT); + } +} + +void Framebuffer::markBufferInitialized(GLenum bufferType, GLint bufferIndex) +{ + switch (bufferType) + { + case GL_COLOR: + { + ASSERT(bufferIndex < static_cast(mState.mColorAttachments.size())); + if (mState.mColorAttachments[bufferIndex].isAttached()) + { + mState.mColorAttachments[bufferIndex].setInitState(InitState::Initialized); + mState.mResourceNeedsInit.reset(bufferIndex); + } + break; + } + case GL_DEPTH: + { + if (mState.mDepthAttachment.isAttached()) + { + mState.mDepthAttachment.setInitState(InitState::Initialized); + mState.mResourceNeedsInit.reset(DIRTY_BIT_DEPTH_ATTACHMENT); + } + break; + } + case GL_STENCIL: + { + if (mState.mStencilAttachment.isAttached()) + { + mState.mStencilAttachment.setInitState(InitState::Initialized); + mState.mResourceNeedsInit.reset(DIRTY_BIT_STENCIL_ATTACHMENT); + } + break; + } + case GL_DEPTH_STENCIL: + { + if (mState.mDepthAttachment.isAttached()) + { + mState.mDepthAttachment.setInitState(InitState::Initialized); + mState.mResourceNeedsInit.reset(DIRTY_BIT_DEPTH_ATTACHMENT); + } + if (mState.mStencilAttachment.isAttached()) { - size_t colorIndex = binding - GL_COLOR_ATTACHMENT0; - ASSERT(colorIndex < mData.mColorAttachments.size()); - mData.mColorAttachments[colorIndex].attach(type, binding, textureIndex, resource); - mDirtyBits.set(DIRTY_BIT_COLOR_ATTACHMENT_0 + colorIndex); + mState.mStencilAttachment.setInitState(InitState::Initialized); + mState.mResourceNeedsInit.reset(DIRTY_BIT_STENCIL_ATTACHMENT); } break; } + default: + UNREACHABLE(); + break; } } -void Framebuffer::resetAttachment(GLenum binding) +Box Framebuffer::getDimensions() const { - setAttachment(GL_NONE, binding, ImageIndex::MakeInvalid(), nullptr); + return mState.getDimensions(); } -void Framebuffer::syncState() const +Error Framebuffer::ensureBufferInitialized(const Context *context, + GLenum bufferType, + GLint bufferIndex) { - if (mDirtyBits.any()) + ASSERT(context->isRobustResourceInitEnabled()); + + if (mState.mResourceNeedsInit.none()) { - mImpl->syncState(mDirtyBits); - mDirtyBits.reset(); + return NoError(); } + + switch (bufferType) + { + case GL_COLOR: + { + ASSERT(bufferIndex < static_cast(mState.mColorAttachments.size())); + if (mState.mResourceNeedsInit[bufferIndex]) + { + ANGLE_TRY(InitAttachment(context, &mState.mColorAttachments[bufferIndex])); + mState.mResourceNeedsInit.reset(bufferIndex); + } + break; + } + case GL_DEPTH: + { + if (mState.mResourceNeedsInit[DIRTY_BIT_DEPTH_ATTACHMENT]) + { + ANGLE_TRY(InitAttachment(context, &mState.mDepthAttachment)); + mState.mResourceNeedsInit.reset(DIRTY_BIT_DEPTH_ATTACHMENT); + } + break; + } + case GL_STENCIL: + { + if (mState.mResourceNeedsInit[DIRTY_BIT_STENCIL_ATTACHMENT]) + { + ANGLE_TRY(InitAttachment(context, &mState.mStencilAttachment)); + mState.mResourceNeedsInit.reset(DIRTY_BIT_STENCIL_ATTACHMENT); + } + break; + } + case GL_DEPTH_STENCIL: + { + if (mState.mResourceNeedsInit[DIRTY_BIT_DEPTH_ATTACHMENT]) + { + ANGLE_TRY(InitAttachment(context, &mState.mDepthAttachment)); + mState.mResourceNeedsInit.reset(DIRTY_BIT_DEPTH_ATTACHMENT); + } + if (mState.mResourceNeedsInit[DIRTY_BIT_STENCIL_ATTACHMENT]) + { + ANGLE_TRY(InitAttachment(context, &mState.mStencilAttachment)); + mState.mResourceNeedsInit.reset(DIRTY_BIT_STENCIL_ATTACHMENT); + } + break; + } + default: + UNREACHABLE(); + break; + } + + return NoError(); +} + +bool Framebuffer::partialBufferClearNeedsInit(const Context *context, GLenum bufferType) +{ + if (!context->isRobustResourceInitEnabled() || mState.mResourceNeedsInit.none()) + { + return false; + } + + switch (bufferType) + { + case GL_COLOR: + return partialClearNeedsInit(context, true, false, false); + case GL_DEPTH: + return partialClearNeedsInit(context, false, true, false); + case GL_STENCIL: + return partialClearNeedsInit(context, false, false, true); + case GL_DEPTH_STENCIL: + return partialClearNeedsInit(context, false, true, true); + default: + UNREACHABLE(); + return false; + } +} + +bool Framebuffer::hasTextureAttachment(const Texture *texture) const +{ + if (!mAttachedTextures.valid()) + { + std::set attachedTextures; + + for (const auto &colorAttachment : mState.mColorAttachments) + { + if (colorAttachment.isAttached() && colorAttachment.type() == GL_TEXTURE) + { + attachedTextures.insert(colorAttachment.getResource()); + } + } + + if (mState.mDepthAttachment.isAttached() && mState.mDepthAttachment.type() == GL_TEXTURE) + { + attachedTextures.insert(mState.mDepthAttachment.getResource()); + } + + if (mState.mStencilAttachment.isAttached() && + mState.mStencilAttachment.type() == GL_TEXTURE) + { + attachedTextures.insert(mState.mStencilAttachment.getResource()); + } + + mAttachedTextures = std::move(attachedTextures); + } + + return (mAttachedTextures.value().count(texture) > 0); } } // namespace gl diff --git a/src/3rdparty/angle/src/libANGLE/Framebuffer.h b/src/3rdparty/angle/src/libANGLE/Framebuffer.h index b07b59ac90..70223f0bc7 100644 --- a/src/3rdparty/angle/src/libANGLE/Framebuffer.h +++ b/src/3rdparty/angle/src/libANGLE/Framebuffer.h @@ -12,16 +12,18 @@ #include +#include "common/Optional.h" #include "common/angleutils.h" #include "libANGLE/Constants.h" #include "libANGLE/Debug.h" #include "libANGLE/Error.h" #include "libANGLE/FramebufferAttachment.h" #include "libANGLE/RefCountObject.h" +#include "libANGLE/signal_utils.h" namespace rx { -class ImplFactory; +class GLImplFactory; class FramebufferImpl; class RenderbufferImpl; class SurfaceImpl; @@ -29,98 +31,171 @@ class SurfaceImpl; namespace egl { +class Display; class Surface; } namespace gl { class Context; +class ContextState; +class Framebuffer; class Renderbuffer; class State; class Texture; class TextureCapsMap; +class ValidationContext; struct Caps; -struct Data; struct Extensions; struct ImageIndex; struct Rectangle; -class Framebuffer final : public LabeledObject +class FramebufferState final : angle::NonCopyable { public: + FramebufferState(); + explicit FramebufferState(const Caps &caps); + ~FramebufferState(); - class Data final : angle::NonCopyable + const std::string &getLabel(); + size_t getReadIndex() const; + + const FramebufferAttachment *getAttachment(GLenum attachment) const; + const FramebufferAttachment *getReadAttachment() const; + const FramebufferAttachment *getFirstNonNullAttachment() const; + const FramebufferAttachment *getFirstColorAttachment() const; + const FramebufferAttachment *getDepthOrStencilAttachment() const; + const FramebufferAttachment *getStencilOrDepthStencilAttachment() const; + const FramebufferAttachment *getColorAttachment(size_t colorAttachment) const; + const FramebufferAttachment *getDepthAttachment() const; + const FramebufferAttachment *getStencilAttachment() const; + const FramebufferAttachment *getDepthStencilAttachment() const; + + const std::vector &getDrawBufferStates() const { return mDrawBufferStates; } + DrawBufferMask getEnabledDrawBuffers() const { return mEnabledDrawBuffers; } + GLenum getReadBufferState() const { return mReadBufferState; } + const std::vector &getColorAttachments() const { - public: - explicit Data(); - explicit Data(const Caps &caps); - ~Data(); + return mColorAttachments; + } - const std::string &getLabel(); + bool attachmentsHaveSameDimensions() const; + bool colorAttachmentsAreUniqueImages() const; + Box getDimensions() const; - const FramebufferAttachment *getReadAttachment() const; - const FramebufferAttachment *getFirstColorAttachment() const; - const FramebufferAttachment *getDepthOrStencilAttachment() const; - const FramebufferAttachment *getColorAttachment(size_t colorAttachment) const; - const FramebufferAttachment *getDepthAttachment() const; - const FramebufferAttachment *getStencilAttachment() const; - const FramebufferAttachment *getDepthStencilAttachment() const; + const FramebufferAttachment *getDrawBuffer(size_t drawBufferIdx) const; + size_t getDrawBufferCount() const; - const std::vector &getDrawBufferStates() const { return mDrawBufferStates; } - GLenum getReadBufferState() const { return mReadBufferState; } - const std::vector &getColorAttachments() const { return mColorAttachments; } + GLint getDefaultWidth() const { return mDefaultWidth; }; + GLint getDefaultHeight() const { return mDefaultHeight; }; + GLint getDefaultSamples() const { return mDefaultSamples; }; + bool getDefaultFixedSampleLocations() const { return mDefaultFixedSampleLocations; }; - bool attachmentsHaveSameDimensions() const; + bool hasDepth() const; + bool hasStencil() const; - private: - friend class Framebuffer; + GLenum getMultiviewLayout() const; + GLsizei getNumViews() const; + const std::vector *getViewportOffsets() const; + GLint getBaseViewIndex() const; - std::string mLabel; + private: + friend class Framebuffer; - std::vector mColorAttachments; - FramebufferAttachment mDepthAttachment; - FramebufferAttachment mStencilAttachment; + std::string mLabel; - std::vector mDrawBufferStates; - GLenum mReadBufferState; - }; + std::vector mColorAttachments; + FramebufferAttachment mDepthAttachment; + FramebufferAttachment mStencilAttachment; - Framebuffer(const Caps &caps, rx::ImplFactory *factory, GLuint id); - Framebuffer(rx::SurfaceImpl *surface); - virtual ~Framebuffer(); + std::vector mDrawBufferStates; + GLenum mReadBufferState; + DrawBufferMask mEnabledDrawBuffers; + + GLint mDefaultWidth; + GLint mDefaultHeight; + GLint mDefaultSamples; + bool mDefaultFixedSampleLocations; + + // It's necessary to store all this extra state so we can restore attachments + // when DEPTH_STENCIL/DEPTH/STENCIL is unbound in WebGL 1. + FramebufferAttachment mWebGLDepthStencilAttachment; + FramebufferAttachment mWebGLDepthAttachment; + FramebufferAttachment mWebGLStencilAttachment; + bool mWebGLDepthStencilConsistent; + + // Tracks if we need to initialize the resources for each attachment. + angle::BitSet mResourceNeedsInit; +}; + +class Framebuffer final : public LabeledObject, public OnAttachmentDirtyReceiver +{ + public: + // Constructor to build application-defined framebuffers + Framebuffer(const Caps &caps, rx::GLImplFactory *factory, GLuint id); + // Constructor to build default framebuffers for a surface + Framebuffer(const egl::Display *display, egl::Surface *surface); + // Constructor to build a fake default framebuffer when surfaceless + Framebuffer(rx::GLImplFactory *factory); + + ~Framebuffer() override; + void onDestroy(const Context *context); + void destroyDefault(const egl::Display *display); void setLabel(const std::string &label) override; const std::string &getLabel() const override; - const rx::FramebufferImpl *getImplementation() const { return mImpl; } - rx::FramebufferImpl *getImplementation() { return mImpl; } + rx::FramebufferImpl *getImplementation() const { return mImpl; } GLuint id() const { return mId; } - void setAttachment(GLenum type, + void setAttachment(const Context *context, + GLenum type, GLenum binding, const ImageIndex &textureIndex, FramebufferAttachmentObject *resource); - void resetAttachment(GLenum binding); - - void detachTexture(GLuint texture); - void detachRenderbuffer(GLuint renderbuffer); + void setAttachmentMultiviewLayered(const Context *context, + GLenum type, + GLenum binding, + const ImageIndex &textureIndex, + FramebufferAttachmentObject *resource, + GLsizei numViews, + GLint baseViewIndex); + void setAttachmentMultiviewSideBySide(const Context *context, + GLenum type, + GLenum binding, + const ImageIndex &textureIndex, + FramebufferAttachmentObject *resource, + GLsizei numViews, + const GLint *viewportOffsets); + void resetAttachment(const Context *context, GLenum binding); + + bool detachTexture(const Context *context, GLuint texture); + bool detachRenderbuffer(const Context *context, GLuint renderbuffer); const FramebufferAttachment *getColorbuffer(size_t colorAttachment) const; const FramebufferAttachment *getDepthbuffer() const; const FramebufferAttachment *getStencilbuffer() const; const FramebufferAttachment *getDepthStencilBuffer() const; const FramebufferAttachment *getDepthOrStencilbuffer() const; + const FramebufferAttachment *getStencilOrDepthStencilAttachment() const; const FramebufferAttachment *getReadColorbuffer() const; GLenum getReadColorbufferType() const; const FramebufferAttachment *getFirstColorbuffer() const; + const FramebufferAttachment *getFirstNonNullAttachment() const; const FramebufferAttachment *getAttachment(GLenum attachment) const; + GLenum getMultiviewLayout() const; + GLsizei getNumViews() const; + GLint getBaseViewIndex() const; + const std::vector *getViewportOffsets() const; size_t getDrawbufferStateCount() const; GLenum getDrawBufferState(size_t drawBuffer) const; + const std::vector &getDrawBufferStates() const; void setDrawBuffers(size_t count, const GLenum *buffers); const FramebufferAttachment *getDrawBuffer(size_t drawBuffer) const; + GLenum getDrawbufferWriteType(size_t drawBuffer) const; bool hasEnabledDrawBuffer() const; GLenum getReadBufferState() const; @@ -129,48 +204,81 @@ class Framebuffer final : public LabeledObject size_t getNumColorBuffers() const; bool hasDepth() const; bool hasStencil() const; - int getSamples(const gl::Data &data) const; + bool usingExtendedDrawBuffers() const; - GLenum checkStatus(const gl::Data &data) const; + // This method calls checkStatus. + int getSamples(const Context *context); + + Error getSamplePosition(size_t index, GLfloat *xy) const; + + GLint getDefaultWidth() const; + GLint getDefaultHeight() const; + GLint getDefaultSamples() const; + bool getDefaultFixedSampleLocations() const; + void setDefaultWidth(GLint defaultWidth); + void setDefaultHeight(GLint defaultHeight); + void setDefaultSamples(GLint defaultSamples); + void setDefaultFixedSampleLocations(bool defaultFixedSampleLocations); + + void invalidateCompletenessCache(); + + GLenum checkStatus(const Context *context); + + // TODO(jmadill): Remove this kludge. + GLenum checkStatus(const ValidationContext *context); + int getSamples(const ValidationContext *context); + + // For when we don't want to check completeness in getSamples(). + int getCachedSamples(const Context *context); + + // Helper for checkStatus == GL_FRAMEBUFFER_COMPLETE. + bool complete(const Context *context); + bool cachedComplete() const; + bool hasValidDepthStencil() const; - Error discard(size_t count, const GLenum *attachments); - Error invalidate(size_t count, const GLenum *attachments); - Error invalidateSub(size_t count, const GLenum *attachments, const gl::Rectangle &area); + Error discard(const Context *context, size_t count, const GLenum *attachments); + Error invalidate(const Context *context, size_t count, const GLenum *attachments); + Error invalidateSub(const Context *context, + size_t count, + const GLenum *attachments, + const gl::Rectangle &area); - Error clear(const gl::Data &data, GLbitfield mask); - Error clearBufferfv(const gl::Data &data, + Error clear(const gl::Context *context, GLbitfield mask); + Error clearBufferfv(const gl::Context *context, GLenum buffer, GLint drawbuffer, const GLfloat *values); - Error clearBufferuiv(const gl::Data &data, + Error clearBufferuiv(const gl::Context *context, GLenum buffer, GLint drawbuffer, const GLuint *values); - Error clearBufferiv(const gl::Data &data, GLenum buffer, GLint drawbuffer, const GLint *values); - Error clearBufferfi(const gl::Data &data, + Error clearBufferiv(const gl::Context *context, + GLenum buffer, + GLint drawbuffer, + const GLint *values); + Error clearBufferfi(const gl::Context *context, GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil); - GLenum getImplementationColorReadFormat() const; - GLenum getImplementationColorReadType() const; - Error readPixels(const gl::State &state, + GLenum getImplementationColorReadFormat(const Context *context) const; + GLenum getImplementationColorReadType(const Context *context) const; + Error readPixels(const gl::Context *context, const gl::Rectangle &area, GLenum format, GLenum type, - GLvoid *pixels) const; + void *pixels); - Error blit(const State &state, + Error blit(const gl::Context *context, const Rectangle &sourceArea, const Rectangle &destArea, GLbitfield mask, - GLenum filter, - const Framebuffer *sourceFramebuffer); + GLenum filter); - enum DirtyBitType + enum DirtyBitType : size_t { DIRTY_BIT_COLOR_ATTACHMENT_0, DIRTY_BIT_COLOR_ATTACHMENT_MAX = @@ -179,26 +287,103 @@ class Framebuffer final : public LabeledObject DIRTY_BIT_STENCIL_ATTACHMENT, DIRTY_BIT_DRAW_BUFFERS, DIRTY_BIT_READ_BUFFER, + DIRTY_BIT_DEFAULT_WIDTH, + DIRTY_BIT_DEFAULT_HEIGHT, + DIRTY_BIT_DEFAULT_SAMPLES, + DIRTY_BIT_DEFAULT_FIXED_SAMPLE_LOCATIONS, DIRTY_BIT_UNKNOWN, - DIRTY_BIT_MAX = DIRTY_BIT_UNKNOWN, + DIRTY_BIT_MAX = DIRTY_BIT_UNKNOWN }; - typedef std::bitset DirtyBits; + typedef angle::BitSet DirtyBits; bool hasAnyDirtyBit() const { return mDirtyBits.any(); } - void syncState() const; + void syncState(const Context *context); - protected: - void detachResourceById(GLenum resourceType, GLuint resourceId); + // OnAttachmentChangedReceiver implementation + void signal(size_t dirtyBit, InitState state) override; - Data mData; + bool formsRenderingFeedbackLoopWith(const State &state) const; + bool formsCopyingFeedbackLoopWith(GLuint copyTextureID, + GLint copyTextureLevel, + GLint copyTextureLayer) const; + + Error ensureDrawAttachmentsInitialized(const Context *context); + Error ensureReadAttachmentInitialized(const Context *context, GLbitfield blitMask); + Box getDimensions() const; + + bool hasTextureAttachment(const Texture *texture) const; + + private: + bool detachResourceById(const Context *context, GLenum resourceType, GLuint resourceId); + bool detachMatchingAttachment(const Context *context, + FramebufferAttachment *attachment, + GLenum matchType, + GLuint matchId, + size_t dirtyBit); + GLenum checkStatusImpl(const Context *context); + void setAttachment(const Context *context, + GLenum type, + GLenum binding, + const ImageIndex &textureIndex, + FramebufferAttachmentObject *resource, + GLsizei numViews, + GLuint baseViewIndex, + GLenum multiviewLayout, + const GLint *viewportOffsets); + void commitWebGL1DepthStencilIfConsistent(const Context *context, + GLsizei numViews, + GLuint baseViewIndex, + GLenum multiviewLayout, + const GLint *viewportOffsets); + void setAttachmentImpl(const Context *context, + GLenum type, + GLenum binding, + const ImageIndex &textureIndex, + FramebufferAttachmentObject *resource, + GLsizei numViews, + GLuint baseViewIndex, + GLenum multiviewLayout, + const GLint *viewportOffsets); + void updateAttachment(const Context *context, + FramebufferAttachment *attachment, + size_t dirtyBit, + OnAttachmentDirtyBinding *onDirtyBinding, + GLenum type, + GLenum binding, + const ImageIndex &textureIndex, + FramebufferAttachmentObject *resource, + GLsizei numViews, + GLuint baseViewIndex, + GLenum multiviewLayout, + const GLint *viewportOffsets); + + void markDrawAttachmentsInitialized(bool color, bool depth, bool stencil); + void markBufferInitialized(GLenum bufferType, GLint bufferIndex); + Error ensureBufferInitialized(const Context *context, GLenum bufferType, GLint bufferIndex); + + // Checks that we have a partially masked clear: + // * some color channels are masked out + // * some stencil values are masked out + // * scissor test partially overlaps the framebuffer + bool partialClearNeedsInit(const Context *context, bool color, bool depth, bool stencil); + bool partialBufferClearNeedsInit(const Context *context, GLenum bufferType); + + FramebufferState mState; rx::FramebufferImpl *mImpl; GLuint mId; - // TODO(jmadill): See if we can make this non-mutable. - mutable DirtyBits mDirtyBits; + Optional mCachedStatus; + std::vector mDirtyColorAttachmentBindings; + OnAttachmentDirtyBinding mDirtyDepthAttachmentBinding; + OnAttachmentDirtyBinding mDirtyStencilAttachmentBinding; + + DirtyBits mDirtyBits; + + // A cache of attached textures for quick validation of feedback loops. + mutable Optional> mAttachedTextures; }; -} +} // namespace gl -#endif // LIBANGLE_FRAMEBUFFER_H_ +#endif // LIBANGLE_FRAMEBUFFER_H_ diff --git a/src/3rdparty/angle/src/libANGLE/FramebufferAttachment.cpp b/src/3rdparty/angle/src/libANGLE/FramebufferAttachment.cpp index 352a326c23..cf6bd9c264 100644 --- a/src/3rdparty/angle/src/libANGLE/FramebufferAttachment.cpp +++ b/src/3rdparty/angle/src/libANGLE/FramebufferAttachment.cpp @@ -11,17 +11,48 @@ #include "common/utilities.h" #include "libANGLE/Config.h" +#include "libANGLE/Context.h" #include "libANGLE/Renderbuffer.h" #include "libANGLE/Surface.h" #include "libANGLE/Texture.h" #include "libANGLE/formatutils.h" +#include "libANGLE/renderer/FramebufferAttachmentObjectImpl.h" #include "libANGLE/renderer/FramebufferImpl.h" namespace gl { +namespace +{ + +std::vector TransformViewportOffsetArrayToVectorOfOffsets(const GLint *viewportOffsets, + GLsizei numViews) +{ + const size_t numViewsAsSizeT = static_cast(numViews); + std::vector offsetVector; + offsetVector.reserve(numViewsAsSizeT); + for (size_t i = 0u; i < numViewsAsSizeT; ++i) + { + offsetVector.emplace_back(Offset(viewportOffsets[i * 2u], viewportOffsets[i * 2u + 1u], 0)); + } + return offsetVector; +} + +} // namespace + ////// FramebufferAttachment::Target Implementation ////// +const GLsizei FramebufferAttachment::kDefaultNumViews = 1; +const GLenum FramebufferAttachment::kDefaultMultiviewLayout = GL_NONE; +const GLint FramebufferAttachment::kDefaultBaseViewIndex = 0; +const GLint FramebufferAttachment::kDefaultViewportOffsets[2] = {0}; + +std::vector FramebufferAttachment::GetDefaultViewportOffsetVector() +{ + return TransformViewportOffsetArrayToVectorOfOffsets( + FramebufferAttachment::kDefaultViewportOffsets, FramebufferAttachment::kDefaultNumViews); +} + FramebufferAttachment::Target::Target() : mBinding(GL_NONE), mTextureIndex(ImageIndex::MakeInvalid()) @@ -50,106 +81,143 @@ FramebufferAttachment::Target &FramebufferAttachment::Target::operator=(const Ta ////// FramebufferAttachment Implementation ////// FramebufferAttachment::FramebufferAttachment() - : mType(GL_NONE), mResource(nullptr) + : mType(GL_NONE), + mResource(nullptr), + mNumViews(kDefaultNumViews), + mMultiviewLayout(kDefaultMultiviewLayout), + mBaseViewIndex(kDefaultBaseViewIndex), + mViewportOffsets(GetDefaultViewportOffsetVector()) { } -FramebufferAttachment::FramebufferAttachment(GLenum type, +FramebufferAttachment::FramebufferAttachment(const Context *context, + GLenum type, GLenum binding, const ImageIndex &textureIndex, FramebufferAttachmentObject *resource) : mResource(nullptr) { - attach(type, binding, textureIndex, resource); + attach(context, type, binding, textureIndex, resource, kDefaultNumViews, kDefaultBaseViewIndex, + kDefaultMultiviewLayout, kDefaultViewportOffsets); } -FramebufferAttachment::FramebufferAttachment(const FramebufferAttachment &other) - : mResource(nullptr) +FramebufferAttachment::FramebufferAttachment(FramebufferAttachment &&other) + : FramebufferAttachment() { - attach(other.mType, other.mTarget.binding(), other.mTarget.textureIndex(), other.mResource); + *this = std::move(other); } -FramebufferAttachment &FramebufferAttachment::operator=(const FramebufferAttachment &other) +FramebufferAttachment &FramebufferAttachment::operator=(FramebufferAttachment &&other) { - attach(other.mType, other.mTarget.binding(), other.mTarget.textureIndex(), other.mResource); + std::swap(mType, other.mType); + std::swap(mTarget, other.mTarget); + std::swap(mResource, other.mResource); + std::swap(mNumViews, other.mNumViews); + std::swap(mMultiviewLayout, other.mMultiviewLayout); + std::swap(mBaseViewIndex, other.mBaseViewIndex); + std::swap(mViewportOffsets, other.mViewportOffsets); return *this; } FramebufferAttachment::~FramebufferAttachment() { - detach(); + ASSERT(!isAttached()); } -void FramebufferAttachment::detach() +void FramebufferAttachment::detach(const Context *context) { mType = GL_NONE; if (mResource != nullptr) { - mResource->onDetach(); + mResource->onDetach(context); mResource = nullptr; } + mNumViews = kDefaultNumViews; + mMultiviewLayout = kDefaultMultiviewLayout; + mBaseViewIndex = kDefaultBaseViewIndex; + mViewportOffsets = GetDefaultViewportOffsetVector(); // not technically necessary, could omit for performance mTarget = Target(); } -void FramebufferAttachment::attach(GLenum type, +void FramebufferAttachment::attach(const Context *context, + GLenum type, GLenum binding, const ImageIndex &textureIndex, - FramebufferAttachmentObject *resource) + FramebufferAttachmentObject *resource, + GLsizei numViews, + GLuint baseViewIndex, + GLenum multiviewLayout, + const GLint *viewportOffsets) { + if (resource == nullptr) + { + detach(context); + return; + } + mType = type; mTarget = Target(binding, textureIndex); - - if (resource) + mNumViews = numViews; + mBaseViewIndex = baseViewIndex; + mMultiviewLayout = multiviewLayout; + if (multiviewLayout == GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE) { - resource->onAttach(); + mViewportOffsets = TransformViewportOffsetArrayToVectorOfOffsets(viewportOffsets, numViews); } + else + { + mViewportOffsets = GetDefaultViewportOffsetVector(); + } + resource->onAttach(context); + if (mResource != nullptr) { - mResource->onDetach(); + mResource->onDetach(context); } + mResource = resource; } GLuint FramebufferAttachment::getRedSize() const { - return GetInternalFormatInfo(getInternalFormat()).redBits; + return getFormat().info->redBits; } GLuint FramebufferAttachment::getGreenSize() const { - return GetInternalFormatInfo(getInternalFormat()).greenBits; + return getFormat().info->greenBits; } GLuint FramebufferAttachment::getBlueSize() const { - return GetInternalFormatInfo(getInternalFormat()).blueBits; + return getFormat().info->blueBits; } GLuint FramebufferAttachment::getAlphaSize() const { - return GetInternalFormatInfo(getInternalFormat()).alphaBits; + return getFormat().info->alphaBits; } GLuint FramebufferAttachment::getDepthSize() const { - return GetInternalFormatInfo(getInternalFormat()).depthBits; + return getFormat().info->depthBits; } GLuint FramebufferAttachment::getStencilSize() const { - return GetInternalFormatInfo(getInternalFormat()).stencilBits; + return getFormat().info->stencilBits; } GLenum FramebufferAttachment::getComponentType() const { - return GetInternalFormatInfo(getInternalFormat()).componentType; + return getFormat().info->componentType; } GLenum FramebufferAttachment::getColorEncoding() const { - return GetInternalFormatInfo(getInternalFormat()).colorEncoding; + return getFormat().info->colorEncoding; } GLuint FramebufferAttachment::id() const @@ -190,6 +258,26 @@ GLint FramebufferAttachment::layer() const return 0; } +GLsizei FramebufferAttachment::getNumViews() const +{ + return mNumViews; +} + +GLenum FramebufferAttachment::getMultiviewLayout() const +{ + return mMultiviewLayout; +} + +GLint FramebufferAttachment::getBaseViewIndex() const +{ + return mBaseViewIndex; +} + +const std::vector &FramebufferAttachment::getMultiviewViewportOffsets() const +{ + return mViewportOffsets; +} + Texture *FramebufferAttachment::getTexture() const { return rx::GetAs(mResource); @@ -205,4 +293,93 @@ const egl::Surface *FramebufferAttachment::getSurface() const return rx::GetAs(mResource); } +FramebufferAttachmentObject *FramebufferAttachment::getResource() const +{ + return mResource; } + +bool FramebufferAttachment::operator==(const FramebufferAttachment &other) const +{ + if (mResource != other.mResource || mType != other.mType || mNumViews != other.mNumViews || + mMultiviewLayout != other.mMultiviewLayout || mBaseViewIndex != other.mBaseViewIndex || + mViewportOffsets != other.mViewportOffsets) + { + return false; + } + + if (mType == GL_TEXTURE && getTextureImageIndex() != other.getTextureImageIndex()) + { + return false; + } + + return true; +} + +bool FramebufferAttachment::operator!=(const FramebufferAttachment &other) const +{ + return !(*this == other); +} + +InitState FramebufferAttachment::initState() const +{ + return mResource ? mResource->initState(mTarget.textureIndex()) : InitState::Initialized; +} + +Error FramebufferAttachment::initializeContents(const Context *context) +{ + ASSERT(mResource); + ANGLE_TRY(mResource->initializeContents(context, mTarget.textureIndex())); + setInitState(InitState::Initialized); + return NoError(); +} + +void FramebufferAttachment::setInitState(InitState initState) const +{ + ASSERT(mResource); + mResource->setInitState(mTarget.textureIndex(), initState); +} + +////// FramebufferAttachmentObject Implementation ////// + +FramebufferAttachmentObject::FramebufferAttachmentObject() +{ +} + +FramebufferAttachmentObject::~FramebufferAttachmentObject() +{ +} + +Error FramebufferAttachmentObject::getAttachmentRenderTarget( + const Context *context, + GLenum binding, + const ImageIndex &imageIndex, + rx::FramebufferAttachmentRenderTarget **rtOut) const +{ + return getAttachmentImpl()->getAttachmentRenderTarget(context, binding, imageIndex, rtOut); +} + +OnAttachmentDirtyChannel *FramebufferAttachmentObject::getDirtyChannel() +{ + return &mDirtyChannel; +} + +Error FramebufferAttachmentObject::initializeContents(const Context *context, + const ImageIndex &imageIndex) +{ + ASSERT(context->isRobustResourceInitEnabled()); + + // Because gl::Texture cannot support tracking individual layer dirtiness, we only handle + // initializing entire mip levels for 2D array textures. + if (imageIndex.type == GL_TEXTURE_2D_ARRAY && imageIndex.hasLayer()) + { + ImageIndex fullMipIndex = imageIndex; + fullMipIndex.layerIndex = ImageIndex::ENTIRE_LEVEL; + return getAttachmentImpl()->initializeContents(context, fullMipIndex); + } + else + { + return getAttachmentImpl()->initializeContents(context, imageIndex); + } +} + +} // namespace gl diff --git a/src/3rdparty/angle/src/libANGLE/FramebufferAttachment.h b/src/3rdparty/angle/src/libANGLE/FramebufferAttachment.h index 33196f5c61..5c0553a1d4 100644 --- a/src/3rdparty/angle/src/libANGLE/FramebufferAttachment.h +++ b/src/3rdparty/angle/src/libANGLE/FramebufferAttachment.h @@ -15,6 +15,7 @@ #include "libANGLE/angletypes.h" #include "libANGLE/Error.h" #include "libANGLE/ImageIndex.h" +#include "libANGLE/signal_utils.h" namespace egl { @@ -38,9 +39,20 @@ class FramebufferAttachmentObjectImpl; namespace gl { class FramebufferAttachmentObject; +struct Format; class Renderbuffer; class Texture; +enum class InitState +{ + MayNeedInit, + Initialized, +}; + +using OnAttachmentDirtyBinding = angle::ChannelBinding; +using OnAttachmentDirtyChannel = angle::BroadcastChannel; +using OnAttachmentDirtyReceiver = angle::SignalReceiver; + // 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. @@ -52,43 +64,27 @@ class FramebufferAttachment final public: FramebufferAttachment(); - FramebufferAttachment(GLenum type, + FramebufferAttachment(const Context *context, + GLenum type, GLenum binding, const ImageIndex &textureIndex, FramebufferAttachmentObject *resource); - FramebufferAttachment(const FramebufferAttachment &other); - FramebufferAttachment &operator=(const FramebufferAttachment &other); + FramebufferAttachment(FramebufferAttachment &&other); + FramebufferAttachment &operator=(FramebufferAttachment &&other); ~FramebufferAttachment(); - // A framebuffer attachment points to one of three types of resources: Renderbuffers, - // Textures and egl::Surface. The "Target" struct indicates which part of the - // object an attachment references. For the three types: - // - a Renderbuffer has a unique renderable target, and needs no target index - // - a Texture has targets for every image and uses an ImageIndex - // - a Surface has targets for Color and Depth/Stencil, and uses the attachment binding - class Target - { - public: - Target(); - Target(GLenum binding, const ImageIndex &imageIndex); - Target(const Target &other); - Target &operator=(const Target &other); - - GLenum binding() const { return mBinding; } - const ImageIndex &textureIndex() const { return mTextureIndex; } - - private: - GLenum mBinding; - ImageIndex mTextureIndex; - }; - - void detach(); - void attach(GLenum type, + void detach(const Context *context); + void attach(const Context *context, + GLenum type, GLenum binding, const ImageIndex &textureIndex, - FramebufferAttachmentObject *resource); + FramebufferAttachmentObject *resource, + GLsizei numViews, + GLuint baseViewIndex, + GLenum multiviewLayout, + const GLint *viewportOffsets); // Helper methods GLuint getRedSize() const; @@ -111,12 +107,16 @@ class FramebufferAttachment final GLenum cubeMapFace() const; GLint mipLevel() const; GLint layer() const; + GLsizei getNumViews() const; + GLenum getMultiviewLayout() const; + GLint getBaseViewIndex() const; + const std::vector &getMultiviewViewportOffsets() const; // The size of the underlying resource the attachment points to. The 'depth' value will // correspond to a 3D texture depth or the layer count of a 2D array texture. For Surfaces and // Renderbuffers, it will always be 1. Extents getSize() const; - GLenum getInternalFormat() const; + const Format &getFormat() const; GLsizei getSamples() const; GLenum type() const { return mType; } bool isAttached() const { return mType != GL_NONE; } @@ -124,95 +124,127 @@ class FramebufferAttachment final Renderbuffer *getRenderbuffer() const; Texture *getTexture() const; const egl::Surface *getSurface() const; + FramebufferAttachmentObject *getResource() const; + InitState initState() const; + Error initializeContents(const Context *context); + void setInitState(InitState initState) const; // "T" must be static_castable from FramebufferAttachmentRenderTarget template - gl::Error getRenderTarget(T **rtOut) const + gl::Error getRenderTarget(const Context *context, T **rtOut) const { - // Cast through the pointer-to-pointer type - rx::FramebufferAttachmentRenderTarget *rtPtr = nullptr; - gl::Error error = getRenderTarget(&rtPtr); - *rtOut = static_cast(rtPtr); - return error; + static_assert(std::is_base_of(), + "Invalid RenderTarget class."); + return getRenderTargetImpl( + context, reinterpret_cast(rtOut)); } + bool operator==(const FramebufferAttachment &other) const; + bool operator!=(const FramebufferAttachment &other) const; + + static std::vector GetDefaultViewportOffsetVector(); + static const GLsizei kDefaultNumViews; + static const GLenum kDefaultMultiviewLayout; + static const GLint kDefaultBaseViewIndex; + static const GLint kDefaultViewportOffsets[2]; + private: - gl::Error getRenderTarget(rx::FramebufferAttachmentRenderTarget **rtOut) const; + gl::Error getRenderTargetImpl(const Context *context, + rx::FramebufferAttachmentRenderTarget **rtOut) const; + + // A framebuffer attachment points to one of three types of resources: Renderbuffers, + // Textures and egl::Surface. The "Target" struct indicates which part of the + // object an attachment references. For the three types: + // - a Renderbuffer has a unique renderable target, and needs no target index + // - a Texture has targets for every image and uses an ImageIndex + // - a Surface has targets for Color and Depth/Stencil, and uses the attachment binding + class Target + { + public: + Target(); + Target(GLenum binding, const ImageIndex &imageIndex); + Target(const Target &other); + Target &operator=(const Target &other); + + GLenum binding() const { return mBinding; } + const ImageIndex &textureIndex() const { return mTextureIndex; } + + private: + GLenum mBinding; + ImageIndex mTextureIndex; + }; GLenum mType; Target mTarget; FramebufferAttachmentObject *mResource; + GLsizei mNumViews; + GLenum mMultiviewLayout; + GLint mBaseViewIndex; + std::vector mViewportOffsets; }; // A base class for objects that FBO Attachments may point to. class FramebufferAttachmentObject { public: - FramebufferAttachmentObject() {} - virtual ~FramebufferAttachmentObject() {} + FramebufferAttachmentObject(); + virtual ~FramebufferAttachmentObject(); - virtual Extents getAttachmentSize(const FramebufferAttachment::Target &target) const = 0; - virtual GLenum getAttachmentInternalFormat(const FramebufferAttachment::Target &target) const = 0; - virtual GLsizei getAttachmentSamples(const FramebufferAttachment::Target &target) const = 0; + virtual Extents getAttachmentSize(const ImageIndex &imageIndex) const = 0; + virtual const Format &getAttachmentFormat(GLenum binding, + const ImageIndex &imageIndex) const = 0; + virtual GLsizei getAttachmentSamples(const ImageIndex &imageIndex) const = 0; - virtual void onAttach() = 0; - virtual void onDetach() = 0; + virtual void onAttach(const Context *context) = 0; + virtual void onDetach(const Context *context) = 0; virtual GLuint getId() const = 0; - Error getAttachmentRenderTarget(const FramebufferAttachment::Target &target, + // These are used for robust resource initialization. + virtual InitState initState(const ImageIndex &imageIndex) const = 0; + virtual void setInitState(const ImageIndex &imageIndex, InitState initState) = 0; + + Error getAttachmentRenderTarget(const Context *context, + GLenum binding, + const ImageIndex &imageIndex, rx::FramebufferAttachmentRenderTarget **rtOut) const; + Error initializeContents(const Context *context, const ImageIndex &imageIndex); + + OnAttachmentDirtyChannel *getDirtyChannel(); + protected: virtual rx::FramebufferAttachmentObjectImpl *getAttachmentImpl() const = 0; + + OnAttachmentDirtyChannel mDirtyChannel; }; inline Extents FramebufferAttachment::getSize() const { - return mResource->getAttachmentSize(mTarget); + ASSERT(mResource); + return mResource->getAttachmentSize(mTarget.textureIndex()); } -inline GLenum FramebufferAttachment::getInternalFormat() const +inline const Format &FramebufferAttachment::getFormat() const { - return mResource->getAttachmentInternalFormat(mTarget); + ASSERT(mResource); + return mResource->getAttachmentFormat(mTarget.binding(), mTarget.textureIndex()); } inline GLsizei FramebufferAttachment::getSamples() const { - return mResource->getAttachmentSamples(mTarget); -} - -inline gl::Error FramebufferAttachment::getRenderTarget(rx::FramebufferAttachmentRenderTarget **rtOut) const -{ - return mResource->getAttachmentRenderTarget(mTarget, rtOut); + ASSERT(mResource); + return mResource->getAttachmentSamples(mTarget.textureIndex()); } -} // namespace gl - -namespace rx -{ - -class FramebufferAttachmentObjectImpl : angle::NonCopyable -{ - public: - FramebufferAttachmentObjectImpl() {} - virtual ~FramebufferAttachmentObjectImpl() {} - - virtual gl::Error getAttachmentRenderTarget(const gl::FramebufferAttachment::Target &target, - FramebufferAttachmentRenderTarget **rtOut) = 0; -}; - -} // namespace rx - -namespace gl -{ - -inline Error FramebufferAttachmentObject::getAttachmentRenderTarget( - const FramebufferAttachment::Target &target, +inline gl::Error FramebufferAttachment::getRenderTargetImpl( + const Context *context, rx::FramebufferAttachmentRenderTarget **rtOut) const { - return getAttachmentImpl()->getAttachmentRenderTarget(target, rtOut); + ASSERT(mResource); + return mResource->getAttachmentRenderTarget(context, mTarget.binding(), mTarget.textureIndex(), + rtOut); } -} +} // namespace gl #endif // LIBANGLE_FRAMEBUFFERATTACHMENT_H_ diff --git a/src/3rdparty/angle/src/libANGLE/HandleAllocator.cpp b/src/3rdparty/angle/src/libANGLE/HandleAllocator.cpp index 4815855d5a..c3c184258f 100644 --- a/src/3rdparty/angle/src/libANGLE/HandleAllocator.cpp +++ b/src/3rdparty/angle/src/libANGLE/HandleAllocator.cpp @@ -49,9 +49,10 @@ GLuint HandleAllocator::allocate() { ASSERT(!mUnallocatedList.empty() || !mReleasedList.empty()); - // Allocate from released list, constant time. + // Allocate from released list, logarithmic time for pop_heap. if (!mReleasedList.empty()) { + std::pop_heap(mReleasedList.begin(), mReleasedList.end()); GLuint reusedHandle = mReleasedList.back(); mReleasedList.pop_back(); return reusedHandle; @@ -63,19 +64,23 @@ GLuint HandleAllocator::allocate() GLuint freeListHandle = listIt->begin; ASSERT(freeListHandle > 0); - listIt->begin++; if (listIt->begin == listIt->end) { mUnallocatedList.erase(listIt); } + else + { + listIt->begin++; + } return freeListHandle; } void HandleAllocator::release(GLuint handle) { - // Add to released list, constant time. + // Add to released list, logarithmic time for push_heap. mReleasedList.push_back(handle); + std::push_heap(mReleasedList.begin(), mReleasedList.end()); } void HandleAllocator::reserve(GLuint handle) @@ -101,7 +106,7 @@ void HandleAllocator::reserve(GLuint handle) if (handle == begin || handle == end) { - if (begin + 1 == end) + if (begin == end) { mUnallocatedList.erase(boundIt); } @@ -117,18 +122,21 @@ void HandleAllocator::reserve(GLuint handle) return; } + ASSERT(begin < handle && handle < end); + // need to split the range auto placementIt = mUnallocatedList.erase(boundIt); + placementIt = mUnallocatedList.insert(placementIt, HandleRange(handle + 1, end)); + mUnallocatedList.insert(placementIt, HandleRange(begin, handle - 1)); +} - if (handle + 1 != end) - { - placementIt = mUnallocatedList.insert(placementIt, HandleRange(handle + 1, end)); - } - if (begin != handle) - { - ASSERT(begin < handle); - mUnallocatedList.insert(placementIt, HandleRange(begin, handle)); - } +void HandleAllocator::reset() +{ + mUnallocatedList.clear(); + mUnallocatedList.push_back(HandleRange(1, std::numeric_limits::max())); + mReleasedList.clear(); + mBaseValue = 1; + mNextValue = 1; } } // namespace gl diff --git a/src/3rdparty/angle/src/libANGLE/HandleAllocator.h b/src/3rdparty/angle/src/libANGLE/HandleAllocator.h index 1888d57cfa..cd21d687f4 100644 --- a/src/3rdparty/angle/src/libANGLE/HandleAllocator.h +++ b/src/3rdparty/angle/src/libANGLE/HandleAllocator.h @@ -14,8 +14,6 @@ #include "angle_gl.h" -#include - namespace gl { @@ -24,7 +22,7 @@ class HandleAllocator final : angle::NonCopyable public: // Maximum handle = MAX_UINT-1 HandleAllocator(); - // Specify maximum handle value + // Specify maximum handle value. Used for testing. HandleAllocator(GLuint maximumHandleValue); ~HandleAllocator(); @@ -34,6 +32,7 @@ class HandleAllocator final : angle::NonCopyable GLuint allocate(); void release(GLuint handle); void reserve(GLuint handle); + void reset(); private: GLuint mBaseValue; @@ -41,6 +40,7 @@ class HandleAllocator final : angle::NonCopyable typedef std::vector HandleList; HandleList mFreeValues; + // Represents an inclusive range [begin, end] struct HandleRange { HandleRange(GLuint beginIn, GLuint endIn) : begin(beginIn), end(endIn) {} @@ -53,7 +53,7 @@ class HandleAllocator final : angle::NonCopyable // The freelist consists of never-allocated handles, stored // as ranges, and handles that were previously allocated and - // released, stored in a stack. + // released, stored in a heap. std::vector mUnallocatedList; std::vector mReleasedList; }; diff --git a/src/3rdparty/angle/src/libANGLE/HandleRangeAllocator.cpp b/src/3rdparty/angle/src/libANGLE/HandleRangeAllocator.cpp new file mode 100644 index 0000000000..2a97ce939f --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/HandleRangeAllocator.cpp @@ -0,0 +1,229 @@ +// +// Copyright (c) 2016 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. +// + +// HandleRangeAllocator.cpp : Implementation for HandleRangeAllocator.h + +#include "libANGLE/HandleRangeAllocator.h" + +#include +#include +#include + +#include "common/angleutils.h" +#include "common/debug.h" + +namespace gl +{ + +const GLuint HandleRangeAllocator::kInvalidHandle = 0; + +HandleRangeAllocator::HandleRangeAllocator() +{ + // Simplify the code by making sure that lower_bound(id) never + // returns the beginning of the map, if id is valid (eg != kInvalidHandle). + mUsed.insert(std::make_pair(0u, 0u)); +} + +HandleRangeAllocator::~HandleRangeAllocator() +{ +} + +GLuint HandleRangeAllocator::allocate() +{ + return allocateRange(1u); +} + +GLuint HandleRangeAllocator::allocateAtOrAbove(GLuint wanted) +{ + if (wanted == 0u || wanted == 1u) + return allocateRange(1u); + + auto current = mUsed.lower_bound(wanted); + auto next = current; + if (current == mUsed.end() || current->first > wanted) + { + current--; + } + else + { + next++; + } + + GLuint firstId = current->first; + GLuint lastId = current->second; + ASSERT(wanted >= firstId); + + if (wanted - 1u <= lastId) + { + // Append to current range. + lastId++; + if (lastId == 0) + { + // The increment overflowed. + return allocateRange(1u); + } + + current->second = lastId; + + if (next != mUsed.end() && next->first - 1u == lastId) + { + // Merge with next range. + current->second = next->second; + mUsed.erase(next); + } + return lastId; + } + else if (next != mUsed.end() && next->first - 1u == wanted) + { + // Prepend to next range. + GLuint lastExisting = next->second; + mUsed.erase(next); + mUsed.insert(std::make_pair(wanted, lastExisting)); + return wanted; + } + mUsed.insert(std::make_pair(wanted, wanted)); + return wanted; +} + +GLuint HandleRangeAllocator::allocateRange(GLuint range) +{ + ASSERT(range != 0); + + auto current = mUsed.begin(); + auto next = current; + + while (++next != mUsed.end()) + { + if (next->first - current->second > range) + break; + current = next; + } + const GLuint firstId = current->second + 1u; + const GLuint lastId = firstId + range - 1u; + + // deal with wraparound + if (firstId == 0u || lastId < firstId) + return kInvalidHandle; + + current->second = lastId; + + if (next != mUsed.end() && next->first - 1u == lastId) + { + // merge with next range + current->second = next->second; + mUsed.erase(next); + } + return firstId; +} + +bool HandleRangeAllocator::markAsUsed(GLuint handle) +{ + ASSERT(handle); + auto current = mUsed.lower_bound(handle); + if (current != mUsed.end() && current->first == handle) + return false; + + auto next = current; + --current; + + if (current->second >= handle) + return false; + + ASSERT(current->first < handle && current->second < handle); + + if (current->second + 1u == handle) + { + // Append to current range. + current->second = handle; + if (next != mUsed.end() && next->first - 1u == handle) + { + // Merge with next range. + current->second = next->second; + mUsed.erase(next); + } + return true; + } + else if (next != mUsed.end() && next->first - 1u == handle) + { + // Prepend to next range. + GLuint lastExisting = next->second; + mUsed.erase(next); + mUsed.insert(std::make_pair(handle, lastExisting)); + return true; + } + + mUsed.insert(std::make_pair(handle, handle)); + return true; +} + +void HandleRangeAllocator::release(GLuint handle) +{ + releaseRange(handle, 1u); +} + +void HandleRangeAllocator::releaseRange(GLuint first, GLuint range) +{ + if (range == 0u || (first == 0u && range == 1u)) + return; + + if (first == 0u) + { + first++; + range--; + } + + GLuint last = first + range - 1u; + if (last < first) + last = std::numeric_limits::max(); + + while (true) + { + auto current = mUsed.lower_bound(last); + if (current == mUsed.end() || current->first > last) + --current; + + if (current->second < first) + return; + + if (current->first >= first) + { + const GLuint lastExisting = current->second; + mUsed.erase(current); + if (last < lastExisting) + { + mUsed.insert(std::make_pair(last + 1u, lastExisting)); + } + } + else if (current->second <= last) + { + current->second = first - 1u; + } + else + { + ASSERT(current->first < first && current->second > last); + const GLuint lastExisting = current->second; + current->second = first - 1u; + mUsed.insert(std::make_pair(last + 1u, lastExisting)); + } + } +} + +bool HandleRangeAllocator::isUsed(GLuint handle) const +{ + if (handle == kInvalidHandle) + return false; + + auto current = mUsed.lower_bound(handle); + if (current != mUsed.end()) + { + if (current->first == handle) + return true; + } + --current; + return current->second >= handle; +} + +} // namespace gl \ No newline at end of file diff --git a/src/3rdparty/angle/src/libANGLE/HandleRangeAllocator.h b/src/3rdparty/angle/src/libANGLE/HandleRangeAllocator.h new file mode 100644 index 0000000000..4d4b6f4f69 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/HandleRangeAllocator.h @@ -0,0 +1,60 @@ +// +// Copyright (c) 2002-2016 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. +// + +// HandleRangeAllocator.h: Defines the gl::HandleRangeAllocator class, which is used to +// allocate contiguous ranges of GL path handles. + +#ifndef LIBANGLE_HANDLERANGEALLOCATOR_H_ +#define LIBANGLE_HANDLERANGEALLOCATOR_H_ + +#include + +#include "angle_gl.h" +#include "common/angleutils.h" + +namespace gl +{ + +// Allocates contiguous ranges of path object handles. +class HandleRangeAllocator final : angle::NonCopyable +{ + public: + static const GLuint kInvalidHandle; + + HandleRangeAllocator(); + ~HandleRangeAllocator(); + + // Allocates a new path handle. + GLuint allocate(); + + // Allocates a handle starting at or above the value of |wanted|. + // Note: may wrap if it starts near limit. + GLuint allocateAtOrAbove(GLuint wanted); + + // Allocates |range| amount of contiguous paths. + // Returns the first id to |first_id| or |kInvalidHandle| if + // allocation failed. + GLuint allocateRange(GLuint range); + + // Marks an id as used. Returns false if handle was already used. + bool markAsUsed(GLuint handle); + + // Release handle. + void release(GLuint handle); + + // Release a |range| amount of contiguous handles, starting from |first| + void releaseRange(GLuint first, GLuint range); + + // Checks whether or not a resource ID is in use. + bool isUsed(GLuint handle) const; + + private: + std::map mUsed; +}; + +} // namespace gl + +#endif // LIBANGLE_HANDLERANGEALLOCATOR_H_ \ No newline at end of file diff --git a/src/3rdparty/angle/src/libANGLE/Image.cpp b/src/3rdparty/angle/src/libANGLE/Image.cpp index a9448e3f6c..04c757c2c4 100644 --- a/src/3rdparty/angle/src/libANGLE/Image.cpp +++ b/src/3rdparty/angle/src/libANGLE/Image.cpp @@ -11,13 +11,42 @@ #include "common/debug.h" #include "common/utilities.h" #include "libANGLE/angletypes.h" +#include "libANGLE/formatutils.h" #include "libANGLE/Texture.h" #include "libANGLE/Renderbuffer.h" +#include "libANGLE/renderer/EGLImplFactory.h" #include "libANGLE/renderer/ImageImpl.h" namespace egl { -ImageSibling::ImageSibling(GLuint id) : RefCountObject(id), mSourcesOf(), mTargetOf() + +namespace +{ +gl::ImageIndex GetImageIndex(EGLenum eglTarget, const egl::AttributeMap &attribs) +{ + if (eglTarget == EGL_GL_RENDERBUFFER) + { + return gl::ImageIndex::MakeInvalid(); + } + + GLenum target = egl_gl::EGLImageTargetToGLTextureTarget(eglTarget); + GLint mip = static_cast(attribs.get(EGL_GL_TEXTURE_LEVEL_KHR, 0)); + GLint layer = static_cast(attribs.get(EGL_GL_TEXTURE_ZOFFSET_KHR, 0)); + + if (target == GL_TEXTURE_3D) + { + return gl::ImageIndex::Make3D(mip, layer); + } + else + { + ASSERT(layer == 0); + return gl::ImageIndex::MakeGeneric(target, mip); + } +} +} // anonymous namespace + +ImageSibling::ImageSibling(GLuint id) + : RefCountObject(id), FramebufferAttachmentObject(), mSourcesOf(), mTargetOf() { } @@ -25,46 +54,38 @@ ImageSibling::~ImageSibling() { // EGL images should hold a ref to their targets and siblings, a Texture should not be deletable // while it is attached to an EGL image. + // Child class should orphan images before destruction. ASSERT(mSourcesOf.empty()); - orphanImages(); + ASSERT(mTargetOf.get() == nullptr); } -void ImageSibling::setTargetImage(egl::Image *imageTarget) +void ImageSibling::setTargetImage(const gl::Context *context, egl::Image *imageTarget) { ASSERT(imageTarget != nullptr); - mTargetOf.set(imageTarget); + mTargetOf.set(context, imageTarget); imageTarget->addTargetSibling(this); } -gl::Error ImageSibling::orphanImages() +gl::Error ImageSibling::orphanImages(const gl::Context *context) { if (mTargetOf.get() != nullptr) { // Can't be a target and have sources. ASSERT(mSourcesOf.empty()); - gl::Error error = mTargetOf->orphanSibling(this); - if (error.isError()) - { - return error; - } - - mTargetOf.set(nullptr); + ANGLE_TRY(mTargetOf->orphanSibling(context, this)); + mTargetOf.set(context, nullptr); } else { - for (auto &sourceImage : mSourcesOf) + for (egl::Image *sourceImage : mSourcesOf) { - gl::Error error = sourceImage->orphanSibling(this); - if (error.isError()) - { - return error; - } + ANGLE_TRY(sourceImage->orphanSibling(context, this)); } mSourcesOf.clear(); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } void ImageSibling::addImageSource(egl::Image *imageSource) @@ -79,114 +100,146 @@ void ImageSibling::removeImageSource(egl::Image *imageSource) mSourcesOf.erase(imageSource); } -Image::Image(rx::ImageImpl *impl, EGLenum target, ImageSibling *buffer, const AttributeMap &attribs) +bool ImageSibling::isEGLImageTarget() const +{ + return (mTargetOf.get() != nullptr); +} + +gl::InitState ImageSibling::sourceEGLImageInitState() const +{ + ASSERT(isEGLImageTarget()); + return mTargetOf->sourceInitState(); +} + +void ImageSibling::setSourceEGLImageInitState(gl::InitState initState) const +{ + ASSERT(isEGLImageTarget()); + mTargetOf->setInitState(initState); +} + +ImageState::ImageState(EGLenum target, ImageSibling *buffer, const AttributeMap &attribs) + : imageIndex(GetImageIndex(target, attribs)), source(buffer), targets() +{ +} + +ImageState::~ImageState() +{ +} + +Image::Image(rx::EGLImplFactory *factory, + EGLenum target, + ImageSibling *buffer, + const AttributeMap &attribs) : RefCountObject(0), - mImplementation(impl), - mInternalFormat(GL_NONE), - mWidth(0), - mHeight(0), - mSamples(0), - mSource(), - mTargets() + mState(target, buffer, attribs), + mImplementation(factory->createImage(mState, target, attribs)), + mOrphanedAndNeedsInit(false) { ASSERT(mImplementation != nullptr); ASSERT(buffer != nullptr); - mSource.set(buffer); - mSource->addImageSource(this); - - if (IsTextureTarget(target)) - { - gl::Texture *texture = rx::GetAs(mSource.get()); - GLenum textureTarget = egl_gl::EGLImageTargetToGLTextureTarget(target); - size_t level = attribs.get(EGL_GL_TEXTURE_LEVEL_KHR, 0); - mInternalFormat = texture->getInternalFormat(textureTarget, level); - mWidth = texture->getWidth(textureTarget, level); - mHeight = texture->getHeight(textureTarget, level); - mSamples = 0; - } - else if (IsRenderbufferTarget(target)) - { - gl::Renderbuffer *renderbuffer = rx::GetAs(mSource.get()); - mInternalFormat = renderbuffer->getInternalFormat(); - mWidth = renderbuffer->getWidth(); - mHeight = renderbuffer->getHeight(); - mSamples = renderbuffer->getSamples(); - } - else - { - UNREACHABLE(); - } + mState.source->addImageSource(this); } -Image::~Image() +gl::Error Image::onDestroy(const gl::Context *context) { - SafeDelete(mImplementation); - // All targets should hold a ref to the egl image and it should not be deleted until there are // no siblings left. - ASSERT(mTargets.empty()); + ASSERT(mState.targets.empty()); // Tell the source that it is no longer used by this image - if (mSource.get() != nullptr) + if (mState.source.get() != nullptr) { - mSource->removeImageSource(this); - mSource.set(nullptr); + mState.source->removeImageSource(this); + mState.source.set(context, nullptr); } + return gl::NoError(); +} + +Image::~Image() +{ + SafeDelete(mImplementation); } void Image::addTargetSibling(ImageSibling *sibling) { - mTargets.insert(sibling); + mState.targets.insert(sibling); } -gl::Error Image::orphanSibling(ImageSibling *sibling) +gl::Error Image::orphanSibling(const gl::Context *context, ImageSibling *sibling) { // notify impl - gl::Error error = mImplementation->orphan(sibling); + ANGLE_TRY(mImplementation->orphan(context, sibling)); - if (mSource.get() == sibling) + if (mState.source.get() == sibling) { // If the sibling is the source, it cannot be a target. - ASSERT(mTargets.find(sibling) == mTargets.end()); - - mSource.set(nullptr); + ASSERT(mState.targets.find(sibling) == mState.targets.end()); + mState.source.set(context, nullptr); + mOrphanedAndNeedsInit = + (sibling->initState(mState.imageIndex) == gl::InitState::MayNeedInit); } else { - mTargets.erase(sibling); + mState.targets.erase(sibling); } - return error; + return gl::NoError(); } -GLenum Image::getInternalFormat() const +const gl::Format &Image::getFormat() const { - return mInternalFormat; + return mState.source->getAttachmentFormat(GL_NONE, mState.imageIndex); } size_t Image::getWidth() const { - return mWidth; + return mState.source->getAttachmentSize(mState.imageIndex).width; } size_t Image::getHeight() const { - return mHeight; + return mState.source->getAttachmentSize(mState.imageIndex).height; } size_t Image::getSamples() const { - return mSamples; + return mState.source->getAttachmentSamples(mState.imageIndex); } -rx::ImageImpl *Image::getImplementation() +rx::ImageImpl *Image::getImplementation() const { return mImplementation; } -const rx::ImageImpl *Image::getImplementation() const +Error Image::initialize() { - return mImplementation; + return mImplementation->initialize(); +} + +bool Image::orphaned() const +{ + return (mState.source.get() == nullptr); +} + +gl::InitState Image::sourceInitState() const +{ + if (orphaned()) + { + return mOrphanedAndNeedsInit ? gl::InitState::MayNeedInit : gl::InitState::Initialized; + } + + return mState.source->initState(mState.imageIndex); } + +void Image::setInitState(gl::InitState initState) +{ + if (orphaned()) + { + mOrphanedAndNeedsInit = false; + } + + return mState.source->setInitState(mState.imageIndex, initState); } + +} // namespace egl diff --git a/src/3rdparty/angle/src/libANGLE/Image.h b/src/3rdparty/angle/src/libANGLE/Image.h index 26c9df914c..d2f1b875c6 100644 --- a/src/3rdparty/angle/src/libANGLE/Image.h +++ b/src/3rdparty/angle/src/libANGLE/Image.h @@ -12,12 +12,15 @@ #include "common/angleutils.h" #include "libANGLE/AttributeMap.h" #include "libANGLE/Error.h" +#include "libANGLE/FramebufferAttachment.h" #include "libANGLE/RefCountObject.h" +#include "libANGLE/formatutils.h" #include namespace rx { +class EGLImplFactory; class ImageImpl; } @@ -25,18 +28,25 @@ namespace egl { class Image; -class ImageSibling : public RefCountObject +// Only currently Renderbuffers and Textures can be bound with images. This makes the relationship +// explicit, and also ensures that an image sibling can determine if it's been initialized or not, +// which is important for the robust resource init extension with Textures and EGLImages. +class ImageSibling : public gl::RefCountObject, public gl::FramebufferAttachmentObject { public: ImageSibling(GLuint id); - virtual ~ImageSibling(); + ~ImageSibling() override; + + bool isEGLImageTarget() const; + gl::InitState sourceEGLImageInitState() const; + void setSourceEGLImageInitState(gl::InitState initState) const; protected: // Set the image target of this sibling - void setTargetImage(egl::Image *imageTarget); + void setTargetImage(const gl::Context *context, egl::Image *imageTarget); // Orphan all EGL image sources and targets - gl::Error orphanImages(); + gl::Error orphanImages(const gl::Context *context); private: friend class Image; @@ -48,22 +58,42 @@ class ImageSibling : public RefCountObject void removeImageSource(egl::Image *imageSource); std::set mSourcesOf; - BindingPointer mTargetOf; + gl::BindingPointer mTargetOf; +}; + +struct ImageState : private angle::NonCopyable +{ + ImageState(EGLenum target, ImageSibling *buffer, const AttributeMap &attribs); + ~ImageState(); + + gl::ImageIndex imageIndex; + gl::BindingPointer source; + std::set targets; }; -class Image final : public RefCountObject +class Image final : public gl::RefCountObject { public: - Image(rx::ImageImpl *impl, EGLenum target, ImageSibling *buffer, const AttributeMap &attribs); - ~Image(); + Image(rx::EGLImplFactory *factory, + EGLenum target, + ImageSibling *buffer, + const AttributeMap &attribs); + + gl::Error onDestroy(const gl::Context *context) override; + ~Image() override; - GLenum getInternalFormat() const; + const gl::Format &getFormat() const; size_t getWidth() const; size_t getHeight() const; size_t getSamples() const; - rx::ImageImpl *getImplementation(); - const rx::ImageImpl *getImplementation() const; + Error initialize(); + + rx::ImageImpl *getImplementation() const; + + bool orphaned() const; + gl::InitState sourceInitState() const; + void setInitState(gl::InitState initState); private: friend class ImageSibling; @@ -74,18 +104,12 @@ class Image final : public RefCountObject // Called from ImageSibling only to notify the image that a sibling (source or target) has // been respecified and state tracking should be updated. - gl::Error orphanSibling(ImageSibling *sibling); + gl::Error orphanSibling(const gl::Context *context, ImageSibling *sibling); + ImageState mState; rx::ImageImpl *mImplementation; - - GLenum mInternalFormat; - size_t mWidth; - size_t mHeight; - size_t mSamples; - - BindingPointer mSource; - std::set mTargets; + bool mOrphanedAndNeedsInit; }; -} +} // namespace egl #endif // LIBANGLE_IMAGE_H_ diff --git a/src/3rdparty/angle/src/libANGLE/ImageIndex.cpp b/src/3rdparty/angle/src/libANGLE/ImageIndex.cpp index c84e7c5d65..6f99f8ab54 100644 --- a/src/3rdparty/angle/src/libANGLE/ImageIndex.cpp +++ b/src/3rdparty/angle/src/libANGLE/ImageIndex.cpp @@ -1,3 +1,4 @@ +#include "ImageIndex.h" // // Copyright 2014 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be @@ -16,7 +17,8 @@ namespace gl ImageIndex::ImageIndex(const ImageIndex &other) : type(other.type), mipIndex(other.mipIndex), - layerIndex(other.layerIndex) + layerIndex(other.layerIndex), + numLayers(other.numLayers) {} ImageIndex &ImageIndex::operator=(const ImageIndex &other) @@ -24,29 +26,45 @@ ImageIndex &ImageIndex::operator=(const ImageIndex &other) type = other.type; mipIndex = other.mipIndex; layerIndex = other.layerIndex; + numLayers = other.numLayers; return *this; } +bool ImageIndex::is3D() const +{ + return type == GL_TEXTURE_3D || type == GL_TEXTURE_2D_ARRAY; +} + ImageIndex ImageIndex::Make2D(GLint mipIndex) { - return ImageIndex(GL_TEXTURE_2D, mipIndex, ENTIRE_LEVEL); + return ImageIndex(GL_TEXTURE_2D, mipIndex, ENTIRE_LEVEL, 1); +} + +ImageIndex ImageIndex::MakeRectangle(GLint mipIndex) +{ + return ImageIndex(GL_TEXTURE_RECTANGLE_ANGLE, mipIndex, ENTIRE_LEVEL, 1); } ImageIndex ImageIndex::MakeCube(GLenum target, GLint mipIndex) { ASSERT(gl::IsCubeMapTextureTarget(target)); return ImageIndex(target, mipIndex, - static_cast(CubeMapTextureTargetToLayerIndex(target))); + static_cast(CubeMapTextureTargetToLayerIndex(target)), 1); } ImageIndex ImageIndex::Make2DArray(GLint mipIndex, GLint layerIndex) { - return ImageIndex(GL_TEXTURE_2D_ARRAY, mipIndex, layerIndex); + return ImageIndex(GL_TEXTURE_2D_ARRAY, mipIndex, layerIndex, 1); +} + +ImageIndex ImageIndex::Make2DArrayRange(GLint mipIndex, GLint layerIndex, GLint numLayers) +{ + return ImageIndex(GL_TEXTURE_2D_ARRAY, mipIndex, layerIndex, numLayers); } ImageIndex ImageIndex::Make3D(GLint mipIndex, GLint layerIndex) { - return ImageIndex(GL_TEXTURE_3D, mipIndex, layerIndex); + return ImageIndex(GL_TEXTURE_3D, mipIndex, layerIndex, 1); } ImageIndex ImageIndex::MakeGeneric(GLenum target, GLint mipIndex) @@ -54,12 +72,17 @@ ImageIndex ImageIndex::MakeGeneric(GLenum target, GLint mipIndex) GLint layerIndex = IsCubeMapTextureTarget(target) ? static_cast(CubeMapTextureTargetToLayerIndex(target)) : ENTIRE_LEVEL; - return ImageIndex(target, mipIndex, layerIndex); + return ImageIndex(target, mipIndex, layerIndex, 1); +} + +ImageIndex ImageIndex::Make2DMultisample() +{ + return ImageIndex(GL_TEXTURE_2D_MULTISAMPLE, 0, ENTIRE_LEVEL, 1); } ImageIndex ImageIndex::MakeInvalid() { - return ImageIndex(GL_NONE, -1, -1); + return ImageIndex(GL_NONE, -1, -1, -1); } bool ImageIndex::operator<(const ImageIndex &other) const @@ -72,33 +95,58 @@ bool ImageIndex::operator<(const ImageIndex &other) const { return mipIndex < other.mipIndex; } - else + else if (layerIndex != other.layerIndex) { return layerIndex < other.layerIndex; } + else + { + return numLayers < other.numLayers; + } +} + +bool ImageIndex::operator==(const ImageIndex &other) const +{ + return (type == other.type) && (mipIndex == other.mipIndex) && + (layerIndex == other.layerIndex) && (numLayers == other.numLayers); } -ImageIndex::ImageIndex(GLenum typeIn, GLint mipIndexIn, GLint layerIndexIn) - : type(typeIn), - mipIndex(mipIndexIn), - layerIndex(layerIndexIn) +bool ImageIndex::operator!=(const ImageIndex &other) const +{ + return !(*this == other); +} + +ImageIndex::ImageIndex(GLenum typeIn, GLint mipIndexIn, GLint layerIndexIn, GLint numLayersIn) + : type(typeIn), mipIndex(mipIndexIn), layerIndex(layerIndexIn), numLayers(numLayersIn) {} +ImageIndexIterator::ImageIndexIterator(const ImageIndexIterator &other) = default; + ImageIndexIterator ImageIndexIterator::Make2D(GLint minMip, GLint maxMip) { return ImageIndexIterator(GL_TEXTURE_2D, Range(minMip, maxMip), - Range(ImageIndex::ENTIRE_LEVEL, ImageIndex::ENTIRE_LEVEL), NULL); + Range(ImageIndex::ENTIRE_LEVEL, ImageIndex::ENTIRE_LEVEL), + nullptr); +} + +ImageIndexIterator ImageIndexIterator::MakeRectangle(GLint minMip, GLint maxMip) +{ + return ImageIndexIterator(GL_TEXTURE_RECTANGLE_ANGLE, Range(minMip, maxMip), + Range(ImageIndex::ENTIRE_LEVEL, ImageIndex::ENTIRE_LEVEL), + nullptr); } ImageIndexIterator ImageIndexIterator::MakeCube(GLint minMip, GLint maxMip) { - return ImageIndexIterator(GL_TEXTURE_CUBE_MAP, Range(minMip, maxMip), Range(0, 6), NULL); + return ImageIndexIterator(GL_TEXTURE_CUBE_MAP, Range(minMip, maxMip), Range(0, 6), + nullptr); } ImageIndexIterator ImageIndexIterator::Make3D(GLint minMip, GLint maxMip, GLint minLayer, GLint maxLayer) { - return ImageIndexIterator(GL_TEXTURE_3D, Range(minMip, maxMip), Range(minLayer, maxLayer), NULL); + return ImageIndexIterator(GL_TEXTURE_3D, Range(minMip, maxMip), + Range(minLayer, maxLayer), nullptr); } ImageIndexIterator ImageIndexIterator::Make2DArray(GLint minMip, GLint maxMip, @@ -108,19 +156,33 @@ ImageIndexIterator ImageIndexIterator::Make2DArray(GLint minMip, GLint maxMip, Range(0, IMPLEMENTATION_MAX_2D_ARRAY_TEXTURE_LAYERS), layerCounts); } -ImageIndexIterator::ImageIndexIterator(GLenum type, const Range &mipRange, - const Range &layerRange, const GLsizei *layerCounts) +ImageIndexIterator ImageIndexIterator::Make2DMultisample() +{ + return ImageIndexIterator(GL_TEXTURE_2D_MULTISAMPLE, Range(0, 0), + Range(ImageIndex::ENTIRE_LEVEL, ImageIndex::ENTIRE_LEVEL), + nullptr); +} + +ImageIndexIterator::ImageIndexIterator(GLenum type, + const Range &mipRange, + const Range &layerRange, + const GLsizei *layerCounts) : mType(type), mMipRange(mipRange), mLayerRange(layerRange), mLayerCounts(layerCounts), - mCurrentMip(mipRange.start), - mCurrentLayer(layerRange.start) + mCurrentMip(mipRange.low()), + mCurrentLayer(layerRange.low()) {} GLint ImageIndexIterator::maxLayer() const { - return (mLayerCounts ? static_cast(mLayerCounts[mCurrentMip]) : mLayerRange.end); + if (mLayerCounts) + { + ASSERT(mCurrentMip >= 0); + return (mCurrentMip < mMipRange.high()) ? mLayerCounts[mCurrentMip] : 0; + } + return mLayerRange.high(); } ImageIndex ImageIndexIterator::next() @@ -134,20 +196,28 @@ ImageIndex ImageIndexIterator::next() if (mCurrentLayer != ImageIndex::ENTIRE_LEVEL) { - if (mCurrentLayer < maxLayer()-1) + if (mCurrentLayer < maxLayer() - 1) { mCurrentLayer++; } - else if (mCurrentMip < mMipRange.end-1) + else if (mCurrentMip < mMipRange.high() - 1) { mCurrentMip++; - mCurrentLayer = mLayerRange.start; + mCurrentLayer = mLayerRange.low(); + } + else + { + done(); } } - else if (mCurrentMip < mMipRange.end-1) + else if (mCurrentMip < mMipRange.high() - 1) { mCurrentMip++; - mCurrentLayer = mLayerRange.start; + mCurrentLayer = mLayerRange.low(); + } + else + { + done(); } return value; @@ -155,7 +225,7 @@ ImageIndex ImageIndexIterator::next() ImageIndex ImageIndexIterator::current() const { - ImageIndex value(mType, mCurrentMip, mCurrentLayer); + ImageIndex value(mType, mCurrentMip, mCurrentLayer, 1); if (mType == GL_TEXTURE_CUBE_MAP) { @@ -167,7 +237,13 @@ ImageIndex ImageIndexIterator::current() const bool ImageIndexIterator::hasNext() const { - return (mCurrentMip < mMipRange.end || mCurrentLayer < maxLayer()); + return (mCurrentMip < mMipRange.high() || mCurrentLayer < maxLayer()); } +void ImageIndexIterator::done() +{ + mCurrentMip = mMipRange.high(); + mCurrentLayer = maxLayer(); } + +} // namespace gl diff --git a/src/3rdparty/angle/src/libANGLE/ImageIndex.h b/src/3rdparty/angle/src/libANGLE/ImageIndex.h index b527c7c8ab..8e1b010325 100644 --- a/src/3rdparty/angle/src/libANGLE/ImageIndex.h +++ b/src/3rdparty/angle/src/libANGLE/ImageIndex.h @@ -23,37 +23,48 @@ struct ImageIndex GLenum type; GLint mipIndex; GLint layerIndex; + GLint numLayers; ImageIndex(const ImageIndex &other); ImageIndex &operator=(const ImageIndex &other); bool hasLayer() const { return layerIndex != ENTIRE_LEVEL; } + bool is3D() const; static ImageIndex Make2D(GLint mipIndex); + static ImageIndex MakeRectangle(GLint mipIndex); static ImageIndex MakeCube(GLenum target, GLint mipIndex); static ImageIndex Make2DArray(GLint mipIndex, GLint layerIndex); + static ImageIndex Make2DArrayRange(GLint mipIndex, GLint layerIndex, GLint numLayers); static ImageIndex Make3D(GLint mipIndex, GLint layerIndex = ENTIRE_LEVEL); static ImageIndex MakeGeneric(GLenum target, GLint mipIndex); + static ImageIndex Make2DMultisample(); static ImageIndex MakeInvalid(); static const GLint ENTIRE_LEVEL = static_cast(-1); bool operator<(const ImageIndex &other) const; + bool operator==(const ImageIndex &other) const; + bool operator!=(const ImageIndex &other) const; private: friend class ImageIndexIterator; - ImageIndex(GLenum typeIn, GLint mipIndexIn, GLint layerIndexIn); + ImageIndex(GLenum typeIn, GLint mipIndexIn, GLint layerIndexIn, GLint numLayersIn); }; class ImageIndexIterator { public: + ImageIndexIterator(const ImageIndexIterator &other); + static ImageIndexIterator Make2D(GLint minMip, GLint maxMip); + static ImageIndexIterator MakeRectangle(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); + static ImageIndexIterator Make2DMultisample(); ImageIndex next(); ImageIndex current() const; @@ -65,6 +76,7 @@ class ImageIndexIterator const Range &layerRange, const GLsizei *layerCounts); GLint maxLayer() const; + void done(); GLenum mType; Range mMipRange; diff --git a/src/3rdparty/angle/src/libANGLE/IndexRangeCache.cpp b/src/3rdparty/angle/src/libANGLE/IndexRangeCache.cpp index 4f165c1b28..71a1392b1b 100644 --- a/src/3rdparty/angle/src/libANGLE/IndexRangeCache.cpp +++ b/src/3rdparty/angle/src/libANGLE/IndexRangeCache.cpp @@ -15,6 +15,14 @@ namespace gl { +IndexRangeCache::IndexRangeCache() +{ +} + +IndexRangeCache::~IndexRangeCache() +{ +} + void IndexRangeCache::addRange(GLenum type, size_t offset, size_t count, diff --git a/src/3rdparty/angle/src/libANGLE/IndexRangeCache.h b/src/3rdparty/angle/src/libANGLE/IndexRangeCache.h index 69de421c13..3b183448e6 100644 --- a/src/3rdparty/angle/src/libANGLE/IndexRangeCache.h +++ b/src/3rdparty/angle/src/libANGLE/IndexRangeCache.h @@ -23,6 +23,9 @@ namespace gl class IndexRangeCache { public: + IndexRangeCache(); + ~IndexRangeCache(); + void addRange(GLenum type, size_t offset, size_t count, diff --git a/src/3rdparty/angle/src/libANGLE/LoggingAnnotator.cpp b/src/3rdparty/angle/src/libANGLE/LoggingAnnotator.cpp new file mode 100644 index 0000000000..799399e453 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/LoggingAnnotator.cpp @@ -0,0 +1,44 @@ +// +// Copyright 2017 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. +// +// LoggingAnnotator.cpp: DebugAnnotator implementing logging +// + +#include "libANGLE/LoggingAnnotator.h" + +#include + +namespace angle +{ + +bool LoggingAnnotator::getStatus() +{ + return false; +} + +void LoggingAnnotator::logMessage(const gl::LogMessage &msg) const +{ + auto *plat = ANGLEPlatformCurrent(); + if (plat != nullptr) + { + switch (msg.getSeverity()) + { + case gl::LOG_ERR: + plat->logError(plat, msg.getMessage().c_str()); + break; + case gl::LOG_WARN: + plat->logWarning(plat, msg.getMessage().c_str()); + break; + default: + UNREACHABLE(); + } + } + else + { + gl::Trace(msg.getSeverity(), msg.getMessage().c_str()); + } +} + +} // namespace angle diff --git a/src/3rdparty/angle/src/libANGLE/LoggingAnnotator.h b/src/3rdparty/angle/src/libANGLE/LoggingAnnotator.h new file mode 100644 index 0000000000..5bec68e189 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/LoggingAnnotator.h @@ -0,0 +1,31 @@ +// +// Copyright 2017 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. +// +// LoggingAnnotator.h: DebugAnnotator implementing logging +// + +#ifndef LIBANGLE_LOGGINGANNOTATOR_H_ +#define LIBANGLE_LOGGINGANNOTATOR_H_ + +#include "common/debug.h" + +namespace angle +{ + +class LoggingAnnotator : public gl::DebugAnnotator +{ + public: + LoggingAnnotator(){}; + ~LoggingAnnotator() override{}; + void beginEvent(const wchar_t *eventName) override {} + void endEvent() override {} + void setMarker(const wchar_t *markerName) override {} + bool getStatus() override; + void logMessage(const gl::LogMessage &msg) const override; +}; + +} // namespace angle + +#endif // LIBANGLE_LOGGINGANNOTATOR_H_ diff --git a/src/3rdparty/angle/src/libANGLE/MemoryProgramCache.cpp b/src/3rdparty/angle/src/libANGLE/MemoryProgramCache.cpp new file mode 100644 index 0000000000..9eec12e3ea --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/MemoryProgramCache.cpp @@ -0,0 +1,772 @@ +// +// Copyright 2017 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. +// +// MemoryProgramCache: Stores compiled and linked programs in memory so they don't +// always have to be re-compiled. Can be used in conjunction with the platform +// layer to warm up the cache from disk. + +#include "libANGLE/MemoryProgramCache.h" + +#include +#include + +#include "common/utilities.h" +#include "common/version.h" +#include "libANGLE/BinaryStream.h" +#include "libANGLE/Context.h" +#include "libANGLE/Uniform.h" +#include "libANGLE/histogram_macros.h" +#include "libANGLE/renderer/ProgramImpl.h" +#include "platform/Platform.h" + +namespace gl +{ + +namespace +{ +enum CacheResult +{ + kCacheMiss, + kCacheHitMemory, + kCacheHitDisk, + kCacheResultMax, +}; + +constexpr unsigned int kWarningLimit = 3; + +void WriteShaderVar(BinaryOutputStream *stream, const sh::ShaderVariable &var) +{ + stream->writeInt(var.type); + stream->writeInt(var.precision); + stream->writeString(var.name); + stream->writeString(var.mappedName); + stream->writeIntVector(var.arraySizes); + stream->writeInt(var.staticUse); + stream->writeString(var.structName); + ASSERT(var.fields.empty()); +} + +void LoadShaderVar(BinaryInputStream *stream, sh::ShaderVariable *var) +{ + var->type = stream->readInt(); + var->precision = stream->readInt(); + var->name = stream->readString(); + var->mappedName = stream->readString(); + stream->readIntVector(&var->arraySizes); + var->staticUse = stream->readBool(); + var->structName = stream->readString(); +} + +void WriteShaderVariableBuffer(BinaryOutputStream *stream, const ShaderVariableBuffer &var) +{ + stream->writeInt(var.binding); + stream->writeInt(var.dataSize); + + stream->writeInt(var.vertexStaticUse); + stream->writeInt(var.fragmentStaticUse); + stream->writeInt(var.computeStaticUse); + + stream->writeInt(var.memberIndexes.size()); + for (unsigned int memberCounterIndex : var.memberIndexes) + { + stream->writeInt(memberCounterIndex); + } +} + +void LoadShaderVariableBuffer(BinaryInputStream *stream, ShaderVariableBuffer *var) +{ + var->binding = stream->readInt(); + var->dataSize = stream->readInt(); + var->vertexStaticUse = stream->readBool(); + var->fragmentStaticUse = stream->readBool(); + var->computeStaticUse = stream->readBool(); + + unsigned int numMembers = stream->readInt(); + for (unsigned int blockMemberIndex = 0; blockMemberIndex < numMembers; blockMemberIndex++) + { + var->memberIndexes.push_back(stream->readInt()); + } +} + +void WriteBufferVariable(BinaryOutputStream *stream, const BufferVariable &var) +{ + WriteShaderVar(stream, var); + + stream->writeInt(var.bufferIndex); + stream->writeInt(var.blockInfo.offset); + stream->writeInt(var.blockInfo.arrayStride); + stream->writeInt(var.blockInfo.matrixStride); + stream->writeInt(var.blockInfo.isRowMajorMatrix); + stream->writeInt(var.blockInfo.topLevelArrayStride); + stream->writeInt(var.topLevelArraySize); + stream->writeInt(var.vertexStaticUse); + stream->writeInt(var.fragmentStaticUse); + stream->writeInt(var.computeStaticUse); +} + +void LoadBufferVariable(BinaryInputStream *stream, BufferVariable *var) +{ + LoadShaderVar(stream, var); + + var->bufferIndex = stream->readInt(); + var->blockInfo.offset = stream->readInt(); + var->blockInfo.arrayStride = stream->readInt(); + var->blockInfo.matrixStride = stream->readInt(); + var->blockInfo.isRowMajorMatrix = stream->readBool(); + var->blockInfo.topLevelArrayStride = stream->readInt(); + var->topLevelArraySize = stream->readInt(); + var->vertexStaticUse = stream->readBool(); + var->fragmentStaticUse = stream->readBool(); + var->computeStaticUse = stream->readBool(); +} + +void WriteInterfaceBlock(BinaryOutputStream *stream, const InterfaceBlock &block) +{ + stream->writeString(block.name); + stream->writeString(block.mappedName); + stream->writeInt(block.isArray); + stream->writeInt(block.arrayElement); + + WriteShaderVariableBuffer(stream, block); +} + +void LoadInterfaceBlock(BinaryInputStream *stream, InterfaceBlock *block) +{ + block->name = stream->readString(); + block->mappedName = stream->readString(); + block->isArray = stream->readBool(); + block->arrayElement = stream->readInt(); + + LoadShaderVariableBuffer(stream, block); +} + +class HashStream final : angle::NonCopyable +{ + public: + std::string str() { return mStringStream.str(); } + + template + HashStream &operator<<(T value) + { + mStringStream << value << kSeparator; + return *this; + } + + private: + static constexpr char kSeparator = ':'; + std::ostringstream mStringStream; +}; + +HashStream &operator<<(HashStream &stream, const Shader *shader) +{ + if (shader) + { + stream << shader->getSourceString().c_str() << shader->getSourceString().length() + << shader->getCompilerResourcesString().c_str(); + } + return stream; +} + +HashStream &operator<<(HashStream &stream, const Program::Bindings &bindings) +{ + for (const auto &binding : bindings) + { + stream << binding.first << binding.second; + } + return stream; +} + +HashStream &operator<<(HashStream &stream, const std::vector &strings) +{ + for (const auto &str : strings) + { + stream << str; + } + return stream; +} + +} // anonymous namespace + +MemoryProgramCache::MemoryProgramCache(size_t maxCacheSizeBytes) + : mProgramBinaryCache(maxCacheSizeBytes), mIssuedWarnings(0) +{ +} + +MemoryProgramCache::~MemoryProgramCache() +{ +} + +// static +LinkResult MemoryProgramCache::Deserialize(const Context *context, + const Program *program, + ProgramState *state, + const uint8_t *binary, + size_t length, + InfoLog &infoLog) +{ + BinaryInputStream stream(binary, length); + + 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) + { + infoLog << "Invalid program binary version."; + return false; + } + + int majorVersion = stream.readInt(); + int minorVersion = stream.readInt(); + if (majorVersion != context->getClientMajorVersion() || + minorVersion != context->getClientMinorVersion()) + { + infoLog << "Cannot load program binaries across different ES context versions."; + return false; + } + + state->mComputeShaderLocalSize[0] = stream.readInt(); + state->mComputeShaderLocalSize[1] = stream.readInt(); + state->mComputeShaderLocalSize[2] = stream.readInt(); + + state->mNumViews = stream.readInt(); + + static_assert(MAX_VERTEX_ATTRIBS <= sizeof(unsigned long) * 8, + "Too many vertex attribs for mask"); + state->mActiveAttribLocationsMask = stream.readInt(); + + unsigned int attribCount = stream.readInt(); + ASSERT(state->mAttributes.empty()); + for (unsigned int attribIndex = 0; attribIndex < attribCount; ++attribIndex) + { + sh::Attribute attrib; + LoadShaderVar(&stream, &attrib); + attrib.location = stream.readInt(); + state->mAttributes.push_back(attrib); + } + + unsigned int uniformCount = stream.readInt(); + ASSERT(state->mUniforms.empty()); + for (unsigned int uniformIndex = 0; uniformIndex < uniformCount; ++uniformIndex) + { + LinkedUniform uniform; + LoadShaderVar(&stream, &uniform); + + uniform.bufferIndex = stream.readInt(); + uniform.blockInfo.offset = stream.readInt(); + uniform.blockInfo.arrayStride = stream.readInt(); + uniform.blockInfo.matrixStride = stream.readInt(); + uniform.blockInfo.isRowMajorMatrix = stream.readBool(); + + uniform.typeInfo = &GetUniformTypeInfo(uniform.type); + + state->mUniforms.push_back(uniform); + } + + const unsigned int uniformIndexCount = stream.readInt(); + ASSERT(state->mUniformLocations.empty()); + for (unsigned int uniformIndexIndex = 0; uniformIndexIndex < uniformIndexCount; + uniformIndexIndex++) + { + VariableLocation variable; + stream.readInt(&variable.arrayIndex); + stream.readInt(&variable.index); + stream.readBool(&variable.ignored); + + state->mUniformLocations.push_back(variable); + } + + unsigned int uniformBlockCount = stream.readInt(); + ASSERT(state->mUniformBlocks.empty()); + for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < uniformBlockCount; + ++uniformBlockIndex) + { + InterfaceBlock uniformBlock; + LoadInterfaceBlock(&stream, &uniformBlock); + state->mUniformBlocks.push_back(uniformBlock); + + state->mActiveUniformBlockBindings.set(uniformBlockIndex, uniformBlock.binding != 0); + } + + unsigned int bufferVariableCount = stream.readInt(); + ASSERT(state->mBufferVariables.empty()); + for (unsigned int index = 0; index < bufferVariableCount; ++index) + { + BufferVariable bufferVariable; + LoadBufferVariable(&stream, &bufferVariable); + state->mBufferVariables.push_back(bufferVariable); + } + + unsigned int shaderStorageBlockCount = stream.readInt(); + ASSERT(state->mShaderStorageBlocks.empty()); + for (unsigned int shaderStorageBlockIndex = 0; + shaderStorageBlockIndex < shaderStorageBlockCount; ++shaderStorageBlockIndex) + { + InterfaceBlock shaderStorageBlock; + LoadInterfaceBlock(&stream, &shaderStorageBlock); + state->mShaderStorageBlocks.push_back(shaderStorageBlock); + } + + unsigned int atomicCounterBufferCount = stream.readInt(); + ASSERT(state->mAtomicCounterBuffers.empty()); + for (unsigned int bufferIndex = 0; bufferIndex < atomicCounterBufferCount; ++bufferIndex) + { + AtomicCounterBuffer atomicCounterBuffer; + LoadShaderVariableBuffer(&stream, &atomicCounterBuffer); + + state->mAtomicCounterBuffers.push_back(atomicCounterBuffer); + } + + unsigned int transformFeedbackVaryingCount = stream.readInt(); + + // Reject programs that use transform feedback varyings if the hardware cannot support them. + if (transformFeedbackVaryingCount > 0 && + context->getWorkarounds().disableProgramCachingForTransformFeedback) + { + infoLog << "Current driver does not support transform feedback in binary programs."; + return false; + } + + ASSERT(state->mLinkedTransformFeedbackVaryings.empty()); + for (unsigned int transformFeedbackVaryingIndex = 0; + transformFeedbackVaryingIndex < transformFeedbackVaryingCount; + ++transformFeedbackVaryingIndex) + { + sh::Varying varying; + stream.readIntVector(&varying.arraySizes); + stream.readInt(&varying.type); + stream.readString(&varying.name); + + GLuint arrayIndex = stream.readInt(); + + state->mLinkedTransformFeedbackVaryings.emplace_back(varying, arrayIndex); + } + + stream.readInt(&state->mTransformFeedbackBufferMode); + + unsigned int outputCount = stream.readInt(); + ASSERT(state->mOutputVariables.empty()); + for (unsigned int outputIndex = 0; outputIndex < outputCount; ++outputIndex) + { + sh::OutputVariable output; + LoadShaderVar(&stream, &output); + output.location = stream.readInt(); + state->mOutputVariables.push_back(output); + } + + unsigned int outputVarCount = stream.readInt(); + ASSERT(state->mOutputLocations.empty()); + for (unsigned int outputIndex = 0; outputIndex < outputVarCount; ++outputIndex) + { + VariableLocation locationData; + stream.readInt(&locationData.arrayIndex); + stream.readInt(&locationData.index); + stream.readBool(&locationData.ignored); + state->mOutputLocations.push_back(locationData); + } + + unsigned int outputTypeCount = stream.readInt(); + for (unsigned int outputIndex = 0; outputIndex < outputTypeCount; ++outputIndex) + { + state->mOutputVariableTypes.push_back(stream.readInt()); + } + static_assert(IMPLEMENTATION_MAX_DRAW_BUFFERS < 8 * sizeof(uint32_t), + "All bits of DrawBufferMask can be contained in an uint32_t"); + state->mActiveOutputVariables = stream.readInt(); + + unsigned int samplerRangeLow = stream.readInt(); + unsigned int samplerRangeHigh = stream.readInt(); + state->mSamplerUniformRange = RangeUI(samplerRangeLow, samplerRangeHigh); + unsigned int samplerCount = stream.readInt(); + for (unsigned int samplerIndex = 0; samplerIndex < samplerCount; ++samplerIndex) + { + GLenum textureType = stream.readInt(); + size_t bindingCount = stream.readInt(); + bool unreferenced = stream.readBool(); + state->mSamplerBindings.emplace_back( + SamplerBinding(textureType, bindingCount, unreferenced)); + } + + unsigned int imageRangeLow = stream.readInt(); + unsigned int imageRangeHigh = stream.readInt(); + state->mImageUniformRange = RangeUI(imageRangeLow, imageRangeHigh); + unsigned int imageBindingCount = stream.readInt(); + for (unsigned int imageIndex = 0; imageIndex < imageBindingCount; ++imageIndex) + { + unsigned int elementCount = stream.readInt(); + ImageBinding imageBinding(elementCount); + for (unsigned int i = 0; i < elementCount; ++i) + { + imageBinding.boundImageUnits[i] = stream.readInt(); + } + state->mImageBindings.emplace_back(imageBinding); + } + + unsigned int atomicCounterRangeLow = stream.readInt(); + unsigned int atomicCounterRangeHigh = stream.readInt(); + state->mAtomicCounterUniformRange = RangeUI(atomicCounterRangeLow, atomicCounterRangeHigh); + + static_assert(SHADER_TYPE_MAX <= sizeof(unsigned long) * 8, "Too many shader types"); + state->mLinkedShaderStages = stream.readInt(); + + return program->getImplementation()->load(context, infoLog, &stream); +} + +// static +void MemoryProgramCache::Serialize(const Context *context, + const gl::Program *program, + angle::MemoryBuffer *binaryOut) +{ + BinaryOutputStream stream; + + stream.writeBytes(reinterpret_cast(ANGLE_COMMIT_HASH), + ANGLE_COMMIT_HASH_SIZE); + + // nullptr context is supported when computing binary length. + if (context) + { + stream.writeInt(context->getClientVersion().major); + stream.writeInt(context->getClientVersion().minor); + } + else + { + stream.writeInt(2); + stream.writeInt(0); + } + + const auto &state = program->getState(); + + const auto &computeLocalSize = state.getComputeShaderLocalSize(); + + stream.writeInt(computeLocalSize[0]); + stream.writeInt(computeLocalSize[1]); + stream.writeInt(computeLocalSize[2]); + + stream.writeInt(state.mNumViews); + + stream.writeInt(state.getActiveAttribLocationsMask().to_ulong()); + + stream.writeInt(state.getAttributes().size()); + for (const sh::Attribute &attrib : state.getAttributes()) + { + WriteShaderVar(&stream, attrib); + stream.writeInt(attrib.location); + } + + stream.writeInt(state.getUniforms().size()); + for (const LinkedUniform &uniform : state.getUniforms()) + { + WriteShaderVar(&stream, uniform); + + // FIXME: referenced + + stream.writeInt(uniform.bufferIndex); + stream.writeInt(uniform.blockInfo.offset); + stream.writeInt(uniform.blockInfo.arrayStride); + stream.writeInt(uniform.blockInfo.matrixStride); + stream.writeInt(uniform.blockInfo.isRowMajorMatrix); + } + + stream.writeInt(state.getUniformLocations().size()); + for (const auto &variable : state.getUniformLocations()) + { + stream.writeInt(variable.arrayIndex); + stream.writeIntOrNegOne(variable.index); + stream.writeInt(variable.ignored); + } + + stream.writeInt(state.getUniformBlocks().size()); + for (const InterfaceBlock &uniformBlock : state.getUniformBlocks()) + { + WriteInterfaceBlock(&stream, uniformBlock); + } + + stream.writeInt(state.getBufferVariables().size()); + for (const BufferVariable &bufferVariable : state.getBufferVariables()) + { + WriteBufferVariable(&stream, bufferVariable); + } + + stream.writeInt(state.getShaderStorageBlocks().size()); + for (const InterfaceBlock &shaderStorageBlock : state.getShaderStorageBlocks()) + { + WriteInterfaceBlock(&stream, shaderStorageBlock); + } + + stream.writeInt(state.mAtomicCounterBuffers.size()); + for (const auto &atomicCounterBuffer : state.mAtomicCounterBuffers) + { + WriteShaderVariableBuffer(&stream, atomicCounterBuffer); + } + + // Warn the app layer if saving a binary with unsupported transform feedback. + if (!state.getLinkedTransformFeedbackVaryings().empty() && + context->getWorkarounds().disableProgramCachingForTransformFeedback) + { + WARN() << "Saving program binary with transform feedback, which is not supported on this " + "driver."; + } + + stream.writeInt(state.getLinkedTransformFeedbackVaryings().size()); + for (const auto &var : state.getLinkedTransformFeedbackVaryings()) + { + stream.writeIntVector(var.arraySizes); + stream.writeInt(var.type); + stream.writeString(var.name); + + stream.writeIntOrNegOne(var.arrayIndex); + } + + stream.writeInt(state.getTransformFeedbackBufferMode()); + + stream.writeInt(state.getOutputVariables().size()); + for (const sh::OutputVariable &output : state.getOutputVariables()) + { + WriteShaderVar(&stream, output); + stream.writeInt(output.location); + } + + stream.writeInt(state.getOutputLocations().size()); + for (const auto &outputVar : state.getOutputLocations()) + { + stream.writeInt(outputVar.arrayIndex); + stream.writeIntOrNegOne(outputVar.index); + stream.writeInt(outputVar.ignored); + } + + stream.writeInt(state.mOutputVariableTypes.size()); + for (const auto &outputVariableType : state.mOutputVariableTypes) + { + stream.writeInt(outputVariableType); + } + + static_assert(IMPLEMENTATION_MAX_DRAW_BUFFERS < 8 * sizeof(uint32_t), + "All bits of DrawBufferMask can be contained in an uint32_t"); + stream.writeInt(static_cast(state.mActiveOutputVariables.to_ulong())); + + stream.writeInt(state.getSamplerUniformRange().low()); + stream.writeInt(state.getSamplerUniformRange().high()); + + stream.writeInt(state.getSamplerBindings().size()); + for (const auto &samplerBinding : state.getSamplerBindings()) + { + stream.writeInt(samplerBinding.textureType); + stream.writeInt(samplerBinding.boundTextureUnits.size()); + stream.writeInt(samplerBinding.unreferenced); + } + + stream.writeInt(state.getImageUniformRange().low()); + stream.writeInt(state.getImageUniformRange().high()); + + stream.writeInt(state.getImageBindings().size()); + for (const auto &imageBinding : state.getImageBindings()) + { + stream.writeInt(imageBinding.boundImageUnits.size()); + for (size_t i = 0; i < imageBinding.boundImageUnits.size(); ++i) + { + stream.writeInt(imageBinding.boundImageUnits[i]); + } + } + + stream.writeInt(state.getAtomicCounterUniformRange().low()); + stream.writeInt(state.getAtomicCounterUniformRange().high()); + + stream.writeInt(state.getLinkedShaderStages().to_ulong()); + + program->getImplementation()->save(context, &stream); + + ASSERT(binaryOut); + binaryOut->resize(stream.length()); + memcpy(binaryOut->data(), stream.data(), stream.length()); +} + +// static +void MemoryProgramCache::ComputeHash(const Context *context, + const Program *program, + ProgramHash *hashOut) +{ + const Shader *vertexShader = program->getAttachedVertexShader(); + const Shader *fragmentShader = program->getAttachedFragmentShader(); + const Shader *computeShader = program->getAttachedComputeShader(); + + // Compute the program hash. Start with the shader hashes and resource strings. + HashStream hashStream; + hashStream << vertexShader << fragmentShader << computeShader; + + // Add some ANGLE metadata and Context properties, such as version and back-end. + hashStream << ANGLE_COMMIT_HASH << context->getClientMajorVersion() + << context->getClientMinorVersion() << context->getString(GL_RENDERER); + + // Hash pre-link program properties. + hashStream << program->getAttributeBindings() << program->getUniformLocationBindings() + << program->getFragmentInputBindings() + << program->getState().getTransformFeedbackVaryingNames() + << program->getState().getTransformFeedbackBufferMode(); + + // Call the secure SHA hashing function. + const std::string &programKey = hashStream.str(); + angle::base::SHA1HashBytes(reinterpret_cast(programKey.c_str()), + programKey.length(), hashOut->data()); +} + +LinkResult MemoryProgramCache::getProgram(const Context *context, + const Program *program, + ProgramState *state, + ProgramHash *hashOut) +{ + ComputeHash(context, program, hashOut); + const angle::MemoryBuffer *binaryProgram = nullptr; + LinkResult result(false); + if (get(*hashOut, &binaryProgram)) + { + InfoLog infoLog; + ANGLE_TRY_RESULT(Deserialize(context, program, state, binaryProgram->data(), + binaryProgram->size(), infoLog), + result); + ANGLE_HISTOGRAM_BOOLEAN("GPU.ANGLE.ProgramCache.LoadBinarySuccess", result.getResult()); + if (!result.getResult()) + { + // Cache load failed, evict. + if (mIssuedWarnings++ < kWarningLimit) + { + WARN() << "Failed to load binary from cache: " << infoLog.str(); + + if (mIssuedWarnings == kWarningLimit) + { + WARN() << "Reaching warning limit for cache load failures, silencing " + "subsequent warnings."; + } + } + remove(*hashOut); + } + } + return result; +} + +bool MemoryProgramCache::get(const ProgramHash &programHash, const angle::MemoryBuffer **programOut) +{ + const CacheEntry *entry = nullptr; + if (!mProgramBinaryCache.get(programHash, &entry)) + { + ANGLE_HISTOGRAM_ENUMERATION("GPU.ANGLE.ProgramCache.CacheResult", kCacheMiss, + kCacheResultMax); + return false; + } + + if (entry->second == CacheSource::PutProgram) + { + ANGLE_HISTOGRAM_ENUMERATION("GPU.ANGLE.ProgramCache.CacheResult", kCacheHitMemory, + kCacheResultMax); + } + else + { + ANGLE_HISTOGRAM_ENUMERATION("GPU.ANGLE.ProgramCache.CacheResult", kCacheHitDisk, + kCacheResultMax); + } + + *programOut = &entry->first; + return true; +} + +bool MemoryProgramCache::getAt(size_t index, + ProgramHash *hashOut, + const angle::MemoryBuffer **programOut) +{ + const CacheEntry *entry = nullptr; + if (!mProgramBinaryCache.getAt(index, hashOut, &entry)) + { + return false; + } + + *programOut = &entry->first; + return true; +} + +void MemoryProgramCache::remove(const ProgramHash &programHash) +{ + bool result = mProgramBinaryCache.eraseByKey(programHash); + ASSERT(result); +} + +void MemoryProgramCache::putProgram(const ProgramHash &programHash, + const Context *context, + const Program *program) +{ + CacheEntry newEntry; + Serialize(context, program, &newEntry.first); + newEntry.second = CacheSource::PutProgram; + + ANGLE_HISTOGRAM_COUNTS("GPU.ANGLE.ProgramCache.ProgramBinarySizeBytes", + static_cast(newEntry.first.size())); + + const CacheEntry *result = + mProgramBinaryCache.put(programHash, std::move(newEntry), newEntry.first.size()); + if (!result) + { + ERR() << "Failed to store binary program in memory cache, program is too large."; + } + else + { + auto *platform = ANGLEPlatformCurrent(); + platform->cacheProgram(platform, programHash, result->first.size(), result->first.data()); + } +} + +void MemoryProgramCache::updateProgram(const Context *context, const Program *program) +{ + gl::ProgramHash programHash; + ComputeHash(context, program, &programHash); + putProgram(programHash, context, program); +} + +void MemoryProgramCache::putBinary(const ProgramHash &programHash, + const uint8_t *binary, + size_t length) +{ + // Copy the binary. + CacheEntry newEntry; + newEntry.first.resize(length); + memcpy(newEntry.first.data(), binary, length); + newEntry.second = CacheSource::PutBinary; + + // Store the binary. + const CacheEntry *result = mProgramBinaryCache.put(programHash, std::move(newEntry), length); + if (!result) + { + ERR() << "Failed to store binary program in memory cache, program is too large."; + } +} + +void MemoryProgramCache::clear() +{ + mProgramBinaryCache.clear(); + mIssuedWarnings = 0; +} + +void MemoryProgramCache::resize(size_t maxCacheSizeBytes) +{ + mProgramBinaryCache.resize(maxCacheSizeBytes); +} + +size_t MemoryProgramCache::entryCount() const +{ + return mProgramBinaryCache.entryCount(); +} + +size_t MemoryProgramCache::trim(size_t limit) +{ + return mProgramBinaryCache.shrinkToSize(limit); +} + +size_t MemoryProgramCache::size() const +{ + return mProgramBinaryCache.size(); +} + +size_t MemoryProgramCache::maxSize() const +{ + return mProgramBinaryCache.maxSize(); +} + +} // namespace gl diff --git a/src/3rdparty/angle/src/libANGLE/MemoryProgramCache.h b/src/3rdparty/angle/src/libANGLE/MemoryProgramCache.h new file mode 100644 index 0000000000..044bd48ecc --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/MemoryProgramCache.h @@ -0,0 +1,130 @@ +// +// Copyright 2017 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. +// +// MemoryProgramCache: Stores compiled and linked programs in memory so they don't +// always have to be re-compiled. Can be used in conjunction with the platform +// layer to warm up the cache from disk. + +#ifndef LIBANGLE_MEMORY_PROGRAM_CACHE_H_ +#define LIBANGLE_MEMORY_PROGRAM_CACHE_H_ + +#include + +#include "common/MemoryBuffer.h" +#include "libANGLE/Error.h" +#include "libANGLE/SizedMRUCache.h" + +namespace gl +{ +// 160-bit SHA-1 hash key. +constexpr size_t kProgramHashLength = 20; +using ProgramHash = std::array; +} // namespace gl + +namespace std +{ +template <> +struct hash +{ + // Simple routine to hash four ints. + size_t operator()(const gl::ProgramHash &programHash) const + { + unsigned int hash = 0; + for (uint32_t num : programHash) + { + hash *= 37; + hash += num; + } + return hash; + } +}; +} // namespace std + +namespace gl +{ +class Context; +class InfoLog; +class Program; +class ProgramState; + +class MemoryProgramCache final : angle::NonCopyable +{ + public: + MemoryProgramCache(size_t maxCacheSizeBytes); + ~MemoryProgramCache(); + + // Writes a program's binary to the output memory buffer. + static void Serialize(const Context *context, + const Program *program, + angle::MemoryBuffer *binaryOut); + + // Loads program state according to the specified binary blob. + static LinkResult Deserialize(const Context *context, + const Program *program, + ProgramState *state, + const uint8_t *binary, + size_t length, + InfoLog &infoLog); + + static void ComputeHash(const Context *context, const Program *program, ProgramHash *hashOut); + + // Check if the cache contains a binary matching the specified program. + bool get(const ProgramHash &programHash, const angle::MemoryBuffer **programOut); + + // For querying the contents of the cache. + bool getAt(size_t index, ProgramHash *hashOut, const angle::MemoryBuffer **programOut); + + // Evict a program from the binary cache. + void remove(const ProgramHash &programHash); + + // Helper method that serializes a program. + void putProgram(const ProgramHash &programHash, const Context *context, const Program *program); + + // Same as putProgram but computes the hash. + void updateProgram(const Context *context, const Program *program); + + // Store a binary directly. + void putBinary(const ProgramHash &programHash, const uint8_t *binary, size_t length); + + // Check the cache, and deserialize and load the program if found. Evict existing hash if load + // fails. + LinkResult getProgram(const Context *context, + const Program *program, + ProgramState *state, + ProgramHash *hashOut); + + // Empty the cache. + void clear(); + + // Resize the cache. Discards current contents. + void resize(size_t maxCacheSizeBytes); + + // Returns the number of entries in the cache. + size_t entryCount() const; + + // Reduces the current cache size and returns the number of bytes freed. + size_t trim(size_t limit); + + // Returns the current cache size in bytes. + size_t size() const; + + // Returns the maximum cache size in bytes. + size_t maxSize() const; + + private: + enum class CacheSource + { + PutProgram, + PutBinary, + }; + + using CacheEntry = std::pair; + angle::SizedMRUCache mProgramBinaryCache; + unsigned int mIssuedWarnings; +}; + +} // namespace gl + +#endif // LIBANGLE_MEMORY_PROGRAM_CACHE_H_ diff --git a/src/3rdparty/angle/src/libANGLE/PackedGLEnums.h b/src/3rdparty/angle/src/libANGLE/PackedGLEnums.h new file mode 100644 index 0000000000..70e32910fc --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/PackedGLEnums.h @@ -0,0 +1,111 @@ +// Copyright 2017 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. +// +// PackedGLEnums_autogen.h: +// Declares ANGLE-specific enums classes for GLEnum and functions operating +// on them. + +#ifndef LIBANGLE_PACKEDGLENUMS_H_ +#define LIBANGLE_PACKEDGLENUMS_H_ + +#include "libANGLE/PackedGLEnums_autogen.h" + +#include +#include + +namespace angle +{ + +template +class EnumIterator final +{ + private: + using UnderlyingType = typename std::underlying_type::type; + + public: + EnumIterator(E value) : mValue(static_cast(value)) {} + EnumIterator &operator++() + { + mValue++; + return *this; + } + bool operator==(const EnumIterator &other) const { return mValue == other.mValue; } + bool operator!=(const EnumIterator &other) const { return mValue != other.mValue; } + E operator*() const { return static_cast(mValue); } + + private: + UnderlyingType mValue; +}; + +template +struct AllEnums +{ + EnumIterator begin() const { return {static_cast(0)}; } + EnumIterator end() const { return {E::InvalidEnum}; } +}; + +template +class PackedEnumMap +{ + private: + using UnderlyingType = typename std::underlying_type::type; + static constexpr size_t kSize = static_cast(E::EnumCount); + using Storage = std::array; + + Storage mData; + + public: + // types: + using value_type = T; + using pointer = T *; + using const_pointer = const T *; + using reference = T &; + using const_reference = const T &; + + using size_type = size_t; + using difference_type = ptrdiff_t; + + using iterator = typename Storage::iterator; + using const_iterator = typename Storage::const_iterator; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + + // No explicit construct/copy/destroy for aggregate type + void fill(const T &u) { mData.fill(u); } + void swap(PackedEnumMap &a) noexcept { mData.swap(a.mData); } + + // iterators: + iterator begin() noexcept { return mData.begin(); } + const_iterator begin() const noexcept { return mData.begin(); } + iterator end() noexcept { return mData.end(); } + const_iterator end() const noexcept { return mData.end(); } + + reverse_iterator rbegin() noexcept { return mData.rbegin(); } + const_reverse_iterator rbegin() const noexcept { return mData.rbegin(); } + reverse_iterator rend() noexcept { return mData.rend(); } + const_reverse_iterator rend() const noexcept { return mData.rend(); } + + // capacity: + constexpr size_type size() const noexcept { return mData.size(); } + constexpr size_type max_size() const noexcept { return mData.max_size(); } + constexpr bool empty() const noexcept { return mData.empty(); } + + // element access: + reference operator[](E n) { return mData[static_cast(n)]; } + const_reference operator[](E n) const { return mData[static_cast(n)]; } + const_reference at(E n) const { return mData.at(static_cast(n)); } + reference at(E n) { return mData.at(static_cast(n)); } + + reference front() { return mData.front(); } + const_reference front() const { return mData.front(); } + reference back() { return mData.back(); } + const_reference back() const { return mData.back(); } + + T *data() noexcept { return mData.data(); } + const T *data() const noexcept { return mData.data(); } +}; + +} // namespace angle + +#endif // LIBANGLE_PACKEDGLENUMS_H_ diff --git a/src/3rdparty/angle/src/libANGLE/PackedGLEnums_autogen.cpp b/src/3rdparty/angle/src/libANGLE/PackedGLEnums_autogen.cpp new file mode 100644 index 0000000000..4959a8ff14 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/PackedGLEnums_autogen.cpp @@ -0,0 +1,174 @@ +// GENERATED FILE - DO NOT EDIT. +// Generated by gen_packed_gl_enums.py using data from packed_gl_enums.json. +// +// Copyright 2017 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. +// +// PackedGLEnums_autogen.cpp: +// Implements ANGLE-specific enums classes for GLEnum and functions operating +// on them. + +#include "libANGLE/PackedGLEnums_autogen.h" +#include "common/debug.h" + +namespace gl +{ + +template <> +BufferBinding FromGLenum(GLenum from) +{ + switch (from) + { + case GL_ARRAY_BUFFER: + return BufferBinding::Array; + case GL_ATOMIC_COUNTER_BUFFER: + return BufferBinding::AtomicCounter; + case GL_COPY_READ_BUFFER: + return BufferBinding::CopyRead; + case GL_COPY_WRITE_BUFFER: + return BufferBinding::CopyWrite; + case GL_DISPATCH_INDIRECT_BUFFER: + return BufferBinding::DispatchIndirect; + case GL_DRAW_INDIRECT_BUFFER: + return BufferBinding::DrawIndirect; + case GL_ELEMENT_ARRAY_BUFFER: + return BufferBinding::ElementArray; + case GL_PIXEL_PACK_BUFFER: + return BufferBinding::PixelPack; + case GL_PIXEL_UNPACK_BUFFER: + return BufferBinding::PixelUnpack; + case GL_SHADER_STORAGE_BUFFER: + return BufferBinding::ShaderStorage; + case GL_TRANSFORM_FEEDBACK_BUFFER: + return BufferBinding::TransformFeedback; + case GL_UNIFORM_BUFFER: + return BufferBinding::Uniform; + default: + return BufferBinding::InvalidEnum; + } +} + +GLenum ToGLenum(BufferBinding from) +{ + switch (from) + { + case BufferBinding::Array: + return GL_ARRAY_BUFFER; + case BufferBinding::AtomicCounter: + return GL_ATOMIC_COUNTER_BUFFER; + case BufferBinding::CopyRead: + return GL_COPY_READ_BUFFER; + case BufferBinding::CopyWrite: + return GL_COPY_WRITE_BUFFER; + case BufferBinding::DispatchIndirect: + return GL_DISPATCH_INDIRECT_BUFFER; + case BufferBinding::DrawIndirect: + return GL_DRAW_INDIRECT_BUFFER; + case BufferBinding::ElementArray: + return GL_ELEMENT_ARRAY_BUFFER; + case BufferBinding::PixelPack: + return GL_PIXEL_PACK_BUFFER; + case BufferBinding::PixelUnpack: + return GL_PIXEL_UNPACK_BUFFER; + case BufferBinding::ShaderStorage: + return GL_SHADER_STORAGE_BUFFER; + case BufferBinding::TransformFeedback: + return GL_TRANSFORM_FEEDBACK_BUFFER; + case BufferBinding::Uniform: + return GL_UNIFORM_BUFFER; + default: + UNREACHABLE(); + return GL_NONE; + } +} + +template <> +BufferUsage FromGLenum(GLenum from) +{ + switch (from) + { + case GL_DYNAMIC_COPY: + return BufferUsage::DynamicCopy; + case GL_DYNAMIC_DRAW: + return BufferUsage::DynamicDraw; + case GL_DYNAMIC_READ: + return BufferUsage::DynamicRead; + case GL_STATIC_COPY: + return BufferUsage::StaticCopy; + case GL_STATIC_DRAW: + return BufferUsage::StaticDraw; + case GL_STATIC_READ: + return BufferUsage::StaticRead; + case GL_STREAM_COPY: + return BufferUsage::StreamCopy; + case GL_STREAM_DRAW: + return BufferUsage::StreamDraw; + case GL_STREAM_READ: + return BufferUsage::StreamRead; + default: + return BufferUsage::InvalidEnum; + } +} + +GLenum ToGLenum(BufferUsage from) +{ + switch (from) + { + case BufferUsage::DynamicCopy: + return GL_DYNAMIC_COPY; + case BufferUsage::DynamicDraw: + return GL_DYNAMIC_DRAW; + case BufferUsage::DynamicRead: + return GL_DYNAMIC_READ; + case BufferUsage::StaticCopy: + return GL_STATIC_COPY; + case BufferUsage::StaticDraw: + return GL_STATIC_DRAW; + case BufferUsage::StaticRead: + return GL_STATIC_READ; + case BufferUsage::StreamCopy: + return GL_STREAM_COPY; + case BufferUsage::StreamDraw: + return GL_STREAM_DRAW; + case BufferUsage::StreamRead: + return GL_STREAM_READ; + default: + UNREACHABLE(); + return GL_NONE; + } +} + +template <> +CullFaceMode FromGLenum(GLenum from) +{ + switch (from) + { + case GL_BACK: + return CullFaceMode::Back; + case GL_FRONT: + return CullFaceMode::Front; + case GL_FRONT_AND_BACK: + return CullFaceMode::FrontAndBack; + default: + return CullFaceMode::InvalidEnum; + } +} + +GLenum ToGLenum(CullFaceMode from) +{ + switch (from) + { + case CullFaceMode::Back: + return GL_BACK; + case CullFaceMode::Front: + return GL_FRONT; + case CullFaceMode::FrontAndBack: + return GL_FRONT_AND_BACK; + default: + UNREACHABLE(); + return GL_NONE; + } +} + +} // namespace gl diff --git a/src/3rdparty/angle/src/libANGLE/PackedGLEnums_autogen.h b/src/3rdparty/angle/src/libANGLE/PackedGLEnums_autogen.h new file mode 100644 index 0000000000..f3f349ab68 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/PackedGLEnums_autogen.h @@ -0,0 +1,84 @@ +// GENERATED FILE - DO NOT EDIT. +// Generated by gen_packed_gl_enums.py using data from packed_gl_enums.json. +// +// Copyright 2017 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. +// +// PackedGLEnums_autogen.h: +// Declares ANGLE-specific enums classes for GLEnum and functions operating +// on them. + +#ifndef LIBANGLE_PACKEDGLENUMS_AUTOGEN_H_ +#define LIBANGLE_PACKEDGLENUMS_AUTOGEN_H_ + +#include + +#include + +namespace gl +{ + +template +Enum FromGLenum(GLenum from); + +enum class BufferBinding : uint8_t +{ + Array = 0, + AtomicCounter = 1, + CopyRead = 2, + CopyWrite = 3, + DispatchIndirect = 4, + DrawIndirect = 5, + ElementArray = 6, + PixelPack = 7, + PixelUnpack = 8, + ShaderStorage = 9, + TransformFeedback = 10, + Uniform = 11, + + InvalidEnum = 12, + EnumCount = 12, +}; + +template <> +BufferBinding FromGLenum(GLenum from); +GLenum ToGLenum(BufferBinding from); + +enum class BufferUsage : uint8_t +{ + DynamicCopy = 0, + DynamicDraw = 1, + DynamicRead = 2, + StaticCopy = 3, + StaticDraw = 4, + StaticRead = 5, + StreamCopy = 6, + StreamDraw = 7, + StreamRead = 8, + + InvalidEnum = 9, + EnumCount = 9, +}; + +template <> +BufferUsage FromGLenum(GLenum from); +GLenum ToGLenum(BufferUsage from); + +enum class CullFaceMode : uint8_t +{ + Back = 0, + Front = 1, + FrontAndBack = 2, + + InvalidEnum = 3, + EnumCount = 3, +}; + +template <> +CullFaceMode FromGLenum(GLenum from); +GLenum ToGLenum(CullFaceMode from); + +} // namespace gl + +#endif // LIBANGLE_PACKEDGLENUMS_AUTOGEN_H_ diff --git a/src/3rdparty/angle/src/libANGLE/Path.cpp b/src/3rdparty/angle/src/libANGLE/Path.cpp new file mode 100644 index 0000000000..8f2ce9ef92 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/Path.cpp @@ -0,0 +1,78 @@ +// +// Copyright (c) 2002-2016 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. +// + +// Path.h: Defines the gl::Path class, representing CHROMIUM_path_rendering +// path object. + +#include "libANGLE/Path.h" +#include "libANGLE/renderer/PathImpl.h" + +#include "common/mathutil.h" +#include "common/debug.h" + +namespace gl +{ + +Path::Path(rx::PathImpl *impl) + : mPath(impl), + mHasData(false), + mEndCaps(GL_FLAT_CHROMIUM), + mJoinStyle(GL_MITER_REVERT_CHROMIUM), + mStrokeWidth(1.0f), + mStrokeBound(0.2f), + mMiterLimit(4.0f) +{ +} + +Path::~Path() +{ + delete mPath; +} + +Error Path::setCommands(GLsizei numCommands, + const GLubyte *commands, + GLsizei numCoords, + GLenum coordType, + const void *coords) +{ + ANGLE_TRY(mPath->setCommands(numCommands, commands, numCoords, coordType, coords)); + + mHasData = true; + + return NoError(); +} + +void Path::setStrokeWidth(GLfloat width) +{ + mStrokeWidth = width; + mPath->setPathParameter(GL_PATH_STROKE_WIDTH_CHROMIUM, mStrokeWidth); +} + +void Path::setStrokeBound(GLfloat bound) +{ + mStrokeBound = clamp(bound, 0.0f, 1.0f); + mPath->setPathParameter(GL_PATH_STROKE_BOUND_CHROMIUM, mStrokeBound); +} + +void Path::setEndCaps(GLenum type) +{ + mEndCaps = type; + mPath->setPathParameter(GL_PATH_END_CAPS_CHROMIUM, static_cast(type)); +} + +void Path::setJoinStyle(GLenum type) +{ + mJoinStyle = type; + mPath->setPathParameter(GL_PATH_JOIN_STYLE_CHROMIUM, static_cast(type)); +} + +void Path::setMiterLimit(GLfloat value) +{ + mMiterLimit = value; + mPath->setPathParameter(GL_PATH_MITER_LIMIT_CHROMIUM, value); +} + +} // gl diff --git a/src/3rdparty/angle/src/libANGLE/Path.h b/src/3rdparty/angle/src/libANGLE/Path.h new file mode 100644 index 0000000000..b103c84607 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/Path.h @@ -0,0 +1,71 @@ +// +// Copyright (c) 2002-2016 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. +// + +// Path.h: Defines the gl::Path class, representing CHROMIUM_path_rendering +// path object. + +#ifndef LIBANGLE_PATH_H_ +#define LIBANGLE_PATH_H_ + +#include "angle_gl.h" +#include "common/angleutils.h" +#include "libANGLE/Error.h" +#include "libANGLE/RefCountObject.h" + +namespace rx +{ +class PathImpl; +} + +namespace gl +{ +class Path final : angle::NonCopyable +{ + public: + Path(rx::PathImpl *impl); + + ~Path(); + + Error setCommands(GLsizei numCommands, + const GLubyte *commands, + GLsizei numCoords, + GLenum coordType, + const void *coords); + + void setStrokeWidth(GLfloat width); + void setStrokeBound(GLfloat bound); + void setEndCaps(GLenum type); + void setJoinStyle(GLenum type); + void setMiterLimit(GLfloat value); + + GLfloat getStrokeWidth() const { return mStrokeWidth; } + GLfloat getStrokeBound() const { return mStrokeBound; } + GLfloat getMiterLimit() const { return mMiterLimit; } + GLenum getEndCaps() const { return mEndCaps; } + GLenum getJoinStyle() const { return mJoinStyle; } + + bool hasPathData() const { return mHasData; } + + rx::PathImpl *getImplementation() const { return mPath; } + + private: + rx::PathImpl *mPath; + + // a Path object is not actually considered "a path" + // untill it has been specified with data. So we'll + // keep this flag to support this semantics. + bool mHasData; + + GLenum mEndCaps; + GLenum mJoinStyle; + GLfloat mStrokeWidth; + GLfloat mStrokeBound; + GLfloat mMiterLimit; +}; + +} // namespace gl + +#endif // LIBANGLE_PATH_H_ \ No newline at end of file diff --git a/src/3rdparty/angle/src/libANGLE/Platform.cpp b/src/3rdparty/angle/src/libANGLE/Platform.cpp index bfcdb1494e..702091624f 100644 --- a/src/3rdparty/angle/src/libANGLE/Platform.cpp +++ b/src/3rdparty/angle/src/libANGLE/Platform.cpp @@ -8,28 +8,62 @@ #include +#include + #include "common/debug.h" namespace { -angle::Platform *currentPlatform = nullptr; +// TODO(jmadill): Make methods owned by egl::Display. +angle::PlatformMethods g_platformMethods; +} // anonymous namespace + +angle::PlatformMethods::PlatformMethods() +{ } -// static -angle::Platform *ANGLE_APIENTRY ANGLEPlatformCurrent() +angle::PlatformMethods *ANGLEPlatformCurrent() { - return currentPlatform; + return &g_platformMethods; } -// static -void ANGLE_APIENTRY ANGLEPlatformInitialize(angle::Platform *platformImpl) +bool ANGLE_APIENTRY ANGLEGetDisplayPlatform(angle::EGLDisplayType display, + const char *const methodNames[], + unsigned int methodNameCount, + void *context, + void *platformMethods) { - ASSERT(platformImpl != nullptr); - currentPlatform = platformImpl; + angle::PlatformMethods **platformMethodsOut = + reinterpret_cast(platformMethods); + + // We allow for a lower input count of impl platform methods if the subset is correct. + if (methodNameCount > angle::g_NumPlatformMethods) + { + ERR() << "Invalid platform method count: " << methodNameCount << ", expected " + << angle::g_NumPlatformMethods << "."; + return false; + } + + for (unsigned int nameIndex = 0; nameIndex < methodNameCount; ++nameIndex) + { + const char *expectedName = angle::g_PlatformMethodNames[nameIndex]; + const char *actualName = methodNames[nameIndex]; + if (strcmp(expectedName, actualName) != 0) + { + ERR() << "Invalid platform method name: " << actualName << ", expected " << expectedName + << "."; + return false; + } + } + + // TODO(jmadill): Store platform methods in display. + g_platformMethods.context = context; + *platformMethodsOut = &g_platformMethods; + return true; } -// static -void ANGLE_APIENTRY ANGLEPlatformShutdown() +void ANGLE_APIENTRY ANGLEResetDisplayPlatform(angle::EGLDisplayType display) { - currentPlatform = nullptr; + // TODO(jmadill): Store platform methods in display. + g_platformMethods = angle::PlatformMethods(); } diff --git a/src/3rdparty/angle/src/libANGLE/Program.cpp b/src/3rdparty/angle/src/libANGLE/Program.cpp index 69497c4436..795d326041 100644 --- a/src/3rdparty/angle/src/libANGLE/Program.cpp +++ b/src/3rdparty/angle/src/libANGLE/Program.cpp @@ -11,18 +11,24 @@ #include -#include "common/BitSetIterator.h" +#include "common/bitset_utils.h" #include "common/debug.h" #include "common/platform.h" +#include "common/string_utils.h" #include "common/utilities.h" -#include "common/version.h" #include "compiler/translator/blocklayout.h" -#include "libANGLE/Data.h" +#include "libANGLE/Context.h" +#include "libANGLE/MemoryProgramCache.h" +#include "libANGLE/ProgramLinkedResources.h" #include "libANGLE/ResourceManager.h" +#include "libANGLE/Uniform.h" +#include "libANGLE/VaryingPacking.h" #include "libANGLE/features.h" -#include "libANGLE/renderer/Renderer.h" -#include "libANGLE/renderer/ProgramImpl.h" +#include "libANGLE/histogram_macros.h" #include "libANGLE/queryconversions.h" +#include "libANGLE/renderer/GLImplFactory.h" +#include "libANGLE/renderer/ProgramImpl.h" +#include "platform/Platform.h" namespace gl { @@ -30,29 +36,6 @@ namespace gl namespace { -void WriteShaderVar(BinaryOutputStream *stream, const sh::ShaderVariable &var) -{ - stream->writeInt(var.type); - stream->writeInt(var.precision); - stream->writeString(var.name); - stream->writeString(var.mappedName); - stream->writeInt(var.arraySize); - stream->writeInt(var.staticUse); - stream->writeString(var.structName); - ASSERT(var.fields.empty()); -} - -void LoadShaderVar(BinaryInputStream *stream, sh::ShaderVariable *var) -{ - var->type = stream->readInt(); - var->precision = stream->readInt(); - var->name = stream->readString(); - var->mappedName = stream->readString(); - var->arraySize = stream->readInt(); - var->staticUse = stream->readBool(); - var->structName = stream->readString(); -} - // This simplified cast function doesn't need to worry about advanced concepts like // depth range values, or casting to bool. template @@ -88,19 +71,19 @@ GLuint UniformStateQueryCast(GLint value) template <> GLfloat UniformStateQueryCast(GLboolean value) { - return (value == GL_TRUE ? 1.0f : 0.0f); + return (ConvertToBool(value) ? 1.0f : 0.0f); } template <> GLint UniformStateQueryCast(GLboolean value) { - return (value == GL_TRUE ? 1 : 0); + return (ConvertToBool(value) ? 1 : 0); } template <> GLuint UniformStateQueryCast(GLboolean value) { - return (value == GL_TRUE ? 1u : 0u); + return (ConvertToBool(value) ? 1u : 0u); } // Default to static_cast @@ -123,29 +106,224 @@ void UniformStateQueryCastLoop(DestT *dataOut, const uint8_t *srcPointer, int co } } -bool UniformInList(const std::vector &list, const std::string &name) +template +GLuint GetResourceIndexFromName(const std::vector &list, const std::string &name) { - for (const LinkedUniform &uniform : list) + std::string nameAsArrayName = name + "[0]"; + for (size_t index = 0; index < list.size(); index++) { - if (uniform.name == name) - return true; + const VarT &resource = list[index]; + if (resource.name == name || (resource.isArray() && resource.name == nameAsArrayName)) + { + return static_cast(index); + } + } + + return GL_INVALID_INDEX; +} + +template +GLint GetVariableLocation(const std::vector &list, + const std::vector &locationList, + const std::string &name) +{ + size_t nameLengthWithoutArrayIndex; + unsigned int arrayIndex = ParseArrayIndex(name, &nameLengthWithoutArrayIndex); + + for (size_t location = 0u; location < locationList.size(); ++location) + { + const VariableLocation &variableLocation = locationList[location]; + if (!variableLocation.used()) + { + continue; + } + + const VarT &variable = list[variableLocation.index]; + + if (angle::BeginsWith(variable.name, name)) + { + if (name.length() == variable.name.length()) + { + ASSERT(name == variable.name); + // GLES 3.1 November 2016 page 87. + // The string exactly matches the name of the active variable. + return static_cast(location); + } + if (name.length() + 3u == variable.name.length() && variable.isArray()) + { + ASSERT(name + "[0]" == variable.name); + // The string identifies the base name of an active array, where the string would + // exactly match the name of the variable if the suffix "[0]" were appended to the + // string. + return static_cast(location); + } + } + if (variable.isArray() && variableLocation.arrayIndex == arrayIndex && + nameLengthWithoutArrayIndex + 3u == variable.name.length() && + angle::BeginsWith(variable.name, name, nameLengthWithoutArrayIndex)) + { + ASSERT(name.substr(0u, nameLengthWithoutArrayIndex) + "[0]" == variable.name); + // The string identifies an active element of the array, where the string ends with the + // concatenation of the "[" character, an integer (with no "+" sign, extra leading + // zeroes, or whitespace) identifying an array element, and the "]" character, the + // integer is less than the number of active elements of the array variable, and where + // the string would exactly match the enumerated name of the array if the decimal + // integer were replaced with zero. + return static_cast(location); + } + } + + return -1; +} + +void CopyStringToBuffer(GLchar *buffer, const std::string &string, GLsizei bufSize, GLsizei *length) +{ + ASSERT(bufSize > 0); + strncpy(buffer, string.c_str(), bufSize); + buffer[bufSize - 1] = '\0'; + + if (length) + { + *length = static_cast(strlen(buffer)); } +} +bool IncludeSameArrayElement(const std::set &nameSet, const std::string &name) +{ + std::vector subscripts; + std::string baseName = ParseResourceName(name, &subscripts); + for (auto nameInSet : nameSet) + { + std::vector arrayIndices; + std::string arrayName = ParseResourceName(nameInSet, &arrayIndices); + if (baseName == arrayName && + (subscripts.empty() || arrayIndices.empty() || subscripts == arrayIndices)) + { + return true; + } + } return false; } -} // anonymous namespace +bool validateInterfaceBlocksCount(GLuint maxInterfaceBlocks, + const std::vector &interfaceBlocks, + const std::string &errorMessage, + InfoLog &infoLog) +{ + GLuint blockCount = 0; + for (const sh::InterfaceBlock &block : interfaceBlocks) + { + if (block.staticUse || block.layout != sh::BLOCKLAYOUT_PACKED) + { + blockCount += (block.arraySize ? block.arraySize : 1); + if (blockCount > maxInterfaceBlocks) + { + infoLog << errorMessage << maxInterfaceBlocks << ")"; + return false; + } + } + } + return true; +} -const char *const g_fakepath = "C:\\fakepath"; +GLuint GetInterfaceBlockIndex(const std::vector &list, const std::string &name) +{ + std::vector subscripts; + std::string baseName = ParseResourceName(name, &subscripts); + + unsigned int numBlocks = static_cast(list.size()); + for (unsigned int blockIndex = 0; blockIndex < numBlocks; blockIndex++) + { + const auto &block = list[blockIndex]; + if (block.name == baseName) + { + const bool arrayElementZero = + (subscripts.empty() && (!block.isArray || block.arrayElement == 0)); + const bool arrayElementMatches = + (subscripts.size() == 1 && subscripts[0] == block.arrayElement); + if (arrayElementMatches || arrayElementZero) + { + return blockIndex; + } + } + } + + return GL_INVALID_INDEX; +} + +void GetInterfaceBlockName(const GLuint index, + const std::vector &list, + GLsizei bufSize, + GLsizei *length, + GLchar *name) +{ + ASSERT(index < list.size()); + + const auto &block = list[index]; -AttributeBindings::AttributeBindings() + if (bufSize > 0) + { + std::string blockName = block.name; + + if (block.isArray) + { + blockName += ArrayString(block.arrayElement); + } + CopyStringToBuffer(name, blockName, bufSize, length); + } +} + +void InitUniformBlockLinker(const gl::Context *context, + const ProgramState &state, + UniformBlockLinker *blockLinker) { + if (state.getAttachedVertexShader()) + { + blockLinker->addShaderBlocks(GL_VERTEX_SHADER, + &state.getAttachedVertexShader()->getUniformBlocks(context)); + } + + if (state.getAttachedFragmentShader()) + { + blockLinker->addShaderBlocks(GL_FRAGMENT_SHADER, + &state.getAttachedFragmentShader()->getUniformBlocks(context)); + } + + if (state.getAttachedComputeShader()) + { + blockLinker->addShaderBlocks(GL_COMPUTE_SHADER, + &state.getAttachedComputeShader()->getUniformBlocks(context)); + } } -AttributeBindings::~AttributeBindings() +void InitShaderStorageBlockLinker(const gl::Context *context, + const ProgramState &state, + ShaderStorageBlockLinker *blockLinker) { + if (state.getAttachedVertexShader()) + { + blockLinker->addShaderBlocks( + GL_VERTEX_SHADER, &state.getAttachedVertexShader()->getShaderStorageBlocks(context)); + } + + if (state.getAttachedFragmentShader()) + { + blockLinker->addShaderBlocks( + GL_FRAGMENT_SHADER, + &state.getAttachedFragmentShader()->getShaderStorageBlocks(context)); + } + + if (state.getAttachedComputeShader()) + { + blockLinker->addShaderBlocks( + GL_COMPUTE_SHADER, &state.getAttachedComputeShader()->getShaderStorageBlocks(context)); + } } +} // anonymous namespace + +const char *const g_fakepath = "C:\\fakepath"; + InfoLog::InfoLog() { } @@ -156,7 +334,12 @@ InfoLog::~InfoLog() size_t InfoLog::getLength() const { - const std::string &logString = mStream.str(); + if (!mLazyStream) + { + return 0; + } + + const std::string &logString = mLazyStream->str(); return logString.empty() ? 0 : logString.length() + 1; } @@ -166,12 +349,12 @@ void InfoLog::getLog(GLsizei bufSize, GLsizei *length, char *infoLog) const if (bufSize > 0) { - const std::string str(mStream.str()); + const std::string logString(str()); - if (!str.empty()) + if (!logString.empty()) { - index = std::min(static_cast(bufSize) - 1, str.length()); - memcpy(infoLog, str.c_str(), index); + index = std::min(static_cast(bufSize) - 1, logString.length()); + memcpy(infoLog, logString.c_str(), index); } infoLog[index] = '\0'; @@ -184,10 +367,12 @@ void InfoLog::getLog(GLsizei bufSize, GLsizei *length, char *infoLog) const } // append a santized message to the program info log. -// The D3D compiler includes a fake file path in some of the warning or error +// 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) { + ensureInitialized(); + std::string msg(message); size_t found; @@ -201,569 +386,682 @@ void InfoLog::appendSanitized(const char *message) } while (found != std::string::npos); - mStream << message << std::endl; + *mLazyStream << message << std::endl; } void InfoLog::reset() { } -VariableLocation::VariableLocation() - : name(), - element(0), - index(0) +VariableLocation::VariableLocation() : arrayIndex(0), index(kUnused), ignored(false) +{ +} + +VariableLocation::VariableLocation(unsigned int arrayIndex, unsigned int index) + : arrayIndex(arrayIndex), index(index), ignored(false) +{ + ASSERT(arrayIndex != GL_INVALID_INDEX); +} + +SamplerBinding::SamplerBinding(GLenum textureTypeIn, size_t elementCount, bool unreferenced) + : textureType(textureTypeIn), boundTextureUnits(elementCount, 0), unreferenced(unreferenced) +{ +} + +SamplerBinding::SamplerBinding(const SamplerBinding &other) = default; + +SamplerBinding::~SamplerBinding() = default; + +Program::Bindings::Bindings() +{ +} + +Program::Bindings::~Bindings() +{ +} + +void Program::Bindings::bindLocation(GLuint index, const std::string &name) +{ + mBindings[name] = index; +} + +int Program::Bindings::getBinding(const std::string &name) const +{ + auto iter = mBindings.find(name); + return (iter != mBindings.end()) ? iter->second : -1; +} + +Program::Bindings::const_iterator Program::Bindings::begin() const { + return mBindings.begin(); } -VariableLocation::VariableLocation(const std::string &name, unsigned int element, unsigned int index) - : name(name), - element(element), - index(index) +Program::Bindings::const_iterator Program::Bindings::end() const { + return mBindings.end(); } -Program::Data::Data() +ImageBinding::ImageBinding(size_t count) : boundImageUnits(count, 0) +{ +} +ImageBinding::ImageBinding(GLuint imageUnit, size_t count) +{ + for (size_t index = 0; index < count; ++index) + { + boundImageUnits.push_back(imageUnit + static_cast(index)); + } +} + +ImageBinding::ImageBinding(const ImageBinding &other) = default; + +ImageBinding::~ImageBinding() = default; + +ProgramState::ProgramState() : mLabel(), mAttachedFragmentShader(nullptr), mAttachedVertexShader(nullptr), + mAttachedComputeShader(nullptr), + mAttachedGeometryShader(nullptr), mTransformFeedbackBufferMode(GL_INTERLEAVED_ATTRIBS), - mBinaryRetrieveableHint(false) + mMaxActiveAttribLocation(0), + mSamplerUniformRange(0, 0), + mImageUniformRange(0, 0), + mAtomicCounterUniformRange(0, 0), + mBinaryRetrieveableHint(false), + mNumViews(-1) { + mComputeShaderLocalSize.fill(1); } -Program::Data::~Data() +ProgramState::~ProgramState() { - if (mAttachedVertexShader != nullptr) - { - mAttachedVertexShader->release(); - } - - if (mAttachedFragmentShader != nullptr) - { - mAttachedFragmentShader->release(); - } + ASSERT(!mAttachedVertexShader && !mAttachedFragmentShader && !mAttachedComputeShader && + !mAttachedGeometryShader); } -const std::string &Program::Data::getLabel() +const std::string &ProgramState::getLabel() { return mLabel; } -const LinkedUniform *Program::Data::getUniformByName(const std::string &name) const +GLuint ProgramState::getUniformIndexFromName(const std::string &name) const { - for (const LinkedUniform &linkedUniform : mUniforms) - { - if (linkedUniform.name == name) - { - return &linkedUniform; - } - } + return GetResourceIndexFromName(mUniforms, name); +} - return nullptr; +GLuint ProgramState::getBufferVariableIndexFromName(const std::string &name) const +{ + return GetResourceIndexFromName(mBufferVariables, name); } -GLint Program::Data::getUniformLocation(const std::string &name) const +GLuint ProgramState::getUniformIndexFromLocation(GLint location) const { - size_t subscript = GL_INVALID_INDEX; - std::string baseName = gl::ParseUniformName(name, &subscript); + ASSERT(location >= 0 && static_cast(location) < mUniformLocations.size()); + return mUniformLocations[location].index; +} - for (size_t location = 0; location < mUniformLocations.size(); ++location) +Optional ProgramState::getSamplerIndex(GLint location) const +{ + GLuint index = getUniformIndexFromLocation(location); + if (!isSamplerUniformIndex(index)) { - const VariableLocation &uniformLocation = mUniformLocations[location]; - const LinkedUniform &uniform = mUniforms[uniformLocation.index]; - - if (uniform.name == baseName) - { - if ((uniform.isArray() && uniformLocation.element == subscript) || - (subscript == GL_INVALID_INDEX)) - { - return static_cast(location); - } - } + return Optional::Invalid(); } - return -1; + return getSamplerIndexFromUniformIndex(index); } -GLuint Program::Data::getUniformIndex(const std::string &name) const +bool ProgramState::isSamplerUniformIndex(GLuint index) const { - size_t subscript = GL_INVALID_INDEX; - std::string baseName = gl::ParseUniformName(name, &subscript); + return mSamplerUniformRange.contains(index); +} - // 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; - } +GLuint ProgramState::getSamplerIndexFromUniformIndex(GLuint uniformIndex) const +{ + ASSERT(isSamplerUniformIndex(uniformIndex)); + return uniformIndex - mSamplerUniformRange.low(); +} - for (size_t index = 0; index < mUniforms.size(); index++) +GLuint ProgramState::getAttributeLocation(const std::string &name) const +{ + for (const sh::Attribute &attribute : mAttributes) { - const LinkedUniform &uniform = mUniforms[index]; - if (uniform.name == baseName) + if (attribute.name == name) { - if (uniform.isArray() || subscript == GL_INVALID_INDEX) - { - return static_cast(index); - } + return attribute.location; } } - return GL_INVALID_INDEX; + return static_cast(-1); } -Program::Program(rx::ImplFactory *factory, ResourceManager *manager, GLuint handle) - : mProgram(factory->createProgram(mData)), +Program::Program(rx::GLImplFactory *factory, ShaderProgramManager *manager, GLuint handle) + : mProgram(factory->createProgram(mState)), mValidated(false), mLinked(false), mDeleteStatus(false), mRefCount(0), mResourceManager(manager), - mHandle(handle), - mSamplerUniformRange(0, 0) + mHandle(handle) { ASSERT(mProgram); - resetUniformBlockBindings(); unlink(); } Program::~Program() { - unlink(true); + ASSERT(!mProgram); +} + +void Program::onDestroy(const Context *context) +{ + if (mState.mAttachedVertexShader != nullptr) + { + mState.mAttachedVertexShader->release(context); + mState.mAttachedVertexShader = nullptr; + } + + if (mState.mAttachedFragmentShader != nullptr) + { + mState.mAttachedFragmentShader->release(context); + mState.mAttachedFragmentShader = nullptr; + } + if (mState.mAttachedComputeShader != nullptr) + { + mState.mAttachedComputeShader->release(context); + mState.mAttachedComputeShader = nullptr; + } + + if (mState.mAttachedGeometryShader != nullptr) + { + mState.mAttachedGeometryShader->release(context); + mState.mAttachedGeometryShader = nullptr; + } + + mProgram->destroy(context); + + ASSERT(!mState.mAttachedVertexShader && !mState.mAttachedFragmentShader && + !mState.mAttachedComputeShader && !mState.mAttachedGeometryShader); SafeDelete(mProgram); + + delete this; } void Program::setLabel(const std::string &label) { - mData.mLabel = label; + mState.mLabel = label; } const std::string &Program::getLabel() const { - return mData.mLabel; + return mState.mLabel; } -bool Program::attachShader(Shader *shader) +void Program::attachShader(Shader *shader) { - if (shader->getType() == GL_VERTEX_SHADER) + switch (shader->getType()) { - if (mData.mAttachedVertexShader) + case GL_VERTEX_SHADER: { - return false; + ASSERT(!mState.mAttachedVertexShader); + mState.mAttachedVertexShader = shader; + mState.mAttachedVertexShader->addRef(); + break; } - - mData.mAttachedVertexShader = shader; - mData.mAttachedVertexShader->addRef(); - } - else if (shader->getType() == GL_FRAGMENT_SHADER) - { - if (mData.mAttachedFragmentShader) + case GL_FRAGMENT_SHADER: { - return false; + ASSERT(!mState.mAttachedFragmentShader); + mState.mAttachedFragmentShader = shader; + mState.mAttachedFragmentShader->addRef(); + break; } - - mData.mAttachedFragmentShader = shader; - mData.mAttachedFragmentShader->addRef(); + case GL_COMPUTE_SHADER: + { + ASSERT(!mState.mAttachedComputeShader); + mState.mAttachedComputeShader = shader; + mState.mAttachedComputeShader->addRef(); + break; + } + case GL_GEOMETRY_SHADER_EXT: + { + ASSERT(!mState.mAttachedGeometryShader); + mState.mAttachedGeometryShader = shader; + mState.mAttachedGeometryShader->addRef(); + break; + } + default: + UNREACHABLE(); } - else UNREACHABLE(); - - return true; } -bool Program::detachShader(Shader *shader) +void Program::detachShader(const Context *context, Shader *shader) { - if (shader->getType() == GL_VERTEX_SHADER) + switch (shader->getType()) { - if (mData.mAttachedVertexShader != shader) + case GL_VERTEX_SHADER: { - return false; + ASSERT(mState.mAttachedVertexShader == shader); + shader->release(context); + mState.mAttachedVertexShader = nullptr; + break; } - - shader->release(); - mData.mAttachedVertexShader = nullptr; - } - else if (shader->getType() == GL_FRAGMENT_SHADER) - { - if (mData.mAttachedFragmentShader != shader) + case GL_FRAGMENT_SHADER: { - return false; + ASSERT(mState.mAttachedFragmentShader == shader); + shader->release(context); + mState.mAttachedFragmentShader = nullptr; + break; } - - shader->release(); - mData.mAttachedFragmentShader = nullptr; + case GL_COMPUTE_SHADER: + { + ASSERT(mState.mAttachedComputeShader == shader); + shader->release(context); + mState.mAttachedComputeShader = nullptr; + break; + } + case GL_GEOMETRY_SHADER_EXT: + { + ASSERT(mState.mAttachedGeometryShader == shader); + shader->release(context); + mState.mAttachedGeometryShader = nullptr; + break; + } + default: + UNREACHABLE(); } - else UNREACHABLE(); - - return true; } int Program::getAttachedShadersCount() const { - return (mData.mAttachedVertexShader ? 1 : 0) + (mData.mAttachedFragmentShader ? 1 : 0); + return (mState.mAttachedVertexShader ? 1 : 0) + (mState.mAttachedFragmentShader ? 1 : 0) + + (mState.mAttachedComputeShader ? 1 : 0) + (mState.mAttachedGeometryShader ? 1 : 0); } -void AttributeBindings::bindAttributeLocation(GLuint index, const char *name) +void Program::bindAttributeLocation(GLuint index, const char *name) { - if (index < MAX_VERTEX_ATTRIBS) - { - for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++) - { - mAttributeBinding[i].erase(name); - } + mAttributeBindings.bindLocation(index, name); +} - mAttributeBinding[index].insert(name); - } +void Program::bindUniformLocation(GLuint index, const char *name) +{ + mUniformLocationBindings.bindLocation(index, name); } -void Program::bindAttributeLocation(GLuint index, const char *name) +void Program::bindFragmentInputLocation(GLint index, const char *name) { - mAttributeBindings.bindAttributeLocation(index, name); + mFragmentInputBindings.bindLocation(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 gl::Data &data) +BindingInfo Program::getFragmentInputBindingInfo(const Context *context, GLint index) const { - unlink(false); + BindingInfo ret; + ret.type = GL_NONE; + ret.valid = false; - mInfoLog.reset(); - resetUniformBlockBindings(); + Shader *fragmentShader = mState.getAttachedFragmentShader(); + ASSERT(fragmentShader); - if (!mData.mAttachedFragmentShader || !mData.mAttachedFragmentShader->isCompiled()) - { - return Error(GL_NO_ERROR); - } - ASSERT(mData.mAttachedFragmentShader->getType() == GL_FRAGMENT_SHADER); + // Find the actual fragment shader varying we're interested in + const std::vector &inputs = fragmentShader->getInputVaryings(context); - if (!mData.mAttachedVertexShader || !mData.mAttachedVertexShader->isCompiled()) + for (const auto &binding : mFragmentInputBindings) { - return Error(GL_NO_ERROR); - } - ASSERT(mData.mAttachedVertexShader->getType() == GL_VERTEX_SHADER); + if (binding.second != static_cast(index)) + continue; - if (!linkAttributes(data, mInfoLog, mAttributeBindings, mData.mAttachedVertexShader)) - { - return Error(GL_NO_ERROR); - } + ret.valid = true; - if (!linkVaryings(mInfoLog, mData.mAttachedVertexShader, mData.mAttachedFragmentShader)) - { - return Error(GL_NO_ERROR); - } + size_t nameLengthWithoutArrayIndex; + unsigned int arrayIndex = ParseArrayIndex(binding.first, &nameLengthWithoutArrayIndex); - if (!linkUniforms(mInfoLog, *data.caps)) - { - return Error(GL_NO_ERROR); + for (const auto &in : inputs) + { + if (in.name.length() == nameLengthWithoutArrayIndex && + angle::BeginsWith(in.name, binding.first, nameLengthWithoutArrayIndex)) + { + if (in.isArray()) + { + // The client wants to bind either "name" or "name[0]". + // GL ES 3.1 spec refers to active array names with language such as: + // "if the string identifies the base name of an active array, where the + // string would exactly match the name of the variable if the suffix "[0]" + // were appended to the string". + if (arrayIndex == GL_INVALID_INDEX) + arrayIndex = 0; + + ret.name = in.mappedName + "[" + ToString(arrayIndex) + "]"; + } + else + { + ret.name = in.mappedName; + } + ret.type = in.type; + return ret; + } + } } - if (!linkUniformBlocks(mInfoLog, *data.caps)) - { - return Error(GL_NO_ERROR); - } + return ret; +} + +void Program::pathFragmentInputGen(const Context *context, + GLint index, + GLenum genMode, + GLint components, + const GLfloat *coeffs) +{ + // If the location is -1 then the command is silently ignored + if (index == -1) + return; + + const auto &binding = getFragmentInputBindingInfo(context, index); + + // If the input doesn't exist then then the command is silently ignored + // This could happen through optimization for example, the shader translator + // decides that a variable is not actually being used and optimizes it away. + if (binding.name.empty()) + return; - const auto &mergedVaryings = getMergedVaryings(); + mProgram->setPathFragmentInputGen(binding.name, genMode, components, coeffs); +} + +// The attached shaders are checked for linking errors by matching up their variables. +// Uniform, input and output variables get collected. +// The code gets compiled into binaries. +Error Program::link(const gl::Context *context) +{ + const auto &data = context->getContextState(); + + auto *platform = ANGLEPlatformCurrent(); + double startTime = platform->currentTime(platform); - if (!linkValidateTransformFeedback(mInfoLog, mergedVaryings, *data.caps)) + unlink(); + + ProgramHash programHash; + auto *cache = context->getMemoryProgramCache(); + if (cache) { - return Error(GL_NO_ERROR); + ANGLE_TRY_RESULT(cache->getProgram(context, this, &mState, &programHash), mLinked); + ANGLE_HISTOGRAM_BOOLEAN("GPU.ANGLE.ProgramCache.LoadBinarySuccess", mLinked); } - linkOutputVariables(); - - rx::LinkResult result = mProgram->link(data, mInfoLog); - if (result.error.isError() || !result.linkSuccess) + if (mLinked) { - return result.error; + double delta = platform->currentTime(platform) - startTime; + int us = static_cast(delta * 1000000.0); + ANGLE_HISTOGRAM_COUNTS("GPU.ANGLE.ProgramCache.ProgramCacheHitTimeUS", us); + return NoError(); } - gatherTransformFeedbackVaryings(mergedVaryings); - gatherInterfaceBlockInfo(); + // Cache load failed, fall through to normal linking. + unlink(); + mInfoLog.reset(); - mLinked = true; - return gl::Error(GL_NO_ERROR); -} + const Caps &caps = data.getCaps(); -int AttributeBindings::getAttributeBinding(const std::string &name) const -{ - for (int location = 0; location < MAX_VERTEX_ATTRIBS; location++) + Shader *vertexShader = mState.mAttachedVertexShader; + Shader *fragmentShader = mState.mAttachedFragmentShader; + Shader *computeShader = mState.mAttachedComputeShader; + + bool isComputeShaderAttached = (computeShader != nullptr); + bool nonComputeShadersAttached = (vertexShader != nullptr || fragmentShader != nullptr); + // Check whether we both have a compute and non-compute shaders attached. + // If there are of both types attached, then linking should fail. + // OpenGL ES 3.10, 7.3 Program Objects, under LinkProgram + if (isComputeShaderAttached == true && nonComputeShadersAttached == true) + { + mInfoLog << "Both a compute and non-compute shaders are attached to the same program."; + return NoError(); + } + + if (computeShader) { - if (mAttributeBinding[location].find(name) != mAttributeBinding[location].end()) + if (!computeShader->isCompiled(context)) { - return location; + mInfoLog << "Attached compute shader is not compiled."; + return NoError(); } - } + ASSERT(computeShader->getType() == GL_COMPUTE_SHADER); - return -1; -} + mState.mComputeShaderLocalSize = computeShader->getWorkGroupSize(context); -// 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 (mData.mAttachedFragmentShader) + // GLSL ES 3.10, 4.4.1.1 Compute Shader Inputs + // If the work group size is not specified, a link time error should occur. + if (!mState.mComputeShaderLocalSize.isDeclared()) { - mData.mAttachedFragmentShader->release(); - mData.mAttachedFragmentShader = nullptr; + mInfoLog << "Work group size is not specified."; + return NoError(); } - if (mData.mAttachedVertexShader) + if (!linkUniforms(context, mInfoLog, mUniformLocationBindings)) { - mData.mAttachedVertexShader->release(); - mData.mAttachedVertexShader = nullptr; + return NoError(); } - } - mData.mAttributes.clear(); - mData.mActiveAttribLocationsMask.reset(); - mData.mTransformFeedbackVaryingVars.clear(); - mData.mUniforms.clear(); - mData.mUniformLocations.clear(); - mData.mUniformBlocks.clear(); - mData.mOutputVariables.clear(); + if (!linkInterfaceBlocks(context, mInfoLog)) + { + return NoError(); + } - mValidated = false; + ProgramLinkedResources resources = { + {0, PackMode::ANGLE_RELAXED}, + {&mState.mUniformBlocks, &mState.mUniforms}, + {&mState.mShaderStorageBlocks, &mState.mBufferVariables}}; - mLinked = false; -} + InitUniformBlockLinker(context, mState, &resources.uniformBlockLinker); + InitShaderStorageBlockLinker(context, mState, &resources.shaderStorageBlockLinker); -bool Program::isLinked() const -{ - return mLinked; -} + ANGLE_TRY_RESULT(mProgram->link(context, resources, mInfoLog), mLinked); + if (!mLinked) + { + return NoError(); + } + } + else + { + if (!fragmentShader || !fragmentShader->isCompiled(context)) + { + return NoError(); + } + ASSERT(fragmentShader->getType() == GL_FRAGMENT_SHADER); -Error Program::loadBinary(GLenum binaryFormat, const void *binary, GLsizei length) -{ - unlink(false); + if (!vertexShader || !vertexShader->isCompiled(context)) + { + return NoError(); + } + ASSERT(vertexShader->getType() == GL_VERTEX_SHADER); -#if ANGLE_PROGRAM_BINARY_LOAD != ANGLE_ENABLED - return Error(GL_NO_ERROR); -#else - ASSERT(binaryFormat == GL_PROGRAM_BINARY_ANGLE); - if (binaryFormat != GL_PROGRAM_BINARY_ANGLE) - { - mInfoLog << "Invalid program binary format."; - return Error(GL_NO_ERROR); - } + if (fragmentShader->getShaderVersion(context) != vertexShader->getShaderVersion(context)) + { + mInfoLog << "Fragment shader version does not match vertex shader version."; + return NoError(); + } - BinaryInputStream stream(binary, length); + if (!linkAttributes(context, mInfoLog)) + { + return NoError(); + } - int majorVersion = stream.readInt(); - int minorVersion = stream.readInt(); - if (majorVersion != ANGLE_MAJOR_VERSION || minorVersion != ANGLE_MINOR_VERSION) - { - mInfoLog << "Invalid program binary version."; - return Error(GL_NO_ERROR); - } + if (!linkVaryings(context, mInfoLog)) + { + return NoError(); + } - 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 << "Invalid program binary version."; - return Error(GL_NO_ERROR); - } + if (!linkUniforms(context, mInfoLog, mUniformLocationBindings)) + { + return NoError(); + } - static_assert(MAX_VERTEX_ATTRIBS <= sizeof(unsigned long) * 8, - "Too many vertex attribs for mask"); - mData.mActiveAttribLocationsMask = stream.readInt(); + if (!linkInterfaceBlocks(context, mInfoLog)) + { + return NoError(); + } - unsigned int attribCount = stream.readInt(); - ASSERT(mData.mAttributes.empty()); - for (unsigned int attribIndex = 0; attribIndex < attribCount; ++attribIndex) - { - sh::Attribute attrib; - LoadShaderVar(&stream, &attrib); - attrib.location = stream.readInt(); - mData.mAttributes.push_back(attrib); - } + if (!linkValidateGlobalNames(context, mInfoLog)) + { + return NoError(); + } - unsigned int uniformCount = stream.readInt(); - ASSERT(mData.mUniforms.empty()); - for (unsigned int uniformIndex = 0; uniformIndex < uniformCount; ++uniformIndex) - { - LinkedUniform uniform; - LoadShaderVar(&stream, &uniform); + const auto &mergedVaryings = getMergedVaryings(context); - uniform.blockIndex = stream.readInt(); - uniform.blockInfo.offset = stream.readInt(); - uniform.blockInfo.arrayStride = stream.readInt(); - uniform.blockInfo.matrixStride = stream.readInt(); - uniform.blockInfo.isRowMajorMatrix = stream.readBool(); + mState.mNumViews = vertexShader->getNumViews(context); - mData.mUniforms.push_back(uniform); - } + linkOutputVariables(context); - const unsigned int uniformIndexCount = stream.readInt(); - ASSERT(mData.mUniformLocations.empty()); - for (unsigned int uniformIndexIndex = 0; uniformIndexIndex < uniformIndexCount; - uniformIndexIndex++) - { - VariableLocation variable; - stream.readString(&variable.name); - stream.readInt(&variable.element); - stream.readInt(&variable.index); + // Map the varyings to the register file + // In WebGL, we use a slightly different handling for packing variables. + auto packMode = data.getExtensions().webglCompatibility ? PackMode::WEBGL_STRICT + : PackMode::ANGLE_RELAXED; - mData.mUniformLocations.push_back(variable); - } + ProgramLinkedResources resources = { + {data.getCaps().maxVaryingVectors, packMode}, + {&mState.mUniformBlocks, &mState.mUniforms}, + {&mState.mShaderStorageBlocks, &mState.mBufferVariables}}; - unsigned int uniformBlockCount = stream.readInt(); - ASSERT(mData.mUniformBlocks.empty()); - for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < uniformBlockCount; - ++uniformBlockIndex) - { - UniformBlock uniformBlock; - stream.readString(&uniformBlock.name); - stream.readBool(&uniformBlock.isArray); - stream.readInt(&uniformBlock.arrayElement); - stream.readInt(&uniformBlock.dataSize); - stream.readBool(&uniformBlock.vertexStaticUse); - stream.readBool(&uniformBlock.fragmentStaticUse); + InitUniformBlockLinker(context, mState, &resources.uniformBlockLinker); + InitShaderStorageBlockLinker(context, mState, &resources.shaderStorageBlockLinker); - unsigned int numMembers = stream.readInt(); - for (unsigned int blockMemberIndex = 0; blockMemberIndex < numMembers; blockMemberIndex++) + if (!linkValidateTransformFeedback(context, mInfoLog, mergedVaryings, caps)) { - uniformBlock.memberUniformIndexes.push_back(stream.readInt()); + return NoError(); } - mData.mUniformBlocks.push_back(uniformBlock); - } + if (!resources.varyingPacking.collectAndPackUserVaryings( + mInfoLog, mergedVaryings, mState.getTransformFeedbackVaryingNames())) + { + return NoError(); + } - unsigned int transformFeedbackVaryingCount = stream.readInt(); - ASSERT(mData.mTransformFeedbackVaryingVars.empty()); - for (unsigned int transformFeedbackVaryingIndex = 0; - transformFeedbackVaryingIndex < transformFeedbackVaryingCount; - ++transformFeedbackVaryingIndex) - { - sh::Varying varying; - stream.readInt(&varying.arraySize); - stream.readInt(&varying.type); - stream.readString(&varying.name); + ANGLE_TRY_RESULT(mProgram->link(context, resources, mInfoLog), mLinked); + if (!mLinked) + { + return NoError(); + } - mData.mTransformFeedbackVaryingVars.push_back(varying); + gatherTransformFeedbackVaryings(mergedVaryings); } - stream.readInt(&mData.mTransformFeedbackBufferMode); + gatherAtomicCounterBuffers(); + initInterfaceBlockBindings(); - unsigned int outputVarCount = stream.readInt(); - for (unsigned int outputIndex = 0; outputIndex < outputVarCount; ++outputIndex) - { - int locationIndex = stream.readInt(); - VariableLocation locationData; - stream.readInt(&locationData.element); - stream.readInt(&locationData.index); - stream.readString(&locationData.name); - mData.mOutputVariables[locationIndex] = locationData; - } + setUniformValuesFromBindingQualifiers(); - stream.readInt(&mSamplerUniformRange.start); - stream.readInt(&mSamplerUniformRange.end); + ASSERT(mLinked); + updateLinkedShaderStages(); - rx::LinkResult result = mProgram->load(mInfoLog, &stream); - if (result.error.isError() || !result.linkSuccess) + // Mark implementation-specific unreferenced uniforms as ignored. + mProgram->markUnusedUniformLocations(&mState.mUniformLocations, &mState.mSamplerBindings); + + // Save to the program cache. + if (cache && (mState.mLinkedTransformFeedbackVaryings.empty() || + !context->getWorkarounds().disableProgramCachingForTransformFeedback)) { - return result.error; + cache->putProgram(programHash, context, this); } - mLinked = true; - return Error(GL_NO_ERROR); -#endif // #if ANGLE_PROGRAM_BINARY_LOAD == ANGLE_ENABLED + double delta = platform->currentTime(platform) - startTime; + int us = static_cast(delta * 1000000.0); + ANGLE_HISTOGRAM_COUNTS("GPU.ANGLE.ProgramCache.ProgramCacheMissTimeUS", us); + + return NoError(); } -Error Program::saveBinary(GLenum *binaryFormat, void *binary, GLsizei bufSize, GLsizei *length) const +void Program::updateLinkedShaderStages() { - if (binaryFormat) + if (mState.mAttachedVertexShader) { - *binaryFormat = GL_PROGRAM_BINARY_ANGLE; + mState.mLinkedShaderStages.set(SHADER_VERTEX); } - BinaryOutputStream stream; - - stream.writeInt(ANGLE_MAJOR_VERSION); - stream.writeInt(ANGLE_MINOR_VERSION); - stream.writeBytes(reinterpret_cast(ANGLE_COMMIT_HASH), ANGLE_COMMIT_HASH_SIZE); - - stream.writeInt(mData.mActiveAttribLocationsMask.to_ulong()); - - stream.writeInt(mData.mAttributes.size()); - for (const sh::Attribute &attrib : mData.mAttributes) + if (mState.mAttachedFragmentShader) { - WriteShaderVar(&stream, attrib); - stream.writeInt(attrib.location); + mState.mLinkedShaderStages.set(SHADER_FRAGMENT); } - stream.writeInt(mData.mUniforms.size()); - for (const gl::LinkedUniform &uniform : mData.mUniforms) + if (mState.mAttachedComputeShader) { - WriteShaderVar(&stream, uniform); - - // FIXME: referenced - - stream.writeInt(uniform.blockIndex); - stream.writeInt(uniform.blockInfo.offset); - stream.writeInt(uniform.blockInfo.arrayStride); - stream.writeInt(uniform.blockInfo.matrixStride); - stream.writeInt(uniform.blockInfo.isRowMajorMatrix); + mState.mLinkedShaderStages.set(SHADER_COMPUTE); } +} - stream.writeInt(mData.mUniformLocations.size()); - for (const auto &variable : mData.mUniformLocations) - { - stream.writeString(variable.name); - stream.writeInt(variable.element); - stream.writeInt(variable.index); - } +// Returns the program object to an unlinked state, before re-linking, or at destruction +void Program::unlink() +{ + mState.mAttributes.clear(); + mState.mActiveAttribLocationsMask.reset(); + mState.mMaxActiveAttribLocation = 0; + mState.mLinkedTransformFeedbackVaryings.clear(); + mState.mUniforms.clear(); + mState.mUniformLocations.clear(); + mState.mUniformBlocks.clear(); + mState.mActiveUniformBlockBindings.reset(); + mState.mAtomicCounterBuffers.clear(); + mState.mOutputVariables.clear(); + mState.mOutputLocations.clear(); + mState.mOutputVariableTypes.clear(); + mState.mActiveOutputVariables.reset(); + mState.mComputeShaderLocalSize.fill(1); + mState.mSamplerBindings.clear(); + mState.mImageBindings.clear(); + mState.mNumViews = -1; + mState.mLinkedShaderStages.reset(); - stream.writeInt(mData.mUniformBlocks.size()); - for (const UniformBlock &uniformBlock : mData.mUniformBlocks) - { - stream.writeString(uniformBlock.name); - stream.writeInt(uniformBlock.isArray); - stream.writeInt(uniformBlock.arrayElement); - stream.writeInt(uniformBlock.dataSize); + mValidated = false; - stream.writeInt(uniformBlock.vertexStaticUse); - stream.writeInt(uniformBlock.fragmentStaticUse); + mLinked = false; +} - stream.writeInt(uniformBlock.memberUniformIndexes.size()); - for (unsigned int memberUniformIndex : uniformBlock.memberUniformIndexes) - { - stream.writeInt(memberUniformIndex); - } - } +bool Program::isLinked() const +{ + return mLinked; +} - stream.writeInt(mData.mTransformFeedbackVaryingVars.size()); - for (const sh::Varying &varying : mData.mTransformFeedbackVaryingVars) +Error Program::loadBinary(const Context *context, + GLenum binaryFormat, + const void *binary, + GLsizei length) +{ + unlink(); + +#if ANGLE_PROGRAM_BINARY_LOAD != ANGLE_ENABLED + return NoError(); +#else + ASSERT(binaryFormat == GL_PROGRAM_BINARY_ANGLE); + if (binaryFormat != GL_PROGRAM_BINARY_ANGLE) { - stream.writeInt(varying.arraySize); - stream.writeInt(varying.type); - stream.writeString(varying.name); + mInfoLog << "Invalid program binary format."; + return NoError(); } - stream.writeInt(mData.mTransformFeedbackBufferMode); + const uint8_t *bytes = reinterpret_cast(binary); + ANGLE_TRY_RESULT( + MemoryProgramCache::Deserialize(context, this, &mState, bytes, length, mInfoLog), mLinked); - stream.writeInt(mData.mOutputVariables.size()); - for (const auto &outputPair : mData.mOutputVariables) - { - stream.writeInt(outputPair.first); - stream.writeInt(outputPair.second.element); - stream.writeInt(outputPair.second.index); - stream.writeString(outputPair.second.name); - } + // Currently we require the full shader text to compute the program hash. + // TODO(jmadill): Store the binary in the internal program cache. - stream.writeInt(mSamplerUniformRange.start); - stream.writeInt(mSamplerUniformRange.end); + return NoError(); +#endif // #if ANGLE_PROGRAM_BINARY_LOAD == ANGLE_ENABLED +} - gl::Error error = mProgram->save(&stream); - if (error.isError()) +Error Program::saveBinary(const Context *context, + GLenum *binaryFormat, + void *binary, + GLsizei bufSize, + GLsizei *length) const +{ + if (binaryFormat) { - return error; + *binaryFormat = GL_PROGRAM_BINARY_ANGLE; } - GLsizei streamLength = static_cast(stream.length()); - const void *streamData = stream.data(); + angle::MemoryBuffer memoryBuf; + MemoryProgramCache::Serialize(context, this, &memoryBuf); + + GLsizei streamLength = static_cast(memoryBuf.size()); + const uint8_t *streamState = memoryBuf.data(); if (streamLength > bufSize) { @@ -775,14 +1073,14 @@ Error Program::saveBinary(GLenum *binaryFormat, void *binary, GLsizei bufSize, G // 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); + return InternalError(); } if (binary) { char *ptr = reinterpret_cast(binary); - memcpy(ptr, streamData, streamLength); + memcpy(ptr, streamState, streamLength); ptr += streamLength; ASSERT(ptr - streamLength == binary); @@ -793,13 +1091,13 @@ Error Program::saveBinary(GLenum *binaryFormat, void *binary, GLsizei bufSize, G *length = streamLength; } - return Error(GL_NO_ERROR); + return NoError(); } -GLint Program::getBinaryLength() const +GLint Program::getBinaryLength(const Context *context) const { GLint length; - Error error = saveBinary(nullptr, nullptr, std::numeric_limits::max(), &length); + Error error = saveBinary(context, nullptr, nullptr, std::numeric_limits::max(), &length); if (error.isError()) { return 0; @@ -812,21 +1110,36 @@ void Program::setBinaryRetrievableHint(bool retrievable) { // TODO(jmadill) : replace with dirty bits mProgram->setBinaryRetrievableHint(retrievable); - mData.mBinaryRetrieveableHint = retrievable; + mState.mBinaryRetrieveableHint = retrievable; } bool Program::getBinaryRetrievableHint() const { - return mData.mBinaryRetrieveableHint; + return mState.mBinaryRetrieveableHint; } -void Program::release() +void Program::setSeparable(bool separable) +{ + // TODO(yunchao) : replace with dirty bits + if (mState.mSeparable != separable) + { + mProgram->setSeparable(separable); + mState.mSeparable = separable; + } +} + +bool Program::isSeparable() const +{ + return mState.mSeparable; +} + +void Program::release(const Context *context) { mRefCount--; if (mRefCount == 0 && mDeleteStatus) { - mResourceManager->deleteProgram(mHandle); + mResourceManager->deleteProgram(context, mHandle); } } @@ -854,24 +1167,40 @@ void Program::getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shade { int total = 0; - if (mData.mAttachedVertexShader) + if (mState.mAttachedComputeShader) { if (total < maxCount) { - shaders[total] = mData.mAttachedVertexShader->getHandle(); + shaders[total] = mState.mAttachedComputeShader->getHandle(); + total++; } + } - total++; + if (mState.mAttachedVertexShader) + { + if (total < maxCount) + { + shaders[total] = mState.mAttachedVertexShader->getHandle(); + total++; + } } - if (mData.mAttachedFragmentShader) + if (mState.mAttachedFragmentShader) { if (total < maxCount) { - shaders[total] = mData.mAttachedFragmentShader->getHandle(); + shaders[total] = mState.mAttachedFragmentShader->getHandle(); + total++; } + } - total++; + if (mState.mAttachedGeometryShader) + { + if (total < maxCount) + { + shaders[total] = mState.mAttachedGeometryShader->getHandle(); + total++; + } } if (count) @@ -882,24 +1211,21 @@ void Program::getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shade GLuint Program::getAttributeLocation(const std::string &name) const { - for (const sh::Attribute &attribute : mData.mAttributes) - { - if (attribute.name == name && attribute.staticUse) - { - return attribute.location; - } - } - - return static_cast(-1); + return mState.getAttributeLocation(name); } bool Program::isAttribLocationActive(size_t attribLocation) const { - ASSERT(attribLocation < mData.mActiveAttribLocationsMask.size()); - return mData.mActiveAttribLocationsMask[attribLocation]; + ASSERT(attribLocation < mState.mActiveAttribLocationsMask.size()); + return mState.mActiveAttribLocationsMask[attribLocation]; } -void Program::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) +void Program::getActiveAttribute(GLuint index, + GLsizei bufsize, + GLsizei *length, + GLint *size, + GLenum *type, + GLchar *name) const { if (!mLinked) { @@ -918,35 +1244,12 @@ void Program::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, return; } - size_t attributeIndex = 0; - - for (const sh::Attribute &attribute : mData.mAttributes) - { - // Skip over inactive attributes - if (attribute.staticUse) - { - if (static_cast(index) == attributeIndex) - { - break; - } - attributeIndex++; - } - } - - ASSERT(index == attributeIndex && attributeIndex < mData.mAttributes.size()); - const sh::Attribute &attrib = mData.mAttributes[attributeIndex]; + ASSERT(index < mState.mAttributes.size()); + const sh::Attribute &attrib = mState.mAttributes[index]; if (bufsize > 0) { - const char *string = attrib.name.c_str(); - - strncpy(name, string, bufsize); - name[bufsize - 1] = '\0'; - - if (length) - { - *length = static_cast(strlen(name)); - } + CopyStringToBuffer(name, attrib.name, bufsize, length); } // Always a single 'type' instance @@ -961,14 +1264,7 @@ GLint Program::getActiveAttributeCount() const return 0; } - GLint count = 0; - - for (const sh::Attribute &attrib : mData.mAttributes) - { - count += (attrib.staticUse ? 1 : 0); - } - - return count; + return static_cast(mState.mAttributes.size()); } GLint Program::getActiveAttributeMaxLength() const @@ -980,30 +1276,105 @@ GLint Program::getActiveAttributeMaxLength() const size_t maxLength = 0; - for (const sh::Attribute &attrib : mData.mAttributes) + for (const sh::Attribute &attrib : mState.mAttributes) { - if (attrib.staticUse) - { - maxLength = std::max(attrib.name.length() + 1, maxLength); - } + maxLength = std::max(attrib.name.length() + 1, maxLength); } return static_cast(maxLength); } -GLint Program::getFragDataLocation(const std::string &name) const +GLuint Program::getInputResourceIndex(const GLchar *name) const +{ + return GetResourceIndexFromName(mState.mAttributes, std::string(name)); +} + +GLuint Program::getOutputResourceIndex(const GLchar *name) const +{ + return GetResourceIndexFromName(mState.mOutputVariables, std::string(name)); +} + +size_t Program::getOutputResourceCount() const +{ + return (mLinked ? mState.mOutputVariables.size() : 0); +} + +template +void Program::getResourceName(GLuint index, + const std::vector &resources, + GLsizei bufSize, + GLsizei *length, + GLchar *name) const { - std::string baseName(name); - unsigned int arrayIndex = ParseAndStripArrayIndex(&baseName); - for (auto outputPair : mData.mOutputVariables) + if (length) + { + *length = 0; + } + + if (!mLinked) { - const VariableLocation &outputVariable = outputPair.second; - if (outputVariable.name == baseName && (arrayIndex == GL_INVALID_INDEX || arrayIndex == outputVariable.element)) + if (bufSize > 0) { - return static_cast(outputPair.first); + name[0] = '\0'; } + return; } - return -1; + ASSERT(index < resources.size()); + const auto &resource = resources[index]; + + if (bufSize > 0) + { + CopyStringToBuffer(name, resource.name, bufSize, length); + } +} + +void Program::getInputResourceName(GLuint index, + GLsizei bufSize, + GLsizei *length, + GLchar *name) const +{ + getResourceName(index, mState.mAttributes, bufSize, length, name); +} + +void Program::getOutputResourceName(GLuint index, + GLsizei bufSize, + GLsizei *length, + GLchar *name) const +{ + getResourceName(index, mState.mOutputVariables, bufSize, length, name); +} + +void Program::getUniformResourceName(GLuint index, + GLsizei bufSize, + GLsizei *length, + GLchar *name) const +{ + getResourceName(index, mState.mUniforms, bufSize, length, name); +} + +void Program::getBufferVariableResourceName(GLuint index, + GLsizei bufSize, + GLsizei *length, + GLchar *name) const +{ + getResourceName(index, mState.mBufferVariables, bufSize, length, name); +} + +const sh::Attribute &Program::getInputResource(GLuint index) const +{ + ASSERT(index < mState.mAttributes.size()); + return mState.mAttributes[index]; +} + +const sh::OutputVariable &Program::getOutputResource(GLuint index) const +{ + ASSERT(index < mState.mOutputVariables.size()); + return mState.mOutputVariables[index]; +} + +GLint Program::getFragDataLocation(const std::string &name) const +{ + return GetVariableLocation(mState.mOutputVariables, mState.mOutputLocations, name); } void Program::getActiveUniform(GLuint index, @@ -1016,27 +1387,16 @@ void Program::getActiveUniform(GLuint index, if (mLinked) { // index must be smaller than getActiveUniformCount() - ASSERT(index < mData.mUniforms.size()); - const LinkedUniform &uniform = mData.mUniforms[index]; + ASSERT(index < mState.mUniforms.size()); + const LinkedUniform &uniform = mState.mUniforms[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 = static_cast(strlen(name)); - } + CopyStringToBuffer(name, string, bufsize, length); } - *size = uniform.elementCount(); + *size = clampCast(uniform.getBasicTypeElementCount()); *type = uniform.type; } else @@ -1060,7 +1420,7 @@ GLint Program::getActiveUniformCount() const { if (mLinked) { - return static_cast(mData.mUniforms.size()); + return static_cast(mState.mUniforms.size()); } else { @@ -1068,13 +1428,18 @@ GLint Program::getActiveUniformCount() const } } +size_t Program::getActiveBufferVariableCount() const +{ + return mLinked ? mState.mBufferVariables.size() : 0; +} + GLint Program::getActiveUniformMaxLength() const { size_t maxLength = 0; if (mLinked) { - for (const LinkedUniform &uniform : mData.mUniforms) + for (const LinkedUniform &uniform : mState.mUniforms) { if (!uniform.name.empty()) { @@ -1091,189 +1456,249 @@ GLint Program::getActiveUniformMaxLength() const return static_cast(maxLength); } -GLint Program::getActiveUniformi(GLuint index, GLenum pname) const +bool Program::isValidUniformLocation(GLint location) const { - ASSERT(static_cast(index) < mData.mUniforms.size()); - const gl::LinkedUniform &uniform = mData.mUniforms[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; + ASSERT(angle::IsValueInRangeForNumericType(mState.mUniformLocations.size())); + return (location >= 0 && static_cast(location) < mState.mUniformLocations.size() && + mState.mUniformLocations[static_cast(location)].used()); } -bool Program::isValidUniformLocation(GLint location) const +const LinkedUniform &Program::getUniformByLocation(GLint location) const { - ASSERT(rx::IsIntegerCastSafe(mData.mUniformLocations.size())); - return (location >= 0 && static_cast(location) < mData.mUniformLocations.size()); + ASSERT(location >= 0 && static_cast(location) < mState.mUniformLocations.size()); + return mState.mUniforms[mState.getUniformIndexFromLocation(location)]; } -const LinkedUniform &Program::getUniformByLocation(GLint location) const +const VariableLocation &Program::getUniformLocation(GLint location) const +{ + ASSERT(location >= 0 && static_cast(location) < mState.mUniformLocations.size()); + return mState.mUniformLocations[location]; +} + +const std::vector &Program::getUniformLocations() const +{ + return mState.mUniformLocations; +} + +const LinkedUniform &Program::getUniformByIndex(GLuint index) const { - ASSERT(location >= 0 && static_cast(location) < mData.mUniformLocations.size()); - return mData.mUniforms[mData.mUniformLocations[location].index]; + ASSERT(index < static_cast(mState.mUniforms.size())); + return mState.mUniforms[index]; +} + +const BufferVariable &Program::getBufferVariableByIndex(GLuint index) const +{ + ASSERT(index < static_cast(mState.mBufferVariables.size())); + return mState.mBufferVariables[index]; } GLint Program::getUniformLocation(const std::string &name) const { - return mData.getUniformLocation(name); + return GetVariableLocation(mState.mUniforms, mState.mUniformLocations, name); } GLuint Program::getUniformIndex(const std::string &name) const { - return mData.getUniformIndex(name); + return mState.getUniformIndexFromName(name); } void Program::setUniform1fv(GLint location, GLsizei count, const GLfloat *v) { - setUniformInternal(location, count * 1, v); - mProgram->setUniform1fv(location, count, v); + const VariableLocation &locationInfo = mState.mUniformLocations[location]; + GLsizei clampedCount = clampUniformCount(locationInfo, count, 1, v); + mProgram->setUniform1fv(location, clampedCount, v); } void Program::setUniform2fv(GLint location, GLsizei count, const GLfloat *v) { - setUniformInternal(location, count * 2, v); - mProgram->setUniform2fv(location, count, v); + const VariableLocation &locationInfo = mState.mUniformLocations[location]; + GLsizei clampedCount = clampUniformCount(locationInfo, count, 2, v); + mProgram->setUniform2fv(location, clampedCount, v); } void Program::setUniform3fv(GLint location, GLsizei count, const GLfloat *v) { - setUniformInternal(location, count * 3, v); - mProgram->setUniform3fv(location, count, v); + const VariableLocation &locationInfo = mState.mUniformLocations[location]; + GLsizei clampedCount = clampUniformCount(locationInfo, count, 3, v); + mProgram->setUniform3fv(location, clampedCount, v); } void Program::setUniform4fv(GLint location, GLsizei count, const GLfloat *v) { - setUniformInternal(location, count * 4, v); - mProgram->setUniform4fv(location, count, v); + const VariableLocation &locationInfo = mState.mUniformLocations[location]; + GLsizei clampedCount = clampUniformCount(locationInfo, count, 4, v); + mProgram->setUniform4fv(location, clampedCount, v); } -void Program::setUniform1iv(GLint location, GLsizei count, const GLint *v) +Program::SetUniformResult Program::setUniform1iv(GLint location, GLsizei count, const GLint *v) { - setUniformInternal(location, count * 1, v); - mProgram->setUniform1iv(location, count, v); + const VariableLocation &locationInfo = mState.mUniformLocations[location]; + GLsizei clampedCount = clampUniformCount(locationInfo, count, 1, v); + + mProgram->setUniform1iv(location, clampedCount, v); + + if (mState.isSamplerUniformIndex(locationInfo.index)) + { + updateSamplerUniform(locationInfo, clampedCount, v); + return SetUniformResult::SamplerChanged; + } + + return SetUniformResult::NoSamplerChange; } void Program::setUniform2iv(GLint location, GLsizei count, const GLint *v) { - setUniformInternal(location, count * 2, v); - mProgram->setUniform2iv(location, count, v); + const VariableLocation &locationInfo = mState.mUniformLocations[location]; + GLsizei clampedCount = clampUniformCount(locationInfo, count, 2, v); + mProgram->setUniform2iv(location, clampedCount, v); } void Program::setUniform3iv(GLint location, GLsizei count, const GLint *v) { - setUniformInternal(location, count * 3, v); - mProgram->setUniform3iv(location, count, v); + const VariableLocation &locationInfo = mState.mUniformLocations[location]; + GLsizei clampedCount = clampUniformCount(locationInfo, count, 3, v); + mProgram->setUniform3iv(location, clampedCount, v); } void Program::setUniform4iv(GLint location, GLsizei count, const GLint *v) { - setUniformInternal(location, count * 4, v); - mProgram->setUniform4iv(location, count, v); + const VariableLocation &locationInfo = mState.mUniformLocations[location]; + GLsizei clampedCount = clampUniformCount(locationInfo, count, 4, v); + mProgram->setUniform4iv(location, clampedCount, v); } void Program::setUniform1uiv(GLint location, GLsizei count, const GLuint *v) { - setUniformInternal(location, count * 1, v); - mProgram->setUniform1uiv(location, count, v); + const VariableLocation &locationInfo = mState.mUniformLocations[location]; + GLsizei clampedCount = clampUniformCount(locationInfo, count, 1, v); + mProgram->setUniform1uiv(location, clampedCount, v); } void Program::setUniform2uiv(GLint location, GLsizei count, const GLuint *v) { - setUniformInternal(location, count * 2, v); - mProgram->setUniform2uiv(location, count, v); + const VariableLocation &locationInfo = mState.mUniformLocations[location]; + GLsizei clampedCount = clampUniformCount(locationInfo, count, 2, v); + mProgram->setUniform2uiv(location, clampedCount, v); } void Program::setUniform3uiv(GLint location, GLsizei count, const GLuint *v) { - setUniformInternal(location, count * 3, v); - mProgram->setUniform3uiv(location, count, v); + const VariableLocation &locationInfo = mState.mUniformLocations[location]; + GLsizei clampedCount = clampUniformCount(locationInfo, count, 3, v); + mProgram->setUniform3uiv(location, clampedCount, v); } void Program::setUniform4uiv(GLint location, GLsizei count, const GLuint *v) { - setUniformInternal(location, count * 4, v); - mProgram->setUniform4uiv(location, count, v); + const VariableLocation &locationInfo = mState.mUniformLocations[location]; + GLsizei clampedCount = clampUniformCount(locationInfo, count, 4, v); + mProgram->setUniform4uiv(location, clampedCount, v); } void Program::setUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v) { - setMatrixUniformInternal<2, 2>(location, count, transpose, v); - mProgram->setUniformMatrix2fv(location, count, transpose, v); + GLsizei clampedCount = clampMatrixUniformCount<2, 2>(location, count, transpose, v); + mProgram->setUniformMatrix2fv(location, clampedCount, transpose, v); } void Program::setUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v) { - setMatrixUniformInternal<3, 3>(location, count, transpose, v); - mProgram->setUniformMatrix3fv(location, count, transpose, v); + GLsizei clampedCount = clampMatrixUniformCount<3, 3>(location, count, transpose, v); + mProgram->setUniformMatrix3fv(location, clampedCount, transpose, v); } void Program::setUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v) { - setMatrixUniformInternal<4, 4>(location, count, transpose, v); - mProgram->setUniformMatrix4fv(location, count, transpose, v); + GLsizei clampedCount = clampMatrixUniformCount<4, 4>(location, count, transpose, v); + mProgram->setUniformMatrix4fv(location, clampedCount, transpose, v); } void Program::setUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v) { - setMatrixUniformInternal<2, 3>(location, count, transpose, v); - mProgram->setUniformMatrix2x3fv(location, count, transpose, v); + GLsizei clampedCount = clampMatrixUniformCount<2, 3>(location, count, transpose, v); + mProgram->setUniformMatrix2x3fv(location, clampedCount, transpose, v); } void Program::setUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v) { - setMatrixUniformInternal<2, 4>(location, count, transpose, v); - mProgram->setUniformMatrix2x4fv(location, count, transpose, v); + GLsizei clampedCount = clampMatrixUniformCount<2, 4>(location, count, transpose, v); + mProgram->setUniformMatrix2x4fv(location, clampedCount, transpose, v); } void Program::setUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v) { - setMatrixUniformInternal<3, 2>(location, count, transpose, v); - mProgram->setUniformMatrix3x2fv(location, count, transpose, v); + GLsizei clampedCount = clampMatrixUniformCount<3, 2>(location, count, transpose, v); + mProgram->setUniformMatrix3x2fv(location, clampedCount, transpose, v); } void Program::setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v) { - setMatrixUniformInternal<3, 4>(location, count, transpose, v); - mProgram->setUniformMatrix3x4fv(location, count, transpose, v); + GLsizei clampedCount = clampMatrixUniformCount<3, 4>(location, count, transpose, v); + mProgram->setUniformMatrix3x4fv(location, clampedCount, transpose, v); } void Program::setUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v) { - setMatrixUniformInternal<4, 2>(location, count, transpose, v); - mProgram->setUniformMatrix4x2fv(location, count, transpose, v); + GLsizei clampedCount = clampMatrixUniformCount<4, 2>(location, count, transpose, v); + mProgram->setUniformMatrix4x2fv(location, clampedCount, transpose, v); } void Program::setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v) { - setMatrixUniformInternal<4, 3>(location, count, transpose, v); - mProgram->setUniformMatrix4x3fv(location, count, transpose, v); + GLsizei clampedCount = clampMatrixUniformCount<4, 3>(location, count, transpose, v); + mProgram->setUniformMatrix4x3fv(location, clampedCount, transpose, v); } -void Program::getUniformfv(GLint location, GLfloat *v) const +void Program::getUniformfv(const Context *context, GLint location, GLfloat *v) const { - getUniformInternal(location, v); -} + const auto &uniformLocation = mState.getUniformLocations()[location]; + const auto &uniform = mState.getUniforms()[uniformLocation.index]; -void Program::getUniformiv(GLint location, GLint *v) const -{ - getUniformInternal(location, v); + GLenum nativeType = gl::VariableComponentType(uniform.type); + if (nativeType == GL_FLOAT) + { + mProgram->getUniformfv(context, location, v); + } + else + { + getUniformInternal(context, v, location, nativeType, + gl::VariableComponentCount(uniform.type)); + } } -void Program::getUniformuiv(GLint location, GLuint *v) const +void Program::getUniformiv(const Context *context, GLint location, GLint *v) const { - getUniformInternal(location, v); -} + const auto &uniformLocation = mState.getUniformLocations()[location]; + const auto &uniform = mState.getUniforms()[uniformLocation.index]; + + GLenum nativeType = gl::VariableComponentType(uniform.type); + if (nativeType == GL_INT || nativeType == GL_BOOL) + { + mProgram->getUniformiv(context, location, v); + } + else + { + getUniformInternal(context, v, location, nativeType, + gl::VariableComponentCount(uniform.type)); + } +} + +void Program::getUniformuiv(const Context *context, GLint location, GLuint *v) const +{ + const auto &uniformLocation = mState.getUniformLocations()[location]; + const auto &uniform = mState.getUniforms()[uniformLocation.index]; + + GLenum nativeType = gl::VariableComponentType(uniform.type); + if (nativeType == GL_UNSIGNED_INT) + { + mProgram->getUniformuiv(context, location, v); + } + else + { + getUniformInternal(context, v, location, nativeType, + gl::VariableComponentCount(uniform.type)); + } +} void Program::flagForDeletion() { @@ -1291,7 +1716,7 @@ void Program::validate(const Caps &caps) if (mLinked) { - mValidated = (mProgram->validate(caps, &mInfoLog) == GL_TRUE); + mValidated = ConvertToBool(mProgram->validate(caps, &mInfoLog)); } else { @@ -1320,22 +1745,15 @@ bool Program::validateSamplers(InfoLog *infoLog, const 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. - for (unsigned int samplerIndex = mSamplerUniformRange.start; - samplerIndex < mSamplerUniformRange.end; ++samplerIndex) + for (const auto &samplerBinding : mState.mSamplerBindings) { - const LinkedUniform &uniform = mData.mUniforms[samplerIndex]; - ASSERT(uniform.isSampler()); - - if (!uniform.staticUse) + if (samplerBinding.unreferenced) continue; - const GLuint *dataPtr = reinterpret_cast(uniform.getDataPtrToElement(0)); - GLenum textureType = SamplerTypeToTextureType(uniform.type); + GLenum textureType = samplerBinding.textureType; - for (unsigned int arrayElement = 0; arrayElement < uniform.elementCount(); ++arrayElement) + for (GLuint textureUnit : samplerBinding.boundTextureUnits) { - GLuint textureUnit = dataPtr[arrayElement]; - if (textureUnit >= caps.maxCombinedTextureImageUnits) { if (infoLog) @@ -1382,70 +1800,34 @@ bool Program::isValidated() const GLuint Program::getActiveUniformBlockCount() const { - return static_cast(mData.mUniformBlocks.size()); + return static_cast(mState.mUniformBlocks.size()); } -void Program::getActiveUniformBlockName(GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName) const +GLuint Program::getActiveAtomicCounterBufferCount() const { - ASSERT(uniformBlockIndex < - mData.mUniformBlocks.size()); // index must be smaller than getActiveUniformBlockCount() - - const UniformBlock &uniformBlock = mData.mUniformBlocks[uniformBlockIndex]; - - if (bufSize > 0) - { - std::string string = uniformBlock.name; - - if (uniformBlock.isArray) - { - string += ArrayString(uniformBlock.arrayElement); - } - - strncpy(uniformBlockName, string.c_str(), bufSize); - uniformBlockName[bufSize - 1] = '\0'; + return static_cast(mState.mAtomicCounterBuffers.size()); +} - if (length) - { - *length = static_cast(strlen(uniformBlockName)); - } - } +GLuint Program::getActiveShaderStorageBlockCount() const +{ + return static_cast(mState.mShaderStorageBlocks.size()); } -void Program::getActiveUniformBlockiv(GLuint uniformBlockIndex, GLenum pname, GLint *params) const +void Program::getActiveUniformBlockName(const GLuint blockIndex, + GLsizei bufSize, + GLsizei *length, + GLchar *blockName) const { - ASSERT(uniformBlockIndex < - mData.mUniformBlocks.size()); // index must be smaller than getActiveUniformBlockCount() + GetInterfaceBlockName(blockIndex, mState.mUniformBlocks, bufSize, length, blockName); +} - const UniformBlock &uniformBlock = mData.mUniformBlocks[uniformBlockIndex]; +void Program::getActiveShaderStorageBlockName(const GLuint blockIndex, + GLsizei bufSize, + GLsizei *length, + GLchar *blockName) const +{ - 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.isArray ? 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.vertexStaticUse); - break; - case GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER: - *params = static_cast(uniformBlock.fragmentStaticUse); - break; - default: UNREACHABLE(); - } + GetInterfaceBlockName(blockIndex, mState.mShaderStorageBlocks, bufSize, length, blockName); } GLint Program::getActiveUniformBlockMaxLength() const @@ -1454,18 +1836,14 @@ GLint Program::getActiveUniformBlockMaxLength() const if (mLinked) { - unsigned int numUniformBlocks = static_cast(mData.mUniformBlocks.size()); + unsigned int numUniformBlocks = static_cast(mState.mUniformBlocks.size()); for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < numUniformBlocks; uniformBlockIndex++) { - const UniformBlock &uniformBlock = mData.mUniformBlocks[uniformBlockIndex]; + const InterfaceBlock &uniformBlock = mState.mUniformBlocks[uniformBlockIndex]; if (!uniformBlock.name.empty()) { - const int length = static_cast(uniformBlock.name.length()) + 1; - - // Counting in "[0]". - const int arrayLength = (uniformBlock.isArray ? 3 : 0); - - maxLength = std::max(length + arrayLength, maxLength); + int length = static_cast(uniformBlock.nameWithArrayIndex().length()); + maxLength = std::max(length + 1, maxLength); } } } @@ -1475,87 +1853,77 @@ GLint Program::getActiveUniformBlockMaxLength() const GLuint Program::getUniformBlockIndex(const std::string &name) const { - size_t subscript = GL_INVALID_INDEX; - std::string baseName = gl::ParseUniformName(name, &subscript); + return GetInterfaceBlockIndex(mState.mUniformBlocks, name); +} - unsigned int numUniformBlocks = static_cast(mData.mUniformBlocks.size()); - for (unsigned int blockIndex = 0; blockIndex < numUniformBlocks; blockIndex++) - { - const gl::UniformBlock &uniformBlock = mData.mUniformBlocks[blockIndex]; - if (uniformBlock.name == baseName) - { - const bool arrayElementZero = - (subscript == GL_INVALID_INDEX && - (!uniformBlock.isArray || uniformBlock.arrayElement == 0)); - if (subscript == uniformBlock.arrayElement || arrayElementZero) - { - return blockIndex; - } - } - } +GLuint Program::getShaderStorageBlockIndex(const std::string &name) const +{ + return GetInterfaceBlockIndex(mState.mShaderStorageBlocks, name); +} - return GL_INVALID_INDEX; +const InterfaceBlock &Program::getUniformBlockByIndex(GLuint index) const +{ + ASSERT(index < static_cast(mState.mUniformBlocks.size())); + return mState.mUniformBlocks[index]; } -const UniformBlock &Program::getUniformBlockByIndex(GLuint index) const +const InterfaceBlock &Program::getShaderStorageBlockByIndex(GLuint index) const { - ASSERT(index < static_cast(mData.mUniformBlocks.size())); - return mData.mUniformBlocks[index]; + ASSERT(index < static_cast(mState.mShaderStorageBlocks.size())); + return mState.mShaderStorageBlocks[index]; } void Program::bindUniformBlock(GLuint uniformBlockIndex, GLuint uniformBlockBinding) { - mData.mUniformBlockBindings[uniformBlockIndex] = uniformBlockBinding; + mState.mUniformBlocks[uniformBlockIndex].binding = uniformBlockBinding; + mState.mActiveUniformBlockBindings.set(uniformBlockIndex, uniformBlockBinding != 0); mProgram->setUniformBlockBinding(uniformBlockIndex, uniformBlockBinding); } GLuint Program::getUniformBlockBinding(GLuint uniformBlockIndex) const { - return mData.getUniformBlockBinding(uniformBlockIndex); + return mState.getUniformBlockBinding(uniformBlockIndex); } -void Program::resetUniformBlockBindings() +GLuint Program::getShaderStorageBlockBinding(GLuint shaderStorageBlockIndex) const { - for (unsigned int blockId = 0; blockId < IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS; blockId++) - { - mData.mUniformBlockBindings[blockId] = 0; - } - mData.mActiveUniformBlockBindings.reset(); + return mState.getShaderStorageBlockBinding(shaderStorageBlockIndex); } void Program::setTransformFeedbackVaryings(GLsizei count, const GLchar *const *varyings, GLenum bufferMode) { - mData.mTransformFeedbackVaryingNames.resize(count); + mState.mTransformFeedbackVaryingNames.resize(count); for (GLsizei i = 0; i < count; i++) { - mData.mTransformFeedbackVaryingNames[i] = varyings[i]; + mState.mTransformFeedbackVaryingNames[i] = varyings[i]; } - mData.mTransformFeedbackBufferMode = bufferMode; + mState.mTransformFeedbackBufferMode = bufferMode; } void Program::getTransformFeedbackVarying(GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name) const { if (mLinked) { - ASSERT(index < mData.mTransformFeedbackVaryingVars.size()); - const sh::Varying &varying = mData.mTransformFeedbackVaryingVars[index]; - GLsizei lastNameIdx = std::min(bufSize - 1, static_cast(varying.name.length())); + ASSERT(index < mState.mLinkedTransformFeedbackVaryings.size()); + const auto &var = mState.mLinkedTransformFeedbackVaryings[index]; + std::string varName = var.nameWithArrayIndex(); + GLsizei lastNameIdx = std::min(bufSize - 1, static_cast(varName.length())); if (length) { *length = lastNameIdx; } if (size) { - *size = varying.elementCount(); + *size = var.size(); } if (type) { - *type = varying.type; + *type = var.type; } if (name) { - memcpy(name, varying.name.c_str(), lastNameIdx); + memcpy(name, varName.c_str(), lastNameIdx); name[lastNameIdx] = '\0'; } } @@ -1565,7 +1933,7 @@ GLsizei Program::getTransformFeedbackVaryingCount() const { if (mLinked) { - return static_cast(mData.mTransformFeedbackVaryingVars.size()); + return static_cast(mState.mLinkedTransformFeedbackVaryings.size()); } else { @@ -1578,9 +1946,10 @@ GLsizei Program::getTransformFeedbackVaryingMaxLength() const if (mLinked) { GLsizei maxSize = 0; - for (const sh::Varying &varying : mData.mTransformFeedbackVaryingVars) + for (const auto &var : mState.mLinkedTransformFeedbackVaryings) { - maxSize = std::max(maxSize, static_cast(varying.name.length() + 1)); + maxSize = + std::max(maxSize, static_cast(var.nameWithArrayIndex().length() + 1)); } return maxSize; @@ -1593,16 +1962,20 @@ GLsizei Program::getTransformFeedbackVaryingMaxLength() const GLenum Program::getTransformFeedbackBufferMode() const { - return mData.mTransformFeedbackBufferMode; + return mState.mTransformFeedbackBufferMode; } -// static -bool Program::linkVaryings(InfoLog &infoLog, - const Shader *vertexShader, - const Shader *fragmentShader) +bool Program::linkVaryings(const Context *context, InfoLog &infoLog) const { - const std::vector &vertexVaryings = vertexShader->getVaryings(); - const std::vector &fragmentVaryings = fragmentShader->getVaryings(); + Shader *vertexShader = mState.mAttachedVertexShader; + Shader *fragmentShader = mState.mAttachedFragmentShader; + + ASSERT(vertexShader->getShaderVersion(context) == fragmentShader->getShaderVersion(context)); + + const std::vector &vertexVaryings = vertexShader->getOutputVaryings(context); + const std::vector &fragmentVaryings = fragmentShader->getInputVaryings(context); + + std::map staticFragmentInputLocations; for (const sh::Varying &output : fragmentVaryings) { @@ -1619,7 +1992,8 @@ bool Program::linkVaryings(InfoLog &infoLog, if (output.name == input.name) { ASSERT(!input.isBuiltIn()); - if (!linkValidateVaryings(infoLog, output.name, input, output)) + if (!linkValidateVaryings(infoLog, output.name, input, output, + vertexShader->getShaderVersion(context))) { return false; } @@ -1635,6 +2009,34 @@ bool Program::linkVaryings(InfoLog &infoLog, infoLog << "Fragment varying " << output.name << " does not match any vertex varying"; return false; } + + // Check for aliased path rendering input bindings (if any). + // If more than one binding refer statically to the same + // location the link must fail. + + if (!output.staticUse) + continue; + + const auto inputBinding = mFragmentInputBindings.getBinding(output.name); + if (inputBinding == -1) + continue; + + const auto it = staticFragmentInputLocations.find(inputBinding); + if (it == std::end(staticFragmentInputLocations)) + { + staticFragmentInputLocations.insert(std::make_pair(inputBinding, output.name)); + } + else + { + infoLog << "Binding for fragment input " << output.name << " conflicts with " + << it->second; + return false; + } + } + + if (!linkValidateBuiltInVaryings(context, infoLog)) + { + return false; } // TODO(jmadill): verify no unmatched vertex varyings? @@ -1642,67 +2044,135 @@ bool Program::linkVaryings(InfoLog &infoLog, return true; } -bool Program::linkUniforms(gl::InfoLog &infoLog, const gl::Caps &caps) +bool Program::linkUniforms(const Context *context, + InfoLog &infoLog, + const Bindings &uniformLocationBindings) +{ + UniformLinker linker(mState); + if (!linker.link(context, infoLog, uniformLocationBindings)) + { + return false; + } + + linker.getResults(&mState.mUniforms, &mState.mUniformLocations); + + linkSamplerAndImageBindings(); + + if (!linkAtomicCounterBuffers()) + { + return false; + } + + return true; +} + +void Program::linkSamplerAndImageBindings() { - const std::vector &vertexUniforms = mData.mAttachedVertexShader->getUniforms(); - const std::vector &fragmentUniforms = mData.mAttachedFragmentShader->getUniforms(); + unsigned int high = static_cast(mState.mUniforms.size()); + unsigned int low = high; + + for (auto counterIter = mState.mUniforms.rbegin(); + counterIter != mState.mUniforms.rend() && counterIter->isAtomicCounter(); ++counterIter) + { + --low; + } + + mState.mAtomicCounterUniformRange = RangeUI(low, high); - // Check that uniforms defined in the vertex and fragment shaders are identical - std::map linkedUniforms; + high = low; - for (const sh::Uniform &vertexUniform : vertexUniforms) + for (auto imageIter = mState.mUniforms.rbegin(); + imageIter != mState.mUniforms.rend() && imageIter->isImage(); ++imageIter) { - linkedUniforms[vertexUniform.name] = LinkedUniform(vertexUniform); + --low; } - for (const sh::Uniform &fragmentUniform : fragmentUniforms) + mState.mImageUniformRange = RangeUI(low, high); + + // If uniform is a image type, insert it into the mImageBindings array. + for (unsigned int imageIndex : mState.mImageUniformRange) { - auto entry = linkedUniforms.find(fragmentUniform.name); - if (entry != linkedUniforms.end()) + // ES3.1 (section 7.6.1) and GLSL ES3.1 (section 4.4.5), Uniform*i{v} commands + // cannot load values into a uniform defined as an image. if declare without a + // binding qualifier, any uniform image variable (include all elements of + // unbound image array) shoud be bound to unit zero. + auto &imageUniform = mState.mUniforms[imageIndex]; + if (imageUniform.binding == -1) { - LinkedUniform *vertexUniform = &entry->second; - const std::string &uniformName = "uniform '" + vertexUniform->name + "'"; - if (!linkValidateUniforms(infoLog, uniformName, *vertexUniform, fragmentUniform)) - { - return false; - } + mState.mImageBindings.emplace_back( + ImageBinding(imageUniform.getBasicTypeElementCount())); + } + else + { + mState.mImageBindings.emplace_back( + ImageBinding(imageUniform.binding, imageUniform.getBasicTypeElementCount())); } } - // Flatten the uniforms list (nested fields) into a simple list (no nesting). - // Also check the maximum uniform vector and sampler counts. - if (!flattenUniformsAndCheckCaps(caps, infoLog)) + high = low; + + for (auto samplerIter = mState.mUniforms.rbegin() + mState.mImageUniformRange.length(); + samplerIter != mState.mUniforms.rend() && samplerIter->isSampler(); ++samplerIter) { - return false; + --low; } - indexUniforms(); + mState.mSamplerUniformRange = RangeUI(low, high); - return true; + // If uniform is a sampler type, insert it into the mSamplerBindings array. + for (unsigned int samplerIndex : mState.mSamplerUniformRange) + { + const auto &samplerUniform = mState.mUniforms[samplerIndex]; + GLenum textureType = SamplerTypeToTextureType(samplerUniform.type); + mState.mSamplerBindings.emplace_back( + SamplerBinding(textureType, samplerUniform.getBasicTypeElementCount(), false)); + } } -void Program::indexUniforms() +bool Program::linkAtomicCounterBuffers() { - for (size_t uniformIndex = 0; uniformIndex < mData.mUniforms.size(); uniformIndex++) + for (unsigned int index : mState.mAtomicCounterUniformRange) { - const gl::LinkedUniform &uniform = mData.mUniforms[uniformIndex]; - - for (unsigned int arrayIndex = 0; arrayIndex < uniform.elementCount(); arrayIndex++) + auto &uniform = mState.mUniforms[index]; + bool found = false; + for (unsigned int bufferIndex = 0; bufferIndex < mState.mAtomicCounterBuffers.size(); + ++bufferIndex) { - if (!uniform.isBuiltIn()) + auto &buffer = mState.mAtomicCounterBuffers[bufferIndex]; + if (buffer.binding == uniform.binding) { - // Assign in-order uniform locations - mData.mUniformLocations.push_back(gl::VariableLocation( - uniform.name, arrayIndex, static_cast(uniformIndex))); + buffer.memberIndexes.push_back(index); + uniform.bufferIndex = bufferIndex; + found = true; + buffer.unionReferencesWith(uniform); + break; } } + if (!found) + { + AtomicCounterBuffer atomicCounterBuffer; + atomicCounterBuffer.binding = uniform.binding; + atomicCounterBuffer.memberIndexes.push_back(index); + atomicCounterBuffer.unionReferencesWith(uniform); + mState.mAtomicCounterBuffers.push_back(atomicCounterBuffer); + uniform.bufferIndex = static_cast(mState.mAtomicCounterBuffers.size() - 1); + } } + // TODO(jie.a.chen@intel.com): Count each atomic counter buffer to validate against + // gl_Max[Vertex|Fragment|Compute|Combined]AtomicCounterBuffers. + + return true; } -bool Program::linkValidateInterfaceBlockFields(InfoLog &infoLog, const std::string &uniformName, const sh::InterfaceBlockField &vertexUniform, const sh::InterfaceBlockField &fragmentUniform) +bool Program::linkValidateInterfaceBlockFields(InfoLog &infoLog, + const std::string &uniformName, + const sh::InterfaceBlockField &vertexUniform, + const sh::InterfaceBlockField &fragmentUniform, + bool webglCompatibility) { - // We don't validate precision on UBO fields. See resolution of Khronos bug 10287. - if (!linkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform, false)) + // If webgl, validate precision of UBO fields, otherwise don't. See Khronos bug 10287. + if (!linkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform, + webglCompatibility)) { return false; } @@ -1716,32 +2186,34 @@ bool Program::linkValidateInterfaceBlockFields(InfoLog &infoLog, const std::stri return true; } -// Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices -bool Program::linkAttributes(const gl::Data &data, - InfoLog &infoLog, - const AttributeBindings &attributeBindings, - const Shader *vertexShader) +// Assigns locations to all attributes from the bindings and program locations. +bool Program::linkAttributes(const Context *context, InfoLog &infoLog) { + const ContextState &data = context->getContextState(); + auto *vertexShader = mState.getAttachedVertexShader(); + unsigned int usedLocations = 0; - mData.mAttributes = vertexShader->getActiveAttributes(); - GLuint maxAttribs = data.caps->maxVertexAttributes; + mState.mAttributes = vertexShader->getActiveAttributes(context); + GLuint maxAttribs = data.getCaps().maxVertexAttributes; // TODO(jmadill): handle aliasing robustly - if (mData.mAttributes.size() > maxAttribs) + if (mState.mAttributes.size() > maxAttribs) { infoLog << "Too many vertex attributes."; return false; } - std::vector usedAttribMap(data.caps->maxVertexAttributes, nullptr); + std::vector usedAttribMap(maxAttribs, nullptr); // Link attributes that have a binding location - for (sh::Attribute &attribute : mData.mAttributes) + for (sh::Attribute &attribute : mState.mAttributes) { - // TODO(jmadill): do staticUse filtering step here, or not at all - ASSERT(attribute.staticUse); + // GLSL ES 3.10 January 2016 section 4.3.4: Vertex shader inputs can't be arrays or + // structures, so we don't need to worry about adjusting their names or generating entries + // for each member/element (unlike uniforms for example). + ASSERT(!attribute.isArray() && !attribute.isStruct()); - int bindingLocation = attributeBindings.getAttributeBinding(attribute.name); + int bindingLocation = mAttributeBindings.getBinding(attribute.name); if (attribute.location == -1 && bindingLocation != -1) { attribute.location = bindingLocation; @@ -1788,10 +2260,8 @@ bool Program::linkAttributes(const gl::Data &data, } // Link attributes that don't have a binding location - for (sh::Attribute &attribute : mData.mAttributes) + for (sh::Attribute &attribute : mState.mAttributes) { - ASSERT(attribute.staticUse); - // Not set by glBindAttribLocation or by location layout qualifier if (attribute.location == -1) { @@ -1808,82 +2278,150 @@ bool Program::linkAttributes(const gl::Data &data, } } - for (const sh::Attribute &attribute : mData.mAttributes) + for (const sh::Attribute &attribute : mState.mAttributes) { - ASSERT(attribute.staticUse); ASSERT(attribute.location != -1); - int regs = VariableRegisterCount(attribute.type); + unsigned int regs = static_cast(VariableRegisterCount(attribute.type)); - for (int r = 0; r < regs; r++) + for (unsigned int r = 0; r < regs; r++) { - mData.mActiveAttribLocationsMask.set(attribute.location + r); + unsigned int location = static_cast(attribute.location) + r; + mState.mActiveAttribLocationsMask.set(location); + mState.mMaxActiveAttribLocation = + std::max(mState.mMaxActiveAttribLocation, location + 1); } } return true; } -bool Program::linkUniformBlocks(InfoLog &infoLog, const Caps &caps) +bool Program::validateVertexAndFragmentInterfaceBlocks( + const std::vector &vertexInterfaceBlocks, + const std::vector &fragmentInterfaceBlocks, + InfoLog &infoLog, + bool webglCompatibility) const { - const Shader &vertexShader = *mData.mAttachedVertexShader; - const Shader &fragmentShader = *mData.mAttachedFragmentShader; - - 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; + typedef std::map InterfaceBlockMap; + InterfaceBlockMap linkedInterfaceBlocks; - GLuint vertexBlockCount = 0; for (const sh::InterfaceBlock &vertexInterfaceBlock : vertexInterfaceBlocks) { - linkedUniformBlocks[vertexInterfaceBlock.name] = &vertexInterfaceBlock; + linkedInterfaceBlocks[vertexInterfaceBlock.name] = &vertexInterfaceBlock; + } - // Note: shared and std140 layouts are always considered active - if (vertexInterfaceBlock.staticUse || vertexInterfaceBlock.layout != sh::BLOCKLAYOUT_PACKED) + for (const sh::InterfaceBlock &fragmentInterfaceBlock : fragmentInterfaceBlocks) + { + auto entry = linkedInterfaceBlocks.find(fragmentInterfaceBlock.name); + if (entry != linkedInterfaceBlocks.end()) { - if (++vertexBlockCount > caps.maxVertexUniformBlocks) + const sh::InterfaceBlock &vertexInterfaceBlock = *entry->second; + if (!areMatchingInterfaceBlocks(infoLog, vertexInterfaceBlock, fragmentInterfaceBlock, + webglCompatibility)) { - infoLog << "Vertex shader uniform block count exceed GL_MAX_VERTEX_UNIFORM_BLOCKS (" - << caps.maxVertexUniformBlocks << ")"; return false; } } + // TODO(jiajia.qin@intel.com): Add + // MAX_COMBINED_UNIFORM_BLOCKS/MAX_COMBINED_SHADER_STORAGE_BLOCKS validation. } + return true; +} - GLuint fragmentBlockCount = 0; - for (const sh::InterfaceBlock &fragmentInterfaceBlock : fragmentInterfaceBlocks) +bool Program::linkInterfaceBlocks(const Context *context, InfoLog &infoLog) +{ + const auto &caps = context->getCaps(); + + if (mState.mAttachedComputeShader) { - auto entry = linkedUniformBlocks.find(fragmentInterfaceBlock.name); - if (entry != linkedUniformBlocks.end()) + Shader &computeShader = *mState.mAttachedComputeShader; + const auto &computeUniformBlocks = computeShader.getUniformBlocks(context); + + if (!validateInterfaceBlocksCount( + caps.maxComputeUniformBlocks, computeUniformBlocks, + "Compute shader uniform block count exceeds GL_MAX_COMPUTE_UNIFORM_BLOCKS (", + infoLog)) { - const sh::InterfaceBlock &vertexInterfaceBlock = *entry->second; - if (!areMatchingInterfaceBlocks(infoLog, vertexInterfaceBlock, fragmentInterfaceBlock)) - { - return false; - } + return false; } - // Note: shared and std140 layouts are always considered active - if (fragmentInterfaceBlock.staticUse || - fragmentInterfaceBlock.layout != sh::BLOCKLAYOUT_PACKED) + const auto &computeShaderStorageBlocks = computeShader.getShaderStorageBlocks(context); + if (!validateInterfaceBlocksCount(caps.maxComputeShaderStorageBlocks, + computeShaderStorageBlocks, + "Compute shader shader storage block count exceeds " + "GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS (", + infoLog)) { - if (++fragmentBlockCount > caps.maxFragmentUniformBlocks) - { - infoLog - << "Fragment shader uniform block count exceed GL_MAX_FRAGMENT_UNIFORM_BLOCKS (" - << caps.maxFragmentUniformBlocks << ")"; - return false; - } + return false; } + return true; + } + + Shader &vertexShader = *mState.mAttachedVertexShader; + Shader &fragmentShader = *mState.mAttachedFragmentShader; + + const auto &vertexUniformBlocks = vertexShader.getUniformBlocks(context); + const auto &fragmentUniformBlocks = fragmentShader.getUniformBlocks(context); + + if (!validateInterfaceBlocksCount( + caps.maxVertexUniformBlocks, vertexUniformBlocks, + "Vertex shader uniform block count exceeds GL_MAX_VERTEX_UNIFORM_BLOCKS (", infoLog)) + { + return false; + } + if (!validateInterfaceBlocksCount( + caps.maxFragmentUniformBlocks, fragmentUniformBlocks, + "Fragment shader uniform block count exceeds GL_MAX_FRAGMENT_UNIFORM_BLOCKS (", + infoLog)) + { + + return false; } + bool webglCompatibility = context->getExtensions().webglCompatibility; + if (!validateVertexAndFragmentInterfaceBlocks(vertexUniformBlocks, fragmentUniformBlocks, + infoLog, webglCompatibility)) + { + return false; + } + + if (context->getClientVersion() >= Version(3, 1)) + { + const auto &vertexShaderStorageBlocks = vertexShader.getShaderStorageBlocks(context); + const auto &fragmentShaderStorageBlocks = fragmentShader.getShaderStorageBlocks(context); + + if (!validateInterfaceBlocksCount(caps.maxVertexShaderStorageBlocks, + vertexShaderStorageBlocks, + "Vertex shader shader storage block count exceeds " + "GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS (", + infoLog)) + { + return false; + } + if (!validateInterfaceBlocksCount(caps.maxFragmentShaderStorageBlocks, + fragmentShaderStorageBlocks, + "Fragment shader shader storage block count exceeds " + "GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS (", + infoLog)) + { + + return false; + } + + if (!validateVertexAndFragmentInterfaceBlocks(vertexShaderStorageBlocks, + fragmentShaderStorageBlocks, infoLog, + webglCompatibility)) + { + return false; + } + } return true; } -bool Program::areMatchingInterfaceBlocks(gl::InfoLog &infoLog, const sh::InterfaceBlock &vertexInterfaceBlock, - const sh::InterfaceBlock &fragmentInterfaceBlock) +bool Program::areMatchingInterfaceBlocks(InfoLog &infoLog, + const sh::InterfaceBlock &vertexInterfaceBlock, + const sh::InterfaceBlock &fragmentInterfaceBlock, + bool webglCompatibility) const { const char* blockName = vertexInterfaceBlock.name.c_str(); // validate blocks for the same member types @@ -1899,7 +2437,9 @@ bool Program::areMatchingInterfaceBlocks(gl::InfoLog &infoLog, const sh::Interfa << "' between vertex and fragment shaders"; return false; } - if (vertexInterfaceBlock.layout != fragmentInterfaceBlock.layout || vertexInterfaceBlock.isRowMajorLayout != fragmentInterfaceBlock.isRowMajorLayout) + if (vertexInterfaceBlock.layout != fragmentInterfaceBlock.layout || + vertexInterfaceBlock.isRowMajorLayout != fragmentInterfaceBlock.isRowMajorLayout || + vertexInterfaceBlock.binding != fragmentInterfaceBlock.binding) { infoLog << "Layout qualifiers differ for interface block '" << blockName << "' between vertex and fragment shaders"; @@ -1920,7 +2460,8 @@ bool Program::areMatchingInterfaceBlocks(gl::InfoLog &infoLog, const sh::Interfa return false; } std::string memberName = "interface block '" + vertexInterfaceBlock.name + "' member '" + vertexMember.name + "'"; - if (!linkValidateInterfaceBlockFields(infoLog, memberName, vertexMember, fragmentMember)) + if (!linkValidateInterfaceBlockFields(infoLog, memberName, vertexMember, fragmentMember, + webglCompatibility)) { return false; } @@ -1936,7 +2477,7 @@ bool Program::linkValidateVariablesBase(InfoLog &infoLog, const std::string &var infoLog << "Types for " << variableName << " differ between vertex and fragment shaders"; return false; } - if (vertexVariable.arraySize != fragmentVariable.arraySize) + if (vertexVariable.arraySizes != fragmentVariable.arraySizes) { infoLog << "Array sizes for " << variableName << " differ between vertex and fragment shaders"; return false; @@ -1946,6 +2487,12 @@ bool Program::linkValidateVariablesBase(InfoLog &infoLog, const std::string &var infoLog << "Precisions for " << variableName << " differ between vertex and fragment shaders"; return false; } + if (vertexVariable.structName != fragmentVariable.structName) + { + infoLog << "Structure names for " << variableName + << " differ between vertex and fragment shaders"; + return false; + } if (vertexVariable.fields.size() != fragmentVariable.fields.size()) { @@ -1979,52 +2526,125 @@ bool Program::linkValidateVariablesBase(InfoLog &infoLog, const std::string &var return true; } -bool Program::linkValidateUniforms(InfoLog &infoLog, const std::string &uniformName, const sh::Uniform &vertexUniform, const sh::Uniform &fragmentUniform) +bool Program::linkValidateVaryings(InfoLog &infoLog, + const std::string &varyingName, + const sh::Varying &vertexVarying, + const sh::Varying &fragmentVarying, + int shaderVersion) { -#if ANGLE_PROGRAM_LINK_VALIDATE_UNIFORM_PRECISION == ANGLE_ENABLED - const bool validatePrecision = true; -#else - const bool validatePrecision = false; -#endif + if (!linkValidateVariablesBase(infoLog, varyingName, vertexVarying, fragmentVarying, false)) + { + return false; + } - if (!linkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform, validatePrecision)) + if (!sh::InterpolationTypesMatch(vertexVarying.interpolation, fragmentVarying.interpolation)) { + infoLog << "Interpolation types for " << varyingName + << " differ between vertex and fragment shaders."; + return false; + } + + if (shaderVersion == 100 && vertexVarying.isInvariant != fragmentVarying.isInvariant) + { + infoLog << "Invariance for " << varyingName + << " differs between vertex and fragment shaders."; return false; } return true; } -bool Program::linkValidateVaryings(InfoLog &infoLog, const std::string &varyingName, const sh::Varying &vertexVarying, const sh::Varying &fragmentVarying) +bool Program::linkValidateBuiltInVaryings(const Context *context, InfoLog &infoLog) const { - if (!linkValidateVariablesBase(infoLog, varyingName, vertexVarying, fragmentVarying, false)) + Shader *vertexShader = mState.mAttachedVertexShader; + Shader *fragmentShader = mState.mAttachedFragmentShader; + const auto &vertexVaryings = vertexShader->getOutputVaryings(context); + const auto &fragmentVaryings = fragmentShader->getInputVaryings(context); + int shaderVersion = vertexShader->getShaderVersion(context); + + if (shaderVersion != 100) { - return false; + // Only ESSL 1.0 has restrictions on matching input and output invariance + return true; } - if (!sh::InterpolationTypesMatch(vertexVarying.interpolation, fragmentVarying.interpolation)) + bool glPositionIsInvariant = false; + bool glPointSizeIsInvariant = false; + bool glFragCoordIsInvariant = false; + bool glPointCoordIsInvariant = false; + + for (const sh::Varying &varying : vertexVaryings) + { + if (!varying.isBuiltIn()) + { + continue; + } + if (varying.name.compare("gl_Position") == 0) + { + glPositionIsInvariant = varying.isInvariant; + } + else if (varying.name.compare("gl_PointSize") == 0) + { + glPointSizeIsInvariant = varying.isInvariant; + } + } + + for (const sh::Varying &varying : fragmentVaryings) + { + if (!varying.isBuiltIn()) + { + continue; + } + if (varying.name.compare("gl_FragCoord") == 0) + { + glFragCoordIsInvariant = varying.isInvariant; + } + else if (varying.name.compare("gl_PointCoord") == 0) + { + glPointCoordIsInvariant = varying.isInvariant; + } + } + + // There is some ambiguity in ESSL 1.00.17 paragraph 4.6.4 interpretation, + // for example, https://cvs.khronos.org/bugzilla/show_bug.cgi?id=13842. + // Not requiring invariance to match is supported by: + // dEQP, WebGL CTS, Nexus 5X GLES + if (glFragCoordIsInvariant && !glPositionIsInvariant) + { + infoLog << "gl_FragCoord can only be declared invariant if and only if gl_Position is " + "declared invariant."; + return false; + } + if (glPointCoordIsInvariant && !glPointSizeIsInvariant) { - infoLog << "Interpolation types for " << varyingName << " differ between vertex and fragment shaders"; + infoLog << "gl_PointCoord can only be declared invariant if and only if gl_PointSize is " + "declared invariant."; return false; } return true; } -bool Program::linkValidateTransformFeedback(InfoLog &infoLog, - const std::vector &varyings, +bool Program::linkValidateTransformFeedback(const gl::Context *context, + InfoLog &infoLog, + const Program::MergedVaryings &varyings, const Caps &caps) const { size_t totalComponents = 0; std::set uniqueNames; - for (const std::string &tfVaryingName : mData.mTransformFeedbackVaryingNames) + for (const std::string &tfVaryingName : mState.mTransformFeedbackVaryingNames) { bool found = false; - for (const sh::Varying *varying : varyings) + std::vector subscripts; + std::string baseName = ParseResourceName(tfVaryingName, &subscripts); + + for (const auto &ref : varyings) { - if (tfVaryingName == varying->name) + const sh::Varying *varying = ref.second.get(); + + if (baseName == varying->name) { if (uniqueNames.count(tfVaryingName) > 0) { @@ -2032,17 +2652,33 @@ bool Program::linkValidateTransformFeedback(InfoLog &infoLog, << tfVaryingName << ")."; return false; } - uniqueNames.insert(tfVaryingName); - - if (varying->isArray()) + if (context->getClientVersion() >= Version(3, 1)) + { + if (IncludeSameArrayElement(uniqueNames, tfVaryingName)) + { + infoLog + << "Two transform feedback varyings include the same array element (" + << tfVaryingName << ")."; + return false; + } + } + else if (varying->isArray()) { infoLog << "Capture of arrays is undefined and not supported."; return false; } + uniqueNames.insert(tfVaryingName); + // TODO(jmadill): Investigate implementation limits on D3D11 - size_t componentCount = gl::VariableComponentCount(varying->type); - if (mData.mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS && + + // GLSL ES 3.10 section 4.3.6: A vertex output can't be an array of arrays. + ASSERT(!varying->isArrayOfArrays()); + size_t elementCount = + ((varying->isArray() && subscripts.empty()) ? varying->getOutermostArraySize() + : 1); + size_t componentCount = VariableComponentCount(varying->type) * elementCount; + if (mState.mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS && componentCount > caps.maxTransformFeedbackSeparateComponents) { infoLog << "Transform feedback varying's " << varying->name << " components (" @@ -2056,19 +2692,21 @@ bool Program::linkValidateTransformFeedback(InfoLog &infoLog, break; } } - - if (tfVaryingName.find('[') != std::string::npos) + if (context->getClientVersion() < Version(3, 1) && + tfVaryingName.find('[') != std::string::npos) { infoLog << "Capture of array elements is undefined and not supported."; return false; } - - // All transform feedback varyings are expected to exist since packVaryings checks for them. - ASSERT(found); - UNUSED_ASSERTION_VARIABLE(found); + if (!found) + { + infoLog << "Transform feedback varying " << tfVaryingName + << " does not exist in the vertex shader."; + return false; + } } - if (mData.mTransformFeedbackBufferMode == GL_INTERLEAVED_ATTRIBS && + if (mState.mTransformFeedbackBufferMode == GL_INTERLEAVED_ATTRIBS && totalComponents > caps.maxTransformFeedbackInterleavedComponents) { infoLog << "Transform feedback varying total components (" << totalComponents @@ -2080,454 +2718,349 @@ bool Program::linkValidateTransformFeedback(InfoLog &infoLog, return true; } -void Program::gatherTransformFeedbackVaryings(const std::vector &varyings) +bool Program::linkValidateGlobalNames(const Context *context, InfoLog &infoLog) const { - // Gather the linked varyings that are used for transform feedback, they should all exist. - mData.mTransformFeedbackVaryingVars.clear(); - for (const std::string &tfVaryingName : mData.mTransformFeedbackVaryingNames) + const std::vector &vertexUniforms = + mState.mAttachedVertexShader->getUniforms(context); + const std::vector &fragmentUniforms = + mState.mAttachedFragmentShader->getUniforms(context); + const std::vector &attributes = + mState.mAttachedVertexShader->getActiveAttributes(context); + for (const auto &attrib : attributes) { - for (const sh::Varying *varying : varyings) + for (const auto &uniform : vertexUniforms) { - if (tfVaryingName == varying->name) + if (uniform.name == attrib.name) { - mData.mTransformFeedbackVaryingVars.push_back(*varying); - break; + infoLog << "Name conflicts between a uniform and an attribute: " << attrib.name; + return false; + } + } + for (const auto &uniform : fragmentUniforms) + { + if (uniform.name == attrib.name) + { + infoLog << "Name conflicts between a uniform and an attribute: " << attrib.name; + return false; } } } + return true; } -std::vector Program::getMergedVaryings() const +void Program::gatherTransformFeedbackVaryings(const Program::MergedVaryings &varyings) { - std::set uniqueNames; - std::vector varyings; - - for (const sh::Varying &varying : mData.mAttachedVertexShader->getVaryings()) + // Gather the linked varyings that are used for transform feedback, they should all exist. + mState.mLinkedTransformFeedbackVaryings.clear(); + for (const std::string &tfVaryingName : mState.mTransformFeedbackVaryingNames) { - if (uniqueNames.count(varying.name) == 0) + std::vector subscripts; + std::string baseName = ParseResourceName(tfVaryingName, &subscripts); + size_t subscript = GL_INVALID_INDEX; + if (!subscripts.empty()) { - uniqueNames.insert(varying.name); - varyings.push_back(&varying); + subscript = subscripts.back(); } - } - - for (const sh::Varying &varying : mData.mAttachedFragmentShader->getVaryings()) - { - if (uniqueNames.count(varying.name) == 0) + for (const auto &ref : varyings) { - uniqueNames.insert(varying.name); - varyings.push_back(&varying); + const sh::Varying *varying = ref.second.get(); + if (baseName == varying->name) + { + mState.mLinkedTransformFeedbackVaryings.emplace_back( + *varying, static_cast(subscript)); + break; + } } } - - return varyings; } -void Program::linkOutputVariables() +Program::MergedVaryings Program::getMergedVaryings(const Context *context) const { - const Shader *fragmentShader = mData.mAttachedFragmentShader; - ASSERT(fragmentShader != nullptr); + MergedVaryings merged; - // Skip this step for GLES2 shaders. - if (fragmentShader->getShaderVersion() == 100) - return; - - const auto &shaderOutputVars = fragmentShader->getActiveOutputVariables(); - - // TODO(jmadill): any caps validation here? - - for (unsigned int outputVariableIndex = 0; outputVariableIndex < shaderOutputVars.size(); - outputVariableIndex++) + for (const sh::Varying &varying : mState.mAttachedVertexShader->getOutputVaryings(context)) { - const sh::OutputVariable &outputVariable = shaderOutputVars[outputVariableIndex]; - - // Don't store outputs for gl_FragDepth, gl_FragColor, etc. - if (outputVariable.isBuiltIn()) - continue; - - // Since multiple output locations must be specified, use 0 for non-specified locations. - int baseLocation = (outputVariable.location == -1 ? 0 : outputVariable.location); - - ASSERT(outputVariable.staticUse); - - for (unsigned int elementIndex = 0; elementIndex < outputVariable.elementCount(); - elementIndex++) - { - const int location = baseLocation + elementIndex; - ASSERT(mData.mOutputVariables.count(location) == 0); - unsigned int element = outputVariable.isArray() ? elementIndex : GL_INVALID_INDEX; - mData.mOutputVariables[location] = - VariableLocation(outputVariable.name, element, outputVariableIndex); - } + merged[varying.name].vertex = &varying; } -} - -bool Program::flattenUniformsAndCheckCaps(const Caps &caps, InfoLog &infoLog) -{ - const gl::Shader *vertexShader = mData.getAttachedVertexShader(); - VectorAndSamplerCount vsCounts; - - std::vector samplerUniforms; - for (const sh::Uniform &uniform : vertexShader->getUniforms()) + for (const sh::Varying &varying : mState.mAttachedFragmentShader->getInputVaryings(context)) { - if (uniform.staticUse) - { - vsCounts += flattenUniform(uniform, uniform.name, &samplerUniforms); - } + merged[varying.name].fragment = &varying; } - if (vsCounts.vectorCount > caps.maxVertexUniformVectors) - { - infoLog << "Vertex shader active uniforms exceed MAX_VERTEX_UNIFORM_VECTORS (" - << caps.maxVertexUniformVectors << ")."; - return false; - } + return merged; +} - if (vsCounts.samplerCount > caps.maxVertexTextureImageUnits) - { - infoLog << "Vertex shader sampler count exceeds MAX_VERTEX_TEXTURE_IMAGE_UNITS (" - << caps.maxVertexTextureImageUnits << ")."; - return false; - } - const gl::Shader *fragmentShader = mData.getAttachedFragmentShader(); - VectorAndSamplerCount fsCounts; +void Program::linkOutputVariables(const Context *context) +{ + Shader *fragmentShader = mState.mAttachedFragmentShader; + ASSERT(fragmentShader != nullptr); + + ASSERT(mState.mOutputVariableTypes.empty()); + ASSERT(mState.mActiveOutputVariables.none()); - for (const sh::Uniform &uniform : fragmentShader->getUniforms()) + // Gather output variable types + for (const auto &outputVariable : fragmentShader->getActiveOutputVariables(context)) { - if (uniform.staticUse) + if (outputVariable.isBuiltIn() && outputVariable.name != "gl_FragColor" && + outputVariable.name != "gl_FragData") { - fsCounts += flattenUniform(uniform, uniform.name, &samplerUniforms); + continue; } - } - - if (fsCounts.vectorCount > caps.maxFragmentUniformVectors) - { - infoLog << "Fragment shader active uniforms exceed MAX_FRAGMENT_UNIFORM_VECTORS (" - << caps.maxFragmentUniformVectors << ")."; - return false; - } - - if (fsCounts.samplerCount > caps.maxTextureImageUnits) - { - infoLog << "Fragment shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (" - << caps.maxTextureImageUnits << ")."; - return false; - } - - mSamplerUniformRange.start = static_cast(mData.mUniforms.size()); - mSamplerUniformRange.end = - mSamplerUniformRange.start + static_cast(samplerUniforms.size()); - - mData.mUniforms.insert(mData.mUniforms.end(), samplerUniforms.begin(), samplerUniforms.end()); - - return true; -} -Program::VectorAndSamplerCount Program::flattenUniform(const sh::ShaderVariable &uniform, - const std::string &fullName, - std::vector *samplerUniforms) -{ - VectorAndSamplerCount vectorAndSamplerCount; + unsigned int baseLocation = + (outputVariable.location == -1 ? 0u + : static_cast(outputVariable.location)); - if (uniform.isStruct()) - { - for (unsigned int elementIndex = 0; elementIndex < uniform.elementCount(); elementIndex++) + // GLSL ES 3.10 section 4.3.6: Output variables cannot be arrays of arrays or arrays of + // structures, so we may use getBasicTypeElementCount(). + unsigned int elementCount = outputVariable.getBasicTypeElementCount(); + for (unsigned int elementIndex = 0; elementIndex < elementCount; elementIndex++) { - const std::string &elementString = (uniform.isArray() ? ArrayString(elementIndex) : ""); - - for (size_t fieldIndex = 0; fieldIndex < uniform.fields.size(); fieldIndex++) + const unsigned int location = baseLocation + elementIndex; + if (location >= mState.mOutputVariableTypes.size()) { - const sh::ShaderVariable &field = uniform.fields[fieldIndex]; - const std::string &fieldFullName = (fullName + elementString + "." + field.name); - - vectorAndSamplerCount += flattenUniform(field, fieldFullName, samplerUniforms); + mState.mOutputVariableTypes.resize(location + 1, GL_NONE); } + ASSERT(location < mState.mActiveOutputVariables.size()); + mState.mActiveOutputVariables.set(location); + mState.mOutputVariableTypes[location] = VariableComponentType(outputVariable.type); } - - return vectorAndSamplerCount; } - // Not a struct - bool isSampler = IsSamplerType(uniform.type); - if (!UniformInList(mData.getUniforms(), fullName) && !UniformInList(*samplerUniforms, fullName)) + // Skip this step for GLES2 shaders. + if (fragmentShader->getShaderVersion(context) == 100) + return; + + mState.mOutputVariables = fragmentShader->getActiveOutputVariables(context); + // TODO(jmadill): any caps validation here? + + for (unsigned int outputVariableIndex = 0; outputVariableIndex < mState.mOutputVariables.size(); + outputVariableIndex++) { - gl::LinkedUniform linkedUniform(uniform.type, uniform.precision, fullName, - uniform.arraySize, -1, - sh::BlockMemberInfo::getDefaultBlockInfo()); - linkedUniform.staticUse = true; + const sh::OutputVariable &outputVariable = mState.mOutputVariables[outputVariableIndex]; - // Store sampler uniforms separately, so we'll append them to the end of the list. - if (isSampler) - { - samplerUniforms->push_back(linkedUniform); - } - else + if (outputVariable.isArray()) { - mData.mUniforms.push_back(linkedUniform); + // We're following the GLES 3.1 November 2016 spec section 7.3.1.1 Naming Active + // Resources and including [0] at the end of array variable names. + mState.mOutputVariables[outputVariableIndex].name += "[0]"; + mState.mOutputVariables[outputVariableIndex].mappedName += "[0]"; } - } - - unsigned int elementCount = uniform.elementCount(); - - // Samplers aren't "real" uniforms, so they don't count towards register usage. - // Likewise, don't count "real" uniforms towards sampler count. - vectorAndSamplerCount.vectorCount = - (isSampler ? 0 : (VariableRegisterCount(uniform.type) * elementCount)); - vectorAndSamplerCount.samplerCount = (isSampler ? elementCount : 0); - - return vectorAndSamplerCount; -} - -void Program::gatherInterfaceBlockInfo() -{ - std::set visitedList; - - const gl::Shader *vertexShader = mData.getAttachedVertexShader(); - - ASSERT(mData.mUniformBlocks.empty()); - for (const sh::InterfaceBlock &vertexBlock : vertexShader->getInterfaceBlocks()) - { - // Only 'packed' blocks are allowed to be considered inacive. - if (!vertexBlock.staticUse && vertexBlock.layout == sh::BLOCKLAYOUT_PACKED) - continue; - if (visitedList.count(vertexBlock.name) > 0) + // Don't store outputs for gl_FragDepth, gl_FragColor, etc. + if (outputVariable.isBuiltIn()) continue; - defineUniformBlock(vertexBlock, GL_VERTEX_SHADER); - visitedList.insert(vertexBlock.name); - } - - const gl::Shader *fragmentShader = mData.getAttachedFragmentShader(); - - for (const sh::InterfaceBlock &fragmentBlock : fragmentShader->getInterfaceBlocks()) - { - // Only 'packed' blocks are allowed to be considered inacive. - if (!fragmentBlock.staticUse && fragmentBlock.layout == sh::BLOCKLAYOUT_PACKED) - continue; + // Since multiple output locations must be specified, use 0 for non-specified locations. + unsigned int baseLocation = + (outputVariable.location == -1 ? 0u + : static_cast(outputVariable.location)); - if (visitedList.count(fragmentBlock.name) > 0) + // GLSL ES 3.10 section 4.3.6: Output variables cannot be arrays of arrays or arrays of + // structures, so we may use getBasicTypeElementCount(). + unsigned int elementCount = outputVariable.getBasicTypeElementCount(); + for (unsigned int elementIndex = 0; elementIndex < elementCount; elementIndex++) { - for (gl::UniformBlock &block : mData.mUniformBlocks) + const unsigned int location = baseLocation + elementIndex; + if (location >= mState.mOutputLocations.size()) { - if (block.name == fragmentBlock.name) - { - block.fragmentStaticUse = fragmentBlock.staticUse; - } + mState.mOutputLocations.resize(location + 1); + } + ASSERT(!mState.mOutputLocations.at(location).used()); + if (outputVariable.isArray()) + { + mState.mOutputLocations[location] = + VariableLocation(elementIndex, outputVariableIndex); + } + else + { + VariableLocation locationInfo; + locationInfo.index = outputVariableIndex; + mState.mOutputLocations[location] = locationInfo; } - - continue; } - - defineUniformBlock(fragmentBlock, GL_FRAGMENT_SHADER); - visitedList.insert(fragmentBlock.name); } } -template -void Program::defineUniformBlockMembers(const std::vector &fields, - const std::string &prefix, - int blockIndex) +void Program::setUniformValuesFromBindingQualifiers() { - for (const VarT &field : fields) + for (unsigned int samplerIndex : mState.mSamplerUniformRange) { - const std::string &fullName = (prefix.empty() ? field.name : prefix + "." + field.name); - - if (field.isStruct()) + const auto &samplerUniform = mState.mUniforms[samplerIndex]; + if (samplerUniform.binding != -1) { - for (unsigned int arrayElement = 0; arrayElement < field.elementCount(); arrayElement++) + GLint location = getUniformLocation(samplerUniform.name); + ASSERT(location != -1); + std::vector boundTextureUnits; + for (unsigned int elementIndex = 0; + elementIndex < samplerUniform.getBasicTypeElementCount(); ++elementIndex) { - const std::string uniformElementName = - fullName + (field.isArray() ? ArrayString(arrayElement) : ""); - defineUniformBlockMembers(field.fields, uniformElementName, blockIndex); + boundTextureUnits.push_back(samplerUniform.binding + elementIndex); } - } - else - { - // If getBlockMemberInfo returns false, the uniform is optimized out. - sh::BlockMemberInfo memberInfo; - if (!mProgram->getUniformBlockMemberInfo(fullName, &memberInfo)) - { - continue; - } - - LinkedUniform newUniform(field.type, field.precision, fullName, field.arraySize, - blockIndex, memberInfo); - - // Since block uniforms have no location, we don't need to store them in the uniform - // locations list. - mData.mUniforms.push_back(newUniform); + setUniform1iv(location, static_cast(boundTextureUnits.size()), + boundTextureUnits.data()); } } } -void Program::defineUniformBlock(const sh::InterfaceBlock &interfaceBlock, GLenum shaderType) +void Program::gatherAtomicCounterBuffers() { - int blockIndex = static_cast(mData.mUniformBlocks.size()); - size_t blockSize = 0; - - // Don't define this block at all if it's not active in the implementation. - if (!mProgram->getUniformBlockSize(interfaceBlock.name, &blockSize)) + for (unsigned int index : mState.mAtomicCounterUniformRange) { - return; + auto &uniform = mState.mUniforms[index]; + uniform.blockInfo.offset = uniform.offset; + uniform.blockInfo.arrayStride = (uniform.isArray() ? 4 : 0); + uniform.blockInfo.matrixStride = 0; + uniform.blockInfo.isRowMajorMatrix = false; } - // Track the first and last uniform index to determine the range of active uniforms in the - // block. - size_t firstBlockUniformIndex = mData.mUniforms.size(); - defineUniformBlockMembers(interfaceBlock.fields, interfaceBlock.fieldPrefix(), blockIndex); - size_t lastBlockUniformIndex = mData.mUniforms.size(); + // TODO(jie.a.chen@intel.com): Get the actual BUFFER_DATA_SIZE from backend for each buffer. +} - std::vector blockUniformIndexes; - for (size_t blockUniformIndex = firstBlockUniformIndex; - blockUniformIndex < lastBlockUniformIndex; ++blockUniformIndex) +void Program::initInterfaceBlockBindings() +{ + // Set initial bindings from shader. + for (unsigned int blockIndex = 0; blockIndex < mState.mUniformBlocks.size(); blockIndex++) { - blockUniformIndexes.push_back(static_cast(blockUniformIndex)); + InterfaceBlock &uniformBlock = mState.mUniformBlocks[blockIndex]; + bindUniformBlock(blockIndex, uniformBlock.binding); } +} - if (interfaceBlock.arraySize > 0) - { - for (unsigned int arrayElement = 0; arrayElement < interfaceBlock.arraySize; ++arrayElement) - { - UniformBlock block(interfaceBlock.name, true, arrayElement); - block.memberUniformIndexes = blockUniformIndexes; - - if (shaderType == GL_VERTEX_SHADER) - { - block.vertexStaticUse = interfaceBlock.staticUse; - } - else - { - ASSERT(shaderType == GL_FRAGMENT_SHADER); - block.fragmentStaticUse = interfaceBlock.staticUse; - } - - // TODO(jmadill): Determine if we can ever have an inactive array element block. - size_t blockElementSize = 0; - if (!mProgram->getUniformBlockSize(block.nameWithArrayIndex(), &blockElementSize)) - { - continue; - } +void Program::updateSamplerUniform(const VariableLocation &locationInfo, + GLsizei clampedCount, + const GLint *v) +{ + ASSERT(mState.isSamplerUniformIndex(locationInfo.index)); + GLuint samplerIndex = mState.getSamplerIndexFromUniformIndex(locationInfo.index); + std::vector *boundTextureUnits = + &mState.mSamplerBindings[samplerIndex].boundTextureUnits; - ASSERT(blockElementSize == blockSize); - block.dataSize = static_cast(blockElementSize); - mData.mUniformBlocks.push_back(block); - } - } - else - { - UniformBlock block(interfaceBlock.name, false, 0); - block.memberUniformIndexes = blockUniformIndexes; + std::copy(v, v + clampedCount, boundTextureUnits->begin() + locationInfo.arrayIndex); - if (shaderType == GL_VERTEX_SHADER) - { - block.vertexStaticUse = interfaceBlock.staticUse; - } - else - { - ASSERT(shaderType == GL_FRAGMENT_SHADER); - block.fragmentStaticUse = interfaceBlock.staticUse; - } - - block.dataSize = static_cast(blockSize); - mData.mUniformBlocks.push_back(block); - } + // Invalidate the validation cache. + mCachedValidateSamplersResult.reset(); } template -void Program::setUniformInternal(GLint location, GLsizei count, const T *v) +GLsizei Program::clampUniformCount(const VariableLocation &locationInfo, + GLsizei count, + int vectorSize, + const T *v) { - const VariableLocation &locationInfo = mData.mUniformLocations[location]; - LinkedUniform *linkedUniform = &mData.mUniforms[locationInfo.index]; - uint8_t *destPointer = linkedUniform->getDataPtrToElement(locationInfo.element); + if (count == 1) + return 1; + + const LinkedUniform &linkedUniform = mState.mUniforms[locationInfo.index]; + + // OpenGL ES 3.0.4 spec pg 67: "Values for any array element that exceeds the highest array + // element index used, as reported by GetActiveUniform, will be ignored by the GL." + unsigned int remainingElements = + linkedUniform.getBasicTypeElementCount() - locationInfo.arrayIndex; + GLsizei maxElementCount = + static_cast(remainingElements * linkedUniform.getElementComponents()); - if (VariableComponentType(linkedUniform->type) == GL_BOOL) + if (count * vectorSize > maxElementCount) { - // Do a cast conversion for boolean types. From the spec: - // "The uniform is set to FALSE if the input value is 0 or 0.0f, and set to TRUE otherwise." - GLint *destAsInt = reinterpret_cast(destPointer); - for (GLsizei component = 0; component < count; ++component) - { - destAsInt[component] = (v[component] != static_cast(0) ? GL_TRUE : GL_FALSE); - } + return maxElementCount / vectorSize; } - else - { - // Invalide the validation cache if we modify the sampler data. - if (linkedUniform->isSampler() && memcmp(destPointer, v, sizeof(T) * count) != 0) - { - mCachedValidateSamplersResult.reset(); - } - memcpy(destPointer, v, sizeof(T) * count); - } + return count; } template -void Program::setMatrixUniformInternal(GLint location, - GLsizei count, - GLboolean transpose, - const T *v) +GLsizei Program::clampMatrixUniformCount(GLint location, + GLsizei count, + GLboolean transpose, + const T *v) { + const VariableLocation &locationInfo = mState.mUniformLocations[location]; + if (!transpose) { - setUniformInternal(location, count * cols * rows, v); - return; + return clampUniformCount(locationInfo, count, cols * rows, v); } - // Perform a transposing copy. - const VariableLocation &locationInfo = mData.mUniformLocations[location]; - LinkedUniform *linkedUniform = &mData.mUniforms[locationInfo.index]; - T *destPtr = reinterpret_cast(linkedUniform->getDataPtrToElement(locationInfo.element)); - for (GLsizei element = 0; element < count; ++element) - { - size_t elementOffset = element * rows * cols; + const LinkedUniform &linkedUniform = mState.mUniforms[locationInfo.index]; - for (size_t row = 0; row < rows; ++row) - { - for (size_t col = 0; col < cols; ++col) - { - destPtr[col * rows + row + elementOffset] = v[row * cols + col + elementOffset]; - } - } - } + // OpenGL ES 3.0.4 spec pg 67: "Values for any array element that exceeds the highest array + // element index used, as reported by GetActiveUniform, will be ignored by the GL." + unsigned int remainingElements = + linkedUniform.getBasicTypeElementCount() - locationInfo.arrayIndex; + return std::min(count, static_cast(remainingElements)); } +// Driver differences mean that doing the uniform value cast ourselves gives consistent results. +// EG: on NVIDIA drivers, it was observed that getUniformi for MAX_INT+1 returned MIN_INT. template -void Program::getUniformInternal(GLint location, DestT *dataOut) const +void Program::getUniformInternal(const Context *context, + DestT *dataOut, + GLint location, + GLenum nativeType, + int components) const { - const VariableLocation &locationInfo = mData.mUniformLocations[location]; - const LinkedUniform &uniform = mData.mUniforms[locationInfo.index]; - - const uint8_t *srcPointer = uniform.getDataPtrToElement(locationInfo.element); - - GLenum componentType = VariableComponentType(uniform.type); - if (componentType == GLTypeToGLenum::value) - { - memcpy(dataOut, srcPointer, uniform.getElementSize()); - return; - } - - int components = VariableComponentCount(uniform.type); - - switch (componentType) + switch (nativeType) { + case GL_BOOL: + { + GLint tempValue[16] = {0}; + mProgram->getUniformiv(context, location, tempValue); + UniformStateQueryCastLoop( + dataOut, reinterpret_cast(tempValue), components); + break; + } case GL_INT: - UniformStateQueryCastLoop(dataOut, srcPointer, components); + { + GLint tempValue[16] = {0}; + mProgram->getUniformiv(context, location, tempValue); + UniformStateQueryCastLoop(dataOut, reinterpret_cast(tempValue), + components); break; + } case GL_UNSIGNED_INT: - UniformStateQueryCastLoop(dataOut, srcPointer, components); - break; - case GL_BOOL: - UniformStateQueryCastLoop(dataOut, srcPointer, components); + { + GLuint tempValue[16] = {0}; + mProgram->getUniformuiv(context, location, tempValue); + UniformStateQueryCastLoop(dataOut, reinterpret_cast(tempValue), + components); break; + } case GL_FLOAT: - UniformStateQueryCastLoop(dataOut, srcPointer, components); + { + GLfloat tempValue[16] = {0}; + mProgram->getUniformfv(context, location, tempValue); + UniformStateQueryCastLoop( + dataOut, reinterpret_cast(tempValue), components); break; + } default: UNREACHABLE(); + break; } } + +bool Program::samplesFromTexture(const gl::State &state, GLuint textureID) const +{ + // Must be called after samplers are validated. + ASSERT(mCachedValidateSamplersResult.valid() && mCachedValidateSamplersResult.value()); + + for (const auto &binding : mState.mSamplerBindings) + { + GLenum textureType = binding.textureType; + for (const auto &unit : binding.boundTextureUnits) + { + GLenum programTextureID = state.getSamplerTextureId(unit, textureType); + if (programTextureID == textureID) + { + // TODO(jmadill): Check for appropriate overlap. + return true; + } + } + } + + return false; } + +} // namespace gl diff --git a/src/3rdparty/angle/src/libANGLE/Program.h b/src/3rdparty/angle/src/libANGLE/Program.h index f885ad1694..c242d84671 100644 --- a/src/3rdparty/angle/src/libANGLE/Program.h +++ b/src/3rdparty/angle/src/libANGLE/Program.h @@ -11,8 +11,10 @@ #define LIBANGLE_PROGRAM_H_ #include -#include +#include +#include +#include #include #include #include @@ -22,15 +24,16 @@ #include "common/mathutil.h" #include "common/Optional.h" -#include "libANGLE/angletypes.h" #include "libANGLE/Constants.h" #include "libANGLE/Debug.h" #include "libANGLE/Error.h" #include "libANGLE/RefCountObject.h" +#include "libANGLE/Uniform.h" +#include "libANGLE/angletypes.h" namespace rx { -class ImplFactory; +class GLImplFactory; class ProgramImpl; struct TranslatedAttribute; } @@ -38,31 +41,17 @@ struct TranslatedAttribute; namespace gl { struct Caps; -struct Data; -class ResourceManager; +class Context; +class ContextState; class Shader; +class ShaderProgramManager; +class State; 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: @@ -122,134 +111,330 @@ class InfoLog : angle::NonCopyable template StreamHelper operator<<(const T &value) { - StreamHelper helper(&mStream); + ensureInitialized(); + StreamHelper helper(mLazyStream.get()); helper << value; return helper; } - std::string str() const { return mStream.str(); } + std::string str() const { return mLazyStream ? mLazyStream->str() : ""; } private: - std::stringstream mStream; + void ensureInitialized() + { + if (!mLazyStream) + { + mLazyStream.reset(new std::stringstream()); + } + } + + std::unique_ptr mLazyStream; }; // Struct used for correlating uniforms/elements of uniform arrays to handles struct VariableLocation { + static constexpr unsigned int kUnused = GL_INVALID_INDEX; + VariableLocation(); - VariableLocation(const std::string &name, unsigned int element, unsigned int index); + VariableLocation(unsigned int arrayIndex, unsigned int index); + + // If used is false, it means this location is only used to fill an empty space in an array, + // and there is no corresponding uniform variable for this location. It can also mean the + // uniform was optimized out by the implementation. + bool used() const { return (index != kUnused); } + void markUnused() { index = kUnused; } + void markIgnored() { ignored = true; } + + // "arrayIndex" stores the index of the innermost GLSL array. It's zero for non-arrays. + unsigned int arrayIndex; + // "index" is an index of the variable. The variable contains the indices for other than the + // innermost GLSL arrays. + unsigned int index; + + // If this location was bound to an unreferenced uniform. Setting data on this uniform is a + // no-op. + bool ignored; +}; +// Information about a variable binding. +// Currently used by CHROMIUM_path_rendering +struct BindingInfo +{ + // The type of binding, for example GL_FLOAT_VEC3. + // This can be GL_NONE if the variable is optimized away. + GLenum type; + + // This is the name of the variable in + // the translated shader program. Note that + // this can be empty in the case where the + // variable has been optimized away. std::string name; - unsigned int element; - unsigned int index; + + // True if the binding is valid, otherwise false. + bool valid; }; -class Program final : angle::NonCopyable, public LabeledObject +// This small structure encapsulates binding sampler uniforms to active GL textures. +struct SamplerBinding { - public: - class Data final : angle::NonCopyable - { - public: - Data(); - ~Data(); + SamplerBinding(GLenum textureTypeIn, size_t elementCount, bool unreferenced); + SamplerBinding(const SamplerBinding &other); + ~SamplerBinding(); - const std::string &getLabel(); + // Necessary for retrieving active textures from the GL state. + GLenum textureType; - const Shader *getAttachedVertexShader() const { return mAttachedVertexShader; } - const Shader *getAttachedFragmentShader() const { return mAttachedFragmentShader; } - const std::vector &getTransformFeedbackVaryingNames() const - { - return mTransformFeedbackVaryingNames; - } - GLint getTransformFeedbackBufferMode() const { return mTransformFeedbackBufferMode; } - GLuint getUniformBlockBinding(GLuint uniformBlockIndex) const - { - ASSERT(uniformBlockIndex < IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS); - return mUniformBlockBindings[uniformBlockIndex]; - } - const UniformBlockBindingMask &getActiveUniformBlockBindingsMask() const - { - return mActiveUniformBlockBindings; - } - const std::vector &getAttributes() const { return mAttributes; } - const AttributesMask &getActiveAttribLocationsMask() const - { - return mActiveAttribLocationsMask; - } - const std::map &getOutputVariables() const - { - return mOutputVariables; - } - const std::vector &getUniforms() const { return mUniforms; } - const std::vector &getUniformLocations() const + // List of all textures bound to this sampler, of type textureType. + std::vector boundTextureUnits; + + // A note if this sampler is an unreferenced uniform. + bool unreferenced; +}; + +// A varying with tranform feedback enabled. If it's an array, either the whole array or one of its +// elements specified by 'arrayIndex' can set to be enabled. +struct TransformFeedbackVarying : public sh::Varying +{ + TransformFeedbackVarying(const sh::Varying &varyingIn, GLuint index) + : sh::Varying(varyingIn), arrayIndex(index) + { + ASSERT(!isArrayOfArrays()); + } + std::string nameWithArrayIndex() const + { + std::stringstream fullNameStr; + fullNameStr << name; + if (arrayIndex != GL_INVALID_INDEX) { - return mUniformLocations; + fullNameStr << "[" << arrayIndex << "]"; } - const std::vector &getUniformBlocks() const { return mUniformBlocks; } + return fullNameStr.str(); + } + GLsizei size() const + { + return (isArray() && arrayIndex == GL_INVALID_INDEX ? getOutermostArraySize() : 1); + } - const LinkedUniform *getUniformByName(const std::string &name) const; - GLint getUniformLocation(const std::string &name) const; - GLuint getUniformIndex(const std::string &name) const; + GLuint arrayIndex; +}; - private: - friend class Program; +struct ImageBinding +{ + ImageBinding(size_t count); + ImageBinding(GLuint imageUnit, size_t count); + ImageBinding(const ImageBinding &other); + ~ImageBinding(); + + std::vector boundImageUnits; +}; + +using ShaderStagesMask = angle::BitSet; + +class ProgramState final : angle::NonCopyable +{ + public: + ProgramState(); + ~ProgramState(); + + const std::string &getLabel(); + + Shader *getAttachedVertexShader() const { return mAttachedVertexShader; } + Shader *getAttachedFragmentShader() const { return mAttachedFragmentShader; } + Shader *getAttachedComputeShader() const { return mAttachedComputeShader; } + Shader *getAttachedGeometryShader() const { return mAttachedGeometryShader; } + const std::vector &getTransformFeedbackVaryingNames() const + { + return mTransformFeedbackVaryingNames; + } + GLint getTransformFeedbackBufferMode() const { return mTransformFeedbackBufferMode; } + GLuint getUniformBlockBinding(GLuint uniformBlockIndex) const + { + ASSERT(uniformBlockIndex < mUniformBlocks.size()); + return mUniformBlocks[uniformBlockIndex].binding; + } + GLuint getShaderStorageBlockBinding(GLuint blockIndex) const + { + ASSERT(blockIndex < mShaderStorageBlocks.size()); + return mShaderStorageBlocks[blockIndex].binding; + } + const UniformBlockBindingMask &getActiveUniformBlockBindingsMask() const + { + return mActiveUniformBlockBindings; + } + const std::vector &getAttributes() const { return mAttributes; } + const AttributesMask &getActiveAttribLocationsMask() const + { + return mActiveAttribLocationsMask; + } + unsigned int getMaxActiveAttribLocation() const { return mMaxActiveAttribLocation; } + DrawBufferMask getActiveOutputVariables() const { return mActiveOutputVariables; } + const std::vector &getOutputVariables() const { return mOutputVariables; } + const std::vector &getOutputLocations() const { return mOutputLocations; } + const std::vector &getUniforms() const { return mUniforms; } + const std::vector &getUniformLocations() const { return mUniformLocations; } + const std::vector &getUniformBlocks() const { return mUniformBlocks; } + const std::vector &getShaderStorageBlocks() const + { + return mShaderStorageBlocks; + } + const std::vector &getBufferVariables() const { return mBufferVariables; } + const std::vector &getSamplerBindings() const { return mSamplerBindings; } + const std::vector &getImageBindings() const { return mImageBindings; } + const sh::WorkGroupSize &getComputeShaderLocalSize() const { return mComputeShaderLocalSize; } + const RangeUI &getSamplerUniformRange() const { return mSamplerUniformRange; } + const RangeUI &getImageUniformRange() const { return mImageUniformRange; } + const RangeUI &getAtomicCounterUniformRange() const { return mAtomicCounterUniformRange; } + + const std::vector &getLinkedTransformFeedbackVaryings() const + { + return mLinkedTransformFeedbackVaryings; + } + const std::vector &getAtomicCounterBuffers() const + { + return mAtomicCounterBuffers; + } - std::string mLabel; + GLuint getUniformIndexFromName(const std::string &name) const; + GLuint getUniformIndexFromLocation(GLint location) const; + Optional getSamplerIndex(GLint location) const; + bool isSamplerUniformIndex(GLuint index) const; + GLuint getSamplerIndexFromUniformIndex(GLuint uniformIndex) const; + GLuint getAttributeLocation(const std::string &name) const; - Shader *mAttachedFragmentShader; - Shader *mAttachedVertexShader; + GLuint getBufferVariableIndexFromName(const std::string &name) const; - std::vector mTransformFeedbackVaryingNames; - std::vector mTransformFeedbackVaryingVars; - GLenum mTransformFeedbackBufferMode; + int getNumViews() const { return mNumViews; } + bool usesMultiview() const { return mNumViews != -1; } - GLuint mUniformBlockBindings[IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS]; - UniformBlockBindingMask mActiveUniformBlockBindings; + const ShaderStagesMask &getLinkedShaderStages() const { return mLinkedShaderStages; } - std::vector mAttributes; - std::bitset mActiveAttribLocationsMask; + private: + friend class MemoryProgramCache; + friend class Program; + + std::string mLabel; + + sh::WorkGroupSize mComputeShaderLocalSize; + + Shader *mAttachedFragmentShader; + Shader *mAttachedVertexShader; + Shader *mAttachedComputeShader; + Shader *mAttachedGeometryShader; + + std::vector mTransformFeedbackVaryingNames; + std::vector mLinkedTransformFeedbackVaryings; + GLenum mTransformFeedbackBufferMode; + + // For faster iteration on the blocks currently being bound. + UniformBlockBindingMask mActiveUniformBlockBindings; + + std::vector mAttributes; + angle::BitSet mActiveAttribLocationsMask; + unsigned int mMaxActiveAttribLocation; + + // Uniforms are sorted in order: + // 1. Non-opaque uniforms + // 2. Sampler uniforms + // 3. Image uniforms + // 4. Atomic counter uniforms + // 5. Uniform block uniforms + // This makes opaque uniform validation easier, since we don't need a separate list. + // For generating the entries and naming them we follow the spec: GLES 3.1 November 2016 section + // 7.3.1.1 Naming Active Resources. There's a separate entry for each struct member and each + // inner array of an array of arrays. Names and mapped names of uniforms that are arrays include + // [0] in the end. This makes implementation of queries simpler. + std::vector mUniforms; + + std::vector mUniformLocations; + std::vector mUniformBlocks; + std::vector mBufferVariables; + std::vector mShaderStorageBlocks; + std::vector mAtomicCounterBuffers; + RangeUI mSamplerUniformRange; + RangeUI mImageUniformRange; + RangeUI mAtomicCounterUniformRange; - // Uniforms are sorted in order: - // 1. Non-sampler uniforms - // 2. Sampler uniforms - // 3. Uniform block uniforms - // This makes sampler validation easier, since we don't need a separate list. - std::vector mUniforms; - std::vector mUniformLocations; - std::vector mUniformBlocks; + // An array of the samplers that are used by the program + std::vector mSamplerBindings; - // TODO(jmadill): use unordered/hash map when available - std::map mOutputVariables; + // An array of the images that are used by the program + std::vector mImageBindings; - bool mBinaryRetrieveableHint; - }; + // Names and mapped names of output variables that are arrays include [0] in the end, similarly + // to uniforms. + std::vector mOutputVariables; + std::vector mOutputLocations; + DrawBufferMask mActiveOutputVariables; - Program(rx::ImplFactory *factory, ResourceManager *manager, GLuint handle); - ~Program(); + // Fragment output variable base types: FLOAT, INT, or UINT. Ordered by location. + std::vector mOutputVariableTypes; + + bool mBinaryRetrieveableHint; + bool mSeparable; + ShaderStagesMask mLinkedShaderStages; + + // ANGLE_multiview. + int mNumViews; +}; + +class Program final : angle::NonCopyable, public LabeledObject +{ + public: + Program(rx::GLImplFactory *factory, ShaderProgramManager *manager, GLuint handle); + void onDestroy(const Context *context); GLuint id() const { return mHandle; } void setLabel(const std::string &label) override; const std::string &getLabel() const override; - rx::ProgramImpl *getImplementation() { return mProgram; } - const rx::ProgramImpl *getImplementation() const { return mProgram; } + rx::ProgramImpl *getImplementation() const { return mProgram; } - bool attachShader(Shader *shader); - bool detachShader(Shader *shader); + void attachShader(Shader *shader); + void detachShader(const Context *context, Shader *shader); int getAttachedShadersCount() const; - void bindAttributeLocation(GLuint index, const char *name); + const Shader *getAttachedVertexShader() const { return mState.mAttachedVertexShader; } + const Shader *getAttachedFragmentShader() const { return mState.mAttachedFragmentShader; } + const Shader *getAttachedComputeShader() const { return mState.mAttachedComputeShader; } + const Shader *getAttachedGeometryShader() const { return mState.mAttachedGeometryShader; } - Error link(const gl::Data &data); + void bindAttributeLocation(GLuint index, const char *name); + void bindUniformLocation(GLuint index, const char *name); + + // CHROMIUM_path_rendering + BindingInfo getFragmentInputBindingInfo(const Context *context, GLint index) const; + void bindFragmentInputLocation(GLint index, const char *name); + void pathFragmentInputGen(const Context *context, + GLint index, + GLenum genMode, + GLint components, + const GLfloat *coeffs); + + Error link(const gl::Context *context); bool isLinked() const; - Error loadBinary(GLenum binaryFormat, const void *binary, GLsizei length); - Error saveBinary(GLenum *binaryFormat, void *binary, GLsizei bufSize, GLsizei *length) const; - GLint getBinaryLength() const; + bool hasLinkedVertexShader() const { return mState.mLinkedShaderStages[SHADER_VERTEX]; } + bool hasLinkedFragmentShader() const { return mState.mLinkedShaderStages[SHADER_FRAGMENT]; } + bool hasLinkedComputeShader() const { return mState.mLinkedShaderStages[SHADER_COMPUTE]; } + + Error loadBinary(const Context *context, + GLenum binaryFormat, + const void *binary, + GLsizei length); + Error saveBinary(const Context *context, + GLenum *binaryFormat, + void *binary, + GLsizei bufSize, + GLsizei *length) const; + GLint getBinaryLength(const Context *context) const; void setBinaryRetrievableHint(bool retrievable); bool getBinaryRetrievableHint() const; + void setSeparable(bool separable); + bool isSeparable() const; + int getInfoLogLength() const; void getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog) const; void getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders) const; @@ -257,12 +442,23 @@ class Program final : angle::NonCopyable, public LabeledObject GLuint getAttributeLocation(const std::string &name) const; bool isAttribLocationActive(size_t attribLocation) const; - void getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); + void getActiveAttribute(GLuint index, + GLsizei bufsize, + GLsizei *length, + GLint *size, + GLenum *type, + GLchar *name) const; GLint getActiveAttributeCount() const; GLint getActiveAttributeMaxLength() const; - const std::vector &getAttributes() const { return mData.mAttributes; } + const std::vector &getAttributes() const { return mState.mAttributes; } GLint getFragDataLocation(const std::string &name) const; + size_t getOutputResourceCount() const; + const std::vector &getOutputVariableTypes() const + { + return mState.mOutputVariableTypes; + } + DrawBufferMask getActiveOutputVariables() const { return mState.mActiveOutputVariables; } void getActiveUniform(GLuint index, GLsizei bufsize, @@ -271,10 +467,21 @@ class Program final : angle::NonCopyable, public LabeledObject GLenum *type, GLchar *name) const; GLint getActiveUniformCount() const; + size_t getActiveBufferVariableCount() const; GLint getActiveUniformMaxLength() const; - GLint getActiveUniformi(GLuint index, GLenum pname) const; bool isValidUniformLocation(GLint location) const; const LinkedUniform &getUniformByLocation(GLint location) const; + const VariableLocation &getUniformLocation(GLint location) const; + const std::vector &getUniformLocations() const; + const LinkedUniform &getUniformByIndex(GLuint index) const; + + const BufferVariable &getBufferVariableByIndex(GLuint index) const; + + enum SetUniformResult + { + SamplerChanged, + NoSamplerChange, + }; GLint getUniformLocation(const std::string &name) const; GLuint getUniformIndex(const std::string &name) const; @@ -282,7 +489,7 @@ class Program final : angle::NonCopyable, public LabeledObject 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); + SetUniformResult 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); @@ -300,21 +507,32 @@ class Program final : angle::NonCopyable, public LabeledObject 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) const; - void getUniformiv(GLint location, GLint *params) const; - void getUniformuiv(GLint location, GLuint *params) const; - - void getActiveUniformBlockName(GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName) const; - void getActiveUniformBlockiv(GLuint uniformBlockIndex, GLenum pname, GLint *params) const; + void getUniformfv(const Context *context, GLint location, GLfloat *params) const; + void getUniformiv(const Context *context, GLint location, GLint *params) const; + void getUniformuiv(const Context *context, GLint location, GLuint *params) const; + + void getActiveUniformBlockName(const GLuint blockIndex, + GLsizei bufSize, + GLsizei *length, + GLchar *blockName) const; + void getActiveShaderStorageBlockName(const GLuint blockIndex, + GLsizei bufSize, + GLsizei *length, + GLchar *blockName) const; GLuint getActiveUniformBlockCount() const; + GLuint getActiveAtomicCounterBufferCount() const; + GLuint getActiveShaderStorageBlockCount() const; GLint getActiveUniformBlockMaxLength() const; GLuint getUniformBlockIndex(const std::string &name) const; + GLuint getShaderStorageBlockIndex(const std::string &name) const; void bindUniformBlock(GLuint uniformBlockIndex, GLuint uniformBlockBinding); GLuint getUniformBlockBinding(GLuint uniformBlockIndex) const; + GLuint getShaderStorageBlockBinding(GLuint shaderStorageBlockIndex) const; - const UniformBlock &getUniformBlockByIndex(GLuint index) const; + const InterfaceBlock &getUniformBlockByIndex(GLuint index) const; + const InterfaceBlock &getShaderStorageBlockByIndex(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; @@ -322,11 +540,14 @@ class Program final : angle::NonCopyable, public LabeledObject GLsizei getTransformFeedbackVaryingMaxLength() const; GLenum getTransformFeedbackBufferMode() const; - 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); + static bool linkValidateInterfaceBlockFields(InfoLog &infoLog, + const std::string &uniformName, + const sh::InterfaceBlockField &vertexUniform, + const sh::InterfaceBlockField &fragmentUniform, + bool webglCompatibility); void addRef(); - void release(); + void release(const Context *context); unsigned int getRefCount() const; void flagForDeletion(); bool isFlaggedForDeletion() const; @@ -334,28 +555,25 @@ class Program final : angle::NonCopyable, public LabeledObject void validate(const Caps &caps); bool validateSamplers(InfoLog *infoLog, const Caps &caps); bool isValidated() const; + bool samplesFromTexture(const gl::State &state, GLuint textureID) const; const AttributesMask &getActiveAttribLocationsMask() const { - return mData.mActiveAttribLocationsMask; + return mState.mActiveAttribLocationsMask; } - private: - void unlink(bool destroy = false); - void resetUniformBlockBindings(); - - bool linkAttributes(const gl::Data &data, - InfoLog &infoLog, - const AttributeBindings &attributeBindings, - const Shader *vertexShader); - bool linkUniformBlocks(InfoLog &infoLog, const Caps &caps); - static bool linkVaryings(InfoLog &infoLog, - const Shader *vertexShader, - const Shader *fragmentShader); - bool linkUniforms(gl::InfoLog &infoLog, const gl::Caps &caps); - void indexUniforms(); - bool areMatchingInterfaceBlocks(gl::InfoLog &infoLog, const sh::InterfaceBlock &vertexInterfaceBlock, - const sh::InterfaceBlock &fragmentInterfaceBlock); + const std::vector &getSamplerBindings() const + { + return mState.mSamplerBindings; + } + + const std::vector &getImageBindings() const { return mState.mImageBindings; } + const sh::WorkGroupSize &getComputeShaderLocalSize() const + { + return mState.mComputeShaderLocalSize; + } + + const ProgramState &getState() const { return mState; } static bool linkValidateVariablesBase(InfoLog &infoLog, const std::string &variableName, @@ -363,71 +581,147 @@ class Program final : angle::NonCopyable, public LabeledObject const sh::ShaderVariable &fragmentVariable, bool validatePrecision); - static bool linkValidateVaryings(InfoLog &infoLog, const std::string &varyingName, const sh::Varying &vertexVarying, const sh::Varying &fragmentVarying); - bool linkValidateTransformFeedback(InfoLog &infoLog, - const std::vector &linkedVaryings, - const Caps &caps) const; + GLuint getInputResourceIndex(const GLchar *name) const; + GLuint getOutputResourceIndex(const GLchar *name) const; + void getInputResourceName(GLuint index, GLsizei bufSize, GLsizei *length, GLchar *name) const; + void getOutputResourceName(GLuint index, GLsizei bufSize, GLsizei *length, GLchar *name) const; + void getUniformResourceName(GLuint index, GLsizei bufSize, GLsizei *length, GLchar *name) const; + void getBufferVariableResourceName(GLuint index, + GLsizei bufSize, + GLsizei *length, + GLchar *name) const; + const sh::Attribute &getInputResource(GLuint index) const; + const sh::OutputVariable &getOutputResource(GLuint index) const; + + class Bindings final : angle::NonCopyable + { + public: + Bindings(); + ~Bindings(); + void bindLocation(GLuint index, const std::string &name); + int getBinding(const std::string &name) const; - void gatherTransformFeedbackVaryings(const std::vector &varyings); - bool assignUniformBlockRegister(InfoLog &infoLog, UniformBlock *uniformBlock, GLenum shader, unsigned int registerIndex, const Caps &caps); - void defineOutputVariables(Shader *fragmentShader); + typedef std::unordered_map::const_iterator const_iterator; + const_iterator begin() const; + const_iterator end() const; - std::vector getMergedVaryings() const; - void linkOutputVariables(); + private: + std::unordered_map mBindings; + }; - bool flattenUniformsAndCheckCaps(const Caps &caps, InfoLog &infoLog); + const Bindings &getAttributeBindings() const { return mAttributeBindings; } + const Bindings &getUniformLocationBindings() const { return mUniformLocationBindings; } + const Bindings &getFragmentInputBindings() const { return mFragmentInputBindings; } - struct VectorAndSamplerCount - { - VectorAndSamplerCount() : vectorCount(0), samplerCount(0) {} - VectorAndSamplerCount(const VectorAndSamplerCount &other) = default; - VectorAndSamplerCount &operator=(const VectorAndSamplerCount &other) = default; + int getNumViews() const { return mState.getNumViews(); } + bool usesMultiview() const { return mState.usesMultiview(); } - VectorAndSamplerCount &operator+=(const VectorAndSamplerCount &other) - { - vectorCount += other.vectorCount; - samplerCount += other.samplerCount; - return *this; - } + struct VaryingRef + { + const sh::Varying *get() const { return vertex ? vertex : fragment; } - unsigned int vectorCount; - unsigned int samplerCount; + const sh::Varying *vertex = nullptr; + const sh::Varying *fragment = nullptr; }; + using MergedVaryings = std::map; + + private: + ~Program() override; + + void unlink(); + + bool linkAttributes(const Context *context, InfoLog &infoLog); + bool validateVertexAndFragmentInterfaceBlocks( + const std::vector &vertexInterfaceBlocks, + const std::vector &fragmentInterfaceBlocks, + InfoLog &infoLog, + bool webglCompatibility) const; + bool linkInterfaceBlocks(const Context *context, InfoLog &infoLog); + bool linkVaryings(const Context *context, InfoLog &infoLog) const; + + bool linkUniforms(const Context *context, + InfoLog &infoLog, + const Bindings &uniformLocationBindings); + void linkSamplerAndImageBindings(); + bool linkAtomicCounterBuffers(); + + void updateLinkedShaderStages(); + + bool areMatchingInterfaceBlocks(InfoLog &infoLog, + const sh::InterfaceBlock &vertexInterfaceBlock, + const sh::InterfaceBlock &fragmentInterfaceBlock, + bool webglCompatibility) const; + + static bool linkValidateVaryings(InfoLog &infoLog, + const std::string &varyingName, + const sh::Varying &vertexVarying, + const sh::Varying &fragmentVarying, + int shaderVersion); + bool linkValidateBuiltInVaryings(const Context *context, InfoLog &infoLog) const; + bool linkValidateTransformFeedback(const gl::Context *context, + InfoLog &infoLog, + const MergedVaryings &linkedVaryings, + const Caps &caps) const; + bool linkValidateGlobalNames(const Context *context, InfoLog &infoLog) const; - VectorAndSamplerCount flattenUniform(const sh::ShaderVariable &uniform, - const std::string &fullName, - std::vector *samplerUniforms); + void gatherTransformFeedbackVaryings(const MergedVaryings &varyings); - void gatherInterfaceBlockInfo(); - template - void defineUniformBlockMembers(const std::vector &fields, - const std::string &prefix, - int blockIndex); + MergedVaryings getMergedVaryings(const Context *context) const; + void linkOutputVariables(const Context *context); - void defineUniformBlock(const sh::InterfaceBlock &interfaceBlock, GLenum shaderType); + void setUniformValuesFromBindingQualifiers(); - template - void setUniformInternal(GLint location, GLsizei count, const T *v); + void gatherAtomicCounterBuffers(); + void initInterfaceBlockBindings(); + // Both these function update the cached uniform values and return a modified "count" + // so that the uniform update doesn't overflow the uniform. + template + GLsizei clampUniformCount(const VariableLocation &locationInfo, + GLsizei count, + int vectorSize, + const T *v); template - void setMatrixUniformInternal(GLint location, GLsizei count, GLboolean transpose, const T *v); + GLsizei clampMatrixUniformCount(GLint location, GLsizei count, GLboolean transpose, const T *v); + + void updateSamplerUniform(const VariableLocation &locationInfo, + GLsizei clampedCount, + const GLint *v); template - void getUniformInternal(GLint location, DestT *dataOut) const; + void getUniformInternal(const Context *context, + DestT *dataOut, + GLint location, + GLenum nativeType, + int components) const; + + template + void getResourceName(GLuint index, + const std::vector &resources, + GLsizei bufSize, + GLsizei *length, + GLchar *name) const; - Data mData; + ProgramState mState; rx::ProgramImpl *mProgram; bool mValidated; - AttributeBindings mAttributeBindings; + Bindings mAttributeBindings; + + // Note that this has nothing to do with binding layout qualifiers that can be set for some + // uniforms in GLES3.1+. It is used to pre-set the location of uniforms. + Bindings mUniformLocationBindings; + + // CHROMIUM_path_rendering + Bindings mFragmentInputBindings; bool mLinked; bool mDeleteStatus; // Flag to indicate that the program can be deleted when no longer in use unsigned int mRefCount; - ResourceManager *mResourceManager; + ShaderProgramManager *mResourceManager; const GLuint mHandle; InfoLog mInfoLog; @@ -435,8 +729,7 @@ class Program final : angle::NonCopyable, public LabeledObject // Cache for sampler validation Optional mCachedValidateSamplersResult; std::vector mTextureUnitTypesCache; - RangeUI mSamplerUniformRange; }; -} +} // namespace gl #endif // LIBANGLE_PROGRAM_H_ diff --git a/src/3rdparty/angle/src/libANGLE/ProgramLinkedResources.cpp b/src/3rdparty/angle/src/libANGLE/ProgramLinkedResources.cpp new file mode 100644 index 0000000000..a33f751525 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/ProgramLinkedResources.cpp @@ -0,0 +1,1040 @@ +// +// Copyright (c) 2017 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. +// + +// UniformLinker.cpp: implements link-time checks for default block uniforms, and generates uniform +// locations. Populates data structures related to uniforms so that they can be stored in program +// state. + +#include "libANGLE/ProgramLinkedResources.h" + +#include "common/string_utils.h" +#include "common/utilities.h" +#include "libANGLE/Caps.h" +#include "libANGLE/Context.h" +#include "libANGLE/Shader.h" +#include "libANGLE/features.h" + +namespace gl +{ + +namespace +{ + +LinkedUniform *FindUniform(std::vector &list, const std::string &name) +{ + for (LinkedUniform &uniform : list) + { + if (uniform.name == name) + return &uniform; + } + + return nullptr; +} + +int GetUniformLocationBinding(const Program::Bindings &uniformLocationBindings, + const sh::Uniform &uniform) +{ + int binding = uniformLocationBindings.getBinding(uniform.name); + if (uniform.isArray() && binding == -1) + { + // Bindings for array uniforms can be set either with or without [0] in the end. + ASSERT(angle::EndsWith(uniform.name, "[0]")); + std::string nameWithoutIndex = uniform.name.substr(0u, uniform.name.length() - 3u); + return uniformLocationBindings.getBinding(nameWithoutIndex); + } + return binding; +} + +} // anonymous namespace + +UniformLinker::UniformLinker(const ProgramState &state) : mState(state) +{ +} + +UniformLinker::~UniformLinker() = default; + +void UniformLinker::getResults(std::vector *uniforms, + std::vector *uniformLocations) +{ + uniforms->swap(mUniforms); + uniformLocations->swap(mUniformLocations); +} + +bool UniformLinker::link(const Context *context, + InfoLog &infoLog, + const Program::Bindings &uniformLocationBindings) +{ + if (mState.getAttachedVertexShader() && mState.getAttachedFragmentShader()) + { + ASSERT(mState.getAttachedComputeShader() == nullptr); + if (!validateVertexAndFragmentUniforms(context, infoLog)) + { + return false; + } + } + + // Flatten the uniforms list (nested fields) into a simple list (no nesting). + // Also check the maximum uniform vector and sampler counts. + if (!flattenUniformsAndCheckCaps(context, infoLog)) + { + return false; + } + + if (!checkMaxCombinedAtomicCounters(context->getCaps(), infoLog)) + { + return false; + } + + if (!indexUniforms(infoLog, uniformLocationBindings)) + { + return false; + } + + return true; +} + +bool UniformLinker::validateVertexAndFragmentUniforms(const Context *context, + InfoLog &infoLog) const +{ + // Check that uniforms defined in the vertex and fragment shaders are identical + std::map linkedUniforms; + const std::vector &vertexUniforms = + mState.getAttachedVertexShader()->getUniforms(context); + const std::vector &fragmentUniforms = + mState.getAttachedFragmentShader()->getUniforms(context); + + for (const sh::Uniform &vertexUniform : vertexUniforms) + { + linkedUniforms[vertexUniform.name] = vertexUniform; + } + + for (const sh::Uniform &fragmentUniform : fragmentUniforms) + { + auto entry = linkedUniforms.find(fragmentUniform.name); + if (entry != linkedUniforms.end()) + { + const sh::Uniform &linkedUniform = entry->second; + const std::string &uniformName = "uniform '" + linkedUniform.name + "'"; + if (!linkValidateUniforms(infoLog, uniformName, linkedUniform, fragmentUniform)) + { + return false; + } + } + } + return true; +} + +// GLSL ES Spec 3.00.3, section 4.3.5. +bool UniformLinker::linkValidateUniforms(InfoLog &infoLog, + const std::string &uniformName, + const sh::Uniform &vertexUniform, + const sh::Uniform &fragmentUniform) +{ +#if ANGLE_PROGRAM_LINK_VALIDATE_UNIFORM_PRECISION == ANGLE_ENABLED + const bool validatePrecision = true; +#else + const bool validatePrecision = false; +#endif + + if (!Program::linkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform, + validatePrecision)) + { + return false; + } + + // GLSL ES Spec 3.10.4, section 4.4.5. + if (vertexUniform.binding != -1 && fragmentUniform.binding != -1 && + vertexUniform.binding != fragmentUniform.binding) + { + infoLog << "Binding layout qualifiers for " << uniformName + << " differ between vertex and fragment shaders."; + return false; + } + + // GLSL ES Spec 3.10.4, section 9.2.1. + if (vertexUniform.location != -1 && fragmentUniform.location != -1 && + vertexUniform.location != fragmentUniform.location) + { + infoLog << "Location layout qualifiers for " << uniformName + << " differ between vertex and fragment shaders."; + return false; + } + if (vertexUniform.offset != fragmentUniform.offset) + { + infoLog << "Offset layout qualifiers for " << uniformName + << " differ between vertex and fragment shaders."; + return false; + } + + return true; +} + +bool UniformLinker::indexUniforms(InfoLog &infoLog, + const Program::Bindings &uniformLocationBindings) +{ + // All the locations where another uniform can't be located. + std::set reservedLocations; + // Locations which have been allocated for an unused uniform. + std::set ignoredLocations; + + int maxUniformLocation = -1; + + // Gather uniform locations that have been set either using the bindUniformLocation API or by + // using a location layout qualifier and check conflicts between them. + if (!gatherUniformLocationsAndCheckConflicts(infoLog, uniformLocationBindings, + &reservedLocations, &ignoredLocations, + &maxUniformLocation)) + { + return false; + } + + // Conflicts have been checked, now we can prune non-statically used uniforms. Code further down + // the line relies on only having statically used uniforms in mUniforms. + pruneUnusedUniforms(); + + // Gather uniforms that have their location pre-set and uniforms that don't yet have a location. + std::vector unlocatedUniforms; + std::map preLocatedUniforms; + + for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++) + { + const LinkedUniform &uniform = mUniforms[uniformIndex]; + + if (uniform.isBuiltIn() || IsAtomicCounterType(uniform.type)) + { + continue; + } + + int preSetLocation = GetUniformLocationBinding(uniformLocationBindings, uniform); + int shaderLocation = uniform.location; + + if (shaderLocation != -1) + { + preSetLocation = shaderLocation; + } + + unsigned int elementCount = uniform.getBasicTypeElementCount(); + for (unsigned int arrayIndex = 0; arrayIndex < elementCount; arrayIndex++) + { + VariableLocation location(arrayIndex, static_cast(uniformIndex)); + + if ((arrayIndex == 0 && preSetLocation != -1) || shaderLocation != -1) + { + int elementLocation = preSetLocation + arrayIndex; + preLocatedUniforms[elementLocation] = location; + } + else + { + unlocatedUniforms.push_back(location); + } + } + } + + // Make enough space for all uniforms, with pre-set locations or not. + mUniformLocations.resize( + std::max(unlocatedUniforms.size() + preLocatedUniforms.size() + ignoredLocations.size(), + static_cast(maxUniformLocation + 1))); + + // Assign uniforms with pre-set locations + for (const auto &uniform : preLocatedUniforms) + { + mUniformLocations[uniform.first] = uniform.second; + } + + // Assign ignored uniforms + for (const auto &ignoredLocation : ignoredLocations) + { + mUniformLocations[ignoredLocation].markIgnored(); + } + + // Automatically assign locations for the rest of the uniforms + size_t nextUniformLocation = 0; + for (const auto &unlocatedUniform : unlocatedUniforms) + { + while (mUniformLocations[nextUniformLocation].used() || + mUniformLocations[nextUniformLocation].ignored) + { + nextUniformLocation++; + } + + ASSERT(nextUniformLocation < mUniformLocations.size()); + mUniformLocations[nextUniformLocation] = unlocatedUniform; + nextUniformLocation++; + } + + return true; +} + +bool UniformLinker::gatherUniformLocationsAndCheckConflicts( + InfoLog &infoLog, + const Program::Bindings &uniformLocationBindings, + std::set *reservedLocations, + std::set *ignoredLocations, + int *maxUniformLocation) +{ + for (const LinkedUniform &uniform : mUniforms) + { + if (uniform.isBuiltIn()) + { + continue; + } + + int apiBoundLocation = GetUniformLocationBinding(uniformLocationBindings, uniform); + int shaderLocation = uniform.location; + + if (shaderLocation != -1) + { + unsigned int elementCount = uniform.getBasicTypeElementCount(); + + for (unsigned int arrayIndex = 0; arrayIndex < elementCount; arrayIndex++) + { + // GLSL ES 3.10 section 4.4.3 + int elementLocation = shaderLocation + arrayIndex; + *maxUniformLocation = std::max(*maxUniformLocation, elementLocation); + if (reservedLocations->find(elementLocation) != reservedLocations->end()) + { + infoLog << "Multiple uniforms bound to location " << elementLocation << "."; + return false; + } + reservedLocations->insert(elementLocation); + if (!uniform.staticUse) + { + ignoredLocations->insert(elementLocation); + } + } + } + else if (apiBoundLocation != -1 && uniform.staticUse) + { + // Only the first location is reserved even if the uniform is an array. + *maxUniformLocation = std::max(*maxUniformLocation, apiBoundLocation); + if (reservedLocations->find(apiBoundLocation) != reservedLocations->end()) + { + infoLog << "Multiple uniforms bound to location " << apiBoundLocation << "."; + return false; + } + reservedLocations->insert(apiBoundLocation); + } + } + + // Record the uniform locations that were bound using the API for uniforms that were not found + // from the shader. Other uniforms should not be assigned to those locations. + for (const auto &locationBinding : uniformLocationBindings) + { + GLuint location = locationBinding.second; + if (reservedLocations->find(location) == reservedLocations->end()) + { + ignoredLocations->insert(location); + *maxUniformLocation = std::max(*maxUniformLocation, static_cast(location)); + } + } + + return true; +} + +void UniformLinker::pruneUnusedUniforms() +{ + auto uniformIter = mUniforms.begin(); + while (uniformIter != mUniforms.end()) + { + if (uniformIter->staticUse) + { + ++uniformIter; + } + else + { + uniformIter = mUniforms.erase(uniformIter); + } + } +} + +bool UniformLinker::flattenUniformsAndCheckCapsForShader( + const Context *context, + Shader *shader, + GLuint maxUniformComponents, + GLuint maxTextureImageUnits, + GLuint maxImageUnits, + GLuint maxAtomicCounters, + const std::string &componentsErrorMessage, + const std::string &samplerErrorMessage, + const std::string &imageErrorMessage, + const std::string &atomicCounterErrorMessage, + std::vector &samplerUniforms, + std::vector &imageUniforms, + std::vector &atomicCounterUniforms, + InfoLog &infoLog) +{ + ShaderUniformCount shaderUniformCount; + for (const sh::Uniform &uniform : shader->getUniforms(context)) + { + shaderUniformCount += flattenUniform(uniform, &samplerUniforms, &imageUniforms, + &atomicCounterUniforms, shader->getType()); + } + + if (shaderUniformCount.vectorCount > maxUniformComponents) + { + infoLog << componentsErrorMessage << maxUniformComponents << ")."; + return false; + } + + if (shaderUniformCount.samplerCount > maxTextureImageUnits) + { + infoLog << samplerErrorMessage << maxTextureImageUnits << ")."; + return false; + } + + if (shaderUniformCount.imageCount > maxImageUnits) + { + infoLog << imageErrorMessage << maxImageUnits << ")."; + return false; + } + + if (shaderUniformCount.atomicCounterCount > maxAtomicCounters) + { + infoLog << atomicCounterErrorMessage << maxAtomicCounters << ")."; + return false; + } + + return true; +} + +bool UniformLinker::flattenUniformsAndCheckCaps(const Context *context, InfoLog &infoLog) +{ + std::vector samplerUniforms; + std::vector imageUniforms; + std::vector atomicCounterUniforms; + + const Caps &caps = context->getCaps(); + + if (mState.getAttachedComputeShader()) + { + Shader *computeShader = mState.getAttachedComputeShader(); + + // TODO (mradev): check whether we need finer-grained component counting + if (!flattenUniformsAndCheckCapsForShader( + context, computeShader, caps.maxComputeUniformComponents / 4, + caps.maxComputeTextureImageUnits, caps.maxComputeImageUniforms, + caps.maxComputeAtomicCounters, + "Compute shader active uniforms exceed MAX_COMPUTE_UNIFORM_COMPONENTS (", + "Compute shader sampler count exceeds MAX_COMPUTE_TEXTURE_IMAGE_UNITS (", + "Compute shader image count exceeds MAX_COMPUTE_IMAGE_UNIFORMS (", + "Compute shader atomic counter count exceeds MAX_COMPUTE_ATOMIC_COUNTERS (", + samplerUniforms, imageUniforms, atomicCounterUniforms, infoLog)) + { + return false; + } + } + else + { + Shader *vertexShader = mState.getAttachedVertexShader(); + + if (!flattenUniformsAndCheckCapsForShader( + context, vertexShader, caps.maxVertexUniformVectors, + caps.maxVertexTextureImageUnits, caps.maxVertexImageUniforms, + caps.maxVertexAtomicCounters, + "Vertex shader active uniforms exceed MAX_VERTEX_UNIFORM_VECTORS (", + "Vertex shader sampler count exceeds MAX_VERTEX_TEXTURE_IMAGE_UNITS (", + "Vertex shader image count exceeds MAX_VERTEX_IMAGE_UNIFORMS (", + "Vertex shader atomic counter count exceeds MAX_VERTEX_ATOMIC_COUNTERS (", + samplerUniforms, imageUniforms, atomicCounterUniforms, infoLog)) + { + return false; + } + + Shader *fragmentShader = mState.getAttachedFragmentShader(); + + if (!flattenUniformsAndCheckCapsForShader( + context, fragmentShader, caps.maxFragmentUniformVectors, caps.maxTextureImageUnits, + caps.maxFragmentImageUniforms, caps.maxFragmentAtomicCounters, + "Fragment shader active uniforms exceed MAX_FRAGMENT_UNIFORM_VECTORS (", + "Fragment shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (", + "Fragment shader image count exceeds MAX_FRAGMENT_IMAGE_UNIFORMS (", + "Fragment shader atomic counter count exceeds MAX_FRAGMENT_ATOMIC_COUNTERS (", + samplerUniforms, imageUniforms, atomicCounterUniforms, infoLog)) + { + return false; + } + } + + mUniforms.insert(mUniforms.end(), samplerUniforms.begin(), samplerUniforms.end()); + mUniforms.insert(mUniforms.end(), imageUniforms.begin(), imageUniforms.end()); + mUniforms.insert(mUniforms.end(), atomicCounterUniforms.begin(), atomicCounterUniforms.end()); + return true; +} + +UniformLinker::ShaderUniformCount UniformLinker::flattenUniform( + const sh::Uniform &uniform, + std::vector *samplerUniforms, + std::vector *imageUniforms, + std::vector *atomicCounterUniforms, + GLenum shaderType) +{ + int location = uniform.location; + ShaderUniformCount shaderUniformCount = + flattenUniformImpl(uniform, uniform.name, uniform.mappedName, samplerUniforms, + imageUniforms, atomicCounterUniforms, shaderType, uniform.staticUse, + uniform.binding, uniform.offset, &location); + if (uniform.staticUse) + { + return shaderUniformCount; + } + return ShaderUniformCount(); +} + +UniformLinker::ShaderUniformCount UniformLinker::flattenArrayOfStructsUniform( + const sh::ShaderVariable &uniform, + unsigned int arrayNestingIndex, + const std::string &namePrefix, + const std::string &mappedNamePrefix, + std::vector *samplerUniforms, + std::vector *imageUniforms, + std::vector *atomicCounterUniforms, + GLenum shaderType, + bool markStaticUse, + int binding, + int offset, + int *location) +{ + // Nested arrays are processed starting from outermost (arrayNestingIndex 0u) and ending at the + // innermost. + ShaderUniformCount shaderUniformCount; + const unsigned int currentArraySize = uniform.getNestedArraySize(arrayNestingIndex); + for (unsigned int arrayElement = 0u; arrayElement < currentArraySize; ++arrayElement) + { + const std::string elementName = namePrefix + ArrayString(arrayElement); + const std::string elementMappedName = mappedNamePrefix + ArrayString(arrayElement); + if (arrayNestingIndex + 1u < uniform.arraySizes.size()) + { + shaderUniformCount += flattenArrayOfStructsUniform( + uniform, arrayNestingIndex + 1u, elementName, elementMappedName, samplerUniforms, + imageUniforms, atomicCounterUniforms, shaderType, markStaticUse, binding, offset, + location); + } + else + { + shaderUniformCount += flattenStructUniform( + uniform.fields, elementName, elementMappedName, samplerUniforms, imageUniforms, + atomicCounterUniforms, shaderType, markStaticUse, binding, offset, location); + } + } + return shaderUniformCount; +} + +UniformLinker::ShaderUniformCount UniformLinker::flattenStructUniform( + const std::vector &fields, + const std::string &namePrefix, + const std::string &mappedNamePrefix, + std::vector *samplerUniforms, + std::vector *imageUniforms, + std::vector *atomicCounterUniforms, + GLenum shaderType, + bool markStaticUse, + int binding, + int offset, + int *location) +{ + ShaderUniformCount shaderUniformCount; + for (const sh::ShaderVariable &field : fields) + { + const std::string &fieldName = namePrefix + "." + field.name; + const std::string &fieldMappedName = mappedNamePrefix + "." + field.mappedName; + + shaderUniformCount += + flattenUniformImpl(field, fieldName, fieldMappedName, samplerUniforms, imageUniforms, + atomicCounterUniforms, shaderType, markStaticUse, -1, -1, location); + } + return shaderUniformCount; +} + +UniformLinker::ShaderUniformCount UniformLinker::flattenArrayUniform( + const sh::ShaderVariable &uniform, + const std::string &namePrefix, + const std::string &mappedNamePrefix, + std::vector *samplerUniforms, + std::vector *imageUniforms, + std::vector *atomicCounterUniforms, + GLenum shaderType, + bool markStaticUse, + int binding, + int offset, + int *location) +{ + ShaderUniformCount shaderUniformCount; + + ASSERT(uniform.isArray()); + for (unsigned int arrayElement = 0u; arrayElement < uniform.getOutermostArraySize(); + ++arrayElement) + { + sh::ShaderVariable uniformElement = uniform; + uniformElement.indexIntoArray(arrayElement); + const std::string elementName = namePrefix + ArrayString(arrayElement); + const std::string elementMappedName = mappedNamePrefix + ArrayString(arrayElement); + + shaderUniformCount += flattenUniformImpl( + uniformElement, elementName, elementMappedName, samplerUniforms, imageUniforms, + atomicCounterUniforms, shaderType, markStaticUse, binding, offset, location); + } + return shaderUniformCount; +} + +UniformLinker::ShaderUniformCount UniformLinker::flattenUniformImpl( + const sh::ShaderVariable &uniform, + const std::string &fullName, + const std::string &fullMappedName, + std::vector *samplerUniforms, + std::vector *imageUniforms, + std::vector *atomicCounterUniforms, + GLenum shaderType, + bool markStaticUse, + int binding, + int offset, + int *location) +{ + ASSERT(location); + ShaderUniformCount shaderUniformCount; + + if (uniform.isStruct()) + { + if (uniform.isArray()) + { + shaderUniformCount += flattenArrayOfStructsUniform( + uniform, 0u, fullName, fullMappedName, samplerUniforms, imageUniforms, + atomicCounterUniforms, shaderType, markStaticUse, binding, offset, location); + } + else + { + shaderUniformCount += flattenStructUniform( + uniform.fields, fullName, fullMappedName, samplerUniforms, imageUniforms, + atomicCounterUniforms, shaderType, markStaticUse, binding, offset, location); + } + return shaderUniformCount; + } + if (uniform.isArrayOfArrays()) + { + // GLES 3.1 November 2016 section 7.3.1 page 77: + // "For an active variable declared as an array of an aggregate data type (structures or + // arrays), a separate entry will be generated for each active array element" + return flattenArrayUniform(uniform, fullName, fullMappedName, samplerUniforms, + imageUniforms, atomicCounterUniforms, shaderType, markStaticUse, + binding, offset, location); + } + + // Not a struct + bool isSampler = IsSamplerType(uniform.type); + bool isImage = IsImageType(uniform.type); + bool isAtomicCounter = IsAtomicCounterType(uniform.type); + std::vector *uniformList = &mUniforms; + if (isSampler) + { + uniformList = samplerUniforms; + } + else if (isImage) + { + uniformList = imageUniforms; + } + else if (isAtomicCounter) + { + uniformList = atomicCounterUniforms; + } + + std::string fullNameWithArrayIndex(fullName); + std::string fullMappedNameWithArrayIndex(fullMappedName); + + if (uniform.isArray()) + { + // We're following the GLES 3.1 November 2016 spec section 7.3.1.1 Naming Active Resources + // and including [0] at the end of array variable names. + fullNameWithArrayIndex += "[0]"; + fullMappedNameWithArrayIndex += "[0]"; + } + + LinkedUniform *existingUniform = FindUniform(*uniformList, fullNameWithArrayIndex); + if (existingUniform) + { + if (binding != -1) + { + existingUniform->binding = binding; + } + if (offset != -1) + { + existingUniform->offset = offset; + } + if (*location != -1) + { + existingUniform->location = *location; + } + if (markStaticUse) + { + existingUniform->staticUse = true; + existingUniform->setStaticUse(shaderType, true); + } + } + else + { + ASSERT(uniform.arraySizes.size() <= 1u); + LinkedUniform linkedUniform(uniform.type, uniform.precision, fullNameWithArrayIndex, + uniform.arraySizes, binding, offset, *location, -1, + sh::BlockMemberInfo::getDefaultBlockInfo()); + linkedUniform.mappedName = fullMappedNameWithArrayIndex; + linkedUniform.staticUse = markStaticUse; + linkedUniform.flattenedOffsetInParentArrays = uniform.flattenedOffsetInParentArrays; + if (markStaticUse) + { + linkedUniform.setStaticUse(shaderType, true); + } + + uniformList->push_back(linkedUniform); + } + + // Struct and array of arrays uniforms get flattened so we can use getBasicTypeElementCount(). + unsigned int elementCount = uniform.getBasicTypeElementCount(); + + // Samplers and images aren't "real" uniforms, so they don't count towards register usage. + // Likewise, don't count "real" uniforms towards opaque count. + shaderUniformCount.vectorCount = + (IsOpaqueType(uniform.type) ? 0 : (VariableRegisterCount(uniform.type) * elementCount)); + shaderUniformCount.samplerCount = (isSampler ? elementCount : 0); + shaderUniformCount.imageCount = (isImage ? elementCount : 0); + shaderUniformCount.atomicCounterCount = (isAtomicCounter ? elementCount : 0); + + if (*location != -1) + { + *location += elementCount; + } + + return shaderUniformCount; +} + +bool UniformLinker::checkMaxCombinedAtomicCounters(const Caps &caps, InfoLog &infoLog) +{ + unsigned int atomicCounterCount = 0; + for (const auto &uniform : mUniforms) + { + if (IsAtomicCounterType(uniform.type) && uniform.staticUse) + { + atomicCounterCount += uniform.getBasicTypeElementCount(); + if (atomicCounterCount > caps.maxCombinedAtomicCounters) + { + infoLog << "atomic counter count exceeds MAX_COMBINED_ATOMIC_COUNTERS" + << caps.maxCombinedAtomicCounters << ")."; + return false; + } + } + } + return true; +} + +// InterfaceBlockLinker implementation. +InterfaceBlockLinker::InterfaceBlockLinker(std::vector *blocksOut) + : mBlocksOut(blocksOut) +{ +} + +InterfaceBlockLinker::~InterfaceBlockLinker() +{ +} + +void InterfaceBlockLinker::addShaderBlocks(GLenum shader, + const std::vector *blocks) +{ + mShaderBlocks.push_back(std::make_pair(shader, blocks)); +} + +void InterfaceBlockLinker::linkBlocks(const GetBlockSize &getBlockSize, + const GetBlockMemberInfo &getMemberInfo) const +{ + ASSERT(mBlocksOut->empty()); + + std::set visitedList; + + for (const auto &shaderBlocks : mShaderBlocks) + { + const GLenum shaderType = shaderBlocks.first; + + for (const auto &block : *shaderBlocks.second) + { + // Only 'packed' blocks are allowed to be considered inactive. + if (!block.staticUse && block.layout == sh::BLOCKLAYOUT_PACKED) + continue; + + if (visitedList.count(block.name) > 0) + { + if (block.staticUse) + { + for (InterfaceBlock &priorBlock : *mBlocksOut) + { + if (block.name == priorBlock.name) + { + priorBlock.setStaticUse(shaderType, true); + // TODO(jiajia.qin@intel.com): update the block members static use. + } + } + } + } + else + { + defineInterfaceBlock(getBlockSize, getMemberInfo, block, shaderType); + visitedList.insert(block.name); + } + } + } +} + +template +void InterfaceBlockLinker::defineArrayOfStructsBlockMembers(const GetBlockMemberInfo &getMemberInfo, + const VarT &field, + unsigned int arrayNestingIndex, + const std::string &prefix, + const std::string &mappedPrefix, + int blockIndex, + bool singleEntryForTopLevelArray, + int topLevelArraySize) const +{ + // Nested arrays are processed starting from outermost (arrayNestingIndex 0u) and ending at the + // innermost. + unsigned int entryGenerationArraySize = field.getNestedArraySize(arrayNestingIndex); + if (singleEntryForTopLevelArray) + { + entryGenerationArraySize = 1; + } + for (unsigned int arrayElement = 0u; arrayElement < entryGenerationArraySize; ++arrayElement) + { + const std::string elementName = prefix + ArrayString(arrayElement); + const std::string elementMappedName = mappedPrefix + ArrayString(arrayElement); + if (arrayNestingIndex + 1u < field.arraySizes.size()) + { + defineArrayOfStructsBlockMembers(getMemberInfo, field, arrayNestingIndex + 1u, + elementName, elementMappedName, blockIndex, false, + topLevelArraySize); + } + else + { + defineBlockMembers(getMemberInfo, field.fields, elementName, elementMappedName, + blockIndex, false, topLevelArraySize); + } + } +} + +template +void InterfaceBlockLinker::defineBlockMembers(const GetBlockMemberInfo &getMemberInfo, + const std::vector &fields, + const std::string &prefix, + const std::string &mappedPrefix, + int blockIndex, + bool singleEntryForTopLevelArray, + int topLevelArraySize) const +{ + for (const VarT &field : fields) + { + std::string fullName = (prefix.empty() ? field.name : prefix + "." + field.name); + std::string fullMappedName = + (mappedPrefix.empty() ? field.mappedName : mappedPrefix + "." + field.mappedName); + + defineBlockMember(getMemberInfo, field, fullName, fullMappedName, blockIndex, + singleEntryForTopLevelArray, topLevelArraySize); + } +} + +template +void InterfaceBlockLinker::defineBlockMember(const GetBlockMemberInfo &getMemberInfo, + const VarT &field, + const std::string &fullName, + const std::string &fullMappedName, + int blockIndex, + bool singleEntryForTopLevelArray, + int topLevelArraySize) const +{ + int nextArraySize = topLevelArraySize; + if (((field.isArray() && field.isStruct()) || field.isArrayOfArrays()) && + singleEntryForTopLevelArray) + { + // In OpenGL ES 3.10 spec, session 7.3.1.1 'For an active shader storage block + // member declared as an array of an aggregate type, an entry will be generated only + // for the first array element, regardless of its type.' + nextArraySize = field.getOutermostArraySize(); + } + + if (field.isStruct()) + { + if (field.isArray()) + { + defineArrayOfStructsBlockMembers(getMemberInfo, field, 0u, fullName, fullMappedName, + blockIndex, singleEntryForTopLevelArray, + nextArraySize); + } + else + { + ASSERT(nextArraySize == topLevelArraySize); + defineBlockMembers(getMemberInfo, field.fields, fullName, fullMappedName, blockIndex, + false, nextArraySize); + } + return; + } + if (field.isArrayOfArrays()) + { + unsigned int entryGenerationArraySize = field.getOutermostArraySize(); + if (singleEntryForTopLevelArray) + { + entryGenerationArraySize = 1u; + } + for (unsigned int arrayElement = 0u; arrayElement < entryGenerationArraySize; + ++arrayElement) + { + VarT fieldElement = field; + fieldElement.indexIntoArray(arrayElement); + const std::string elementName = fullName + ArrayString(arrayElement); + const std::string elementMappedName = fullMappedName + ArrayString(arrayElement); + + defineBlockMember(getMemberInfo, fieldElement, elementName, elementMappedName, + blockIndex, false, nextArraySize); + } + return; + } + + // If getBlockMemberInfo returns false, the variable is optimized out. + sh::BlockMemberInfo memberInfo; + if (!getMemberInfo(fullName, fullMappedName, &memberInfo)) + { + return; + } + + std::string fullNameWithArrayIndex = fullName; + std::string fullMappedNameWithArrayIndex = fullMappedName; + + if (field.isArray()) + { + fullNameWithArrayIndex += "[0]"; + fullMappedNameWithArrayIndex += "[0]"; + } + + ASSERT(nextArraySize == topLevelArraySize); + defineBlockMemberImpl(field, fullNameWithArrayIndex, fullMappedNameWithArrayIndex, blockIndex, + memberInfo, nextArraySize); +} + +void InterfaceBlockLinker::defineInterfaceBlock(const GetBlockSize &getBlockSize, + const GetBlockMemberInfo &getMemberInfo, + const sh::InterfaceBlock &interfaceBlock, + GLenum shaderType) const +{ + size_t blockSize = 0; + std::vector blockIndexes; + + int blockIndex = static_cast(mBlocksOut->size()); + // Track the first and last block member index to determine the range of active block members in + // the block. + size_t firstBlockMemberIndex = getCurrentBlockMemberIndex(); + defineBlockMembers(getMemberInfo, interfaceBlock.fields, interfaceBlock.fieldPrefix(), + interfaceBlock.fieldMappedPrefix(), blockIndex, + interfaceBlock.blockType == sh::BlockType::BLOCK_BUFFER, 1); + size_t lastBlockMemberIndex = getCurrentBlockMemberIndex(); + + for (size_t blockMemberIndex = firstBlockMemberIndex; blockMemberIndex < lastBlockMemberIndex; + ++blockMemberIndex) + { + blockIndexes.push_back(static_cast(blockMemberIndex)); + } + + // ESSL 3.10 section 4.4.4 page 58: + // Any uniform or shader storage block declared without a binding qualifier is initially + // assigned to block binding point zero. + int blockBinding = (interfaceBlock.binding == -1 ? 0 : interfaceBlock.binding); + for (unsigned int arrayElement = 0; arrayElement < interfaceBlock.elementCount(); + ++arrayElement) + { + std::string blockArrayName = interfaceBlock.name; + std::string blockMappedArrayName = interfaceBlock.mappedName; + if (interfaceBlock.isArray()) + { + blockArrayName += ArrayString(arrayElement); + blockMappedArrayName += ArrayString(arrayElement); + } + + // Don't define this block at all if it's not active in the implementation. + if (!getBlockSize(blockArrayName, blockMappedArrayName, &blockSize)) + { + continue; + } + + InterfaceBlock block(interfaceBlock.name, interfaceBlock.mappedName, + interfaceBlock.isArray(), arrayElement, blockBinding + arrayElement); + block.memberIndexes = blockIndexes; + block.setStaticUse(shaderType, interfaceBlock.staticUse); + + // Since all block elements in an array share the same active interface blocks, they + // will all be active once any block member is used. So, since interfaceBlock.name[0] + // was active, here we will add every block element in the array. + block.dataSize = static_cast(blockSize); + mBlocksOut->push_back(block); + } +} + +// UniformBlockLinker implementation. +UniformBlockLinker::UniformBlockLinker(std::vector *blocksOut, + std::vector *uniformsOut) + : InterfaceBlockLinker(blocksOut), mUniformsOut(uniformsOut) +{ +} + +UniformBlockLinker::~UniformBlockLinker() +{ +} + +void UniformBlockLinker::defineBlockMemberImpl(const sh::ShaderVariable &field, + const std::string &fullName, + const std::string &fullMappedName, + int blockIndex, + const sh::BlockMemberInfo &memberInfo, + int /*topLevelArraySize*/) const +{ + LinkedUniform newUniform(field.type, field.precision, fullName, field.arraySizes, -1, -1, -1, + blockIndex, memberInfo); + newUniform.mappedName = fullMappedName; + // TODO(jiajia.qin@intel.com): update the block memeber static use. + + // Since block uniforms have no location, we don't need to store them in the uniform locations + // list. + mUniformsOut->push_back(newUniform); +} + +size_t UniformBlockLinker::getCurrentBlockMemberIndex() const +{ + return mUniformsOut->size(); +} + +// ShaderStorageBlockLinker implementation. +ShaderStorageBlockLinker::ShaderStorageBlockLinker(std::vector *blocksOut, + std::vector *bufferVariablesOut) + : InterfaceBlockLinker(blocksOut), mBufferVariablesOut(bufferVariablesOut) +{ +} + +ShaderStorageBlockLinker::~ShaderStorageBlockLinker() +{ +} + +void ShaderStorageBlockLinker::defineBlockMemberImpl(const sh::ShaderVariable &field, + const std::string &fullName, + const std::string &fullMappedName, + int blockIndex, + const sh::BlockMemberInfo &memberInfo, + int topLevelArraySize) const +{ + BufferVariable newBufferVariable(field.type, field.precision, fullName, field.arraySizes, + blockIndex, memberInfo); + newBufferVariable.mappedName = fullMappedName; + // TODO(jiajia.qin@intel.com): update the block memeber static use. + + newBufferVariable.topLevelArraySize = topLevelArraySize; + + mBufferVariablesOut->push_back(newBufferVariable); +} + +size_t ShaderStorageBlockLinker::getCurrentBlockMemberIndex() const +{ + return mBufferVariablesOut->size(); +} + +} // namespace gl diff --git a/src/3rdparty/angle/src/libANGLE/ProgramLinkedResources.h b/src/3rdparty/angle/src/libANGLE/ProgramLinkedResources.h new file mode 100644 index 0000000000..1bf91b7f3b --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/ProgramLinkedResources.h @@ -0,0 +1,274 @@ +// +// Copyright (c) 2017 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. +// + +// UniformLinker.h: implements link-time checks for default block uniforms, and generates uniform +// locations. Populates data structures related to uniforms so that they can be stored in program +// state. + +#ifndef LIBANGLE_UNIFORMLINKER_H_ +#define LIBANGLE_UNIFORMLINKER_H_ + +#include "libANGLE/Program.h" +#include "libANGLE/Uniform.h" +#include "libANGLE/VaryingPacking.h" + +#include + +namespace gl +{ + +class UniformLinker +{ + public: + UniformLinker(const ProgramState &state); + ~UniformLinker(); + + bool link(const Context *context, + InfoLog &infoLog, + const Program::Bindings &uniformLocationBindings); + + void getResults(std::vector *uniforms, + std::vector *uniformLocations); + + private: + struct ShaderUniformCount + { + ShaderUniformCount() : vectorCount(0), samplerCount(0), imageCount(0), atomicCounterCount(0) + { + } + ShaderUniformCount(const ShaderUniformCount &other) = default; + ShaderUniformCount &operator=(const ShaderUniformCount &other) = default; + + ShaderUniformCount &operator+=(const ShaderUniformCount &other) + { + vectorCount += other.vectorCount; + samplerCount += other.samplerCount; + imageCount += other.imageCount; + atomicCounterCount += other.atomicCounterCount; + return *this; + } + + unsigned int vectorCount; + unsigned int samplerCount; + unsigned int imageCount; + unsigned int atomicCounterCount; + }; + + bool validateVertexAndFragmentUniforms(const Context *context, InfoLog &infoLog) const; + + static bool linkValidateUniforms(InfoLog &infoLog, + const std::string &uniformName, + const sh::Uniform &vertexUniform, + const sh::Uniform &fragmentUniform); + + bool flattenUniformsAndCheckCapsForShader(const Context *context, + Shader *shader, + GLuint maxUniformComponents, + GLuint maxTextureImageUnits, + GLuint maxImageUnits, + GLuint maxAtomicCounters, + const std::string &componentsErrorMessage, + const std::string &samplerErrorMessage, + const std::string &imageErrorMessage, + const std::string &atomicCounterErrorMessage, + std::vector &samplerUniforms, + std::vector &imageUniforms, + std::vector &atomicCounterUniforms, + InfoLog &infoLog); + + bool flattenUniformsAndCheckCaps(const Context *context, InfoLog &infoLog); + bool checkMaxCombinedAtomicCounters(const Caps &caps, InfoLog &infoLog); + + ShaderUniformCount flattenUniform(const sh::Uniform &uniform, + std::vector *samplerUniforms, + std::vector *imageUniforms, + std::vector *atomicCounterUniforms, + GLenum shaderType); + + ShaderUniformCount flattenArrayOfStructsUniform( + const sh::ShaderVariable &uniform, + unsigned int arrayNestingIndex, + const std::string &namePrefix, + const std::string &mappedNamePrefix, + std::vector *samplerUniforms, + std::vector *imageUniforms, + std::vector *atomicCounterUniforms, + GLenum shaderType, + bool markStaticUse, + int binding, + int offset, + int *location); + + ShaderUniformCount flattenStructUniform(const std::vector &fields, + const std::string &namePrefix, + const std::string &mappedNamePrefix, + std::vector *samplerUniforms, + std::vector *imageUniforms, + std::vector *atomicCounterUniforms, + GLenum shaderType, + bool markStaticUse, + int binding, + int offset, + int *location); + + ShaderUniformCount flattenArrayUniform(const sh::ShaderVariable &uniform, + const std::string &fullName, + const std::string &fullMappedName, + std::vector *samplerUniforms, + std::vector *imageUniforms, + std::vector *atomicCounterUniforms, + GLenum shaderType, + bool markStaticUse, + int binding, + int offset, + int *location); + + // markStaticUse is given as a separate parameter because it is tracked here at struct + // granularity. + ShaderUniformCount flattenUniformImpl(const sh::ShaderVariable &uniform, + const std::string &fullName, + const std::string &fullMappedName, + std::vector *samplerUniforms, + std::vector *imageUniforms, + std::vector *atomicCounterUniforms, + GLenum shaderType, + bool markStaticUse, + int binding, + int offset, + int *location); + + bool indexUniforms(InfoLog &infoLog, const Program::Bindings &uniformLocationBindings); + bool gatherUniformLocationsAndCheckConflicts(InfoLog &infoLog, + const Program::Bindings &uniformLocationBindings, + std::set *reservedLocations, + std::set *ignoredLocations, + int *maxUniformLocation); + void pruneUnusedUniforms(); + + const ProgramState &mState; + std::vector mUniforms; + std::vector mUniformLocations; +}; + +// This class is intended to be used during the link step to store interface block information. +// It is called by the Impl class during ProgramImpl::link so that it has access to the +// real block size and layout. +class InterfaceBlockLinker : angle::NonCopyable +{ + public: + virtual ~InterfaceBlockLinker(); + + using GetBlockSize = std::function< + bool(const std::string &blockName, const std::string &blockMappedName, size_t *sizeOut)>; + using GetBlockMemberInfo = std::function< + bool(const std::string &name, const std::string &mappedName, sh::BlockMemberInfo *infoOut)>; + + // This is called once per shader stage. It stores a pointer to the block vector, so it's + // important that this class does not persist longer than the duration of Program::link. + void addShaderBlocks(GLenum shader, const std::vector *blocks); + + // This is called once during a link operation, after all shader blocks are added. + void linkBlocks(const GetBlockSize &getBlockSize, + const GetBlockMemberInfo &getMemberInfo) const; + + protected: + InterfaceBlockLinker(std::vector *blocksOut); + void defineInterfaceBlock(const GetBlockSize &getBlockSize, + const GetBlockMemberInfo &getMemberInfo, + const sh::InterfaceBlock &interfaceBlock, + GLenum shaderType) const; + + template + void defineBlockMembers(const GetBlockMemberInfo &getMemberInfo, + const std::vector &fields, + const std::string &prefix, + const std::string &mappedPrefix, + int blockIndex, + bool singleEntryForTopLevelArray, + int topLevelArraySize) const; + template + void defineBlockMember(const GetBlockMemberInfo &getMemberInfo, + const VarT &field, + const std::string &fullName, + const std::string &fullMappedName, + int blockIndex, + bool singleEntryForTopLevelArray, + int topLevelArraySize) const; + + virtual void defineBlockMemberImpl(const sh::ShaderVariable &field, + const std::string &fullName, + const std::string &fullMappedName, + int blockIndex, + const sh::BlockMemberInfo &memberInfo, + int topLevelArraySize) const = 0; + virtual size_t getCurrentBlockMemberIndex() const = 0; + + using ShaderBlocks = std::pair *>; + std::vector mShaderBlocks; + + std::vector *mBlocksOut; + + private: + template + void defineArrayOfStructsBlockMembers(const GetBlockMemberInfo &getMemberInfo, + const VarT &field, + unsigned int arrayNestingIndex, + const std::string &prefix, + const std::string &mappedPrefix, + int blockIndex, + bool singleEntryForTopLevelArray, + int topLevelArraySize) const; +}; + +class UniformBlockLinker final : public InterfaceBlockLinker +{ + public: + UniformBlockLinker(std::vector *blocksOut, + std::vector *uniformsOut); + ~UniformBlockLinker() override; + + private: + void defineBlockMemberImpl(const sh::ShaderVariable &field, + const std::string &fullName, + const std::string &fullMappedName, + int blockIndex, + const sh::BlockMemberInfo &memberInfo, + int topLevelArraySize) const override; + size_t getCurrentBlockMemberIndex() const override; + std::vector *mUniformsOut; +}; + +class ShaderStorageBlockLinker final : public InterfaceBlockLinker +{ + public: + ShaderStorageBlockLinker(std::vector *blocksOut, + std::vector *bufferVariablesOut); + ~ShaderStorageBlockLinker() override; + + private: + void defineBlockMemberImpl(const sh::ShaderVariable &field, + const std::string &fullName, + const std::string &fullMappedName, + int blockIndex, + const sh::BlockMemberInfo &memberInfo, + int topLevelArraySize) const override; + size_t getCurrentBlockMemberIndex() const override; + std::vector *mBufferVariablesOut; +}; + +// The link operation is responsible for finishing the link of uniform and interface blocks. +// This way it can filter out unreferenced resources and still have access to the info. +// TODO(jmadill): Integrate uniform linking/filtering as well as interface blocks. +struct ProgramLinkedResources +{ + VaryingPacking varyingPacking; + UniformBlockLinker uniformBlockLinker; + ShaderStorageBlockLinker shaderStorageBlockLinker; +}; + +} // namespace gl + +#endif // LIBANGLE_UNIFORMLINKER_H_ diff --git a/src/3rdparty/angle/src/libANGLE/ProgramPipeline.cpp b/src/3rdparty/angle/src/libANGLE/ProgramPipeline.cpp new file mode 100644 index 0000000000..0445512090 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/ProgramPipeline.cpp @@ -0,0 +1,65 @@ +// +// Copyright (c) 2017 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. +// + +// ProgramPipeline.cpp: Implements the gl::ProgramPipeline class. +// Implements GL program pipeline objects and related functionality. +// [OpenGL ES 3.1] section 7.4 page 105. + +#include "libANGLE/ProgramPipeline.h" + +#include "libANGLE/angletypes.h" +#include "libANGLE/renderer/GLImplFactory.h" +#include "libANGLE/renderer/ProgramPipelineImpl.h" + +namespace gl +{ + +ProgramPipelineState::ProgramPipelineState() : mLabel() +{ +} + +ProgramPipelineState::~ProgramPipelineState() +{ +} + +const std::string &ProgramPipelineState::getLabel() const +{ + return mLabel; +} + +ProgramPipeline::ProgramPipeline(rx::GLImplFactory *factory, GLuint handle) + : RefCountObject(handle), + mProgramPipeline(factory->createProgramPipeline(mState)) +{ + ASSERT(mProgramPipeline); +} + +ProgramPipeline::~ProgramPipeline() +{ + mProgramPipeline.release(); +} + +Error ProgramPipeline::onDestroy(const Context *context) +{ + return NoError(); +} + +void ProgramPipeline::setLabel(const std::string &label) +{ + mState.mLabel = label; +} + +const std::string &ProgramPipeline::getLabel() const +{ + return mState.mLabel; +} + +rx::ProgramPipelineImpl *ProgramPipeline::getImplementation() const +{ + return mProgramPipeline.get(); +} + +} // namespace gl diff --git a/src/3rdparty/angle/src/libANGLE/ProgramPipeline.h b/src/3rdparty/angle/src/libANGLE/ProgramPipeline.h new file mode 100644 index 0000000000..2aac87c7b8 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/ProgramPipeline.h @@ -0,0 +1,65 @@ +// +// Copyright (c) 2017 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. +// + +// ProgramPipeline.h: Defines the gl::ProgramPipeline class. +// Implements GL program pipeline objects and related functionality. +// [OpenGL ES 3.1] section 7.4 page 105. + +#ifndef LIBANGLE_PROGRAMPIPELINE_H_ +#define LIBANGLE_PROGRAMPIPELINE_H_ + +#include + +#include "common/angleutils.h" +#include "libANGLE/Debug.h" +#include "libANGLE/RefCountObject.h" + +namespace rx +{ +class GLImplFactory; +class ProgramPipelineImpl; +}; + +namespace gl +{ +class Context; +class ProgramPipeline; + +class ProgramPipelineState final : angle::NonCopyable +{ + public: + ProgramPipelineState(); + ~ProgramPipelineState(); + + const std::string &getLabel() const; + + private: + friend class ProgramPipeline; + + std::string mLabel; +}; + +class ProgramPipeline final : public RefCountObject, public LabeledObject +{ + public: + ProgramPipeline(rx::GLImplFactory *factory, GLuint handle); + ~ProgramPipeline() override; + + Error onDestroy(const Context *context) override; + + void setLabel(const std::string &label) override; + const std::string &getLabel() const override; + + rx::ProgramPipelineImpl *getImplementation() const; + + private: + std::unique_ptr mProgramPipeline; + + ProgramPipelineState mState; +}; +} + +#endif // LIBANGLE_PROGRAMPIPELINE_H_ diff --git a/src/3rdparty/angle/src/libANGLE/Query.h b/src/3rdparty/angle/src/libANGLE/Query.h index 5486f983e7..c307eaaf08 100644 --- a/src/3rdparty/angle/src/libANGLE/Query.h +++ b/src/3rdparty/angle/src/libANGLE/Query.h @@ -29,7 +29,8 @@ class Query final : public RefCountObject, public LabeledObject { public: Query(rx::QueryImpl *impl, GLuint id); - virtual ~Query(); + void destroy(const gl::Context *context) {} + ~Query() override; void setLabel(const std::string &label) override; const std::string &getLabel() const override; diff --git a/src/3rdparty/angle/src/libANGLE/RefCountObject.cpp b/src/3rdparty/angle/src/libANGLE/RefCountObject.cpp deleted file mode 100644 index b1210200cf..0000000000 --- a/src/3rdparty/angle/src/libANGLE/RefCountObject.cpp +++ /dev/null @@ -1,39 +0,0 @@ -// -// 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 index 86e6d788b5..cb41cc27f4 100644 --- a/src/3rdparty/angle/src/libANGLE/RefCountObject.h +++ b/src/3rdparty/angle/src/libANGLE/RefCountObject.h @@ -12,16 +12,21 @@ #ifndef LIBANGLE_REFCOUNTOBJECT_H_ #define LIBANGLE_REFCOUNTOBJECT_H_ -#include "common/debug.h" - #include "angle_gl.h" +#include "common/debug.h" +#include "libANGLE/Error.h" #include -class RefCountObject : angle::NonCopyable +namespace gl +{ +class Context; + +class RefCountObjectNoID : angle::NonCopyable { public: - explicit RefCountObject(GLuint id) : mId(id), mRefCount(0) {} + RefCountObjectNoID() : mRefCount(0) {} + virtual Error onDestroy(const Context *context); void addRef() const { ++mRefCount; } @@ -35,17 +40,56 @@ class RefCountObject : angle::NonCopyable } } + size_t getRefCount() const { return mRefCount; } + + protected: + virtual ~RefCountObjectNoID(); + + // A specialized release method for objects which need a destroy context. + void release(const gl::Context *context) + { + ASSERT(mRefCount > 0); + if (--mRefCount == 0) + { + ANGLE_SWALLOW_ERR(onDestroy(context)); + delete this; + } + } + + template + friend class BindingPointer; + mutable std::size_t mRefCount; +}; + +inline RefCountObjectNoID::~RefCountObjectNoID() +{ + ASSERT(mRefCount == 0); +} + +inline Error RefCountObjectNoID::onDestroy(const Context *context) +{ + return NoError(); +} + +template +class BindingPointer; + +class RefCountObject : RefCountObjectNoID +{ + public: + explicit RefCountObject(GLuint id) : mId(id) {} + GLuint id() const { return mId; } - size_t getRefCount() const { return mRefCount; } + using RefCountObjectNoID::release; + using RefCountObjectNoID::addRef; + using RefCountObjectNoID::getRefCount; protected: - virtual ~RefCountObject() { ASSERT(mRefCount == 0); } + ~RefCountObject() override {} private: GLuint mId; - - mutable std::size_t mRefCount; }; template @@ -57,15 +101,17 @@ class BindingPointer { } - BindingPointer(const BindingPointer &other) - : mObject(nullptr) + BindingPointer(ObjectType *object) : mObject(object) { mObject->addRef(); } + + BindingPointer(const BindingPointer &other) : mObject(other.mObject) { - set(other.mObject); + mObject->addRef(); } - void operator=(const BindingPointer &other) + BindingPointer &operator=(BindingPointer &&other) { - set(other.mObject); + std::swap(mObject, other.mObject); + return *this; } virtual ~BindingPointer() @@ -74,11 +120,12 @@ class BindingPointer ASSERT(mObject == nullptr); } - virtual void set(ObjectType *newObject) + virtual void set(const Context *context, 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(); + if (newObject != nullptr) reinterpret_cast(newObject)->addRef(); + if (mObject != nullptr) + reinterpret_cast(mObject)->release(context); mObject = newObject; } @@ -104,16 +151,16 @@ class OffsetBindingPointer : public BindingPointer public: OffsetBindingPointer() : mOffset(0), mSize(0) { } - void set(ObjectType *newObject) override + void set(const Context *context, ObjectType *newObject) override { - BindingPointer::set(newObject); + BindingPointer::set(context, newObject); mOffset = 0; mSize = 0; } - void set(ObjectType *newObject, GLintptr offset, GLsizeiptr size) + void set(const Context *context, ObjectType *newObject, GLintptr offset, GLsizeiptr size) { - BindingPointer::set(newObject); + BindingPointer::set(context, newObject); mOffset = offset; mSize = size; } @@ -135,5 +182,6 @@ class OffsetBindingPointer : public BindingPointer GLintptr mOffset; GLsizeiptr mSize; }; +} // namespace gl #endif // LIBANGLE_REFCOUNTOBJECT_H_ diff --git a/src/3rdparty/angle/src/libANGLE/Renderbuffer.cpp b/src/3rdparty/angle/src/libANGLE/Renderbuffer.cpp index 161fbea797..8310f1abda 100644 --- a/src/3rdparty/angle/src/libANGLE/Renderbuffer.cpp +++ b/src/3rdparty/angle/src/libANGLE/Renderbuffer.cpp @@ -25,11 +25,24 @@ Renderbuffer::Renderbuffer(rx::RenderbufferImpl *impl, GLuint id) mLabel(), mWidth(0), mHeight(0), - mInternalFormat(GL_RGBA4), - mSamples(0) + mFormat(GL_RGBA4), + mSamples(0), + mInitState(InitState::MayNeedInit) { } +Error Renderbuffer::onDestroy(const Context *context) +{ + ANGLE_TRY(orphanImages(context)); + + if (mRenderbuffer) + { + ANGLE_TRY(mRenderbuffer->onDestroy(context)); + } + + return NoError(); +} + Renderbuffer::~Renderbuffer() { SafeDelete(mRenderbuffer); @@ -45,70 +58,70 @@ const std::string &Renderbuffer::getLabel() const return mLabel; } -Error Renderbuffer::setStorage(GLenum internalformat, size_t width, size_t height) +Error Renderbuffer::setStorage(const Context *context, + GLenum internalformat, + size_t width, + size_t height) { - orphanImages(); + ANGLE_TRY(orphanImages(context)); - Error error = mRenderbuffer->setStorage(internalformat, width, height); - if (error.isError()) - { - return error; - } + ANGLE_TRY(mRenderbuffer->setStorage(context, internalformat, width, height)); mWidth = static_cast(width); mHeight = static_cast(height); - mInternalFormat = internalformat; + mFormat = Format(internalformat); mSamples = 0; - return Error(GL_NO_ERROR); + mInitState = InitState::MayNeedInit; + mDirtyChannel.signal(mInitState); + + return NoError(); } -Error Renderbuffer::setStorageMultisample(size_t samples, GLenum internalformat, size_t width, size_t height) +Error Renderbuffer::setStorageMultisample(const Context *context, + size_t samples, + GLenum internalformat, + size_t width, + size_t height) { - orphanImages(); + ANGLE_TRY(orphanImages(context)); - Error error = mRenderbuffer->setStorageMultisample(samples, internalformat, width, height); - if (error.isError()) - { - return error; - } + ANGLE_TRY( + mRenderbuffer->setStorageMultisample(context, samples, internalformat, width, height)); mWidth = static_cast(width); mHeight = static_cast(height); - mInternalFormat = internalformat; + mFormat = Format(internalformat); mSamples = static_cast(samples); - return Error(GL_NO_ERROR); + mInitState = InitState::MayNeedInit; + mDirtyChannel.signal(mInitState); + + return NoError(); } -Error Renderbuffer::setStorageEGLImageTarget(egl::Image *image) +Error Renderbuffer::setStorageEGLImageTarget(const Context *context, egl::Image *image) { - orphanImages(); + ANGLE_TRY(orphanImages(context)); - Error error = mRenderbuffer->setStorageEGLImageTarget(image); - if (error.isError()) - { - return error; - } + ANGLE_TRY(mRenderbuffer->setStorageEGLImageTarget(context, image)); - setTargetImage(image); + setTargetImage(context, image); mWidth = static_cast(image->getWidth()); mHeight = static_cast(image->getHeight()); - mInternalFormat = image->getInternalFormat(); + mFormat = Format(image->getFormat()); mSamples = 0; - return Error(GL_NO_ERROR); -} + mInitState = image->sourceInitState(); + mDirtyChannel.signal(mInitState); -rx::RenderbufferImpl *Renderbuffer::getImplementation() -{ - ASSERT(mRenderbuffer); - return mRenderbuffer; + return NoError(); } -const rx::RenderbufferImpl *Renderbuffer::getImplementation() const +rx::RenderbufferImpl *Renderbuffer::getImplementation() const { + ASSERT(mRenderbuffer); return mRenderbuffer; } @@ -122,9 +135,9 @@ GLsizei Renderbuffer::getHeight() const return mHeight; } -GLenum Renderbuffer::getInternalFormat() const +const Format &Renderbuffer::getFormat() const { - return mInternalFormat; + return mFormat; } GLsizei Renderbuffer::getSamples() const @@ -134,42 +147,42 @@ GLsizei Renderbuffer::getSamples() const GLuint Renderbuffer::getRedSize() const { - return GetInternalFormatInfo(mInternalFormat).redBits; + return mFormat.info->redBits; } GLuint Renderbuffer::getGreenSize() const { - return GetInternalFormatInfo(mInternalFormat).greenBits; + return mFormat.info->greenBits; } GLuint Renderbuffer::getBlueSize() const { - return GetInternalFormatInfo(mInternalFormat).blueBits; + return mFormat.info->blueBits; } GLuint Renderbuffer::getAlphaSize() const { - return GetInternalFormatInfo(mInternalFormat).alphaBits; + return mFormat.info->alphaBits; } GLuint Renderbuffer::getDepthSize() const { - return GetInternalFormatInfo(mInternalFormat).depthBits; + return mFormat.info->depthBits; } GLuint Renderbuffer::getStencilSize() const { - return GetInternalFormatInfo(mInternalFormat).stencilBits; + return mFormat.info->stencilBits; } -void Renderbuffer::onAttach() +void Renderbuffer::onAttach(const Context *context) { addRef(); } -void Renderbuffer::onDetach() +void Renderbuffer::onDetach(const Context *context) { - release(); + release(context); } GLuint Renderbuffer::getId() const @@ -177,8 +190,46 @@ GLuint Renderbuffer::getId() const return id(); } -Extents Renderbuffer::getAttachmentSize(const FramebufferAttachment::Target & /*target*/) const +Extents Renderbuffer::getAttachmentSize(const gl::ImageIndex & /*imageIndex*/) const { return Extents(mWidth, mHeight, 1); } + +const Format &Renderbuffer::getAttachmentFormat(GLenum /*binding*/, + const ImageIndex & /*imageIndex*/) const +{ + return getFormat(); +} +GLsizei Renderbuffer::getAttachmentSamples(const ImageIndex & /*imageIndex*/) const +{ + return getSamples(); } + +InitState Renderbuffer::initState(const gl::ImageIndex & /*imageIndex*/) const +{ + if (isEGLImageTarget()) + { + return sourceEGLImageInitState(); + } + + return mInitState; +} + +void Renderbuffer::setInitState(const gl::ImageIndex & /*imageIndex*/, InitState initState) +{ + if (isEGLImageTarget()) + { + setSourceEGLImageInitState(initState); + } + else + { + mInitState = initState; + } +} + +rx::FramebufferAttachmentObjectImpl *Renderbuffer::getAttachmentImpl() const +{ + return mRenderbuffer; +} + +} // namespace gl diff --git a/src/3rdparty/angle/src/libANGLE/Renderbuffer.h b/src/3rdparty/angle/src/libANGLE/Renderbuffer.h index 04af03e879..def18e6ff7 100644 --- a/src/3rdparty/angle/src/libANGLE/Renderbuffer.h +++ b/src/3rdparty/angle/src/libANGLE/Renderbuffer.h @@ -17,6 +17,7 @@ #include "libANGLE/Error.h" #include "libANGLE/FramebufferAttachment.h" #include "libANGLE/Image.h" +#include "libANGLE/formatutils.h" #include "libANGLE/renderer/RenderbufferImpl.h" namespace gl @@ -27,26 +28,30 @@ namespace gl // attachment point. class Renderbuffer final : public egl::ImageSibling, - public gl::FramebufferAttachmentObject, public LabeledObject { public: Renderbuffer(rx::RenderbufferImpl *impl, GLuint id); - virtual ~Renderbuffer(); + ~Renderbuffer() override; + + Error onDestroy(const Context *context) override; void setLabel(const std::string &label) override; const std::string &getLabel() const override; - Error setStorage(GLenum internalformat, size_t width, size_t height); - Error setStorageMultisample(size_t samples, GLenum internalformat, size_t width, size_t height); - Error setStorageEGLImageTarget(egl::Image *imageTarget); + Error setStorage(const Context *context, GLenum internalformat, size_t width, size_t height); + Error setStorageMultisample(const Context *context, + size_t samples, + GLenum internalformat, + size_t width, + size_t height); + Error setStorageEGLImageTarget(const Context *context, egl::Image *imageTarget); - rx::RenderbufferImpl *getImplementation(); - const rx::RenderbufferImpl *getImplementation() const; + rx::RenderbufferImpl *getImplementation() const; GLsizei getWidth() const; GLsizei getHeight() const; - GLenum getInternalFormat() const; + const Format &getFormat() const; GLsizei getSamples() const; GLuint getRedSize() const; GLuint getGreenSize() const; @@ -56,16 +61,19 @@ class Renderbuffer final : public egl::ImageSibling, GLuint getStencilSize() const; // FramebufferAttachmentObject Impl - Extents getAttachmentSize(const FramebufferAttachment::Target &target) const override; - GLenum getAttachmentInternalFormat(const FramebufferAttachment::Target &/*target*/) const override { return getInternalFormat(); } - GLsizei getAttachmentSamples(const FramebufferAttachment::Target &/*target*/) const override { return getSamples(); } + Extents getAttachmentSize(const ImageIndex &imageIndex) const override; + const Format &getAttachmentFormat(GLenum binding, const ImageIndex &imageIndex) const override; + GLsizei getAttachmentSamples(const ImageIndex &imageIndex) const override; - void onAttach() override; - void onDetach() override; + void onAttach(const Context *context) override; + void onDetach(const Context *context) override; GLuint getId() const override; + InitState initState(const ImageIndex &imageIndex) const override; + void setInitState(const ImageIndex &imageIndex, InitState initState) override; + private: - rx::FramebufferAttachmentObjectImpl *getAttachmentImpl() const override { return mRenderbuffer; } + rx::FramebufferAttachmentObjectImpl *getAttachmentImpl() const override; rx::RenderbufferImpl *mRenderbuffer; @@ -73,10 +81,13 @@ class Renderbuffer final : public egl::ImageSibling, GLsizei mWidth; GLsizei mHeight; - GLenum mInternalFormat; + Format mFormat; GLsizei mSamples; + + // For robust resource init. + InitState mInitState; }; -} +} // namespace gl #endif // LIBANGLE_RENDERBUFFER_H_ diff --git a/src/3rdparty/angle/src/libANGLE/ResourceManager.cpp b/src/3rdparty/angle/src/libANGLE/ResourceManager.cpp index dc9dad1e9f..79eb7e5f42 100644 --- a/src/3rdparty/angle/src/libANGLE/ResourceManager.cpp +++ b/src/3rdparty/angle/src/libANGLE/ResourceManager.cpp @@ -1,456 +1,483 @@ // -// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. +// Copyright (c) 2002-2016 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. +// ResourceManager.cpp: Implements the the ResourceManager classes, which handle allocation and +// lifetime of GL objects. #include "libANGLE/ResourceManager.h" #include "libANGLE/Buffer.h" +#include "libANGLE/Fence.h" +#include "libANGLE/Path.h" #include "libANGLE/Program.h" +#include "libANGLE/ProgramPipeline.h" #include "libANGLE/Renderbuffer.h" +#include "libANGLE/Sampler.h" #include "libANGLE/Shader.h" #include "libANGLE/Texture.h" -#include "libANGLE/Sampler.h" -#include "libANGLE/Fence.h" -#include "libANGLE/renderer/Renderer.h" +#include "libANGLE/renderer/GLImplFactory.h" namespace gl { -ResourceManager::ResourceManager(rx::ImplFactory *factory) - : mFactory(factory), - mRefCount(1) + +namespace +{ + +template +GLuint AllocateEmptyObject(HandleAllocator *handleAllocator, ResourceMap *objectMap) { + GLuint handle = handleAllocator->allocate(); + objectMap->assign(handle, nullptr); + return handle; } -ResourceManager::~ResourceManager() +} // anonymous namespace + +template +ResourceManagerBase::ResourceManagerBase() : mRefCount(1) { - while (!mBufferMap.empty()) - { - deleteBuffer(mBufferMap.begin()->first); - } +} - while (!mProgramMap.empty()) - { - deleteProgram(mProgramMap.begin()->first); - } +template +void ResourceManagerBase::addRef() +{ + mRefCount++; +} - while (!mShaderMap.empty()) +template +void ResourceManagerBase::release(const Context *context) +{ + if (--mRefCount == 0) { - deleteShader(mShaderMap.begin()->first); + reset(context); + delete this; } +} - while (!mRenderbufferMap.empty()) - { - deleteRenderbuffer(mRenderbufferMap.begin()->first); - } +template +TypedResourceManager::~TypedResourceManager() +{ + ASSERT(mObjectMap.empty()); +} - while (!mTextureMap.empty()) +template +void TypedResourceManager::reset(const Context *context) +{ + this->mHandleAllocator.reset(); + for (const auto &resource : mObjectMap) { - deleteTexture(mTextureMap.begin()->first); + if (resource.second) + { + ImplT::DeleteObject(context, resource.second); + } } + mObjectMap.clear(); +} - while (!mSamplerMap.empty()) +template +void TypedResourceManager::deleteObject( + const Context *context, + GLuint handle) +{ + ResourceType *resource = nullptr; + if (!mObjectMap.erase(handle, &resource)) { - deleteSampler(mSamplerMap.begin()->first); + return; } - while (!mFenceSyncMap.empty()) + // Requires an explicit this-> because of C++ template rules. + this->mHandleAllocator.release(handle); + + if (resource) { - deleteFenceSync(mFenceSyncMap.begin()->first); + ImplT::DeleteObject(context, resource); } } -void ResourceManager::addRef() +template class ResourceManagerBase; +template class ResourceManagerBase; +template class TypedResourceManager; +template class TypedResourceManager; +template class TypedResourceManager; +template class TypedResourceManager; +template class TypedResourceManager; +template class TypedResourceManager; +template class TypedResourceManager; + +// BufferManager Implementation. + +// static +Buffer *BufferManager::AllocateNewObject(rx::GLImplFactory *factory, GLuint handle) { - mRefCount++; + Buffer *buffer = new Buffer(factory, handle); + buffer->addRef(); + return buffer; } -void ResourceManager::release() +// static +void BufferManager::DeleteObject(const Context *context, Buffer *buffer) { - if (--mRefCount == 0) - { - delete this; - } + buffer->release(context); } -// Returns an unused buffer name -GLuint ResourceManager::createBuffer() +GLuint BufferManager::createBuffer() { - GLuint handle = mBufferHandleAllocator.allocate(); + return AllocateEmptyObject(&mHandleAllocator, &mObjectMap); +} - mBufferMap[handle] = NULL; +Buffer *BufferManager::getBuffer(GLuint handle) const +{ + return mObjectMap.query(handle); +} - return handle; +// ShaderProgramManager Implementation. + +ShaderProgramManager::ShaderProgramManager() +{ } -// Returns an unused shader/program name -GLuint ResourceManager::createShader(const gl::Limitations &rendererLimitations, GLenum type) +ShaderProgramManager::~ShaderProgramManager() { - GLuint handle = mProgramShaderHandleAllocator.allocate(); + ASSERT(mPrograms.empty()); + ASSERT(mShaders.empty()); +} - if (type == GL_VERTEX_SHADER || type == GL_FRAGMENT_SHADER) +void ShaderProgramManager::reset(const Context *context) +{ + while (!mPrograms.empty()) { - mShaderMap[handle] = new Shader(this, mFactory, rendererLimitations, type, handle); + deleteProgram(context, mPrograms.begin()->first); } - else UNREACHABLE(); - - return handle; + mPrograms.clear(); + while (!mShaders.empty()) + { + deleteShader(context, mShaders.begin()->first); + } + mShaders.clear(); } -// Returns an unused program/shader name -GLuint ResourceManager::createProgram() +GLuint ShaderProgramManager::createShader(rx::GLImplFactory *factory, + const gl::Limitations &rendererLimitations, + GLenum type) { - GLuint handle = mProgramShaderHandleAllocator.allocate(); - - mProgramMap[handle] = new Program(mFactory, this, handle); - + ASSERT(type == GL_VERTEX_SHADER || type == GL_FRAGMENT_SHADER || type == GL_COMPUTE_SHADER || + type == GL_GEOMETRY_SHADER_EXT); + GLuint handle = mHandleAllocator.allocate(); + mShaders.assign(handle, new Shader(this, factory, rendererLimitations, type, handle)); return handle; } -// Returns an unused texture name -GLuint ResourceManager::createTexture() +void ShaderProgramManager::deleteShader(const Context *context, GLuint shader) { - GLuint handle = mTextureHandleAllocator.allocate(); - - mTextureMap[handle] = NULL; - - return handle; + deleteObject(context, &mShaders, shader); } -// Returns an unused renderbuffer name -GLuint ResourceManager::createRenderbuffer() +Shader *ShaderProgramManager::getShader(GLuint handle) const { - GLuint handle = mRenderbufferHandleAllocator.allocate(); - - mRenderbufferMap[handle] = NULL; - - return handle; + return mShaders.query(handle); } -// Returns an unused sampler name -GLuint ResourceManager::createSampler() +GLuint ShaderProgramManager::createProgram(rx::GLImplFactory *factory) { - GLuint handle = mSamplerHandleAllocator.allocate(); - - mSamplerMap[handle] = NULL; - + GLuint handle = mHandleAllocator.allocate(); + mPrograms.assign(handle, new Program(factory, this, handle)); return handle; } -// Returns the next unused fence name, and allocates the fence -GLuint ResourceManager::createFenceSync() +void ShaderProgramManager::deleteProgram(const gl::Context *context, GLuint program) { - GLuint handle = mFenceSyncHandleAllocator.allocate(); - - FenceSync *fenceSync = new FenceSync(mFactory->createFenceSync(), handle); - fenceSync->addRef(); - mFenceSyncMap[handle] = fenceSync; + deleteObject(context, &mPrograms, program); +} - return handle; +Program *ShaderProgramManager::getProgram(GLuint handle) const +{ + return mPrograms.query(handle); } -void ResourceManager::deleteBuffer(GLuint buffer) +template +void ShaderProgramManager::deleteObject(const Context *context, + ResourceMap *objectMap, + GLuint id) { - BufferMap::iterator bufferObject = mBufferMap.find(buffer); + ObjectType *object = objectMap->query(id); + if (!object) + { + return; + } - if (bufferObject != mBufferMap.end()) + if (object->getRefCount() == 0) + { + mHandleAllocator.release(id); + object->onDestroy(context); + objectMap->erase(id, &object); + } + else { - mBufferHandleAllocator.release(bufferObject->first); - if (bufferObject->second) bufferObject->second->release(); - mBufferMap.erase(bufferObject); + object->flagForDeletion(); } } -void ResourceManager::deleteShader(GLuint shader) +// TextureManager Implementation. + +// static +Texture *TextureManager::AllocateNewObject(rx::GLImplFactory *factory, GLuint handle, GLenum target) { - ShaderMap::iterator shaderObject = mShaderMap.find(shader); + Texture *texture = new Texture(factory, handle, target); + texture->addRef(); + return texture; +} - if (shaderObject != mShaderMap.end()) - { - if (shaderObject->second->getRefCount() == 0) - { - mProgramShaderHandleAllocator.release(shaderObject->first); - delete shaderObject->second; - mShaderMap.erase(shaderObject); - } - else - { - shaderObject->second->flagForDeletion(); - } - } +// static +void TextureManager::DeleteObject(const Context *context, Texture *texture) +{ + texture->release(context); } -void ResourceManager::deleteProgram(GLuint program) +GLuint TextureManager::createTexture() { - ProgramMap::iterator programObject = mProgramMap.find(program); + return AllocateEmptyObject(&mHandleAllocator, &mObjectMap); +} + +Texture *TextureManager::getTexture(GLuint handle) const +{ + ASSERT(mObjectMap.query(0) == nullptr); + return mObjectMap.query(handle); +} - if (programObject != mProgramMap.end()) +void TextureManager::signalAllTexturesDirty() const +{ + for (const auto &texture : mObjectMap) { - if (programObject->second->getRefCount() == 0) + if (texture.second) { - mProgramShaderHandleAllocator.release(programObject->first); - delete programObject->second; - mProgramMap.erase(programObject); - } - else - { - programObject->second->flagForDeletion(); + // We don't know if the Texture needs init, but that's ok, since it will only force + // a re-check, and will not initialize the pixels if it's not needed. + texture.second->signalDirty(InitState::MayNeedInit); } } } -void ResourceManager::deleteTexture(GLuint texture) -{ - TextureMap::iterator textureObject = mTextureMap.find(texture); +// RenderbufferManager Implementation. - if (textureObject != mTextureMap.end()) - { - mTextureHandleAllocator.release(textureObject->first); - if (textureObject->second) textureObject->second->release(); - mTextureMap.erase(textureObject); - } +// static +Renderbuffer *RenderbufferManager::AllocateNewObject(rx::GLImplFactory *factory, GLuint handle) +{ + Renderbuffer *renderbuffer = new Renderbuffer(factory->createRenderbuffer(), handle); + renderbuffer->addRef(); + return renderbuffer; } -void ResourceManager::deleteRenderbuffer(GLuint renderbuffer) +// static +void RenderbufferManager::DeleteObject(const Context *context, Renderbuffer *renderbuffer) { - RenderbufferMap::iterator renderbufferObject = mRenderbufferMap.find(renderbuffer); + renderbuffer->release(context); +} - if (renderbufferObject != mRenderbufferMap.end()) - { - mRenderbufferHandleAllocator.release(renderbufferObject->first); - if (renderbufferObject->second) renderbufferObject->second->release(); - mRenderbufferMap.erase(renderbufferObject); - } +GLuint RenderbufferManager::createRenderbuffer() +{ + return AllocateEmptyObject(&mHandleAllocator, &mObjectMap); } -void ResourceManager::deleteSampler(GLuint sampler) +Renderbuffer *RenderbufferManager::getRenderbuffer(GLuint handle) const { - auto samplerObject = mSamplerMap.find(sampler); + return mObjectMap.query(handle); +} - if (samplerObject != mSamplerMap.end()) - { - mSamplerHandleAllocator.release(samplerObject->first); - if (samplerObject->second) samplerObject->second->release(); - mSamplerMap.erase(samplerObject); - } +// SamplerManager Implementation. + +// static +Sampler *SamplerManager::AllocateNewObject(rx::GLImplFactory *factory, GLuint handle) +{ + Sampler *sampler = new Sampler(factory, handle); + sampler->addRef(); + return sampler; } -void ResourceManager::deleteFenceSync(GLuint fenceSync) +// static +void SamplerManager::DeleteObject(const Context *context, Sampler *sampler) { - auto fenceObjectIt = mFenceSyncMap.find(fenceSync); + sampler->release(context); +} - if (fenceObjectIt != mFenceSyncMap.end()) - { - mFenceSyncHandleAllocator.release(fenceObjectIt->first); - if (fenceObjectIt->second) fenceObjectIt->second->release(); - mFenceSyncMap.erase(fenceObjectIt); - } +GLuint SamplerManager::createSampler() +{ + return AllocateEmptyObject(&mHandleAllocator, &mObjectMap); } -Buffer *ResourceManager::getBuffer(unsigned int handle) +Sampler *SamplerManager::getSampler(GLuint handle) const { - BufferMap::iterator buffer = mBufferMap.find(handle); + return mObjectMap.query(handle); +} - if (buffer == mBufferMap.end()) - { - return NULL; - } - else - { - return buffer->second; - } +bool SamplerManager::isSampler(GLuint sampler) const +{ + return mObjectMap.contains(sampler); } -Shader *ResourceManager::getShader(unsigned int handle) +// SyncManager Implementation. + +// static +void SyncManager::DeleteObject(const Context *context, Sync *sync) { - ShaderMap::iterator shader = mShaderMap.find(handle); + sync->release(context); +} - if (shader == mShaderMap.end()) - { - return NULL; - } - else - { - return shader->second; - } +GLuint SyncManager::createSync(rx::GLImplFactory *factory) +{ + GLuint handle = mHandleAllocator.allocate(); + Sync *sync = new Sync(factory->createSync(), handle); + sync->addRef(); + mObjectMap.assign(handle, sync); + return handle; } -Texture *ResourceManager::getTexture(unsigned int handle) +Sync *SyncManager::getSync(GLuint handle) const { - if (handle == 0) return NULL; + return mObjectMap.query(handle); +} - TextureMap::iterator texture = mTextureMap.find(handle); +// PathManager Implementation. - if (texture == mTextureMap.end()) - { - return NULL; - } - else - { - return texture->second; - } +PathManager::PathManager() +{ } -Program *ResourceManager::getProgram(unsigned int handle) const +ErrorOrResult PathManager::createPaths(rx::GLImplFactory *factory, GLsizei range) { - ProgramMap::const_iterator program = mProgramMap.find(handle); + // Allocate client side handles. + const GLuint client = mHandleAllocator.allocateRange(static_cast(range)); + if (client == HandleRangeAllocator::kInvalidHandle) + return OutOfMemory() << "Failed to allocate path handle range."; - if (program == mProgramMap.end()) + const auto &paths = factory->createPaths(range); + if (paths.empty()) { - return NULL; + mHandleAllocator.releaseRange(client, range); + return OutOfMemory() << "Failed to allocate path objects."; } - else + + for (GLsizei i = 0; i < range; ++i) { - return program->second; + rx::PathImpl *impl = paths[static_cast(i)]; + const auto id = client + i; + mPaths.assign(id, new Path(impl)); } + return client; } -Renderbuffer *ResourceManager::getRenderbuffer(unsigned int handle) +void PathManager::deletePaths(GLuint first, GLsizei range) { - RenderbufferMap::iterator renderbuffer = mRenderbufferMap.find(handle); - - if (renderbuffer == mRenderbufferMap.end()) + for (GLsizei i = 0; i < range; ++i) { - return NULL; - } - else - { - return renderbuffer->second; + const auto id = first + i; + Path *p = nullptr; + if (!mPaths.erase(id, &p)) + continue; + delete p; } + mHandleAllocator.releaseRange(first, static_cast(range)); } -Sampler *ResourceManager::getSampler(unsigned int handle) +Path *PathManager::getPath(GLuint handle) const { - auto sampler = mSamplerMap.find(handle); + return mPaths.query(handle); +} - if (sampler == mSamplerMap.end()) - { - return NULL; - } - else - { - return sampler->second; - } +bool PathManager::hasPath(GLuint handle) const +{ + return mHandleAllocator.isUsed(handle); } -FenceSync *ResourceManager::getFenceSync(unsigned int handle) +PathManager::~PathManager() { - auto fenceObjectIt = mFenceSyncMap.find(handle); + ASSERT(mPaths.empty()); +} - if (fenceObjectIt == mFenceSyncMap.end()) - { - return NULL; - } - else +void PathManager::reset(const Context *context) +{ + for (auto path : mPaths) { - return fenceObjectIt->second; + SafeDelete(path.second); } + mPaths.clear(); } -void ResourceManager::setRenderbuffer(GLuint handle, Renderbuffer *buffer) +// FramebufferManager Implementation. + +// static +Framebuffer *FramebufferManager::AllocateNewObject(rx::GLImplFactory *factory, + GLuint handle, + const Caps &caps) { - mRenderbufferMap[handle] = buffer; + return new Framebuffer(caps, factory, handle); } -void ResourceManager::checkBufferAllocation(GLuint handle) +// static +void FramebufferManager::DeleteObject(const Context *context, Framebuffer *framebuffer) { - if (handle != 0) + // Default framebuffer are owned by their respective Surface + if (framebuffer->id() != 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; - } + framebuffer->onDestroy(context); + delete framebuffer; } } -void ResourceManager::checkTextureAllocation(GLuint handle, GLenum type) +GLuint FramebufferManager::createFramebuffer() { - if (handle != 0) - { - auto textureMapIt = mTextureMap.find(handle); - bool handleAllocated = (textureMapIt != mTextureMap.end()); - - if (handleAllocated && textureMapIt->second != nullptr) - { - return; - } + return AllocateEmptyObject(&mHandleAllocator, &mObjectMap); +} - Texture *texture = new Texture(mFactory->createTexture(type), handle, type); - texture->addRef(); +Framebuffer *FramebufferManager::getFramebuffer(GLuint handle) const +{ + return mObjectMap.query(handle); +} - if (handleAllocated) - { - textureMapIt->second = texture; - } - else - { - mTextureHandleAllocator.reserve(handle); - mTextureMap[handle] = texture; - } - } +void FramebufferManager::setDefaultFramebuffer(Framebuffer *framebuffer) +{ + ASSERT(framebuffer == nullptr || framebuffer->id() == 0); + mObjectMap.assign(0, framebuffer); } -void ResourceManager::checkRenderbufferAllocation(GLuint handle) +void FramebufferManager::invalidateFramebufferComplenessCache() const { - if (handle != 0) + for (const auto &framebuffer : mObjectMap) { - auto renderbufferMapIt = mRenderbufferMap.find(handle); - bool handleAllocated = (renderbufferMapIt != mRenderbufferMap.end()); - - if (handleAllocated && renderbufferMapIt->second != nullptr) + if (framebuffer.second) { - return; + framebuffer.second->invalidateCompletenessCache(); } + } +} - Renderbuffer *renderbuffer = new Renderbuffer(mFactory->createRenderbuffer(), handle); - renderbuffer->addRef(); +// ProgramPipelineManager Implementation. - if (handleAllocated) - { - renderbufferMapIt->second = renderbuffer; - } - else - { - mRenderbufferHandleAllocator.reserve(handle); - mRenderbufferMap[handle] = renderbuffer; - } - } +// static +ProgramPipeline *ProgramPipelineManager::AllocateNewObject(rx::GLImplFactory *factory, + GLuint handle) +{ + ProgramPipeline *pipeline = new ProgramPipeline(factory, handle); + pipeline->addRef(); + return pipeline; } -void ResourceManager::checkSamplerAllocation(GLuint sampler) +// static +void ProgramPipelineManager::DeleteObject(const Context *context, ProgramPipeline *pipeline) { - if (sampler != 0 && !getSampler(sampler)) - { - Sampler *samplerObject = new Sampler(mFactory, sampler); - mSamplerMap[sampler] = samplerObject; - samplerObject->addRef(); - // Samplers cannot be created via Bind - } + pipeline->release(context); } -bool ResourceManager::isSampler(GLuint sampler) +GLuint ProgramPipelineManager::createProgramPipeline() { - return mSamplerMap.find(sampler) != mSamplerMap.end(); + return AllocateEmptyObject(&mHandleAllocator, &mObjectMap); } +ProgramPipeline *ProgramPipelineManager::getProgramPipeline(GLuint handle) const +{ + return mObjectMap.query(handle); } + +} // namespace gl diff --git a/src/3rdparty/angle/src/libANGLE/ResourceManager.h b/src/3rdparty/angle/src/libANGLE/ResourceManager.h index 2073e9d728..2dfeff5234 100644 --- a/src/3rdparty/angle/src/libANGLE/ResourceManager.h +++ b/src/3rdparty/angle/src/libANGLE/ResourceManager.h @@ -1,115 +1,289 @@ // -// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. +// Copyright (c) 2002-2016 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. +// ResourceManager.h : Defines the ResourceManager classes, which handle allocation and lifetime of +// GL objects. #ifndef LIBANGLE_RESOURCEMANAGER_H_ #define LIBANGLE_RESOURCEMANAGER_H_ #include "angle_gl.h" #include "common/angleutils.h" -#include "libANGLE/angletypes.h" +#include "libANGLE/Error.h" #include "libANGLE/HandleAllocator.h" - -#include +#include "libANGLE/HandleRangeAllocator.h" +#include "libANGLE/ResourceMap.h" namespace rx { -class ImplFactory; +class GLImplFactory; } namespace gl { class Buffer; -struct Data; -class FenceSync; +struct Caps; +class Context; +class Sync; +class Framebuffer; struct Limitations; +class Path; class Program; +class ProgramPipeline; class Renderbuffer; class Sampler; class Shader; class Texture; -class ResourceManager : angle::NonCopyable +template +class ResourceManagerBase : angle::NonCopyable { public: - explicit ResourceManager(rx::ImplFactory *factory); - ~ResourceManager(); + ResourceManagerBase(); void addRef(); - void release(); + void release(const Context *context); + + protected: + virtual void reset(const Context *context) = 0; + virtual ~ResourceManagerBase() {} + + HandleAllocatorType mHandleAllocator; + + private: + size_t mRefCount; +}; + +template +class TypedResourceManager : public ResourceManagerBase +{ + public: + TypedResourceManager() {} + + void deleteObject(const Context *context, GLuint handle); + bool isHandleGenerated(GLuint handle) const + { + // Zero is always assumed to have been generated implicitly. + return handle == 0 || mObjectMap.contains(handle); + } + + protected: + ~TypedResourceManager() override; + + // Inlined in the header for performance. + template + ResourceType *checkObjectAllocation(rx::GLImplFactory *factory, GLuint handle, ArgTypes... args) + { + ResourceType *value = mObjectMap.query(handle); + if (value) + { + return value; + } + + if (handle == 0) + { + return nullptr; + } + + ResourceType *object = ImplT::AllocateNewObject(factory, handle, args...); + + if (!mObjectMap.contains(handle)) + { + this->mHandleAllocator.reserve(handle); + } + mObjectMap.assign(handle, object); + + return object; + } + + void reset(const Context *context) override; + + ResourceMap mObjectMap; +}; +class BufferManager : public TypedResourceManager +{ + public: GLuint createBuffer(); - GLuint createShader(const gl::Limitations &rendererLimitations, GLenum type); - GLuint createProgram(); + Buffer *getBuffer(GLuint handle) const; + + Buffer *checkBufferAllocation(rx::GLImplFactory *factory, GLuint handle) + { + return checkObjectAllocation(factory, handle); + } + + // TODO(jmadill): Investigate design which doesn't expose these methods publicly. + static Buffer *AllocateNewObject(rx::GLImplFactory *factory, GLuint handle); + static void DeleteObject(const Context *context, Buffer *buffer); + + protected: + ~BufferManager() override {} +}; + +class ShaderProgramManager : public ResourceManagerBase +{ + public: + ShaderProgramManager(); + + GLuint createShader(rx::GLImplFactory *factory, + const Limitations &rendererLimitations, + GLenum type); + void deleteShader(const Context *context, GLuint shader); + Shader *getShader(GLuint handle) const; + + GLuint createProgram(rx::GLImplFactory *factory); + void deleteProgram(const Context *context, GLuint program); + Program *getProgram(GLuint handle) const; + + protected: + ~ShaderProgramManager() override; + + private: + template + void deleteObject(const Context *context, ResourceMap *objectMap, GLuint id); + + void reset(const Context *context) override; + + ResourceMap mShaders; + ResourceMap mPrograms; +}; + +class TextureManager : public TypedResourceManager +{ + public: GLuint createTexture(); + Texture *getTexture(GLuint handle) const; + + void signalAllTexturesDirty() const; + + Texture *checkTextureAllocation(rx::GLImplFactory *factory, GLuint handle, GLenum target) + { + return checkObjectAllocation(factory, handle, target); + } + + static Texture *AllocateNewObject(rx::GLImplFactory *factory, GLuint handle, GLenum target); + static void DeleteObject(const Context *context, Texture *texture); + + protected: + ~TextureManager() override {} +}; + +class RenderbufferManager + : public TypedResourceManager +{ + public: GLuint createRenderbuffer(); + Renderbuffer *getRenderbuffer(GLuint handle) const; + + Renderbuffer *checkRenderbufferAllocation(rx::GLImplFactory *factory, GLuint handle) + { + return checkObjectAllocation(factory, handle); + } + + static Renderbuffer *AllocateNewObject(rx::GLImplFactory *factory, GLuint handle); + static void DeleteObject(const Context *context, Renderbuffer *renderbuffer); + + protected: + ~RenderbufferManager() override {} +}; + +class SamplerManager : public TypedResourceManager +{ + public: 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); + Sampler *getSampler(GLuint handle) const; + bool isSampler(GLuint sampler) const; + + Sampler *checkSamplerAllocation(rx::GLImplFactory *factory, GLuint handle) + { + return checkObjectAllocation(factory, handle); + } - void setRenderbuffer(GLuint handle, Renderbuffer *renderbuffer); + static Sampler *AllocateNewObject(rx::GLImplFactory *factory, GLuint handle); + static void DeleteObject(const Context *context, Sampler *sampler); - void checkBufferAllocation(GLuint handle); - void checkTextureAllocation(GLuint handle, GLenum type); - void checkRenderbufferAllocation(GLuint handle); - void checkSamplerAllocation(GLuint sampler); + protected: + ~SamplerManager() override {} +}; + +class SyncManager : public TypedResourceManager +{ + public: + GLuint createSync(rx::GLImplFactory *factory); + Sync *getSync(GLuint handle) const; + + static void DeleteObject(const Context *context, Sync *sync); + + protected: + ~SyncManager() override {} +}; + +class PathManager : public ResourceManagerBase +{ + public: + PathManager(); - bool isSampler(GLuint sampler); + ErrorOrResult createPaths(rx::GLImplFactory *factory, GLsizei range); + void deletePaths(GLuint first, GLsizei range); + Path *getPath(GLuint handle) const; + bool hasPath(GLuint handle) const; + + protected: + ~PathManager() override; + void reset(const Context *context) override; private: - void createTextureInternal(GLuint handle); + ResourceMap mPaths; +}; - rx::ImplFactory *mFactory; - std::size_t mRefCount; +class FramebufferManager + : public TypedResourceManager +{ + public: + GLuint createFramebuffer(); + Framebuffer *getFramebuffer(GLuint handle) const; + void setDefaultFramebuffer(Framebuffer *framebuffer); - typedef std::map BufferMap; - BufferMap mBufferMap; - HandleAllocator mBufferHandleAllocator; + void invalidateFramebufferComplenessCache() const; - typedef std::map ShaderMap; - ShaderMap mShaderMap; + Framebuffer *checkFramebufferAllocation(rx::GLImplFactory *factory, + const Caps &caps, + GLuint handle) + { + return checkObjectAllocation(factory, handle, caps); + } - typedef std::map ProgramMap; - ProgramMap mProgramMap; - HandleAllocator mProgramShaderHandleAllocator; + static Framebuffer *AllocateNewObject(rx::GLImplFactory *factory, + GLuint handle, + const Caps &caps); + static void DeleteObject(const Context *context, Framebuffer *framebuffer); - typedef std::map TextureMap; - TextureMap mTextureMap; - HandleAllocator mTextureHandleAllocator; + protected: + ~FramebufferManager() override {} +}; - typedef std::map RenderbufferMap; - RenderbufferMap mRenderbufferMap; - HandleAllocator mRenderbufferHandleAllocator; +class ProgramPipelineManager + : public TypedResourceManager +{ + public: + GLuint createProgramPipeline(); + ProgramPipeline *getProgramPipeline(GLuint handle) const; - typedef std::map SamplerMap; - SamplerMap mSamplerMap; - HandleAllocator mSamplerHandleAllocator; + ProgramPipeline *checkProgramPipelineAllocation(rx::GLImplFactory *factory, GLuint handle) + { + return checkObjectAllocation(factory, handle); + } - typedef std::map FenceMap; - FenceMap mFenceSyncMap; - HandleAllocator mFenceSyncHandleAllocator; + static ProgramPipeline *AllocateNewObject(rx::GLImplFactory *factory, GLuint handle); + static void DeleteObject(const Context *context, ProgramPipeline *pipeline); + + protected: + ~ProgramPipelineManager() override {} }; -} +} // namespace gl #endif // LIBANGLE_RESOURCEMANAGER_H_ diff --git a/src/3rdparty/angle/src/libANGLE/ResourceMap.h b/src/3rdparty/angle/src/libANGLE/ResourceMap.h new file mode 100644 index 0000000000..b00da68612 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/ResourceMap.h @@ -0,0 +1,305 @@ +// +// Copyright 2017 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. +// +// ResourceMap: +// An optimized resource map which packs the first set of allocated objects into a +// flat array, and then falls back to an unordered map for the higher handle values. +// + +#ifndef LIBANGLE_RESOURCE_MAP_H_ +#define LIBANGLE_RESOURCE_MAP_H_ + +#include "libANGLE/angletypes.h" + +namespace gl +{ + +template +class ResourceMap final : angle::NonCopyable +{ + public: + ResourceMap(); + ~ResourceMap(); + + ResourceType *query(GLuint handle) const; + + // Returns true if the handle was reserved. Not necessarily if the resource is created. + bool contains(GLuint handle) const; + + // Returns the element that was at this location. + bool erase(GLuint handle, ResourceType **resourceOut); + + void assign(GLuint handle, ResourceType *resource); + + // Clears the map. + void clear(); + + using IndexAndResource = std::pair; + using HashMap = std::unordered_map; + + class Iterator final + { + public: + bool operator==(const Iterator &other) const; + bool operator!=(const Iterator &other) const; + Iterator &operator++(); + const IndexAndResource *operator->() const; + const IndexAndResource &operator*() const; + + private: + friend class ResourceMap; + Iterator(const ResourceMap &origin, + GLuint flatIndex, + typename HashMap::const_iterator hashIndex); + void updateValue(); + + const ResourceMap &mOrigin; + GLuint mFlatIndex; + typename HashMap::const_iterator mHashIndex; + IndexAndResource mValue; + }; + + // null values represent reserved handles. + Iterator begin() const; + Iterator end() const; + Iterator find(GLuint handle) const; + + // Not a constant-time operation, should only be used for verification. + bool empty() const; + + private: + friend class Iterator; + + GLuint nextNonNullResource(size_t flatIndex) const; + + // constexpr methods cannot contain reinterpret_cast, so we need a static method. + static ResourceType *InvalidPointer(); + static constexpr intptr_t kInvalidPointer = static_cast(-1); + + // Start with 32 maximum elements in the map, which can grow. + static constexpr size_t kInitialFlatResourcesSize = 0x20; + + // Experimental testing suggests that 16k is a reasonable upper limit. + static constexpr size_t kFlatResourcesLimit = 0x4000; + + std::vector mFlatResources; + + // A map of GL objects indexed by object ID. + HashMap mHashedResources; +}; + +template +ResourceMap::ResourceMap() + : mFlatResources(kInitialFlatResourcesSize, InvalidPointer()), mHashedResources() +{ +} + +template +ResourceMap::~ResourceMap() +{ + ASSERT(empty()); +} + +template +ResourceType *ResourceMap::query(GLuint handle) const +{ + if (handle < mFlatResources.size()) + { + auto value = mFlatResources[handle]; + return (value == InvalidPointer() ? nullptr : value); + } + auto it = mHashedResources.find(handle); + return (it == mHashedResources.end() ? nullptr : it->second); +} + +template +bool ResourceMap::contains(GLuint handle) const +{ + if (handle < mFlatResources.size()) + { + return (mFlatResources[handle] != InvalidPointer()); + } + return (mHashedResources.find(handle) != mHashedResources.end()); +} + +template +bool ResourceMap::erase(GLuint handle, ResourceType **resourceOut) +{ + if (handle < mFlatResources.size()) + { + auto &value = mFlatResources[handle]; + if (value == InvalidPointer()) + { + return false; + } + *resourceOut = value; + value = InvalidPointer(); + } + else + { + auto it = mHashedResources.find(handle); + if (it == mHashedResources.end()) + { + return false; + } + *resourceOut = it->second; + mHashedResources.erase(it); + } + return true; +} + +template +void ResourceMap::assign(GLuint handle, ResourceType *resource) +{ + if (handle < kFlatResourcesLimit) + { + if (handle >= mFlatResources.size()) + { + // Use power-of-two. + size_t newSize = mFlatResources.size(); + while (newSize <= handle) + { + newSize *= 2; + } + mFlatResources.resize(newSize, nullptr); + } + ASSERT(mFlatResources.size() > handle); + mFlatResources[handle] = resource; + } + else + { + mHashedResources[handle] = resource; + } +} + +template +typename ResourceMap::Iterator ResourceMap::begin() const +{ + return Iterator(*this, nextNonNullResource(0), mHashedResources.begin()); +} + +template +typename ResourceMap::Iterator ResourceMap::end() const +{ + return Iterator(*this, static_cast(mFlatResources.size()), mHashedResources.end()); +} + +template +typename ResourceMap::Iterator ResourceMap::find(GLuint handle) const +{ + if (handle < mFlatResources.size()) + { + return (mFlatResources[handle] != InvalidPointer() + ? Iterator(handle, mHashedResources.begin()) + : end()); + } + else + { + return mHashedResources.find(handle); + } +} + +template +bool ResourceMap::empty() const +{ + return (begin() == end()); +} + +template +void ResourceMap::clear() +{ + mFlatResources.assign(kInitialFlatResourcesSize, InvalidPointer()); + mHashedResources.clear(); +} + +template +GLuint ResourceMap::nextNonNullResource(size_t flatIndex) const +{ + for (size_t index = flatIndex; index < mFlatResources.size(); index++) + { + if (mFlatResources[index] != nullptr && mFlatResources[index] != InvalidPointer()) + { + return static_cast(index); + } + } + return static_cast(mFlatResources.size()); +} + +template +// static +ResourceType *ResourceMap::InvalidPointer() +{ + return reinterpret_cast(kInvalidPointer); +} + +template +ResourceMap::Iterator::Iterator( + const ResourceMap &origin, + GLuint flatIndex, + typename ResourceMap::HashMap::const_iterator hashIndex) + : mOrigin(origin), mFlatIndex(flatIndex), mHashIndex(hashIndex), mValue() +{ + updateValue(); +} + +template +bool ResourceMap::Iterator::operator==(const Iterator &other) const +{ + return (mFlatIndex == other.mFlatIndex && mHashIndex == other.mHashIndex); +} + +template +bool ResourceMap::Iterator::operator!=(const Iterator &other) const +{ + return !(*this == other); +} + +template +typename ResourceMap::Iterator &ResourceMap::Iterator::operator++() +{ + if (mFlatIndex < static_cast(mOrigin.mFlatResources.size())) + { + mFlatIndex = mOrigin.nextNonNullResource(mFlatIndex + 1); + } + else + { + mHashIndex++; + } + updateValue(); + return *this; +} + +template +const typename ResourceMap::IndexAndResource + *ResourceMap::Iterator::operator->() const +{ + return &mValue; +} + +template +const typename ResourceMap::IndexAndResource + &ResourceMap::Iterator::operator*() const +{ + return mValue; +} + +template +void ResourceMap::Iterator::updateValue() +{ + if (mFlatIndex < static_cast(mOrigin.mFlatResources.size())) + { + mValue.first = mFlatIndex; + mValue.second = mOrigin.mFlatResources[mFlatIndex]; + } + else if (mHashIndex != mOrigin.mHashedResources.end()) + { + mValue.first = mHashIndex->first; + mValue.second = mHashIndex->second; + } +} + +} // namespace gl + +#endif // LIBANGLE_RESOURCE_MAP_H_ diff --git a/src/3rdparty/angle/src/libANGLE/Sampler.cpp b/src/3rdparty/angle/src/libANGLE/Sampler.cpp index d8d606a46f..0f05b697a2 100644 --- a/src/3rdparty/angle/src/libANGLE/Sampler.cpp +++ b/src/3rdparty/angle/src/libANGLE/Sampler.cpp @@ -9,14 +9,14 @@ #include "libANGLE/Sampler.h" #include "libANGLE/angletypes.h" -#include "libANGLE/renderer/ImplFactory.h" +#include "libANGLE/renderer/GLImplFactory.h" #include "libANGLE/renderer/SamplerImpl.h" namespace gl { -Sampler::Sampler(rx::ImplFactory *factory, GLuint id) - : RefCountObject(id), mImpl(factory->createSampler()), mLabel(), mSamplerState() +Sampler::Sampler(rx::GLImplFactory *factory, GLuint id) + : RefCountObject(id), mState(), mImpl(factory->createSampler(mState)), mLabel() { } @@ -25,6 +25,11 @@ Sampler::~Sampler() SafeDelete(mImpl); } +Error Sampler::onDestroy(const Context *context) +{ + return NoError(); +} + void Sampler::setLabel(const std::string &label) { mLabel = label; @@ -37,116 +42,128 @@ const std::string &Sampler::getLabel() const void Sampler::setMinFilter(GLenum minFilter) { - mSamplerState.minFilter = minFilter; + mState.minFilter = minFilter; } GLenum Sampler::getMinFilter() const { - return mSamplerState.minFilter; + return mState.minFilter; } void Sampler::setMagFilter(GLenum magFilter) { - mSamplerState.magFilter = magFilter; + mState.magFilter = magFilter; } GLenum Sampler::getMagFilter() const { - return mSamplerState.magFilter; + return mState.magFilter; } void Sampler::setWrapS(GLenum wrapS) { - mSamplerState.wrapS = wrapS; + mState.wrapS = wrapS; } GLenum Sampler::getWrapS() const { - return mSamplerState.wrapS; + return mState.wrapS; } void Sampler::setWrapT(GLenum wrapT) { - mSamplerState.wrapT = wrapT; + mState.wrapT = wrapT; } GLenum Sampler::getWrapT() const { - return mSamplerState.wrapT; + return mState.wrapT; } void Sampler::setWrapR(GLenum wrapR) { - mSamplerState.wrapR = wrapR; + mState.wrapR = wrapR; } GLenum Sampler::getWrapR() const { - return mSamplerState.wrapR; + return mState.wrapR; } void Sampler::setMaxAnisotropy(float maxAnisotropy) { - mSamplerState.maxAnisotropy = maxAnisotropy; + mState.maxAnisotropy = maxAnisotropy; } float Sampler::getMaxAnisotropy() const { - return mSamplerState.maxAnisotropy; + return mState.maxAnisotropy; } void Sampler::setMinLod(GLfloat minLod) { - mSamplerState.minLod = minLod; + mState.minLod = minLod; } GLfloat Sampler::getMinLod() const { - return mSamplerState.minLod; + return mState.minLod; } void Sampler::setMaxLod(GLfloat maxLod) { - mSamplerState.maxLod = maxLod; + mState.maxLod = maxLod; } GLfloat Sampler::getMaxLod() const { - return mSamplerState.maxLod; + return mState.maxLod; } void Sampler::setCompareMode(GLenum compareMode) { - mSamplerState.compareMode = compareMode; + mState.compareMode = compareMode; } GLenum Sampler::getCompareMode() const { - return mSamplerState.compareMode; + return mState.compareMode; } void Sampler::setCompareFunc(GLenum compareFunc) { - mSamplerState.compareFunc = compareFunc; + mState.compareFunc = compareFunc; } GLenum Sampler::getCompareFunc() const { - return mSamplerState.compareFunc; + return mState.compareFunc; } -const SamplerState &Sampler::getSamplerState() const +void Sampler::setSRGBDecode(GLenum sRGBDecode) { - return mSamplerState; + mState.sRGBDecode = sRGBDecode; } -const rx::SamplerImpl *Sampler::getImplementation() const +GLenum Sampler::getSRGBDecode() const { - return mImpl; + return mState.sRGBDecode; +} + +const SamplerState &Sampler::getSamplerState() const +{ + return mState; } -rx::SamplerImpl *Sampler::getImplementation() +rx::SamplerImpl *Sampler::getImplementation() const { return mImpl; } + +void Sampler::syncState(const Context *context) +{ + // TODO(jmadill): Use actual dirty bits for sampler. + mImpl->syncState(context); } + +} // namespace gl diff --git a/src/3rdparty/angle/src/libANGLE/Sampler.h b/src/3rdparty/angle/src/libANGLE/Sampler.h index a40b1655fc..cd34273b44 100644 --- a/src/3rdparty/angle/src/libANGLE/Sampler.h +++ b/src/3rdparty/angle/src/libANGLE/Sampler.h @@ -16,7 +16,7 @@ namespace rx { -class ImplFactory; +class GLImplFactory; class SamplerImpl; } @@ -26,9 +26,11 @@ namespace gl class Sampler final : public RefCountObject, public LabeledObject { public: - Sampler(rx::ImplFactory *factory, GLuint id); + Sampler(rx::GLImplFactory *factory, GLuint id); ~Sampler() override; + Error onDestroy(const Context *context) override; + void setLabel(const std::string &label) override; const std::string &getLabel() const override; @@ -62,19 +64,22 @@ class Sampler final : public RefCountObject, public LabeledObject void setCompareFunc(GLenum compareFunc); GLenum getCompareFunc() const; + void setSRGBDecode(GLenum sRGBDecode); + GLenum getSRGBDecode() const; + const SamplerState &getSamplerState() const; - const rx::SamplerImpl *getImplementation() const; - rx::SamplerImpl *getImplementation(); + rx::SamplerImpl *getImplementation() const; + + void syncState(const Context *context); private: + SamplerState mState; rx::SamplerImpl *mImpl; std::string mLabel; - - SamplerState mSamplerState; }; -} +} // namespace gl #endif // LIBANGLE_SAMPLER_H_ diff --git a/src/3rdparty/angle/src/libANGLE/Shader.cpp b/src/3rdparty/angle/src/libANGLE/Shader.cpp index bbe9077fc9..94c4f3c705 100644 --- a/src/3rdparty/angle/src/libANGLE/Shader.cpp +++ b/src/3rdparty/angle/src/libANGLE/Shader.cpp @@ -14,11 +14,13 @@ #include "common/utilities.h" #include "GLSLANG/ShaderLang.h" +#include "libANGLE/Caps.h" #include "libANGLE/Compiler.h" #include "libANGLE/Constants.h" -#include "libANGLE/renderer/Renderer.h" +#include "libANGLE/renderer/GLImplFactory.h" #include "libANGLE/renderer/ShaderImpl.h" #include "libANGLE/ResourceManager.h" +#include "libANGLE/Context.h" namespace gl { @@ -55,16 +57,16 @@ bool CompareShaderVar(const sh::ShaderVariable &x, const sh::ShaderVariable &y) { if (x.type == y.type) { - return x.arraySize > y.arraySize; + return x.getArraySizeProduct() > y.getArraySizeProduct(); } // Special case for handling structs: we sort these to the end of the list - if (x.type == GL_STRUCT_ANGLEX) + if (x.type == GL_NONE) { return false; } - if (y.type == GL_STRUCT_ANGLEX) + if (y.type == GL_NONE) { return true; } @@ -72,45 +74,61 @@ bool CompareShaderVar(const sh::ShaderVariable &x, const sh::ShaderVariable &y) return gl::VariableSortOrder(x.type) < gl::VariableSortOrder(y.type); } -Shader::Data::Data(GLenum shaderType) : mLabel(), mShaderType(shaderType), mShaderVersion(100) +ShaderState::ShaderState(GLenum shaderType) + : mLabel(), + mShaderType(shaderType), + mShaderVersion(100), + mNumViews(-1), + mGeometryShaderInputPrimitiveType(GL_INVALID_VALUE), + mGeometryShaderOutputPrimitiveType(GL_INVALID_VALUE), + mGeometryShaderInvocations(1), + mGeometryShaderMaxVertices(-1), + mCompileStatus(CompileStatus::NOT_COMPILED) { + mLocalSize.fill(-1); } -Shader::Data::~Data() +ShaderState::~ShaderState() { } -Shader::Shader(ResourceManager *manager, - rx::ImplFactory *implFactory, +Shader::Shader(ShaderProgramManager *manager, + rx::GLImplFactory *implFactory, const gl::Limitations &rendererLimitations, GLenum type, GLuint handle) - : mData(type), - mImplementation(implFactory->createShader(mData)), + : mState(type), + mImplementation(implFactory->createShader(mState)), mRendererLimitations(rendererLimitations), mHandle(handle), mType(type), mRefCount(0), mDeleteStatus(false), - mCompiled(false), mResourceManager(manager) { ASSERT(mImplementation); } +void Shader::onDestroy(const gl::Context *context) +{ + mBoundCompiler.set(context, nullptr); + mImplementation.reset(nullptr); + delete this; +} + Shader::~Shader() { - SafeDelete(mImplementation); + ASSERT(!mImplementation); } void Shader::setLabel(const std::string &label) { - mData.mLabel = label; + mState.mLabel = label; } const std::string &Shader::getLabel() const { - return mData.mLabel; + return mState.mLabel; } GLuint Shader::getHandle() const @@ -134,11 +152,12 @@ void Shader::setSource(GLsizei count, const char *const *string, const GLint *le } } - mData.mSource = stream.str(); + mState.mSource = stream.str(); } -int Shader::getInfoLogLength() const +int Shader::getInfoLogLength(const Context *context) { + resolveCompile(context); if (mInfoLog.empty()) { return 0; @@ -147,8 +166,10 @@ int Shader::getInfoLogLength() const return (static_cast(mInfoLog.length()) + 1); } -void Shader::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog) const +void Shader::getInfoLog(const Context *context, GLsizei bufSize, GLsizei *length, char *infoLog) { + resolveCompile(context); + int index = 0; if (bufSize > 0) @@ -167,21 +188,25 @@ void Shader::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog) const int Shader::getSourceLength() const { - return mData.mSource.empty() ? 0 : (static_cast(mData.mSource.length()) + 1); + return mState.mSource.empty() ? 0 : (static_cast(mState.mSource.length()) + 1); } -int Shader::getTranslatedSourceLength() const +int Shader::getTranslatedSourceLength(const Context *context) { - if (mData.mTranslatedSource.empty()) + resolveCompile(context); + + if (mState.mTranslatedSource.empty()) { return 0; } - return (static_cast(mData.mTranslatedSource.length()) + 1); + return (static_cast(mState.mTranslatedSource.length()) + 1); } -int Shader::getTranslatedSourceWithDebugInfoLength() const +int Shader::getTranslatedSourceWithDebugInfoLength(const Context *context) { + resolveCompile(context); + const std::string &debugInfo = mImplementation->getDebugInfo(); if (debugInfo.empty()) { @@ -191,7 +216,11 @@ int Shader::getTranslatedSourceWithDebugInfoLength() const return (static_cast(debugInfo.length()) + 1); } -void Shader::getSourceImpl(const std::string &source, GLsizei bufSize, GLsizei *length, char *buffer) +// static +void Shader::GetSourceImpl(const std::string &source, + GLsizei bufSize, + GLsizei *length, + char *buffer) { int index = 0; @@ -211,117 +240,186 @@ void Shader::getSourceImpl(const std::string &source, GLsizei bufSize, GLsizei * void Shader::getSource(GLsizei bufSize, GLsizei *length, char *buffer) const { - getSourceImpl(mData.mSource, bufSize, length, buffer); + GetSourceImpl(mState.mSource, bufSize, length, buffer); +} + +void Shader::getTranslatedSource(const Context *context, + GLsizei bufSize, + GLsizei *length, + char *buffer) +{ + GetSourceImpl(getTranslatedSource(context), bufSize, length, buffer); } -void Shader::getTranslatedSource(GLsizei bufSize, GLsizei *length, char *buffer) const +const std::string &Shader::getTranslatedSource(const Context *context) { - getSourceImpl(mData.mTranslatedSource, bufSize, length, buffer); + resolveCompile(context); + return mState.mTranslatedSource; } -void Shader::getTranslatedSourceWithDebugInfo(GLsizei bufSize, GLsizei *length, char *buffer) const +void Shader::getTranslatedSourceWithDebugInfo(const Context *context, + GLsizei bufSize, + GLsizei *length, + char *buffer) { + resolveCompile(context); const std::string &debugInfo = mImplementation->getDebugInfo(); - getSourceImpl(debugInfo, bufSize, length, buffer); + GetSourceImpl(debugInfo, bufSize, length, buffer); } -void Shader::compile(Compiler *compiler) +void Shader::compile(const Context *context) { - mData.mTranslatedSource.clear(); + mState.mTranslatedSource.clear(); mInfoLog.clear(); - mData.mShaderVersion = 100; - mData.mVaryings.clear(); - mData.mUniforms.clear(); - mData.mInterfaceBlocks.clear(); - mData.mActiveAttributes.clear(); - mData.mActiveOutputVariables.clear(); - - ShHandle compilerHandle = compiler->getCompilerHandle(mData.mShaderType); + mState.mShaderVersion = 100; + mState.mInputVaryings.clear(); + mState.mOutputVaryings.clear(); + mState.mUniforms.clear(); + mState.mUniformBlocks.clear(); + mState.mShaderStorageBlocks.clear(); + mState.mActiveAttributes.clear(); + mState.mActiveOutputVariables.clear(); + mState.mNumViews = -1; + mState.mGeometryShaderInputPrimitiveType = GL_INVALID_VALUE; + mState.mGeometryShaderOutputPrimitiveType = GL_INVALID_VALUE; + mState.mGeometryShaderInvocations = 1; + mState.mGeometryShaderMaxVertices = -1; + + mState.mCompileStatus = CompileStatus::COMPILE_REQUESTED; + mBoundCompiler.set(context, context->getCompiler()); + + // Cache the compile source and options for compilation. Must be done now, since the source + // can change before the link call or another call that resolves the compile. std::stringstream sourceStream; - std::string sourcePath; - int additionalOptions = - mImplementation->prepareSourceAndReturnOptions(&sourceStream, &sourcePath); - int compileOptions = (SH_OBJECT_CODE | SH_VARIABLES | additionalOptions); + mLastCompileOptions = + mImplementation->prepareSourceAndReturnOptions(&sourceStream, &mLastCompiledSourcePath); + mLastCompileOptions |= (SH_OBJECT_CODE | SH_VARIABLES); + mLastCompiledSource = sourceStream.str(); + + // Add default options to WebGL shaders to prevent unexpected behavior during compilation. + if (context->getExtensions().webglCompatibility) + { + mLastCompileOptions |= SH_INIT_GL_POSITION; + mLastCompileOptions |= SH_LIMIT_CALL_STACK_DEPTH; + mLastCompileOptions |= SH_LIMIT_EXPRESSION_COMPLEXITY; + mLastCompileOptions |= SH_ENFORCE_PACKING_RESTRICTIONS; + } // Some targets (eg D3D11 Feature Level 9_3 and below) do not support non-constant loop indexes // in fragment shaders. Shader compilation will fail. To provide a better error message we can // instruct the compiler to pre-validate. if (mRendererLimitations.shadersRequireIndexedLoopValidation) { - compileOptions |= SH_VALIDATE_LOOP_INDEXING; + mLastCompileOptions |= SH_VALIDATE_LOOP_INDEXING; } +} - std::string sourceString = sourceStream.str(); - std::vector sourceCStrings; - - if (!sourcePath.empty()) +void Shader::resolveCompile(const Context *context) +{ + if (!mState.compilePending()) { - sourceCStrings.push_back(sourcePath.c_str()); + return; } - sourceCStrings.push_back(sourceString.c_str()); + ASSERT(mBoundCompiler.get()); + ShHandle compilerHandle = mBoundCompiler->getCompilerHandle(mState.mShaderType); + + std::vector srcStrings; + + if (!mLastCompiledSourcePath.empty()) + { + srcStrings.push_back(mLastCompiledSourcePath.c_str()); + } - bool result = - ShCompile(compilerHandle, &sourceCStrings[0], sourceCStrings.size(), compileOptions); + srcStrings.push_back(mLastCompiledSource.c_str()); - if (!result) + if (!sh::Compile(compilerHandle, &srcStrings[0], srcStrings.size(), mLastCompileOptions)) { - mInfoLog = ShGetInfoLog(compilerHandle); - TRACE("\n%s", mInfoLog.c_str()); - mCompiled = false; + mInfoLog = sh::GetInfoLog(compilerHandle); + WARN() << std::endl << mInfoLog; + mState.mCompileStatus = CompileStatus::NOT_COMPILED; return; } - mData.mTranslatedSource = ShGetObjectCode(compilerHandle); + mState.mTranslatedSource = sh::GetObjectCode(compilerHandle); -#ifndef NDEBUG +#if !defined(NDEBUG) // Prefix translated shader with commented out un-translated shader. // Useful in diagnostics tools which capture the shader source. std::ostringstream shaderStream; shaderStream << "// GLSL\n"; shaderStream << "//\n"; - size_t curPos = 0; - while (curPos != std::string::npos) + std::istringstream inputSourceStream(mState.mSource); + std::string line; + while (std::getline(inputSourceStream, line)) { - size_t nextLine = mData.mSource.find("\n", curPos); - size_t len = (nextLine == std::string::npos) ? std::string::npos : (nextLine - curPos + 1); - - shaderStream << "// " << mData.mSource.substr(curPos, len); + // Remove null characters from the source line + line.erase(std::remove(line.begin(), line.end(), '\0'), line.end()); - curPos = (nextLine == std::string::npos) ? std::string::npos : (nextLine + 1); + shaderStream << "// " << line << std::endl; } shaderStream << "\n\n"; - shaderStream << mData.mTranslatedSource; - mData.mTranslatedSource = shaderStream.str(); -#endif + shaderStream << mState.mTranslatedSource; + mState.mTranslatedSource = shaderStream.str(); +#endif // !defined(NDEBUG) // Gather the shader information - mData.mShaderVersion = ShGetShaderVersion(compilerHandle); + mState.mShaderVersion = sh::GetShaderVersion(compilerHandle); - mData.mVaryings = GetShaderVariables(ShGetVaryings(compilerHandle)); - mData.mUniforms = GetShaderVariables(ShGetUniforms(compilerHandle)); - mData.mInterfaceBlocks = GetShaderVariables(ShGetInterfaceBlocks(compilerHandle)); + mState.mUniforms = GetShaderVariables(sh::GetUniforms(compilerHandle)); + mState.mUniformBlocks = GetShaderVariables(sh::GetUniformBlocks(compilerHandle)); + mState.mShaderStorageBlocks = GetShaderVariables(sh::GetShaderStorageBlocks(compilerHandle)); - if (mData.mShaderType == GL_VERTEX_SHADER) + switch (mState.mShaderType) { - mData.mActiveAttributes = GetActiveShaderVariables(ShGetAttributes(compilerHandle)); - } - else - { - ASSERT(mData.mShaderType == GL_FRAGMENT_SHADER); - - // TODO(jmadill): Figure out why we only sort in the FS, and if we need to. - std::sort(mData.mVaryings.begin(), mData.mVaryings.end(), CompareShaderVar); - mData.mActiveOutputVariables = - GetActiveShaderVariables(ShGetOutputVariables(compilerHandle)); + case GL_COMPUTE_SHADER: + { + mState.mLocalSize = sh::GetComputeShaderLocalGroupSize(compilerHandle); + break; + } + case GL_VERTEX_SHADER: + { + { + mState.mOutputVaryings = GetShaderVariables(sh::GetOutputVaryings(compilerHandle)); + mState.mActiveAttributes = + GetActiveShaderVariables(sh::GetAttributes(compilerHandle)); + mState.mNumViews = sh::GetVertexShaderNumViews(compilerHandle); + } + break; + } + case GL_FRAGMENT_SHADER: + { + mState.mInputVaryings = GetShaderVariables(sh::GetInputVaryings(compilerHandle)); + // TODO(jmadill): Figure out why we only sort in the FS, and if we need to. + std::sort(mState.mInputVaryings.begin(), mState.mInputVaryings.end(), CompareShaderVar); + mState.mActiveOutputVariables = + GetActiveShaderVariables(sh::GetOutputVariables(compilerHandle)); + break; + } + case GL_GEOMETRY_SHADER_EXT: + { + mState.mInputVaryings = GetShaderVariables(sh::GetInputVaryings(compilerHandle)); + mState.mOutputVaryings = GetShaderVariables(sh::GetOutputVaryings(compilerHandle)); + + mState.mGeometryShaderInputPrimitiveType = + sh::GetGeometryShaderInputPrimitiveType(compilerHandle); + mState.mGeometryShaderOutputPrimitiveType = + sh::GetGeometryShaderOutputPrimitiveType(compilerHandle); + mState.mGeometryShaderInvocations = sh::GetGeometryShaderInvocations(compilerHandle); + mState.mGeometryShaderMaxVertices = sh::GetGeometryShaderMaxVertices(compilerHandle); + break; + } + default: + UNREACHABLE(); } - ASSERT(!mData.mTranslatedSource.empty()); + ASSERT(!mState.mTranslatedSource.empty()); - mCompiled = mImplementation->postTranslateCompile(compiler, &mInfoLog); + bool success = mImplementation->postTranslateCompile(mBoundCompiler.get(), &mInfoLog); + mState.mCompileStatus = success ? CompileStatus::COMPILED : CompileStatus::NOT_COMPILED; } void Shader::addRef() @@ -329,13 +427,13 @@ void Shader::addRef() mRefCount++; } -void Shader::release() +void Shader::release(const Context *context) { mRefCount--; if (mRefCount == 0 && mDeleteStatus) { - mResourceManager->deleteShader(mHandle); + mResourceManager->deleteShader(context, mHandle); } } @@ -354,57 +452,110 @@ void Shader::flagForDeletion() mDeleteStatus = true; } -int Shader::getShaderVersion() const +bool Shader::isCompiled(const Context *context) { - return mData.mShaderVersion; + resolveCompile(context); + return mState.mCompileStatus == CompileStatus::COMPILED; } -const std::vector &Shader::getVaryings() const +int Shader::getShaderVersion(const Context *context) { - return mData.getVaryings(); + resolveCompile(context); + return mState.mShaderVersion; } -const std::vector &Shader::getUniforms() const +const std::vector &Shader::getInputVaryings(const Context *context) { - return mData.getUniforms(); + resolveCompile(context); + return mState.getInputVaryings(); } -const std::vector &Shader::getInterfaceBlocks() const +const std::vector &Shader::getOutputVaryings(const Context *context) { - return mData.getInterfaceBlocks(); + resolveCompile(context); + return mState.getOutputVaryings(); } -const std::vector &Shader::getActiveAttributes() const +const std::vector &Shader::getUniforms(const Context *context) { - return mData.getActiveAttributes(); + resolveCompile(context); + return mState.getUniforms(); } -const std::vector &Shader::getActiveOutputVariables() const +const std::vector &Shader::getUniformBlocks(const Context *context) { - return mData.getActiveOutputVariables(); + resolveCompile(context); + return mState.getUniformBlocks(); } -int Shader::getSemanticIndex(const std::string &attributeName) const +const std::vector &Shader::getShaderStorageBlocks(const Context *context) { - if (!attributeName.empty()) - { - const auto &activeAttributes = mData.getActiveAttributes(); + resolveCompile(context); + return mState.getShaderStorageBlocks(); +} - int semanticIndex = 0; - for (size_t attributeIndex = 0; attributeIndex < activeAttributes.size(); attributeIndex++) - { - const sh::ShaderVariable &attribute = activeAttributes[attributeIndex]; +const std::vector &Shader::getActiveAttributes(const Context *context) +{ + resolveCompile(context); + return mState.getActiveAttributes(); +} + +const std::vector &Shader::getActiveOutputVariables(const Context *context) +{ + resolveCompile(context); + return mState.getActiveOutputVariables(); +} - if (attribute.name == attributeName) +std::string Shader::getTransformFeedbackVaryingMappedName(const std::string &tfVaryingName, + const Context *context) +{ + // TODO(jiawei.shao@intel.com): support transform feedback on geometry shader. + ASSERT(mState.getShaderType() == GL_VERTEX_SHADER); + const auto &varyings = getOutputVaryings(context); + auto bracketPos = tfVaryingName.find("["); + if (bracketPos != std::string::npos) + { + auto tfVaryingBaseName = tfVaryingName.substr(0, bracketPos); + for (const auto &varying : varyings) + { + if (varying.name == tfVaryingBaseName) { - return semanticIndex; + std::string mappedNameWithArrayIndex = + varying.mappedName + tfVaryingName.substr(bracketPos); + return mappedNameWithArrayIndex; + } + } + } + else + { + for (const auto &varying : varyings) + { + if (varying.name == tfVaryingName) + { + return varying.mappedName; } - - semanticIndex += gl::VariableRegisterCount(attribute.type); } } + UNREACHABLE(); + return std::string(); +} - return -1; +const sh::WorkGroupSize &Shader::getWorkGroupSize(const Context *context) +{ + resolveCompile(context); + return mState.mLocalSize; } +int Shader::getNumViews(const Context *context) +{ + resolveCompile(context); + return mState.mNumViews; } + +const std::string &Shader::getCompilerResourcesString() const +{ + ASSERT(mBoundCompiler.get()); + return mBoundCompiler->getBuiltinResourcesString(mState.mShaderType); +} + +} // namespace gl diff --git a/src/3rdparty/angle/src/libANGLE/Shader.h b/src/3rdparty/angle/src/libANGLE/Shader.h index 997977c87b..4b6be4696d 100644 --- a/src/3rdparty/angle/src/libANGLE/Shader.h +++ b/src/3rdparty/angle/src/libANGLE/Shader.h @@ -12,20 +12,22 @@ #ifndef LIBANGLE_SHADER_H_ #define LIBANGLE_SHADER_H_ -#include #include +#include +#include #include #include "angle_gl.h" #include +#include "common/Optional.h" #include "common/angleutils.h" -#include "libANGLE/angletypes.h" #include "libANGLE/Debug.h" +#include "libANGLE/angletypes.h" namespace rx { -class ImplFactory; +class GLImplFactory; class ShaderImpl; class ShaderSh; } @@ -33,63 +35,92 @@ class ShaderSh; namespace gl { class Compiler; +class ContextState; struct Limitations; -class ResourceManager; -struct Data; +class ShaderProgramManager; +class Context; -class Shader final : angle::NonCopyable, public LabeledObject +// We defer the compile until link time, or until properties are queried. +enum class CompileStatus +{ + NOT_COMPILED, + COMPILE_REQUESTED, + COMPILED, +}; + +class ShaderState final : angle::NonCopyable { public: - class Data final : angle::NonCopyable + ShaderState(GLenum shaderType); + ~ShaderState(); + + const std::string &getLabel() const { return mLabel; } + + const std::string &getSource() const { return mSource; } + const std::string &getTranslatedSource() const { return mTranslatedSource; } + + GLenum getShaderType() const { return mShaderType; } + int getShaderVersion() const { return mShaderVersion; } + + const std::vector &getInputVaryings() const { return mInputVaryings; } + const std::vector &getOutputVaryings() const { return mOutputVaryings; } + const std::vector &getUniforms() const { return mUniforms; } + const std::vector &getUniformBlocks() const { return mUniformBlocks; } + const std::vector &getShaderStorageBlocks() const { - public: - Data(GLenum shaderType); - ~Data(); - - const std::string &getLabel() const { return mLabel; } - - const std::string &getSource() const { return mSource; } - const std::string &getTranslatedSource() const { return mTranslatedSource; } - - GLenum getShaderType() const { return mShaderType; } - int getShaderVersion() const { return mShaderVersion; } - - 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; - } - - private: - friend class Shader; - - std::string mLabel; - - GLenum mShaderType; - int mShaderVersion; - std::string mTranslatedSource; - std::string mSource; - - std::vector mVaryings; - std::vector mUniforms; - std::vector mInterfaceBlocks; - std::vector mActiveAttributes; - std::vector mActiveOutputVariables; - }; - - Shader(ResourceManager *manager, - rx::ImplFactory *implFactory, + return mShaderStorageBlocks; + } + const std::vector &getActiveAttributes() const { return mActiveAttributes; } + const std::vector &getActiveOutputVariables() const + { + return mActiveOutputVariables; + } + + bool compilePending() const { return mCompileStatus == CompileStatus::COMPILE_REQUESTED; } + + private: + friend class Shader; + + std::string mLabel; + + GLenum mShaderType; + int mShaderVersion; + std::string mTranslatedSource; + std::string mSource; + + sh::WorkGroupSize mLocalSize; + + std::vector mInputVaryings; + std::vector mOutputVaryings; + std::vector mUniforms; + std::vector mUniformBlocks; + std::vector mShaderStorageBlocks; + std::vector mActiveAttributes; + std::vector mActiveOutputVariables; + + // ANGLE_multiview. + int mNumViews; + + // Geometry Shader. + GLenum mGeometryShaderInputPrimitiveType; + GLenum mGeometryShaderOutputPrimitiveType; + int mGeometryShaderInvocations; + int mGeometryShaderMaxVertices; + + // Indicates if this shader has been successfully compiled + CompileStatus mCompileStatus; +}; + +class Shader final : angle::NonCopyable, public LabeledObject +{ + public: + Shader(ShaderProgramManager *manager, + rx::GLImplFactory *implFactory, const gl::Limitations &rendererLimitations, GLenum type, GLuint handle); - virtual ~Shader(); + void onDestroy(const Context *context); void setLabel(const std::string &label) override; const std::string &getLabel() const override; @@ -97,56 +128,85 @@ class Shader final : angle::NonCopyable, public LabeledObject GLenum getType() const { return mType; } GLuint getHandle() const; - const rx::ShaderImpl *getImplementation() const { return mImplementation; } + rx::ShaderImpl *getImplementation() const { return mImplementation.get(); } - 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 getInfoLogLength(const Context *context); + void getInfoLog(const Context *context, GLsizei bufSize, GLsizei *length, char *infoLog); int getSourceLength() const; + const std::string &getSourceString() const { return mState.getSource(); } void getSource(GLsizei bufSize, GLsizei *length, char *buffer) const; - int getTranslatedSourceLength() const; - int getTranslatedSourceWithDebugInfoLength() const; - const std::string &getTranslatedSource() const { return mData.getTranslatedSource(); } - 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; } + int getTranslatedSourceLength(const Context *context); + int getTranslatedSourceWithDebugInfoLength(const Context *context); + const std::string &getTranslatedSource(const Context *context); + void getTranslatedSource(const Context *context, + GLsizei bufSize, + GLsizei *length, + char *buffer); + void getTranslatedSourceWithDebugInfo(const Context *context, + GLsizei bufSize, + GLsizei *length, + char *buffer); + + void compile(const Context *context); + bool isCompiled(const Context *context); void addRef(); - void release(); + void release(const Context *context); unsigned int getRefCount() const; bool isFlaggedForDeletion() const; void flagForDeletion(); - int getShaderVersion() const; + int getShaderVersion(const Context *context); - 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; + const std::vector &getInputVaryings(const Context *context); + const std::vector &getOutputVaryings(const Context *context); + const std::vector &getUniforms(const Context *context); + const std::vector &getUniformBlocks(const Context *context); + const std::vector &getShaderStorageBlocks(const Context *context); + const std::vector &getActiveAttributes(const Context *context); + const std::vector &getActiveOutputVariables(const Context *context); - int getSemanticIndex(const std::string &attributeName) const; + // Returns mapped name of a transform feedback varying. The original name may contain array + // brackets with an index inside, which will get copied to the mapped name. The varying must be + // known to be declared in the shader. + std::string getTransformFeedbackVaryingMappedName(const std::string &tfVaryingName, + const Context *context); - private: - static void getSourceImpl(const std::string &source, GLsizei bufSize, GLsizei *length, char *buffer); + const sh::WorkGroupSize &getWorkGroupSize(const Context *context); + + int getNumViews(const Context *context); - Data mData; - rx::ShaderImpl *mImplementation; + const std::string &getCompilerResourcesString() const; + + private: + ~Shader() override; + static void GetSourceImpl(const std::string &source, + GLsizei bufSize, + GLsizei *length, + char *buffer); + + void resolveCompile(const Context *context); + + ShaderState mState; + std::string mLastCompiledSource; + std::string mLastCompiledSourcePath; + ShCompileOptions mLastCompileOptions; + std::unique_ptr mImplementation; const gl::Limitations &mRendererLimitations; const GLuint mHandle; const GLenum mType; 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 std::string mInfoLog; - ResourceManager *mResourceManager; + // We keep a reference to the translator in order to defer compiles while preserving settings. + BindingPointer mBoundCompiler; + + ShaderProgramManager *mResourceManager; }; bool CompareShaderVar(const sh::ShaderVariable &x, const sh::ShaderVariable &y); -} +} // namespace gl #endif // LIBANGLE_SHADER_H_ diff --git a/src/3rdparty/angle/src/libANGLE/SizedMRUCache.h b/src/3rdparty/angle/src/libANGLE/SizedMRUCache.h new file mode 100644 index 0000000000..6a608a697e --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/SizedMRUCache.h @@ -0,0 +1,174 @@ +// +// Copyright 2017 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. +// +// SizedMRUCache.h: A hashing map that stores blobs of sized, untyped data. + +#ifndef LIBANGLE_SIZED_MRU_CACHE_H_ +#define LIBANGLE_SIZED_MRU_CACHE_H_ + +#include +#include "common/third_party/smhasher/src/PMurHash.h" + +namespace angle +{ + +template +class SizedMRUCache final : angle::NonCopyable +{ + public: + SizedMRUCache(size_t maximumTotalSize) + : mMaximumTotalSize(maximumTotalSize), + mCurrentSize(0), + mStore(SizedMRUCacheStore::NO_AUTO_EVICT) + { + } + + // Returns nullptr on failure. + const Value *put(const Key &key, Value &&value, size_t size) + { + if (size > mMaximumTotalSize) + { + return nullptr; + } + + // Check for existing key. + eraseByKey(key); + + auto retVal = mStore.Put(key, ValueAndSize(std::move(value), size)); + mCurrentSize += size; + + shrinkToSize(mMaximumTotalSize); + + return &retVal->second.value; + } + + bool get(const Key &key, const Value **valueOut) + { + const auto &iter = mStore.Get(key); + if (iter == mStore.end()) + { + return false; + } + *valueOut = &iter->second.value; + return true; + } + + bool getAt(size_t index, Key *keyOut, const Value **valueOut) + { + if (index < mStore.size()) + { + auto it = mStore.begin(); + std::advance(it, index); + *keyOut = it->first; + *valueOut = &it->second.value; + return true; + } + *valueOut = nullptr; + return false; + } + + bool empty() const { return mStore.empty(); } + + void clear() + { + mStore.Clear(); + mCurrentSize = 0; + } + + bool eraseByKey(const Key &key) + { + // Check for existing key. + auto existing = mStore.Peek(key); + if (existing != mStore.end()) + { + mCurrentSize -= existing->second.size; + mStore.Erase(existing); + return true; + } + + return false; + } + + size_t entryCount() const { return mStore.size(); } + + size_t size() const { return mCurrentSize; } + + // Also discards the cache contents. + void resize(size_t maximumTotalSize) + { + clear(); + mMaximumTotalSize = maximumTotalSize; + } + + // Reduce current memory usage. + size_t shrinkToSize(size_t limit) + { + size_t initialSize = mCurrentSize; + + while (mCurrentSize > limit) + { + ASSERT(!mStore.empty()); + auto iter = mStore.rbegin(); + mCurrentSize -= iter->second.size; + mStore.Erase(iter); + } + + return (initialSize - mCurrentSize); + } + + size_t maxSize() const { return mMaximumTotalSize; } + + private: + struct ValueAndSize + { + ValueAndSize() : value(), size(0) {} + ValueAndSize(Value &&value, size_t size) : value(std::move(value)), size(size) {} + ValueAndSize(ValueAndSize &&other) : ValueAndSize() { *this = std::move(other); } + ValueAndSize &operator=(ValueAndSize &&other) + { + std::swap(value, other.value); + std::swap(size, other.size); + return *this; + } + + Value value; + size_t size; + }; + + using SizedMRUCacheStore = base::HashingMRUCache; + + size_t mMaximumTotalSize; + size_t mCurrentSize; + SizedMRUCacheStore mStore; +}; + +// Helper function used in a few places. +template +void TrimCache(size_t maxStates, size_t gcLimit, const char *name, T *cache) +{ + const size_t kGarbageCollectionLimit = maxStates / 2 + gcLimit; + + if (cache->size() >= kGarbageCollectionLimit) + { + WARN() << "Overflowed the " << name << " cache limit of " << (maxStates / 2) + << " elements, removing the least recently used to make room."; + cache->ShrinkToSize(maxStates / 2); + } +} + +// Computes a hash of struct "key". Any structs passed to this function must be multiples of +// 4 bytes, since the PMurhHas32 method can only operate increments of 4-byte words. +template +std::size_t ComputeGenericHash(const T &key) +{ + static const unsigned int seed = 0xABCDEF98; + + // We can't support "odd" alignments. + static_assert(sizeof(key) % 4 == 0, "ComputeGenericHash requires aligned types"); + return PMurHash32(seed, &key, sizeof(T)); +} + +} // namespace angle +#endif // LIBANGLE_SIZED_MRU_CACHE_H_ diff --git a/src/3rdparty/angle/src/libANGLE/State.cpp b/src/3rdparty/angle/src/libANGLE/State.cpp index a1437b838b..f87e963710 100644 --- a/src/3rdparty/angle/src/libANGLE/State.cpp +++ b/src/3rdparty/angle/src/libANGLE/State.cpp @@ -8,15 +8,32 @@ #include "libANGLE/State.h" -#include "common/BitSetIterator.h" -#include "libANGLE/Context.h" +#include +#include + +#include "common/bitset_utils.h" +#include "common/mathutil.h" +#include "common/matrix_utils.h" #include "libANGLE/Caps.h" +#include "libANGLE/Context.h" #include "libANGLE/Debug.h" #include "libANGLE/Framebuffer.h" #include "libANGLE/FramebufferAttachment.h" #include "libANGLE/Query.h" #include "libANGLE/VertexArray.h" #include "libANGLE/formatutils.h" +#include "libANGLE/queryconversions.h" +#include "libANGLE/renderer/ContextImpl.h" + +namespace +{ + +GLenum ActiveQueryType(const GLenum type) +{ + return (type == GL_ANY_SAMPLES_PASSED_CONSERVATIVE) ? GL_ANY_SAMPLES_PASSED : type; +} + +} // anonymous namepace namespace gl { @@ -30,11 +47,15 @@ State::State() mSampleCoverage(false), mSampleCoverageValue(0), mSampleCoverageInvert(false), + mSampleMask(false), + mMaxSampleMaskWords(0), mStencilRef(0), mStencilBackRef(0), mLineWidth(0), mGenerateMipmapHint(GL_NONE), mFragmentShaderDerivativeHint(GL_NONE), + mBindGeneratesResource(true), + mClientArraysEnabled(true), mNearZ(0), mFarZ(0), mReadFramebuffer(nullptr), @@ -42,49 +63,31 @@ State::State() mProgram(nullptr), mVertexArray(nullptr), mActiveSampler(0), - mPrimitiveRestart(false) -{ - // Initialize dirty bit masks - // TODO(jmadill): additional ES3 state - mUnpackStateBitMask.set(DIRTY_BIT_UNPACK_ALIGNMENT); - mUnpackStateBitMask.set(DIRTY_BIT_UNPACK_ROW_LENGTH); - mUnpackStateBitMask.set(DIRTY_BIT_UNPACK_IMAGE_HEIGHT); - mUnpackStateBitMask.set(DIRTY_BIT_UNPACK_SKIP_IMAGES); - mUnpackStateBitMask.set(DIRTY_BIT_UNPACK_SKIP_ROWS); - mUnpackStateBitMask.set(DIRTY_BIT_UNPACK_SKIP_PIXELS); - - mPackStateBitMask.set(DIRTY_BIT_PACK_ALIGNMENT); - mPackStateBitMask.set(DIRTY_BIT_PACK_REVERSE_ROW_ORDER); - mPackStateBitMask.set(DIRTY_BIT_PACK_ROW_LENGTH); - mPackStateBitMask.set(DIRTY_BIT_PACK_SKIP_ROWS); - mPackStateBitMask.set(DIRTY_BIT_PACK_SKIP_PIXELS); - - mClearStateBitMask.set(DIRTY_BIT_RASTERIZER_DISCARD_ENABLED); - mClearStateBitMask.set(DIRTY_BIT_SCISSOR_TEST_ENABLED); - mClearStateBitMask.set(DIRTY_BIT_SCISSOR); - mClearStateBitMask.set(DIRTY_BIT_VIEWPORT); - mClearStateBitMask.set(DIRTY_BIT_CLEAR_COLOR); - mClearStateBitMask.set(DIRTY_BIT_CLEAR_DEPTH); - mClearStateBitMask.set(DIRTY_BIT_CLEAR_STENCIL); - mClearStateBitMask.set(DIRTY_BIT_COLOR_MASK); - mClearStateBitMask.set(DIRTY_BIT_DEPTH_MASK); - mClearStateBitMask.set(DIRTY_BIT_STENCIL_WRITEMASK_FRONT); - mClearStateBitMask.set(DIRTY_BIT_STENCIL_WRITEMASK_BACK); - - mBlitStateBitMask.set(DIRTY_BIT_SCISSOR_TEST_ENABLED); - mBlitStateBitMask.set(DIRTY_BIT_SCISSOR); + mPrimitiveRestart(false), + mMultiSampling(false), + mSampleAlphaToOne(false), + mFramebufferSRGB(true), + mRobustResourceInit(false), + mProgramBinaryCacheEnabled(false) +{ } State::~State() { - reset(); } -void State::initialize(const Caps &caps, - const Extensions &extensions, - GLuint clientVersion, - bool debug) +void State::initialize(const Context *context, + bool debug, + bool bindGeneratesResource, + bool clientArraysEnabled, + bool robustResourceInit, + bool programBinaryCacheEnabled) { + const Caps &caps = context->getCaps(); + const Extensions &extensions = context->getExtensions(); + const Extensions &nativeExtensions = context->getImplementation()->getNativeExtensions(); + const Version &clientVersion = context->getClientVersion(); + mMaxDrawBuffers = caps.maxDrawBuffers; mMaxCombinedTextureImageUnits = caps.maxCombinedTextureImageUnits; @@ -93,62 +96,34 @@ void State::initialize(const Caps &caps, 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; + + mMaxSampleMaskWords = caps.maxSampleMaskWords; + mSampleMask = false; + mSampleMaskValues.fill(~GLbitfield(0)); + mGenerateMipmapHint = GL_DONT_CARE; mFragmentShaderDerivativeHint = GL_DONT_CARE; + mBindGeneratesResource = bindGeneratesResource; + mClientArraysEnabled = clientArraysEnabled; + mLineWidth = 1.0f; mViewport.x = 0; @@ -167,23 +142,48 @@ void State::initialize(const Caps &caps, mVertexAttribCurrentValues.resize(caps.maxVertexAttributes); - mUniformBuffers.resize(caps.maxCombinedUniformBlocks); + mUniformBuffers.resize(caps.maxUniformBufferBindings); mSamplerTextures[GL_TEXTURE_2D].resize(caps.maxCombinedTextureImageUnits); mSamplerTextures[GL_TEXTURE_CUBE_MAP].resize(caps.maxCombinedTextureImageUnits); - if (clientVersion >= 3) + if (clientVersion >= Version(3, 0)) { // TODO: These could also be enabled via extension mSamplerTextures[GL_TEXTURE_2D_ARRAY].resize(caps.maxCombinedTextureImageUnits); mSamplerTextures[GL_TEXTURE_3D].resize(caps.maxCombinedTextureImageUnits); } + if (clientVersion >= Version(3, 1)) + { + mSamplerTextures[GL_TEXTURE_2D_MULTISAMPLE].resize(caps.maxCombinedTextureImageUnits); + + mAtomicCounterBuffers.resize(caps.maxAtomicCounterBufferBindings); + mShaderStorageBuffers.resize(caps.maxShaderStorageBufferBindings); + mImageUnits.resize(caps.maxImageUnits); + } + if (nativeExtensions.textureRectangle) + { + mSamplerTextures[GL_TEXTURE_RECTANGLE_ANGLE].resize(caps.maxCombinedTextureImageUnits); + } + if (nativeExtensions.eglImageExternal || nativeExtensions.eglStreamConsumerExternal) + { + mSamplerTextures[GL_TEXTURE_EXTERNAL_OES].resize(caps.maxCombinedTextureImageUnits); + } + mCompleteTextureCache.resize(caps.maxCombinedTextureImageUnits, nullptr); + mCompleteTextureBindings.reserve(caps.maxCombinedTextureImageUnits); + mCachedTexturesInitState = InitState::MayNeedInit; + for (uint32_t textureIndex = 0; textureIndex < caps.maxCombinedTextureImageUnits; + ++textureIndex) + { + mCompleteTextureBindings.emplace_back(OnAttachmentDirtyBinding(this, textureIndex)); + } mSamplers.resize(caps.maxCombinedTextureImageUnits); - mActiveQueries[GL_ANY_SAMPLES_PASSED].set(nullptr); - mActiveQueries[GL_ANY_SAMPLES_PASSED_CONSERVATIVE].set(nullptr); - mActiveQueries[GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN].set(nullptr); - mActiveQueries[GL_TIME_ELAPSED_EXT].set(nullptr); + mActiveQueries[GL_ANY_SAMPLES_PASSED].set(context, nullptr); + mActiveQueries[GL_ANY_SAMPLES_PASSED_CONSERVATIVE].set(context, nullptr); + mActiveQueries[GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN].set(context, nullptr); + mActiveQueries[GL_TIME_ELAPSED_EXT].set(context, nullptr); + mActiveQueries[GL_COMMANDS_COMPLETED_CHROMIUM].set(context, nullptr); mProgram = nullptr; @@ -194,52 +194,89 @@ void State::initialize(const Caps &caps, mDebug.setOutputEnabled(debug); mDebug.setMaxLoggedMessages(extensions.maxDebugLoggedMessages); + + mMultiSampling = true; + mSampleAlphaToOne = false; + + mCoverageModulation = GL_NONE; + + angle::Matrix::setToIdentity(mPathMatrixProj); + angle::Matrix::setToIdentity(mPathMatrixMV); + mPathStencilFunc = GL_ALWAYS; + mPathStencilRef = 0; + mPathStencilMask = std::numeric_limits::max(); + + mRobustResourceInit = robustResourceInit; + mProgramBinaryCacheEnabled = programBinaryCacheEnabled; } -void State::reset() +void State::reset(const Context *context) { - for (TextureBindingMap::iterator bindingVec = mSamplerTextures.begin(); bindingVec != mSamplerTextures.end(); bindingVec++) + for (auto &bindingVec : mSamplerTextures) { - TextureBindingVector &textureVector = bindingVec->second; + TextureBindingVector &textureVector = bindingVec.second; for (size_t textureIdx = 0; textureIdx < textureVector.size(); textureIdx++) { - textureVector[textureIdx].set(NULL); + textureVector[textureIdx].set(context, nullptr); } } for (size_t samplerIdx = 0; samplerIdx < mSamplers.size(); samplerIdx++) { - mSamplers[samplerIdx].set(NULL); + mSamplers[samplerIdx].set(context, nullptr); } - mArrayBuffer.set(NULL); - mRenderbuffer.set(NULL); + for (auto &imageUnit : mImageUnits) + { + imageUnit.texture.set(context, nullptr); + imageUnit.level = 0; + imageUnit.layered = false; + imageUnit.layer = 0; + imageUnit.access = GL_READ_ONLY; + imageUnit.format = GL_R32UI; + } + + mRenderbuffer.set(context, nullptr); + + for (auto type : angle::AllEnums()) + { + mBoundBuffers[type].set(context, nullptr); + } if (mProgram) { - mProgram->release(); + mProgram->release(context); } - mProgram = NULL; + mProgram = nullptr; + + mProgramPipeline.set(context, nullptr); - mTransformFeedback.set(NULL); + mTransformFeedback.set(context, nullptr); for (State::ActiveQueryMap::iterator i = mActiveQueries.begin(); i != mActiveQueries.end(); i++) { - i->second.set(NULL); + i->second.set(context, nullptr); } - mGenericUniformBuffer.set(NULL); - for (BufferVector::iterator bufItr = mUniformBuffers.begin(); bufItr != mUniformBuffers.end(); ++bufItr) + for (auto &buf : mUniformBuffers) { - bufItr->set(NULL); + buf.set(context, nullptr); } - mCopyReadBuffer.set(NULL); - mCopyWriteBuffer.set(NULL); + for (auto &buf : mAtomicCounterBuffers) + { + buf.set(context, nullptr); + } - mPack.pixelBuffer.set(NULL); - mUnpack.pixelBuffer.set(NULL); + for (auto &buf : mShaderStorageBuffers) + { + buf.set(context, nullptr); + } - mProgram = NULL; + angle::Matrix::setToIdentity(mPathMatrixProj); + angle::Matrix::setToIdentity(mPathMatrixMV); + mPathStencilFunc = GL_ALWAYS; + mPathStencilRef = 0; + mPathStencilMask = std::numeric_limits::max(); // TODO(jmadill): Is this necessary? setAllDirtyBits(); @@ -318,7 +355,7 @@ void State::setCullFace(bool enabled) mDirtyBits.set(DIRTY_BIT_CULL_FACE_ENABLED); } -void State::setCullMode(GLenum mode) +void State::setCullMode(CullFaceMode mode) { mRasterizer.cullMode = mode; mDirtyBits.set(DIRTY_BIT_CULL_FACE); @@ -528,6 +565,58 @@ bool State::getSampleCoverageInvert() const return mSampleCoverageInvert; } +bool State::isSampleMaskEnabled() const +{ + return mSampleMask; +} + +void State::setSampleMaskEnabled(bool enabled) +{ + mSampleMask = enabled; + mDirtyBits.set(DIRTY_BIT_SAMPLE_MASK_ENABLED); +} + +void State::setSampleMaskParams(GLuint maskNumber, GLbitfield mask) +{ + ASSERT(maskNumber < mMaxSampleMaskWords); + mSampleMaskValues[maskNumber] = mask; + // TODO(jmadill): Use a child dirty bit if we ever use more than two words. + mDirtyBits.set(DIRTY_BIT_SAMPLE_MASK); +} + +GLbitfield State::getSampleMaskWord(GLuint maskNumber) const +{ + ASSERT(maskNumber < mMaxSampleMaskWords); + return mSampleMaskValues[maskNumber]; +} + +GLuint State::getMaxSampleMaskWords() const +{ + return mMaxSampleMaskWords; +} + +void State::setSampleAlphaToOne(bool enabled) +{ + mSampleAlphaToOne = enabled; + mDirtyBits.set(DIRTY_BIT_SAMPLE_ALPHA_TO_ONE); +} + +bool State::isSampleAlphaToOneEnabled() const +{ + return mSampleAlphaToOne; +} + +void State::setMultisampling(bool enabled) +{ + mMultiSampling = enabled; + mDirtyBits.set(DIRTY_BIT_MULTISAMPLING); +} + +bool State::isMultisamplingEnabled() const +{ + return mMultiSampling; +} + bool State::isScissorTestEnabled() const { return mScissorTest; @@ -579,6 +668,8 @@ void State::setEnableFeature(GLenum feature, bool enabled) { switch (feature) { + case GL_MULTISAMPLE_EXT: setMultisampling(enabled); break; + case GL_SAMPLE_ALPHA_TO_ONE_EXT: setSampleAlphaToOne(enabled); break; case GL_CULL_FACE: setCullFace(enabled); break; case GL_POLYGON_OFFSET_FILL: setPolygonOffsetFill(enabled); break; case GL_SAMPLE_ALPHA_TO_COVERAGE: setSampleAlphaToCoverage(enabled); break; @@ -590,20 +681,28 @@ void State::setEnableFeature(GLenum feature, bool enabled) case GL_DITHER: setDither(enabled); break; case GL_PRIMITIVE_RESTART_FIXED_INDEX: setPrimitiveRestart(enabled); break; case GL_RASTERIZER_DISCARD: setRasterizerDiscard(enabled); break; + case GL_SAMPLE_MASK: + setSampleMaskEnabled(enabled); + break; case GL_DEBUG_OUTPUT_SYNCHRONOUS: mDebug.setOutputSynchronous(enabled); break; case GL_DEBUG_OUTPUT: mDebug.setOutputEnabled(enabled); break; + case GL_FRAMEBUFFER_SRGB_EXT: + setFramebufferSRGB(enabled); + break; default: UNREACHABLE(); } } -bool State::getEnableFeature(GLenum feature) +bool State::getEnableFeature(GLenum feature) const { switch (feature) { + case GL_MULTISAMPLE_EXT: return isMultisamplingEnabled(); + case GL_SAMPLE_ALPHA_TO_ONE_EXT: return isSampleAlphaToOneEnabled(); case GL_CULL_FACE: return isCullFaceEnabled(); case GL_POLYGON_OFFSET_FILL: return isPolygonOffsetFillEnabled(); case GL_SAMPLE_ALPHA_TO_COVERAGE: return isSampleAlphaToCoverageEnabled(); @@ -615,11 +714,26 @@ bool State::getEnableFeature(GLenum feature) case GL_DITHER: return isDitherEnabled(); case GL_PRIMITIVE_RESTART_FIXED_INDEX: return isPrimitiveRestartEnabled(); case GL_RASTERIZER_DISCARD: return isRasterizerDiscardEnabled(); + case GL_SAMPLE_MASK: + return isSampleMaskEnabled(); case GL_DEBUG_OUTPUT_SYNCHRONOUS: return mDebug.isOutputSynchronous(); case GL_DEBUG_OUTPUT: return mDebug.isOutputEnabled(); - default: UNREACHABLE(); return false; + case GL_BIND_GENERATES_RESOURCE_CHROMIUM: + return isBindGeneratesResourceEnabled(); + case GL_CLIENT_ARRAYS_ANGLE: + return areClientArraysEnabled(); + case GL_FRAMEBUFFER_SRGB_EXT: + return getFramebufferSRGB(); + case GL_ROBUST_RESOURCE_INITIALIZATION_ANGLE: + return mRobustResourceInit; + case GL_PROGRAM_CACHE_ENABLED_ANGLE: + return mProgramBinaryCacheEnabled; + + default: + UNREACHABLE(); + return false; } } @@ -649,6 +763,16 @@ void State::setFragmentShaderDerivativeHint(GLenum hint) // Ignore for now. It is valid for implementations to ignore hint. } +bool State::isBindGeneratesResourceEnabled() const +{ + return mBindGeneratesResource; +} + +bool State::areClientArraysEnabled() const +{ + return mClientArraysEnabled; +} + void State::setViewportParams(GLint x, GLint y, GLsizei width, GLsizei height) { mViewport.x = x; @@ -673,9 +797,11 @@ unsigned int State::getActiveSampler() const return static_cast(mActiveSampler); } -void State::setSamplerTexture(GLenum type, Texture *texture) +void State::setSamplerTexture(const Context *context, GLenum type, Texture *texture) { - mSamplerTextures[type][mActiveSampler].set(texture); + mSamplerTextures[type][mActiveSampler].set(context, texture); + mDirtyBits.set(DIRTY_BIT_TEXTURE_BINDINGS); + mDirtyObjects.set(DIRTY_OBJECT_PROGRAM_TEXTURES); } Texture *State::getTargetTexture(GLenum target) const @@ -699,7 +825,7 @@ GLuint State::getSamplerTextureId(unsigned int sampler, GLenum type) const return it->second[sampler].id(); } -void State::detachTexture(const TextureMap &zeroTextures, GLuint texture) +void State::detachTexture(const Context *context, 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 @@ -710,40 +836,54 @@ void State::detachTexture(const TextureMap &zeroTextures, GLuint texture) // 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++) + for (auto &bindingVec : mSamplerTextures) { - GLenum textureType = bindingVec->first; - TextureBindingVector &textureVector = bindingVec->second; - for (size_t textureIdx = 0; textureIdx < textureVector.size(); textureIdx++) + GLenum textureType = bindingVec.first; + TextureBindingVector &textureVector = bindingVec.second; + for (BindingPointer &binding : textureVector) { - 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()); + binding.set(context, it->second.get()); + mDirtyBits.set(DIRTY_BIT_TEXTURE_BINDINGS); } } } + for (auto &bindingImageUnit : mImageUnits) + { + if (bindingImageUnit.texture.id() == texture) + { + bindingImageUnit.texture.set(context, nullptr); + bindingImageUnit.level = 0; + bindingImageUnit.layered = false; + bindingImageUnit.layer = 0; + bindingImageUnit.access = GL_READ_ONLY; + bindingImageUnit.format = GL_R32UI; + break; + } + } + // [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) + if (mReadFramebuffer && mReadFramebuffer->detachTexture(context, texture)) { - mReadFramebuffer->detachTexture(texture); + mDirtyObjects.set(DIRTY_OBJECT_READ_FRAMEBUFFER); } - if (mDrawFramebuffer) + if (mDrawFramebuffer && mDrawFramebuffer->detachTexture(context, texture)) { - mDrawFramebuffer->detachTexture(texture); + mDirtyObjects.set(DIRTY_OBJECT_DRAW_FRAMEBUFFER); } } -void State::initializeZeroTextures(const TextureMap &zeroTextures) +void State::initializeZeroTextures(const Context *context, const TextureMap &zeroTextures) { for (const auto &zeroTexture : zeroTextures) { @@ -751,14 +891,16 @@ void State::initializeZeroTextures(const TextureMap &zeroTextures) for (size_t textureUnit = 0; textureUnit < samplerTextureArray.size(); ++textureUnit) { - samplerTextureArray[textureUnit].set(zeroTexture.second.get()); + samplerTextureArray[textureUnit].set(context, zeroTexture.second.get()); } } } -void State::setSamplerBinding(GLuint textureUnit, Sampler *sampler) +void State::setSamplerBinding(const Context *context, GLuint textureUnit, Sampler *sampler) { - mSamplers[textureUnit].set(sampler); + mSamplers[textureUnit].set(context, sampler); + mDirtyBits.set(DIRTY_BIT_SAMPLER_BINDINGS); + mDirtyObjects.set(DIRTY_OBJECT_PROGRAM_TEXTURES); } GLuint State::getSamplerId(GLuint textureUnit) const @@ -772,25 +914,26 @@ Sampler *State::getSampler(GLuint textureUnit) const return mSamplers[textureUnit].get(); } -void State::detachSampler(GLuint sampler) +void State::detachSampler(const Context *context, 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++) + for (BindingPointer &samplerBinding : mSamplers) { - BindingPointer &samplerBinding = mSamplers[textureUnit]; if (samplerBinding.id() == sampler) { - samplerBinding.set(NULL); + samplerBinding.set(context, nullptr); + mDirtyBits.set(DIRTY_BIT_SAMPLER_BINDINGS); } } } -void State::setRenderbufferBinding(Renderbuffer *renderbuffer) +void State::setRenderbufferBinding(const Context *context, Renderbuffer *renderbuffer) { - mRenderbuffer.set(renderbuffer); + mRenderbuffer.set(context, renderbuffer); + mDirtyBits.set(DIRTY_BIT_RENDERBUFFER_BINDING); } GLuint State::getRenderbufferId() const @@ -798,12 +941,12 @@ GLuint State::getRenderbufferId() const return mRenderbuffer.id(); } -Renderbuffer *State::getCurrentRenderbuffer() +Renderbuffer *State::getCurrentRenderbuffer() const { return mRenderbuffer.get(); } -void State::detachRenderbuffer(GLuint renderbuffer) +void State::detachRenderbuffer(const Context *context, 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 @@ -811,7 +954,7 @@ void State::detachRenderbuffer(GLuint renderbuffer) if (mRenderbuffer.id() == renderbuffer) { - mRenderbuffer.set(NULL); + setRenderbufferBinding(context, nullptr); } // [OpenGL ES 2.0.24] section 4.4 page 111: @@ -822,14 +965,17 @@ void State::detachRenderbuffer(GLuint renderbuffer) Framebuffer *readFramebuffer = mReadFramebuffer; Framebuffer *drawFramebuffer = mDrawFramebuffer; - if (readFramebuffer) + if (readFramebuffer && readFramebuffer->detachRenderbuffer(context, renderbuffer)) { - readFramebuffer->detachRenderbuffer(renderbuffer); + mDirtyObjects.set(DIRTY_OBJECT_READ_FRAMEBUFFER); } if (drawFramebuffer && drawFramebuffer != readFramebuffer) { - drawFramebuffer->detachRenderbuffer(renderbuffer); + if (drawFramebuffer->detachRenderbuffer(context, renderbuffer)) + { + mDirtyObjects.set(DIRTY_OBJECT_DRAW_FRAMEBUFFER); + } } } @@ -873,26 +1019,16 @@ Framebuffer *State::getTargetFramebuffer(GLenum target) const return mDrawFramebuffer; default: UNREACHABLE(); - return NULL; + return nullptr; } } -Framebuffer *State::getReadFramebuffer() +Framebuffer *State::getReadFramebuffer() const { return mReadFramebuffer; } -Framebuffer *State::getDrawFramebuffer() -{ - return mDrawFramebuffer; -} - -const Framebuffer *State::getReadFramebuffer() const -{ - return mReadFramebuffer; -} - -const Framebuffer *State::getDrawFramebuffer() const +Framebuffer *State::getDrawFramebuffer() const { return mDrawFramebuffer; } @@ -934,13 +1070,13 @@ void State::setVertexArrayBinding(VertexArray *vertexArray) GLuint State::getVertexArrayId() const { - ASSERT(mVertexArray != NULL); + ASSERT(mVertexArray != nullptr); return mVertexArray->id(); } VertexArray *State::getVertexArray() const { - ASSERT(mVertexArray != NULL); + ASSERT(mVertexArray != nullptr); return mVertexArray; } @@ -948,7 +1084,7 @@ bool State::removeVertexArrayBinding(GLuint vertexArray) { if (mVertexArray->id() == vertexArray) { - mVertexArray = NULL; + mVertexArray = nullptr; mDirtyBits.set(DIRTY_BIT_VERTEX_ARRAY_BINDING); mDirtyObjects.set(DIRTY_OBJECT_VERTEX_ARRAY); return true; @@ -957,13 +1093,47 @@ bool State::removeVertexArrayBinding(GLuint vertexArray) return false; } -void State::setProgram(Program *newProgram) +void State::bindVertexBuffer(const Context *context, + GLuint bindingIndex, + Buffer *boundBuffer, + GLintptr offset, + GLsizei stride) +{ + getVertexArray()->bindVertexBuffer(context, bindingIndex, boundBuffer, offset, stride); + mDirtyObjects.set(DIRTY_OBJECT_VERTEX_ARRAY); +} + +void State::setVertexAttribBinding(const Context *context, GLuint attribIndex, GLuint bindingIndex) +{ + getVertexArray()->setVertexAttribBinding(context, attribIndex, bindingIndex); + mDirtyObjects.set(DIRTY_OBJECT_VERTEX_ARRAY); +} + +void State::setVertexAttribFormat(GLuint attribIndex, + GLint size, + GLenum type, + bool normalized, + bool pureInteger, + GLuint relativeOffset) +{ + getVertexArray()->setVertexAttribFormat(attribIndex, size, type, normalized, pureInteger, + relativeOffset); + mDirtyObjects.set(DIRTY_OBJECT_VERTEX_ARRAY); +} + +void State::setVertexBindingDivisor(GLuint bindingIndex, GLuint divisor) +{ + getVertexArray()->setVertexBindingDivisor(bindingIndex, divisor); + mDirtyObjects.set(DIRTY_OBJECT_VERTEX_ARRAY); +} + +void State::setProgram(const Context *context, Program *newProgram) { if (mProgram != newProgram) { if (mProgram) { - mProgram->release(); + mProgram->release(context); } mProgram = newProgram; @@ -971,7 +1141,10 @@ void State::setProgram(Program *newProgram) if (mProgram) { newProgram->addRef(); + mDirtyObjects.set(DIRTY_OBJECT_PROGRAM_TEXTURES); } + mDirtyBits.set(DIRTY_BIT_PROGRAM_EXECUTABLE); + mDirtyBits.set(DIRTY_BIT_PROGRAM_BINDING); } } @@ -980,9 +1153,10 @@ Program *State::getProgram() const return mProgram; } -void State::setTransformFeedbackBinding(TransformFeedback *transformFeedback) +void State::setTransformFeedbackBinding(const Context *context, + TransformFeedback *transformFeedback) { - mTransformFeedback.set(transformFeedback); + mTransformFeedback.set(context, transformFeedback); } TransformFeedback *State::getCurrentTransformFeedback() const @@ -992,23 +1166,37 @@ TransformFeedback *State::getCurrentTransformFeedback() const bool State::isTransformFeedbackActiveUnpaused() const { - gl::TransformFeedback *curTransformFeedback = getCurrentTransformFeedback(); + TransformFeedback *curTransformFeedback = getCurrentTransformFeedback(); return curTransformFeedback && curTransformFeedback->isActive() && !curTransformFeedback->isPaused(); } -void State::detachTransformFeedback(GLuint transformFeedback) +bool State::removeTransformFeedbackBinding(const Context *context, GLuint transformFeedback) { if (mTransformFeedback.id() == transformFeedback) { - mTransformFeedback.set(NULL); + mTransformFeedback.set(context, nullptr); + return true; } + + return false; +} + +void State::setProgramPipelineBinding(const Context *context, ProgramPipeline *pipeline) +{ + mProgramPipeline.set(context, pipeline); +} + +void State::detachProgramPipeline(const Context *context, GLuint pipeline) +{ + mProgramPipeline.set(context, nullptr); } -bool State::isQueryActive() const +bool State::isQueryActive(const GLenum type) const { for (auto &iter : mActiveQueries) { - if (iter.second.get() != NULL) + const Query *query = iter.second.get(); + if (query != nullptr && ActiveQueryType(query->getType()) == ActiveQueryType(type)) { return true; } @@ -1030,9 +1218,9 @@ bool State::isQueryActive(Query *query) const return false; } -void State::setActiveQuery(GLenum target, Query *query) +void State::setActiveQuery(const Context *context, GLenum target, Query *query) { - mActiveQueries[target].set(query); + mActiveQueries[target].set(context, query); } GLuint State::getActiveQueryId(GLenum target) const @@ -1051,24 +1239,64 @@ Query *State::getActiveQuery(GLenum target) const return it->second.get(); } -void State::setArrayBufferBinding(Buffer *buffer) +void State::setBufferBinding(const Context *context, BufferBinding target, Buffer *buffer) { - mArrayBuffer.set(buffer); -} - -GLuint State::getArrayBufferId() const -{ - return mArrayBuffer.id(); + switch (target) + { + case BufferBinding::PixelPack: + mBoundBuffers[target].set(context, buffer); + mDirtyBits.set(DIRTY_BIT_PACK_BUFFER_BINDING); + break; + case BufferBinding::PixelUnpack: + mBoundBuffers[target].set(context, buffer); + mDirtyBits.set(DIRTY_BIT_UNPACK_BUFFER_BINDING); + break; + case BufferBinding::DrawIndirect: + mBoundBuffers[target].set(context, buffer); + mDirtyBits.set(DIRTY_BIT_DRAW_INDIRECT_BUFFER_BINDING); + break; + case BufferBinding::TransformFeedback: + if (mTransformFeedback.get() != nullptr) + { + mTransformFeedback->bindGenericBuffer(context, buffer); + } + break; + case BufferBinding::ElementArray: + getVertexArray()->setElementArrayBuffer(context, buffer); + mDirtyObjects.set(DIRTY_OBJECT_VERTEX_ARRAY); + break; + default: + mBoundBuffers[target].set(context, buffer); + break; + } } - -void State::setGenericUniformBufferBinding(Buffer *buffer) +void State::setIndexedBufferBinding(const Context *context, + BufferBinding target, + GLuint index, + Buffer *buffer, + GLintptr offset, + GLsizeiptr size) { - mGenericUniformBuffer.set(buffer); -} + setBufferBinding(context, target, buffer); -void State::setIndexedUniformBufferBinding(GLuint index, Buffer *buffer, GLintptr offset, GLsizeiptr size) -{ - mUniformBuffers[index].set(buffer, offset, size); + switch (target) + { + case BufferBinding::TransformFeedback: + mTransformFeedback->bindIndexedBuffer(context, index, buffer, offset, size); + break; + case BufferBinding::Uniform: + mUniformBuffers[index].set(context, buffer, offset, size); + break; + case BufferBinding::AtomicCounter: + mAtomicCounterBuffers[index].set(context, buffer, offset, size); + break; + case BufferBinding::ShaderStorage: + mShaderStorageBuffers[index].set(context, buffer, offset, size); + break; + default: + UNREACHABLE(); + break; + } } const OffsetBindingPointer &State::getIndexedUniformBuffer(size_t index) const @@ -1077,62 +1305,48 @@ const OffsetBindingPointer &State::getIndexedUniformBuffer(size_t index) return mUniformBuffers[index]; } -void State::setCopyReadBufferBinding(Buffer *buffer) +const OffsetBindingPointer &State::getIndexedAtomicCounterBuffer(size_t index) const { - mCopyReadBuffer.set(buffer); + ASSERT(static_cast(index) < mAtomicCounterBuffers.size()); + return mAtomicCounterBuffers[index]; } -void State::setCopyWriteBufferBinding(Buffer *buffer) +const OffsetBindingPointer &State::getIndexedShaderStorageBuffer(size_t index) const { - mCopyWriteBuffer.set(buffer); + ASSERT(static_cast(index) < mShaderStorageBuffers.size()); + return mShaderStorageBuffers[index]; } -void State::setPixelPackBufferBinding(Buffer *buffer) -{ - mPack.pixelBuffer.set(buffer); -} - -void State::setPixelUnpackBufferBinding(Buffer *buffer) -{ - mUnpack.pixelBuffer.set(buffer); -} - -Buffer *State::getTargetBuffer(GLenum target) const +Buffer *State::getTargetBuffer(BufferBinding 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().get(); - case GL_PIXEL_PACK_BUFFER: return mPack.pixelBuffer.get(); - case GL_PIXEL_UNPACK_BUFFER: return mUnpack.pixelBuffer.get(); - case GL_TRANSFORM_FEEDBACK_BUFFER: return mTransformFeedback->getGenericBuffer().get(); - case GL_UNIFORM_BUFFER: return mGenericUniformBuffer.get(); - default: UNREACHABLE(); return NULL; + case BufferBinding::ElementArray: + return getVertexArray()->getElementArrayBuffer().get(); + case BufferBinding::TransformFeedback: + return mTransformFeedback->getGenericBuffer().get(); + default: + return mBoundBuffers[target].get(); } } -void State::detachBuffer(GLuint bufferName) +void State::detachBuffer(const Context *context, GLuint bufferName) { - BindingPointer *buffers[] = {&mArrayBuffer, &mCopyReadBuffer, - &mCopyWriteBuffer, &mPack.pixelBuffer, - &mUnpack.pixelBuffer, &mGenericUniformBuffer}; - for (auto buffer : buffers) + for (auto &buffer : mBoundBuffers) { - if (buffer->id() == bufferName) + if (buffer.id() == bufferName) { - buffer->set(nullptr); + buffer.set(context, nullptr); } } TransformFeedback *curTransformFeedback = getCurrentTransformFeedback(); if (curTransformFeedback) { - curTransformFeedback->detachBuffer(bufferName); + curTransformFeedback->detachBuffer(context, bufferName); } - getVertexArray()->detachBuffer(bufferName); + getVertexArray()->detachBuffer(context, bufferName); } void State::setEnableVertexAttribArray(unsigned int attribNum, bool enabled) @@ -1145,46 +1359,56 @@ void State::setVertexAttribf(GLuint index, const GLfloat values[4]) { ASSERT(static_cast(index) < mVertexAttribCurrentValues.size()); mVertexAttribCurrentValues[index].setFloatValues(values); - mDirtyBits.set(DIRTY_BIT_CURRENT_VALUE_0 + index); + mDirtyBits.set(DIRTY_BIT_CURRENT_VALUES); + mDirtyCurrentValues.set(index); } void State::setVertexAttribu(GLuint index, const GLuint values[4]) { ASSERT(static_cast(index) < mVertexAttribCurrentValues.size()); mVertexAttribCurrentValues[index].setUnsignedIntValues(values); - mDirtyBits.set(DIRTY_BIT_CURRENT_VALUE_0 + index); + mDirtyBits.set(DIRTY_BIT_CURRENT_VALUES); + mDirtyCurrentValues.set(index); } void State::setVertexAttribi(GLuint index, const GLint values[4]) { ASSERT(static_cast(index) < mVertexAttribCurrentValues.size()); mVertexAttribCurrentValues[index].setIntValues(values); - mDirtyBits.set(DIRTY_BIT_CURRENT_VALUE_0 + index); + mDirtyBits.set(DIRTY_BIT_CURRENT_VALUES); + mDirtyCurrentValues.set(index); +} + +void State::setVertexAttribPointer(const Context *context, + unsigned int attribNum, + Buffer *boundBuffer, + GLint size, + GLenum type, + bool normalized, + bool pureInteger, + GLsizei stride, + const void *pointer) +{ + getVertexArray()->setVertexAttribPointer(context, attribNum, boundBuffer, size, type, + normalized, pureInteger, stride, pointer); + mDirtyObjects.set(DIRTY_OBJECT_VERTEX_ARRAY); } -void State::setVertexAttribState(unsigned int attribNum, - Buffer *boundBuffer, - GLint size, - GLenum type, - bool normalized, - bool pureInteger, - GLsizei stride, - const void *pointer) +void State::setVertexAttribDivisor(const Context *context, GLuint index, GLuint divisor) { - getVertexArray()->setAttributeState(attribNum, boundBuffer, size, type, normalized, pureInteger, stride, pointer); + getVertexArray()->setVertexAttribDivisor(context, index, divisor); mDirtyObjects.set(DIRTY_OBJECT_VERTEX_ARRAY); } -void State::setVertexAttribDivisor(GLuint index, GLuint divisor) +const VertexAttribCurrentValueData &State::getVertexAttribCurrentValue(size_t attribNum) const { - getVertexArray()->setVertexAttribDivisor(index, divisor); - mDirtyObjects.set(DIRTY_OBJECT_VERTEX_ARRAY); + ASSERT(attribNum < mVertexAttribCurrentValues.size()); + return mVertexAttribCurrentValues[attribNum]; } -const VertexAttribCurrentValueData &State::getVertexAttribCurrentValue(unsigned int attribNum) const +const std::vector &State::getVertexAttribCurrentValues() const { - ASSERT(static_cast(attribNum) < mVertexAttribCurrentValues.size()); - return mVertexAttribCurrentValues[attribNum]; + return mVertexAttribCurrentValues; } const void *State::getVertexAttribPointer(unsigned int attribNum) const @@ -1195,7 +1419,7 @@ const void *State::getVertexAttribPointer(unsigned int attribNum) const void State::setPackAlignment(GLint alignment) { mPack.alignment = alignment; - mDirtyBits.set(DIRTY_BIT_PACK_ALIGNMENT); + mDirtyBits.set(DIRTY_BIT_PACK_STATE); } GLint State::getPackAlignment() const @@ -1206,7 +1430,7 @@ GLint State::getPackAlignment() const void State::setPackReverseRowOrder(bool reverseRowOrder) { mPack.reverseRowOrder = reverseRowOrder; - mDirtyBits.set(DIRTY_BIT_PACK_REVERSE_ROW_ORDER); + mDirtyBits.set(DIRTY_BIT_PACK_STATE); } bool State::getPackReverseRowOrder() const @@ -1217,7 +1441,7 @@ bool State::getPackReverseRowOrder() const void State::setPackRowLength(GLint rowLength) { mPack.rowLength = rowLength; - mDirtyBits.set(DIRTY_BIT_PACK_ROW_LENGTH); + mDirtyBits.set(DIRTY_BIT_PACK_STATE); } GLint State::getPackRowLength() const @@ -1228,7 +1452,7 @@ GLint State::getPackRowLength() const void State::setPackSkipRows(GLint skipRows) { mPack.skipRows = skipRows; - mDirtyBits.set(DIRTY_BIT_PACK_SKIP_ROWS); + mDirtyBits.set(DIRTY_BIT_PACK_STATE); } GLint State::getPackSkipRows() const @@ -1239,7 +1463,7 @@ GLint State::getPackSkipRows() const void State::setPackSkipPixels(GLint skipPixels) { mPack.skipPixels = skipPixels; - mDirtyBits.set(DIRTY_BIT_PACK_SKIP_PIXELS); + mDirtyBits.set(DIRTY_BIT_PACK_STATE); } GLint State::getPackSkipPixels() const @@ -1260,7 +1484,7 @@ PixelPackState &State::getPackState() void State::setUnpackAlignment(GLint alignment) { mUnpack.alignment = alignment; - mDirtyBits.set(DIRTY_BIT_UNPACK_ALIGNMENT); + mDirtyBits.set(DIRTY_BIT_UNPACK_STATE); } GLint State::getUnpackAlignment() const @@ -1271,7 +1495,7 @@ GLint State::getUnpackAlignment() const void State::setUnpackRowLength(GLint rowLength) { mUnpack.rowLength = rowLength; - mDirtyBits.set(DIRTY_BIT_UNPACK_ROW_LENGTH); + mDirtyBits.set(DIRTY_BIT_UNPACK_STATE); } GLint State::getUnpackRowLength() const @@ -1282,7 +1506,7 @@ GLint State::getUnpackRowLength() const void State::setUnpackImageHeight(GLint imageHeight) { mUnpack.imageHeight = imageHeight; - mDirtyBits.set(DIRTY_BIT_UNPACK_IMAGE_HEIGHT); + mDirtyBits.set(DIRTY_BIT_UNPACK_STATE); } GLint State::getUnpackImageHeight() const @@ -1293,7 +1517,7 @@ GLint State::getUnpackImageHeight() const void State::setUnpackSkipImages(GLint skipImages) { mUnpack.skipImages = skipImages; - mDirtyBits.set(DIRTY_BIT_UNPACK_SKIP_IMAGES); + mDirtyBits.set(DIRTY_BIT_UNPACK_STATE); } GLint State::getUnpackSkipImages() const @@ -1304,7 +1528,7 @@ GLint State::getUnpackSkipImages() const void State::setUnpackSkipRows(GLint skipRows) { mUnpack.skipRows = skipRows; - mDirtyBits.set(DIRTY_BIT_UNPACK_SKIP_ROWS); + mDirtyBits.set(DIRTY_BIT_UNPACK_STATE); } GLint State::getUnpackSkipRows() const @@ -1315,7 +1539,7 @@ GLint State::getUnpackSkipRows() const void State::setUnpackSkipPixels(GLint skipPixels) { mUnpack.skipPixels = skipPixels; - mDirtyBits.set(DIRTY_BIT_UNPACK_SKIP_PIXELS); + mDirtyBits.set(DIRTY_BIT_UNPACK_STATE); } GLint State::getUnpackSkipPixels() const @@ -1343,6 +1567,84 @@ Debug &State::getDebug() return mDebug; } +void State::setCoverageModulation(GLenum components) +{ + mCoverageModulation = components; + mDirtyBits.set(DIRTY_BIT_COVERAGE_MODULATION); +} + +GLenum State::getCoverageModulation() const +{ + return mCoverageModulation; +} + +void State::loadPathRenderingMatrix(GLenum matrixMode, const GLfloat *matrix) +{ + if (matrixMode == GL_PATH_MODELVIEW_CHROMIUM) + { + memcpy(mPathMatrixMV, matrix, 16 * sizeof(GLfloat)); + mDirtyBits.set(DIRTY_BIT_PATH_RENDERING_MATRIX_MV); + } + else if (matrixMode == GL_PATH_PROJECTION_CHROMIUM) + { + memcpy(mPathMatrixProj, matrix, 16 * sizeof(GLfloat)); + mDirtyBits.set(DIRTY_BIT_PATH_RENDERING_MATRIX_PROJ); + } + else + { + UNREACHABLE(); + } +} + +const GLfloat *State::getPathRenderingMatrix(GLenum which) const +{ + if (which == GL_PATH_MODELVIEW_MATRIX_CHROMIUM) + { + return mPathMatrixMV; + } + else if (which == GL_PATH_PROJECTION_MATRIX_CHROMIUM) + { + return mPathMatrixProj; + } + + UNREACHABLE(); + return nullptr; +} + +void State::setPathStencilFunc(GLenum func, GLint ref, GLuint mask) +{ + mPathStencilFunc = func; + mPathStencilRef = ref; + mPathStencilMask = mask; + mDirtyBits.set(DIRTY_BIT_PATH_RENDERING_STENCIL_STATE); +} + +GLenum State::getPathStencilFunc() const +{ + return mPathStencilFunc; +} + +GLint State::getPathStencilRef() const +{ + return mPathStencilRef; +} + +GLuint State::getPathStencilMask() const +{ + return mPathStencilMask; +} + +void State::setFramebufferSRGB(bool sRGB) +{ + mFramebufferSRGB = sRGB; + mDirtyBits.set(DIRTY_BIT_FRAMEBUFFER_SRGB); +} + +bool State::getFramebufferSRGB() const +{ + return mFramebufferSRGB; +} + void State::getBooleanv(GLenum pname, GLboolean *params) { switch (pname) @@ -1355,10 +1657,15 @@ void State::getBooleanv(GLenum pname, GLboolean *params) params[2] = mBlend.colorMaskBlue; params[3] = mBlend.colorMaskAlpha; break; - case GL_CULL_FACE: *params = mRasterizer.cullFace; 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_SAMPLE_MASK: + *params = mSampleMask; + break; case GL_SCISSOR_TEST: *params = mScissorTest; break; case GL_STENCIL_TEST: *params = mDepthStencil.stencilTest; break; case GL_DEPTH_TEST: *params = mDepthStencil.depthTest; break; @@ -1378,6 +1685,28 @@ void State::getBooleanv(GLenum pname, GLboolean *params) case GL_DEBUG_OUTPUT: *params = mDebug.isOutputEnabled() ? GL_TRUE : GL_FALSE; break; + case GL_MULTISAMPLE_EXT: + *params = mMultiSampling; + break; + case GL_SAMPLE_ALPHA_TO_ONE_EXT: + *params = mSampleAlphaToOne; + break; + case GL_BIND_GENERATES_RESOURCE_CHROMIUM: + *params = isBindGeneratesResourceEnabled() ? GL_TRUE : GL_FALSE; + break; + case GL_CLIENT_ARRAYS_ANGLE: + *params = areClientArraysEnabled() ? GL_TRUE : GL_FALSE; + break; + case GL_FRAMEBUFFER_SRGB_EXT: + *params = getFramebufferSRGB() ? GL_TRUE : GL_FALSE; + break; + case GL_ROBUST_RESOURCE_INITIALIZATION_ANGLE: + *params = mRobustResourceInit ? GL_TRUE : GL_FALSE; + break; + case GL_PROGRAM_CACHE_ENABLED_ANGLE: + *params = mProgramBinaryCacheEnabled ? GL_TRUE : GL_FALSE; + break; + default: UNREACHABLE(); break; @@ -1413,13 +1742,21 @@ void State::getFloatv(GLenum pname, GLfloat *params) params[2] = mBlendColor.blue; params[3] = mBlendColor.alpha; break; + case GL_MULTISAMPLE_EXT: + *params = static_cast(mMultiSampling); + break; + case GL_SAMPLE_ALPHA_TO_ONE_EXT: + *params = static_cast(mSampleAlphaToOne); + case GL_COVERAGE_MODULATION_CHROMIUM: + params[0] = static_cast(mCoverageModulation); + break; default: UNREACHABLE(); break; } } -void State::getIntegerv(const gl::Data &data, GLenum pname, GLint *params) +void State::getIntegerv(const Context *context, GLenum pname, GLint *params) { if (pname >= GL_DRAW_BUFFER0_EXT && pname <= GL_DRAW_BUFFER15_EXT) { @@ -1437,8 +1774,15 @@ void State::getIntegerv(const gl::Data &data, GLenum pname, GLint *params) // State::getFloatv. switch (pname) { - case GL_ARRAY_BUFFER_BINDING: *params = mArrayBuffer.id(); break; - case GL_ELEMENT_ARRAY_BUFFER_BINDING: *params = getVertexArray()->getElementArrayBuffer().id(); break; + case GL_ARRAY_BUFFER_BINDING: + *params = mBoundBuffers[BufferBinding::Array].id(); + break; + case GL_DRAW_INDIRECT_BUFFER_BINDING: + *params = mBoundBuffers[BufferBinding::DrawIndirect].id(); + break; + case GL_ELEMENT_ARRAY_BUFFER_BINDING: + *params = getVertexArray()->getElementArrayBuffer().id(); + 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; @@ -1477,10 +1821,14 @@ void State::getIntegerv(const gl::Data &data, GLenum pname, GLint *params) 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_VALUE_MASK: + *params = CastMaskValue(context, 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_BACK_VALUE_MASK: + *params = CastMaskValue(context, 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; @@ -1494,32 +1842,40 @@ void State::getIntegerv(const gl::Data &data, GLenum pname, GLint *params) 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_WRITEMASK: + *params = CastMaskValue(context, mDepthStencil.stencilWritemask); + break; + case GL_STENCIL_BACK_WRITEMASK: + *params = CastMaskValue(context, 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_IMPLEMENTATION_COLOR_READ_TYPE: + *params = mReadFramebuffer->getImplementationColorReadType(context); + break; + case GL_IMPLEMENTATION_COLOR_READ_FORMAT: + *params = mReadFramebuffer->getImplementationColorReadFormat(context); + break; case GL_SAMPLE_BUFFERS: case GL_SAMPLES: { - gl::Framebuffer *framebuffer = mDrawFramebuffer; - if (framebuffer->checkStatus(data) == GL_FRAMEBUFFER_COMPLETE) + Framebuffer *framebuffer = mDrawFramebuffer; + if (framebuffer->checkStatus(context) == 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; + case GL_SAMPLE_BUFFERS: + if (framebuffer->getSamples(context) != 0) + { + *params = 1; + } + else + { + *params = 0; + } + break; + case GL_SAMPLES: + *params = framebuffer->getSamples(context); + break; } } else @@ -1540,15 +1896,19 @@ void State::getIntegerv(const gl::Data &data, GLenum pname, GLint *params) 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_CULL_FACE_MODE: + *params = ToGLenum(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(); - const gl::FramebufferAttachment *colorbuffer = framebuffer->getFirstColorbuffer(); + Framebuffer *framebuffer = getDrawFramebuffer(); + const FramebufferAttachment *colorbuffer = framebuffer->getFirstColorbuffer(); if (colorbuffer) { @@ -1568,8 +1928,8 @@ void State::getIntegerv(const gl::Data &data, GLenum pname, GLint *params) break; case GL_DEPTH_BITS: { - const gl::Framebuffer *framebuffer = getDrawFramebuffer(); - const gl::FramebufferAttachment *depthbuffer = framebuffer->getDepthbuffer(); + const Framebuffer *framebuffer = getDrawFramebuffer(); + const FramebufferAttachment *depthbuffer = framebuffer->getDepthbuffer(); if (depthbuffer) { @@ -1583,8 +1943,8 @@ void State::getIntegerv(const gl::Data &data, GLenum pname, GLint *params) break; case GL_STENCIL_BITS: { - const gl::Framebuffer *framebuffer = getDrawFramebuffer(); - const gl::FramebufferAttachment *stencilbuffer = framebuffer->getStencilbuffer(); + const Framebuffer *framebuffer = getDrawFramebuffer(); + const FramebufferAttachment *stencilbuffer = framebuffer->getStencilbuffer(); if (stencilbuffer) { @@ -1600,6 +1960,11 @@ void State::getIntegerv(const gl::Data &data, GLenum pname, GLint *params) ASSERT(mActiveSampler < mMaxCombinedTextureImageUnits); *params = getSamplerTextureId(static_cast(mActiveSampler), GL_TEXTURE_2D); break; + case GL_TEXTURE_BINDING_RECTANGLE_ANGLE: + ASSERT(mActiveSampler < mMaxCombinedTextureImageUnits); + *params = getSamplerTextureId(static_cast(mActiveSampler), + GL_TEXTURE_RECTANGLE_ANGLE); + break; case GL_TEXTURE_BINDING_CUBE_MAP: ASSERT(mActiveSampler < mMaxCombinedTextureImageUnits); *params = @@ -1614,27 +1979,45 @@ void State::getIntegerv(const gl::Data &data, GLenum pname, GLint *params) *params = getSamplerTextureId(static_cast(mActiveSampler), GL_TEXTURE_2D_ARRAY); break; + case GL_TEXTURE_BINDING_2D_MULTISAMPLE: + ASSERT(mActiveSampler < mMaxCombinedTextureImageUnits); + *params = getSamplerTextureId(static_cast(mActiveSampler), + GL_TEXTURE_2D_MULTISAMPLE); + break; + case GL_TEXTURE_BINDING_EXTERNAL_OES: + ASSERT(mActiveSampler < mMaxCombinedTextureImageUnits); + *params = getSamplerTextureId(static_cast(mActiveSampler), + GL_TEXTURE_EXTERNAL_OES); + break; case GL_UNIFORM_BUFFER_BINDING: - *params = mGenericUniformBuffer.id(); - break; + *params = mBoundBuffers[BufferBinding::Uniform].id(); + break; case GL_TRANSFORM_FEEDBACK_BINDING: *params = mTransformFeedback.id(); break; case GL_TRANSFORM_FEEDBACK_BUFFER_BINDING: - *params = mTransformFeedback->getGenericBuffer().id(); - break; + ASSERT(mTransformFeedback.get() != nullptr); + *params = mTransformFeedback->getGenericBuffer().id(); + break; case GL_COPY_READ_BUFFER_BINDING: - *params = mCopyReadBuffer.id(); - break; + *params = mBoundBuffers[BufferBinding::CopyRead].id(); + break; case GL_COPY_WRITE_BUFFER_BINDING: - *params = mCopyWriteBuffer.id(); - break; + *params = mBoundBuffers[BufferBinding::CopyWrite].id(); + break; case GL_PIXEL_PACK_BUFFER_BINDING: - *params = mPack.pixelBuffer.id(); - break; + *params = mBoundBuffers[BufferBinding::PixelPack].id(); + break; case GL_PIXEL_UNPACK_BUFFER_BINDING: - *params = mUnpack.pixelBuffer.id(); - break; + *params = mBoundBuffers[BufferBinding::PixelUnpack].id(); + break; + case GL_READ_BUFFER: + *params = mReadFramebuffer->getReadBufferState(); + break; + case GL_SAMPLER_BINDING: + ASSERT(mActiveSampler < mMaxCombinedTextureImageUnits); + *params = getSamplerId(static_cast(mActiveSampler)); + break; case GL_DEBUG_LOGGED_MESSAGES: *params = static_cast(mDebug.getMessageCount()); break; @@ -1644,6 +2027,20 @@ void State::getIntegerv(const gl::Data &data, GLenum pname, GLint *params) case GL_DEBUG_GROUP_STACK_DEPTH: *params = static_cast(mDebug.getGroupStackDepth()); break; + case GL_MULTISAMPLE_EXT: + *params = static_cast(mMultiSampling); + break; + case GL_SAMPLE_ALPHA_TO_ONE_EXT: + *params = static_cast(mSampleAlphaToOne); + case GL_COVERAGE_MODULATION_CHROMIUM: + *params = static_cast(mCoverageModulation); + break; + case GL_ATOMIC_COUNTER_BUFFER_BINDING: + *params = mBoundBuffers[BufferBinding::AtomicCounter].id(); + break; + case GL_SHADER_STORAGE_BUFFER_BINDING: + *params = mBoundBuffers[BufferBinding::ShaderStorage].id(); + break; default: UNREACHABLE(); break; @@ -1666,75 +2063,111 @@ void State::getPointerv(GLenum pname, void **params) const } } -bool State::getIndexedIntegerv(GLenum target, GLuint index, GLint *data) +void State::getIntegeri_v(GLenum target, GLuint index, GLint *data) { switch (target) { case GL_TRANSFORM_FEEDBACK_BUFFER_BINDING: - if (static_cast(index) < mTransformFeedback->getIndexedBufferCount()) - { - *data = mTransformFeedback->getIndexedBuffer(index).id(); - } - break; + ASSERT(static_cast(index) < mTransformFeedback->getIndexedBufferCount()); + *data = mTransformFeedback->getIndexedBuffer(index).id(); + break; case GL_UNIFORM_BUFFER_BINDING: - if (static_cast(index) < mUniformBuffers.size()) - { - *data = mUniformBuffers[index].id(); - } - break; + ASSERT(static_cast(index) < mUniformBuffers.size()); + *data = mUniformBuffers[index].id(); + break; + case GL_ATOMIC_COUNTER_BUFFER_BINDING: + ASSERT(static_cast(index) < mAtomicCounterBuffers.size()); + *data = mAtomicCounterBuffers[index].id(); + break; + case GL_SHADER_STORAGE_BUFFER_BINDING: + ASSERT(static_cast(index) < mShaderStorageBuffers.size()); + *data = mShaderStorageBuffers[index].id(); + break; + case GL_VERTEX_BINDING_BUFFER: + ASSERT(static_cast(index) < mVertexArray->getMaxBindings()); + *data = mVertexArray->getVertexBinding(index).getBuffer().id(); + break; + case GL_VERTEX_BINDING_DIVISOR: + ASSERT(static_cast(index) < mVertexArray->getMaxBindings()); + *data = mVertexArray->getVertexBinding(index).getDivisor(); + break; + case GL_VERTEX_BINDING_OFFSET: + ASSERT(static_cast(index) < mVertexArray->getMaxBindings()); + *data = static_cast(mVertexArray->getVertexBinding(index).getOffset()); + break; + case GL_VERTEX_BINDING_STRIDE: + ASSERT(static_cast(index) < mVertexArray->getMaxBindings()); + *data = mVertexArray->getVertexBinding(index).getStride(); + break; + case GL_SAMPLE_MASK_VALUE: + ASSERT(static_cast(index) < mSampleMaskValues.size()); + *data = mSampleMaskValues[index]; + break; default: - return false; + UNREACHABLE(); + break; } - - return true; } -bool State::getIndexedInteger64v(GLenum target, GLuint index, GLint64 *data) +void State::getInteger64i_v(GLenum target, GLuint index, GLint64 *data) { switch (target) { case GL_TRANSFORM_FEEDBACK_BUFFER_START: - if (static_cast(index) < mTransformFeedback->getIndexedBufferCount()) - { - *data = mTransformFeedback->getIndexedBuffer(index).getOffset(); - } - break; + ASSERT(static_cast(index) < mTransformFeedback->getIndexedBufferCount()); + *data = mTransformFeedback->getIndexedBuffer(index).getOffset(); + break; case GL_TRANSFORM_FEEDBACK_BUFFER_SIZE: - if (static_cast(index) < mTransformFeedback->getIndexedBufferCount()) - { - *data = mTransformFeedback->getIndexedBuffer(index).getSize(); - } - break; + ASSERT(static_cast(index) < mTransformFeedback->getIndexedBufferCount()); + *data = mTransformFeedback->getIndexedBuffer(index).getSize(); + break; case GL_UNIFORM_BUFFER_START: - if (static_cast(index) < mUniformBuffers.size()) - { - *data = mUniformBuffers[index].getOffset(); - } - break; + ASSERT(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; + ASSERT(static_cast(index) < mUniformBuffers.size()); + *data = mUniformBuffers[index].getSize(); + break; + case GL_ATOMIC_COUNTER_BUFFER_START: + ASSERT(static_cast(index) < mAtomicCounterBuffers.size()); + *data = mAtomicCounterBuffers[index].getOffset(); + break; + case GL_ATOMIC_COUNTER_BUFFER_SIZE: + ASSERT(static_cast(index) < mAtomicCounterBuffers.size()); + *data = mAtomicCounterBuffers[index].getSize(); + break; + case GL_SHADER_STORAGE_BUFFER_START: + ASSERT(static_cast(index) < mShaderStorageBuffers.size()); + *data = mShaderStorageBuffers[index].getOffset(); + break; + case GL_SHADER_STORAGE_BUFFER_SIZE: + ASSERT(static_cast(index) < mShaderStorageBuffers.size()); + *data = mShaderStorageBuffers[index].getSize(); + break; default: - return false; + UNREACHABLE(); + break; } +} - return true; +void State::getBooleani_v(GLenum target, GLuint index, GLboolean *data) +{ + UNREACHABLE(); } -bool State::hasMappedBuffer(GLenum target) const +bool State::hasMappedBuffer(BufferBinding target) const { - if (target == GL_ARRAY_BUFFER) + if (target == BufferBinding::Array) { - const VertexArray *vao = getVertexArray(); + const VertexArray *vao = getVertexArray(); const auto &vertexAttribs = vao->getVertexAttributes(); + const auto &vertexBindings = vao->getVertexBindings(); size_t maxEnabledAttrib = vao->getMaxEnabledAttribute(); for (size_t attribIndex = 0; attribIndex < maxEnabledAttrib; attribIndex++) { - const gl::VertexAttribute &vertexAttrib = vertexAttribs[attribIndex]; - gl::Buffer *boundBuffer = vertexAttrib.buffer.get(); + const VertexAttribute &vertexAttrib = vertexAttribs[attribIndex]; + auto *boundBuffer = vertexBindings[vertexAttrib.bindingIndex].getBuffer().get(); if (vertexAttrib.enabled && boundBuffer && boundBuffer->isMapped()) { return true; @@ -1750,35 +2183,36 @@ bool State::hasMappedBuffer(GLenum target) const } } -void State::syncDirtyObjects() +void State::syncDirtyObjects(const Context *context) { if (!mDirtyObjects.any()) return; - syncDirtyObjects(mDirtyObjects); + syncDirtyObjects(context, mDirtyObjects); } -void State::syncDirtyObjects(const DirtyObjects &bitset) +void State::syncDirtyObjects(const Context *context, const DirtyObjects &bitset) { - for (auto dirtyObject : angle::IterateBitSet(bitset)) + for (auto dirtyObject : bitset) { switch (dirtyObject) { case DIRTY_OBJECT_READ_FRAMEBUFFER: ASSERT(mReadFramebuffer); - mReadFramebuffer->syncState(); + mReadFramebuffer->syncState(context); break; case DIRTY_OBJECT_DRAW_FRAMEBUFFER: ASSERT(mDrawFramebuffer); - mDrawFramebuffer->syncState(); + mDrawFramebuffer->syncState(context); break; case DIRTY_OBJECT_VERTEX_ARRAY: ASSERT(mVertexArray); - mVertexArray->syncImplState(); + mVertexArray->syncState(context); break; - case DIRTY_OBJECT_PROGRAM: - // TODO(jmadill): implement this + case DIRTY_OBJECT_PROGRAM_TEXTURES: + syncProgramTextures(context); break; + default: UNREACHABLE(); break; @@ -1788,7 +2222,82 @@ void State::syncDirtyObjects(const DirtyObjects &bitset) mDirtyObjects &= ~bitset; } -void State::syncDirtyObject(GLenum target) +void State::syncProgramTextures(const Context *context) +{ + // TODO(jmadill): Fine-grained updates. + if (!mProgram) + { + return; + } + + ASSERT(mDirtyObjects[DIRTY_OBJECT_PROGRAM_TEXTURES]); + mDirtyBits.set(DIRTY_BIT_TEXTURE_BINDINGS); + + ActiveTextureMask newActiveTextures; + + // Initialize to the 'Initialized' state and set to 'MayNeedInit' if any texture is not + // initialized. + mCachedTexturesInitState = InitState::Initialized; + + for (const SamplerBinding &samplerBinding : mProgram->getSamplerBindings()) + { + if (samplerBinding.unreferenced) + continue; + + GLenum textureType = samplerBinding.textureType; + for (GLuint textureUnitIndex : samplerBinding.boundTextureUnits) + { + Texture *texture = getSamplerTexture(textureUnitIndex, textureType); + Sampler *sampler = getSampler(textureUnitIndex); + ASSERT(static_cast(textureUnitIndex) < mCompleteTextureCache.size()); + ASSERT(static_cast(textureUnitIndex) < newActiveTextures.size()); + + ASSERT(texture); + + // Mark the texture binding bit as dirty if the texture completeness changes. + // TODO(jmadill): Use specific dirty bit for completeness change. + if (texture->isSamplerComplete(context, sampler) && + !mDrawFramebuffer->hasTextureAttachment(texture)) + { + texture->syncState(); + mCompleteTextureCache[textureUnitIndex] = texture; + } + else + { + mCompleteTextureCache[textureUnitIndex] = nullptr; + } + + // Bind the texture unconditionally, to recieve completeness change notifications. + mCompleteTextureBindings[textureUnitIndex].bind(texture->getDirtyChannel()); + mActiveTexturesMask.set(textureUnitIndex); + newActiveTextures.set(textureUnitIndex); + + if (sampler != nullptr) + { + sampler->syncState(context); + } + + if (texture->initState() == InitState::MayNeedInit) + { + mCachedTexturesInitState = InitState::MayNeedInit; + } + } + } + + // Unset now missing textures. + ActiveTextureMask negativeMask = mActiveTexturesMask & ~newActiveTextures; + if (negativeMask.any()) + { + for (auto textureIndex : negativeMask) + { + mCompleteTextureBindings[textureIndex].reset(); + mCompleteTextureCache[textureIndex] = nullptr; + mActiveTexturesMask.reset(textureIndex); + } + } +} + +void State::syncDirtyObject(const Context *context, GLenum target) { DirtyObjects localSet; @@ -1807,12 +2316,14 @@ void State::syncDirtyObject(GLenum target) case GL_VERTEX_ARRAY: localSet.set(DIRTY_OBJECT_VERTEX_ARRAY); break; + case GL_TEXTURE: + case GL_SAMPLER: case GL_PROGRAM: - localSet.set(DIRTY_OBJECT_PROGRAM); + localSet.set(DIRTY_OBJECT_PROGRAM_TEXTURES); break; } - syncDirtyObjects(localSet); + syncDirtyObjects(context, localSet); } void State::setObjectDirty(GLenum target) @@ -1832,10 +2343,91 @@ void State::setObjectDirty(GLenum target) case GL_VERTEX_ARRAY: mDirtyObjects.set(DIRTY_OBJECT_VERTEX_ARRAY); break; + case GL_TEXTURE: + case GL_SAMPLER: case GL_PROGRAM: - mDirtyObjects.set(DIRTY_OBJECT_PROGRAM); + mDirtyObjects.set(DIRTY_OBJECT_PROGRAM_TEXTURES); + mDirtyBits.set(DIRTY_BIT_TEXTURE_BINDINGS); break; } } +void State::onProgramExecutableChange(Program *program) +{ + // OpenGL Spec: + // "If LinkProgram or ProgramBinary successfully re-links a program object + // that was already in use as a result of a previous call to UseProgram, then the + // generated executable code will be installed as part of the current rendering state." + if (program->isLinked() && mProgram == program) + { + mDirtyBits.set(DIRTY_BIT_PROGRAM_EXECUTABLE); + mDirtyObjects.set(DIRTY_OBJECT_PROGRAM_TEXTURES); + } +} + +void State::setImageUnit(const Context *context, + GLuint unit, + Texture *texture, + GLint level, + GLboolean layered, + GLint layer, + GLenum access, + GLenum format) +{ + mImageUnits[unit].texture.set(context, texture); + mImageUnits[unit].level = level; + mImageUnits[unit].layered = layered; + mImageUnits[unit].layer = layer; + mImageUnits[unit].access = access; + mImageUnits[unit].format = format; +} + +const ImageUnit &State::getImageUnit(GLuint unit) const +{ + return mImageUnits[unit]; +} + +// Handle a dirty texture event. +void State::signal(size_t textureIndex, InitState initState) +{ + // Conservatively assume all textures are dirty. + // TODO(jmadill): More fine-grained update. + mDirtyObjects.set(DIRTY_OBJECT_PROGRAM_TEXTURES); + + if (initState == InitState::MayNeedInit) + { + mCachedTexturesInitState = InitState::MayNeedInit; + } +} + +Error State::clearUnclearedActiveTextures(const Context *context) +{ + ASSERT(mRobustResourceInit); + + if (mCachedTexturesInitState == InitState::Initialized) + { + return NoError(); + } + + for (auto textureIndex : mActiveTexturesMask) + { + Texture *texture = mCompleteTextureCache[textureIndex]; + if (texture) + { + ANGLE_TRY(texture->ensureInitialized(context)); + } + } + + mCachedTexturesInitState = InitState::Initialized; + + return NoError(); +} + +AttributesMask State::getAndResetDirtyCurrentValues() const +{ + AttributesMask retVal = mDirtyCurrentValues; + mDirtyCurrentValues.reset(); + return retVal; +} + } // namespace gl diff --git a/src/3rdparty/angle/src/libANGLE/State.h b/src/3rdparty/angle/src/libANGLE/State.h index e822d7e679..52e1d78382 100644 --- a/src/3rdparty/angle/src/libANGLE/State.h +++ b/src/3rdparty/angle/src/libANGLE/State.h @@ -12,14 +12,18 @@ #include #include +#include "common/Color.h" #include "common/angleutils.h" +#include "common/bitset_utils.h" #include "libANGLE/Debug.h" #include "libANGLE/Program.h" +#include "libANGLE/ProgramPipeline.h" #include "libANGLE/RefCountObject.h" #include "libANGLE/Renderbuffer.h" #include "libANGLE/Sampler.h" #include "libANGLE/Texture.h" #include "libANGLE/TransformFeedback.h" +#include "libANGLE/Version.h" #include "libANGLE/VertexAttribute.h" #include "libANGLE/angletypes.h" @@ -29,21 +33,20 @@ class Query; class VertexArray; class Context; struct Caps; -struct Data; -typedef std::map> TextureMap; - -class State : angle::NonCopyable +class State : public OnAttachmentDirtyReceiver, angle::NonCopyable { public: State(); - ~State(); + ~State() override; - void initialize(const Caps &caps, - const Extensions &extensions, - GLuint clientVersion, - bool debug); - void reset(); + void initialize(const Context *context, + bool debug, + bool bindGeneratesResource, + bool clientArraysEnabled, + bool robustResourceInit, + bool programBinaryCacheEnabled); + void reset(const Context *context); // State chunk getters const RasterizerState &getRasterizerState() const; @@ -74,7 +77,7 @@ class State : angle::NonCopyable // Face culling state manipulation bool isCullFaceEnabled() const; void setCullFace(bool enabled); - void setCullMode(GLenum mode); + void setCullMode(CullFaceMode mode); void setFrontFace(GLenum front); // Depth test state manipulation @@ -100,8 +103,12 @@ class State : angle::NonCopyable 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); + void setStencilOperations(GLenum stencilFail, + GLenum stencilPassDepthFail, + GLenum stencilPassDepthPass); + void setStencilBackOperations(GLenum stencilBackFail, + GLenum stencilBackPassDepthFail, + GLenum stencilBackPassDepthPass); GLint getStencilRef() const; GLint getStencilBackRef() const; @@ -116,9 +123,22 @@ class State : angle::NonCopyable bool isSampleCoverageEnabled() const; void setSampleCoverage(bool enabled); void setSampleCoverageParams(GLclampf value, bool invert); - GLclampf getSampleCoverageValue() const; + GLfloat getSampleCoverageValue() const; bool getSampleCoverageInvert() const; + // Multisample mask state manipulation. + bool isSampleMaskEnabled() const; + void setSampleMaskEnabled(bool enabled); + void setSampleMaskParams(GLuint maskNumber, GLbitfield mask); + GLbitfield getSampleMaskWord(GLuint maskNumber) const; + GLuint getMaxSampleMaskWords() const; + + // Multisampling/alpha to one manipulation. + void setSampleAlphaToOne(bool enabled); + bool isSampleAlphaToOneEnabled() const; + void setMultisampling(bool enabled); + bool isMultisamplingEnabled() const; + // Scissor test state toggle & query bool isScissorTestEnabled() const; void setScissorTest(bool enabled); @@ -131,7 +151,7 @@ class State : angle::NonCopyable // Generic state toggle & query void setEnableFeature(GLenum feature, bool enabled); - bool getEnableFeature(GLenum feature); + bool getEnableFeature(GLenum feature) const; // Line width state setter void setLineWidth(GLfloat width); @@ -141,6 +161,12 @@ class State : angle::NonCopyable void setGenerateMipmapHint(GLenum hint); void setFragmentShaderDerivativeHint(GLenum hint); + // GL_CHROMIUM_bind_generates_resource + bool isBindGeneratesResourceEnabled() const; + + // GL_ANGLE_client_arrays + bool areClientArraysEnabled() const; + // Viewport state setter/getter void setViewportParams(GLint x, GLint y, GLsizei width, GLsizei height); const Rectangle &getViewport() const; @@ -148,33 +174,31 @@ class State : angle::NonCopyable // Texture binding & active texture unit manipulation void setActiveSampler(unsigned int active); unsigned int getActiveSampler() const; - void setSamplerTexture(GLenum type, Texture *texture); + void setSamplerTexture(const Context *context, GLenum type, Texture *texture); Texture *getTargetTexture(GLenum target) const; 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); + void detachTexture(const Context *context, const TextureMap &zeroTextures, GLuint texture); + void initializeZeroTextures(const Context *context, const TextureMap &zeroTextures); // Sampler object binding manipulation - void setSamplerBinding(GLuint textureUnit, Sampler *sampler); + void setSamplerBinding(const Context *context, GLuint textureUnit, Sampler *sampler); GLuint getSamplerId(GLuint textureUnit) const; Sampler *getSampler(GLuint textureUnit) const; - void detachSampler(GLuint sampler); + void detachSampler(const Context *context, GLuint sampler); // Renderbuffer binding manipulation - void setRenderbufferBinding(Renderbuffer *renderbuffer); + void setRenderbufferBinding(const Context *context, Renderbuffer *renderbuffer); GLuint getRenderbufferId() const; - Renderbuffer *getCurrentRenderbuffer(); - void detachRenderbuffer(GLuint renderbuffer); + Renderbuffer *getCurrentRenderbuffer() const; + void detachRenderbuffer(const Context *context, 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; + Framebuffer *getReadFramebuffer() const; + Framebuffer *getDrawFramebuffer() const; bool removeReadFramebufferBinding(GLuint framebuffer); bool removeDrawFramebufferBinding(GLuint framebuffer); @@ -185,55 +209,75 @@ class State : angle::NonCopyable bool removeVertexArrayBinding(GLuint vertexArray); // Program binding manipulation - void setProgram(Program *newProgram); + void setProgram(const Context *context, Program *newProgram); Program *getProgram() const; // Transform feedback object (not buffer) binding manipulation - void setTransformFeedbackBinding(TransformFeedback *transformFeedback); + void setTransformFeedbackBinding(const Context *context, TransformFeedback *transformFeedback); TransformFeedback *getCurrentTransformFeedback() const; bool isTransformFeedbackActiveUnpaused() const; - void detachTransformFeedback(GLuint transformFeedback); + bool removeTransformFeedbackBinding(const Context *context, GLuint transformFeedback); // Query binding manipulation - bool isQueryActive() const; + bool isQueryActive(const GLenum type) const; bool isQueryActive(Query *query) const; - void setActiveQuery(GLenum target, Query *query); + void setActiveQuery(const Context *context, GLenum target, Query *query); GLuint getActiveQueryId(GLenum target) const; Query *getActiveQuery(GLenum target) const; + // Program Pipeline binding manipulation + void setProgramPipelineBinding(const Context *context, ProgramPipeline *pipeline); + void detachProgramPipeline(const Context *context, GLuint pipeline); + //// Typed buffer binding point manipulation //// - // GL_ARRAY_BUFFER - void setArrayBufferBinding(Buffer *buffer); - GLuint getArrayBufferId() const; + void setBufferBinding(const Context *context, BufferBinding target, Buffer *buffer); + Buffer *getTargetBuffer(BufferBinding target) const; + void setIndexedBufferBinding(const Context *context, + BufferBinding target, + GLuint index, + Buffer *buffer, + GLintptr offset, + GLsizeiptr size); - // GL_UNIFORM_BUFFER - Both indexed and generic targets - void setGenericUniformBufferBinding(Buffer *buffer); - void setIndexedUniformBufferBinding(GLuint index, Buffer *buffer, GLintptr offset, GLsizeiptr size); const OffsetBindingPointer &getIndexedUniformBuffer(size_t index) const; + const OffsetBindingPointer &getIndexedAtomicCounterBuffer(size_t index) const; + const OffsetBindingPointer &getIndexedShaderStorageBuffer(size_t index) 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; // Detach a buffer from all bindings - void detachBuffer(GLuint bufferName); + void detachBuffer(const Context *context, GLuint bufferName); // Vertex attrib manipulation void setEnableVertexAttribArray(unsigned int attribNum, bool enabled); + void setElementArrayBuffer(const Context *context, Buffer *buffer); 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); - void setVertexAttribDivisor(GLuint index, GLuint divisor); - const VertexAttribCurrentValueData &getVertexAttribCurrentValue(unsigned int attribNum) const; + void setVertexAttribPointer(const Context *context, + unsigned int attribNum, + Buffer *boundBuffer, + GLint size, + GLenum type, + bool normalized, + bool pureInteger, + GLsizei stride, + const void *pointer); + void setVertexAttribDivisor(const Context *context, GLuint index, GLuint divisor); + const VertexAttribCurrentValueData &getVertexAttribCurrentValue(size_t attribNum) const; + const std::vector &getVertexAttribCurrentValues() const; const void *getVertexAttribPointer(unsigned int attribNum) const; + void bindVertexBuffer(const Context *context, + GLuint bindingIndex, + Buffer *boundBuffer, + GLintptr offset, + GLsizei stride); + void setVertexAttribFormat(GLuint attribIndex, + GLint size, + GLenum type, + bool normalized, + bool pureInteger, + GLuint relativeOffset); + void setVertexAttribBinding(const Context *context, GLuint attribIndex, GLuint bindingIndex); + void setVertexBindingDivisor(GLuint bindingIndex, GLuint divisor); // Pixel pack state manipulation void setPackAlignment(GLint alignment); @@ -269,15 +313,37 @@ class State : angle::NonCopyable const Debug &getDebug() const; Debug &getDebug(); + // CHROMIUM_framebuffer_mixed_samples coverage modulation + void setCoverageModulation(GLenum components); + GLenum getCoverageModulation() const; + + // CHROMIUM_path_rendering + void loadPathRenderingMatrix(GLenum matrixMode, const GLfloat *matrix); + const GLfloat *getPathRenderingMatrix(GLenum which) const; + void setPathStencilFunc(GLenum func, GLint ref, GLuint mask); + + GLenum getPathStencilFunc() const; + GLint getPathStencilRef() const; + GLuint getPathStencilMask() const; + + // GL_EXT_sRGB_write_control + void setFramebufferSRGB(bool sRGB); + bool getFramebufferSRGB() const; + // 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); + void getIntegerv(const Context *context, GLenum pname, GLint *params); void getPointerv(GLenum pname, void **params) const; - bool getIndexedIntegerv(GLenum target, GLuint index, GLint *data); - bool getIndexedInteger64v(GLenum target, GLuint index, GLint64 *data); + void getIntegeri_v(GLenum target, GLuint index, GLint *data); + void getInteger64i_v(GLenum target, GLuint index, GLint64 *data); + void getBooleani_v(GLenum target, GLuint index, GLboolean *data); - bool hasMappedBuffer(GLenum target) const; + bool hasMappedBuffer(BufferBinding target) const; + bool isRobustResourceInitEnabled() const { return mRobustResourceInit; } + + // Sets the dirty bit for the program executable. + void onProgramExecutableChange(Program *program); enum DirtyBitType { @@ -293,6 +359,8 @@ class State : angle::NonCopyable DIRTY_BIT_SAMPLE_ALPHA_TO_COVERAGE_ENABLED, DIRTY_BIT_SAMPLE_COVERAGE_ENABLED, DIRTY_BIT_SAMPLE_COVERAGE, + DIRTY_BIT_SAMPLE_MASK_ENABLED, + DIRTY_BIT_SAMPLE_MASK, DIRTY_BIT_DEPTH_TEST_ENABLED, DIRTY_BIT_DEPTH_FUNC, DIRTY_BIT_DEPTH_MASK, @@ -314,17 +382,10 @@ class State : angle::NonCopyable DIRTY_BIT_CLEAR_COLOR, DIRTY_BIT_CLEAR_DEPTH, DIRTY_BIT_CLEAR_STENCIL, - DIRTY_BIT_UNPACK_ALIGNMENT, - DIRTY_BIT_UNPACK_ROW_LENGTH, - DIRTY_BIT_UNPACK_IMAGE_HEIGHT, - DIRTY_BIT_UNPACK_SKIP_IMAGES, - DIRTY_BIT_UNPACK_SKIP_ROWS, - DIRTY_BIT_UNPACK_SKIP_PIXELS, - DIRTY_BIT_PACK_ALIGNMENT, - DIRTY_BIT_PACK_REVERSE_ROW_ORDER, - DIRTY_BIT_PACK_ROW_LENGTH, - DIRTY_BIT_PACK_SKIP_ROWS, - DIRTY_BIT_PACK_SKIP_PIXELS, + DIRTY_BIT_UNPACK_STATE, + DIRTY_BIT_UNPACK_BUFFER_BINDING, + DIRTY_BIT_PACK_STATE, + DIRTY_BIT_PACK_BUFFER_BINDING, DIRTY_BIT_DITHER_ENABLED, DIRTY_BIT_GENERATE_MIPMAP_HINT, DIRTY_BIT_SHADER_DERIVATIVE_HINT, @@ -332,51 +393,83 @@ class State : angle::NonCopyable DIRTY_BIT_DRAW_FRAMEBUFFER_BINDING, DIRTY_BIT_RENDERBUFFER_BINDING, DIRTY_BIT_VERTEX_ARRAY_BINDING, + DIRTY_BIT_DRAW_INDIRECT_BUFFER_BINDING, DIRTY_BIT_PROGRAM_BINDING, - DIRTY_BIT_CURRENT_VALUE_0, - DIRTY_BIT_CURRENT_VALUE_MAX = DIRTY_BIT_CURRENT_VALUE_0 + MAX_VERTEX_ATTRIBS, - DIRTY_BIT_INVALID = DIRTY_BIT_CURRENT_VALUE_MAX, - DIRTY_BIT_MAX = DIRTY_BIT_INVALID, + DIRTY_BIT_PROGRAM_EXECUTABLE, + // TODO(jmadill): Fine-grained dirty bits for each texture/sampler. + DIRTY_BIT_TEXTURE_BINDINGS, + DIRTY_BIT_SAMPLER_BINDINGS, + DIRTY_BIT_MULTISAMPLING, + DIRTY_BIT_SAMPLE_ALPHA_TO_ONE, + DIRTY_BIT_COVERAGE_MODULATION, // CHROMIUM_framebuffer_mixed_samples + DIRTY_BIT_PATH_RENDERING_MATRIX_MV, // CHROMIUM_path_rendering path model view matrix + DIRTY_BIT_PATH_RENDERING_MATRIX_PROJ, // CHROMIUM_path_rendering path projection matrix + DIRTY_BIT_PATH_RENDERING_STENCIL_STATE, + DIRTY_BIT_FRAMEBUFFER_SRGB, // GL_EXT_sRGB_write_control + DIRTY_BIT_CURRENT_VALUES, + DIRTY_BIT_INVALID, + DIRTY_BIT_MAX = DIRTY_BIT_INVALID, }; + static_assert(DIRTY_BIT_MAX <= 64, "State dirty bits must be capped at 64"); + // TODO(jmadill): Consider storing dirty objects in a list instead of by binding. enum DirtyObjectType { DIRTY_OBJECT_READ_FRAMEBUFFER, DIRTY_OBJECT_DRAW_FRAMEBUFFER, DIRTY_OBJECT_VERTEX_ARRAY, - DIRTY_OBJECT_PROGRAM, + // Use a very coarse bit for any program or texture change. + // TODO(jmadill): Fine-grained dirty bits for each texture/sampler. + DIRTY_OBJECT_PROGRAM_TEXTURES, DIRTY_OBJECT_UNKNOWN, DIRTY_OBJECT_MAX = DIRTY_OBJECT_UNKNOWN, }; - typedef std::bitset DirtyBits; + typedef angle::BitSet DirtyBits; const DirtyBits &getDirtyBits() const { return mDirtyBits; } void clearDirtyBits() { mDirtyBits.reset(); } void clearDirtyBits(const DirtyBits &bitset) { mDirtyBits &= ~bitset; } void setAllDirtyBits() { mDirtyBits.set(); } - typedef std::bitset DirtyObjects; + typedef angle::BitSet DirtyObjects; void clearDirtyObjects() { mDirtyObjects.reset(); } void setAllDirtyObjects() { mDirtyObjects.set(); } - void syncDirtyObjects(); - void syncDirtyObjects(const DirtyObjects &bitset); - void syncDirtyObject(GLenum target); + void syncDirtyObjects(const Context *context); + void syncDirtyObjects(const Context *context, const DirtyObjects &bitset); + void syncDirtyObject(const Context *context, GLenum target); void setObjectDirty(GLenum target); - // Dirty bit masks - const DirtyBits &unpackStateBitMask() const { return mUnpackStateBitMask; } - const DirtyBits &packStateBitMask() const { return mPackStateBitMask; } - const DirtyBits &clearStateBitMask() const { return mClearStateBitMask; } - const DirtyBits &blitStateBitMask() const { return mBlitStateBitMask; } + // This actually clears the current value dirty bits. + // TODO(jmadill): Pass mutable dirty bits into Impl. + AttributesMask getAndResetDirtyCurrentValues() const; + + void setImageUnit(const Context *context, + GLuint unit, + Texture *texture, + GLint level, + GLboolean layered, + GLint layer, + GLenum access, + GLenum format); + + const ImageUnit &getImageUnit(GLuint unit) const; + const std::vector &getCompleteTextureCache() const { return mCompleteTextureCache; } + + // Handle a dirty texture event. + void signal(size_t textureIndex, InitState initState) override; + + Error clearUnclearedActiveTextures(const Context *context); private: + void syncProgramTextures(const Context *context); + // Cached values from Context's caps GLuint mMaxDrawBuffers; GLuint mMaxCombinedTextureImageUnits; ColorF mColorClearValue; - GLclampf mDepthClearValue; + GLfloat mDepthClearValue; int mStencilClearValue; RasterizerState mRasterizer; @@ -386,8 +479,11 @@ class State : angle::NonCopyable BlendState mBlend; ColorF mBlendColor; bool mSampleCoverage; - GLclampf mSampleCoverageValue; + GLfloat mSampleCoverageValue; bool mSampleCoverageInvert; + bool mSampleMask; + GLuint mMaxSampleMaskWords; + std::array mSampleMaskValues; DepthStencilState mDepthStencil; GLint mStencilRef; @@ -398,59 +494,109 @@ class State : angle::NonCopyable GLenum mGenerateMipmapHint; GLenum mFragmentShaderDerivativeHint; + bool mBindGeneratesResource; + bool mClientArraysEnabled; + Rectangle mViewport; float mNearZ; float mFarZ; - BindingPointer mArrayBuffer; Framebuffer *mReadFramebuffer; Framebuffer *mDrawFramebuffer; BindingPointer mRenderbuffer; Program *mProgram; + BindingPointer mProgramPipeline; typedef std::vector VertexAttribVector; - VertexAttribVector mVertexAttribCurrentValues; // From glVertexAttrib + VertexAttribVector mVertexAttribCurrentValues; // From glVertexAttrib VertexArray *mVertexArray; // Texture and sampler bindings - size_t mActiveSampler; // Active texture unit selector - GL_TEXTURE0 + size_t mActiveSampler; // Active texture unit selector - GL_TEXTURE0 typedef std::vector> TextureBindingVector; typedef std::map TextureBindingMap; TextureBindingMap mSamplerTextures; + // Texture Completeness Caching + // ---------------------------- + // The texture completeness cache uses dirty bits to avoid having to scan the list + // of textures each draw call. This gl::State class implements OnAttachmentDirtyReceiver, + // and keeps an array of bindings to the Texture class. When the Textures are marked dirty, + // they send messages to the State class (and any Framebuffers they're attached to) via the + // State::signal method (see above). Internally this then invalidates the completeness cache. + // + // Note this requires that we also invalidate the completeness cache manually on events like + // re-binding textures/samplers or a change in the program. For more information see the + // signal_utils.h header and the design doc linked there. + + // A cache of complete textures. nullptr indicates unbound or incomplete. + // Don't use BindingPointer because this cache is only valid within a draw call. + // Also stores a notification channel to the texture itself to handle texture change events. + std::vector mCompleteTextureCache; + std::vector mCompleteTextureBindings; + InitState mCachedTexturesInitState; + using ActiveTextureMask = angle::BitSet; + ActiveTextureMask mActiveTexturesMask; + typedef std::vector> SamplerBindingVector; SamplerBindingVector mSamplers; + typedef std::vector ImageUnitVector; + ImageUnitVector mImageUnits; + typedef std::map> ActiveQueryMap; ActiveQueryMap mActiveQueries; - BindingPointer mGenericUniformBuffer; - typedef std::vector> BufferVector; + // Stores the currently bound buffer for each binding point. It has entries for the element + // array buffer and the transform feedback buffer but these should not be used. Instead these + // bind points are respectively owned by current the vertex array object and the current + // transform feedback object. + using BoundBufferMap = angle::PackedEnumMap>; + BoundBufferMap mBoundBuffers; + + using BufferVector = std::vector>; BufferVector mUniformBuffers; + BufferVector mAtomicCounterBuffers; + BufferVector mShaderStorageBuffers; BindingPointer mTransformFeedback; - BindingPointer mCopyReadBuffer; - BindingPointer mCopyWriteBuffer; - + BindingPointer mPixelUnpackBuffer; PixelUnpackState mUnpack; + BindingPointer mPixelPackBuffer; PixelPackState mPack; bool mPrimitiveRestart; Debug mDebug; - DirtyBits mDirtyBits; - DirtyBits mUnpackStateBitMask; - DirtyBits mPackStateBitMask; - DirtyBits mClearStateBitMask; - DirtyBits mBlitStateBitMask; + bool mMultiSampling; + bool mSampleAlphaToOne; + + GLenum mCoverageModulation; + + // CHROMIUM_path_rendering + GLfloat mPathMatrixMV[16]; + GLfloat mPathMatrixProj[16]; + GLenum mPathStencilFunc; + GLint mPathStencilRef; + GLuint mPathStencilMask; + + // GL_EXT_sRGB_write_control + bool mFramebufferSRGB; + // GL_ANGLE_robust_resource_intialization + bool mRobustResourceInit; + + // GL_ANGLE_program_cache_control + bool mProgramBinaryCacheEnabled; + + DirtyBits mDirtyBits; DirtyObjects mDirtyObjects; + mutable AttributesMask mDirtyCurrentValues; }; -} - -#endif // LIBANGLE_STATE_H_ +} // namespace gl +#endif // LIBANGLE_STATE_H_ diff --git a/src/3rdparty/angle/src/libANGLE/Stream.cpp b/src/3rdparty/angle/src/libANGLE/Stream.cpp new file mode 100644 index 0000000000..68279976b7 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/Stream.cpp @@ -0,0 +1,271 @@ +// +// Copyright (c) 2016 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. +// + +// Stream.cpp: Implements the egl::Stream class, representing the stream +// where frames are streamed in. Implements EGLStreanKHR. + +#include "libANGLE/Stream.h" + +#include +#include + +#include "common/debug.h" +#include "common/mathutil.h" +#include "common/platform.h" +#include "common/utilities.h" +#include "libANGLE/Context.h" +#include "libANGLE/Display.h" +#include "libANGLE/renderer/DisplayImpl.h" +#include "libANGLE/renderer/StreamProducerImpl.h" + +namespace egl +{ + +Stream::Stream(Display *display, const AttributeMap &attribs) + : mDisplay(display), + mProducerImplementation(nullptr), + mState(EGL_STREAM_STATE_CREATED_KHR), + mProducerFrame(0), + mConsumerFrame(0), + mConsumerLatency(attribs.getAsInt(EGL_CONSUMER_LATENCY_USEC_KHR, 0)), + mConsumerAcquireTimeout(attribs.getAsInt(EGL_CONSUMER_ACQUIRE_TIMEOUT_USEC_KHR, 0)), + mPlaneCount(0), + mConsumerType(ConsumerType::NoConsumer), + mProducerType(ProducerType::NoProducer) +{ + for (auto &plane : mPlanes) + { + plane.textureUnit = -1; + plane.texture = nullptr; + } +} + +Stream::~Stream() +{ + SafeDelete(mProducerImplementation); + for (auto &plane : mPlanes) + { + if (plane.texture != nullptr) + { + plane.texture->releaseStream(); + } + } +} + +void Stream::setConsumerLatency(EGLint latency) +{ + mConsumerLatency = latency; +} + +EGLint Stream::getConsumerLatency() const +{ + return mConsumerLatency; +} + +EGLuint64KHR Stream::getProducerFrame() const +{ + return mProducerFrame; +} + +EGLuint64KHR Stream::getConsumerFrame() const +{ + return mConsumerFrame; +} + +EGLenum Stream::getState() const +{ + return mState; +} + +void Stream::setConsumerAcquireTimeout(EGLint timeout) +{ + mConsumerAcquireTimeout = timeout; +} + +EGLint Stream::getConsumerAcquireTimeout() const +{ + return mConsumerAcquireTimeout; +} + +Stream::ProducerType Stream::getProducerType() const +{ + return mProducerType; +} + +Stream::ConsumerType Stream::getConsumerType() const +{ + return mConsumerType; +} + +EGLint Stream::getPlaneCount() const +{ + return mPlaneCount; +} + +rx::StreamProducerImpl *Stream::getImplementation() +{ + return mProducerImplementation; +} + +Error Stream::createConsumerGLTextureExternal(const AttributeMap &attributes, gl::Context *context) +{ + ASSERT(mState == EGL_STREAM_STATE_CREATED_KHR); + ASSERT(mConsumerType == ConsumerType::NoConsumer); + ASSERT(mProducerType == ProducerType::NoProducer); + ASSERT(context != nullptr); + + const auto &glState = context->getGLState(); + EGLenum bufferType = attributes.getAsInt(EGL_COLOR_BUFFER_TYPE, EGL_RGB_BUFFER); + if (bufferType == EGL_RGB_BUFFER) + { + mPlanes[0].texture = glState.getTargetTexture(GL_TEXTURE_EXTERNAL_OES); + ASSERT(mPlanes[0].texture != nullptr); + mPlanes[0].texture->bindStream(this); + mConsumerType = ConsumerType::GLTextureRGB; + mPlaneCount = 1; + } + else + { + mPlaneCount = attributes.getAsInt(EGL_YUV_NUMBER_OF_PLANES_EXT, 2); + ASSERT(mPlaneCount <= 3); + for (EGLint i = 0; i < mPlaneCount; i++) + { + // Fetch all the textures + mPlanes[i].textureUnit = attributes.getAsInt(EGL_YUV_PLANE0_TEXTURE_UNIT_NV + i, -1); + if (mPlanes[i].textureUnit != EGL_NONE) + { + mPlanes[i].texture = + glState.getSamplerTexture(mPlanes[i].textureUnit, GL_TEXTURE_EXTERNAL_OES); + ASSERT(mPlanes[i].texture != nullptr); + } + } + + // Bind them to the stream + for (EGLint i = 0; i < mPlaneCount; i++) + { + if (mPlanes[i].textureUnit != EGL_NONE) + { + mPlanes[i].texture->bindStream(this); + } + } + mConsumerType = ConsumerType::GLTextureYUV; + } + + mContext = context; + mState = EGL_STREAM_STATE_CONNECTING_KHR; + + return NoError(); +} + +Error Stream::createProducerD3D11TextureNV12(const AttributeMap &attributes) +{ + ASSERT(mState == EGL_STREAM_STATE_CONNECTING_KHR); + ASSERT(mConsumerType == ConsumerType::GLTextureYUV); + ASSERT(mProducerType == ProducerType::NoProducer); + ASSERT(mPlaneCount == 2); + + mProducerImplementation = mDisplay->getImplementation()->createStreamProducerD3DTextureNV12( + mConsumerType, attributes); + mProducerType = ProducerType::D3D11TextureNV12; + mState = EGL_STREAM_STATE_EMPTY_KHR; + + return NoError(); +} + +// Called when the consumer of this stream starts using the stream +Error Stream::consumerAcquire(const gl::Context *context) +{ + ASSERT(mState == EGL_STREAM_STATE_NEW_FRAME_AVAILABLE_KHR || + mState == EGL_STREAM_STATE_OLD_FRAME_AVAILABLE_KHR); + ASSERT(mConsumerType == ConsumerType::GLTextureRGB || + mConsumerType == ConsumerType::GLTextureYUV); + ASSERT(mProducerType == ProducerType::D3D11TextureNV12); + + mState = EGL_STREAM_STATE_OLD_FRAME_AVAILABLE_KHR; + mConsumerFrame++; + + // Bind the planes to the gl textures + for (int i = 0; i < mPlaneCount; i++) + { + if (mPlanes[i].texture != nullptr) + { + ANGLE_TRY(mPlanes[i].texture->acquireImageFromStream( + context, mProducerImplementation->getGLFrameDescription(i))); + } + } + + return NoError(); +} + +Error Stream::consumerRelease(const gl::Context *context) +{ + ASSERT(mState == EGL_STREAM_STATE_NEW_FRAME_AVAILABLE_KHR || + mState == EGL_STREAM_STATE_OLD_FRAME_AVAILABLE_KHR); + ASSERT(mConsumerType == ConsumerType::GLTextureRGB || + mConsumerType == ConsumerType::GLTextureYUV); + ASSERT(mProducerType == ProducerType::D3D11TextureNV12); + + // Release the images + for (int i = 0; i < mPlaneCount; i++) + { + if (mPlanes[i].texture != nullptr) + { + ANGLE_TRY(mPlanes[i].texture->releaseImageFromStream(context)); + } + } + + return NoError(); +} + +bool Stream::isConsumerBoundToContext(const gl::Context *context) const +{ + ASSERT(context != nullptr); + return (context == mContext); +} + +Error Stream::validateD3D11NV12Texture(void *texture) const +{ + ASSERT(mConsumerType == ConsumerType::GLTextureRGB || + mConsumerType == ConsumerType::GLTextureYUV); + ASSERT(mProducerType == ProducerType::D3D11TextureNV12); + ASSERT(mProducerImplementation != nullptr); + + return mProducerImplementation->validateD3DNV12Texture(texture); +} + +Error Stream::postD3D11NV12Texture(void *texture, const AttributeMap &attributes) +{ + ASSERT(mConsumerType == ConsumerType::GLTextureRGB || + mConsumerType == ConsumerType::GLTextureYUV); + ASSERT(mProducerType == ProducerType::D3D11TextureNV12); + + mProducerImplementation->postD3DNV12Texture(texture, attributes); + mProducerFrame++; + + mState = EGL_STREAM_STATE_NEW_FRAME_AVAILABLE_KHR; + + return NoError(); +} + +// This is called when a texture object associated with this stream is destroyed. Even if multiple +// textures are bound, one being destroyed invalidates the stream, so all the remaining textures +// will be released and the stream will be invalidated. +void Stream::releaseTextures() +{ + for (auto &plane : mPlanes) + { + if (plane.texture != nullptr) + { + plane.texture->releaseStream(); + plane.texture = nullptr; + } + } + mConsumerType = ConsumerType::NoConsumer; + mProducerType = ProducerType::NoProducer; + mState = EGL_STREAM_STATE_DISCONNECTED_KHR; +} + +} // namespace egl diff --git a/src/3rdparty/angle/src/libANGLE/Stream.h b/src/3rdparty/angle/src/libANGLE/Stream.h new file mode 100644 index 0000000000..b674c44008 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/Stream.h @@ -0,0 +1,143 @@ +// +// Copyright (c) 2016 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. +// + +// Stream.h: Defines the egl::Stream class, representing the stream +// where frames are streamed in. Implements EGLStreanKHR. + +#ifndef LIBANGLE_STREAM_H_ +#define LIBANGLE_STREAM_H_ + +#include + +#include +#include + +#include "common/angleutils.h" +#include "libANGLE/AttributeMap.h" + +namespace rx +{ +class StreamProducerImpl; +} + +namespace gl +{ +class Context; +class Texture; +} + +namespace egl +{ +class Display; +class Error; +class Thread; + +class Stream final : angle::NonCopyable +{ + public: + Stream(Display *display, const AttributeMap &attribs); + ~Stream(); + + enum class ConsumerType + { + NoConsumer, + GLTextureRGB, + GLTextureYUV, + }; + + enum class ProducerType + { + NoProducer, + D3D11TextureNV12, + }; + + // A GL texture interpretation of a part of a producer frame. For use with GL texture consumers + struct GLTextureDescription + { + unsigned int width; + unsigned int height; + unsigned int internalFormat; + unsigned int mipLevels; + }; + + EGLenum getState() const; + + void setConsumerLatency(EGLint latency); + EGLint getConsumerLatency() const; + + EGLuint64KHR getProducerFrame() const; + EGLuint64KHR getConsumerFrame() const; + + void setConsumerAcquireTimeout(EGLint timeout); + EGLint getConsumerAcquireTimeout() const; + + ConsumerType getConsumerType() const; + ProducerType getProducerType() const; + + EGLint getPlaneCount() const; + + rx::StreamProducerImpl *getImplementation(); + + // Consumer creation methods + Error createConsumerGLTextureExternal(const AttributeMap &attributes, gl::Context *context); + + // Producer creation methods + Error createProducerD3D11TextureNV12(const AttributeMap &attributes); + + // Consumer methods + Error consumerAcquire(const gl::Context *context); + Error consumerRelease(const gl::Context *context); + + // Some consumers are bound to GL contexts. This validates that a given context is bound to the + // stream's consumer + bool isConsumerBoundToContext(const gl::Context *context) const; + + // Producer methods + Error validateD3D11NV12Texture(void *texture) const; + Error postD3D11NV12Texture(void *texture, const AttributeMap &attributes); + + private: + // Associated display + Display *mDisplay; + + // Producer Implementation + rx::StreamProducerImpl *mProducerImplementation; + + // Associated GL context. Note that this is a weak pointer used for validation purposes only, + // and should never be arbitrarily dereferenced without knowing the context still exists as it + // can become dangling at any time. + gl::Context *mContext; + + // EGL defined attributes + EGLint mState; + EGLuint64KHR mProducerFrame; + EGLuint64KHR mConsumerFrame; + EGLint mConsumerLatency; + + // EGL gltexture consumer attributes + EGLint mConsumerAcquireTimeout; + + // EGL gltexture yuv consumer attributes + EGLint mPlaneCount; + struct PlaneTexture + { + EGLint textureUnit; + gl::Texture *texture; + }; + // Texture units and textures for all the planes + std::array mPlanes; + + // Consumer and producer types + ConsumerType mConsumerType; + ProducerType mProducerType; + + // ANGLE-only method, used internally + friend class gl::Texture; + void releaseTextures(); +}; +} // namespace egl + +#endif // LIBANGLE_STREAM_H_ diff --git a/src/3rdparty/angle/src/libANGLE/Surface.cpp b/src/3rdparty/angle/src/libANGLE/Surface.cpp index b5ed0ff5a6..746da03778 100644 --- a/src/3rdparty/angle/src/libANGLE/Surface.cpp +++ b/src/3rdparty/angle/src/libANGLE/Surface.cpp @@ -10,29 +10,44 @@ #include "libANGLE/Surface.h" -#include "libANGLE/Config.h" -#include "libANGLE/Framebuffer.h" -#include "libANGLE/Texture.h" - #include #include +#include "libANGLE/Config.h" +#include "libANGLE/Context.h" +#include "libANGLE/Display.h" +#include "libANGLE/Framebuffer.h" +#include "libANGLE/Texture.h" +#include "libANGLE/Thread.h" +#include "libANGLE/formatutils.h" +#include "libANGLE/renderer/EGLImplFactory.h" + namespace egl { -Surface::Surface(rx::SurfaceImpl *impl, - EGLint surfaceType, - const egl::Config *config, - const AttributeMap &attributes) +SurfaceState::SurfaceState(const egl::Config *configIn, const AttributeMap &attributesIn) + : defaultFramebuffer(nullptr), config(configIn), attributes(attributesIn) +{ +} + +Surface::Surface(EGLint surfaceType, const egl::Config *config, const AttributeMap &attributes) : FramebufferAttachmentObject(), - mImplementation(impl), - mDefaultFramebuffer(nullptr), + mState(config, attributes), + mImplementation(nullptr), mCurrentCount(0), mDestroyed(false), mType(surfaceType), - mConfig(config), mPostSubBufferRequested(false), + mLargestPbuffer(false), + mGLColorspace(EGL_GL_COLORSPACE_LINEAR), + mVGAlphaFormat(EGL_VG_ALPHA_FORMAT_NONPRE), + mVGColorspace(EGL_VG_COLORSPACE_sRGB), + mMipmapTexture(false), + mMipmapLevel(0), + mHorizontalResolution(EGL_UNKNOWN), + mVerticalResolution(EGL_UNKNOWN), + mMultisampleResolve(EGL_MULTISAMPLE_RESOLVE_DEFAULT), mFixedSize(false), mFixedWidth(0), mFixedHeight(0), @@ -41,75 +56,135 @@ Surface::Surface(rx::SurfaceImpl *impl, // FIXME: Determine actual pixel aspect ratio mPixelAspectRatio(static_cast(1.0 * EGL_DISPLAY_SCALING)), mRenderBuffer(EGL_BACK_BUFFER), - mSwapBehavior(impl->getSwapBehavior()), + mSwapBehavior(EGL_NONE), mOrientation(0), - mTexture() + mTexture(), + mBackFormat(config->renderTargetFormat), + mDSFormat(config->depthStencilFormat) { mPostSubBufferRequested = (attributes.get(EGL_POST_SUB_BUFFER_SUPPORTED_NV, EGL_FALSE) == EGL_TRUE); mFlexibleSurfaceCompatibilityRequested = (attributes.get(EGL_FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE, EGL_FALSE) == EGL_TRUE); + if (mType == EGL_PBUFFER_BIT) + { + mLargestPbuffer = (attributes.get(EGL_LARGEST_PBUFFER, EGL_FALSE) == EGL_TRUE); + } + + mGLColorspace = + static_cast(attributes.get(EGL_GL_COLORSPACE, EGL_GL_COLORSPACE_LINEAR)); + mVGAlphaFormat = + static_cast(attributes.get(EGL_VG_ALPHA_FORMAT, EGL_VG_ALPHA_FORMAT_NONPRE)); + mVGColorspace = static_cast(attributes.get(EGL_VG_COLORSPACE, EGL_VG_COLORSPACE_sRGB)); + mMipmapTexture = (attributes.get(EGL_MIPMAP_TEXTURE, EGL_FALSE) == EGL_TRUE); + mDirectComposition = (attributes.get(EGL_DIRECT_COMPOSITION_ANGLE, EGL_FALSE) == EGL_TRUE); + mRobustResourceInitialization = + (attributes.get(EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE, 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); + mFixedWidth = static_cast(attributes.get(EGL_WIDTH, 0)); + mFixedHeight = static_cast(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); + mTextureFormat = static_cast(attributes.get(EGL_TEXTURE_FORMAT, EGL_NO_TEXTURE)); + mTextureTarget = static_cast(attributes.get(EGL_TEXTURE_TARGET, EGL_NO_TEXTURE)); } - mOrientation = attributes.get(EGL_SURFACE_ORIENTATION_ANGLE, 0); - - mDefaultFramebuffer = createDefaultFramebuffer(); - ASSERT(mDefaultFramebuffer != nullptr); + mOrientation = static_cast(attributes.get(EGL_SURFACE_ORIENTATION_ANGLE, 0)); } Surface::~Surface() { +} + +rx::FramebufferAttachmentObjectImpl *Surface::getAttachmentImpl() const +{ + return mImplementation; +} + +Error Surface::destroyImpl(const Display *display) +{ + if (mState.defaultFramebuffer) + { + mState.defaultFramebuffer->destroyDefault(display); + } + if (mImplementation) + { + mImplementation->destroy(display); + } + if (mTexture.get()) { if (mImplementation) { - mImplementation->releaseTexImage(EGL_BACK_BUFFER); + ANGLE_TRY(mImplementation->releaseTexImage(EGL_BACK_BUFFER)); } - mTexture->releaseTexImageFromSurface(); - mTexture.set(nullptr); + auto glErr = mTexture->releaseTexImageFromSurface(display->getProxyContext()); + if (glErr.isError()) + { + return Error(EGL_BAD_SURFACE); + } + mTexture.set(nullptr, nullptr); } - SafeDelete(mDefaultFramebuffer); + if (mState.defaultFramebuffer) + { + mState.defaultFramebuffer->onDestroy(display->getProxyContext()); + } + SafeDelete(mState.defaultFramebuffer); SafeDelete(mImplementation); + + delete this; + return NoError(); +} + +Error Surface::initialize(const Display *display) +{ + ANGLE_TRY(mImplementation->initialize(display)); + + // Initialized here since impl is nullptr in the constructor. + // Must happen after implementation initialize for Android. + mSwapBehavior = mImplementation->getSwapBehavior(); + + // Must happen after implementation initialize for OSX. + mState.defaultFramebuffer = createDefaultFramebuffer(display); + ASSERT(mState.defaultFramebuffer != nullptr); + + return NoError(); } -void Surface::setIsCurrent(bool isCurrent) +Error Surface::setIsCurrent(const gl::Context *context, bool isCurrent) { if (isCurrent) { mCurrentCount++; + return NoError(); } - else + + ASSERT(mCurrentCount > 0); + mCurrentCount--; + if (mCurrentCount == 0 && mDestroyed) { - ASSERT(mCurrentCount > 0); - mCurrentCount--; - if (mCurrentCount == 0 && mDestroyed) - { - delete this; - } + ASSERT(context); + return destroyImpl(context->getCurrentDisplay()); } + return NoError(); } -void Surface::onDestroy() +Error Surface::onDestroy(const Display *display) { mDestroyed = true; if (mCurrentCount == 0) { - delete this; + return destroyImpl(display); } + return NoError(); } EGLint Surface::getType() const @@ -117,14 +192,23 @@ EGLint Surface::getType() const return mType; } -Error Surface::swap() +Error Surface::swap(const gl::Context *context) +{ + return mImplementation->swap(context); +} + +Error Surface::swapWithDamage(const gl::Context *context, EGLint *rects, EGLint n_rects) { - return mImplementation->swap(); + return mImplementation->swapWithDamage(context, rects, n_rects); } -Error Surface::postSubBuffer(EGLint x, EGLint y, EGLint width, EGLint height) +Error Surface::postSubBuffer(const gl::Context *context, + EGLint x, + EGLint y, + EGLint width, + EGLint height) { - return mImplementation->postSubBuffer(x, y, width, height); + return mImplementation->postSubBuffer(context, x, y, width, height); } Error Surface::querySurfacePointerANGLE(EGLint attribute, void **value) @@ -142,9 +226,30 @@ void Surface::setSwapInterval(EGLint interval) mImplementation->setSwapInterval(interval); } +void Surface::setMipmapLevel(EGLint level) +{ + // Level is set but ignored + UNIMPLEMENTED(); + mMipmapLevel = level; +} + +void Surface::setMultisampleResolve(EGLenum resolve) +{ + // Behaviour is set but ignored + UNIMPLEMENTED(); + mMultisampleResolve = resolve; +} + +void Surface::setSwapBehavior(EGLenum behavior) +{ + // Behaviour is set but ignored + UNIMPLEMENTED(); + mSwapBehavior = behavior; +} + const Config *Surface::getConfig() const { - return mConfig; + return mState.config; } EGLint Surface::getPixelAspectRatio() const @@ -172,6 +277,51 @@ EGLenum Surface::getTextureTarget() const return mTextureTarget; } +bool Surface::getLargestPbuffer() const +{ + return mLargestPbuffer; +} + +EGLenum Surface::getGLColorspace() const +{ + return mGLColorspace; +} + +EGLenum Surface::getVGAlphaFormat() const +{ + return mVGAlphaFormat; +} + +EGLenum Surface::getVGColorspace() const +{ + return mVGColorspace; +} + +bool Surface::getMipmapTexture() const +{ + return mMipmapTexture; +} + +EGLint Surface::getMipmapLevel() const +{ + return mMipmapLevel; +} + +EGLint Surface::getHorizontalResolution() const +{ + return mHorizontalResolution; +} + +EGLint Surface::getVerticalResolution() const +{ + return mVerticalResolution; +} + +EGLenum Surface::getMultisampleResolve() const +{ + return mMultisampleResolve; +} + EGLint Surface::isFixedSize() const { return mFixedSize; @@ -187,42 +337,60 @@ EGLint Surface::getHeight() const return mFixedSize ? static_cast(mFixedHeight) : mImplementation->getHeight(); } -Error Surface::bindTexImage(gl::Texture *texture, EGLint buffer) +Error Surface::bindTexImage(const gl::Context *context, gl::Texture *texture, EGLint buffer) { ASSERT(!mTexture.get()); + ANGLE_TRY(mImplementation->bindTexImage(texture, buffer)); + + auto glErr = texture->bindTexImageFromSurface(context, this); + if (glErr.isError()) + { + return Error(EGL_BAD_SURFACE); + } + mTexture.set(context, texture); - texture->bindTexImageFromSurface(this); - mTexture.set(texture); - return mImplementation->bindTexImage(texture, buffer); + return NoError(); } -Error Surface::releaseTexImage(EGLint buffer) +Error Surface::releaseTexImage(const gl::Context *context, EGLint buffer) { + ASSERT(context); + + ANGLE_TRY(mImplementation->releaseTexImage(buffer)); + ASSERT(mTexture.get()); - mTexture->releaseTexImageFromSurface(); - mTexture.set(nullptr); + auto glErr = mTexture->releaseTexImageFromSurface(context); + if (glErr.isError()) + { + return Error(EGL_BAD_SURFACE); + } + mTexture.set(context, nullptr); - return mImplementation->releaseTexImage(buffer); + return NoError(); } -void Surface::releaseTexImageFromTexture() +Error Surface::getSyncValues(EGLuint64KHR *ust, EGLuint64KHR *msc, EGLuint64KHR *sbc) +{ + return mImplementation->getSyncValues(ust, msc, sbc); +} + +void Surface::releaseTexImageFromTexture(const gl::Context *context) { ASSERT(mTexture.get()); - mTexture.set(nullptr); + mTexture.set(context, nullptr); } -gl::Extents Surface::getAttachmentSize(const gl::FramebufferAttachment::Target & /*target*/) const +gl::Extents Surface::getAttachmentSize(const gl::ImageIndex & /*target*/) const { return gl::Extents(getWidth(), getHeight(), 1); } -GLenum Surface::getAttachmentInternalFormat(const gl::FramebufferAttachment::Target &target) const +const gl::Format &Surface::getAttachmentFormat(GLenum binding, const gl::ImageIndex &target) const { - const egl::Config *config = getConfig(); - return (target.binding() == GL_BACK ? config->renderTargetFormat : config->depthStencilFormat); + return (binding == GL_BACK ? mBackFormat : mDSFormat); } -GLsizei Surface::getAttachmentSamples(const gl::FramebufferAttachment::Target &target) const +GLsizei Surface::getAttachmentSamples(const gl::ImageIndex &target) const { return getConfig()->samples; } @@ -233,29 +401,84 @@ GLuint Surface::getId() const return 0; } -gl::Framebuffer *Surface::createDefaultFramebuffer() +gl::Framebuffer *Surface::createDefaultFramebuffer(const Display *display) { - gl::Framebuffer *framebuffer = new gl::Framebuffer(mImplementation); + return new gl::Framebuffer(display, this); +} - GLenum drawBufferState = GL_BACK; - framebuffer->setDrawBuffers(1, &drawBufferState); - framebuffer->setReadBuffer(GL_BACK); +gl::InitState Surface::initState(const gl::ImageIndex & /*imageIndex*/) const +{ + // TODO(jmadill): Lazy surface init. + return gl::InitState::Initialized; +} - framebuffer->setAttachment(GL_FRAMEBUFFER_DEFAULT, GL_BACK, gl::ImageIndex::MakeInvalid(), - this); +void Surface::setInitState(const gl::ImageIndex & /*imageIndex*/, gl::InitState /*initState*/) +{ + // No-op. +} - if (mConfig->depthSize > 0) - { - framebuffer->setAttachment(GL_FRAMEBUFFER_DEFAULT, GL_DEPTH, gl::ImageIndex::MakeInvalid(), - this); - } +WindowSurface::WindowSurface(rx::EGLImplFactory *implFactory, + const egl::Config *config, + EGLNativeWindowType window, + const AttributeMap &attribs) + : Surface(EGL_WINDOW_BIT, config, attribs) +{ + mImplementation = implFactory->createWindowSurface(mState, window, attribs); +} - if (mConfig->stencilSize > 0) - { - framebuffer->setAttachment(GL_FRAMEBUFFER_DEFAULT, GL_STENCIL, - gl::ImageIndex::MakeInvalid(), this); - } +WindowSurface::~WindowSurface() +{ +} - return framebuffer; +PbufferSurface::PbufferSurface(rx::EGLImplFactory *implFactory, + const Config *config, + const AttributeMap &attribs) + : Surface(EGL_PBUFFER_BIT, config, attribs) +{ + mImplementation = implFactory->createPbufferSurface(mState, attribs); +} + +PbufferSurface::PbufferSurface(rx::EGLImplFactory *implFactory, + const Config *config, + EGLenum buftype, + EGLClientBuffer clientBuffer, + const AttributeMap &attribs) + : Surface(EGL_PBUFFER_BIT, config, attribs) +{ + mImplementation = + implFactory->createPbufferFromClientBuffer(mState, buftype, clientBuffer, attribs); } + +PbufferSurface::~PbufferSurface() +{ } + +PixmapSurface::PixmapSurface(rx::EGLImplFactory *implFactory, + const Config *config, + NativePixmapType nativePixmap, + const AttributeMap &attribs) + : Surface(EGL_PIXMAP_BIT, config, attribs) +{ + mImplementation = implFactory->createPixmapSurface(mState, nativePixmap, attribs); +} + +PixmapSurface::~PixmapSurface() +{ +} + +// SurfaceDeleter implementation. + +SurfaceDeleter::SurfaceDeleter(const Display *display) : mDisplay(display) +{ +} + +SurfaceDeleter::~SurfaceDeleter() +{ +} + +void SurfaceDeleter::operator()(Surface *surface) +{ + ANGLE_SWALLOW_ERR(surface->onDestroy(mDisplay)); +} + +} // namespace egl diff --git a/src/3rdparty/angle/src/libANGLE/Surface.h b/src/3rdparty/angle/src/libANGLE/Surface.h index e110f5da7b..b3188ff909 100644 --- a/src/3rdparty/angle/src/libANGLE/Surface.h +++ b/src/3rdparty/angle/src/libANGLE/Surface.h @@ -14,9 +14,11 @@ #include #include "common/angleutils.h" +#include "libANGLE/AttributeMap.h" #include "libANGLE/Error.h" #include "libANGLE/FramebufferAttachment.h" #include "libANGLE/RefCountObject.h" +#include "libANGLE/formatutils.h" #include "libANGLE/renderer/SurfaceImpl.h" namespace gl @@ -25,33 +27,55 @@ class Framebuffer; class Texture; } +namespace rx +{ +class EGLImplFactory; +} + namespace egl { -class AttributeMap; class Display; struct Config; -class Surface final : public gl::FramebufferAttachmentObject +struct SurfaceState final : private angle::NonCopyable { - public: - Surface(rx::SurfaceImpl *impl, EGLint surfaceType, const egl::Config *config, const AttributeMap &attributes); + SurfaceState(const egl::Config *configIn, const AttributeMap &attributesIn); + + gl::Framebuffer *defaultFramebuffer; + const egl::Config *config; + AttributeMap attributes; +}; - rx::SurfaceImpl *getImplementation() { return mImplementation; } - const rx::SurfaceImpl *getImplementation() const { return mImplementation; } +class Surface : public gl::FramebufferAttachmentObject +{ + public: + rx::SurfaceImpl *getImplementation() const { return mImplementation; } EGLint getType() const; - Error swap(); - Error postSubBuffer(EGLint x, EGLint y, EGLint width, EGLint height); + Error initialize(const Display *display); + Error swap(const gl::Context *context); + Error swapWithDamage(const gl::Context *context, EGLint *rects, EGLint n_rects); + Error postSubBuffer(const gl::Context *context, + 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); + Error bindTexImage(const gl::Context *context, gl::Texture *texture, EGLint buffer); + Error releaseTexImage(const gl::Context *context, EGLint buffer); + + Error getSyncValues(EGLuint64KHR *ust, EGLuint64KHR *msc, EGLuint64KHR *sbc); EGLint isPostSubBufferSupported() const; void setSwapInterval(EGLint interval); - void setIsCurrent(bool isCurrent); - void onDestroy(); + Error setIsCurrent(const gl::Context *context, bool isCurrent); + Error onDestroy(const Display *display); + + void setMipmapLevel(EGLint level); + void setMultisampleResolve(EGLenum resolve); + void setSwapBehavior(EGLenum behavior); const Config *getConfig() const; @@ -63,19 +87,29 @@ class Surface final : public gl::FramebufferAttachmentObject EGLenum getSwapBehavior() const; EGLenum getTextureFormat() const; EGLenum getTextureTarget() const; + bool getLargestPbuffer() const; + EGLenum getGLColorspace() const; + EGLenum getVGAlphaFormat() const; + EGLenum getVGColorspace() const; + bool getMipmapTexture() const; + EGLint getMipmapLevel() const; + EGLint getHorizontalResolution() const; + EGLint getVerticalResolution() const; + EGLenum getMultisampleResolve() const; gl::Texture *getBoundTexture() const { return mTexture.get(); } - gl::Framebuffer *getDefaultFramebuffer() { return mDefaultFramebuffer; } + gl::Framebuffer *getDefaultFramebuffer() { return mState.defaultFramebuffer; } EGLint isFixedSize() const; // FramebufferAttachmentObject implementation - gl::Extents getAttachmentSize(const gl::FramebufferAttachment::Target &target) const override; - GLenum getAttachmentInternalFormat(const gl::FramebufferAttachment::Target &target) const override; - GLsizei getAttachmentSamples(const gl::FramebufferAttachment::Target &target) const override; + gl::Extents getAttachmentSize(const gl::ImageIndex &imageIndex) const override; + const gl::Format &getAttachmentFormat(GLenum binding, + const gl::ImageIndex &imageIndex) const override; + GLsizei getAttachmentSamples(const gl::ImageIndex &imageIndex) const override; - void onAttach() override {} - void onDetach() override {} + void onAttach(const gl::Context *context) override {} + void onDetach(const gl::Context *context) override {} GLuint getId() const override; bool flexibleSurfaceCompatibilityRequested() const @@ -86,34 +120,50 @@ class Surface final : public gl::FramebufferAttachmentObject bool directComposition() const { return mDirectComposition; } - private: - virtual ~Surface(); - rx::FramebufferAttachmentObjectImpl *getAttachmentImpl() const override { return mImplementation; } + gl::InitState initState(const gl::ImageIndex &imageIndex) const override; + void setInitState(const gl::ImageIndex &imageIndex, gl::InitState initState) override; + + bool isRobustResourceInitEnabled() const { return mRobustResourceInitialization; } + + protected: + Surface(EGLint surfaceType, const egl::Config *config, const AttributeMap &attributes); + ~Surface() override; + rx::FramebufferAttachmentObjectImpl *getAttachmentImpl() const override; - gl::Framebuffer *createDefaultFramebuffer(); + gl::Framebuffer *createDefaultFramebuffer(const Display *display); // ANGLE-only method, used internally friend class gl::Texture; - void releaseTexImageFromTexture(); + void releaseTexImageFromTexture(const gl::Context *context); + SurfaceState mState; rx::SurfaceImpl *mImplementation; - gl::Framebuffer *mDefaultFramebuffer; int mCurrentCount; bool mDestroyed; EGLint mType; - const egl::Config *mConfig; - bool mPostSubBufferRequested; bool mFlexibleSurfaceCompatibilityRequested; + bool mLargestPbuffer; + EGLenum mGLColorspace; + EGLenum mVGAlphaFormat; + EGLenum mVGColorspace; + bool mMipmapTexture; + EGLint mMipmapLevel; + EGLint mHorizontalResolution; + EGLint mVerticalResolution; + EGLenum mMultisampleResolve; + bool mFixedSize; size_t mFixedWidth; size_t mFixedHeight; bool mDirectComposition; + bool mRobustResourceInitialization; + EGLenum mTextureFormat; EGLenum mTextureTarget; @@ -123,9 +173,66 @@ class Surface final : public gl::FramebufferAttachmentObject EGLint mOrientation; - BindingPointer mTexture; + gl::BindingPointer mTexture; + + gl::Format mBackFormat; + gl::Format mDSFormat; + + private: + Error destroyImpl(const Display *display); }; -} +class WindowSurface final : public Surface +{ + public: + WindowSurface(rx::EGLImplFactory *implFactory, + const Config *config, + EGLNativeWindowType window, + const AttributeMap &attribs); + ~WindowSurface() override; +}; + +class PbufferSurface final : public Surface +{ + public: + PbufferSurface(rx::EGLImplFactory *implFactory, + const Config *config, + const AttributeMap &attribs); + PbufferSurface(rx::EGLImplFactory *implFactory, + const Config *config, + EGLenum buftype, + EGLClientBuffer clientBuffer, + const AttributeMap &attribs); + + protected: + ~PbufferSurface() override; +}; + +class PixmapSurface final : public Surface +{ + public: + PixmapSurface(rx::EGLImplFactory *implFactory, + const Config *config, + NativePixmapType nativePixmap, + const AttributeMap &attribs); + + protected: + ~PixmapSurface() override; +}; + +class SurfaceDeleter final +{ + public: + SurfaceDeleter(const Display *display); + ~SurfaceDeleter(); + void operator()(Surface *surface); + + private: + const Display *mDisplay; +}; + +using SurfacePointer = angle::UniqueObjectPointerBase; + +} // namespace egl #endif // LIBANGLE_SURFACE_H_ diff --git a/src/3rdparty/angle/src/libANGLE/Texture.cpp b/src/3rdparty/angle/src/libANGLE/Texture.cpp index 5ef6762d3d..da92e65916 100644 --- a/src/3rdparty/angle/src/libANGLE/Texture.cpp +++ b/src/3rdparty/angle/src/libANGLE/Texture.cpp @@ -12,66 +12,571 @@ #include "common/utilities.h" #include "libANGLE/Config.h" #include "libANGLE/Context.h" -#include "libANGLE/Data.h" +#include "libANGLE/ContextState.h" #include "libANGLE/Image.h" #include "libANGLE/Surface.h" #include "libANGLE/formatutils.h" +#include "libANGLE/renderer/GLImplFactory.h" +#include "libANGLE/renderer/TextureImpl.h" namespace gl { -bool IsMipmapFiltered(const gl::SamplerState &samplerState) +namespace +{ +bool IsPointSampled(const SamplerState &samplerState) +{ + return (samplerState.magFilter == GL_NEAREST && + (samplerState.minFilter == GL_NEAREST || + samplerState.minFilter == GL_NEAREST_MIPMAP_NEAREST)); +} + +size_t GetImageDescIndex(GLenum target, size_t level) +{ + return IsCubeMapTextureTarget(target) ? ((level * 6) + CubeMapTextureTargetToLayerIndex(target)) + : level; +} + +ImageIndex GetImageIndexFromDescIndex(GLenum target, size_t descIndex) +{ + if (target == GL_TEXTURE_CUBE_MAP) + { + size_t faceIndex = descIndex % 6; + size_t mipIndex = descIndex / 6; + return ImageIndex::MakeCube(LayerIndexToCubeMapTextureTarget(faceIndex), + static_cast(mipIndex)); + } + + return ImageIndex::MakeGeneric(target, static_cast(descIndex)); +} + +InitState DetermineInitState(const Context *context, const uint8_t *pixels) +{ + // Can happen in tests. + if (!context || !context->isRobustResourceInitEnabled()) + return InitState::Initialized; + + const auto &glState = context->getGLState(); + return (pixels == nullptr && glState.getTargetBuffer(gl::BufferBinding::PixelUnpack) == nullptr) + ? InitState::MayNeedInit + : InitState::Initialized; +} + +} // namespace + +bool IsMipmapFiltered(const SamplerState &samplerState) { switch (samplerState.minFilter) { - case GL_NEAREST: - case GL_LINEAR: + 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; + } +} + +SwizzleState::SwizzleState() + : swizzleRed(GL_INVALID_INDEX), + swizzleGreen(GL_INVALID_INDEX), + swizzleBlue(GL_INVALID_INDEX), + swizzleAlpha(GL_INVALID_INDEX) +{ +} + +SwizzleState::SwizzleState(GLenum red, GLenum green, GLenum blue, GLenum alpha) + : swizzleRed(red), swizzleGreen(green), swizzleBlue(blue), swizzleAlpha(alpha) +{ +} + +bool SwizzleState::swizzleRequired() const +{ + return swizzleRed != GL_RED || swizzleGreen != GL_GREEN || swizzleBlue != GL_BLUE || + swizzleAlpha != GL_ALPHA; +} + +bool SwizzleState::operator==(const SwizzleState &other) const +{ + return swizzleRed == other.swizzleRed && swizzleGreen == other.swizzleGreen && + swizzleBlue == other.swizzleBlue && swizzleAlpha == other.swizzleAlpha; +} + +bool SwizzleState::operator!=(const SwizzleState &other) const +{ + return !(*this == other); +} + +TextureState::TextureState(GLenum target) + : mTarget(target), + mSwizzleState(GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA), + mSamplerState(SamplerState::CreateDefaultForTarget(target)), + mBaseLevel(0), + mMaxLevel(1000), + mDepthStencilTextureMode(GL_DEPTH_COMPONENT), + mImmutableFormat(false), + mImmutableLevels(0), + mUsage(GL_NONE), + mImageDescs((IMPLEMENTATION_MAX_TEXTURE_LEVELS + 1) * + (target == GL_TEXTURE_CUBE_MAP ? 6 : 1)), + mInitState(InitState::MayNeedInit) +{ +} + +TextureState::~TextureState() +{ +} + +bool TextureState::swizzleRequired() const +{ + return mSwizzleState.swizzleRequired(); +} + +GLuint TextureState::getEffectiveBaseLevel() const +{ + if (mImmutableFormat) + { + // GLES 3.0.4 section 3.8.10 + return std::min(mBaseLevel, mImmutableLevels - 1); + } + // Some classes use the effective base level to index arrays with level data. By clamping the + // effective base level to max levels these arrays need just one extra item to store properties + // that should be returned for all out-of-range base level values, instead of needing special + // handling for out-of-range base levels. + return std::min(mBaseLevel, static_cast(IMPLEMENTATION_MAX_TEXTURE_LEVELS)); +} + +GLuint TextureState::getEffectiveMaxLevel() const +{ + if (mImmutableFormat) + { + // GLES 3.0.4 section 3.8.10 + GLuint clampedMaxLevel = std::max(mMaxLevel, getEffectiveBaseLevel()); + clampedMaxLevel = std::min(clampedMaxLevel, mImmutableLevels - 1); + return clampedMaxLevel; + } + return mMaxLevel; +} + +GLuint TextureState::getMipmapMaxLevel() const +{ + const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), getEffectiveBaseLevel()); + GLuint expectedMipLevels = 0; + if (mTarget == GL_TEXTURE_3D) + { + const int maxDim = std::max(std::max(baseImageDesc.size.width, baseImageDesc.size.height), + baseImageDesc.size.depth); + expectedMipLevels = static_cast(log2(maxDim)); + } + else + { + expectedMipLevels = static_cast( + log2(std::max(baseImageDesc.size.width, baseImageDesc.size.height))); + } + + return std::min(getEffectiveBaseLevel() + expectedMipLevels, getEffectiveMaxLevel()); +} + +bool TextureState::setBaseLevel(GLuint baseLevel) +{ + if (mBaseLevel != baseLevel) + { + mBaseLevel = baseLevel; + return true; + } + return false; +} + +bool TextureState::setMaxLevel(GLuint maxLevel) +{ + if (mMaxLevel != maxLevel) + { + mMaxLevel = maxLevel; + return true; + } + + return false; +} + +// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81. +// According to [OpenGL ES 3.0.5] section 3.8.13 Texture Completeness page 160 any +// per-level checks begin at the base-level. +// For OpenGL ES2 the base level is always zero. +bool TextureState::isCubeComplete() const +{ + ASSERT(mTarget == GL_TEXTURE_CUBE_MAP); + + const ImageDesc &baseImageDesc = + getImageDesc(FirstCubeMapTextureTarget, getEffectiveBaseLevel()); + if (baseImageDesc.size.width == 0 || baseImageDesc.size.width != baseImageDesc.size.height) + { return false; - case GL_NEAREST_MIPMAP_NEAREST: - case GL_LINEAR_MIPMAP_NEAREST: - case GL_NEAREST_MIPMAP_LINEAR: - case GL_LINEAR_MIPMAP_LINEAR: + } + + for (GLenum face = FirstCubeMapTextureTarget + 1; face <= LastCubeMapTextureTarget; face++) + { + const ImageDesc &faceImageDesc = getImageDesc(face, getEffectiveBaseLevel()); + if (faceImageDesc.size.width != baseImageDesc.size.width || + faceImageDesc.size.height != baseImageDesc.size.height || + !Format::SameSized(faceImageDesc.format, baseImageDesc.format)) + { + return false; + } + } + + return true; +} + +bool TextureState::computeSamplerCompleteness(const SamplerState &samplerState, + const ContextState &data) const +{ + if (mBaseLevel > mMaxLevel) + { + return false; + } + const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), getEffectiveBaseLevel()); + if (baseImageDesc.size.width == 0 || baseImageDesc.size.height == 0 || + baseImageDesc.size.depth == 0) + { + return false; + } + // The cases where the texture is incomplete because base level is out of range should be + // handled by the above condition. + ASSERT(mBaseLevel < IMPLEMENTATION_MAX_TEXTURE_LEVELS || mImmutableFormat); + + if (mTarget == GL_TEXTURE_CUBE_MAP && baseImageDesc.size.width != baseImageDesc.size.height) + { + return false; + } + + // According to es 3.1 spec, texture is justified as incomplete if sized internalformat is + // unfilterable(table 20.11) and filter is not GL_NEAREST(8.16). The default value of minFilter + // is NEAREST_MIPMAP_LINEAR and magFilter is LINEAR(table 20.11,). For multismaple texture, + // filter state of multisample texture is ignored(11.1.3.3). So it shouldn't be judged as + // incomplete texture. So, we ignore filtering for multisample texture completeness here. + if (mTarget != GL_TEXTURE_2D_MULTISAMPLE && + !baseImageDesc.format.info->filterSupport(data.getClientVersion(), data.getExtensions()) && + !IsPointSampled(samplerState)) + { + return false; + } + bool npotSupport = data.getExtensions().textureNPOT || data.getClientMajorVersion() >= 3; + if (!npotSupport) + { + if ((samplerState.wrapS != GL_CLAMP_TO_EDGE && !isPow2(baseImageDesc.size.width)) || + (samplerState.wrapT != GL_CLAMP_TO_EDGE && !isPow2(baseImageDesc.size.height))) + { + return false; + } + } + + if (mTarget != GL_TEXTURE_2D_MULTISAMPLE && IsMipmapFiltered(samplerState)) + { + if (!npotSupport) + { + if (!isPow2(baseImageDesc.size.width) || !isPow2(baseImageDesc.size.height)) + { + return false; + } + } + + if (!computeMipmapCompleteness()) + { + return false; + } + } + else + { + if (mTarget == GL_TEXTURE_CUBE_MAP && !isCubeComplete()) + { + return false; + } + } + + // From GL_OES_EGL_image_external_essl3: If state is present in a sampler object bound to a + // texture unit that would have been rejected by a call to TexParameter* for the texture bound + // to that unit, the behavior of the implementation is as if the texture were incomplete. For + // example, if TEXTURE_WRAP_S or TEXTURE_WRAP_T is set to anything but CLAMP_TO_EDGE on the + // sampler object bound to a texture unit and the texture bound to that unit is an external + // texture, the texture will be considered incomplete. + // Sampler object state which does not affect sampling for the type of texture bound to a + // texture unit, such as TEXTURE_WRAP_R for an external texture, does not affect completeness. + if (mTarget == GL_TEXTURE_EXTERNAL_OES) + { + if (samplerState.wrapS != GL_CLAMP_TO_EDGE || samplerState.wrapT != GL_CLAMP_TO_EDGE) + { + return false; + } + + if (samplerState.minFilter != GL_LINEAR && samplerState.minFilter != GL_NEAREST) + { + 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. + if (mTarget != GL_TEXTURE_2D_MULTISAMPLE && baseImageDesc.format.info->depthBits > 0 && + data.getClientMajorVersion() >= 3) + { + // Note: we restrict this validation to sized types. For the OES_depth_textures + // extension, due to some underspecification problems, we must allow linear filtering + // for legacy compatibility with WebGL 1. + // See http://crbug.com/649200 + if (samplerState.compareMode == GL_NONE && baseImageDesc.format.info->sized) + { + if ((samplerState.minFilter != GL_NEAREST && + samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST) || + samplerState.magFilter != GL_NEAREST) + { + return false; + } + } + } + + return true; +} + +bool TextureState::computeMipmapCompleteness() const +{ + const GLuint maxLevel = getMipmapMaxLevel(); + + for (GLuint level = getEffectiveBaseLevel(); level <= maxLevel; level++) + { + if (mTarget == GL_TEXTURE_CUBE_MAP) + { + for (GLenum face = FirstCubeMapTextureTarget; face <= LastCubeMapTextureTarget; face++) + { + if (!computeLevelCompleteness(face, level)) + { + return false; + } + } + } + else + { + if (!computeLevelCompleteness(mTarget, level)) + { + return false; + } + } + } + + return true; +} + +bool TextureState::computeLevelCompleteness(GLenum target, size_t level) const +{ + ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS); + + if (mImmutableFormat) + { return true; - default: UNREACHABLE(); + } + + const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), getEffectiveBaseLevel()); + if (baseImageDesc.size.width == 0 || baseImageDesc.size.height == 0 || + baseImageDesc.size.depth == 0) + { + return false; + } + + const ImageDesc &levelImageDesc = getImageDesc(target, level); + if (levelImageDesc.size.width == 0 || levelImageDesc.size.height == 0 || + levelImageDesc.size.depth == 0) + { return false; } + + if (!Format::SameSized(levelImageDesc.format, baseImageDesc.format)) + { + return false; + } + + ASSERT(level >= getEffectiveBaseLevel()); + const size_t relativeLevel = level - getEffectiveBaseLevel(); + if (levelImageDesc.size.width != std::max(1, baseImageDesc.size.width >> relativeLevel)) + { + return false; + } + + if (levelImageDesc.size.height != std::max(1, baseImageDesc.size.height >> relativeLevel)) + { + return false; + } + + if (mTarget == GL_TEXTURE_3D) + { + if (levelImageDesc.size.depth != std::max(1, baseImageDesc.size.depth >> relativeLevel)) + { + return false; + } + } + else if (mTarget == GL_TEXTURE_2D_ARRAY) + { + if (levelImageDesc.size.depth != baseImageDesc.size.depth) + { + return false; + } + } + + return true; +} + +GLenum TextureState::getBaseImageTarget() const +{ + return mTarget == GL_TEXTURE_CUBE_MAP ? FirstCubeMapTextureTarget : mTarget; +} + +ImageDesc::ImageDesc() + : ImageDesc(Extents(0, 0, 0), Format::Invalid(), 0, GL_TRUE, InitState::Initialized) +{ +} + +ImageDesc::ImageDesc(const Extents &size, const Format &format, const InitState initState) + : size(size), format(format), samples(0), fixedSampleLocations(GL_TRUE), initState(initState) +{ } -bool IsPointSampled(const gl::SamplerState &samplerState) +ImageDesc::ImageDesc(const Extents &size, + const Format &format, + const GLsizei samples, + const bool fixedSampleLocations, + const InitState initState) + : size(size), + format(format), + samples(samples), + fixedSampleLocations(fixedSampleLocations), + initState(initState) { - return (samplerState.magFilter == GL_NEAREST && (samplerState.minFilter == GL_NEAREST || samplerState.minFilter == GL_NEAREST_MIPMAP_NEAREST)); } -static size_t GetImageDescIndex(GLenum target, size_t level) +const ImageDesc &TextureState::getImageDesc(GLenum target, size_t level) const { - return IsCubeMapTextureTarget(target) ? ((level * 6) + CubeMapTextureTargetToLayerIndex(target)) : level; + size_t descIndex = GetImageDescIndex(target, level); + ASSERT(descIndex < mImageDescs.size()); + return mImageDescs[descIndex]; } -Texture::Texture(rx::TextureImpl *impl, GLuint id, GLenum target) +void TextureState::setImageDesc(GLenum target, size_t level, const ImageDesc &desc) +{ + size_t descIndex = GetImageDescIndex(target, level); + ASSERT(descIndex < mImageDescs.size()); + mImageDescs[descIndex] = desc; + if (desc.initState == InitState::MayNeedInit) + { + mInitState = InitState::MayNeedInit; + } +} + +const ImageDesc &TextureState::getImageDesc(const ImageIndex &imageIndex) const +{ + return getImageDesc(imageIndex.type, imageIndex.mipIndex); +} + +void TextureState::setImageDescChain(GLuint baseLevel, + GLuint maxLevel, + Extents baseSize, + const Format &format, + InitState initState) +{ + for (GLuint level = baseLevel; level <= maxLevel; level++) + { + int relativeLevel = (level - baseLevel); + Extents levelSize(std::max(baseSize.width >> relativeLevel, 1), + std::max(baseSize.height >> relativeLevel, 1), + (mTarget == GL_TEXTURE_2D_ARRAY) + ? baseSize.depth + : std::max(baseSize.depth >> relativeLevel, 1)); + ImageDesc levelInfo(levelSize, format, initState); + + if (mTarget == GL_TEXTURE_CUBE_MAP) + { + for (GLenum face = FirstCubeMapTextureTarget; face <= LastCubeMapTextureTarget; face++) + { + setImageDesc(face, level, levelInfo); + } + } + else + { + setImageDesc(mTarget, level, levelInfo); + } + } +} + +void TextureState::setImageDescChainMultisample(Extents baseSize, + const Format &format, + GLsizei samples, + bool fixedSampleLocations, + InitState initState) +{ + ASSERT(mTarget == GL_TEXTURE_2D_MULTISAMPLE); + ImageDesc levelInfo(baseSize, format, samples, fixedSampleLocations, initState); + setImageDesc(mTarget, 0, levelInfo); +} + +void TextureState::clearImageDesc(GLenum target, size_t level) +{ + setImageDesc(target, level, ImageDesc()); +} + +void TextureState::clearImageDescs() +{ + for (size_t descIndex = 0; descIndex < mImageDescs.size(); descIndex++) + { + mImageDescs[descIndex] = ImageDesc(); + } +} + +Texture::Texture(rx::GLImplFactory *factory, GLuint id, GLenum target) : egl::ImageSibling(id), - mTexture(impl), + mState(target), + mTexture(factory->createTexture(mState)), mLabel(), - mTextureState(), - mTarget(target), - mImageDescs(IMPLEMENTATION_MAX_TEXTURE_LEVELS * (target == GL_TEXTURE_CUBE_MAP ? 6 : 1)), - mCompletenessCache(), - mBoundSurface(NULL) + mBoundSurface(nullptr), + mBoundStream(nullptr) { } -Texture::~Texture() +Error Texture::onDestroy(const Context *context) { if (mBoundSurface) { - mBoundSurface->releaseTexImage(EGL_BACK_BUFFER); - mBoundSurface = NULL; + ANGLE_TRY(mBoundSurface->releaseTexImage(context, EGL_BACK_BUFFER)); + mBoundSurface = nullptr; + } + if (mBoundStream) + { + mBoundStream->releaseTextures(); + mBoundStream = nullptr; + } + + ANGLE_TRY(orphanImages(context)); + + if (mTexture) + { + ANGLE_TRY(mTexture->onDestroy(context)); } + return NoError(); +} + +Texture::~Texture() +{ SafeDelete(mTexture); } void Texture::setLabel(const std::string &label) { mLabel = label; + mDirtyBits.set(DIRTY_BIT_LABEL); } const std::string &Texture::getLabel() const @@ -81,295 +586,323 @@ const std::string &Texture::getLabel() const GLenum Texture::getTarget() const { - return mTarget; + return mState.mTarget; } void Texture::setSwizzleRed(GLenum swizzleRed) { - mTextureState.swizzleRed = swizzleRed; + mState.mSwizzleState.swizzleRed = swizzleRed; + mDirtyBits.set(DIRTY_BIT_SWIZZLE_RED); } GLenum Texture::getSwizzleRed() const { - return mTextureState.swizzleRed; + return mState.mSwizzleState.swizzleRed; } void Texture::setSwizzleGreen(GLenum swizzleGreen) { - mTextureState.swizzleGreen = swizzleGreen; + mState.mSwizzleState.swizzleGreen = swizzleGreen; + mDirtyBits.set(DIRTY_BIT_SWIZZLE_GREEN); } GLenum Texture::getSwizzleGreen() const { - return mTextureState.swizzleGreen; + return mState.mSwizzleState.swizzleGreen; } void Texture::setSwizzleBlue(GLenum swizzleBlue) { - mTextureState.swizzleBlue = swizzleBlue; + mState.mSwizzleState.swizzleBlue = swizzleBlue; + mDirtyBits.set(DIRTY_BIT_SWIZZLE_BLUE); } GLenum Texture::getSwizzleBlue() const { - return mTextureState.swizzleBlue; + return mState.mSwizzleState.swizzleBlue; } void Texture::setSwizzleAlpha(GLenum swizzleAlpha) { - mTextureState.swizzleAlpha = swizzleAlpha; + mState.mSwizzleState.swizzleAlpha = swizzleAlpha; + mDirtyBits.set(DIRTY_BIT_SWIZZLE_ALPHA); } GLenum Texture::getSwizzleAlpha() const { - return mTextureState.swizzleAlpha; + return mState.mSwizzleState.swizzleAlpha; } void Texture::setMinFilter(GLenum minFilter) { - mTextureState.samplerState.minFilter = minFilter; + mState.mSamplerState.minFilter = minFilter; + mDirtyBits.set(DIRTY_BIT_MIN_FILTER); } GLenum Texture::getMinFilter() const { - return mTextureState.samplerState.minFilter; + return mState.mSamplerState.minFilter; } void Texture::setMagFilter(GLenum magFilter) { - mTextureState.samplerState.magFilter = magFilter; + mState.mSamplerState.magFilter = magFilter; + mDirtyBits.set(DIRTY_BIT_MAG_FILTER); } GLenum Texture::getMagFilter() const { - return mTextureState.samplerState.magFilter; + return mState.mSamplerState.magFilter; } void Texture::setWrapS(GLenum wrapS) { - mTextureState.samplerState.wrapS = wrapS; + mState.mSamplerState.wrapS = wrapS; + mDirtyBits.set(DIRTY_BIT_WRAP_S); } GLenum Texture::getWrapS() const { - return mTextureState.samplerState.wrapS; + return mState.mSamplerState.wrapS; } void Texture::setWrapT(GLenum wrapT) { - mTextureState.samplerState.wrapT = wrapT; + mState.mSamplerState.wrapT = wrapT; + mDirtyBits.set(DIRTY_BIT_WRAP_T); } GLenum Texture::getWrapT() const { - return mTextureState.samplerState.wrapT; + return mState.mSamplerState.wrapT; } void Texture::setWrapR(GLenum wrapR) { - mTextureState.samplerState.wrapR = wrapR; + mState.mSamplerState.wrapR = wrapR; + mDirtyBits.set(DIRTY_BIT_WRAP_R); } GLenum Texture::getWrapR() const { - return mTextureState.samplerState.wrapR; + return mState.mSamplerState.wrapR; } void Texture::setMaxAnisotropy(float maxAnisotropy) { - mTextureState.samplerState.maxAnisotropy = maxAnisotropy; + mState.mSamplerState.maxAnisotropy = maxAnisotropy; + mDirtyBits.set(DIRTY_BIT_MAX_ANISOTROPY); } float Texture::getMaxAnisotropy() const { - return mTextureState.samplerState.maxAnisotropy; + return mState.mSamplerState.maxAnisotropy; } void Texture::setMinLod(GLfloat minLod) { - mTextureState.samplerState.minLod = minLod; + mState.mSamplerState.minLod = minLod; + mDirtyBits.set(DIRTY_BIT_MIN_LOD); } GLfloat Texture::getMinLod() const { - return mTextureState.samplerState.minLod; + return mState.mSamplerState.minLod; } void Texture::setMaxLod(GLfloat maxLod) { - mTextureState.samplerState.maxLod = maxLod; + mState.mSamplerState.maxLod = maxLod; + mDirtyBits.set(DIRTY_BIT_MAX_LOD); } GLfloat Texture::getMaxLod() const { - return mTextureState.samplerState.maxLod; + return mState.mSamplerState.maxLod; } void Texture::setCompareMode(GLenum compareMode) { - mTextureState.samplerState.compareMode = compareMode; + mState.mSamplerState.compareMode = compareMode; + mDirtyBits.set(DIRTY_BIT_COMPARE_MODE); } GLenum Texture::getCompareMode() const { - return mTextureState.samplerState.compareMode; + return mState.mSamplerState.compareMode; } void Texture::setCompareFunc(GLenum compareFunc) { - mTextureState.samplerState.compareFunc = compareFunc; + mState.mSamplerState.compareFunc = compareFunc; + mDirtyBits.set(DIRTY_BIT_COMPARE_FUNC); } GLenum Texture::getCompareFunc() const { - return mTextureState.samplerState.compareFunc; + return mState.mSamplerState.compareFunc; +} + +void Texture::setSRGBDecode(GLenum sRGBDecode) +{ + mState.mSamplerState.sRGBDecode = sRGBDecode; + mDirtyBits.set(DIRTY_BIT_SRGB_DECODE); +} + +GLenum Texture::getSRGBDecode() const +{ + return mState.mSamplerState.sRGBDecode; } const SamplerState &Texture::getSamplerState() const { - return mTextureState.samplerState; + return mState.mSamplerState; } -void Texture::setBaseLevel(GLuint baseLevel) +Error Texture::setBaseLevel(const Context *context, GLuint baseLevel) { - mTextureState.baseLevel = baseLevel; + if (mState.setBaseLevel(baseLevel)) + { + ANGLE_TRY(mTexture->setBaseLevel(context, mState.getEffectiveBaseLevel())); + mDirtyBits.set(DIRTY_BIT_BASE_LEVEL); + invalidateCompletenessCache(); + } + + return NoError(); } GLuint Texture::getBaseLevel() const { - return mTextureState.baseLevel; + return mState.mBaseLevel; } void Texture::setMaxLevel(GLuint maxLevel) { - mTextureState.maxLevel = maxLevel; + if (mState.setMaxLevel(maxLevel)) + { + mDirtyBits.set(DIRTY_BIT_MAX_LEVEL); + invalidateCompletenessCache(); + } } GLuint Texture::getMaxLevel() const { - return mTextureState.maxLevel; + return mState.mMaxLevel; +} + +void Texture::setDepthStencilTextureMode(GLenum mode) +{ + if (mode != mState.mDepthStencilTextureMode) + { + // Changing the mode from the default state (GL_DEPTH_COMPONENT) is not implemented yet + UNIMPLEMENTED(); + } + + // TODO(geofflang): add dirty bits + mState.mDepthStencilTextureMode = mode; +} + +GLenum Texture::getDepthStencilTextureMode() const +{ + return mState.mDepthStencilTextureMode; } bool Texture::getImmutableFormat() const { - return mTextureState.immutableFormat; + return mState.mImmutableFormat; } GLuint Texture::getImmutableLevels() const { - return mTextureState.immutableLevels; + return mState.mImmutableLevels; } void Texture::setUsage(GLenum usage) { - mTextureState.usage = usage; - getImplementation()->setUsage(usage); + mState.mUsage = usage; + mDirtyBits.set(DIRTY_BIT_USAGE); } GLenum Texture::getUsage() const { - return mTextureState.usage; + return mState.mUsage; } const TextureState &Texture::getTextureState() const { - return mTextureState; + return mState; } 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; + ASSERT(target == mState.mTarget || + (mState.mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target))); + return mState.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; + ASSERT(target == mState.mTarget || + (mState.mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target))); + return mState.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; + ASSERT(target == mState.mTarget || + (mState.mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target))); + return mState.getImageDesc(target, level).size.depth; } -GLenum Texture::getInternalFormat(GLenum target, size_t level) const +const Format &Texture::getFormat(GLenum target, size_t level) const { - ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target))); - return getImageDesc(target, level).internalFormat; + ASSERT(target == mState.mTarget || + (mState.mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target))); + return mState.getImageDesc(target, level).format; } -bool Texture::isSamplerComplete(const SamplerState &samplerState, const Data &data) const +GLsizei Texture::getSamples(GLenum target, size_t level) const { - const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), mTextureState.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; + ASSERT(target == mState.mTarget || + (mState.mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target))); + return mState.getImageDesc(target, level).samples; } -bool Texture::isMipmapComplete() const +bool Texture::getFixedSampleLocations(GLenum target, size_t level) const { - return computeMipmapCompleteness(); + ASSERT(target == mState.mTarget || + (mState.mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target))); + return mState.getImageDesc(target, level).fixedSampleLocations; } -// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81. -bool Texture::isCubeComplete() const +GLuint Texture::getMipmapMaxLevel() 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; - } + return mState.getMipmapMaxLevel(); +} - 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; - } - } +bool Texture::isMipmapComplete() const +{ + return mState.computeMipmapCompleteness(); +} - return true; +egl::Surface *Texture::getBoundSurface() const +{ + return mBoundSurface; } -size_t Texture::getMipCompleteLevels() const +egl::Stream *Texture::getBoundStream() const { - const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), 0); - if (mTarget == GL_TEXTURE_3D) - { - const int maxDim = std::max(std::max(baseImageDesc.size.width, baseImageDesc.size.height), - baseImageDesc.size.depth); - return log2(maxDim) + 1; - } - else - { - return log2(std::max(baseImageDesc.size.width, baseImageDesc.size.height)) + 1; - } + return mBoundStream; } -egl::Surface *Texture::getBoundSurface() const +void Texture::signalDirty(InitState initState) const { - return mBoundSurface; + mDirtyChannel.signal(initState); + invalidateCompletenessCache(); } -Error Texture::setImage(Context *context, +Error Texture::setImage(const Context *context, + const PixelUnpackState &unpackState, GLenum target, size_t level, GLenum internalFormat, @@ -378,33 +911,25 @@ Error Texture::setImage(Context *context, GLenum type, const uint8_t *pixels) { - ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target))); + ASSERT(target == mState.mTarget || + (mState.mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target))); // Release from previous calls to eglBindTexImage, to avoid calling the Impl after - releaseTexImageInternal(); - orphanImages(); - - // Hack: allow nullptr for testing - if (context != nullptr) - { - // Sync the unpack state - context->syncRendererState(context->getState().unpackStateBitMask()); - } + ANGLE_TRY(releaseTexImageInternal(context)); + ANGLE_TRY(orphanImages(context)); - const PixelUnpackState defaultUnpack; - const PixelUnpackState &unpack = context ? context->getState().getUnpackState() : defaultUnpack; - Error error = mTexture->setImage(target, level, internalFormat, size, format, type, unpack, pixels); - if (error.isError()) - { - return error; - } + ANGLE_TRY(mTexture->setImage(context, target, level, internalFormat, size, format, type, + unpackState, pixels)); - setImageDesc(target, level, ImageDesc(size, GetSizedInternalFormat(internalFormat, type))); + InitState initState = DetermineInitState(context, pixels); + mState.setImageDesc(target, level, ImageDesc(size, Format(internalFormat, type), initState)); + signalDirty(initState); - return Error(GL_NO_ERROR); + return NoError(); } -Error Texture::setSubImage(Context *context, +Error Texture::setSubImage(const Context *context, + const PixelUnpackState &unpackState, GLenum target, size_t level, const Box &area, @@ -412,16 +937,16 @@ Error Texture::setSubImage(Context *context, GLenum type, const uint8_t *pixels) { - ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target))); + ASSERT(target == mState.mTarget || + (mState.mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target))); - // Sync the unpack state - context->syncRendererState(context->getState().unpackStateBitMask()); + ANGLE_TRY(ensureSubImageInitialized(context, target, level, area)); - const PixelUnpackState &unpack = context->getState().getUnpackState(); - return mTexture->setSubImage(target, level, area, format, type, unpack, pixels); + return mTexture->setSubImage(context, target, level, area, format, type, unpackState, pixels); } -Error Texture::setCompressedImage(Context *context, +Error Texture::setCompressedImage(const Context *context, + const PixelUnpackState &unpackState, GLenum target, size_t level, GLenum internalFormat, @@ -429,28 +954,25 @@ Error Texture::setCompressedImage(Context *context, size_t imageSize, const uint8_t *pixels) { - ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target))); + ASSERT(target == mState.mTarget || + (mState.mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target))); // Release from previous calls to eglBindTexImage, to avoid calling the Impl after - releaseTexImageInternal(); - orphanImages(); - - // Sync the unpack state - context->syncRendererState(context->getState().unpackStateBitMask()); + ANGLE_TRY(releaseTexImageInternal(context)); + ANGLE_TRY(orphanImages(context)); - const PixelUnpackState &unpack = context->getState().getUnpackState(); - Error error = mTexture->setCompressedImage(target, level, internalFormat, size, unpack, imageSize, pixels); - if (error.isError()) - { - return error; - } + ANGLE_TRY(mTexture->setCompressedImage(context, target, level, internalFormat, size, + unpackState, imageSize, pixels)); - setImageDesc(target, level, ImageDesc(size, GetSizedInternalFormat(internalFormat, GL_UNSIGNED_BYTE))); + InitState initState = DetermineInitState(context, pixels); + mState.setImageDesc(target, level, ImageDesc(size, Format(internalFormat), initState)); + signalDirty(initState); - return Error(GL_NO_ERROR); + return NoError(); } -Error Texture::setCompressedSubImage(Context *context, +Error Texture::setCompressedSubImage(const Context *context, + const PixelUnpackState &unpackState, GLenum target, size_t level, const Box &area, @@ -458,428 +980,505 @@ Error Texture::setCompressedSubImage(Context *context, size_t imageSize, const uint8_t *pixels) { - ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target))); + ASSERT(target == mState.mTarget || + (mState.mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target))); - // Sync the unpack state - context->syncRendererState(context->getState().unpackStateBitMask()); + ANGLE_TRY(ensureSubImageInitialized(context, target, level, area)); - const PixelUnpackState &unpack = context->getState().getUnpackState(); - return mTexture->setCompressedSubImage(target, level, area, format, unpack, imageSize, pixels); + return mTexture->setCompressedSubImage(context, target, level, area, format, unpackState, + imageSize, pixels); } -Error Texture::copyImage(GLenum target, size_t level, const Rectangle &sourceArea, GLenum internalFormat, - const Framebuffer *source) +Error Texture::copyImage(const Context *context, + GLenum target, + size_t level, + const Rectangle &sourceArea, + GLenum internalFormat, + Framebuffer *source) { - ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target))); + ASSERT(target == mState.mTarget || + (mState.mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target))); // Release from previous calls to eglBindTexImage, to avoid calling the Impl after - releaseTexImageInternal(); - orphanImages(); + ANGLE_TRY(releaseTexImageInternal(context)); + ANGLE_TRY(orphanImages(context)); - Error error = mTexture->copyImage(target, level, sourceArea, internalFormat, source); - if (error.isError()) - { - return error; - } + // Ensure source FBO is initialized. + ANGLE_TRY(source->ensureReadAttachmentInitialized(context, GL_COLOR_BUFFER_BIT)); - setImageDesc(target, level, ImageDesc(Extents(sourceArea.width, sourceArea.height, 1), - GetSizedInternalFormat(internalFormat, GL_UNSIGNED_BYTE))); + // Use the source FBO size as the init image area. + Box destBox(0, 0, 0, sourceArea.width, sourceArea.height, 1); + ANGLE_TRY(ensureSubImageInitialized(context, target, level, destBox)); - return Error(GL_NO_ERROR); -} + ANGLE_TRY(mTexture->copyImage(context, target, level, sourceArea, internalFormat, source)); -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))); + const InternalFormat &internalFormatInfo = + GetInternalFormatInfo(internalFormat, GL_UNSIGNED_BYTE); + + mState.setImageDesc(target, level, + ImageDesc(Extents(sourceArea.width, sourceArea.height, 1), + Format(internalFormatInfo), InitState::Initialized)); + + // We need to initialize this texture only if the source attachment is not initialized. + signalDirty(InitState::Initialized); - return mTexture->copySubImage(target, level, destOffset, sourceArea, source); + return NoError(); } -Error Texture::setStorage(GLenum target, size_t levels, GLenum internalFormat, const Extents &size) +Error Texture::copySubImage(const Context *context, + GLenum target, + size_t level, + const Offset &destOffset, + const Rectangle &sourceArea, + Framebuffer *source) { - ASSERT(target == mTarget); + ASSERT(target == mState.mTarget || + (mState.mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target))); - // Release from previous calls to eglBindTexImage, to avoid calling the Impl after - releaseTexImageInternal(); - orphanImages(); - - Error error = mTexture->setStorage(target, levels, internalFormat, size); - if (error.isError()) - { - return error; - } + // Ensure source FBO is initialized. + ANGLE_TRY(source->ensureReadAttachmentInitialized(context, GL_COLOR_BUFFER_BIT)); - mTextureState.immutableFormat = true; - mTextureState.immutableLevels = static_cast(levels); - clearImageDescs(); - setImageDescChain(levels, size, internalFormat); + Box destBox(destOffset.x, destOffset.y, destOffset.y, sourceArea.width, sourceArea.height, 1); + ANGLE_TRY(ensureSubImageInitialized(context, target, level, destBox)); - return Error(GL_NO_ERROR); + return mTexture->copySubImage(context, target, level, destOffset, sourceArea, source); } -Error Texture::generateMipmaps() +Error Texture::copyTexture(const Context *context, + GLenum target, + size_t level, + GLenum internalFormat, + GLenum type, + size_t sourceLevel, + bool unpackFlipY, + bool unpackPremultiplyAlpha, + bool unpackUnmultiplyAlpha, + Texture *source) { + ASSERT(target == mState.mTarget || + (mState.mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target))); + // Release from previous calls to eglBindTexImage, to avoid calling the Impl after - releaseTexImageInternal(); + ANGLE_TRY(releaseTexImageInternal(context)); + ANGLE_TRY(orphanImages(context)); - // EGL_KHR_gl_image states that images are only orphaned when generating mipmaps if the texture - // is not mip complete. - if (!isMipmapComplete()) - { - orphanImages(); - } + // Initialize source texture. + // Note: we don't have a way to notify which portions of the image changed currently. + ANGLE_TRY(source->ensureInitialized(context)); - Error error = mTexture->generateMipmaps(mTextureState); - if (error.isError()) - { - return error; - } + ANGLE_TRY(mTexture->copyTexture(context, target, level, internalFormat, type, sourceLevel, + unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha, + source)); + + const auto &sourceDesc = source->mState.getImageDesc(source->getTarget(), 0); + const InternalFormat &internalFormatInfo = GetInternalFormatInfo(internalFormat, type); + mState.setImageDesc( + target, level, + ImageDesc(sourceDesc.size, Format(internalFormatInfo), InitState::Initialized)); - 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); + signalDirty(InitState::Initialized); - return Error(GL_NO_ERROR); + return NoError(); } -void Texture::setImageDescChain(size_t levels, Extents baseSize, GLenum sizedInternalFormat) +Error Texture::copySubTexture(const Context *context, + GLenum target, + size_t level, + const Offset &destOffset, + size_t sourceLevel, + const Rectangle &sourceArea, + bool unpackFlipY, + bool unpackPremultiplyAlpha, + bool unpackUnmultiplyAlpha, + Texture *source) { - for (int level = 0; level < static_cast(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); + ASSERT(target == mState.mTarget || + (mState.mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target))); - if (mTarget == GL_TEXTURE_CUBE_MAP) - { - for (GLenum face = FirstCubeMapTextureTarget; face <= LastCubeMapTextureTarget; face++) - { - setImageDesc(face, level, levelInfo); - } - } - else - { - setImageDesc(mTarget, level, levelInfo); - } - } -} + // Ensure source is initialized. + ANGLE_TRY(source->ensureInitialized(context)); -Texture::ImageDesc::ImageDesc() - : ImageDesc(Extents(0, 0, 0), GL_NONE) -{ -} + Box destBox(destOffset.x, destOffset.y, destOffset.y, sourceArea.width, sourceArea.height, 1); + ANGLE_TRY(ensureSubImageInitialized(context, target, level, destBox)); -Texture::ImageDesc::ImageDesc(const Extents &size, GLenum internalFormat) - : size(size), - internalFormat(internalFormat) -{ + return mTexture->copySubTexture(context, target, level, destOffset, sourceLevel, sourceArea, + unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha, + source); } -const Texture::ImageDesc &Texture::getImageDesc(GLenum target, size_t level) const +Error Texture::copyCompressedTexture(const Context *context, const Texture *source) { - size_t descIndex = GetImageDescIndex(target, level); - ASSERT(descIndex < mImageDescs.size()); - return mImageDescs[descIndex]; + // Release from previous calls to eglBindTexImage, to avoid calling the Impl after + ANGLE_TRY(releaseTexImageInternal(context)); + ANGLE_TRY(orphanImages(context)); + + ANGLE_TRY(mTexture->copyCompressedTexture(context, source)); + + ASSERT(source->getTarget() != GL_TEXTURE_CUBE_MAP && getTarget() != GL_TEXTURE_CUBE_MAP); + const auto &sourceDesc = source->mState.getImageDesc(source->getTarget(), 0); + mState.setImageDesc(getTarget(), 0, sourceDesc); + + return NoError(); } -void Texture::setImageDesc(GLenum target, size_t level, const ImageDesc &desc) +Error Texture::setStorage(const Context *context, + GLenum target, + GLsizei levels, + GLenum internalFormat, + const Extents &size) { - size_t descIndex = GetImageDescIndex(target, level); - ASSERT(descIndex < mImageDescs.size()); - mImageDescs[descIndex] = desc; - mCompletenessCache.cacheValid = false; + ASSERT(target == mState.mTarget); + + // Release from previous calls to eglBindTexImage, to avoid calling the Impl after + ANGLE_TRY(releaseTexImageInternal(context)); + ANGLE_TRY(orphanImages(context)); + + ANGLE_TRY(mTexture->setStorage(context, target, levels, internalFormat, size)); + + mState.mImmutableFormat = true; + mState.mImmutableLevels = static_cast(levels); + mState.clearImageDescs(); + mState.setImageDescChain(0, static_cast(levels - 1), size, Format(internalFormat), + InitState::MayNeedInit); + + // Changing the texture to immutable can trigger a change in the base and max levels: + // GLES 3.0.4 section 3.8.10 pg 158: + // "For immutable-format textures, levelbase is clamped to the range[0;levels],levelmax is then + // clamped to the range[levelbase;levels]. + mDirtyBits.set(DIRTY_BIT_BASE_LEVEL); + mDirtyBits.set(DIRTY_BIT_MAX_LEVEL); + + signalDirty(InitState::MayNeedInit); + + return NoError(); } -void Texture::clearImageDesc(GLenum target, size_t level) +Error Texture::setStorageMultisample(const Context *context, + GLenum target, + GLsizei samples, + GLint internalFormat, + const Extents &size, + bool fixedSampleLocations) { - setImageDesc(target, level, ImageDesc()); + ASSERT(target == mState.mTarget); + + // Release from previous calls to eglBindTexImage, to avoid calling the Impl after + ANGLE_TRY(releaseTexImageInternal(context)); + ANGLE_TRY(orphanImages(context)); + + ANGLE_TRY(mTexture->setStorageMultisample(context, target, samples, internalFormat, size, + fixedSampleLocations)); + + mState.mImmutableFormat = true; + mState.mImmutableLevels = static_cast(1); + mState.clearImageDescs(); + mState.setImageDescChainMultisample(size, Format(internalFormat), samples, fixedSampleLocations, + InitState::MayNeedInit); + + signalDirty(InitState::MayNeedInit); + + return NoError(); } -void Texture::clearImageDescs() +Error Texture::generateMipmap(const Context *context) { - for (size_t descIndex = 0; descIndex < mImageDescs.size(); descIndex++) + // Release from previous calls to eglBindTexImage, to avoid calling the Impl after + ANGLE_TRY(releaseTexImageInternal(context)); + + // EGL_KHR_gl_image states that images are only orphaned when generating mipmaps if the texture + // is not mip complete. + if (!isMipmapComplete()) { - mImageDescs[descIndex] = ImageDesc(); + ANGLE_TRY(orphanImages(context)); + } + + const GLuint baseLevel = mState.getEffectiveBaseLevel(); + const GLuint maxLevel = mState.getMipmapMaxLevel(); + + if (maxLevel > baseLevel) + { + syncState(); + const ImageDesc &baseImageInfo = + mState.getImageDesc(mState.getBaseImageTarget(), baseLevel); + + // Clear the base image immediately if necessary. + if (context->isRobustResourceInitEnabled() && + baseImageInfo.initState == InitState::MayNeedInit) + { + ANGLE_TRY(initializeContents( + context, GetImageIndexFromDescIndex(mState.getBaseImageTarget(), baseLevel))); + } + + ANGLE_TRY(mTexture->generateMipmap(context)); + + mState.setImageDescChain(baseLevel, maxLevel, baseImageInfo.size, baseImageInfo.format, + InitState::Initialized); } - mCompletenessCache.cacheValid = false; + + signalDirty(InitState::Initialized); + + return NoError(); } -void Texture::bindTexImageFromSurface(egl::Surface *surface) +Error Texture::bindTexImageFromSurface(const Context *context, egl::Surface *surface) { ASSERT(surface); if (mBoundSurface) { - releaseTexImageFromSurface(); + ANGLE_TRY(releaseTexImageFromSurface(context)); } - mTexture->bindTexImage(surface); + ANGLE_TRY(mTexture->bindTexImage(context, surface)); mBoundSurface = surface; // Set the image info to the size and format of the surface - ASSERT(mTarget == GL_TEXTURE_2D); + ASSERT(mState.mTarget == GL_TEXTURE_2D || mState.mTarget == GL_TEXTURE_RECTANGLE_ANGLE); Extents size(surface->getWidth(), surface->getHeight(), 1); - ImageDesc desc(size, surface->getConfig()->renderTargetFormat); - setImageDesc(mTarget, 0, desc); + ImageDesc desc(size, Format(surface->getConfig()->renderTargetFormat), InitState::Initialized); + mState.setImageDesc(mState.mTarget, 0, desc); + signalDirty(InitState::Initialized); + return NoError(); } -void Texture::releaseTexImageFromSurface() +Error Texture::releaseTexImageFromSurface(const Context *context) { ASSERT(mBoundSurface); mBoundSurface = nullptr; - mTexture->releaseTexImage(); + ANGLE_TRY(mTexture->releaseTexImage(context)); // Erase the image info for level 0 - ASSERT(mTarget == GL_TEXTURE_2D); - clearImageDesc(mTarget, 0); + ASSERT(mState.mTarget == GL_TEXTURE_2D || mState.mTarget == GL_TEXTURE_RECTANGLE_ANGLE); + mState.clearImageDesc(mState.mTarget, 0); + signalDirty(InitState::Initialized); + return NoError(); +} + +void Texture::bindStream(egl::Stream *stream) +{ + ASSERT(stream); + + // It should not be possible to bind a texture already bound to another stream + ASSERT(mBoundStream == nullptr); + + mBoundStream = stream; + + ASSERT(mState.mTarget == GL_TEXTURE_EXTERNAL_OES); +} + +void Texture::releaseStream() +{ + ASSERT(mBoundStream); + mBoundStream = nullptr; +} + +Error Texture::acquireImageFromStream(const Context *context, + const egl::Stream::GLTextureDescription &desc) +{ + ASSERT(mBoundStream != nullptr); + ANGLE_TRY(mTexture->setImageExternal(context, mState.mTarget, mBoundStream, desc)); + + Extents size(desc.width, desc.height, 1); + mState.setImageDesc(mState.mTarget, 0, + ImageDesc(size, Format(desc.internalFormat), InitState::Initialized)); + signalDirty(InitState::Initialized); + return NoError(); +} + +Error Texture::releaseImageFromStream(const Context *context) +{ + ASSERT(mBoundStream != nullptr); + ANGLE_TRY(mTexture->setImageExternal(context, mState.mTarget, nullptr, + egl::Stream::GLTextureDescription())); + + // Set to incomplete + mState.clearImageDesc(mState.mTarget, 0); + signalDirty(InitState::Initialized); + return NoError(); } -void Texture::releaseTexImageInternal() +Error Texture::releaseTexImageInternal(const Context *context) { if (mBoundSurface) { // Notify the surface - mBoundSurface->releaseTexImageFromTexture(); + mBoundSurface->releaseTexImageFromTexture(context); // Then, call the same method as from the surface - releaseTexImageFromSurface(); + ANGLE_TRY(releaseTexImageFromSurface(context)); } + return NoError(); } -Error Texture::setEGLImageTarget(GLenum target, egl::Image *imageTarget) +Error Texture::setEGLImageTarget(const Context *context, GLenum target, egl::Image *imageTarget) { - ASSERT(target == mTarget); - ASSERT(target == GL_TEXTURE_2D); + ASSERT(target == mState.mTarget); + ASSERT(target == GL_TEXTURE_2D || target == GL_TEXTURE_EXTERNAL_OES); // Release from previous calls to eglBindTexImage, to avoid calling the Impl after - releaseTexImageInternal(); - orphanImages(); + ANGLE_TRY(releaseTexImageInternal(context)); + ANGLE_TRY(orphanImages(context)); - Error error = mTexture->setEGLImageTarget(target, imageTarget); - if (error.isError()) - { - return error; - } + ANGLE_TRY(mTexture->setEGLImageTarget(context, target, imageTarget)); - setTargetImage(imageTarget); + setTargetImage(context, imageTarget); Extents size(static_cast(imageTarget->getWidth()), static_cast(imageTarget->getHeight()), 1); - GLenum internalFormat = imageTarget->getInternalFormat(); - GLenum type = GetInternalFormatInfo(internalFormat).type; - clearImageDescs(); - setImageDesc(target, 0, ImageDesc(size, GetSizedInternalFormat(internalFormat, type))); + auto initState = imageTarget->sourceInitState(); - return Error(GL_NO_ERROR); + mState.clearImageDescs(); + mState.setImageDesc(target, 0, ImageDesc(size, imageTarget->getFormat(), initState)); + signalDirty(initState); + + return NoError(); } -GLenum Texture::getBaseImageTarget() const +Extents Texture::getAttachmentSize(const ImageIndex &imageIndex) const { - return mTarget == GL_TEXTURE_CUBE_MAP ? FirstCubeMapTextureTarget : mTarget; + return mState.getImageDesc(imageIndex).size; } -bool Texture::computeSamplerCompleteness(const SamplerState &samplerState, const Data &data) const +const Format &Texture::getAttachmentFormat(GLenum /*binding*/, const ImageIndex &imageIndex) const { - const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), mTextureState.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()) - { - return false; - } - } - else - { - if (mTarget == GL_TEXTURE_CUBE_MAP && !isCubeComplete()) - { - return false; - } - } + return mState.getImageDesc(imageIndex).format; +} - // 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; - } - } - } +GLsizei Texture::getAttachmentSamples(const ImageIndex &imageIndex) const +{ + return getSamples(imageIndex.type, 0); +} - return true; +void Texture::onAttach(const Context *context) +{ + addRef(); } -bool Texture::computeMipmapCompleteness() const +void Texture::onDetach(const Context *context) { - size_t expectedMipLevels = getMipCompleteLevels(); + release(context); +} - size_t maxLevel = std::min(expectedMipLevels, mTextureState.maxLevel + 1); +GLuint Texture::getId() const +{ + return id(); +} - for (size_t level = mTextureState.baseLevel; level < maxLevel; level++) - { - if (mTarget == GL_TEXTURE_CUBE_MAP) - { - for (GLenum face = FirstCubeMapTextureTarget; face <= LastCubeMapTextureTarget; face++) - { - if (!computeLevelCompleteness(face, level)) - { - return false; - } - } - } - else - { - if (!computeLevelCompleteness(mTarget, level)) - { - return false; - } - } - } +void Texture::syncState() +{ + mTexture->syncState(mDirtyBits); + mDirtyBits.reset(); +} - return true; +rx::FramebufferAttachmentObjectImpl *Texture::getAttachmentImpl() const +{ + return mTexture; } -bool Texture::computeLevelCompleteness(GLenum target, size_t level) const +bool Texture::isSamplerComplete(const Context *context, const Sampler *optionalSampler) { - ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS); + const auto &samplerState = + optionalSampler ? optionalSampler->getSamplerState() : mState.mSamplerState; + const auto &contextState = context->getContextState(); - if (mTextureState.immutableFormat) + if (contextState.getContextID() != mCompletenessCache.context || + mCompletenessCache.samplerState != samplerState) { - return true; + mCompletenessCache.context = context->getContextState().getContextID(); + mCompletenessCache.samplerState = samplerState; + mCompletenessCache.samplerComplete = + mState.computeSamplerCompleteness(samplerState, contextState); } - const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), mTextureState.baseLevel); - if (baseImageDesc.size.width == 0 || baseImageDesc.size.height == 0 || baseImageDesc.size.depth == 0) - { - return false; - } + return mCompletenessCache.samplerComplete; +} - const ImageDesc &levelImageDesc = getImageDesc(target, level); - if (levelImageDesc.size.width == 0 || levelImageDesc.size.height == 0 || - levelImageDesc.size.depth == 0) - { - return false; - } +Texture::SamplerCompletenessCache::SamplerCompletenessCache() + : context(0), samplerState(), samplerComplete(false) +{ +} - if (levelImageDesc.internalFormat != baseImageDesc.internalFormat) - { - return false; - } +void Texture::invalidateCompletenessCache() const +{ + mCompletenessCache.context = 0; +} - ASSERT(level >= mTextureState.baseLevel); - const size_t relativeLevel = level - mTextureState.baseLevel; - if (levelImageDesc.size.width != std::max(1, baseImageDesc.size.width >> relativeLevel)) +Error Texture::ensureInitialized(const Context *context) +{ + if (!context->isRobustResourceInitEnabled() || mState.mInitState == InitState::Initialized) { - return false; + return NoError(); } - if (levelImageDesc.size.height != std::max(1, baseImageDesc.size.height >> relativeLevel)) - { - return false; - } + bool anyDirty = false; - if (mTarget == GL_TEXTURE_3D) + for (size_t descIndex = 0; descIndex < mState.mImageDescs.size(); ++descIndex) { - if (levelImageDesc.size.depth != std::max(1, baseImageDesc.size.depth >> relativeLevel)) + auto &imageDesc = mState.mImageDescs[descIndex]; + if (imageDesc.initState == InitState::MayNeedInit) { - return false; + ASSERT(mState.mInitState == InitState::MayNeedInit); + const auto &imageIndex = GetImageIndexFromDescIndex(mState.mTarget, descIndex); + ANGLE_TRY(initializeContents(context, imageIndex)); + imageDesc.initState = InitState::Initialized; + anyDirty = true; } } - else if (mTarget == GL_TEXTURE_2D_ARRAY) + if (anyDirty) { - if (levelImageDesc.size.depth != baseImageDesc.size.depth) - { - return false; - } + signalDirty(InitState::Initialized); } + mState.mInitState = InitState::Initialized; - return true; + return NoError(); } -Texture::SamplerCompletenessCache::SamplerCompletenessCache() - : cacheValid(false), - samplerState(), - filterable(false), - clientVersion(0), - supportsNPOT(false), - samplerComplete(false) +InitState Texture::initState(const ImageIndex &imageIndex) const { + return mState.getImageDesc(imageIndex).initState; } -Extents Texture::getAttachmentSize(const gl::FramebufferAttachment::Target &target) const +InitState Texture::initState() const { - return getImageDesc(target.textureIndex().type, target.textureIndex().mipIndex).size; + return mState.mInitState; } -GLenum Texture::getAttachmentInternalFormat(const gl::FramebufferAttachment::Target &target) const +void Texture::setInitState(const ImageIndex &imageIndex, InitState initState) { - return getInternalFormat(target.textureIndex().type, target.textureIndex().mipIndex); + ImageDesc newDesc = mState.getImageDesc(imageIndex); + newDesc.initState = initState; + mState.setImageDesc(imageIndex.type, imageIndex.mipIndex, newDesc); } -GLsizei Texture::getAttachmentSamples(const gl::FramebufferAttachment::Target &/*target*/) const +Error Texture::ensureSubImageInitialized(const Context *context, + GLenum target, + size_t level, + const gl::Box &area) { - // Multisample textures not currently supported - return 0; -} + if (!context->isRobustResourceInitEnabled() || mState.mInitState == InitState::Initialized) + { + return NoError(); + } -void Texture::onAttach() -{ - addRef(); -} + // Pre-initialize the texture contents if necessary. + // TODO(jmadill): Check if area overlaps the entire texture. + const auto &imageIndex = GetImageIndexFromDescIndex(target, level); + const auto &desc = mState.getImageDesc(imageIndex); + if (desc.initState == InitState::MayNeedInit) + { + ASSERT(mState.mInitState == InitState::MayNeedInit); + bool coversWholeImage = area.x == 0 && area.y == 0 && area.z == 0 && + area.width == desc.size.width && area.height == desc.size.height && + area.depth == desc.size.depth; + if (!coversWholeImage) + { + ANGLE_TRY(initializeContents(context, imageIndex)); + } + setInitState(imageIndex, InitState::Initialized); + } -void Texture::onDetach() -{ - release(); + return NoError(); } -GLuint Texture::getId() const -{ - return id(); -} -} +} // namespace gl diff --git a/src/3rdparty/angle/src/libANGLE/Texture.h b/src/3rdparty/angle/src/libANGLE/Texture.h index 7ca8a456fc..7525da2b2f 100644 --- a/src/3rdparty/angle/src/libANGLE/Texture.h +++ b/src/3rdparty/angle/src/libANGLE/Texture.h @@ -13,37 +13,169 @@ #include #include "angle_gl.h" +#include "common/Optional.h" #include "common/debug.h" #include "libANGLE/Caps.h" -#include "libANGLE/Debug.h" #include "libANGLE/Constants.h" +#include "libANGLE/Debug.h" #include "libANGLE/Error.h" #include "libANGLE/FramebufferAttachment.h" #include "libANGLE/Image.h" +#include "libANGLE/Stream.h" #include "libANGLE/angletypes.h" -#include "libANGLE/renderer/TextureImpl.h" +#include "libANGLE/formatutils.h" namespace egl { class Surface; +class Stream; +} + +namespace rx +{ +class GLImplFactory; +class TextureImpl; +class TextureGL; } namespace gl { -class Context; +class ContextState; class Framebuffer; -struct Data; +class Sampler; +class Texture; bool IsMipmapFiltered(const SamplerState &samplerState); +struct ImageDesc final +{ + ImageDesc(); + ImageDesc(const Extents &size, const Format &format, const InitState initState); + ImageDesc(const Extents &size, + const Format &format, + const GLsizei samples, + const bool fixedSampleLocations, + const InitState initState); + + ImageDesc(const ImageDesc &other) = default; + ImageDesc &operator=(const ImageDesc &other) = default; + + Extents size; + Format format; + GLsizei samples; + bool fixedSampleLocations; + + // Needed for robust resource initialization. + InitState initState; +}; + +struct SwizzleState final +{ + SwizzleState(); + SwizzleState(GLenum red, GLenum green, GLenum blue, GLenum alpha); + SwizzleState(const SwizzleState &other) = default; + SwizzleState &operator=(const SwizzleState &other) = default; + + bool swizzleRequired() const; + + bool operator==(const SwizzleState &other) const; + bool operator!=(const SwizzleState &other) const; + + GLenum swizzleRed; + GLenum swizzleGreen; + GLenum swizzleBlue; + GLenum swizzleAlpha; +}; + +// State from Table 6.9 (state per texture object) in the OpenGL ES 3.0.2 spec. +struct TextureState final : private angle::NonCopyable +{ + TextureState(GLenum target); + ~TextureState(); + + bool swizzleRequired() const; + GLuint getEffectiveBaseLevel() const; + GLuint getEffectiveMaxLevel() const; + + // Returns the value called "q" in the GLES 3.0.4 spec section 3.8.10. + GLuint getMipmapMaxLevel() const; + + // Returns true if base level changed. + bool setBaseLevel(GLuint baseLevel); + bool setMaxLevel(GLuint maxLevel); + + bool isCubeComplete() const; + + const ImageDesc &getImageDesc(GLenum target, size_t level) const; + const ImageDesc &getImageDesc(const ImageIndex &imageIndex) const; + + GLenum getTarget() const { return mTarget; } + const SwizzleState &getSwizzleState() const { return mSwizzleState; } + const SamplerState &getSamplerState() const { return mSamplerState; } + GLenum getUsage() const { return mUsage; } + + private: + // Texture needs access to the ImageDesc functions. + friend class Texture; + // TODO(jmadill): Remove TextureGL from friends. + friend class rx::TextureGL; + friend bool operator==(const TextureState &a, const TextureState &b); + + bool computeSamplerCompleteness(const SamplerState &samplerState, + const ContextState &data) const; + bool computeMipmapCompleteness() const; + bool computeLevelCompleteness(GLenum target, size_t level) const; + + GLenum getBaseImageTarget() const; + + void setImageDesc(GLenum target, size_t level, const ImageDesc &desc); + void setImageDescChain(GLuint baselevel, + GLuint maxLevel, + Extents baseSize, + const Format &format, + InitState initState); + void setImageDescChainMultisample(Extents baseSize, + const Format &format, + GLsizei samples, + bool fixedSampleLocations, + InitState initState); + + void clearImageDesc(GLenum target, size_t level); + void clearImageDescs(); + + const GLenum mTarget; + + SwizzleState mSwizzleState; + + SamplerState mSamplerState; + + GLuint mBaseLevel; + GLuint mMaxLevel; + + GLenum mDepthStencilTextureMode; + + bool mImmutableFormat; + GLuint mImmutableLevels; + + // From GL_ANGLE_texture_usage + GLenum mUsage; + + std::vector mImageDescs; + InitState mInitState; +}; + +bool operator==(const TextureState &a, const TextureState &b); +bool operator!=(const TextureState &a, const TextureState &b); + class Texture final : public egl::ImageSibling, - public FramebufferAttachmentObject, public LabeledObject { public: - Texture(rx::TextureImpl *impl, GLuint id, GLenum target); + Texture(rx::GLImplFactory *factory, GLuint id, GLenum target); ~Texture() override; + Error onDestroy(const Context *context) override; + void setLabel(const std::string &label) override; const std::string &getLabel() const override; @@ -91,14 +223,20 @@ class Texture final : public egl::ImageSibling, void setCompareFunc(GLenum compareFunc); GLenum getCompareFunc() const; + void setSRGBDecode(GLenum sRGBDecode); + GLenum getSRGBDecode() const; + const SamplerState &getSamplerState() const; - void setBaseLevel(GLuint baseLevel); + gl::Error setBaseLevel(const Context *context, GLuint baseLevel); GLuint getBaseLevel() const; void setMaxLevel(GLuint maxLevel); GLuint getMaxLevel() const; + void setDepthStencilTextureMode(GLenum mode); + GLenum getDepthStencilTextureMode() const; + bool getImmutableFormat() const; GLuint getImmutableLevels() const; @@ -111,14 +249,17 @@ class Texture final : public egl::ImageSibling, 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; + GLsizei getSamples(GLenum target, size_t level) const; + bool getFixedSampleLocations(GLenum target, size_t level) const; + const Format &getFormat(GLenum target, size_t level) const; + + // Returns the value called "q" in the GLES 3.0.4 spec section 3.8.10. + GLuint getMipmapMaxLevel() const; - bool isSamplerComplete(const SamplerState &samplerState, const Data &data) const; bool isMipmapComplete() const; - bool isCubeComplete() const; - size_t getMipCompleteLevels() const; - Error setImage(Context *context, + Error setImage(const Context *context, + const PixelUnpackState &unpackState, GLenum target, size_t level, GLenum internalFormat, @@ -126,7 +267,8 @@ class Texture final : public egl::ImageSibling, GLenum format, GLenum type, const uint8_t *pixels); - Error setSubImage(Context *context, + Error setSubImage(const Context *context, + const PixelUnpackState &unpackState, GLenum target, size_t level, const Box &area, @@ -134,14 +276,16 @@ class Texture final : public egl::ImageSibling, GLenum type, const uint8_t *pixels); - Error setCompressedImage(Context *context, + Error setCompressedImage(const Context *context, + const PixelUnpackState &unpackState, GLenum target, size_t level, GLenum internalFormat, const Extents &size, size_t imageSize, const uint8_t *pixels); - Error setCompressedSubImage(Context *context, + Error setCompressedSubImage(const Context *context, + const PixelUnpackState &unpackState, GLenum target, size_t level, const Box &area, @@ -149,98 +293,179 @@ class Texture final : public egl::ImageSibling, size_t imageSize, const uint8_t *pixels); - Error copyImage(GLenum target, + Error copyImage(const Context *context, + GLenum target, size_t level, const Rectangle &sourceArea, GLenum internalFormat, - const Framebuffer *source); - Error copySubImage(GLenum target, + Framebuffer *source); + Error copySubImage(const Context *context, + GLenum target, size_t level, const Offset &destOffset, const Rectangle &sourceArea, - const Framebuffer *source); + Framebuffer *source); - Error setStorage(GLenum target, size_t levels, GLenum internalFormat, const Extents &size); + Error copyTexture(const Context *context, + GLenum target, + size_t level, + GLenum internalFormat, + GLenum type, + size_t sourceLevel, + bool unpackFlipY, + bool unpackPremultiplyAlpha, + bool unpackUnmultiplyAlpha, + Texture *source); + Error copySubTexture(const Context *context, + GLenum target, + size_t level, + const Offset &destOffset, + size_t sourceLevel, + const Rectangle &sourceArea, + bool unpackFlipY, + bool unpackPremultiplyAlpha, + bool unpackUnmultiplyAlpha, + Texture *source); + Error copyCompressedTexture(const Context *context, const Texture *source); + + Error setStorage(const Context *context, + GLenum target, + GLsizei levels, + GLenum internalFormat, + const Extents &size); + + Error setStorageMultisample(const Context *context, + GLenum target, + GLsizei samples, + GLint internalformat, + const Extents &size, + bool fixedSampleLocations); - Error setEGLImageTarget(GLenum target, egl::Image *imageTarget); + Error setEGLImageTarget(const Context *context, GLenum target, egl::Image *imageTarget); - Error generateMipmaps(); + Error generateMipmap(const Context *context); egl::Surface *getBoundSurface() const; + egl::Stream *getBoundStream() const; - rx::TextureImpl *getImplementation() { return mTexture; } - const rx::TextureImpl *getImplementation() const { return mTexture; } + void signalDirty(InitState initState) const; + + bool isSamplerComplete(const Context *context, const Sampler *optionalSampler); + + rx::TextureImpl *getImplementation() const { return mTexture; } // FramebufferAttachmentObject implementation - Extents getAttachmentSize(const FramebufferAttachment::Target &target) const override; - GLenum getAttachmentInternalFormat(const FramebufferAttachment::Target &target) const override; - GLsizei getAttachmentSamples(const FramebufferAttachment::Target &target) const override; + Extents getAttachmentSize(const ImageIndex &imageIndex) const override; + const Format &getAttachmentFormat(GLenum binding, const ImageIndex &imageIndex) const override; + GLsizei getAttachmentSamples(const ImageIndex &imageIndex) const override; - void onAttach() override; - void onDetach() override; + void onAttach(const Context *context) override; + void onDetach(const Context *context) override; GLuint getId() const override; + // Needed for robust resource init. + Error ensureInitialized(const Context *context); + InitState initState(const ImageIndex &imageIndex) const override; + InitState initState() const; + void setInitState(const ImageIndex &imageIndex, InitState initState) override; + + enum DirtyBitType + { + // Sampler state + DIRTY_BIT_MIN_FILTER, + DIRTY_BIT_MAG_FILTER, + DIRTY_BIT_WRAP_S, + DIRTY_BIT_WRAP_T, + DIRTY_BIT_WRAP_R, + DIRTY_BIT_MAX_ANISOTROPY, + DIRTY_BIT_MIN_LOD, + DIRTY_BIT_MAX_LOD, + DIRTY_BIT_COMPARE_MODE, + DIRTY_BIT_COMPARE_FUNC, + DIRTY_BIT_SRGB_DECODE, + + // Texture state + DIRTY_BIT_SWIZZLE_RED, + DIRTY_BIT_SWIZZLE_GREEN, + DIRTY_BIT_SWIZZLE_BLUE, + DIRTY_BIT_SWIZZLE_ALPHA, + DIRTY_BIT_BASE_LEVEL, + DIRTY_BIT_MAX_LEVEL, + + // Misc + DIRTY_BIT_LABEL, + DIRTY_BIT_USAGE, + + DIRTY_BIT_COUNT, + }; + using DirtyBits = angle::BitSet; + + void syncState(); + bool hasAnyDirtyBit() const { return mDirtyBits.any(); } + private: - rx::FramebufferAttachmentObjectImpl *getAttachmentImpl() const override { return mTexture; } + rx::FramebufferAttachmentObjectImpl *getAttachmentImpl() const override; // ANGLE-only method, used internally friend class egl::Surface; - void bindTexImageFromSurface(egl::Surface *surface); - void releaseTexImageFromSurface(); - + Error bindTexImageFromSurface(const Context *context, egl::Surface *surface); + Error releaseTexImageFromSurface(const Context *context); + + // ANGLE-only methods, used internally + friend class egl::Stream; + void bindStream(egl::Stream *stream); + void releaseStream(); + Error acquireImageFromStream(const Context *context, + const egl::Stream::GLTextureDescription &desc); + Error releaseImageFromStream(const Context *context); + + void invalidateCompletenessCache() const; + Error releaseTexImageInternal(const Context *context); + + Error ensureSubImageInitialized(const Context *context, + GLenum target, + size_t level, + const gl::Box &area); + + TextureState mState; + DirtyBits mDirtyBits; rx::TextureImpl *mTexture; std::string mLabel; - TextureState mTextureState; - - GLenum mTarget; - - struct ImageDesc - { - Extents size; - GLenum internalFormat; - - ImageDesc(); - ImageDesc(const Extents &size, GLenum internalFormat); - }; - - GLenum getBaseImageTarget() const; - - bool computeSamplerCompleteness(const SamplerState &samplerState, const Data &data) const; - bool computeMipmapCompleteness() const; - bool computeLevelCompleteness(GLenum target, size_t level) 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(); - void releaseTexImageInternal(); - - std::vector mImageDescs; + egl::Surface *mBoundSurface; + egl::Stream *mBoundStream; struct SamplerCompletenessCache { SamplerCompletenessCache(); - bool cacheValid; + // Context used to generate this cache entry + ContextID context; // 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; + mutable SamplerCompletenessCache mCompletenessCache; }; +inline bool operator==(const TextureState &a, const TextureState &b) +{ + return a.mSwizzleState == b.mSwizzleState && a.mSamplerState == b.mSamplerState && + a.mBaseLevel == b.mBaseLevel && a.mMaxLevel == b.mMaxLevel && + a.mImmutableFormat == b.mImmutableFormat && a.mImmutableLevels == b.mImmutableLevels && + a.mUsage == b.mUsage; +} + +inline bool operator!=(const TextureState &a, const TextureState &b) +{ + return !(a == b); } +} // namespace gl -#endif // LIBANGLE_TEXTURE_H_ +#endif // LIBANGLE_TEXTURE_H_ diff --git a/src/3rdparty/angle/src/libANGLE/Thread.cpp b/src/3rdparty/angle/src/libANGLE/Thread.cpp new file mode 100644 index 0000000000..d346db1fa2 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/Thread.cpp @@ -0,0 +1,91 @@ +// +// Copyright(c) 2016 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. +// + +// Thread.cpp : Defines the Thread class which represents a global EGL thread. + +#include "libANGLE/Thread.h" + +#include "libANGLE/Context.h" +#include "libANGLE/Error.h" + +namespace egl +{ +Thread::Thread() + : mError(EGL_SUCCESS), + mAPI(EGL_OPENGL_ES_API), + mContext(static_cast(EGL_NO_CONTEXT)) +{ +} + +void Thread::setError(const Error &error) +{ + mError = error.getCode(); +} + +EGLint Thread::getError() const +{ + return mError; +} + +void Thread::setAPI(EGLenum api) +{ + mAPI = api; +} + +EGLenum Thread::getAPI() const +{ + return mAPI; +} + +void Thread::setCurrent(gl::Context *context) +{ + mContext = context; +} + +Surface *Thread::getCurrentDrawSurface() const +{ + if (mContext) + { + return mContext->getCurrentDrawSurface(); + } + return nullptr; +} + +Surface *Thread::getCurrentReadSurface() const +{ + if (mContext) + { + return mContext->getCurrentReadSurface(); + } + return nullptr; +} + +gl::Context *Thread::getContext() const +{ + return mContext; +} + +gl::Context *Thread::getValidContext() const +{ + if (mContext && mContext->isContextLost()) + { + mContext->handleError(gl::OutOfMemory() << "Context has been lost."); + return nullptr; + } + + return mContext; +} + +Display *Thread::getCurrentDisplay() const +{ + if (mContext) + { + return mContext->getCurrentDisplay(); + } + return nullptr; +} + +} // namespace egl diff --git a/src/3rdparty/angle/src/libANGLE/Thread.h b/src/3rdparty/angle/src/libANGLE/Thread.h new file mode 100644 index 0000000000..6406dad9e0 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/Thread.h @@ -0,0 +1,51 @@ +// +// Copyright(c) 2016 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. +// + +// Thread.h : Defines the Thread class which represents a global EGL thread. + +#ifndef LIBANGLE_THREAD_H_ +#define LIBANGLE_THREAD_H_ + +#include + +namespace gl +{ +class Context; +} // namespace gl + +namespace egl +{ +class Error; +class Display; +class Surface; + +class Thread +{ + public: + Thread(); + + void setError(const Error &error); + EGLint getError() const; + + void setAPI(EGLenum api); + EGLenum getAPI() const; + + void setCurrent(gl::Context *context); + Surface *getCurrentDrawSurface() const; + Surface *getCurrentReadSurface() const; + gl::Context *getContext() const; + gl::Context *getValidContext() const; + Display *getCurrentDisplay() const; + + private: + EGLint mError; + EGLenum mAPI; + gl::Context *mContext; +}; + +} // namespace egl + +#endif // LIBANGLE_THREAD_H_ diff --git a/src/3rdparty/angle/src/libANGLE/TransformFeedback.cpp b/src/3rdparty/angle/src/libANGLE/TransformFeedback.cpp index b7961971d0..99235debd4 100644 --- a/src/3rdparty/angle/src/libANGLE/TransformFeedback.cpp +++ b/src/3rdparty/angle/src/libANGLE/TransformFeedback.cpp @@ -8,133 +8,204 @@ #include "libANGLE/Buffer.h" #include "libANGLE/Caps.h" +#include "libANGLE/ContextState.h" +#include "libANGLE/Program.h" +#include "libANGLE/renderer/GLImplFactory.h" #include "libANGLE/renderer/TransformFeedbackImpl.h" namespace gl { -TransformFeedback::TransformFeedback(rx::TransformFeedbackImpl *impl, GLuint id, const Caps &caps) - : RefCountObject(id), - mImplementation(impl), - mLabel(), +TransformFeedbackState::TransformFeedbackState(size_t maxIndexedBuffers) + : mLabel(), mActive(false), mPrimitiveMode(GL_NONE), mPaused(false), + mProgram(nullptr), mGenericBuffer(), - mIndexedBuffers(caps.maxTransformFeedbackSeparateAttributes) + mIndexedBuffers(maxIndexedBuffers) { - ASSERT(impl != NULL); } -TransformFeedback::~TransformFeedback() +TransformFeedbackState::~TransformFeedbackState() +{ +} + +const BindingPointer &TransformFeedbackState::getGenericBuffer() const { - mGenericBuffer.set(nullptr); - for (size_t i = 0; i < mIndexedBuffers.size(); i++) + return mGenericBuffer; +} + +const OffsetBindingPointer &TransformFeedbackState::getIndexedBuffer(size_t idx) const +{ + return mIndexedBuffers[idx]; +} + +const std::vector> &TransformFeedbackState::getIndexedBuffers() const +{ + return mIndexedBuffers; +} + +TransformFeedback::TransformFeedback(rx::GLImplFactory *implFactory, GLuint id, const Caps &caps) + : RefCountObject(id), + mState(caps.maxTransformFeedbackSeparateAttributes), + mImplementation(implFactory->createTransformFeedback(mState)) +{ + ASSERT(mImplementation != nullptr); +} + +Error TransformFeedback::onDestroy(const Context *context) +{ + if (mState.mProgram) { - mIndexedBuffers[i].set(nullptr); + mState.mProgram->release(context); + mState.mProgram = nullptr; } + ASSERT(!mState.mProgram); + mState.mGenericBuffer.set(context, nullptr); + for (size_t i = 0; i < mState.mIndexedBuffers.size(); i++) + { + mState.mIndexedBuffers[i].set(context, nullptr); + } + + return NoError(); +} + +TransformFeedback::~TransformFeedback() +{ SafeDelete(mImplementation); } void TransformFeedback::setLabel(const std::string &label) { - mLabel = label; + mState.mLabel = label; } const std::string &TransformFeedback::getLabel() const { - return mLabel; + return mState.mLabel; } -void TransformFeedback::begin(GLenum primitiveMode) +void TransformFeedback::begin(const Context *context, GLenum primitiveMode, Program *program) { - mActive = true; - mPrimitiveMode = primitiveMode; - mPaused = false; + mState.mActive = true; + mState.mPrimitiveMode = primitiveMode; + mState.mPaused = false; mImplementation->begin(primitiveMode); + bindProgram(context, program); } -void TransformFeedback::end() +void TransformFeedback::end(const Context *context) { - mActive = false; - mPrimitiveMode = GL_NONE; - mPaused = false; + mState.mActive = false; + mState.mPrimitiveMode = GL_NONE; + mState.mPaused = false; mImplementation->end(); + if (mState.mProgram) + { + mState.mProgram->release(context); + mState.mProgram = nullptr; + } } void TransformFeedback::pause() { - mPaused = true; + mState.mPaused = true; mImplementation->pause(); } void TransformFeedback::resume() { - mPaused = false; + mState.mPaused = false; mImplementation->resume(); } bool TransformFeedback::isActive() const { - return mActive; + return mState.mActive; } bool TransformFeedback::isPaused() const { - return mPaused; + return mState.mPaused; } GLenum TransformFeedback::getPrimitiveMode() const { - return mPrimitiveMode; + return mState.mPrimitiveMode; +} + +void TransformFeedback::bindProgram(const Context *context, Program *program) +{ + if (mState.mProgram != program) + { + if (mState.mProgram != nullptr) + { + mState.mProgram->release(context); + } + mState.mProgram = program; + if (mState.mProgram != nullptr) + { + mState.mProgram->addRef(); + } + } } -void TransformFeedback::bindGenericBuffer(Buffer *buffer) +bool TransformFeedback::hasBoundProgram(GLuint program) const { - mGenericBuffer.set(buffer); - mImplementation->bindGenericBuffer(mGenericBuffer); + return mState.mProgram != nullptr && mState.mProgram->id() == program; } -void TransformFeedback::detachBuffer(GLuint bufferName) +void TransformFeedback::bindGenericBuffer(const Context *context, Buffer *buffer) { - for (size_t index = 0; index < mIndexedBuffers.size(); index++) + mState.mGenericBuffer.set(context, buffer); + mImplementation->bindGenericBuffer(mState.mGenericBuffer); +} + +void TransformFeedback::detachBuffer(const Context *context, GLuint bufferName) +{ + for (size_t index = 0; index < mState.mIndexedBuffers.size(); index++) { - if (mIndexedBuffers[index].id() == bufferName) + if (mState.mIndexedBuffers[index].id() == bufferName) { - mIndexedBuffers[index].set(nullptr); - mImplementation->bindIndexedBuffer(index, mIndexedBuffers[index]); + mState.mIndexedBuffers[index].set(context, nullptr); + mImplementation->bindIndexedBuffer(index, mState.mIndexedBuffers[index]); } } - if (mGenericBuffer.id() == bufferName) + if (mState.mGenericBuffer.id() == bufferName) { - mGenericBuffer.set(nullptr); - mImplementation->bindGenericBuffer(mGenericBuffer); + mState.mGenericBuffer.set(context, nullptr); + mImplementation->bindGenericBuffer(mState.mGenericBuffer); } } const BindingPointer &TransformFeedback::getGenericBuffer() const { - return mGenericBuffer; + return mState.mGenericBuffer; } -void TransformFeedback::bindIndexedBuffer(size_t index, Buffer *buffer, size_t offset, size_t size) +void TransformFeedback::bindIndexedBuffer(const Context *context, + size_t index, + Buffer *buffer, + size_t offset, + size_t size) { - ASSERT(index < mIndexedBuffers.size()); - mIndexedBuffers[index].set(buffer, offset, size); - mImplementation->bindIndexedBuffer(index, mIndexedBuffers[index]); + ASSERT(index < mState.mIndexedBuffers.size()); + mState.mIndexedBuffers[index].set(context, buffer, offset, size); + mImplementation->bindIndexedBuffer(index, mState.mIndexedBuffers[index]); } const OffsetBindingPointer &TransformFeedback::getIndexedBuffer(size_t index) const { - ASSERT(index < mIndexedBuffers.size()); - return mIndexedBuffers[index]; + ASSERT(index < mState.mIndexedBuffers.size()); + return mState.mIndexedBuffers[index]; } size_t TransformFeedback::getIndexedBufferCount() const { - return mIndexedBuffers.size(); + return mState.mIndexedBuffers.size(); } rx::TransformFeedbackImpl *TransformFeedback::getImplementation() diff --git a/src/3rdparty/angle/src/libANGLE/TransformFeedback.h b/src/3rdparty/angle/src/libANGLE/TransformFeedback.h index 098e4ea4d6..2b35d43f9a 100644 --- a/src/3rdparty/angle/src/libANGLE/TransformFeedback.h +++ b/src/3rdparty/angle/src/libANGLE/TransformFeedback.h @@ -16,6 +16,7 @@ namespace rx { +class GLImplFactory; class TransformFeedbackImpl; } @@ -23,18 +24,46 @@ namespace gl { class Buffer; struct Caps; +class Context; +class Program; + +class TransformFeedbackState final : angle::NonCopyable +{ + public: + TransformFeedbackState(size_t maxIndexedBuffers); + ~TransformFeedbackState(); + + const BindingPointer &getGenericBuffer() const; + const OffsetBindingPointer &getIndexedBuffer(size_t idx) const; + const std::vector> &getIndexedBuffers() const; + + private: + friend class TransformFeedback; + + std::string mLabel; + + bool mActive; + GLenum mPrimitiveMode; + bool mPaused; + + Program *mProgram; + + BindingPointer mGenericBuffer; + std::vector> mIndexedBuffers; +}; class TransformFeedback final : public RefCountObject, public LabeledObject { public: - TransformFeedback(rx::TransformFeedbackImpl* impl, GLuint id, const Caps &caps); - virtual ~TransformFeedback(); + TransformFeedback(rx::GLImplFactory *implFactory, GLuint id, const Caps &caps); + ~TransformFeedback() override; + Error onDestroy(const Context *context) override; void setLabel(const std::string &label) override; const std::string &getLabel() const override; - void begin(GLenum primitiveMode); - void end(); + void begin(const Context *context, GLenum primitiveMode, Program *program); + void end(const Context *context); void pause(); void resume(); @@ -42,29 +71,29 @@ class TransformFeedback final : public RefCountObject, public LabeledObject bool isPaused() const; GLenum getPrimitiveMode() const; - void bindGenericBuffer(Buffer *buffer); + bool hasBoundProgram(GLuint program) const; + + void bindGenericBuffer(const Context *context, Buffer *buffer); const BindingPointer &getGenericBuffer() const; - void bindIndexedBuffer(size_t index, Buffer *buffer, size_t offset, size_t size); + void bindIndexedBuffer(const Context *context, + size_t index, + Buffer *buffer, + size_t offset, + size_t size); const OffsetBindingPointer &getIndexedBuffer(size_t index) const; size_t getIndexedBufferCount() const; - void detachBuffer(GLuint bufferName); + void detachBuffer(const Context *context, GLuint bufferName); rx::TransformFeedbackImpl *getImplementation(); const rx::TransformFeedbackImpl *getImplementation() const; private: - rx::TransformFeedbackImpl* mImplementation; - - std::string mLabel; + void bindProgram(const Context *context, Program *program); - bool mActive; - GLenum mPrimitiveMode; - bool mPaused; - - BindingPointer mGenericBuffer; - std::vector> mIndexedBuffers; + TransformFeedbackState mState; + rx::TransformFeedbackImpl* mImplementation; }; } diff --git a/src/3rdparty/angle/src/libANGLE/Uniform.cpp b/src/3rdparty/angle/src/libANGLE/Uniform.cpp index bfae3c014f..dee8eee915 100644 --- a/src/3rdparty/angle/src/libANGLE/Uniform.cpp +++ b/src/3rdparty/angle/src/libANGLE/Uniform.cpp @@ -13,46 +13,99 @@ namespace gl { +StaticallyUsed::StaticallyUsed() + : vertexStaticUse(false), fragmentStaticUse(false), computeStaticUse(false) +{ +} + +StaticallyUsed::~StaticallyUsed() +{ +} + +StaticallyUsed::StaticallyUsed(const StaticallyUsed &rhs) = default; +StaticallyUsed &StaticallyUsed::operator=(const StaticallyUsed &rhs) = default; + +void StaticallyUsed::setStaticUse(GLenum shaderType, bool used) +{ + switch (shaderType) + { + case GL_VERTEX_SHADER: + vertexStaticUse = used; + break; + + case GL_FRAGMENT_SHADER: + fragmentStaticUse = used; + break; + + case GL_COMPUTE_SHADER: + computeStaticUse = used; + break; + + default: + UNREACHABLE(); + } +} + +void StaticallyUsed::unionReferencesWith(const StaticallyUsed &other) +{ + vertexStaticUse |= other.vertexStaticUse; + fragmentStaticUse |= other.fragmentStaticUse; + computeStaticUse |= other.computeStaticUse; +} + LinkedUniform::LinkedUniform() - : blockIndex(-1), blockInfo(sh::BlockMemberInfo::getDefaultBlockInfo()) + : typeInfo(nullptr), bufferIndex(-1), blockInfo(sh::BlockMemberInfo::getDefaultBlockInfo()) { } LinkedUniform::LinkedUniform(GLenum typeIn, GLenum precisionIn, const std::string &nameIn, - unsigned int arraySizeIn, - const int blockIndexIn, + const std::vector &arraySizesIn, + const int bindingIn, + const int offsetIn, + const int locationIn, + const int bufferIndexIn, const sh::BlockMemberInfo &blockInfoIn) - : blockIndex(blockIndexIn), blockInfo(blockInfoIn) + : typeInfo(&GetUniformTypeInfo(typeIn)), bufferIndex(bufferIndexIn), blockInfo(blockInfoIn) { type = typeIn; precision = precisionIn; name = nameIn; - arraySize = arraySizeIn; + arraySizes = arraySizesIn; + binding = bindingIn; + offset = offsetIn; + location = locationIn; + ASSERT(!isArrayOfArrays()); + ASSERT(!isArray() || !isStruct()); } LinkedUniform::LinkedUniform(const sh::Uniform &uniform) - : sh::Uniform(uniform), blockIndex(-1), blockInfo(sh::BlockMemberInfo::getDefaultBlockInfo()) + : sh::Uniform(uniform), + typeInfo(&GetUniformTypeInfo(type)), + bufferIndex(-1), + blockInfo(sh::BlockMemberInfo::getDefaultBlockInfo()) { + ASSERT(!isArrayOfArrays()); + ASSERT(!isArray() || !isStruct()); } LinkedUniform::LinkedUniform(const LinkedUniform &uniform) - : sh::Uniform(uniform), blockIndex(uniform.blockIndex), blockInfo(uniform.blockInfo) + : sh::Uniform(uniform), + StaticallyUsed(uniform), + typeInfo(uniform.typeInfo), + bufferIndex(uniform.bufferIndex), + blockInfo(uniform.blockInfo) { - // This function is not intended to be called during runtime. - ASSERT(uniform.mLazyData.empty()); } LinkedUniform &LinkedUniform::operator=(const LinkedUniform &uniform) { - // This function is not intended to be called during runtime. - ASSERT(uniform.mLazyData.empty()); - sh::Uniform::operator=(uniform); - blockIndex = uniform.blockIndex; + StaticallyUsed::operator=(uniform); + typeInfo = uniform.typeInfo; + bufferIndex = uniform.bufferIndex; blockInfo = uniform.blockInfo; - return *this; } @@ -62,80 +115,92 @@ LinkedUniform::~LinkedUniform() bool LinkedUniform::isInDefaultBlock() const { - return blockIndex == -1; + return bufferIndex == -1; } -size_t LinkedUniform::dataSize() const +bool LinkedUniform::isSampler() const { - ASSERT(type != GL_STRUCT_ANGLEX); - if (mLazyData.empty()) - { - mLazyData.resize(VariableExternalSize(type) * elementCount()); - ASSERT(!mLazyData.empty()); - } + return typeInfo->isSampler; +} - return mLazyData.size(); +bool LinkedUniform::isImage() const +{ + return typeInfo->isImageType; } -uint8_t *LinkedUniform::data() +bool LinkedUniform::isAtomicCounter() const { - if (mLazyData.empty()) - { - // dataSize() will init the data store. - size_t size = dataSize(); - memset(mLazyData.data(), 0, size); - } + return IsAtomicCounterType(type); +} - return mLazyData.data(); +bool LinkedUniform::isField() const +{ + return name.find('.') != std::string::npos; } -const uint8_t *LinkedUniform::data() const +size_t LinkedUniform::getElementSize() const { - return const_cast(this)->data(); + return typeInfo->externalSize; } -bool LinkedUniform::isSampler() const +size_t LinkedUniform::getElementComponents() const { - return IsSamplerType(type); + return typeInfo->componentCount; } -bool LinkedUniform::isField() const +BufferVariable::BufferVariable() + : bufferIndex(-1), blockInfo(sh::BlockMemberInfo::getDefaultBlockInfo()), topLevelArraySize(-1) { - return name.find('.') != std::string::npos; } -size_t LinkedUniform::getElementSize() const +BufferVariable::BufferVariable(GLenum typeIn, + GLenum precisionIn, + const std::string &nameIn, + const std::vector &arraySizesIn, + const int bufferIndexIn, + const sh::BlockMemberInfo &blockInfoIn) + : bufferIndex(bufferIndexIn), blockInfo(blockInfoIn), topLevelArraySize(-1) +{ + type = typeIn; + precision = precisionIn; + name = nameIn; + arraySizes = arraySizesIn; +} + +BufferVariable::~BufferVariable() { - return VariableExternalSize(type); } -uint8_t *LinkedUniform::getDataPtrToElement(size_t elementIndex) +ShaderVariableBuffer::ShaderVariableBuffer() : binding(0), dataSize(0) { - ASSERT((!isArray() && elementIndex == 0) || (isArray() && elementIndex < arraySize)); - return data() + getElementSize() * elementIndex; } -const uint8_t *LinkedUniform::getDataPtrToElement(size_t elementIndex) const +ShaderVariableBuffer::ShaderVariableBuffer(const ShaderVariableBuffer &other) = default; + +ShaderVariableBuffer::~ShaderVariableBuffer() +{ +} + +int ShaderVariableBuffer::numActiveVariables() const { - return const_cast(this)->getDataPtrToElement(elementIndex); + return static_cast(memberIndexes.size()); } -UniformBlock::UniformBlock() - : isArray(false), arrayElement(0), dataSize(0), vertexStaticUse(false), fragmentStaticUse(false) +InterfaceBlock::InterfaceBlock() : isArray(false), arrayElement(0) { } -UniformBlock::UniformBlock(const std::string &nameIn, bool isArrayIn, unsigned int arrayElementIn) - : name(nameIn), - isArray(isArrayIn), - arrayElement(arrayElementIn), - dataSize(0), - vertexStaticUse(false), - fragmentStaticUse(false) +InterfaceBlock::InterfaceBlock(const std::string &nameIn, + const std::string &mappedNameIn, + bool isArrayIn, + unsigned int arrayElementIn, + int bindingIn) + : name(nameIn), mappedName(mappedNameIn), isArray(isArrayIn), arrayElement(arrayElementIn) { + binding = bindingIn; } -std::string UniformBlock::nameWithArrayIndex() const +std::string InterfaceBlock::nameWithArrayIndex() const { std::stringstream fullNameStr; fullNameStr << name; @@ -146,4 +211,16 @@ std::string UniformBlock::nameWithArrayIndex() const return fullNameStr.str(); } + +std::string InterfaceBlock::mappedNameWithArrayIndex() const +{ + std::stringstream fullNameStr; + fullNameStr << mappedName; + if (isArray) + { + fullNameStr << "[" << arrayElement << "]"; + } + + return fullNameStr.str(); +} } diff --git a/src/3rdparty/angle/src/libANGLE/Uniform.h b/src/3rdparty/angle/src/libANGLE/Uniform.h index e62a583f3d..14c39387a6 100644 --- a/src/3rdparty/angle/src/libANGLE/Uniform.h +++ b/src/3rdparty/angle/src/libANGLE/Uniform.h @@ -18,53 +18,107 @@ namespace gl { +struct UniformTypeInfo; + +struct StaticallyUsed +{ + StaticallyUsed(); + StaticallyUsed(const StaticallyUsed &rhs); + virtual ~StaticallyUsed(); + + StaticallyUsed &operator=(const StaticallyUsed &rhs); + + void setStaticUse(GLenum shaderType, bool used); + void unionReferencesWith(const StaticallyUsed &other); + + bool vertexStaticUse; + bool fragmentStaticUse; + bool computeStaticUse; +}; // Helper struct representing a single shader uniform -struct LinkedUniform : public sh::Uniform +struct LinkedUniform : public sh::Uniform, public StaticallyUsed { LinkedUniform(); - LinkedUniform(GLenum type, GLenum precision, const std::string &name, unsigned int arraySize, const int blockIndex, const sh::BlockMemberInfo &blockInfo); + LinkedUniform(GLenum type, + GLenum precision, + const std::string &name, + const std::vector &arraySizes, + const int binding, + const int offset, + const int location, + const int bufferIndex, + const sh::BlockMemberInfo &blockInfo); LinkedUniform(const sh::Uniform &uniform); LinkedUniform(const LinkedUniform &uniform); LinkedUniform &operator=(const LinkedUniform &uniform); - ~LinkedUniform(); + ~LinkedUniform() override; - size_t dataSize() const; - uint8_t *data(); - const uint8_t *data() const; bool isSampler() const; + bool isImage() const; + bool isAtomicCounter() const; bool isInDefaultBlock() const; bool isField() const; size_t getElementSize() const; - uint8_t *getDataPtrToElement(size_t elementIndex); - const uint8_t *getDataPtrToElement(size_t elementIndex) const; + size_t getElementComponents() const; + + const UniformTypeInfo *typeInfo; - int blockIndex; + // Identifies the containing buffer backed resource -- interface block or atomic counter buffer. + int bufferIndex; sh::BlockMemberInfo blockInfo; +}; - private: - mutable rx::MemoryBuffer mLazyData; +struct BufferVariable : public sh::ShaderVariable, public StaticallyUsed +{ + BufferVariable(); + BufferVariable(GLenum type, + GLenum precision, + const std::string &name, + const std::vector &arraySizes, + const int bufferIndex, + const sh::BlockMemberInfo &blockInfo); + ~BufferVariable() override; + + int bufferIndex; + sh::BlockMemberInfo blockInfo; + + int topLevelArraySize; +}; + +// Parent struct for atomic counter, uniform block, and shader storage block buffer, which all +// contain a group of shader variables, and have a GL buffer backed. +struct ShaderVariableBuffer : public StaticallyUsed +{ + ShaderVariableBuffer(); + ShaderVariableBuffer(const ShaderVariableBuffer &other); + ~ShaderVariableBuffer() override; + int numActiveVariables() const; + + int binding; + unsigned int dataSize; + std::vector memberIndexes; }; -// Helper struct representing a single shader uniform block -struct UniformBlock +using AtomicCounterBuffer = ShaderVariableBuffer; + +// Helper struct representing a single shader interface block +struct InterfaceBlock : public ShaderVariableBuffer { - UniformBlock(); - UniformBlock(const std::string &nameIn, bool isArrayIn, unsigned int arrayElementIn); - UniformBlock(const UniformBlock &other) = default; - UniformBlock &operator=(const UniformBlock &other) = default; + InterfaceBlock(); + InterfaceBlock(const std::string &nameIn, + const std::string &mappedNameIn, + bool isArrayIn, + unsigned int arrayElementIn, + int bindingIn); std::string nameWithArrayIndex() const; + std::string mappedNameWithArrayIndex() const; std::string name; + std::string mappedName; bool isArray; unsigned int arrayElement; - unsigned int dataSize; - - bool vertexStaticUse; - bool fragmentStaticUse; - - std::vector memberUniformIndexes; }; } diff --git a/src/3rdparty/angle/src/libANGLE/VaryingPacking.cpp b/src/3rdparty/angle/src/libANGLE/VaryingPacking.cpp new file mode 100644 index 0000000000..6fc707b549 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/VaryingPacking.cpp @@ -0,0 +1,408 @@ +// +// 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. +// +// VaryingPacking: +// Class which describes a mapping from varyings to registers, according +// to the spec, or using custom packing algorithms. We also keep a register +// allocation list for the D3D renderer. +// + +#include "libANGLE/VaryingPacking.h" + +#include "common/utilities.h" +#include "libANGLE/Program.h" +#include "libANGLE/Shader.h" + +namespace gl +{ + +namespace +{ + +// true if varying x has a higher priority in packing than y +bool ComparePackedVarying(const PackedVarying &x, const PackedVarying &y) +{ + // If the PackedVarying 'x' or 'y' to be compared is an array element, this clones an equivalent + // non-array shader variable 'vx' or 'vy' for actual comparison instead. + sh::ShaderVariable vx, vy; + const sh::ShaderVariable *px, *py; + if (x.isArrayElement()) + { + vx = *x.varying; + vx.arraySizes.clear(); + px = &vx; + } + else + { + px = x.varying; + } + + if (y.isArrayElement()) + { + vy = *y.varying; + vy.arraySizes.clear(); + py = &vy; + } + else + { + py = y.varying; + } + + return gl::CompareShaderVar(*px, *py); +} + +} // anonymous namespace + +// Implementation of VaryingPacking +VaryingPacking::VaryingPacking(GLuint maxVaryingVectors, PackMode packMode) + : mRegisterMap(maxVaryingVectors), mPackMode(packMode) +{ +} + +VaryingPacking::~VaryingPacking() = default; + +// Packs varyings into generic varying registers, using the algorithm from +// See [OpenGL ES Shading Language 1.00 rev. 17] appendix A section 7 page 111 +// Also [OpenGL ES Shading Language 3.00 rev. 4] Section 11 page 119 +// Returns false if unsuccessful. +bool VaryingPacking::packVarying(const PackedVarying &packedVarying) +{ + const auto &varying = *packedVarying.varying; + + // "Non - square matrices of type matCxR consume the same space as a square matrix of type matN + // where N is the greater of C and R." + // Here we are a bit more conservative and allow packing non-square matrices more tightly. + // Make sure we use transposed matrix types to count registers correctly. + ASSERT(!varying.isStruct()); + GLenum transposedType = gl::TransposeMatrixType(varying.type); + unsigned int varyingRows = gl::VariableRowCount(transposedType); + unsigned int varyingColumns = gl::VariableColumnCount(transposedType); + + // "Variables of type mat2 occupies 2 complete rows." + // For non-WebGL contexts, we allow mat2 to occupy only two columns per row. + if (mPackMode == PackMode::WEBGL_STRICT && varying.type == GL_FLOAT_MAT2) + { + varyingColumns = 4; + } + + // "Arrays of size N are assumed to take N times the size of the base type" + // GLSL ES 3.10 section 4.3.6: Output variables cannot be arrays of arrays or arrays of + // structures, so we may use getBasicTypeElementCount(). + const unsigned int elementCount = varying.getBasicTypeElementCount(); + varyingRows *= (packedVarying.isArrayElement() ? 1 : elementCount); + + unsigned int maxVaryingVectors = static_cast(mRegisterMap.size()); + + // Fail if we are packing a single over-large varying. + if (varyingRows > maxVaryingVectors) + { + return false; + } + + // "For 2, 3 and 4 component variables packing is started using the 1st column of the 1st row. + // Variables are then allocated to successive rows, aligning them to the 1st column." + if (varyingColumns >= 2 && varyingColumns <= 4) + { + for (unsigned int row = 0; row <= maxVaryingVectors - varyingRows; ++row) + { + if (isFree(row, 0, varyingRows, varyingColumns)) + { + insert(row, 0, packedVarying); + return true; + } + } + + // "For 2 component variables, when there are no spare rows, the strategy is switched to + // using the highest numbered row and the lowest numbered column where the variable will + // fit." + if (varyingColumns == 2) + { + for (unsigned int r = maxVaryingVectors - varyingRows + 1; r-- >= 1;) + { + if (isFree(r, 2, varyingRows, 2)) + { + insert(r, 2, packedVarying); + return true; + } + } + } + + return false; + } + + // "1 component variables have their own packing rule. They are packed in order of size, largest + // first. Each variable is placed in the column that leaves the least amount of space in the + // column and aligned to the lowest available rows within that column." + ASSERT(varyingColumns == 1); + unsigned int contiguousSpace[4] = {0}; + unsigned int bestContiguousSpace[4] = {0}; + unsigned int totalSpace[4] = {0}; + + for (unsigned int row = 0; row < maxVaryingVectors; ++row) + { + for (unsigned int column = 0; column < 4; ++column) + { + if (mRegisterMap[row][column]) + { + contiguousSpace[column] = 0; + } + else + { + contiguousSpace[column]++; + totalSpace[column]++; + + if (contiguousSpace[column] > bestContiguousSpace[column]) + { + bestContiguousSpace[column] = contiguousSpace[column]; + } + } + } + } + + unsigned int bestColumn = 0; + for (unsigned int column = 1; column < 4; ++column) + { + if (bestContiguousSpace[column] >= varyingRows && + (bestContiguousSpace[bestColumn] < varyingRows || + totalSpace[column] < totalSpace[bestColumn])) + { + bestColumn = column; + } + } + + if (bestContiguousSpace[bestColumn] >= varyingRows) + { + for (unsigned int row = 0; row < maxVaryingVectors; row++) + { + if (isFree(row, bestColumn, varyingRows, 1)) + { + for (unsigned int arrayIndex = 0; arrayIndex < varyingRows; ++arrayIndex) + { + // If varyingRows > 1, it must be an array. + PackedVaryingRegister registerInfo; + registerInfo.packedVarying = &packedVarying; + registerInfo.registerRow = row + arrayIndex; + registerInfo.registerColumn = bestColumn; + registerInfo.varyingArrayIndex = + (packedVarying.isArrayElement() ? packedVarying.arrayIndex : arrayIndex); + registerInfo.varyingRowIndex = 0; + // Do not record register info for builtins. + // TODO(jmadill): Clean this up. + if (!packedVarying.varying->isBuiltIn()) + { + mRegisterList.push_back(registerInfo); + } + mRegisterMap[row + arrayIndex][bestColumn] = true; + } + break; + } + } + return true; + } + + return false; +} + +bool VaryingPacking::isFree(unsigned int registerRow, + unsigned int registerColumn, + unsigned int varyingRows, + unsigned int varyingColumns) const +{ + for (unsigned int row = 0; row < varyingRows; ++row) + { + ASSERT(registerRow + row < mRegisterMap.size()); + for (unsigned int column = 0; column < varyingColumns; ++column) + { + ASSERT(registerColumn + column < 4); + if (mRegisterMap[registerRow + row][registerColumn + column]) + { + return false; + } + } + } + + return true; +} + +void VaryingPacking::insert(unsigned int registerRow, + unsigned int registerColumn, + const PackedVarying &packedVarying) +{ + unsigned int varyingRows = 0; + unsigned int varyingColumns = 0; + + const auto &varying = *packedVarying.varying; + ASSERT(!varying.isStruct()); + GLenum transposedType = gl::TransposeMatrixType(varying.type); + varyingRows = gl::VariableRowCount(transposedType); + varyingColumns = gl::VariableColumnCount(transposedType); + + PackedVaryingRegister registerInfo; + registerInfo.packedVarying = &packedVarying; + registerInfo.registerColumn = registerColumn; + + // GLSL ES 3.10 section 4.3.6: Output variables cannot be arrays of arrays or arrays of + // structures, so we may use getBasicTypeElementCount(). + const unsigned int arrayElementCount = varying.getBasicTypeElementCount(); + for (unsigned int arrayElement = 0; arrayElement < arrayElementCount; ++arrayElement) + { + if (packedVarying.isArrayElement() && arrayElement != packedVarying.arrayIndex) + { + continue; + } + for (unsigned int varyingRow = 0; varyingRow < varyingRows; ++varyingRow) + { + registerInfo.registerRow = registerRow + (arrayElement * varyingRows) + varyingRow; + registerInfo.varyingRowIndex = varyingRow; + registerInfo.varyingArrayIndex = arrayElement; + // Do not record register info for builtins. + // TODO(jmadill): Clean this up. + if (!packedVarying.varying->isBuiltIn()) + { + mRegisterList.push_back(registerInfo); + } + + for (unsigned int columnIndex = 0; columnIndex < varyingColumns; ++columnIndex) + { + mRegisterMap[registerInfo.registerRow][registerColumn + columnIndex] = true; + } + } + } +} + +bool VaryingPacking::collectAndPackUserVaryings(gl::InfoLog &infoLog, + const Program::MergedVaryings &mergedVaryings, + const std::vector &tfVaryings) +{ + std::set uniqueFullNames; + mPackedVaryings.clear(); + + for (const auto &ref : mergedVaryings) + { + const sh::Varying *input = ref.second.vertex; + const sh::Varying *output = ref.second.fragment; + + // Only pack statically used varyings that have a matched input or output, plus special + // builtins. + if (((input && output) || (output && output->isBuiltIn())) && output->staticUse) + { + // Will get the vertex shader interpolation by default. + auto interpolation = ref.second.get()->interpolation; + + // Note that we lose the vertex shader static use information here. The data for the + // variable is taken from the fragment shader. + if (output->isStruct()) + { + ASSERT(!output->isArray()); + for (const auto &field : output->fields) + { + ASSERT(!field.isStruct() && !field.isArray()); + mPackedVaryings.push_back(PackedVarying(field, interpolation, output->name)); + uniqueFullNames.insert(mPackedVaryings.back().nameWithArrayIndex()); + } + } + else + { + mPackedVaryings.push_back(PackedVarying(*output, interpolation)); + uniqueFullNames.insert(mPackedVaryings.back().nameWithArrayIndex()); + } + continue; + } + + // Keep Transform FB varyings in the merged list always. + if (!input) + { + continue; + } + + for (const std::string &tfVarying : tfVaryings) + { + std::vector subscripts; + std::string baseName = ParseResourceName(tfVarying, &subscripts); + size_t subscript = GL_INVALID_INDEX; + if (!subscripts.empty()) + { + subscript = subscripts.back(); + } + // Already packed for fragment shader. + if (uniqueFullNames.count(tfVarying) > 0 || uniqueFullNames.count(baseName) > 0) + { + continue; + } + // Array as a whole and array element conflict has already been checked in + // linkValidateTransformFeedback. + if (baseName == input->name) + { + // Transform feedback for varying structs is underspecified. + // See Khronos bug 9856. + // TODO(jmadill): Figure out how to be spec-compliant here. + if (!input->isStruct() && tfVarying.compare(0, 3, "gl_") != 0) + { + mPackedVaryings.push_back(PackedVarying(*input, input->interpolation)); + mPackedVaryings.back().vertexOnly = true; + mPackedVaryings.back().arrayIndex = static_cast(subscript); + uniqueFullNames.insert(tfVarying); + } + // Continue to match next array element for 'input' if the current match is array + // element. + if (subscript == GL_INVALID_INDEX) + { + break; + } + } + } + } + + std::sort(mPackedVaryings.begin(), mPackedVaryings.end(), ComparePackedVarying); + + return packUserVaryings(infoLog, mPackedVaryings, tfVaryings); +} + +// See comment on packVarying. +bool VaryingPacking::packUserVaryings(gl::InfoLog &infoLog, + const std::vector &packedVaryings, + const std::vector &transformFeedbackVaryings) +{ + + // "Variables are packed into the registers one at a time so that they each occupy a contiguous + // subrectangle. No splitting of variables is permitted." + for (const PackedVarying &packedVarying : packedVaryings) + { + if (!packVarying(packedVarying)) + { + infoLog << "Could not pack varying " << packedVarying.nameWithArrayIndex(); + return false; + } + } + + // Sort the packed register list + std::sort(mRegisterList.begin(), mRegisterList.end()); + + // Assign semantic indices + for (unsigned int semanticIndex = 0; + semanticIndex < static_cast(mRegisterList.size()); ++semanticIndex) + { + mRegisterList[semanticIndex].semanticIndex = semanticIndex; + } + + return true; +} + +unsigned int VaryingPacking::getRegisterCount() const +{ + unsigned int count = 0; + + for (const Register ® : mRegisterMap) + { + if (reg.data[0] || reg.data[1] || reg.data[2] || reg.data[3]) + { + ++count; + } + } + + return count; +} + +} // namespace rx diff --git a/src/3rdparty/angle/src/libANGLE/VaryingPacking.h b/src/3rdparty/angle/src/libANGLE/VaryingPacking.h new file mode 100644 index 0000000000..14b25f929e --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/VaryingPacking.h @@ -0,0 +1,184 @@ +// +// 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. +// +// VaryingPacking: +// Class which describes a mapping from varyings to registers, according +// to the spec, or using custom packing algorithms. We also keep a register +// allocation list for the D3D renderer. +// + +#ifndef LIBANGLE_VARYINGPACKING_H_ +#define LIBANGLE_VARYINGPACKING_H_ + +#include + +#include "angle_gl.h" +#include "common/angleutils.h" +#include "libANGLE/Program.h" + +namespace gl +{ +class InfoLog; + +struct PackedVarying +{ + PackedVarying(const sh::ShaderVariable &varyingIn, sh::InterpolationType interpolationIn) + : PackedVarying(varyingIn, interpolationIn, "") + { + } + PackedVarying(const sh::ShaderVariable &varyingIn, + sh::InterpolationType interpolationIn, + const std::string &parentStructNameIn) + : varying(&varyingIn), + vertexOnly(false), + interpolation(interpolationIn), + parentStructName(parentStructNameIn), + arrayIndex(GL_INVALID_INDEX) + { + } + + bool isStructField() const { return !parentStructName.empty(); } + + bool isArrayElement() const { return arrayIndex != GL_INVALID_INDEX; } + + std::string nameWithArrayIndex() const + { + std::stringstream fullNameStr; + fullNameStr << varying->name; + if (arrayIndex != GL_INVALID_INDEX) + { + fullNameStr << "[" << arrayIndex << "]"; + } + return fullNameStr.str(); + } + + const sh::ShaderVariable *varying; + + // Transform feedback varyings can be only referenced in the VS. + bool vertexOnly; + + // Cached so we can store sh::ShaderVariable to point to varying fields. + sh::InterpolationType interpolation; + + // Struct name + std::string parentStructName; + + GLuint arrayIndex; +}; + +struct PackedVaryingRegister final +{ + PackedVaryingRegister() + : packedVarying(nullptr), + varyingArrayIndex(0), + varyingRowIndex(0), + registerRow(0), + registerColumn(0) + { + } + + PackedVaryingRegister(const PackedVaryingRegister &) = default; + PackedVaryingRegister &operator=(const PackedVaryingRegister &) = default; + + bool operator<(const PackedVaryingRegister &other) const + { + return sortOrder() < other.sortOrder(); + } + + unsigned int sortOrder() const + { + // TODO(jmadill): Handle interpolation types + return registerRow * 4 + registerColumn; + } + + bool isStructField() const { return !structFieldName.empty(); } + + // Index to the array of varyings. + const PackedVarying *packedVarying; + + // The array element of the packed varying. + unsigned int varyingArrayIndex; + + // The row of the array element of the packed varying. + unsigned int varyingRowIndex; + + // The register row to which we've assigned this packed varying. + unsigned int registerRow; + + // The column of the register row into which we've packed this varying. + unsigned int registerColumn; + + // Assigned after packing + unsigned int semanticIndex; + + // Struct member this varying corresponds to. + std::string structFieldName; +}; + +// Supported packing modes: +enum class PackMode +{ + // We treat mat2 arrays as taking two full rows. + WEBGL_STRICT, + + // We allow mat2 to take a 2x2 chunk. + ANGLE_RELAXED, +}; + +class VaryingPacking final : angle::NonCopyable +{ + public: + VaryingPacking(GLuint maxVaryingVectors, PackMode packMode); + ~VaryingPacking(); + + bool packUserVaryings(gl::InfoLog &infoLog, + const std::vector &packedVaryings, + const std::vector &tfVaryings); + + bool collectAndPackUserVaryings(gl::InfoLog &infoLog, + const Program::MergedVaryings &mergedVaryings, + const std::vector &tfVaryings); + + struct Register + { + Register() { data[0] = data[1] = data[2] = data[3] = false; } + + bool &operator[](unsigned int index) { return data[index]; } + bool operator[](unsigned int index) const { return data[index]; } + + bool data[4]; + }; + + Register &operator[](unsigned int index) { return mRegisterMap[index]; } + const Register &operator[](unsigned int index) const { return mRegisterMap[index]; } + + const std::vector &getRegisterList() const { return mRegisterList; } + unsigned int getMaxSemanticIndex() const + { + return static_cast(mRegisterList.size()); + } + unsigned int getRegisterCount() const; + size_t getRegisterMapSize() const { return mRegisterMap.size(); } + + private: + bool packVarying(const PackedVarying &packedVarying); + bool isFree(unsigned int registerRow, + unsigned int registerColumn, + unsigned int varyingRows, + unsigned int varyingColumns) const; + void insert(unsigned int registerRow, + unsigned int registerColumn, + const PackedVarying &packedVarying); + + std::vector mRegisterMap; + std::vector mRegisterList; + std::vector mPackedVaryings; + + PackMode mPackMode; +}; + +} // namespace gl + +#endif // LIBANGLE_VARYINGPACKING_H_ diff --git a/src/3rdparty/angle/src/libANGLE/Version.h b/src/3rdparty/angle/src/libANGLE/Version.h index 72dfbb6b8d..7bd41846c8 100644 --- a/src/3rdparty/angle/src/libANGLE/Version.h +++ b/src/3rdparty/angle/src/libANGLE/Version.h @@ -9,23 +9,24 @@ #ifndef LIBANGLE_VERSION_H_ #define LIBANGLE_VERSION_H_ -#include - namespace gl { struct Version { - Version(); - Version(GLuint major, GLuint minor); + constexpr Version(); + constexpr Version(unsigned int major, unsigned int minor); - GLuint major; - GLuint minor; + unsigned int major; + unsigned int minor; }; +bool operator==(const Version &a, const Version &b); +bool operator!=(const Version &a, const Version &b); bool operator>=(const Version &a, const Version &b); +bool operator<=(const Version &a, const Version &b); bool operator<(const Version &a, const Version &b); - +bool operator>(const Version &a, const Version &b); } #include "Version.inl" diff --git a/src/3rdparty/angle/src/libANGLE/Version.inl b/src/3rdparty/angle/src/libANGLE/Version.inl index f64f7cae77..c98054829e 100644 --- a/src/3rdparty/angle/src/libANGLE/Version.inl +++ b/src/3rdparty/angle/src/libANGLE/Version.inl @@ -6,28 +6,54 @@ // Version.inl: Encapsulation of a GL version. +#include + namespace gl { -inline Version::Version() +constexpr Version::Version() : Version(0, 0) { } -inline Version::Version(GLuint major_, GLuint minor_) +// Avoid conflicts with linux system defines +#undef major +#undef minor + +constexpr Version::Version(unsigned int major_, unsigned int minor_) + : major(major_), + minor(minor_) { - major = major_; - minor = minor_; +} + +inline bool operator==(const Version &a, const Version &b) +{ + return std::tie(a.major, a.minor) == std::tie(b.major, b.minor); +} + +inline bool operator!=(const Version &a, const Version &b) +{ + return std::tie(a.major, a.minor) != std::tie(b.major, b.minor); } inline bool operator>=(const Version &a, const Version &b) { - return a.major > b.major || (a.major == b.major && a.minor >= b.minor); + return std::tie(a.major, a.minor) >= std::tie(b.major, b.minor); +} + +inline bool operator<=(const Version &a, const Version &b) +{ + return std::tie(a.major, a.minor) <= std::tie(b.major, b.minor); } inline bool operator<(const Version &a, const Version &b) { - return !(a >= b); + return std::tie(a.major, a.minor) < std::tie(b.major, b.minor); } +inline bool operator>(const Version &a, const Version &b) +{ + return std::tie(a.major, a.minor) > std::tie(b.major, b.minor); } + +} // namespace gl diff --git a/src/3rdparty/angle/src/libANGLE/VertexArray.cpp b/src/3rdparty/angle/src/libANGLE/VertexArray.cpp index 8d51e9b469..a8c2fce155 100644 --- a/src/3rdparty/angle/src/libANGLE/VertexArray.cpp +++ b/src/3rdparty/angle/src/libANGLE/VertexArray.cpp @@ -8,36 +8,53 @@ #include "libANGLE/VertexArray.h" #include "libANGLE/Buffer.h" -#include "libANGLE/renderer/ImplFactory.h" +#include "libANGLE/Context.h" +#include "libANGLE/renderer/GLImplFactory.h" #include "libANGLE/renderer/VertexArrayImpl.h" namespace gl { -VertexArray::Data::Data(size_t maxAttribs) - : mLabel(), mVertexAttributes(maxAttribs), mMaxEnabledAttribute(0) +VertexArrayState::VertexArrayState(size_t maxAttribs, size_t maxAttribBindings) + : mLabel(), mVertexBindings(maxAttribBindings), mMaxEnabledAttribute(0) { -} + ASSERT(maxAttribs <= maxAttribBindings); -VertexArray::Data::~Data() -{ - for (size_t i = 0; i < getMaxAttribs(); i++) + for (size_t i = 0; i < maxAttribs; i++) { - mVertexAttributes[i].buffer.set(nullptr); + mVertexAttributes.emplace_back(static_cast(i)); } - mElementArrayBuffer.set(nullptr); } -VertexArray::VertexArray(rx::ImplFactory *factory, GLuint id, size_t maxAttribs) +VertexArrayState::~VertexArrayState() +{ +} + +VertexArray::VertexArray(rx::GLImplFactory *factory, + GLuint id, + size_t maxAttribs, + size_t maxAttribBindings) : mId(id), - mVertexArray(factory->createVertexArray(mData)), - mData(maxAttribs) + mState(maxAttribs, maxAttribBindings), + mVertexArray(factory->createVertexArray(mState)) { } -VertexArray::~VertexArray() +void VertexArray::onDestroy(const Context *context) { + for (auto &binding : mState.mVertexBindings) + { + binding.setBuffer(context, nullptr); + } + mState.mElementArrayBuffer.set(context, nullptr); + mVertexArray->destroy(context); SafeDelete(mVertexArray); + delete this; +} + +VertexArray::~VertexArray() +{ + ASSERT(!mVertexArray); } GLuint VertexArray::id() const @@ -47,94 +64,204 @@ GLuint VertexArray::id() const void VertexArray::setLabel(const std::string &label) { - mData.mLabel = label; + mState.mLabel = label; } const std::string &VertexArray::getLabel() const { - return mData.mLabel; + return mState.mLabel; } -void VertexArray::detachBuffer(GLuint bufferName) +void VertexArray::detachBuffer(const Context *context, GLuint bufferName) { - for (size_t attribute = 0; attribute < getMaxAttribs(); attribute++) + for (auto &binding : mState.mVertexBindings) { - if (mData.mVertexAttributes[attribute].buffer.id() == bufferName) + if (binding.getBuffer().id() == bufferName) { - mData.mVertexAttributes[attribute].buffer.set(nullptr); + binding.setBuffer(context, nullptr); } } - if (mData.mElementArrayBuffer.id() == bufferName) + if (mState.mElementArrayBuffer.id() == bufferName) + { + mState.mElementArrayBuffer.set(context, nullptr); + } +} + +const VertexAttribute &VertexArray::getVertexAttribute(size_t attribIndex) const +{ + ASSERT(attribIndex < getMaxAttribs()); + return mState.mVertexAttributes[attribIndex]; +} + +const VertexBinding &VertexArray::getVertexBinding(size_t bindingIndex) const +{ + ASSERT(bindingIndex < getMaxBindings()); + return mState.mVertexBindings[bindingIndex]; +} + +size_t VertexArray::GetVertexIndexFromDirtyBit(size_t dirtyBit) +{ + static_assert(gl::MAX_VERTEX_ATTRIBS == gl::MAX_VERTEX_ATTRIB_BINDINGS, + "The stride of vertex attributes should equal to that of vertex bindings."); + ASSERT(dirtyBit > DIRTY_BIT_ELEMENT_ARRAY_BUFFER); + return (dirtyBit - DIRTY_BIT_ATTRIB_0_ENABLED) % gl::MAX_VERTEX_ATTRIBS; +} + +void VertexArray::bindVertexBufferImpl(const Context *context, + size_t bindingIndex, + Buffer *boundBuffer, + GLintptr offset, + GLsizei stride) +{ + ASSERT(bindingIndex < getMaxBindings()); + + VertexBinding *binding = &mState.mVertexBindings[bindingIndex]; + + binding->setBuffer(context, boundBuffer); + binding->setOffset(offset); + binding->setStride(stride); +} + +void VertexArray::bindVertexBuffer(const Context *context, + size_t bindingIndex, + Buffer *boundBuffer, + GLintptr offset, + GLsizei stride) +{ + bindVertexBufferImpl(context, bindingIndex, boundBuffer, offset, stride); + + mDirtyBits.set(DIRTY_BIT_BINDING_0_BUFFER + bindingIndex); +} + +void VertexArray::setVertexAttribBinding(const Context *context, + size_t attribIndex, + GLuint bindingIndex) +{ + ASSERT(attribIndex < getMaxAttribs() && bindingIndex < getMaxBindings()); + + if (mState.mVertexAttributes[attribIndex].bindingIndex != bindingIndex) { - mData.mElementArrayBuffer.set(nullptr); + // In ES 3.0 contexts, the binding cannot change, hence the code below is unreachable. + ASSERT(context->getClientVersion() >= ES_3_1); + mState.mVertexAttributes[attribIndex].bindingIndex = bindingIndex; + + mDirtyBits.set(DIRTY_BIT_ATTRIB_0_BINDING + attribIndex); } } -const VertexAttribute &VertexArray::getVertexAttribute(size_t attributeIndex) const +void VertexArray::setVertexBindingDivisor(size_t bindingIndex, GLuint divisor) +{ + ASSERT(bindingIndex < getMaxBindings()); + + mState.mVertexBindings[bindingIndex].setDivisor(divisor); + + mDirtyBits.set(DIRTY_BIT_BINDING_0_DIVISOR + bindingIndex); +} + +void VertexArray::setVertexAttribFormatImpl(size_t attribIndex, + GLint size, + GLenum type, + bool normalized, + bool pureInteger, + GLuint relativeOffset) { - ASSERT(attributeIndex < getMaxAttribs()); - return mData.mVertexAttributes[attributeIndex]; + ASSERT(attribIndex < getMaxAttribs()); + + VertexAttribute *attrib = &mState.mVertexAttributes[attribIndex]; + + attrib->size = size; + attrib->type = type; + attrib->normalized = normalized; + attrib->pureInteger = pureInteger; + attrib->relativeOffset = relativeOffset; } -void VertexArray::setVertexAttribDivisor(size_t index, GLuint divisor) +void VertexArray::setVertexAttribFormat(size_t attribIndex, + GLint size, + GLenum type, + bool normalized, + bool pureInteger, + GLuint relativeOffset) { - ASSERT(index < getMaxAttribs()); - mData.mVertexAttributes[index].divisor = divisor; - mDirtyBits.set(DIRTY_BIT_ATTRIB_0_DIVISOR + index); + setVertexAttribFormatImpl(attribIndex, size, type, normalized, pureInteger, relativeOffset); + + mDirtyBits.set(DIRTY_BIT_ATTRIB_0_FORMAT + attribIndex); +} + +void VertexArray::setVertexAttribDivisor(const Context *context, size_t attribIndex, GLuint divisor) +{ + ASSERT(attribIndex < getMaxAttribs()); + + setVertexAttribBinding(context, attribIndex, static_cast(attribIndex)); + setVertexBindingDivisor(attribIndex, divisor); } -void VertexArray::enableAttribute(size_t attributeIndex, bool enabledState) +void VertexArray::enableAttribute(size_t attribIndex, bool enabledState) { - ASSERT(attributeIndex < getMaxAttribs()); - mData.mVertexAttributes[attributeIndex].enabled = enabledState; - mDirtyBits.set(DIRTY_BIT_ATTRIB_0_ENABLED + attributeIndex); + ASSERT(attribIndex < getMaxAttribs()); + + mState.mVertexAttributes[attribIndex].enabled = enabledState; + + mDirtyBits.set(DIRTY_BIT_ATTRIB_0_ENABLED + attribIndex); // Update state cache if (enabledState) { - mData.mMaxEnabledAttribute = std::max(attributeIndex + 1, mData.mMaxEnabledAttribute); + mState.mMaxEnabledAttribute = std::max(attribIndex + 1, mState.mMaxEnabledAttribute); } - else if (mData.mMaxEnabledAttribute == attributeIndex + 1) + else if (mState.mMaxEnabledAttribute == attribIndex + 1) { - while (mData.mMaxEnabledAttribute > 0 && - !mData.mVertexAttributes[mData.mMaxEnabledAttribute - 1].enabled) + while (mState.mMaxEnabledAttribute > 0 && + !mState.mVertexAttributes[mState.mMaxEnabledAttribute - 1].enabled) { - --mData.mMaxEnabledAttribute; + --mState.mMaxEnabledAttribute; } } } -void VertexArray::setAttributeState(size_t attributeIndex, gl::Buffer *boundBuffer, GLint size, GLenum type, - bool normalized, bool pureInteger, GLsizei stride, const void *pointer) +void VertexArray::setVertexAttribPointer(const Context *context, + size_t attribIndex, + gl::Buffer *boundBuffer, + GLint size, + GLenum type, + bool normalized, + bool pureInteger, + GLsizei stride, + const void *pointer) { - ASSERT(attributeIndex < getMaxAttribs()); + ASSERT(attribIndex < getMaxAttribs()); + + GLintptr offset = boundBuffer ? reinterpret_cast(pointer) : 0; + + setVertexAttribFormatImpl(attribIndex, size, type, normalized, pureInteger, 0); + setVertexAttribBinding(context, attribIndex, static_cast(attribIndex)); - VertexAttribute *attrib = &mData.mVertexAttributes[attributeIndex]; + VertexAttribute &attrib = mState.mVertexAttributes[attribIndex]; - attrib->buffer.set(boundBuffer); - attrib->size = size; - attrib->type = type; - attrib->normalized = normalized; - attrib->pureInteger = pureInteger; - attrib->stride = stride; - attrib->pointer = pointer; - mDirtyBits.set(DIRTY_BIT_ATTRIB_0_POINTER + attributeIndex); + GLsizei effectiveStride = + stride != 0 ? stride : static_cast(ComputeVertexAttributeTypeSize(attrib)); + attrib.pointer = pointer; + attrib.vertexAttribArrayStride = stride; + + bindVertexBufferImpl(context, attribIndex, boundBuffer, offset, effectiveStride); + + mDirtyBits.set(DIRTY_BIT_ATTRIB_0_POINTER + attribIndex); } -void VertexArray::setElementArrayBuffer(Buffer *buffer) +void VertexArray::setElementArrayBuffer(const Context *context, Buffer *buffer) { - mData.mElementArrayBuffer.set(buffer); + mState.mElementArrayBuffer.set(context, buffer); mDirtyBits.set(DIRTY_BIT_ELEMENT_ARRAY_BUFFER); } -void VertexArray::syncImplState() +void VertexArray::syncState(const Context *context) { if (mDirtyBits.any()) { - mVertexArray->syncState(mDirtyBits); + mVertexArray->syncState(context, mDirtyBits); mDirtyBits.reset(); } } -} +} // namespace gl diff --git a/src/3rdparty/angle/src/libANGLE/VertexArray.h b/src/3rdparty/angle/src/libANGLE/VertexArray.h index 6bc267d399..f82ec789f0 100644 --- a/src/3rdparty/angle/src/libANGLE/VertexArray.h +++ b/src/3rdparty/angle/src/libANGLE/VertexArray.h @@ -23,68 +23,131 @@ namespace rx { -class ImplFactory; +class GLImplFactory; class VertexArrayImpl; -} +} // namespace rx namespace gl { class Buffer; -class VertexArray final : public LabeledObject +class VertexArrayState final : angle::NonCopyable { public: - VertexArray(rx::ImplFactory *factory, GLuint id, size_t maxAttribs); - ~VertexArray(); + VertexArrayState(size_t maxAttribs, size_t maxBindings); + ~VertexArrayState(); - GLuint id() const; + const std::string &getLabel() const { return mLabel; } - void setLabel(const std::string &label) override; - const std::string &getLabel() const override; + const BindingPointer &getElementArrayBuffer() const { return mElementArrayBuffer; } + size_t getMaxAttribs() const { return mVertexAttributes.size(); } + size_t getMaxBindings() const { return mVertexBindings.size(); } + size_t getMaxEnabledAttribute() const { return mMaxEnabledAttribute; } + const std::vector &getVertexAttributes() const { return mVertexAttributes; } + const VertexAttribute &getVertexAttribute(size_t attribIndex) const + { + return mVertexAttributes[attribIndex]; + } + const std::vector &getVertexBindings() const { return mVertexBindings; } + const VertexBinding &getVertexBinding(size_t bindingIndex) const + { + return mVertexBindings[bindingIndex]; + } + const VertexBinding &getBindingFromAttribIndex(size_t attribIndex) const + { + return mVertexBindings[mVertexAttributes[attribIndex].bindingIndex]; + } + size_t getBindingIndexFromAttribIndex(size_t attribIndex) const + { + return mVertexAttributes[attribIndex].bindingIndex; + } - const VertexAttribute &getVertexAttribute(size_t attributeIndex) const; + private: + friend class VertexArray; + std::string mLabel; + std::vector mVertexAttributes; + BindingPointer mElementArrayBuffer; + std::vector mVertexBindings; + size_t mMaxEnabledAttribute; +}; - void detachBuffer(GLuint bufferName); - void setVertexAttribDivisor(size_t index, GLuint divisor); - void enableAttribute(size_t attributeIndex, bool enabledState); - void setAttributeState(size_t attributeIndex, gl::Buffer *boundBuffer, GLint size, GLenum type, - bool normalized, bool pureInteger, GLsizei stride, const void *pointer); +class VertexArray final : public LabeledObject +{ + public: + VertexArray(rx::GLImplFactory *factory, GLuint id, size_t maxAttribs, size_t maxAttribBindings); - void setElementArrayBuffer(Buffer *buffer); + void onDestroy(const Context *context); - const BindingPointer &getElementArrayBuffer() const { return mData.getElementArrayBuffer(); } - size_t getMaxAttribs() const { return mData.getVertexAttributes().size(); } - const std::vector &getVertexAttributes() const { return mData.getVertexAttributes(); } + GLuint id() const; - rx::VertexArrayImpl *getImplementation() { return mVertexArray; } - const rx::VertexArrayImpl *getImplementation() const { return mVertexArray; } + void setLabel(const std::string &label) override; + const std::string &getLabel() const override; - size_t getMaxEnabledAttribute() const { return mData.getMaxEnabledAttribute(); } + const VertexBinding &getVertexBinding(size_t bindingIndex) const; + const VertexAttribute &getVertexAttribute(size_t attribIndex) const; + const VertexBinding &getBindingFromAttribIndex(size_t attribIndex) const + { + return mState.getBindingFromAttribIndex(attribIndex); + } + + void detachBuffer(const Context *context, GLuint bufferName); + void setVertexAttribDivisor(const Context *context, size_t index, GLuint divisor); + void enableAttribute(size_t attribIndex, bool enabledState); + void setVertexAttribPointer(const Context *context, + size_t attribIndex, + Buffer *boundBuffer, + GLint size, + GLenum type, + bool normalized, + bool pureInteger, + GLsizei stride, + const void *pointer); + void setVertexAttribFormat(size_t attribIndex, + GLint size, + GLenum type, + bool normalized, + bool pureInteger, + GLuint relativeOffset); + void bindVertexBuffer(const Context *context, + size_t bindingIndex, + Buffer *boundBuffer, + GLintptr offset, + GLsizei stride); + void setVertexAttribBinding(const Context *context, size_t attribIndex, GLuint bindingIndex); + void setVertexBindingDivisor(size_t bindingIndex, GLuint divisor); + void setVertexAttribFormatImpl(size_t attribIndex, + GLint size, + GLenum type, + bool normalized, + bool pureInteger, + GLuint relativeOffset); + void bindVertexBufferImpl(const Context *context, + size_t bindingIndex, + Buffer *boundBuffer, + GLintptr offset, + GLsizei stride); + + void setElementArrayBuffer(const Context *context, Buffer *buffer); + + const BindingPointer &getElementArrayBuffer() const + { + return mState.getElementArrayBuffer(); + } + size_t getMaxAttribs() const { return mState.getMaxAttribs(); } + size_t getMaxBindings() const { return mState.getMaxBindings(); } - class Data final : public angle::NonCopyable + const std::vector &getVertexAttributes() const { - public: - explicit Data(size_t maxAttribs); - ~Data(); - - const std::string &getLabel() const { return mLabel; } - - const BindingPointer &getElementArrayBuffer() const { return mElementArrayBuffer; } - size_t getMaxAttribs() const { return mVertexAttributes.size(); } - size_t getMaxEnabledAttribute() const { return mMaxEnabledAttribute; } - const std::vector &getVertexAttributes() const { return mVertexAttributes; } - const VertexAttribute &getVertexAttribute(size_t index) const - { - return mVertexAttributes[index]; - } - - private: - friend class VertexArray; - std::string mLabel; - std::vector mVertexAttributes; - BindingPointer mElementArrayBuffer; - size_t mMaxEnabledAttribute; - }; + return mState.getVertexAttributes(); + } + const std::vector &getVertexBindings() const + { + return mState.getVertexBindings(); + } + + rx::VertexArrayImpl *getImplementation() const { return mVertexArray; } + + size_t getMaxEnabledAttribute() const { return mState.getMaxEnabledAttribute(); } enum DirtyBitType { @@ -98,28 +161,45 @@ class VertexArray final : public LabeledObject DIRTY_BIT_ATTRIB_0_POINTER = DIRTY_BIT_ATTRIB_MAX_ENABLED, DIRTY_BIT_ATTRIB_MAX_POINTER = DIRTY_BIT_ATTRIB_0_POINTER + gl::MAX_VERTEX_ATTRIBS, - // Reserve bits for divisors - DIRTY_BIT_ATTRIB_0_DIVISOR = DIRTY_BIT_ATTRIB_MAX_POINTER, - DIRTY_BIT_ATTRIB_MAX_DIVISOR = DIRTY_BIT_ATTRIB_0_DIVISOR + gl::MAX_VERTEX_ATTRIBS, + // Reserve bits for changes to VertexAttribFormat + DIRTY_BIT_ATTRIB_0_FORMAT = DIRTY_BIT_ATTRIB_MAX_POINTER, + DIRTY_BIT_ATTRIB_MAX_FORMAT = DIRTY_BIT_ATTRIB_0_FORMAT + gl::MAX_VERTEX_ATTRIBS, + + // Reserve bits for changes to VertexAttribBinding + DIRTY_BIT_ATTRIB_0_BINDING = DIRTY_BIT_ATTRIB_MAX_FORMAT, + DIRTY_BIT_ATTRIB_MAX_BINDING = DIRTY_BIT_ATTRIB_0_BINDING + gl::MAX_VERTEX_ATTRIBS, + + // Reserve bits for changes to BindVertexBuffer + DIRTY_BIT_BINDING_0_BUFFER = DIRTY_BIT_ATTRIB_MAX_BINDING, + DIRTY_BIT_BINDING_MAX_BUFFER = DIRTY_BIT_BINDING_0_BUFFER + gl::MAX_VERTEX_ATTRIB_BINDINGS, - DIRTY_BIT_UNKNOWN = DIRTY_BIT_ATTRIB_MAX_DIVISOR, + // Reserve bits for binding divisors + DIRTY_BIT_BINDING_0_DIVISOR = DIRTY_BIT_BINDING_MAX_BUFFER, + DIRTY_BIT_BINDING_MAX_DIVISOR = + DIRTY_BIT_BINDING_0_DIVISOR + gl::MAX_VERTEX_ATTRIB_BINDINGS, + + DIRTY_BIT_UNKNOWN = DIRTY_BIT_BINDING_MAX_DIVISOR, DIRTY_BIT_MAX = DIRTY_BIT_UNKNOWN, }; - typedef std::bitset DirtyBits; + using DirtyBits = angle::BitSet; + + static size_t GetVertexIndexFromDirtyBit(size_t dirtyBit); - void syncImplState(); + void syncState(const Context *context); bool hasAnyDirtyBit() const { return mDirtyBits.any(); } private: - GLuint mId; + ~VertexArray() override; - rx::VertexArrayImpl *mVertexArray; + GLuint mId; - Data mData; + VertexArrayState mState; DirtyBits mDirtyBits; + + rx::VertexArrayImpl *mVertexArray; }; -} +} // namespace gl #endif // LIBANGLE_VERTEXARRAY_H_ diff --git a/src/3rdparty/angle/src/libANGLE/VertexAttribute.cpp b/src/3rdparty/angle/src/libANGLE/VertexAttribute.cpp index 13d78fd13c..20f7452fa5 100644 --- a/src/3rdparty/angle/src/libANGLE/VertexAttribute.cpp +++ b/src/3rdparty/angle/src/libANGLE/VertexAttribute.cpp @@ -3,7 +3,7 @@ // 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. +// Implementation of the state classes for mananging GLES 3.1 Vertex Array Objects. // #include "libANGLE/VertexAttribute.h" @@ -11,16 +11,74 @@ namespace gl { -VertexAttribute::VertexAttribute() +// [OpenGL ES 3.1] (November 3, 2016) Section 20 Page 361 +// Table 20.2: Vertex Array Object State +VertexBinding::VertexBinding() : mStride(16u), mDivisor(0), mOffset(0) +{ +} + +VertexBinding::VertexBinding(VertexBinding &&binding) +{ + *this = std::move(binding); +} + +VertexBinding::~VertexBinding() +{ +} + +VertexBinding &VertexBinding::operator=(VertexBinding &&binding) +{ + if (this != &binding) + { + mStride = binding.mStride; + mDivisor = binding.mDivisor; + mOffset = binding.mOffset; + std::swap(binding.mBuffer, mBuffer); + } + return *this; +} + +VertexAttribute::VertexAttribute(GLuint bindingIndex) : enabled(false), type(GL_FLOAT), - size(4), + size(4u), normalized(false), pureInteger(false), - stride(0), - pointer(NULL), - divisor(0) + pointer(nullptr), + relativeOffset(0), + vertexAttribArrayStride(0), + bindingIndex(bindingIndex) +{ +} + +VertexAttribute::VertexAttribute(VertexAttribute &&attrib) + : enabled(attrib.enabled), + type(attrib.type), + size(attrib.size), + normalized(attrib.normalized), + pureInteger(attrib.pureInteger), + pointer(attrib.pointer), + relativeOffset(attrib.relativeOffset), + vertexAttribArrayStride(attrib.vertexAttribArrayStride), + bindingIndex(attrib.bindingIndex) +{ +} + +VertexAttribute &VertexAttribute::operator=(VertexAttribute &&attrib) { + if (this != &attrib) + { + enabled = attrib.enabled; + type = attrib.type; + size = attrib.size; + normalized = attrib.normalized; + pureInteger = attrib.pureInteger; + pointer = attrib.pointer; + relativeOffset = attrib.relativeOffset; + vertexAttribArrayStride = attrib.vertexAttribArrayStride; + bindingIndex = attrib.bindingIndex; + } + return *this; } size_t ComputeVertexAttributeTypeSize(const VertexAttribute& attrib) @@ -43,32 +101,62 @@ size_t ComputeVertexAttributeTypeSize(const VertexAttribute& attrib) } } -size_t ComputeVertexAttributeStride(const VertexAttribute& attrib) +size_t ComputeVertexAttributeStride(const VertexAttribute &attrib, const VertexBinding &binding) { - if (!attrib.enabled) - { - return 16; - } - return attrib.stride ? attrib.stride : ComputeVertexAttributeTypeSize(attrib); + // In ES 3.1, VertexAttribPointer will store the type size in the binding stride. + // Hence, rendering always uses the binding's stride. + return attrib.enabled ? binding.getStride() : 16u; +} + +// Warning: you should ensure binding really matches attrib.bindingIndex before using this function. +GLintptr ComputeVertexAttributeOffset(const VertexAttribute &attrib, const VertexBinding &binding) +{ + return attrib.relativeOffset + binding.getOffset(); } -size_t ComputeVertexAttributeElementCount(const VertexAttribute &attrib, - size_t drawCount, - size_t instanceCount) +size_t ComputeVertexBindingElementCount(GLuint divisor, size_t drawCount, size_t instanceCount) { // 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 (instanceCount > 0 && attrib.divisor > 0) + if (instanceCount > 0 && 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 (instanceCount + attrib.divisor - 1u) / attrib.divisor; + return (instanceCount + divisor - 1u) / divisor; } return drawCount; } + +GLenum GetVertexAttributeBaseType(const VertexAttribute &attrib) +{ + if (attrib.pureInteger) + { + switch (attrib.type) + { + case GL_BYTE: + case GL_SHORT: + case GL_INT: + return GL_INT; + + case GL_UNSIGNED_BYTE: + case GL_UNSIGNED_SHORT: + case GL_UNSIGNED_INT: + return GL_UNSIGNED_INT; + + default: + UNREACHABLE(); + return GL_NONE; + } + } + else + { + return GL_FLOAT; + } } + +} // namespace gl diff --git a/src/3rdparty/angle/src/libANGLE/VertexAttribute.h b/src/3rdparty/angle/src/libANGLE/VertexAttribute.h index d1ee1b47a2..c531bece7c 100644 --- a/src/3rdparty/angle/src/libANGLE/VertexAttribute.h +++ b/src/3rdparty/angle/src/libANGLE/VertexAttribute.h @@ -3,7 +3,7 @@ // 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 +// Helper structures about Generic Vertex Attribute. // #ifndef LIBANGLE_VERTEXATTRIBUTE_H_ @@ -13,45 +13,77 @@ namespace gl { +class VertexArray; -struct VertexAttribute +// +// Implementation of Generic Vertex Attribute Bindings for ES3.1. The members are intentionally made +// private in order to hide implementation details. +// +class VertexBinding final : angle::NonCopyable { - bool enabled; // From glEnable/DisableVertexAttribArray + public: + VertexBinding(); + VertexBinding(VertexBinding &&binding); + ~VertexBinding(); + VertexBinding &operator=(VertexBinding &&binding); + + GLuint getStride() const { return mStride; } + void setStride(GLuint strideIn) { mStride = strideIn; } + + GLuint getDivisor() const { return mDivisor; } + void setDivisor(GLuint divisorIn) { mDivisor = divisorIn; } + + GLintptr getOffset() const { return mOffset; } + void setOffset(GLintptr offsetIn) { mOffset = offsetIn; } + + const BindingPointer &getBuffer() const { return mBuffer; } + void setBuffer(const gl::Context *context, Buffer *bufferIn) { mBuffer.set(context, bufferIn); } + + private: + GLuint mStride; + GLuint mDivisor; + GLintptr mOffset; + + BindingPointer mBuffer; +}; +// +// Implementation of Generic Vertex Attributes for ES3.1 +// +struct VertexAttribute final : private angle::NonCopyable +{ + explicit VertexAttribute(GLuint bindingIndex); + explicit VertexAttribute(VertexAttribute &&attrib); + VertexAttribute &operator=(VertexAttribute &&attrib); + + bool enabled; // For 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; + const void *pointer; + GLuint relativeOffset; - VertexAttribute(); + GLuint vertexAttribArrayStride; // ONLY for queries of VERTEX_ATTRIB_ARRAY_STRIDE + GLuint bindingIndex; }; -bool operator==(const VertexAttribute &a, const VertexAttribute &b); -bool operator!=(const VertexAttribute &a, const VertexAttribute &b); +size_t ComputeVertexAttributeTypeSize(const VertexAttribute &attrib); + +// Warning: you should ensure binding really matches attrib.bindingIndex before using this function. +size_t ComputeVertexAttributeStride(const VertexAttribute &attrib, const VertexBinding &binding); + +// Warning: you should ensure binding really matches attrib.bindingIndex before using this function. +GLintptr ComputeVertexAttributeOffset(const VertexAttribute &attrib, const VertexBinding &binding); -template -T QuerySingleVertexAttributeParameter(const VertexAttribute& attrib, GLenum pname); +size_t ComputeVertexBindingElementCount(GLuint divisor, size_t drawCount, size_t instanceCount); -size_t ComputeVertexAttributeTypeSize(const VertexAttribute& attrib); -size_t ComputeVertexAttributeStride(const VertexAttribute& attrib); -size_t ComputeVertexAttributeElementCount(const VertexAttribute &attrib, - size_t drawCount, - size_t instanceCount); +GLenum GetVertexAttributeBaseType(const VertexAttribute &attrib); struct VertexAttribCurrentValueData { - union - { + union { GLfloat FloatValues[4]; GLint IntValues[4]; GLuint UnsignedIntValues[4]; @@ -68,8 +100,8 @@ struct VertexAttribCurrentValueData bool operator==(const VertexAttribCurrentValueData &a, const VertexAttribCurrentValueData &b); bool operator!=(const VertexAttribCurrentValueData &a, const VertexAttribCurrentValueData &b); -} +} // namespace gl #include "VertexAttribute.inl" -#endif // LIBANGLE_VERTEXATTRIBUTE_H_ +#endif // LIBANGLE_VERTEXATTRIBUTE_H_ diff --git a/src/3rdparty/angle/src/libANGLE/VertexAttribute.inl b/src/3rdparty/angle/src/libANGLE/VertexAttribute.inl index 0cd31f6762..1c1843e46f 100644 --- a/src/3rdparty/angle/src/libANGLE/VertexAttribute.inl +++ b/src/3rdparty/angle/src/libANGLE/VertexAttribute.inl @@ -9,51 +9,6 @@ namespace gl { -inline 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; -} - -inline bool operator!=(const VertexAttribute &a, const VertexAttribute &b) -{ - return !(a == 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); - } -} - inline VertexAttribCurrentValueData::VertexAttribCurrentValueData() : Type(GL_FLOAT) { @@ -100,4 +55,4 @@ inline bool operator!=(const VertexAttribCurrentValueData &a, const VertexAttrib return !(a == b); } -} +} // namespace gl diff --git a/src/3rdparty/angle/src/libANGLE/Workarounds.h b/src/3rdparty/angle/src/libANGLE/Workarounds.h new file mode 100644 index 0000000000..898031d78d --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/Workarounds.h @@ -0,0 +1,29 @@ +// +// Copyright (c) 2016 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. +// + +// Workarounds.h: Workarounds for driver bugs and other behaviors seen +// on all platforms. + +#ifndef LIBANGLE_WORKAROUNDS_H_ +#define LIBANGLE_WORKAROUNDS_H_ + +namespace gl +{ + +struct Workarounds +{ + // Force the context to be lost (via KHR_robustness) if a GL_OUT_OF_MEMORY error occurs. The + // driver may be in an inconsistent state if this happens, and some users of ANGLE rely on this + // notification to prevent further execution. + bool loseContextOnOutOfMemory = false; + + // Program binaries don't contain transform feedback varyings on Qualcomm GPUs. + // Work around this by disabling the program cache for programs with transform feedback. + bool disableProgramCachingForTransformFeedback = false; +}; +} // namespace gl + +#endif // LIBANGLE_WORKAROUNDS_H_ diff --git a/src/3rdparty/angle/src/libANGLE/WorkerThread.cpp b/src/3rdparty/angle/src/libANGLE/WorkerThread.cpp new file mode 100644 index 0000000000..b5d789ef93 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/WorkerThread.cpp @@ -0,0 +1,157 @@ +// +// Copyright 2016 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. +// +// WorkerThread: +// Task running thread for ANGLE, similar to a TaskRunner in Chromium. +// Might be implemented differently depending on platform. +// + +#include "libANGLE/WorkerThread.h" + +namespace angle +{ + +namespace priv +{ +// SingleThreadedWorkerPool implementation. +SingleThreadedWorkerPool::SingleThreadedWorkerPool(size_t maxThreads) + : WorkerThreadPoolBase(maxThreads) +{ +} + +SingleThreadedWorkerPool::~SingleThreadedWorkerPool() +{ +} + +SingleThreadedWaitableEvent SingleThreadedWorkerPool::postWorkerTaskImpl(Closure *task) +{ + (*task)(); + return SingleThreadedWaitableEvent(EventResetPolicy::Automatic, EventInitialState::Signaled); +} + +// SingleThreadedWaitableEvent implementation. +SingleThreadedWaitableEvent::SingleThreadedWaitableEvent() + : SingleThreadedWaitableEvent(EventResetPolicy::Automatic, EventInitialState::NonSignaled) +{ +} + +SingleThreadedWaitableEvent::SingleThreadedWaitableEvent(EventResetPolicy resetPolicy, + EventInitialState initialState) + : WaitableEventBase(resetPolicy, initialState) +{ +} + +SingleThreadedWaitableEvent::~SingleThreadedWaitableEvent() +{ +} + +SingleThreadedWaitableEvent::SingleThreadedWaitableEvent(SingleThreadedWaitableEvent &&other) + : WaitableEventBase(std::move(other)) +{ +} + +SingleThreadedWaitableEvent &SingleThreadedWaitableEvent::operator=( + SingleThreadedWaitableEvent &&other) +{ + return copyBase(std::move(other)); +} + +void SingleThreadedWaitableEvent::resetImpl() +{ + mSignaled = false; +} + +void SingleThreadedWaitableEvent::waitImpl() +{ +} + +void SingleThreadedWaitableEvent::signalImpl() +{ + mSignaled = true; +} + +#if (ANGLE_STD_ASYNC_WORKERS == ANGLE_ENABLED) +// AsyncWorkerPool implementation. +AsyncWorkerPool::AsyncWorkerPool(size_t maxThreads) : WorkerThreadPoolBase(maxThreads) +{ +} + +AsyncWorkerPool::~AsyncWorkerPool() +{ +} + +AsyncWaitableEvent AsyncWorkerPool::postWorkerTaskImpl(Closure *task) +{ + auto future = std::async(std::launch::async, [task] { (*task)(); }); + + AsyncWaitableEvent waitable(EventResetPolicy::Automatic, EventInitialState::NonSignaled); + + waitable.setFuture(std::move(future)); + + return waitable; +} + +// AsyncWaitableEvent implementation. +AsyncWaitableEvent::AsyncWaitableEvent() + : AsyncWaitableEvent(EventResetPolicy::Automatic, EventInitialState::NonSignaled) +{ +} + +AsyncWaitableEvent::AsyncWaitableEvent(EventResetPolicy resetPolicy, EventInitialState initialState) + : WaitableEventBase(resetPolicy, initialState) +{ +} + +AsyncWaitableEvent::~AsyncWaitableEvent() +{ +} + +AsyncWaitableEvent::AsyncWaitableEvent(AsyncWaitableEvent &&other) + : WaitableEventBase(std::move(other)), mFuture(std::move(other.mFuture)) +{ +} + +AsyncWaitableEvent &AsyncWaitableEvent::operator=(AsyncWaitableEvent &&other) +{ + std::swap(mFuture, other.mFuture); + return copyBase(std::move(other)); +} + +void AsyncWaitableEvent::setFuture(std::future &&future) +{ + mFuture = std::move(future); +} + +void AsyncWaitableEvent::resetImpl() +{ + mSignaled = false; + mFuture = std::future(); +} + +void AsyncWaitableEvent::waitImpl() +{ + if (mSignaled || !mFuture.valid()) + { + return; + } + + mFuture.wait(); + signal(); +} + +void AsyncWaitableEvent::signalImpl() +{ + mSignaled = true; + + if (mResetPolicy == EventResetPolicy::Automatic) + { + reset(); + } +} +#endif // (ANGLE_STD_ASYNC_WORKERS == ANGLE_ENABLED) + +} // namespace priv + +} // namespace angle diff --git a/src/3rdparty/angle/src/libANGLE/WorkerThread.h b/src/3rdparty/angle/src/libANGLE/WorkerThread.h new file mode 100644 index 0000000000..f6b81dce21 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/WorkerThread.h @@ -0,0 +1,284 @@ +// +// Copyright 2016 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. +// +// WorkerThread: +// Asychronous tasks/threads for ANGLE, similar to a TaskRunner in Chromium. +// Can be implemented as different targets, depending on platform. +// + +#ifndef LIBANGLE_WORKER_THREAD_H_ +#define LIBANGLE_WORKER_THREAD_H_ + +#include +#include + +#include "common/debug.h" +#include "libANGLE/features.h" + +#if (ANGLE_STD_ASYNC_WORKERS == ANGLE_ENABLED) +#include +#endif // (ANGLE_STD_ASYNC_WORKERS == ANGLE_ENABLED) + +namespace angle +{ +// Indicates whether a WaitableEvent should automatically reset the event state after a single +// waiting thread has been released or remain signaled until reset() is manually invoked. +enum class EventResetPolicy +{ + Manual, + Automatic +}; + +// Specify the initial state on creation. +enum class EventInitialState +{ + NonSignaled, + Signaled +}; + +// A callback function with no return value and no arguments. +class Closure +{ + public: + virtual ~Closure() = default; + virtual void operator()() = 0; +}; + +namespace priv +{ +// An event that we can wait on, useful for joining worker threads. +template +class WaitableEventBase : angle::NonCopyable +{ + public: + WaitableEventBase(EventResetPolicy resetPolicy, EventInitialState initialState); + + WaitableEventBase(WaitableEventBase &&other); + + // Puts the event in the un-signaled state. + void reset(); + + // Waits indefinitely for the event to be signaled. + void wait(); + + // Puts the event in the signaled state, causing any thread blocked on Wait to be woken up. + // The event state is reset to non-signaled after a waiting thread has been released. + void signal(); + + protected: + Impl ©Base(Impl &&other); + + template + static size_t WaitManyBase(std::array *waitables); + + EventResetPolicy mResetPolicy; + bool mSignaled; +}; + +template +WaitableEventBase::WaitableEventBase(EventResetPolicy resetPolicy, + EventInitialState initialState) + : mResetPolicy(resetPolicy), mSignaled(initialState == EventInitialState::Signaled) +{ +} + +template +WaitableEventBase::WaitableEventBase(WaitableEventBase &&other) + : mResetPolicy(other.mResetPolicy), mSignaled(other.mSignaled) +{ +} + +template +void WaitableEventBase::reset() +{ + static_cast(this)->resetImpl(); +} + +template +void WaitableEventBase::wait() +{ + static_cast(this)->waitImpl(); +} + +template +void WaitableEventBase::signal() +{ + static_cast(this)->signalImpl(); +} + +template +template +// static +size_t WaitableEventBase::WaitManyBase(std::array *waitables) +{ + ASSERT(Count > 0); + + for (size_t index = 0; index < Count; ++index) + { + (*waitables)[index].wait(); + } + + return 0; +} + +template +Impl &WaitableEventBase::copyBase(Impl &&other) +{ + std::swap(mSignaled, other.mSignaled); + std::swap(mResetPolicy, other.mResetPolicy); + return *static_cast(this); +} + +class SingleThreadedWaitableEvent : public WaitableEventBase +{ + public: + SingleThreadedWaitableEvent(); + SingleThreadedWaitableEvent(EventResetPolicy resetPolicy, EventInitialState initialState); + ~SingleThreadedWaitableEvent(); + + SingleThreadedWaitableEvent(SingleThreadedWaitableEvent &&other); + SingleThreadedWaitableEvent &operator=(SingleThreadedWaitableEvent &&other); + + void resetImpl(); + void waitImpl(); + void signalImpl(); + + // Wait, synchronously, on multiple events. + // returns the index of a WaitableEvent which has been signaled. + template + static size_t WaitMany(std::array *waitables); +}; + +template +// static +size_t SingleThreadedWaitableEvent::WaitMany( + std::array *waitables) +{ + return WaitableEventBase::WaitManyBase(waitables); +} + +#if (ANGLE_STD_ASYNC_WORKERS == ANGLE_ENABLED) +class AsyncWaitableEvent : public WaitableEventBase +{ + public: + AsyncWaitableEvent(); + AsyncWaitableEvent(EventResetPolicy resetPolicy, EventInitialState initialState); + ~AsyncWaitableEvent(); + + AsyncWaitableEvent(AsyncWaitableEvent &&other); + AsyncWaitableEvent &operator=(AsyncWaitableEvent &&other); + + void resetImpl(); + void waitImpl(); + void signalImpl(); + + // Wait, synchronously, on multiple events. + // returns the index of a WaitableEvent which has been signaled. + template + static size_t WaitMany(std::array *waitables); + + private: + friend class AsyncWorkerPool; + void setFuture(std::future &&future); + + std::future mFuture; +}; + +template +// static +size_t AsyncWaitableEvent::WaitMany(std::array *waitables) +{ + return WaitableEventBase::WaitManyBase(waitables); +} +#endif // (ANGLE_STD_ASYNC_WORKERS == ANGLE_ENABLED) + +// The traits class allows the the thread pool to return the "Typed" waitable event from postTask. +// Otherwise postTask would always think it returns the current active type, so the unit tests +// could not run on multiple worker types in the same compilation. +template +struct WorkerThreadPoolTraits; + +class SingleThreadedWorkerPool; +template <> +struct WorkerThreadPoolTraits +{ + using WaitableEventType = SingleThreadedWaitableEvent; +}; + +#if (ANGLE_STD_ASYNC_WORKERS == ANGLE_ENABLED) +class AsyncWorkerPool; +template <> +struct WorkerThreadPoolTraits +{ + using WaitableEventType = AsyncWaitableEvent; +}; +#endif // (ANGLE_STD_ASYNC_WORKERS == ANGLE_ENABLED) + +// Request WorkerThreads from the WorkerThreadPool. Each pool can keep worker threads around so +// we avoid the costly spin up and spin down time. +template +class WorkerThreadPoolBase : angle::NonCopyable +{ + public: + WorkerThreadPoolBase(size_t maxThreads); + ~WorkerThreadPoolBase(); + + using WaitableEventType = typename WorkerThreadPoolTraits::WaitableEventType; + + // Returns an event to wait on for the task to finish. + // If the pool fails to create the task, returns null. + WaitableEventType postWorkerTask(Closure *task); +}; + +template +WorkerThreadPoolBase::WorkerThreadPoolBase(size_t maxThreads) +{ +} + +template +WorkerThreadPoolBase::~WorkerThreadPoolBase() +{ +} + +template +typename WorkerThreadPoolBase::WaitableEventType WorkerThreadPoolBase::postWorkerTask( + Closure *task) +{ + return static_cast(this)->postWorkerTaskImpl(task); +} + +class SingleThreadedWorkerPool : public WorkerThreadPoolBase +{ + public: + SingleThreadedWorkerPool(size_t maxThreads); + ~SingleThreadedWorkerPool(); + + SingleThreadedWaitableEvent postWorkerTaskImpl(Closure *task); +}; + +#if (ANGLE_STD_ASYNC_WORKERS == ANGLE_ENABLED) +class AsyncWorkerPool : public WorkerThreadPoolBase +{ + public: + AsyncWorkerPool(size_t maxThreads); + ~AsyncWorkerPool(); + + AsyncWaitableEvent postWorkerTaskImpl(Closure *task); +}; +#endif // (ANGLE_STD_ASYNC_WORKERS == ANGLE_ENABLED) + +} // namespace priv + +#if (ANGLE_STD_ASYNC_WORKERS == ANGLE_ENABLED) +using WaitableEvent = priv::AsyncWaitableEvent; +using WorkerThreadPool = priv::AsyncWorkerPool; +#else +using WaitableEvent = priv::SingleThreadedWaitableEvent; +using WorkerThreadPool = priv::SingleThreadedWorkerPool; +#endif // (ANGLE_STD_ASYNC_WORKERS == ANGLE_ENABLED) + +} // namespace angle + +#endif // LIBANGLE_WORKER_THREAD_H_ diff --git a/src/3rdparty/angle/src/libANGLE/angletypes.cpp b/src/3rdparty/angle/src/libANGLE/angletypes.cpp index fa5b157906..702d391e46 100644 --- a/src/3rdparty/angle/src/libANGLE/angletypes.cpp +++ b/src/3rdparty/angle/src/libANGLE/angletypes.cpp @@ -39,39 +39,143 @@ PrimitiveType GetPrimitiveType(GLenum drawMode) } } +RasterizerState::RasterizerState() +{ + memset(this, 0, sizeof(RasterizerState)); + + rasterizerDiscard = false; + cullFace = false; + cullMode = CullFaceMode::Back; + frontFace = GL_CCW; + polygonOffsetFill = false; + polygonOffsetFactor = 0.0f; + polygonOffsetUnits = 0.0f; + pointDrawMode = false; + multiSample = false; +} + +bool operator==(const RasterizerState &a, const RasterizerState &b) +{ + return memcmp(&a, &b, sizeof(RasterizerState)) == 0; +} + +bool operator!=(const RasterizerState &a, const RasterizerState &b) +{ + return !(a == b); +} + +BlendState::BlendState() +{ + memset(this, 0, sizeof(BlendState)); + + blend = false; + sourceBlendRGB = GL_ONE; + sourceBlendAlpha = GL_ONE; + destBlendRGB = GL_ZERO; + destBlendAlpha = GL_ZERO; + blendEquationRGB = GL_FUNC_ADD; + blendEquationAlpha = GL_FUNC_ADD; + sampleAlphaToCoverage = false; + dither = true; +} + +BlendState::BlendState(const BlendState &other) +{ + memcpy(this, &other, sizeof(BlendState)); +} + +bool operator==(const BlendState &a, const BlendState &b) +{ + return memcmp(&a, &b, sizeof(BlendState)) == 0; +} + +bool operator!=(const BlendState &a, const BlendState &b) +{ + return !(a == b); +} + +DepthStencilState::DepthStencilState() +{ + memset(this, 0, sizeof(DepthStencilState)); + + depthTest = false; + depthFunc = GL_LESS; + depthMask = true; + stencilTest = false; + stencilFunc = GL_ALWAYS; + stencilMask = static_cast(-1); + stencilWritemask = static_cast(-1); + stencilBackFunc = GL_ALWAYS; + stencilBackMask = static_cast(-1); + stencilBackWritemask = static_cast(-1); + stencilFail = GL_KEEP; + stencilPassDepthFail = GL_KEEP; + stencilPassDepthPass = GL_KEEP; + stencilBackFail = GL_KEEP; + stencilBackPassDepthFail = GL_KEEP; + stencilBackPassDepthPass = GL_KEEP; +} + +DepthStencilState::DepthStencilState(const DepthStencilState &other) +{ + memcpy(this, &other, sizeof(DepthStencilState)); +} + +bool operator==(const DepthStencilState &a, const DepthStencilState &b) +{ + return memcmp(&a, &b, sizeof(DepthStencilState)) == 0; +} + +bool operator!=(const DepthStencilState &a, const DepthStencilState &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), - minLod(-1000.0f), - maxLod(1000.0f), - compareMode(GL_NONE), - compareFunc(GL_LEQUAL) { + memset(this, 0, sizeof(SamplerState)); + + minFilter = GL_NEAREST_MIPMAP_LINEAR; + magFilter = GL_LINEAR; + wrapS = GL_REPEAT; + wrapT = GL_REPEAT; + wrapR = GL_REPEAT; + maxAnisotropy = 1.0f; + minLod = -1000.0f; + maxLod = 1000.0f; + compareMode = GL_NONE; + compareFunc = GL_LEQUAL; + sRGBDecode = GL_DECODE_EXT; } -TextureState::TextureState() - : swizzleRed(GL_RED), - swizzleGreen(GL_GREEN), - swizzleBlue(GL_BLUE), - swizzleAlpha(GL_ALPHA), - samplerState(), - baseLevel(0), - maxLevel(1000), - immutableFormat(false), - immutableLevels(0) +SamplerState::SamplerState(const SamplerState &other) = default; + +// static +SamplerState SamplerState::CreateDefaultForTarget(GLenum target) { + SamplerState state; + + // According to OES_EGL_image_external and ARB_texture_rectangle: For external textures, the + // default min filter is GL_LINEAR and the default s and t wrap modes are GL_CLAMP_TO_EDGE. + if (target == GL_TEXTURE_EXTERNAL_OES || target == GL_TEXTURE_RECTANGLE_ANGLE) + { + state.minFilter = GL_LINEAR; + state.wrapS = GL_CLAMP_TO_EDGE; + state.wrapT = GL_CLAMP_TO_EDGE; + } + + return state; } -bool TextureState::swizzleRequired() const +ImageUnit::ImageUnit() + : texture(), level(0), layered(false), layer(0), access(GL_READ_ONLY), format(GL_R32UI) { - return swizzleRed != GL_RED || swizzleGreen != GL_GREEN || - swizzleBlue != GL_BLUE || swizzleAlpha != GL_ALPHA; } +ImageUnit::ImageUnit(const ImageUnit &other) = default; + +ImageUnit::~ImageUnit() = default; + static void MinMax(int a, int b, int *minimum, int *maximum) { if (a < b) @@ -133,6 +237,16 @@ bool Box::operator!=(const Box &other) const return !(*this == other); } +bool operator==(const Offset &a, const Offset &b) +{ + return a.x == b.x && a.y == b.y && a.z == b.z; +} + +bool operator!=(const Offset &a, const Offset &b) +{ + return !(a == b); +} + bool operator==(const Extents &lhs, const Extents &rhs) { return lhs.width == rhs.width && lhs.height == rhs.height && lhs.depth == rhs.depth; @@ -142,4 +256,4 @@ bool operator!=(const Extents &lhs, const Extents &rhs) { return !(lhs == rhs); } -} +} // namespace gl diff --git a/src/3rdparty/angle/src/libANGLE/angletypes.h b/src/3rdparty/angle/src/libANGLE/angletypes.h index c29ad06bd2..4f364b090a 100644 --- a/src/3rdparty/angle/src/libANGLE/angletypes.h +++ b/src/3rdparty/angle/src/libANGLE/angletypes.h @@ -9,20 +9,22 @@ #ifndef LIBANGLE_ANGLETYPES_H_ #define LIBANGLE_ANGLETYPES_H_ +#include "common/bitset_utils.h" #include "libANGLE/Constants.h" +#include "libANGLE/Error.h" +#include "libANGLE/PackedGLEnums.h" #include "libANGLE/RefCountObject.h" #include #include +#include +#include namespace gl { class Buffer; -class State; -class Program; -struct VertexAttribute; -struct VertexAttribCurrentValueData; +class Texture; enum PrimitiveType { @@ -41,31 +43,19 @@ PrimitiveType GetPrimitiveType(GLenum drawMode); enum SamplerType { SAMPLER_PIXEL, - SAMPLER_VERTEX + SAMPLER_VERTEX, + SAMPLER_COMPUTE }; -template -struct Color +enum ShaderType { - 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) { } + SHADER_VERTEX, + SHADER_FRAGMENT, + SHADER_GEOMETRY, + SHADER_COMPUTE, + SHADER_TYPE_MAX }; -template -bool operator==(const Color &a, const Color &b); - -template -bool operator!=(const Color &a, const Color &b); - -typedef Color ColorF; -typedef Color ColorI; -typedef Color ColorUI; - struct Rectangle { Rectangle() : x(0), y(0), width(0), height(0) {} @@ -100,6 +90,9 @@ struct Offset Offset(int x_in, int y_in, int z_in) : x(x_in), y(y_in), z(z_in) { } }; +bool operator==(const Offset &a, const Offset &b); +bool operator!=(const Offset &a, const Offset &b); + struct Extents { int width; @@ -109,6 +102,9 @@ struct Extents Extents() : width(0), height(0), depth(0) { } Extents(int width_, int height_, int depth_) : width(width_), height(height_), depth(depth_) { } + Extents(const Extents &other) = default; + Extents &operator=(const Extents &other) = default; + bool empty() const { return (width * height * depth) == 0; } }; @@ -131,11 +127,13 @@ struct Box bool operator!=(const Box &other) const; }; - -struct RasterizerState +struct RasterizerState final { + // This will zero-initialize the struct, including padding. + RasterizerState(); + bool cullFace; - GLenum cullMode; + CullFaceMode cullMode; GLenum frontFace; bool polygonOffsetFill; @@ -148,8 +146,15 @@ struct RasterizerState bool rasterizerDiscard; }; -struct BlendState +bool operator==(const RasterizerState &a, const RasterizerState &b); +bool operator!=(const RasterizerState &a, const RasterizerState &b); + +struct BlendState final { + // This will zero-initialize the struct, including padding. + BlendState(); + BlendState(const BlendState &other); + bool blend; GLenum sourceBlendRGB; GLenum destBlendRGB; @@ -168,8 +173,15 @@ struct BlendState bool dither; }; -struct DepthStencilState +bool operator==(const BlendState &a, const BlendState &b); +bool operator!=(const BlendState &a, const BlendState &b); + +struct DepthStencilState final { + // This will zero-initialize the struct, including padding. + DepthStencilState(); + DepthStencilState(const DepthStencilState &other); + bool depthTest; GLenum depthFunc; bool depthMask; @@ -189,10 +201,17 @@ struct DepthStencilState GLuint stencilBackWritemask; }; +bool operator==(const DepthStencilState &a, const DepthStencilState &b); +bool operator!=(const DepthStencilState &a, const DepthStencilState &b); + // State from Table 6.10 (state per sampler object) -struct SamplerState +struct SamplerState final { + // This will zero-initialize the struct, including padding. SamplerState(); + SamplerState(const SamplerState &other); + + static SamplerState CreateDefaultForTarget(GLenum target); GLenum minFilter; GLenum magFilter; @@ -209,110 +228,92 @@ struct SamplerState GLenum compareMode; GLenum compareFunc; + + GLenum sRGBDecode; }; bool operator==(const SamplerState &a, const SamplerState &b); bool operator!=(const SamplerState &a, const SamplerState &b); -// State from Table 6.9 (state per texture object) in the OpenGL ES 3.0.2 spec. -struct TextureState +struct DrawArraysIndirectCommand { - TextureState(); - - GLenum swizzleRed; - GLenum swizzleGreen; - GLenum swizzleBlue; - GLenum swizzleAlpha; - - SamplerState samplerState; - - GLuint baseLevel; - GLuint maxLevel; - - bool immutableFormat; - GLuint immutableLevels; + GLuint count; + GLuint instanceCount; + GLuint first; + GLuint baseInstance; +}; +static_assert(sizeof(DrawArraysIndirectCommand) == 16, + "Unexpected size of DrawArraysIndirectCommand"); - // From GL_ANGLE_texture_usage - GLenum usage; +struct DrawElementsIndirectCommand +{ + GLuint count; + GLuint primCount; + GLuint firstIndex; + GLint baseVertex; + GLuint baseInstance; +}; +static_assert(sizeof(DrawElementsIndirectCommand) == 20, + "Unexpected size of DrawElementsIndirectCommand"); - bool swizzleRequired() const; +struct ImageUnit +{ + ImageUnit(); + ImageUnit(const ImageUnit &other); + ~ImageUnit(); + + BindingPointer texture; + GLint level; + GLboolean layered; + GLint layer; + GLenum access; + GLenum format; }; -bool operator==(const TextureState &a, const TextureState &b); -bool operator!=(const TextureState &a, const TextureState &b); +struct PixelStoreStateBase +{ + GLint alignment = 4; + GLint rowLength = 0; + GLint skipRows = 0; + GLint skipPixels = 0; + GLint imageHeight = 0; + GLint skipImages = 0; +}; -struct PixelUnpackState +struct PixelUnpackState : PixelStoreStateBase { - 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 +struct PixelPackState : PixelStoreStateBase { - 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) - {} + bool reverseRowOrder = false; }; // Used in Program and VertexArray. -typedef std::bitset AttributesMask; +using AttributesMask = angle::BitSet; -// Use in Program -typedef std::bitset UniformBlockBindingMask; -} +// Used in Program +using UniformBlockBindingMask = angle::BitSet; + +// Used in Framebuffer +using DrawBufferMask = angle::BitSet; + +using ContextID = uintptr_t; + +constexpr size_t CUBE_FACE_COUNT = 6; + +using TextureMap = std::map>; + +template +using AttachmentArray = std::array; + +template +using DrawBuffersArray = std::array; + +} // namespace gl namespace rx { -enum VendorID : uint32_t -{ - VENDOR_ID_UNKNOWN = 0x0, - VENDOR_ID_AMD = 0x1002, - VENDOR_ID_INTEL = 0x8086, - VENDOR_ID_NVIDIA = 0x10DE, -}; - // A macro that determines whether an object has a given runtime type. #if defined(__clang__) #if __has_feature(cxx_rtti) @@ -354,12 +355,12 @@ inline DestT *GetImplAs(SrcT *src) } template -inline const DestT *GetImplAs(const SrcT *src) +inline DestT *SafeGetImplAs(SrcT *src) { - return GetAs(src->getImplementation()); + return src != nullptr ? GetAs(src->getImplementation()) : nullptr; } -} +} // namespace rx #include "angletypes.inl" @@ -407,6 +408,80 @@ inline GLenum FramebufferBindingToEnum(FramebufferBinding binding) return GL_NONE; } } -} + +template +class DestroyThenDelete +{ + public: + DestroyThenDelete(const ContextT *context) : mContext(context) {} + + void operator()(ObjT *obj) + { + ANGLE_SWALLOW_ERR(obj->onDestroy(mContext)); + delete obj; + } + + private: + const ContextT *mContext; +}; + +// Helper class for wrapping an onDestroy function. +template +class UniqueObjectPointerBase : angle::NonCopyable +{ + public: + template + UniqueObjectPointerBase(const ContextT *context) : mObject(nullptr), mDeleter(context) + { + } + + template + UniqueObjectPointerBase(ObjT *obj, const ContextT *context) : mObject(obj), mDeleter(context) + { + } + + ~UniqueObjectPointerBase() + { + if (mObject) + { + mDeleter(mObject); + } + } + + ObjT *operator->() const { return mObject; } + + ObjT *release() + { + auto obj = mObject; + mObject = nullptr; + return obj; + } + + ObjT *get() const { return mObject; } + + void reset(ObjT *obj) + { + if (mObject) + { + mDeleter(mObject); + } + mObject = obj; + } + + private: + ObjT *mObject; + DeleterT mDeleter; +}; + +template +using UniqueObjectPointer = UniqueObjectPointerBase>; + +} // namespace angle + +namespace gl +{ +class ContextState; + +} // namespace gl #endif // LIBANGLE_ANGLETYPES_H_ diff --git a/src/3rdparty/angle/src/libANGLE/angletypes.inl b/src/3rdparty/angle/src/libANGLE/angletypes.inl index d51bcaaa78..3fbe0747d2 100644 --- a/src/3rdparty/angle/src/libANGLE/angletypes.inl +++ b/src/3rdparty/angle/src/libANGLE/angletypes.inl @@ -9,21 +9,6 @@ namespace gl { -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); -} - inline bool operator==(const Rectangle &a, const Rectangle &b) { return a.x == b.x && @@ -39,16 +24,7 @@ inline bool operator!=(const Rectangle &a, const Rectangle &b) inline bool operator==(const SamplerState &a, const SamplerState &b) { - return a.minFilter == b.minFilter && - a.magFilter == b.magFilter && - a.wrapS == b.wrapS && - a.wrapT == b.wrapT && - a.wrapR == b.wrapR && - a.maxAnisotropy == b.maxAnisotropy && - a.minLod == b.minLod && - a.maxLod == b.maxLod && - a.compareMode == b.compareMode && - a.compareFunc == b.compareFunc; + return memcmp(&a, &b, sizeof(SamplerState)) == 0; } inline bool operator!=(const SamplerState &a, const SamplerState &b) @@ -56,23 +32,4 @@ inline bool operator!=(const SamplerState &a, const SamplerState &b) return !(a == b); } -inline bool operator==(const TextureState &a, const TextureState &b) -{ - return a.swizzleRed == b.swizzleRed && - a.swizzleGreen == b.swizzleGreen && - a.swizzleBlue == b.swizzleBlue && - a.swizzleAlpha == b.swizzleAlpha && - a.samplerState == b.samplerState && - a.baseLevel == b.baseLevel && - a.maxLevel == b.maxLevel && - a.immutableFormat == b.immutableFormat && - a.immutableLevels == b.immutableLevels && - a.usage == b.usage; -} - -inline bool operator!=(const TextureState &a, const TextureState &b) -{ - return !(a == b); -} - -} +} // namespace gl diff --git a/src/3rdparty/angle/src/libANGLE/entry_points_enum_autogen.h b/src/3rdparty/angle/src/libANGLE/entry_points_enum_autogen.h new file mode 100644 index 0000000000..14b5e3c1b0 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/entry_points_enum_autogen.h @@ -0,0 +1,336 @@ +// GENERATED FILE - DO NOT EDIT. +// Generated by generate_entry_points.py using data from gl.xml. +// +// Copyright 2017 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. +// +// entry_points_enum_autogen.h: +// Defines the GLES entry points enumeration. + +#ifndef LIBGLESV2_ENTRYPOINTSENUM_AUTOGEN_H_ +#define LIBGLESV2_ENTRYPOINTSENUM_AUTOGEN_H_ + +namespace gl +{ +enum class EntryPoint +{ + Invalid, + ActiveTexture, + AttachShader, + BindAttribLocation, + BindBuffer, + BindFramebuffer, + BindRenderbuffer, + BindTexture, + BlendColor, + BlendEquation, + BlendEquationSeparate, + BlendFunc, + BlendFuncSeparate, + BufferData, + BufferSubData, + CheckFramebufferStatus, + Clear, + ClearColor, + ClearDepthf, + ClearStencil, + ColorMask, + CompileShader, + CompressedTexImage2D, + CompressedTexSubImage2D, + CopyTexImage2D, + CopyTexSubImage2D, + CreateProgram, + CreateShader, + CullFace, + DeleteBuffers, + DeleteFramebuffers, + DeleteProgram, + DeleteRenderbuffers, + DeleteShader, + DeleteTextures, + DepthFunc, + DepthMask, + DepthRangef, + DetachShader, + Disable, + DisableVertexAttribArray, + DrawArrays, + DrawElements, + Enable, + EnableVertexAttribArray, + Finish, + Flush, + FramebufferRenderbuffer, + FramebufferTexture2D, + FrontFace, + GenBuffers, + GenerateMipmap, + GenFramebuffers, + GenRenderbuffers, + GenTextures, + GetActiveAttrib, + GetActiveUniform, + GetAttachedShaders, + GetAttribLocation, + GetBooleanv, + GetBufferParameteriv, + GetError, + GetFloatv, + GetFramebufferAttachmentParameteriv, + GetIntegerv, + GetProgramiv, + GetProgramInfoLog, + GetRenderbufferParameteriv, + GetShaderiv, + GetShaderInfoLog, + GetShaderPrecisionFormat, + GetShaderSource, + GetString, + GetTexParameterfv, + GetTexParameteriv, + GetUniformfv, + GetUniformiv, + GetUniformLocation, + GetVertexAttribfv, + GetVertexAttribiv, + GetVertexAttribPointerv, + Hint, + IsBuffer, + IsEnabled, + IsFramebuffer, + IsProgram, + IsRenderbuffer, + IsShader, + IsTexture, + LineWidth, + LinkProgram, + PixelStorei, + PolygonOffset, + ReadPixels, + ReleaseShaderCompiler, + RenderbufferStorage, + SampleCoverage, + Scissor, + ShaderBinary, + ShaderSource, + StencilFunc, + StencilFuncSeparate, + StencilMask, + StencilMaskSeparate, + StencilOp, + StencilOpSeparate, + TexImage2D, + TexParameterf, + TexParameterfv, + TexParameteri, + TexParameteriv, + TexSubImage2D, + Uniform1f, + Uniform1fv, + Uniform1i, + Uniform1iv, + Uniform2f, + Uniform2fv, + Uniform2i, + Uniform2iv, + Uniform3f, + Uniform3fv, + Uniform3i, + Uniform3iv, + Uniform4f, + Uniform4fv, + Uniform4i, + Uniform4iv, + UniformMatrix2fv, + UniformMatrix3fv, + UniformMatrix4fv, + UseProgram, + ValidateProgram, + VertexAttrib1f, + VertexAttrib1fv, + VertexAttrib2f, + VertexAttrib2fv, + VertexAttrib3f, + VertexAttrib3fv, + VertexAttrib4f, + VertexAttrib4fv, + VertexAttribPointer, + Viewport, + ReadBuffer, + DrawRangeElements, + TexImage3D, + TexSubImage3D, + CopyTexSubImage3D, + CompressedTexImage3D, + CompressedTexSubImage3D, + GenQueries, + DeleteQueries, + IsQuery, + BeginQuery, + EndQuery, + GetQueryiv, + GetQueryObjectuiv, + UnmapBuffer, + GetBufferPointerv, + DrawBuffers, + UniformMatrix2x3fv, + UniformMatrix3x2fv, + UniformMatrix2x4fv, + UniformMatrix4x2fv, + UniformMatrix3x4fv, + UniformMatrix4x3fv, + BlitFramebuffer, + RenderbufferStorageMultisample, + FramebufferTextureLayer, + MapBufferRange, + FlushMappedBufferRange, + BindVertexArray, + DeleteVertexArrays, + GenVertexArrays, + IsVertexArray, + GetIntegeri_v, + BeginTransformFeedback, + EndTransformFeedback, + BindBufferRange, + BindBufferBase, + TransformFeedbackVaryings, + GetTransformFeedbackVarying, + VertexAttribIPointer, + GetVertexAttribIiv, + GetVertexAttribIuiv, + VertexAttribI4i, + VertexAttribI4ui, + VertexAttribI4iv, + VertexAttribI4uiv, + GetUniformuiv, + GetFragDataLocation, + Uniform1ui, + Uniform2ui, + Uniform3ui, + Uniform4ui, + Uniform1uiv, + Uniform2uiv, + Uniform3uiv, + Uniform4uiv, + ClearBufferiv, + ClearBufferuiv, + ClearBufferfv, + ClearBufferfi, + GetStringi, + CopyBufferSubData, + GetUniformIndices, + GetActiveUniformsiv, + GetUniformBlockIndex, + GetActiveUniformBlockiv, + GetActiveUniformBlockName, + UniformBlockBinding, + DrawArraysInstanced, + DrawElementsInstanced, + FenceSync, + IsSync, + DeleteSync, + ClientWaitSync, + WaitSync, + GetInteger64v, + GetSynciv, + GetInteger64i_v, + GetBufferParameteri64v, + GenSamplers, + DeleteSamplers, + IsSampler, + BindSampler, + SamplerParameteri, + SamplerParameteriv, + SamplerParameterf, + SamplerParameterfv, + GetSamplerParameteriv, + GetSamplerParameterfv, + VertexAttribDivisor, + BindTransformFeedback, + DeleteTransformFeedbacks, + GenTransformFeedbacks, + IsTransformFeedback, + PauseTransformFeedback, + ResumeTransformFeedback, + GetProgramBinary, + ProgramBinary, + ProgramParameteri, + InvalidateFramebuffer, + InvalidateSubFramebuffer, + TexStorage2D, + TexStorage3D, + GetInternalformativ, + DispatchCompute, + DispatchComputeIndirect, + DrawArraysIndirect, + DrawElementsIndirect, + FramebufferParameteri, + GetFramebufferParameteriv, + GetProgramInterfaceiv, + GetProgramResourceIndex, + GetProgramResourceName, + GetProgramResourceiv, + GetProgramResourceLocation, + UseProgramStages, + ActiveShaderProgram, + CreateShaderProgramv, + BindProgramPipeline, + DeleteProgramPipelines, + GenProgramPipelines, + IsProgramPipeline, + GetProgramPipelineiv, + ProgramUniform1i, + ProgramUniform2i, + ProgramUniform3i, + ProgramUniform4i, + ProgramUniform1ui, + ProgramUniform2ui, + ProgramUniform3ui, + ProgramUniform4ui, + ProgramUniform1f, + ProgramUniform2f, + ProgramUniform3f, + ProgramUniform4f, + ProgramUniform1iv, + ProgramUniform2iv, + ProgramUniform3iv, + ProgramUniform4iv, + ProgramUniform1uiv, + ProgramUniform2uiv, + ProgramUniform3uiv, + ProgramUniform4uiv, + ProgramUniform1fv, + ProgramUniform2fv, + ProgramUniform3fv, + ProgramUniform4fv, + ProgramUniformMatrix2fv, + ProgramUniformMatrix3fv, + ProgramUniformMatrix4fv, + ProgramUniformMatrix2x3fv, + ProgramUniformMatrix3x2fv, + ProgramUniformMatrix2x4fv, + ProgramUniformMatrix4x2fv, + ProgramUniformMatrix3x4fv, + ProgramUniformMatrix4x3fv, + ValidateProgramPipeline, + GetProgramPipelineInfoLog, + BindImageTexture, + GetBooleani_v, + MemoryBarrier, + MemoryBarrierByRegion, + TexStorage2DMultisample, + GetMultisamplefv, + SampleMaski, + GetTexLevelParameteriv, + GetTexLevelParameterfv, + BindVertexBuffer, + VertexAttribFormat, + VertexAttribIFormat, + VertexAttribBinding, + VertexBindingDivisor, + DrawElementsInstancedANGLE +}; +} // namespace gl +#endif // LIBGLESV2_ENTRY_POINTS_ENUM_AUTOGEN_H_ diff --git a/src/3rdparty/angle/src/libANGLE/es3_copy_conversion_formats.json b/src/3rdparty/angle/src/libANGLE/es3_copy_conversion_formats.json new file mode 100644 index 0000000000..39b71fd93a --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/es3_copy_conversion_formats.json @@ -0,0 +1,44 @@ +{ + "From ES 3.0.1 spec, table 3.15": + [ + [ "GL_ALPHA", "GL_RGBA" ], + [ "GL_LUMINANCE", "GL_RED" ], + [ "GL_LUMINANCE", "GL_RG" ], + [ "GL_LUMINANCE", "GL_RGB" ], + [ "GL_LUMINANCE", "GL_RGBA" ], + [ "GL_LUMINANCE_ALPHA", "GL_RGBA" ], + [ "GL_RED", "GL_RED" ], + [ "GL_RED", "GL_RG" ], + [ "GL_RED", "GL_RGB" ], + [ "GL_RED", "GL_RGBA" ], + [ "GL_RG", "GL_RG" ], + [ "GL_RG", "GL_RGB" ], + [ "GL_RG", "GL_RGBA" ], + [ "GL_RGB", "GL_RGB" ], + [ "GL_RGB", "GL_RGBA" ], + [ "GL_RGBA", "GL_RGBA" ] + ], + + "Necessary for ANGLE back-buffers": + [ + [ "GL_ALPHA", "GL_BGRA_EXT" ], + [ "GL_LUMINANCE", "GL_BGRA_EXT" ], + [ "GL_LUMINANCE_ALPHA", "GL_BGRA_EXT" ], + [ "GL_RED", "GL_BGRA_EXT" ], + [ "GL_RG", "GL_BGRA_EXT" ], + [ "GL_RGB", "GL_BGRA_EXT" ], + [ "GL_RGBA", "GL_BGRA_EXT" ], + [ "GL_BGRA_EXT", "GL_BGRA_EXT" ], + + [ "GL_RED_INTEGER", "GL_RED_INTEGER" ], + [ "GL_RED_INTEGER", "GL_RG_INTEGER" ], + [ "GL_RED_INTEGER", "GL_RGB_INTEGER" ], + [ "GL_RED_INTEGER", "GL_RGBA_INTEGER" ], + [ "GL_RG_INTEGER", "GL_RG_INTEGER" ], + [ "GL_RG_INTEGER", "GL_RGB_INTEGER" ], + [ "GL_RG_INTEGER", "GL_RGBA_INTEGER" ], + [ "GL_RGB_INTEGER", "GL_RGB_INTEGER" ], + [ "GL_RGB_INTEGER", "GL_RGBA_INTEGER" ], + [ "GL_RGBA_INTEGER", "GL_RGBA_INTEGER" ] + ] +} diff --git a/src/3rdparty/angle/src/libANGLE/es3_copy_conversion_table_autogen.cpp b/src/3rdparty/angle/src/libANGLE/es3_copy_conversion_table_autogen.cpp new file mode 100644 index 0000000000..149f79f458 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/es3_copy_conversion_table_autogen.cpp @@ -0,0 +1,171 @@ +// GENERATED FILE - DO NOT EDIT. +// Generated by gen_copy_conversion_table.py using data from es3_copy_conversion_formats.json. +// +// Copyright 2017 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. +// +// format_map: +// Determining the sized internal format from a (format,type) pair. +// Also check es3 format combinations for validity. + +#include "angle_gl.h" +#include "common/debug.h" + +namespace gl +{ + +bool ValidES3CopyConversion(GLenum textureFormat, GLenum framebufferFormat) +{ + switch (textureFormat) + { + case GL_ALPHA: + switch (framebufferFormat) + { + case GL_BGRA_EXT: + case GL_RGBA: + return true; + default: + break; + } + break; + + case GL_BGRA_EXT: + switch (framebufferFormat) + { + case GL_BGRA_EXT: + return true; + default: + break; + } + break; + + case GL_LUMINANCE: + switch (framebufferFormat) + { + case GL_BGRA_EXT: + case GL_RED: + case GL_RG: + case GL_RGB: + case GL_RGBA: + return true; + default: + break; + } + break; + + case GL_LUMINANCE_ALPHA: + switch (framebufferFormat) + { + case GL_BGRA_EXT: + case GL_RGBA: + return true; + default: + break; + } + break; + + case GL_RED: + switch (framebufferFormat) + { + case GL_BGRA_EXT: + case GL_RED: + case GL_RG: + case GL_RGB: + case GL_RGBA: + return true; + default: + break; + } + break; + + case GL_RED_INTEGER: + switch (framebufferFormat) + { + case GL_RED_INTEGER: + case GL_RGBA_INTEGER: + case GL_RGB_INTEGER: + case GL_RG_INTEGER: + return true; + default: + break; + } + break; + + case GL_RG: + switch (framebufferFormat) + { + case GL_BGRA_EXT: + case GL_RG: + case GL_RGB: + case GL_RGBA: + return true; + default: + break; + } + break; + + case GL_RGB: + switch (framebufferFormat) + { + case GL_BGRA_EXT: + case GL_RGB: + case GL_RGBA: + return true; + default: + break; + } + break; + + case GL_RGBA: + switch (framebufferFormat) + { + case GL_BGRA_EXT: + case GL_RGBA: + return true; + default: + break; + } + break; + + case GL_RGBA_INTEGER: + switch (framebufferFormat) + { + case GL_RGBA_INTEGER: + return true; + default: + break; + } + break; + + case GL_RGB_INTEGER: + switch (framebufferFormat) + { + case GL_RGBA_INTEGER: + case GL_RGB_INTEGER: + return true; + default: + break; + } + break; + + case GL_RG_INTEGER: + switch (framebufferFormat) + { + case GL_RGBA_INTEGER: + case GL_RGB_INTEGER: + case GL_RG_INTEGER: + return true; + default: + break; + } + break; + + default: + break; + } + + return false; +} + +} // namespace gl diff --git a/src/3rdparty/angle/src/libANGLE/es3_format_type_combinations.json b/src/3rdparty/angle/src/libANGLE/es3_format_type_combinations.json new file mode 100644 index 0000000000..fb12242e75 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/es3_format_type_combinations.json @@ -0,0 +1,171 @@ +{ + "Format combinations from ES 3.0.1 spec, table 3.2": + [ + [ "GL_RGBA8", "GL_RGBA", "GL_UNSIGNED_BYTE" ], + [ "GL_RGB5_A1", "GL_RGBA", "GL_UNSIGNED_BYTE" ], + [ "GL_RGBA4", "GL_RGBA", "GL_UNSIGNED_BYTE" ], + [ "GL_SRGB8_ALPHA8", "GL_RGBA", "GL_UNSIGNED_BYTE" ], + [ "GL_RGBA8_SNORM", "GL_RGBA", "GL_BYTE" ], + [ "GL_RGBA4", "GL_RGBA", "GL_UNSIGNED_SHORT_4_4_4_4" ], + [ "GL_RGB10_A2", "GL_RGBA", "GL_UNSIGNED_INT_2_10_10_10_REV" ], + [ "GL_RGB5_A1", "GL_RGBA", "GL_UNSIGNED_INT_2_10_10_10_REV" ], + [ "GL_RGB5_A1", "GL_RGBA", "GL_UNSIGNED_SHORT_5_5_5_1" ], + [ "GL_RGBA16F", "GL_RGBA", "GL_HALF_FLOAT" ], + [ "GL_RGBA16F", "GL_RGBA", "GL_HALF_FLOAT_OES" ], + [ "GL_RGBA32F", "GL_RGBA", "GL_FLOAT" ], + [ "GL_RGBA16F", "GL_RGBA", "GL_FLOAT" ], + [ "GL_RGBA8UI", "GL_RGBA_INTEGER", "GL_UNSIGNED_BYTE" ], + [ "GL_RGBA8I", "GL_RGBA_INTEGER", "GL_BYTE" ], + [ "GL_RGBA16UI", "GL_RGBA_INTEGER", "GL_UNSIGNED_SHORT" ], + [ "GL_RGBA16I", "GL_RGBA_INTEGER", "GL_SHORT" ], + [ "GL_RGBA32UI", "GL_RGBA_INTEGER", "GL_UNSIGNED_INT" ], + [ "GL_RGBA32I", "GL_RGBA_INTEGER", "GL_INT" ], + [ "GL_RGB10_A2UI", "GL_RGBA_INTEGER", "GL_UNSIGNED_INT_2_10_10_10_REV" ], + [ "GL_RGB8", "GL_RGB", "GL_UNSIGNED_BYTE" ], + [ "GL_RGB565", "GL_RGB", "GL_UNSIGNED_BYTE" ], + [ "GL_SRGB8", "GL_RGB", "GL_UNSIGNED_BYTE" ], + [ "GL_RGB8_SNORM", "GL_RGB", "GL_BYTE" ], + [ "GL_RGB565", "GL_RGB", "GL_UNSIGNED_SHORT_5_6_5" ], + [ "GL_R11F_G11F_B10F", "GL_RGB", "GL_UNSIGNED_INT_10F_11F_11F_REV" ], + [ "GL_RGB9_E5", "GL_RGB", "GL_UNSIGNED_INT_5_9_9_9_REV" ], + [ "GL_RGB16F", "GL_RGB", "GL_HALF_FLOAT" ], + [ "GL_RGB16F", "GL_RGB", "GL_HALF_FLOAT_OES" ], + [ "GL_R11F_G11F_B10F", "GL_RGB", "GL_HALF_FLOAT" ], + [ "GL_R11F_G11F_B10F", "GL_RGB", "GL_HALF_FLOAT_OES" ], + [ "GL_RGB9_E5", "GL_RGB", "GL_HALF_FLOAT" ], + [ "GL_RGB9_E5", "GL_RGB", "GL_HALF_FLOAT_OES" ], + [ "GL_RGB32F", "GL_RGB", "GL_FLOAT" ], + [ "GL_RGB16F", "GL_RGB", "GL_FLOAT" ], + [ "GL_R11F_G11F_B10F", "GL_RGB", "GL_FLOAT" ], + [ "GL_RGB9_E5", "GL_RGB", "GL_FLOAT" ], + [ "GL_RGB8UI", "GL_RGB_INTEGER", "GL_UNSIGNED_BYTE" ], + [ "GL_RGB8I", "GL_RGB_INTEGER", "GL_BYTE" ], + [ "GL_RGB16UI", "GL_RGB_INTEGER", "GL_UNSIGNED_SHORT" ], + [ "GL_RGB16I", "GL_RGB_INTEGER", "GL_SHORT" ], + [ "GL_RGB32UI", "GL_RGB_INTEGER", "GL_UNSIGNED_INT" ], + [ "GL_RGB32I", "GL_RGB_INTEGER", "GL_INT" ], + [ "GL_RG8", "GL_RG", "GL_UNSIGNED_BYTE" ], + [ "GL_RG8_SNORM", "GL_RG", "GL_BYTE" ], + [ "GL_RG16F", "GL_RG", "GL_HALF_FLOAT" ], + [ "GL_RG16F", "GL_RG", "GL_HALF_FLOAT_OES" ], + [ "GL_RG32F", "GL_RG", "GL_FLOAT" ], + [ "GL_RG16F", "GL_RG", "GL_FLOAT" ], + [ "GL_RG8UI", "GL_RG_INTEGER", "GL_UNSIGNED_BYTE" ], + [ "GL_RG8I", "GL_RG_INTEGER", "GL_BYTE" ], + [ "GL_RG16UI", "GL_RG_INTEGER", "GL_UNSIGNED_SHORT" ], + [ "GL_RG16I", "GL_RG_INTEGER", "GL_SHORT" ], + [ "GL_RG32UI", "GL_RG_INTEGER", "GL_UNSIGNED_INT" ], + [ "GL_RG32I", "GL_RG_INTEGER", "GL_INT" ], + [ "GL_R8", "GL_RED", "GL_UNSIGNED_BYTE" ], + [ "GL_R8_SNORM", "GL_RED", "GL_BYTE" ], + [ "GL_R16F", "GL_RED", "GL_HALF_FLOAT" ], + [ "GL_R16F", "GL_RED", "GL_HALF_FLOAT_OES" ], + [ "GL_R32F", "GL_RED", "GL_FLOAT" ], + [ "GL_R16F", "GL_RED", "GL_FLOAT" ], + [ "GL_R8UI", "GL_RED_INTEGER", "GL_UNSIGNED_BYTE" ], + [ "GL_R8I", "GL_RED_INTEGER", "GL_BYTE" ], + [ "GL_R16UI", "GL_RED_INTEGER", "GL_UNSIGNED_SHORT" ], + [ "GL_R16I", "GL_RED_INTEGER", "GL_SHORT" ], + [ "GL_R32UI", "GL_RED_INTEGER", "GL_UNSIGNED_INT" ], + [ "GL_R32I", "GL_RED_INTEGER", "GL_INT" ] + ], + "Unsized formats": + [ + [ "GL_RGBA", "GL_RGBA", "GL_UNSIGNED_BYTE" ], + [ "GL_RGBA", "GL_RGBA", "GL_UNSIGNED_SHORT_4_4_4_4" ], + [ "GL_RGBA", "GL_RGBA", "GL_UNSIGNED_SHORT_5_5_5_1" ], + [ "GL_RGB", "GL_RGB", "GL_UNSIGNED_BYTE" ], + [ "GL_RGB", "GL_RGB", "GL_UNSIGNED_SHORT_5_6_5" ], + [ "GL_LUMINANCE_ALPHA", "GL_LUMINANCE_ALPHA", "GL_UNSIGNED_BYTE" ], + [ "GL_LUMINANCE", "GL_LUMINANCE", "GL_UNSIGNED_BYTE" ], + [ "GL_ALPHA", "GL_ALPHA", "GL_UNSIGNED_BYTE" ], + [ "GL_SRGB_ALPHA_EXT", "GL_SRGB_ALPHA_EXT", "GL_UNSIGNED_BYTE" ], + [ "GL_SRGB_EXT", "GL_SRGB_EXT", "GL_UNSIGNED_BYTE" ], + [ "GL_RG", "GL_RG", "GL_UNSIGNED_BYTE" ], + [ "GL_RG", "GL_RG", "GL_FLOAT" ], + [ "GL_RG", "GL_RG", "GL_HALF_FLOAT" ], + [ "GL_RG", "GL_RG", "GL_HALF_FLOAT_OES" ], + [ "GL_RED", "GL_RED", "GL_UNSIGNED_BYTE" ], + [ "GL_RED", "GL_RED", "GL_FLOAT" ], + [ "GL_RED", "GL_RED", "GL_HALF_FLOAT" ], + [ "GL_RED", "GL_RED", "GL_HALF_FLOAT_OES" ], + [ "GL_DEPTH_STENCIL", "GL_DEPTH_STENCIL", "GL_UNSIGNED_INT_24_8" ] + ], + "Depth stencil formats": + [ + [ "GL_DEPTH_COMPONENT16", "GL_DEPTH_COMPONENT", "GL_UNSIGNED_SHORT" ], + [ "GL_DEPTH_COMPONENT24", "GL_DEPTH_COMPONENT", "GL_UNSIGNED_INT" ], + [ "GL_DEPTH_COMPONENT16", "GL_DEPTH_COMPONENT", "GL_UNSIGNED_INT" ], + [ "GL_DEPTH_COMPONENT32F", "GL_DEPTH_COMPONENT", "GL_FLOAT" ], + [ "GL_DEPTH24_STENCIL8", "GL_DEPTH_STENCIL", "GL_UNSIGNED_INT_24_8" ], + [ "GL_DEPTH32F_STENCIL8", "GL_DEPTH_STENCIL", "GL_FLOAT_32_UNSIGNED_INT_24_8_REV" ] + ], + "From GL_EXT_sRGB": + [ + [ "GL_SRGB8_ALPHA8_EXT", "GL_SRGB_ALPHA_EXT", "GL_UNSIGNED_BYTE" ], + [ "GL_SRGB8", "GL_SRGB_EXT", "GL_UNSIGNED_BYTE" ] + ], + "From GL_OES_texture_float": + [ + [ "GL_RGBA", "GL_RGBA", "GL_FLOAT" ], + [ "GL_RGB", "GL_RGB", "GL_FLOAT" ], + [ "GL_LUMINANCE_ALPHA", "GL_LUMINANCE_ALPHA", "GL_FLOAT" ], + [ "GL_LUMINANCE", "GL_LUMINANCE", "GL_FLOAT" ], + [ "GL_ALPHA", "GL_ALPHA", "GL_FLOAT" ] + ], + "From GL_OES_texture_half_float": + [ + [ "GL_RGBA", "GL_RGBA", "GL_HALF_FLOAT_OES" ], + [ "GL_RGB", "GL_RGB", "GL_HALF_FLOAT_OES" ], + [ "GL_LUMINANCE_ALPHA", "GL_LUMINANCE_ALPHA", "GL_HALF_FLOAT" ], + [ "GL_LUMINANCE_ALPHA", "GL_LUMINANCE_ALPHA", "GL_HALF_FLOAT_OES" ], + [ "GL_LUMINANCE", "GL_LUMINANCE", "GL_HALF_FLOAT" ], + [ "GL_LUMINANCE", "GL_LUMINANCE", "GL_HALF_FLOAT_OES" ], + [ "GL_ALPHA", "GL_ALPHA", "GL_HALF_FLOAT" ], + [ "GL_ALPHA", "GL_ALPHA", "GL_HALF_FLOAT_OES" ] + ], + "From GL_EXT_texture_format_BGRA8888": + [ + [ "GL_BGRA_EXT", "GL_BGRA_EXT", "GL_UNSIGNED_BYTE" ] + ], + "From GL_EXT_texture_storage": + [ + [ "GL_ALPHA8_EXT", "GL_ALPHA", "GL_UNSIGNED_BYTE" ], + [ "GL_LUMINANCE8_EXT", "GL_LUMINANCE", "GL_UNSIGNED_BYTE" ], + [ "GL_LUMINANCE8_ALPHA8_EXT", "GL_LUMINANCE_ALPHA", "GL_UNSIGNED_BYTE" ], + [ "GL_ALPHA32F_EXT", "GL_ALPHA", "GL_FLOAT" ], + [ "GL_LUMINANCE32F_EXT", "GL_LUMINANCE", "GL_FLOAT" ], + [ "GL_LUMINANCE_ALPHA32F_EXT", "GL_LUMINANCE_ALPHA", "GL_FLOAT" ], + [ "GL_ALPHA16F_EXT", "GL_ALPHA", "GL_HALF_FLOAT" ], + [ "GL_ALPHA16F_EXT", "GL_ALPHA", "GL_HALF_FLOAT_OES" ], + [ "GL_LUMINANCE16F_EXT", "GL_LUMINANCE", "GL_HALF_FLOAT" ], + [ "GL_LUMINANCE16F_EXT", "GL_LUMINANCE", "GL_HALF_FLOAT_OES" ], + [ "GL_LUMINANCE_ALPHA16F_EXT", "GL_LUMINANCE_ALPHA", "GL_HALF_FLOAT" ], + [ "GL_LUMINANCE_ALPHA16F_EXT", "GL_LUMINANCE_ALPHA", "GL_HALF_FLOAT_OES" ] + ], + "From GL_EXT_texture_storage and GL_EXT_texture_format_BGRA8888": + [ + [ "GL_BGRA8_EXT", "GL_BGRA_EXT", "GL_UNSIGNED_BYTE" ], + [ "GL_BGRA4_ANGLEX", "GL_BGRA_EXT", "GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT" ], + [ "GL_BGRA4_ANGLEX", "GL_BGRA_EXT", "GL_UNSIGNED_BYTE" ], + [ "GL_BGR5_A1_ANGLEX", "GL_BGRA_EXT", "GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT" ], + [ "GL_BGR5_A1_ANGLEX", "GL_BGRA_EXT", "GL_UNSIGNED_BYTE" ] + ], + "From GL_ANGLE_depth_texture and OES_depth_texture": + [ + [ "GL_DEPTH_COMPONENT32_OES", "GL_DEPTH_COMPONENT", "GL_UNSIGNED_INT_24_8" ], + [ "GL_DEPTH_COMPONENT", "GL_DEPTH_COMPONENT", "GL_UNSIGNED_SHORT" ], + [ "GL_DEPTH_COMPONENT", "GL_DEPTH_COMPONENT", "GL_UNSIGNED_INT" ] + ], + "From GL_EXT_texture_norm16": + [ + [ "GL_R16_EXT", "GL_RED", "GL_UNSIGNED_SHORT" ], + [ "GL_RG16_EXT", "GL_RG", "GL_UNSIGNED_SHORT" ], + [ "GL_RGB16_EXT", "GL_RGB", "GL_UNSIGNED_SHORT" ], + [ "GL_RGBA16_EXT", "GL_RGBA", "GL_UNSIGNED_SHORT" ], + [ "GL_R16_SNORM_EXT", "GL_RED", "GL_SHORT" ], + [ "GL_RG16_SNORM_EXT", "GL_RG", "GL_SHORT" ], + [ "GL_RGB16_SNORM_EXT", "GL_RGB", "GL_SHORT" ], + [ "GL_RGBA16_SNORM_EXT", "GL_RGBA", "GL_SHORT" ] + ] +} diff --git a/src/3rdparty/angle/src/libANGLE/features.h b/src/3rdparty/angle/src/libANGLE/features.h index ecf486dcf7..48a194ff0b 100644 --- a/src/3rdparty/angle/src/libANGLE/features.h +++ b/src/3rdparty/angle/src/libANGLE/features.h @@ -7,6 +7,8 @@ #ifndef LIBANGLE_FEATURES_H_ #define LIBANGLE_FEATURES_H_ +#include "common/platform.h" + #define ANGLE_DISABLED 0 #define ANGLE_ENABLED 1 @@ -50,4 +52,14 @@ #define ANGLE_PROGRAM_LINK_VALIDATE_UNIFORM_PRECISION ANGLE_ENABLED #endif +// Controls if our threading code uses std::async or falls back to single-threaded operations. +// TODO(jmadill): Enable on Linux once STL chrono headers are updated. +#if !defined(ANGLE_STD_ASYNC_WORKERS) +#if defined(ANGLE_PLATFORM_WINDOWS) +#define ANGLE_STD_ASYNC_WORKERS ANGLE_ENABLED +#else +#define ANGLE_STD_ASYNC_WORKERS ANGLE_DISABLED +#endif // defined(ANGLE_PLATFORM_WINDOWS) +#endif // !defined(ANGLE_STD_ASYNC_WORKERS) + #endif // LIBANGLE_FEATURES_H_ diff --git a/src/3rdparty/angle/src/libANGLE/format_map_autogen.cpp b/src/3rdparty/angle/src/libANGLE/format_map_autogen.cpp new file mode 100644 index 0000000000..a7f3ebafc8 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/format_map_autogen.cpp @@ -0,0 +1,1570 @@ +// GENERATED FILE - DO NOT EDIT. +// Generated by gen_format_map.py using data from format_map_data.json. +// ES3 format info from es3_format_type_combinations.json. +// +// Copyright 2017 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. +// +// format_map: +// Determining the sized internal format from a (format,type) pair. +// Also check es3 format combinations for validity. + +#include "angle_gl.h" +#include "common/debug.h" + +namespace gl +{ + +GLenum GetSizedFormatInternal(GLenum format, GLenum type) +{ + switch (format) + { + case GL_ALPHA: + switch (type) + { + case GL_FLOAT: + return GL_ALPHA32F_EXT; + case GL_HALF_FLOAT: + return GL_ALPHA16F_EXT; + case GL_HALF_FLOAT_OES: + return GL_ALPHA16F_EXT; + case GL_UNSIGNED_BYTE: + return GL_ALPHA8_EXT; + default: + break; + } + break; + + case GL_BGRA_EXT: + switch (type) + { + case GL_UNSIGNED_BYTE: + return GL_BGRA8_EXT; + case GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT: + return GL_BGR5_A1_ANGLEX; + case GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT: + return GL_BGRA4_ANGLEX; + case GL_UNSIGNED_SHORT_5_6_5: + return GL_BGR565_ANGLEX; + default: + break; + } + break; + + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: + switch (type) + { + case GL_UNSIGNED_BYTE: + return GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; + default: + break; + } + break; + + case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: + switch (type) + { + case GL_UNSIGNED_BYTE: + return GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE; + default: + break; + } + break; + + case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: + switch (type) + { + case GL_UNSIGNED_BYTE: + return GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE; + default: + break; + } + break; + + case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: + switch (type) + { + case GL_UNSIGNED_BYTE: + return GL_COMPRESSED_RGB_S3TC_DXT1_EXT; + default: + break; + } + break; + + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT: + switch (type) + { + case GL_UNSIGNED_BYTE: + return GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT; + default: + break; + } + break; + + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT: + switch (type) + { + case GL_UNSIGNED_BYTE: + return GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT; + default: + break; + } + break; + + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT: + switch (type) + { + case GL_UNSIGNED_BYTE: + return GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT; + default: + break; + } + break; + + case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT: + switch (type) + { + case GL_UNSIGNED_BYTE: + return GL_COMPRESSED_SRGB_S3TC_DXT1_EXT; + default: + break; + } + break; + + case GL_DEPTH_COMPONENT: + switch (type) + { + case GL_FLOAT: + return GL_DEPTH_COMPONENT32F; + case GL_UNSIGNED_INT: + return GL_DEPTH_COMPONENT32_OES; + case GL_UNSIGNED_SHORT: + return GL_DEPTH_COMPONENT16; + default: + break; + } + break; + + case GL_DEPTH_STENCIL: + switch (type) + { + case GL_FLOAT_32_UNSIGNED_INT_24_8_REV: + return GL_DEPTH32F_STENCIL8; + case GL_UNSIGNED_INT_24_8: + return GL_DEPTH24_STENCIL8; + default: + break; + } + break; + + case GL_LUMINANCE: + switch (type) + { + case GL_FLOAT: + return GL_LUMINANCE32F_EXT; + case GL_HALF_FLOAT: + return GL_LUMINANCE16F_EXT; + case GL_HALF_FLOAT_OES: + return GL_LUMINANCE16F_EXT; + case GL_UNSIGNED_BYTE: + return GL_LUMINANCE8_EXT; + default: + break; + } + break; + + case GL_LUMINANCE_ALPHA: + switch (type) + { + case GL_FLOAT: + return GL_LUMINANCE_ALPHA32F_EXT; + case GL_HALF_FLOAT: + return GL_LUMINANCE_ALPHA16F_EXT; + case GL_HALF_FLOAT_OES: + return GL_LUMINANCE_ALPHA16F_EXT; + case GL_UNSIGNED_BYTE: + return GL_LUMINANCE8_ALPHA8_EXT; + default: + break; + } + break; + + case GL_RED: + switch (type) + { + case GL_BYTE: + return GL_R8_SNORM; + case GL_FLOAT: + return GL_R32F; + case GL_HALF_FLOAT: + return GL_R16F; + case GL_HALF_FLOAT_OES: + return GL_R16F; + case GL_SHORT: + return GL_R16_SNORM_EXT; + case GL_UNSIGNED_BYTE: + return GL_R8; + case GL_UNSIGNED_SHORT: + return GL_R16_EXT; + default: + break; + } + break; + + case GL_RED_INTEGER: + switch (type) + { + case GL_BYTE: + return GL_R8I; + case GL_INT: + return GL_R32I; + case GL_SHORT: + return GL_R16I; + case GL_UNSIGNED_BYTE: + return GL_R8UI; + case GL_UNSIGNED_INT: + return GL_R32UI; + case GL_UNSIGNED_SHORT: + return GL_R16UI; + default: + break; + } + break; + + case GL_RG: + switch (type) + { + case GL_BYTE: + return GL_RG8_SNORM; + case GL_FLOAT: + return GL_RG32F; + case GL_HALF_FLOAT: + return GL_RG16F; + case GL_HALF_FLOAT_OES: + return GL_RG16F; + case GL_SHORT: + return GL_RG16_SNORM_EXT; + case GL_UNSIGNED_BYTE: + return GL_RG8; + case GL_UNSIGNED_SHORT: + return GL_RG16_EXT; + default: + break; + } + break; + + case GL_RGB: + switch (type) + { + case GL_BYTE: + return GL_RGB8_SNORM; + case GL_FLOAT: + return GL_RGB32F; + case GL_HALF_FLOAT: + return GL_RGB16F; + case GL_HALF_FLOAT_OES: + return GL_RGB16F; + case GL_SHORT: + return GL_RGB16_SNORM_EXT; + case GL_UNSIGNED_BYTE: + return GL_RGB8; + case GL_UNSIGNED_INT_10F_11F_11F_REV: + return GL_R11F_G11F_B10F; + case GL_UNSIGNED_INT_5_9_9_9_REV: + return GL_RGB9_E5; + case GL_UNSIGNED_SHORT: + return GL_RGB16_EXT; + case GL_UNSIGNED_SHORT_5_6_5: + return GL_RGB565; + default: + break; + } + break; + + case GL_RGBA: + switch (type) + { + case GL_BYTE: + return GL_RGBA8_SNORM; + case GL_FLOAT: + return GL_RGBA32F; + case GL_HALF_FLOAT: + return GL_RGBA16F; + case GL_HALF_FLOAT_OES: + return GL_RGBA16F; + case GL_SHORT: + return GL_RGBA16_SNORM_EXT; + case GL_UNSIGNED_BYTE: + return GL_RGBA8; + case GL_UNSIGNED_INT_2_10_10_10_REV: + return GL_RGB10_A2; + case GL_UNSIGNED_SHORT: + return GL_RGBA16_EXT; + case GL_UNSIGNED_SHORT_4_4_4_4: + return GL_RGBA4; + case GL_UNSIGNED_SHORT_5_5_5_1: + return GL_RGB5_A1; + default: + break; + } + break; + + case GL_RGBA_INTEGER: + switch (type) + { + case GL_BYTE: + return GL_RGBA8I; + case GL_INT: + return GL_RGBA32I; + case GL_SHORT: + return GL_RGBA16I; + case GL_UNSIGNED_BYTE: + return GL_RGBA8UI; + case GL_UNSIGNED_INT: + return GL_RGBA32UI; + case GL_UNSIGNED_INT_2_10_10_10_REV: + return GL_RGB10_A2UI; + case GL_UNSIGNED_SHORT: + return GL_RGBA16UI; + default: + break; + } + break; + + case GL_RGB_INTEGER: + switch (type) + { + case GL_BYTE: + return GL_RGB8I; + case GL_INT: + return GL_RGB32I; + case GL_SHORT: + return GL_RGB16I; + case GL_UNSIGNED_BYTE: + return GL_RGB8UI; + case GL_UNSIGNED_INT: + return GL_RGB32UI; + case GL_UNSIGNED_SHORT: + return GL_RGB16UI; + default: + break; + } + break; + + case GL_RG_INTEGER: + switch (type) + { + case GL_BYTE: + return GL_RG8I; + case GL_INT: + return GL_RG32I; + case GL_SHORT: + return GL_RG16I; + case GL_UNSIGNED_BYTE: + return GL_RG8UI; + case GL_UNSIGNED_INT: + return GL_RG32UI; + case GL_UNSIGNED_SHORT: + return GL_RG16UI; + default: + break; + } + break; + + case GL_SRGB_ALPHA_EXT: + switch (type) + { + case GL_UNSIGNED_BYTE: + return GL_SRGB8_ALPHA8; + default: + break; + } + break; + + case GL_SRGB_EXT: + switch (type) + { + case GL_UNSIGNED_BYTE: + return GL_SRGB8; + default: + break; + } + break; + + case GL_STENCIL: + switch (type) + { + case GL_UNSIGNED_BYTE: + return GL_STENCIL_INDEX8; + default: + break; + } + break; + + case GL_NONE: + return GL_NONE; + + default: + break; + } + + return GL_NONE; +} + +bool ValidES3Format(GLenum format) +{ + switch (format) + { + case GL_ALPHA: + case GL_BGRA_EXT: + case GL_DEPTH_COMPONENT: + case GL_DEPTH_STENCIL: + case GL_LUMINANCE: + case GL_LUMINANCE_ALPHA: + case GL_RED: + case GL_RED_INTEGER: + case GL_RG: + case GL_RGB: + case GL_RGBA: + case GL_RGBA_INTEGER: + case GL_RGB_INTEGER: + case GL_RG_INTEGER: + case GL_SRGB_ALPHA_EXT: + case GL_SRGB_EXT: + return true; + + default: + return false; + } +} + +bool ValidES3Type(GLenum type) +{ + switch (type) + { + case GL_BYTE: + case GL_FLOAT: + case GL_FLOAT_32_UNSIGNED_INT_24_8_REV: + case GL_HALF_FLOAT: + case GL_HALF_FLOAT_OES: + case GL_INT: + case GL_SHORT: + case GL_UNSIGNED_BYTE: + case GL_UNSIGNED_INT: + case GL_UNSIGNED_INT_10F_11F_11F_REV: + case GL_UNSIGNED_INT_24_8: + case GL_UNSIGNED_INT_2_10_10_10_REV: + case GL_UNSIGNED_INT_5_9_9_9_REV: + case GL_UNSIGNED_SHORT: + case GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT: + case GL_UNSIGNED_SHORT_4_4_4_4: + case GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT: + case GL_UNSIGNED_SHORT_5_5_5_1: + case GL_UNSIGNED_SHORT_5_6_5: + return true; + + default: + return false; + } +} + +bool ValidES3FormatCombination(GLenum format, GLenum type, GLenum internalFormat) +{ + ASSERT(ValidES3Format(format) && ValidES3Type(type)); + + switch (format) + { + case GL_RGB_INTEGER: + switch (type) + { + case GL_INT: + { + switch (internalFormat) + { + case GL_RGB32I: + return true; + default: + break; + } + break; + } + case GL_UNSIGNED_SHORT: + { + switch (internalFormat) + { + case GL_RGB16UI: + return true; + default: + break; + } + break; + } + case GL_SHORT: + { + switch (internalFormat) + { + case GL_RGB16I: + return true; + default: + break; + } + break; + } + case GL_UNSIGNED_BYTE: + { + switch (internalFormat) + { + case GL_RGB8UI: + return true; + default: + break; + } + break; + } + case GL_BYTE: + { + switch (internalFormat) + { + case GL_RGB8I: + return true; + default: + break; + } + break; + } + case GL_UNSIGNED_INT: + { + switch (internalFormat) + { + case GL_RGB32UI: + return true; + default: + break; + } + break; + } + default: + break; + } + break; + + case GL_RGBA_INTEGER: + switch (type) + { + case GL_INT: + { + switch (internalFormat) + { + case GL_RGBA32I: + return true; + default: + break; + } + break; + } + case GL_UNSIGNED_SHORT: + { + switch (internalFormat) + { + case GL_RGBA16UI: + return true; + default: + break; + } + break; + } + case GL_UNSIGNED_INT_2_10_10_10_REV: + { + switch (internalFormat) + { + case GL_RGB10_A2UI: + return true; + default: + break; + } + break; + } + case GL_SHORT: + { + switch (internalFormat) + { + case GL_RGBA16I: + return true; + default: + break; + } + break; + } + case GL_UNSIGNED_BYTE: + { + switch (internalFormat) + { + case GL_RGBA8UI: + return true; + default: + break; + } + break; + } + case GL_BYTE: + { + switch (internalFormat) + { + case GL_RGBA8I: + return true; + default: + break; + } + break; + } + case GL_UNSIGNED_INT: + { + switch (internalFormat) + { + case GL_RGBA32UI: + return true; + default: + break; + } + break; + } + default: + break; + } + break; + + case GL_RGB: + switch (type) + { + case GL_UNSIGNED_INT_10F_11F_11F_REV: + { + switch (internalFormat) + { + case GL_R11F_G11F_B10F: + return true; + default: + break; + } + break; + } + case GL_UNSIGNED_SHORT: + { + switch (internalFormat) + { + case GL_RGB16_EXT: + return true; + default: + break; + } + break; + } + case GL_SHORT: + { + switch (internalFormat) + { + case GL_RGB16_SNORM_EXT: + return true; + default: + break; + } + break; + } + case GL_UNSIGNED_BYTE: + { + switch (internalFormat) + { + case GL_RGB: + case GL_RGB8: + case GL_RGB565: + case GL_SRGB8: + return true; + default: + break; + } + break; + } + case GL_UNSIGNED_SHORT_5_6_5: + { + switch (internalFormat) + { + case GL_RGB: + case GL_RGB565: + return true; + default: + break; + } + break; + } + case GL_HALF_FLOAT_OES: + { + switch (internalFormat) + { + case GL_RGB: + case GL_RGB16F: + case GL_R11F_G11F_B10F: + case GL_RGB9_E5: + return true; + default: + break; + } + break; + } + case GL_HALF_FLOAT: + { + switch (internalFormat) + { + case GL_RGB16F: + case GL_R11F_G11F_B10F: + case GL_RGB9_E5: + return true; + default: + break; + } + break; + } + case GL_FLOAT: + { + switch (internalFormat) + { + case GL_RGB: + case GL_RGB32F: + case GL_RGB16F: + case GL_R11F_G11F_B10F: + case GL_RGB9_E5: + return true; + default: + break; + } + break; + } + case GL_BYTE: + { + switch (internalFormat) + { + case GL_RGB8_SNORM: + return true; + default: + break; + } + break; + } + case GL_UNSIGNED_INT_5_9_9_9_REV: + { + switch (internalFormat) + { + case GL_RGB9_E5: + return true; + default: + break; + } + break; + } + default: + break; + } + break; + + case GL_LUMINANCE_ALPHA: + switch (type) + { + case GL_HALF_FLOAT: + { + switch (internalFormat) + { + case GL_LUMINANCE_ALPHA: + case GL_LUMINANCE_ALPHA16F_EXT: + return true; + default: + break; + } + break; + } + case GL_FLOAT: + { + switch (internalFormat) + { + case GL_LUMINANCE_ALPHA: + case GL_LUMINANCE_ALPHA32F_EXT: + return true; + default: + break; + } + break; + } + case GL_UNSIGNED_BYTE: + { + switch (internalFormat) + { + case GL_LUMINANCE_ALPHA: + case GL_LUMINANCE8_ALPHA8_EXT: + return true; + default: + break; + } + break; + } + case GL_HALF_FLOAT_OES: + { + switch (internalFormat) + { + case GL_LUMINANCE_ALPHA: + case GL_LUMINANCE_ALPHA16F_EXT: + return true; + default: + break; + } + break; + } + default: + break; + } + break; + + case GL_ALPHA: + switch (type) + { + case GL_HALF_FLOAT: + { + switch (internalFormat) + { + case GL_ALPHA: + case GL_ALPHA16F_EXT: + return true; + default: + break; + } + break; + } + case GL_FLOAT: + { + switch (internalFormat) + { + case GL_ALPHA: + case GL_ALPHA32F_EXT: + return true; + default: + break; + } + break; + } + case GL_UNSIGNED_BYTE: + { + switch (internalFormat) + { + case GL_ALPHA: + case GL_ALPHA8_EXT: + return true; + default: + break; + } + break; + } + case GL_HALF_FLOAT_OES: + { + switch (internalFormat) + { + case GL_ALPHA: + case GL_ALPHA16F_EXT: + return true; + default: + break; + } + break; + } + default: + break; + } + break; + + case GL_RGBA: + switch (type) + { + case GL_UNSIGNED_SHORT: + { + switch (internalFormat) + { + case GL_RGBA16_EXT: + return true; + default: + break; + } + break; + } + case GL_UNSIGNED_INT_2_10_10_10_REV: + { + switch (internalFormat) + { + case GL_RGB10_A2: + case GL_RGB5_A1: + return true; + default: + break; + } + break; + } + case GL_SHORT: + { + switch (internalFormat) + { + case GL_RGBA16_SNORM_EXT: + return true; + default: + break; + } + break; + } + case GL_UNSIGNED_SHORT_4_4_4_4: + { + switch (internalFormat) + { + case GL_RGBA: + case GL_RGBA4: + return true; + default: + break; + } + break; + } + case GL_UNSIGNED_BYTE: + { + switch (internalFormat) + { + case GL_RGBA: + case GL_RGBA8: + case GL_RGB5_A1: + case GL_RGBA4: + case GL_SRGB8_ALPHA8: + return true; + default: + break; + } + break; + } + case GL_HALF_FLOAT_OES: + { + switch (internalFormat) + { + case GL_RGBA: + case GL_RGBA16F: + return true; + default: + break; + } + break; + } + case GL_HALF_FLOAT: + { + switch (internalFormat) + { + case GL_RGBA16F: + return true; + default: + break; + } + break; + } + case GL_FLOAT: + { + switch (internalFormat) + { + case GL_RGBA: + case GL_RGBA32F: + case GL_RGBA16F: + return true; + default: + break; + } + break; + } + case GL_BYTE: + { + switch (internalFormat) + { + case GL_RGBA8_SNORM: + return true; + default: + break; + } + break; + } + case GL_UNSIGNED_SHORT_5_5_5_1: + { + switch (internalFormat) + { + case GL_RGBA: + case GL_RGB5_A1: + return true; + default: + break; + } + break; + } + default: + break; + } + break; + + case GL_LUMINANCE: + switch (type) + { + case GL_HALF_FLOAT: + { + switch (internalFormat) + { + case GL_LUMINANCE: + case GL_LUMINANCE16F_EXT: + return true; + default: + break; + } + break; + } + case GL_FLOAT: + { + switch (internalFormat) + { + case GL_LUMINANCE: + case GL_LUMINANCE32F_EXT: + return true; + default: + break; + } + break; + } + case GL_UNSIGNED_BYTE: + { + switch (internalFormat) + { + case GL_LUMINANCE: + case GL_LUMINANCE8_EXT: + return true; + default: + break; + } + break; + } + case GL_HALF_FLOAT_OES: + { + switch (internalFormat) + { + case GL_LUMINANCE: + case GL_LUMINANCE16F_EXT: + return true; + default: + break; + } + break; + } + default: + break; + } + break; + + case GL_RG_INTEGER: + switch (type) + { + case GL_INT: + { + switch (internalFormat) + { + case GL_RG32I: + return true; + default: + break; + } + break; + } + case GL_UNSIGNED_SHORT: + { + switch (internalFormat) + { + case GL_RG16UI: + return true; + default: + break; + } + break; + } + case GL_SHORT: + { + switch (internalFormat) + { + case GL_RG16I: + return true; + default: + break; + } + break; + } + case GL_UNSIGNED_BYTE: + { + switch (internalFormat) + { + case GL_RG8UI: + return true; + default: + break; + } + break; + } + case GL_BYTE: + { + switch (internalFormat) + { + case GL_RG8I: + return true; + default: + break; + } + break; + } + case GL_UNSIGNED_INT: + { + switch (internalFormat) + { + case GL_RG32UI: + return true; + default: + break; + } + break; + } + default: + break; + } + break; + + case GL_RED_INTEGER: + switch (type) + { + case GL_INT: + { + switch (internalFormat) + { + case GL_R32I: + return true; + default: + break; + } + break; + } + case GL_UNSIGNED_SHORT: + { + switch (internalFormat) + { + case GL_R16UI: + return true; + default: + break; + } + break; + } + case GL_SHORT: + { + switch (internalFormat) + { + case GL_R16I: + return true; + default: + break; + } + break; + } + case GL_UNSIGNED_BYTE: + { + switch (internalFormat) + { + case GL_R8UI: + return true; + default: + break; + } + break; + } + case GL_BYTE: + { + switch (internalFormat) + { + case GL_R8I: + return true; + default: + break; + } + break; + } + case GL_UNSIGNED_INT: + { + switch (internalFormat) + { + case GL_R32UI: + return true; + default: + break; + } + break; + } + default: + break; + } + break; + + case GL_RED: + switch (type) + { + case GL_UNSIGNED_SHORT: + { + switch (internalFormat) + { + case GL_R16_EXT: + return true; + default: + break; + } + break; + } + case GL_SHORT: + { + switch (internalFormat) + { + case GL_R16_SNORM_EXT: + return true; + default: + break; + } + break; + } + case GL_FLOAT: + { + switch (internalFormat) + { + case GL_RED: + case GL_R32F: + case GL_R16F: + return true; + default: + break; + } + break; + } + case GL_HALF_FLOAT_OES: + { + switch (internalFormat) + { + case GL_RED: + case GL_R16F: + return true; + default: + break; + } + break; + } + case GL_HALF_FLOAT: + { + switch (internalFormat) + { + case GL_RED: + case GL_R16F: + return true; + default: + break; + } + break; + } + case GL_UNSIGNED_BYTE: + { + switch (internalFormat) + { + case GL_RED: + case GL_R8: + return true; + default: + break; + } + break; + } + case GL_BYTE: + { + switch (internalFormat) + { + case GL_R8_SNORM: + return true; + default: + break; + } + break; + } + default: + break; + } + break; + + case GL_DEPTH_COMPONENT: + switch (type) + { + case GL_UNSIGNED_INT: + { + switch (internalFormat) + { + case GL_DEPTH_COMPONENT: + case GL_DEPTH_COMPONENT24: + case GL_DEPTH_COMPONENT16: + return true; + default: + break; + } + break; + } + case GL_UNSIGNED_INT_24_8: + { + switch (internalFormat) + { + case GL_DEPTH_COMPONENT32_OES: + return true; + default: + break; + } + break; + } + case GL_FLOAT: + { + switch (internalFormat) + { + case GL_DEPTH_COMPONENT32F: + return true; + default: + break; + } + break; + } + case GL_UNSIGNED_SHORT: + { + switch (internalFormat) + { + case GL_DEPTH_COMPONENT: + case GL_DEPTH_COMPONENT16: + return true; + default: + break; + } + break; + } + default: + break; + } + break; + + case GL_DEPTH_STENCIL: + switch (type) + { + case GL_UNSIGNED_INT_24_8: + { + switch (internalFormat) + { + case GL_DEPTH_STENCIL: + case GL_DEPTH24_STENCIL8: + return true; + default: + break; + } + break; + } + case GL_FLOAT_32_UNSIGNED_INT_24_8_REV: + { + switch (internalFormat) + { + case GL_DEPTH32F_STENCIL8: + return true; + default: + break; + } + break; + } + default: + break; + } + break; + + case GL_SRGB_EXT: + switch (type) + { + case GL_UNSIGNED_BYTE: + { + switch (internalFormat) + { + case GL_SRGB_EXT: + case GL_SRGB8: + return true; + default: + break; + } + break; + } + default: + break; + } + break; + + case GL_SRGB_ALPHA_EXT: + switch (type) + { + case GL_UNSIGNED_BYTE: + { + switch (internalFormat) + { + case GL_SRGB_ALPHA_EXT: + case GL_SRGB8_ALPHA8_EXT: + return true; + default: + break; + } + break; + } + default: + break; + } + break; + + case GL_RG: + switch (type) + { + case GL_UNSIGNED_SHORT: + { + switch (internalFormat) + { + case GL_RG16_EXT: + return true; + default: + break; + } + break; + } + case GL_SHORT: + { + switch (internalFormat) + { + case GL_RG16_SNORM_EXT: + return true; + default: + break; + } + break; + } + case GL_FLOAT: + { + switch (internalFormat) + { + case GL_RG: + case GL_RG32F: + case GL_RG16F: + return true; + default: + break; + } + break; + } + case GL_HALF_FLOAT_OES: + { + switch (internalFormat) + { + case GL_RG: + case GL_RG16F: + return true; + default: + break; + } + break; + } + case GL_HALF_FLOAT: + { + switch (internalFormat) + { + case GL_RG: + case GL_RG16F: + return true; + default: + break; + } + break; + } + case GL_UNSIGNED_BYTE: + { + switch (internalFormat) + { + case GL_RG: + case GL_RG8: + return true; + default: + break; + } + break; + } + case GL_BYTE: + { + switch (internalFormat) + { + case GL_RG8_SNORM: + return true; + default: + break; + } + break; + } + default: + break; + } + break; + + case GL_BGRA_EXT: + switch (type) + { + case GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT: + { + switch (internalFormat) + { + case GL_BGRA4_ANGLEX: + return true; + default: + break; + } + break; + } + case GL_UNSIGNED_BYTE: + { + switch (internalFormat) + { + case GL_BGRA8_EXT: + case GL_BGRA4_ANGLEX: + case GL_BGR5_A1_ANGLEX: + case GL_BGRA_EXT: + return true; + default: + break; + } + break; + } + case GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT: + { + switch (internalFormat) + { + case GL_BGR5_A1_ANGLEX: + return true; + default: + break; + } + break; + } + default: + break; + } + break; + + default: + UNREACHABLE(); + break; + } + + return false; +} + +} // namespace gl diff --git a/src/3rdparty/angle/src/libANGLE/format_map_data.json b/src/3rdparty/angle/src/libANGLE/format_map_data.json new file mode 100644 index 0000000000..a4f1c98b4d --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/format_map_data.json @@ -0,0 +1,142 @@ +{ + "GL_RGBA": { + "GL_UNSIGNED_BYTE": "GL_RGBA8", + "GL_UNSIGNED_SHORT": "GL_RGBA16_EXT", + "GL_BYTE": "GL_RGBA8_SNORM", + "GL_SHORT": "GL_RGBA16_SNORM_EXT", + "GL_UNSIGNED_SHORT_4_4_4_4": "GL_RGBA4", + "GL_UNSIGNED_SHORT_5_5_5_1": "GL_RGB5_A1", + "GL_UNSIGNED_INT_2_10_10_10_REV": "GL_RGB10_A2", + "GL_FLOAT": "GL_RGBA32F", + "GL_HALF_FLOAT": "GL_RGBA16F", + "GL_HALF_FLOAT_OES": "GL_RGBA16F" + }, + "GL_RGBA_INTEGER": { + "GL_UNSIGNED_BYTE": "GL_RGBA8UI", + "GL_BYTE": "GL_RGBA8I", + "GL_UNSIGNED_SHORT": "GL_RGBA16UI", + "GL_SHORT": "GL_RGBA16I", + "GL_UNSIGNED_INT": "GL_RGBA32UI", + "GL_INT": "GL_RGBA32I", + "GL_UNSIGNED_INT_2_10_10_10_REV": "GL_RGB10_A2UI" + }, + "GL_RGB": { + "GL_UNSIGNED_BYTE": "GL_RGB8", + "GL_UNSIGNED_SHORT": "GL_RGB16_EXT", + "GL_BYTE": "GL_RGB8_SNORM", + "GL_SHORT": "GL_RGB16_SNORM_EXT", + "GL_UNSIGNED_SHORT_5_6_5": "GL_RGB565", + "GL_UNSIGNED_INT_10F_11F_11F_REV": "GL_R11F_G11F_B10F", + "GL_UNSIGNED_INT_5_9_9_9_REV": "GL_RGB9_E5", + "GL_FLOAT": "GL_RGB32F", + "GL_HALF_FLOAT": "GL_RGB16F", + "GL_HALF_FLOAT_OES": "GL_RGB16F" + }, + "GL_RGB_INTEGER": { + "GL_UNSIGNED_BYTE": "GL_RGB8UI", + "GL_BYTE": "GL_RGB8I", "GL_UNSIGNED_SHORT": "GL_RGB16UI", + "GL_SHORT": "GL_RGB16I", + "GL_UNSIGNED_INT": "GL_RGB32UI", + "GL_INT": "GL_RGB32I" + }, + "GL_RG": { + "GL_UNSIGNED_BYTE": "GL_RG8", + "GL_UNSIGNED_SHORT": "GL_RG16_EXT", + "GL_BYTE": "GL_RG8_SNORM", + "GL_SHORT": "GL_RG16_SNORM_EXT", + "GL_FLOAT": "GL_RG32F", + "GL_HALF_FLOAT": "GL_RG16F", + "GL_HALF_FLOAT_OES": "GL_RG16F" + }, + "GL_RG_INTEGER": { + "GL_UNSIGNED_BYTE": "GL_RG8UI", + "GL_BYTE": "GL_RG8I", + "GL_UNSIGNED_SHORT": "GL_RG16UI", + "GL_SHORT": "GL_RG16I", + "GL_UNSIGNED_INT": "GL_RG32UI", + "GL_INT": "GL_RG32I" + }, + "GL_RED": { + "GL_UNSIGNED_BYTE": "GL_R8", + "GL_UNSIGNED_SHORT": "GL_R16_EXT", + "GL_BYTE": "GL_R8_SNORM", + "GL_SHORT": "GL_R16_SNORM_EXT", + "GL_FLOAT": "GL_R32F", + "GL_HALF_FLOAT": "GL_R16F", + "GL_HALF_FLOAT_OES": "GL_R16F" + }, + "GL_RED_INTEGER": { + "GL_UNSIGNED_BYTE": "GL_R8UI", + "GL_BYTE": "GL_R8I", + "GL_UNSIGNED_SHORT": "GL_R16UI", + "GL_SHORT": "GL_R16I", + "GL_UNSIGNED_INT": "GL_R32UI", + "GL_INT": "GL_R32I" + }, + "GL_LUMINANCE_ALPHA": { + "GL_UNSIGNED_BYTE": "GL_LUMINANCE8_ALPHA8_EXT", + "GL_FLOAT": "GL_LUMINANCE_ALPHA32F_EXT", + "GL_HALF_FLOAT": "GL_LUMINANCE_ALPHA16F_EXT", + "GL_HALF_FLOAT_OES": "GL_LUMINANCE_ALPHA16F_EXT" + }, + "GL_LUMINANCE": { + "GL_UNSIGNED_BYTE": "GL_LUMINANCE8_EXT", + "GL_FLOAT": "GL_LUMINANCE32F_EXT", + "GL_HALF_FLOAT": "GL_LUMINANCE16F_EXT", + "GL_HALF_FLOAT_OES": "GL_LUMINANCE16F_EXT" + }, + "GL_ALPHA": { + "GL_UNSIGNED_BYTE": "GL_ALPHA8_EXT", + "GL_FLOAT": "GL_ALPHA32F_EXT", + "GL_HALF_FLOAT": "GL_ALPHA16F_EXT", + "GL_HALF_FLOAT_OES": "GL_ALPHA16F_EXT" + }, + "GL_BGRA_EXT": { + "GL_UNSIGNED_BYTE": "GL_BGRA8_EXT", + "GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT": "GL_BGRA4_ANGLEX", + "GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT": "GL_BGR5_A1_ANGLEX", + "GL_UNSIGNED_SHORT_5_6_5": "GL_BGR565_ANGLEX" + }, + "GL_SRGB_EXT": { + "GL_UNSIGNED_BYTE": "GL_SRGB8" + }, + "GL_SRGB_ALPHA_EXT": { + "GL_UNSIGNED_BYTE": "GL_SRGB8_ALPHA8" + }, + "GL_COMPRESSED_RGB_S3TC_DXT1_EXT": { + "GL_UNSIGNED_BYTE": "GL_COMPRESSED_RGB_S3TC_DXT1_EXT" + }, + "GL_COMPRESSED_RGBA_S3TC_DXT1_EXT": { + "GL_UNSIGNED_BYTE": "GL_COMPRESSED_RGBA_S3TC_DXT1_EXT" + }, + "GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE": { + "GL_UNSIGNED_BYTE": "GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE" + }, + "GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE": { + "GL_UNSIGNED_BYTE": "GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE" + }, + "GL_COMPRESSED_SRGB_S3TC_DXT1_EXT": { + "GL_UNSIGNED_BYTE": "GL_COMPRESSED_SRGB_S3TC_DXT1_EXT" + }, + "GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT": { + "GL_UNSIGNED_BYTE": "GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT" + }, + "GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT": { + "GL_UNSIGNED_BYTE": "GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT" + }, + "GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT": { + "GL_UNSIGNED_BYTE": "GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT" + }, + "GL_DEPTH_COMPONENT": { + "GL_UNSIGNED_SHORT": "GL_DEPTH_COMPONENT16", + "GL_UNSIGNED_INT": "GL_DEPTH_COMPONENT32_OES", + "GL_FLOAT": "GL_DEPTH_COMPONENT32F" + }, + "GL_STENCIL": { + "GL_UNSIGNED_BYTE": "GL_STENCIL_INDEX8" + }, + "GL_DEPTH_STENCIL": { + "GL_UNSIGNED_INT_24_8": "GL_DEPTH24_STENCIL8", + "GL_FLOAT_32_UNSIGNED_INT_24_8_REV": "GL_DEPTH32F_STENCIL8" + } +} diff --git a/src/3rdparty/angle/src/libANGLE/formatutils.cpp b/src/3rdparty/angle/src/libANGLE/formatutils.cpp index f8b9a8bab8..67bb2efdea 100644 --- a/src/3rdparty/angle/src/libANGLE/formatutils.cpp +++ b/src/3rdparty/angle/src/libANGLE/formatutils.cpp @@ -6,11 +6,13 @@ // formatutils.cpp: Queries for GL image formats. -#include "common/mathutil.h" #include "libANGLE/formatutils.h" + +#include "common/mathutil.h" #include "libANGLE/Context.h" #include "libANGLE/Framebuffer.h" -#include "libANGLE/renderer/Renderer.h" + +using namespace angle; namespace gl { @@ -18,116 +20,28 @@ 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. +GLenum GetSizedFormatInternal(GLenum format, GLenum type); -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); +namespace +{ +using InternalFormatInfoMap = + std::unordered_map>; - return map; +} // anonymous namespace + +FormatType::FormatType() : format(GL_NONE), type(GL_NONE) +{ +} + +FormatType::FormatType(GLenum format_, GLenum type_) : format(format_), type(type_) +{ +} + +bool FormatType::operator<(const FormatType &other) const +{ + if (format != other.format) + return format < other.format; + return type < other.type; } Type::Type() @@ -158,20 +72,20 @@ bool operator<(const Type& a, const Type& b) } // Information about internal formats -static bool AlwaysSupported(GLuint, const Extensions &) +static bool AlwaysSupported(const Version &, const Extensions &) { return true; } -static bool NeverSupported(GLuint, const Extensions &) +static bool NeverSupported(const Version &, const Extensions &) { return false; } -template -static bool RequireES(GLuint clientVersion, const Extensions &) +template +static bool RequireES(const Version &clientVersion, const Extensions &) { - return clientVersion >= minCoreGLVersion; + return clientVersion >= Version(minCoreGLMajorVersion, minCoreGLMinorVersion); } // Pointer to a boolean memeber of the Extensions struct @@ -179,96 +93,192 @@ typedef bool(Extensions::*ExtensionBool); // Check support for a single extension template -static bool RequireExt(GLuint, const Extensions & extensions) +static bool RequireExt(const Version &, 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) +template +static bool RequireESOrExt(const Version &clientVersion, const Extensions &extensions) { - return clientVersion >= minCoreGLVersion || extensions.*bool1; + return clientVersion >= Version(minCoreGLMajorVersion, minCoreGLMinorVersion) || + extensions.*bool1; } // Check for a minimum client version or two extensions -template -static bool RequireESOrExtAndExt(GLuint clientVersion, const Extensions &extensions) +template +static bool RequireESOrExtAndExt(const Version &clientVersion, const Extensions &extensions) { - return clientVersion >= minCoreGLVersion || (extensions.*bool1 && extensions.*bool2); + return clientVersion >= Version(minCoreGLMajorVersion, minCoreGLMinorVersion) || + (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) +template +static bool RequireESOrExtOrExt(const Version &clientVersion, const Extensions &extensions) { - return clientVersion >= minCoreGLVersion || extensions.*bool1 || extensions.*bool2; + return clientVersion >= Version(minCoreGLMajorVersion, minCoreGLMinorVersion) || + extensions.*bool1 || extensions.*bool2; } // Check support for two extensions template -static bool RequireExtAndExt(GLuint, const Extensions &extensions) +static bool RequireExtAndExt(const Version &, const Extensions &extensions) { return extensions.*bool1 && extensions.*bool2; } // Check support for either of two extensions template -static bool RequireExtOrExt(GLuint, const Extensions &extensions) +static bool RequireExtOrExt(const Version &, const Extensions &extensions) { return extensions.*bool1 || extensions.*bool2; } // Special function for half float formats with three or four channels. -static bool HalfFloatSupport(GLuint clientVersion, const Extensions &extensions) +static bool HalfFloatSupport(const Version &clientVersion, const Extensions &extensions) { - return clientVersion >= 3 || extensions.textureHalfFloat; + return clientVersion >= Version(3, 0) || extensions.textureHalfFloat; } -static bool HalfFloatRenderableSupport(GLuint clientVersion, const Extensions &extensions) +static bool HalfFloatRGBRenderableSupport(const Version &clientVersion, + const Extensions &extensions) { return HalfFloatSupport(clientVersion, extensions) && extensions.colorBufferHalfFloat; } +static bool HalfFloatRGBARenderableSupport(const Version &clientVersion, + const Extensions &extensions) +{ + return HalfFloatSupport(clientVersion, extensions) && + (extensions.colorBufferHalfFloat || extensions.colorBufferFloat); +} + // Special function for half float formats with one or two channels. -static bool HalfFloatSupportRG(GLuint clientVersion, const Extensions &extensions) + +// R16F, RG16F +static bool HalfFloatRGSupport(const Version &clientVersion, const Extensions &extensions) +{ + return clientVersion >= Version(3, 0) || (extensions.textureHalfFloat && extensions.textureRG); +} + +// R16F, RG16F +static bool HalfFloatRGRenderableSupport(const Version &clientVersion, const Extensions &extensions) { - return clientVersion >= 3 || (extensions.textureHalfFloat && extensions.textureRG); + // It's unclear if EXT_color_buffer_half_float gives renderability to non-OES half float + // textures + return HalfFloatRGSupport(clientVersion, extensions) && + (extensions.colorBufferHalfFloat || extensions.colorBufferFloat); } -static bool HalfFloatRenderableSupportRG(GLuint clientVersion, const Extensions &extensions) +// RED + HALF_FLOAT_OES, RG + HALF_FLOAT_OES +static bool UnsizedHalfFloatOESRGSupport(const Version &, const Extensions &extensions) { - return HalfFloatSupportRG(clientVersion, extensions) && extensions.colorBufferHalfFloat; + return extensions.textureHalfFloat && extensions.textureRG; +} + +// RED + HALF_FLOAT_OES, RG + HALF_FLOAT_OES +static bool UnsizedHalfFloatOESRGRenderableSupport(const Version &clientVersion, + const Extensions &extensions) +{ + return UnsizedHalfFloatOESRGSupport(clientVersion, extensions) && + extensions.colorBufferHalfFloat; +} + +// RGB + HALF_FLOAT_OES, RGBA + HALF_FLOAT_OES +static bool UnsizedHalfFloatOESSupport(const Version &clientVersion, const Extensions &extensions) +{ + return extensions.textureHalfFloat; +} + +// RGB + HALF_FLOAT_OES, RGBA + HALF_FLOAT_OES +static bool UnsizedHalfFloatOESRenderableSupport(const Version &clientVersion, + const Extensions &extensions) +{ + return UnsizedHalfFloatOESSupport(clientVersion, extensions) && extensions.colorBufferHalfFloat; } // Special function for float formats with three or four channels. -static bool FloatSupport(GLuint clientVersion, const Extensions &extensions) + +// RGB32F, RGBA32F +static bool FloatSupport(const Version &clientVersion, const Extensions &extensions) { - return clientVersion >= 3 || extensions.textureFloat; + return clientVersion >= Version(3, 0) || extensions.textureFloat; } -static bool FloatRenderableSupport(GLuint clientVersion, const Extensions &extensions) +// RGB32F +static bool FloatRGBRenderableSupport(const Version &clientVersion, const Extensions &extensions) +{ + return FloatSupport(clientVersion, extensions) && extensions.colorBufferFloatRGB; +} + +// RGBA32F +static bool FloatRGBARenderableSupport(const Version &clientVersion, const Extensions &extensions) { - // We don't expose colorBufferFloat in ES2, but we silently support rendering to float. return FloatSupport(clientVersion, extensions) && - (extensions.colorBufferFloat || clientVersion == 2); + (extensions.colorBufferFloat || extensions.colorBufferFloatRGBA); +} + +// RGB + FLOAT, RGBA + FLOAT +static bool UnsizedFloatSupport(const Version &clientVersion, const Extensions &extensions) +{ + return extensions.textureFloat; +} + +// RGB + FLOAT +static bool UnsizedFloatRGBRenderableSupport(const Version &clientVersion, + const Extensions &extensions) +{ + return UnsizedFloatSupport(clientVersion, extensions) && extensions.colorBufferFloatRGB; +} + +// RGBA + FLOAT +static bool UnsizedFloatRGBARenderableSupport(const Version &clientVersion, + const Extensions &extensions) +{ + return UnsizedFloatSupport(clientVersion, extensions) && + (extensions.colorBufferFloatRGBA || extensions.colorBufferFloat); } // Special function for float formats with one or two channels. -static bool FloatSupportRG(GLuint clientVersion, const Extensions &extensions) + +// R32F, RG32F +static bool FloatRGSupport(const Version &clientVersion, const Extensions &extensions) +{ + return clientVersion >= Version(3, 0) || (extensions.textureFloat && extensions.textureRG); +} + +// R32F, RG32F +static bool FloatRGRenderableSupport(const Version &clientVersion, const Extensions &extensions) { - return clientVersion >= 3 || (extensions.textureFloat && extensions.textureRG); + return FloatRGSupport(clientVersion, extensions) && extensions.colorBufferFloat; } -static bool FloatRenderableSupportRG(GLuint clientVersion, const Extensions &extensions) +// RED + FLOAT, RG + FLOAT +static bool UnsizedFloatRGSupport(const Version &clientVersion, const Extensions &extensions) { - // We don't expose colorBufferFloat in ES2, but we silently support rendering to float. - return FloatSupportRG(clientVersion, extensions) && - (extensions.colorBufferFloat || clientVersion == 2); + return extensions.textureFloat && extensions.textureRG; +} + +// RED + FLOAT, RG + FLOAT +static bool UnsizedFloatRGRenderableSupport(const Version &clientVersion, + const Extensions &extensions) +{ + return FloatRGSupport(clientVersion, extensions) && extensions.colorBufferFloat; } InternalFormat::InternalFormat() - : redBits(0), + : internalFormat(GL_NONE), + sized(false), + sizedInternalFormat(GL_NONE), + redBits(0), greenBits(0), blueBits(0), luminanceBits(0), @@ -291,32 +301,252 @@ InternalFormat::InternalFormat() { } -static InternalFormat UnsizedFormat(GLenum format, InternalFormat::SupportCheckFunction textureSupport, - InternalFormat::SupportCheckFunction renderSupport, - InternalFormat::SupportCheckFunction filterSupport) +InternalFormat::InternalFormat(const InternalFormat &other) = default; + +bool InternalFormat::isLUMA() const { - InternalFormat formatInfo; - formatInfo.format = format; - formatInfo.textureSupport = textureSupport; - formatInfo.renderSupport = renderSupport; - formatInfo.filterSupport = filterSupport; - return formatInfo; + return ((redBits + greenBits + blueBits + depthBits + stencilBits) == 0 && + (luminanceBits + alphaBits) > 0); +} + +GLenum InternalFormat::getReadPixelsFormat() const +{ + return format; } -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) +GLenum InternalFormat::getReadPixelsType(const Version &version) const +{ + switch (type) + { + case GL_HALF_FLOAT: + case GL_HALF_FLOAT_OES: + if (version < Version(3, 0)) + { + // The internal format may have a type of GL_HALF_FLOAT but when exposing this type + // as the IMPLEMENTATION_READ_TYPE, only HALF_FLOAT_OES is allowed by + // OES_texture_half_float. HALF_FLOAT becomes core in ES3 and is acceptable to use + // as an IMPLEMENTATION_READ_TYPE. + return GL_HALF_FLOAT_OES; + } + else + { + return GL_HALF_FLOAT; + } + + default: + return type; + } +} + +bool InternalFormat::isRequiredRenderbufferFormat(const Version &version) const +{ + // GLES 3.0.5 section 4.4.2.2: + // "Implementations are required to support the same internal formats for renderbuffers as the + // required formats for textures enumerated in section 3.8.3.1, with the exception of the color + // formats labelled "texture-only"." + if (!sized || compressed) + { + return false; + } + + // Luma formats. + if (isLUMA()) + { + return false; + } + + // Depth/stencil formats. + if (depthBits > 0 || stencilBits > 0) + { + // GLES 2.0.25 table 4.5. + // GLES 3.0.5 section 3.8.3.1. + // GLES 3.1 table 8.14. + + // Required formats in all versions. + switch (internalFormat) + { + case GL_DEPTH_COMPONENT16: + case GL_STENCIL_INDEX8: + // Note that STENCIL_INDEX8 is not mentioned in GLES 3.0.5 section 3.8.3.1, but it + // is in section 4.4.2.2. + return true; + default: + break; + } + if (version.major < 3) + { + return false; + } + // Required formats in GLES 3.0 and up. + switch (internalFormat) + { + case GL_DEPTH_COMPONENT32F: + case GL_DEPTH_COMPONENT24: + case GL_DEPTH32F_STENCIL8: + case GL_DEPTH24_STENCIL8: + return true; + default: + return false; + } + } + + // RGBA formats. + // GLES 2.0.25 table 4.5. + // GLES 3.0.5 section 3.8.3.1. + // GLES 3.1 table 8.13. + + // Required formats in all versions. + switch (internalFormat) + { + case GL_RGBA4: + case GL_RGB5_A1: + case GL_RGB565: + return true; + default: + break; + } + if (version.major < 3) + { + return false; + } + + if (format == GL_BGRA_EXT) + { + return false; + } + + switch (componentType) + { + case GL_SIGNED_NORMALIZED: + case GL_FLOAT: + return false; + case GL_UNSIGNED_INT: + case GL_INT: + // Integer RGB formats are not required renderbuffer formats. + if (alphaBits == 0 && blueBits != 0) + { + return false; + } + // All integer R and RG formats are required. + // Integer RGBA formats including RGB10_A2_UI are required. + return true; + case GL_UNSIGNED_NORMALIZED: + if (internalFormat == GL_SRGB8) + { + return false; + } + return true; + default: + UNREACHABLE(); + return false; + } +} + +Format::Format(GLenum internalFormat) : Format(GetSizedInternalFormatInfo(internalFormat)) +{ +} + +Format::Format(const InternalFormat &internalFormat) : info(&internalFormat) +{ +} + +Format::Format(GLenum internalFormat, GLenum type) + : info(&GetInternalFormatInfo(internalFormat, type)) +{ +} + +Format::Format(const Format &other) = default; +Format &Format::operator=(const Format &other) = default; + +bool Format::valid() const +{ + return info->internalFormat != GL_NONE; +} + +// static +bool Format::SameSized(const Format &a, const Format &b) +{ + return a.info->sizedInternalFormat == b.info->sizedInternalFormat; +} + +static GLenum EquivalentBlitInternalFormat(GLenum internalformat) +{ + // BlitFramebuffer works if the color channels are identically + // sized, even if there is a swizzle (for example, blitting from a + // multisampled RGBA8 renderbuffer to a BGRA8 texture). This could + // be expanded and/or autogenerated if that is found necessary. + if (internalformat == GL_BGRA8_EXT) + return GL_RGBA8; + return internalformat; +} + +// static +bool Format::EquivalentForBlit(const Format &a, const Format &b) +{ + return (EquivalentBlitInternalFormat(a.info->sizedInternalFormat) == + EquivalentBlitInternalFormat(b.info->sizedInternalFormat)); +} + +// static +Format Format::Invalid() +{ + static Format invalid(GL_NONE, GL_NONE); + return invalid; +} + +std::ostream &operator<<(std::ostream &os, const Format &fmt) +{ + // TODO(ynovikov): return string representation when available + return FmtHexShort(os, fmt.info->sizedInternalFormat); +} + +bool InternalFormat::operator==(const InternalFormat &other) const +{ + // We assume all internal formats are unique if they have the same internal format and type + return internalFormat == other.internalFormat && type == other.type; +} + +bool InternalFormat::operator!=(const InternalFormat &other) const +{ + return !(*this == other); +} + +void InsertFormatInfo(InternalFormatInfoMap *map, const InternalFormat &formatInfo) +{ + ASSERT(!formatInfo.sized || (*map).count(formatInfo.internalFormat) == 0); + ASSERT((*map)[formatInfo.internalFormat].count(formatInfo.type) == 0); + (*map)[formatInfo.internalFormat][formatInfo.type] = formatInfo; +} + +void AddRGBAFormat(InternalFormatInfoMap *map, + GLenum internalFormat, + bool sized, + 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.internalFormat = internalFormat; + formatInfo.sized = sized; + formatInfo.sizedInternalFormat = + sized ? internalFormat : GetSizedFormatInternal(internalFormat, type); 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.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; @@ -324,15 +554,27 @@ static InternalFormat RGBAFormat(GLuint red, GLuint green, GLuint blue, GLuint a formatInfo.textureSupport = textureSupport; formatInfo.renderSupport = renderSupport; formatInfo.filterSupport = filterSupport; - return formatInfo; + + InsertFormatInfo(map, formatInfo); } -static InternalFormat LUMAFormat(GLuint luminance, GLuint alpha, GLenum format, GLenum type, GLenum componentType, - InternalFormat::SupportCheckFunction textureSupport, - InternalFormat::SupportCheckFunction renderSupport, - InternalFormat::SupportCheckFunction filterSupport) +static void AddLUMAFormat(InternalFormatInfoMap *map, + GLenum internalFormat, + bool sized, + GLuint luminance, + GLuint alpha, + GLenum format, + GLenum type, + GLenum componentType, + InternalFormat::SupportCheckFunction textureSupport, + InternalFormat::SupportCheckFunction renderSupport, + InternalFormat::SupportCheckFunction filterSupport) { InternalFormat formatInfo; + formatInfo.internalFormat = internalFormat; + formatInfo.sized = sized; + formatInfo.sizedInternalFormat = + sized ? internalFormat : GetSizedFormatInternal(internalFormat, type); formatInfo.luminanceBits = luminance; formatInfo.alphaBits = alpha; formatInfo.pixelBytes = (luminance + alpha) / 8; @@ -344,15 +586,28 @@ static InternalFormat LUMAFormat(GLuint luminance, GLuint alpha, GLenum format, formatInfo.textureSupport = textureSupport; formatInfo.renderSupport = renderSupport; formatInfo.filterSupport = filterSupport; - return formatInfo; + + InsertFormatInfo(map, 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) +void AddDepthStencilFormat(InternalFormatInfoMap *map, + GLenum internalFormat, + bool sized, + GLuint depthBits, + GLuint stencilBits, + GLuint unusedBits, + GLenum format, + GLenum type, + GLenum componentType, + InternalFormat::SupportCheckFunction textureSupport, + InternalFormat::SupportCheckFunction renderSupport, + InternalFormat::SupportCheckFunction filterSupport) { InternalFormat formatInfo; + formatInfo.internalFormat = internalFormat; + formatInfo.sized = sized; + formatInfo.sizedInternalFormat = + sized ? internalFormat : GetSizedFormatInternal(internalFormat, type); formatInfo.depthBits = depthBits; formatInfo.stencilBits = stencilBits; formatInfo.pixelBytes = (depthBits + stencilBits + unusedBits) / 8; @@ -364,16 +619,27 @@ static InternalFormat DepthStencilFormat(GLuint depthBits, GLuint stencilBits, G formatInfo.textureSupport = textureSupport; formatInfo.renderSupport = renderSupport; formatInfo.filterSupport = filterSupport; - return formatInfo; + + InsertFormatInfo(map, 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) +void AddCompressedFormat(InternalFormatInfoMap *map, + GLenum internalFormat, + 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.internalFormat = internalFormat; + formatInfo.sized = true; + formatInfo.sizedInternalFormat = internalFormat; formatInfo.compressedBlockWidth = compressedBlockWidth; formatInfo.compressedBlockHeight = compressedBlockHeight; formatInfo.pixelBytes = compressedBlockSize / 8; @@ -386,189 +652,279 @@ static InternalFormat CompressedFormat(GLuint compressedBlockWidth, GLuint compr formatInfo.textureSupport = textureSupport; formatInfo.renderSupport = renderSupport; formatInfo.filterSupport = filterSupport; - return formatInfo; -} -typedef std::pair InternalFormatInfoPair; -typedef std::map InternalFormatInfoMap; + InsertFormatInfo(map, formatInfo); +} static InternalFormatInfoMap BuildInternalFormatInfoMap() { InternalFormatInfoMap map; - // clang-format off // 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>, RequireES<3>, 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))); + map[GL_NONE][GL_NONE] = InternalFormat(); + + // clang-format off + + // | Internal format |sized| R | G | B | A |S | Format | Type | Component type | SRGB | Texture supported | Renderable | Filterable | + AddRGBAFormat(&map, GL_R8, true, 8, 0, 0, 0, 0, GL_RED, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, false, RequireESOrExt<3, 0, &Extensions::textureRG>, RequireESOrExt<3, 0, &Extensions::textureRG>, AlwaysSupported); + AddRGBAFormat(&map, GL_R8_SNORM, true, 8, 0, 0, 0, 0, GL_RED, GL_BYTE, GL_SIGNED_NORMALIZED, false, RequireES<3, 0>, NeverSupported, AlwaysSupported); + AddRGBAFormat(&map, GL_RG8, true, 8, 8, 0, 0, 0, GL_RG, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, false, RequireESOrExt<3, 0, &Extensions::textureRG>, RequireESOrExt<3, 0, &Extensions::textureRG>, AlwaysSupported); + AddRGBAFormat(&map, GL_RG8_SNORM, true, 8, 8, 0, 0, 0, GL_RG, GL_BYTE, GL_SIGNED_NORMALIZED, false, RequireES<3, 0>, NeverSupported, AlwaysSupported); + AddRGBAFormat(&map, GL_RGB8, true, 8, 8, 8, 0, 0, GL_RGB, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, false, RequireESOrExt<3, 0, &Extensions::rgb8rgba8>, RequireESOrExt<3, 0, &Extensions::rgb8rgba8>, AlwaysSupported); + AddRGBAFormat(&map, GL_RGB8_SNORM, true, 8, 8, 8, 0, 0, GL_RGB, GL_BYTE, GL_SIGNED_NORMALIZED, false, RequireES<3, 0>, NeverSupported, AlwaysSupported); + AddRGBAFormat(&map, GL_RGB565, true, 5, 6, 5, 0, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, GL_UNSIGNED_NORMALIZED, false, RequireES<2, 0>, RequireES<2, 0>, AlwaysSupported); + AddRGBAFormat(&map, GL_RGBA4, true, 4, 4, 4, 4, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, GL_UNSIGNED_NORMALIZED, false, RequireES<2, 0>, RequireES<2, 0>, AlwaysSupported); + AddRGBAFormat(&map, GL_RGB5_A1, true, 5, 5, 5, 1, 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, GL_UNSIGNED_NORMALIZED, false, RequireES<2, 0>, RequireES<2, 0>, AlwaysSupported); + AddRGBAFormat(&map, GL_RGBA8, true, 8, 8, 8, 8, 0, GL_RGBA, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, false, RequireESOrExt<3, 0, &Extensions::rgb8rgba8>, RequireESOrExt<3, 0, &Extensions::rgb8rgba8>, AlwaysSupported); + AddRGBAFormat(&map, GL_RGBA8_SNORM, true, 8, 8, 8, 8, 0, GL_RGBA, GL_BYTE, GL_SIGNED_NORMALIZED, false, RequireES<3, 0>, NeverSupported, AlwaysSupported); + AddRGBAFormat(&map, GL_RGB10_A2, true, 10, 10, 10, 2, 0, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV, GL_UNSIGNED_NORMALIZED, false, RequireES<3, 0>, RequireES<3, 0>, AlwaysSupported); + AddRGBAFormat(&map, GL_RGB10_A2UI, true, 10, 10, 10, 2, 0, GL_RGBA_INTEGER, GL_UNSIGNED_INT_2_10_10_10_REV, GL_UNSIGNED_INT, false, RequireES<3, 0>, RequireES<3, 0>, NeverSupported); + AddRGBAFormat(&map, GL_SRGB8, true, 8, 8, 8, 0, 0, GL_RGB, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, true, RequireESOrExt<3, 0, &Extensions::sRGB>, NeverSupported, AlwaysSupported); + AddRGBAFormat(&map, GL_SRGB8_ALPHA8, true, 8, 8, 8, 8, 0, GL_RGBA, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, true, RequireESOrExt<3, 0, &Extensions::sRGB>, RequireESOrExt<3, 0, &Extensions::sRGB>, AlwaysSupported); + AddRGBAFormat(&map, GL_RGB9_E5, true, 9, 9, 9, 0, 5, GL_RGB, GL_UNSIGNED_INT_5_9_9_9_REV, GL_FLOAT, false, RequireES<3, 0>, NeverSupported, AlwaysSupported); + AddRGBAFormat(&map, GL_R8I, true, 8, 0, 0, 0, 0, GL_RED_INTEGER, GL_BYTE, GL_INT, false, RequireES<3, 0>, RequireES<3, 0>, NeverSupported); + AddRGBAFormat(&map, GL_R8UI, true, 8, 0, 0, 0, 0, GL_RED_INTEGER, GL_UNSIGNED_BYTE, GL_UNSIGNED_INT, false, RequireES<3, 0>, RequireES<3, 0>, NeverSupported); + AddRGBAFormat(&map, GL_R16I, true, 16, 0, 0, 0, 0, GL_RED_INTEGER, GL_SHORT, GL_INT, false, RequireES<3, 0>, RequireES<3, 0>, NeverSupported); + AddRGBAFormat(&map, GL_R16UI, true, 16, 0, 0, 0, 0, GL_RED_INTEGER, GL_UNSIGNED_SHORT, GL_UNSIGNED_INT, false, RequireES<3, 0>, RequireES<3, 0>, NeverSupported); + AddRGBAFormat(&map, GL_R32I, true, 32, 0, 0, 0, 0, GL_RED_INTEGER, GL_INT, GL_INT, false, RequireES<3, 0>, RequireES<3, 0>, NeverSupported); + AddRGBAFormat(&map, GL_R32UI, true, 32, 0, 0, 0, 0, GL_RED_INTEGER, GL_UNSIGNED_INT, GL_UNSIGNED_INT, false, RequireES<3, 0>, RequireES<3, 0>, NeverSupported); + AddRGBAFormat(&map, GL_RG8I, true, 8, 8, 0, 0, 0, GL_RG_INTEGER, GL_BYTE, GL_INT, false, RequireES<3, 0>, RequireES<3, 0>, NeverSupported); + AddRGBAFormat(&map, GL_RG8UI, true, 8, 8, 0, 0, 0, GL_RG_INTEGER, GL_UNSIGNED_BYTE, GL_UNSIGNED_INT, false, RequireES<3, 0>, RequireES<3, 0>, NeverSupported); + AddRGBAFormat(&map, GL_RG16I, true, 16, 16, 0, 0, 0, GL_RG_INTEGER, GL_SHORT, GL_INT, false, RequireES<3, 0>, RequireES<3, 0>, NeverSupported); + AddRGBAFormat(&map, GL_RG16UI, true, 16, 16, 0, 0, 0, GL_RG_INTEGER, GL_UNSIGNED_SHORT, GL_UNSIGNED_INT, false, RequireES<3, 0>, RequireES<3, 0>, NeverSupported); + AddRGBAFormat(&map, GL_RG32I, true, 32, 32, 0, 0, 0, GL_RG_INTEGER, GL_INT, GL_INT, false, RequireES<3, 0>, RequireES<3, 0>, NeverSupported); + AddRGBAFormat(&map, GL_R11F_G11F_B10F, true, 11, 11, 10, 0, 0, GL_RGB, GL_UNSIGNED_INT_10F_11F_11F_REV, GL_FLOAT, false, RequireES<3, 0>, RequireExt<&Extensions::colorBufferFloat>, AlwaysSupported); + AddRGBAFormat(&map, GL_RG32UI, true, 32, 32, 0, 0, 0, GL_RG_INTEGER, GL_UNSIGNED_INT, GL_UNSIGNED_INT, false, RequireES<3, 0>, RequireES<3, 0>, NeverSupported); + AddRGBAFormat(&map, GL_RGB8I, true, 8, 8, 8, 0, 0, GL_RGB_INTEGER, GL_BYTE, GL_INT, false, RequireES<3, 0>, NeverSupported, NeverSupported); + AddRGBAFormat(&map, GL_RGB8UI, true, 8, 8, 8, 0, 0, GL_RGB_INTEGER, GL_UNSIGNED_BYTE, GL_UNSIGNED_INT, false, RequireES<3, 0>, NeverSupported, NeverSupported); + AddRGBAFormat(&map, GL_RGB16I, true, 16, 16, 16, 0, 0, GL_RGB_INTEGER, GL_SHORT, GL_INT, false, RequireES<3, 0>, NeverSupported, NeverSupported); + AddRGBAFormat(&map, GL_RGB16UI, true, 16, 16, 16, 0, 0, GL_RGB_INTEGER, GL_UNSIGNED_SHORT, GL_UNSIGNED_INT, false, RequireES<3, 0>, NeverSupported, NeverSupported); + AddRGBAFormat(&map, GL_RGB32I, true, 32, 32, 32, 0, 0, GL_RGB_INTEGER, GL_INT, GL_INT, false, RequireES<3, 0>, NeverSupported, NeverSupported); + AddRGBAFormat(&map, GL_RGB32UI, true, 32, 32, 32, 0, 0, GL_RGB_INTEGER, GL_UNSIGNED_INT, GL_UNSIGNED_INT, false, RequireES<3, 0>, NeverSupported, NeverSupported); + AddRGBAFormat(&map, GL_RGBA8I, true, 8, 8, 8, 8, 0, GL_RGBA_INTEGER, GL_BYTE, GL_INT, false, RequireES<3, 0>, RequireES<3, 0>, NeverSupported); + AddRGBAFormat(&map, GL_RGBA8UI, true, 8, 8, 8, 8, 0, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE, GL_UNSIGNED_INT, false, RequireES<3, 0>, RequireES<3, 0>, NeverSupported); + AddRGBAFormat(&map, GL_RGBA16I, true, 16, 16, 16, 16, 0, GL_RGBA_INTEGER, GL_SHORT, GL_INT, false, RequireES<3, 0>, RequireES<3, 0>, NeverSupported); + AddRGBAFormat(&map, GL_RGBA16UI, true, 16, 16, 16, 16, 0, GL_RGBA_INTEGER, GL_UNSIGNED_SHORT, GL_UNSIGNED_INT, false, RequireES<3, 0>, RequireES<3, 0>, NeverSupported); + AddRGBAFormat(&map, GL_RGBA32I, true, 32, 32, 32, 32, 0, GL_RGBA_INTEGER, GL_INT, GL_INT, false, RequireES<3, 0>, RequireES<3, 0>, NeverSupported); + AddRGBAFormat(&map, GL_RGBA32UI, true, 32, 32, 32, 32, 0, GL_RGBA_INTEGER, GL_UNSIGNED_INT, GL_UNSIGNED_INT, false, RequireES<3, 0>, RequireES<3, 0>, NeverSupported); + + AddRGBAFormat(&map, GL_BGRA8_EXT, true, 8, 8, 8, 8, 0, GL_BGRA_EXT, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, false, RequireExt<&Extensions::textureFormatBGRA8888>, RequireExt<&Extensions::textureFormatBGRA8888>, AlwaysSupported); + AddRGBAFormat(&map, GL_BGRA4_ANGLEX, true, 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); + AddRGBAFormat(&map, GL_BGR5_A1_ANGLEX, true, 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); + + // Special format which is not really supported, so always false for all supports. + AddRGBAFormat(&map, GL_BGR565_ANGLEX, true, 5, 6, 5, 1, 0, GL_BGRA_EXT, GL_UNSIGNED_SHORT_5_6_5, GL_UNSIGNED_NORMALIZED, false, NeverSupported, NeverSupported, NeverSupported); // 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, HalfFloatSupportRG, HalfFloatRenderableSupportRG, RequireExt<&Extensions::textureHalfFloatLinear>))); - map.insert(InternalFormatInfoPair(GL_RG16F, RGBAFormat(16, 16, 0, 0, 0, GL_RG, GL_HALF_FLOAT, GL_FLOAT, false, HalfFloatSupportRG, HalfFloatRenderableSupportRG, RequireExt<&Extensions::textureHalfFloatLinear>))); - map.insert(InternalFormatInfoPair(GL_RGB16F, RGBAFormat(16, 16, 16, 0, 0, GL_RGB, GL_HALF_FLOAT, GL_FLOAT, false, HalfFloatSupport, HalfFloatRenderableSupport, RequireExt<&Extensions::textureHalfFloatLinear>))); - map.insert(InternalFormatInfoPair(GL_RGBA16F, RGBAFormat(16, 16, 16, 16, 0, GL_RGBA, GL_HALF_FLOAT, GL_FLOAT, false, HalfFloatSupport, HalfFloatRenderableSupport, RequireExt<&Extensions::textureHalfFloatLinear>))); - map.insert(InternalFormatInfoPair(GL_R32F, RGBAFormat(32, 0, 0, 0, 0, GL_RED, GL_FLOAT, GL_FLOAT, false, FloatSupportRG, FloatRenderableSupportRG, RequireExt<&Extensions::textureFloatLinear> ))); - map.insert(InternalFormatInfoPair(GL_RG32F, RGBAFormat(32, 32, 0, 0, 0, GL_RG, GL_FLOAT, GL_FLOAT, false, FloatSupportRG, FloatRenderableSupportRG, RequireExt<&Extensions::textureFloatLinear> ))); - map.insert(InternalFormatInfoPair(GL_RGB32F, RGBAFormat(32, 32, 32, 0, 0, GL_RGB, GL_FLOAT, GL_FLOAT, false, FloatSupport, FloatRenderableSupport, RequireExt<&Extensions::textureFloatLinear> ))); - map.insert(InternalFormatInfoPair(GL_RGBA32F, RGBAFormat(32, 32, 32, 32, 0, GL_RGBA, GL_FLOAT, GL_FLOAT, false, FloatSupport, FloatRenderableSupport, RequireExt<&Extensions::textureFloatLinear> ))); + // | Internal format |sized| D |S | Format | Type | Comp | SRGB | Texture supported | Renderable | Filterable | + // | | | | | | | type | | | | | + AddRGBAFormat(&map, GL_R16F, true, 16, 0, 0, 0, 0, GL_RED, GL_HALF_FLOAT, GL_FLOAT, false, HalfFloatRGSupport, HalfFloatRGRenderableSupport, RequireESOrExt<3, 0, &Extensions::textureHalfFloatLinear>); + AddRGBAFormat(&map, GL_RG16F, true, 16, 16, 0, 0, 0, GL_RG, GL_HALF_FLOAT, GL_FLOAT, false, HalfFloatRGSupport, HalfFloatRGRenderableSupport, RequireESOrExt<3, 0, &Extensions::textureHalfFloatLinear>); + AddRGBAFormat(&map, GL_RGB16F, true, 16, 16, 16, 0, 0, GL_RGB, GL_HALF_FLOAT, GL_FLOAT, false, HalfFloatSupport, HalfFloatRGBRenderableSupport, RequireESOrExt<3, 0, &Extensions::textureHalfFloatLinear>); + AddRGBAFormat(&map, GL_RGBA16F, true, 16, 16, 16, 16, 0, GL_RGBA, GL_HALF_FLOAT, GL_FLOAT, false, HalfFloatSupport, HalfFloatRGBARenderableSupport, RequireESOrExt<3, 0, &Extensions::textureHalfFloatLinear>); + AddRGBAFormat(&map, GL_R32F, true, 32, 0, 0, 0, 0, GL_RED, GL_FLOAT, GL_FLOAT, false, FloatRGSupport, FloatRGRenderableSupport, RequireExt<&Extensions::textureFloatLinear> ); + AddRGBAFormat(&map, GL_RG32F, true, 32, 32, 0, 0, 0, GL_RG, GL_FLOAT, GL_FLOAT, false, FloatRGSupport, FloatRGRenderableSupport, RequireExt<&Extensions::textureFloatLinear> ); + AddRGBAFormat(&map, GL_RGB32F, true, 32, 32, 32, 0, 0, GL_RGB, GL_FLOAT, GL_FLOAT, false, FloatSupport, FloatRGBRenderableSupport, RequireExt<&Extensions::textureFloatLinear> ); + AddRGBAFormat(&map, GL_RGBA32F, true, 32, 32, 32, 32, 0, GL_RGBA, GL_FLOAT, GL_FLOAT, false, FloatSupport, FloatRGBARenderableSupport, 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, RequireExtOrExt<&Extensions::depthTextures, &Extensions::depth32>, RequireExtOrExt<&Extensions::depthTextures, &Extensions::depth32>, 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 ))); + // | Internal format |sized| D |S | X | Format | Type | Component type | Supported | Renderable | Filterable | + AddDepthStencilFormat(&map, GL_DEPTH_COMPONENT16, true, 16, 0, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, GL_UNSIGNED_NORMALIZED, RequireES<2, 0>, RequireES<2, 0>, RequireESOrExt<3, 0, &Extensions::depthTextures>); + AddDepthStencilFormat(&map, GL_DEPTH_COMPONENT24, true, 24, 0, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, GL_UNSIGNED_NORMALIZED, RequireES<3, 0>, RequireES<3, 0>, RequireESOrExt<3, 0, &Extensions::depthTextures>); + AddDepthStencilFormat(&map, GL_DEPTH_COMPONENT32F, true, 32, 0, 0, GL_DEPTH_COMPONENT, GL_FLOAT, GL_FLOAT, RequireES<3, 0>, RequireES<3, 0>, RequireESOrExt<3, 0, &Extensions::depthTextures>); + AddDepthStencilFormat(&map, GL_DEPTH_COMPONENT32_OES, true, 32, 0, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, GL_UNSIGNED_NORMALIZED, RequireExtOrExt<&Extensions::depthTextures, &Extensions::depth32>, RequireExtOrExt<&Extensions::depthTextures, &Extensions::depth32>, AlwaysSupported ); + AddDepthStencilFormat(&map, GL_DEPTH24_STENCIL8, true, 24, 8, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, GL_UNSIGNED_NORMALIZED, RequireESOrExt<3, 0, &Extensions::depthTextures>, RequireESOrExtOrExt<3, 0, &Extensions::depthTextures, &Extensions::packedDepthStencil>, AlwaysSupported ); + AddDepthStencilFormat(&map, GL_DEPTH32F_STENCIL8, true, 32, 8, 24, GL_DEPTH_STENCIL, GL_FLOAT_32_UNSIGNED_INT_24_8_REV, GL_FLOAT, RequireES<3, 0>, RequireES<3, 0>, 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))); + // | Internal format |sized| L | A | Format | Type | Component type | Supported | Renderable | Filterable | + AddLUMAFormat(&map, GL_ALPHA8_EXT, true, 0, 8, GL_ALPHA, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, RequireExt<&Extensions::textureStorage>, NeverSupported, AlwaysSupported); + AddLUMAFormat(&map, GL_LUMINANCE8_EXT, true, 8, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, RequireExt<&Extensions::textureStorage>, NeverSupported, AlwaysSupported); + AddLUMAFormat(&map, GL_LUMINANCE8_ALPHA8_EXT, true, 8, 8, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, RequireExt<&Extensions::textureStorage>, NeverSupported, AlwaysSupported); + AddLUMAFormat(&map, GL_ALPHA16F_EXT, true, 0, 16, GL_ALPHA, GL_HALF_FLOAT_OES, GL_FLOAT, RequireExtAndExt<&Extensions::textureStorage, &Extensions::textureHalfFloat>, NeverSupported, RequireESOrExt<3, 0, &Extensions::textureHalfFloatLinear>); + AddLUMAFormat(&map, GL_LUMINANCE16F_EXT, true, 16, 0, GL_LUMINANCE, GL_HALF_FLOAT_OES, GL_FLOAT, RequireExtAndExt<&Extensions::textureStorage, &Extensions::textureHalfFloat>, NeverSupported, RequireESOrExt<3, 0, &Extensions::textureHalfFloatLinear>); + AddLUMAFormat(&map, GL_LUMINANCE_ALPHA16F_EXT, true, 16, 16, GL_LUMINANCE_ALPHA, GL_HALF_FLOAT_OES, GL_FLOAT, RequireExtAndExt<&Extensions::textureStorage, &Extensions::textureHalfFloat>, NeverSupported, RequireESOrExt<3, 0, &Extensions::textureHalfFloatLinear>); + AddLUMAFormat(&map, GL_ALPHA32F_EXT, true, 0, 32, GL_ALPHA, GL_FLOAT, GL_FLOAT, RequireExtAndExt<&Extensions::textureStorage, &Extensions::textureFloat>, NeverSupported, RequireExt<&Extensions::textureFloatLinear>); + AddLUMAFormat(&map, GL_LUMINANCE32F_EXT, true, 32, 0, GL_LUMINANCE, GL_FLOAT, GL_FLOAT, RequireExtAndExt<&Extensions::textureStorage, &Extensions::textureFloat>, NeverSupported, RequireExt<&Extensions::textureFloatLinear>); + AddLUMAFormat(&map, GL_LUMINANCE_ALPHA32F_EXT, true, 32, 32, GL_LUMINANCE_ALPHA, GL_FLOAT, GL_FLOAT, RequireExtAndExt<&Extensions::textureStorage, &Extensions::textureFloat>, NeverSupported, RequireExt<&Extensions::textureFloatLinear>); // 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, RequireES<3>, NeverSupported, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_COMPRESSED_SIGNED_R11_EAC, CompressedFormat(4, 4, 64, 1, GL_COMPRESSED_SIGNED_R11_EAC, GL_UNSIGNED_BYTE, false, RequireES<3>, NeverSupported, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_COMPRESSED_RG11_EAC, CompressedFormat(4, 4, 128, 2, GL_COMPRESSED_RG11_EAC, GL_UNSIGNED_BYTE, false, RequireES<3>, NeverSupported, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_COMPRESSED_SIGNED_RG11_EAC, CompressedFormat(4, 4, 128, 2, GL_COMPRESSED_SIGNED_RG11_EAC, GL_UNSIGNED_BYTE, false, RequireES<3>, NeverSupported, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGB8_ETC2, CompressedFormat(4, 4, 64, 3, GL_COMPRESSED_RGB8_ETC2, GL_UNSIGNED_BYTE, false, RequireES<3>, NeverSupported, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_COMPRESSED_SRGB8_ETC2, CompressedFormat(4, 4, 64, 3, GL_COMPRESSED_SRGB8_ETC2, GL_UNSIGNED_BYTE, true, RequireES<3>, NeverSupported, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2, CompressedFormat(4, 4, 64, 3, GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2, GL_UNSIGNED_BYTE, false, RequireES<3>, NeverSupported, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2, CompressedFormat(4, 4, 64, 3, GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2, GL_UNSIGNED_BYTE, true, RequireES<3>, NeverSupported, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGBA8_ETC2_EAC, CompressedFormat(4, 4, 128, 4, GL_COMPRESSED_RGBA8_ETC2_EAC, GL_UNSIGNED_BYTE, false, RequireES<3>, NeverSupported, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC, CompressedFormat(4, 4, 128, 4, GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC, GL_UNSIGNED_BYTE, true, RequireES<3>, NeverSupported, AlwaysSupported))); + // | Internal format |W |H | BS |CC| Format | Type | SRGB | Supported | Renderable | Filterable | + AddCompressedFormat(&map, GL_COMPRESSED_R11_EAC, 4, 4, 64, 1, GL_RED, GL_UNSIGNED_BYTE, false, RequireES<3, 0>, NeverSupported, AlwaysSupported); + AddCompressedFormat(&map, GL_COMPRESSED_SIGNED_R11_EAC, 4, 4, 64, 1, GL_RED, GL_UNSIGNED_BYTE, false, RequireES<3, 0>, NeverSupported, AlwaysSupported); + AddCompressedFormat(&map, GL_COMPRESSED_RG11_EAC, 4, 4, 128, 2, GL_RG, GL_UNSIGNED_BYTE, false, RequireES<3, 0>, NeverSupported, AlwaysSupported); + AddCompressedFormat(&map, GL_COMPRESSED_SIGNED_RG11_EAC, 4, 4, 128, 2, GL_RG, GL_UNSIGNED_BYTE, false, RequireES<3, 0>, NeverSupported, AlwaysSupported); + AddCompressedFormat(&map, GL_COMPRESSED_RGB8_ETC2, 4, 4, 64, 3, GL_RGB, GL_UNSIGNED_BYTE, false, RequireES<3, 0>, NeverSupported, AlwaysSupported); + AddCompressedFormat(&map, GL_COMPRESSED_SRGB8_ETC2, 4, 4, 64, 3, GL_RGB, GL_UNSIGNED_BYTE, true, RequireES<3, 0>, NeverSupported, AlwaysSupported); + AddCompressedFormat(&map, GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2, 4, 4, 64, 3, GL_RGB, GL_UNSIGNED_BYTE, false, RequireES<3, 0>, NeverSupported, AlwaysSupported); + AddCompressedFormat(&map, GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2, 4, 4, 64, 3, GL_RGB, GL_UNSIGNED_BYTE, true, RequireES<3, 0>, NeverSupported, AlwaysSupported); + AddCompressedFormat(&map, GL_COMPRESSED_RGBA8_ETC2_EAC, 4, 4, 128, 4, GL_RGBA, GL_UNSIGNED_BYTE, false, RequireES<3, 0>, NeverSupported, AlwaysSupported); + AddCompressedFormat(&map, GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC, 4, 4, 128, 4, GL_RGBA, GL_UNSIGNED_BYTE, true, RequireES<3, 0>, NeverSupported, AlwaysSupported); // 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))); + // | Internal format |W |H | BS |CC| Format | Type | SRGB | Supported | Renderable | Filterable | + AddCompressedFormat(&map, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 4, 4, 64, 3, GL_RGB, GL_UNSIGNED_BYTE, false, RequireExt<&Extensions::textureCompressionDXT1>, NeverSupported, AlwaysSupported); + AddCompressedFormat(&map, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, 4, 4, 64, 4, GL_RGBA, 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))); + AddCompressedFormat(&map, GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE, 4, 4, 128, 4, GL_RGBA, GL_UNSIGNED_BYTE, false, RequireExt<&Extensions::textureCompressionDXT3>, 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))); + AddCompressedFormat(&map, GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE, 4, 4, 128, 4, GL_RGBA, GL_UNSIGNED_BYTE, false, RequireExt<&Extensions::textureCompressionDXT5>, NeverSupported, AlwaysSupported); // From GL_OES_compressed_ETC1_RGB8_texture - map.insert(InternalFormatInfoPair(GL_ETC1_RGB8_OES, CompressedFormat(4, 4, 64, 3, GL_ETC1_RGB8_OES, GL_UNSIGNED_BYTE, false, RequireExt<&Extensions::compressedETC1RGB8Texture>, NeverSupported, AlwaysSupported))); + AddCompressedFormat(&map, GL_ETC1_RGB8_OES, 4, 4, 64, 3, GL_RGB, GL_UNSIGNED_BYTE, false, RequireExt<&Extensions::compressedETC1RGB8Texture>, NeverSupported, AlwaysSupported); + + // From GL_EXT_texture_compression_s3tc_srgb + // | Internal format |W |H | BS |CC| Format | Type | SRGB | Supported | Renderable | Filterable | + AddCompressedFormat(&map, GL_COMPRESSED_SRGB_S3TC_DXT1_EXT, 4, 4, 64, 3, GL_RGB, GL_UNSIGNED_BYTE, true, RequireExt<&Extensions::textureCompressionS3TCsRGB>, NeverSupported, AlwaysSupported); + AddCompressedFormat(&map, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT, 4, 4, 64, 4, GL_RGBA, GL_UNSIGNED_BYTE, true, RequireExt<&Extensions::textureCompressionS3TCsRGB>, NeverSupported, AlwaysSupported); + AddCompressedFormat(&map, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT, 4, 4, 128, 4, GL_RGBA, GL_UNSIGNED_BYTE, true, RequireExt<&Extensions::textureCompressionS3TCsRGB>, NeverSupported, AlwaysSupported); + AddCompressedFormat(&map, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, 4, 4, 128, 4, GL_RGBA, GL_UNSIGNED_BYTE, true, RequireExt<&Extensions::textureCompressionS3TCsRGB>, NeverSupported, AlwaysSupported); // From KHR_texture_compression_astc_hdr - // | Internal format | | W | H | BS |CC| Format | Type | SRGB | Supported | Renderable | Filterable | - map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGBA_ASTC_4x4_KHR, CompressedFormat( 4, 4, 128, 4, GL_COMPRESSED_RGBA_ASTC_4x4_KHR, GL_UNSIGNED_BYTE, false, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGBA_ASTC_5x4_KHR, CompressedFormat( 5, 4, 128, 4, GL_COMPRESSED_RGBA_ASTC_5x4_KHR, GL_UNSIGNED_BYTE, false, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGBA_ASTC_5x5_KHR, CompressedFormat( 5, 5, 128, 4, GL_COMPRESSED_RGBA_ASTC_5x5_KHR, GL_UNSIGNED_BYTE, false, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGBA_ASTC_6x5_KHR, CompressedFormat( 6, 5, 128, 4, GL_COMPRESSED_RGBA_ASTC_6x5_KHR, GL_UNSIGNED_BYTE, false, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGBA_ASTC_6x6_KHR, CompressedFormat( 6, 6, 128, 4, GL_COMPRESSED_RGBA_ASTC_6x6_KHR, GL_UNSIGNED_BYTE, false, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGBA_ASTC_8x5_KHR, CompressedFormat( 8, 5, 128, 4, GL_COMPRESSED_RGBA_ASTC_8x5_KHR, GL_UNSIGNED_BYTE, false, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGBA_ASTC_8x6_KHR, CompressedFormat( 8, 6, 128, 4, GL_COMPRESSED_RGBA_ASTC_8x6_KHR, GL_UNSIGNED_BYTE, false, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGBA_ASTC_8x8_KHR, CompressedFormat( 8, 8, 128, 4, GL_COMPRESSED_RGBA_ASTC_8x8_KHR, GL_UNSIGNED_BYTE, false, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGBA_ASTC_10x5_KHR, CompressedFormat(10, 5, 128, 4, GL_COMPRESSED_RGBA_ASTC_10x5_KHR, GL_UNSIGNED_BYTE, false, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGBA_ASTC_10x6_KHR, CompressedFormat(10, 6, 128, 4, GL_COMPRESSED_RGBA_ASTC_10x6_KHR, GL_UNSIGNED_BYTE, false, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGBA_ASTC_10x8_KHR, CompressedFormat(10, 8, 128, 4, GL_COMPRESSED_RGBA_ASTC_10x8_KHR, GL_UNSIGNED_BYTE, false, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGBA_ASTC_10x10_KHR, CompressedFormat(10, 10, 128, 4, GL_COMPRESSED_RGBA_ASTC_10x10_KHR, GL_UNSIGNED_BYTE, false, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGBA_ASTC_12x10_KHR, CompressedFormat(12, 10, 128, 4, GL_COMPRESSED_RGBA_ASTC_12x10_KHR, GL_UNSIGNED_BYTE, false, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGBA_ASTC_12x12_KHR, CompressedFormat(12, 12, 128, 4, GL_COMPRESSED_RGBA_ASTC_12x12_KHR, GL_UNSIGNED_BYTE, false, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported))); - - map.insert(InternalFormatInfoPair(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR, CompressedFormat( 4, 4, 128, 4, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR, GL_UNSIGNED_BYTE, true, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR, CompressedFormat( 5, 4, 128, 4, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR, GL_UNSIGNED_BYTE, true, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR, CompressedFormat( 5, 5, 128, 4, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR, GL_UNSIGNED_BYTE, true, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR, CompressedFormat( 6, 5, 128, 4, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR, GL_UNSIGNED_BYTE, true, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR, CompressedFormat( 6, 6, 128, 4, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR, GL_UNSIGNED_BYTE, true, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR, CompressedFormat( 8, 5, 128, 4, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR, GL_UNSIGNED_BYTE, true, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR, CompressedFormat( 8, 6, 128, 4, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR, GL_UNSIGNED_BYTE, true, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR, CompressedFormat( 8, 8, 128, 4, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR, GL_UNSIGNED_BYTE, true, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR, CompressedFormat(10, 5, 128, 4, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR, GL_UNSIGNED_BYTE, true, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR, CompressedFormat(10, 6, 128, 4, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR, GL_UNSIGNED_BYTE, true, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR, CompressedFormat(10, 8, 128, 4, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR, GL_UNSIGNED_BYTE, true, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR, CompressedFormat(10, 10, 128, 4, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR, GL_UNSIGNED_BYTE, true, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR, CompressedFormat(12, 10, 128, 4, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR, GL_UNSIGNED_BYTE, true, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR, CompressedFormat(12, 12, 128, 4, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR, GL_UNSIGNED_BYTE, true, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported))); + // | Internal format | W | H | BS |CC| Format | Type | SRGB | Supported | Renderable | Filterable | + AddCompressedFormat(&map, GL_COMPRESSED_RGBA_ASTC_4x4_KHR, 4, 4, 128, 4, GL_RGBA, GL_UNSIGNED_BYTE, false, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported); + AddCompressedFormat(&map, GL_COMPRESSED_RGBA_ASTC_5x4_KHR, 5, 4, 128, 4, GL_RGBA, GL_UNSIGNED_BYTE, false, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported); + AddCompressedFormat(&map, GL_COMPRESSED_RGBA_ASTC_5x5_KHR, 5, 5, 128, 4, GL_RGBA, GL_UNSIGNED_BYTE, false, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported); + AddCompressedFormat(&map, GL_COMPRESSED_RGBA_ASTC_6x5_KHR, 6, 5, 128, 4, GL_RGBA, GL_UNSIGNED_BYTE, false, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported); + AddCompressedFormat(&map, GL_COMPRESSED_RGBA_ASTC_6x6_KHR, 6, 6, 128, 4, GL_RGBA, GL_UNSIGNED_BYTE, false, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported); + AddCompressedFormat(&map, GL_COMPRESSED_RGBA_ASTC_8x5_KHR, 8, 5, 128, 4, GL_RGBA, GL_UNSIGNED_BYTE, false, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported); + AddCompressedFormat(&map, GL_COMPRESSED_RGBA_ASTC_8x6_KHR, 8, 6, 128, 4, GL_RGBA, GL_UNSIGNED_BYTE, false, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported); + AddCompressedFormat(&map, GL_COMPRESSED_RGBA_ASTC_8x8_KHR, 8, 8, 128, 4, GL_RGBA, GL_UNSIGNED_BYTE, false, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported); + AddCompressedFormat(&map, GL_COMPRESSED_RGBA_ASTC_10x5_KHR, 10, 5, 128, 4, GL_RGBA, GL_UNSIGNED_BYTE, false, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported); + AddCompressedFormat(&map, GL_COMPRESSED_RGBA_ASTC_10x6_KHR, 10, 6, 128, 4, GL_RGBA, GL_UNSIGNED_BYTE, false, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported); + AddCompressedFormat(&map, GL_COMPRESSED_RGBA_ASTC_10x8_KHR, 10, 8, 128, 4, GL_RGBA, GL_UNSIGNED_BYTE, false, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported); + AddCompressedFormat(&map, GL_COMPRESSED_RGBA_ASTC_10x10_KHR, 10, 10, 128, 4, GL_RGBA, GL_UNSIGNED_BYTE, false, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported); + AddCompressedFormat(&map, GL_COMPRESSED_RGBA_ASTC_12x10_KHR, 12, 10, 128, 4, GL_RGBA, GL_UNSIGNED_BYTE, false, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported); + AddCompressedFormat(&map, GL_COMPRESSED_RGBA_ASTC_12x12_KHR, 12, 12, 128, 4, GL_RGBA, GL_UNSIGNED_BYTE, false, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported); + + AddCompressedFormat(&map, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR, 4, 4, 128, 4, GL_RGBA, GL_UNSIGNED_BYTE, true, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported); + AddCompressedFormat(&map, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR, 5, 4, 128, 4, GL_RGBA, GL_UNSIGNED_BYTE, true, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported); + AddCompressedFormat(&map, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR, 5, 5, 128, 4, GL_RGBA, GL_UNSIGNED_BYTE, true, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported); + AddCompressedFormat(&map, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR, 6, 5, 128, 4, GL_RGBA, GL_UNSIGNED_BYTE, true, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported); + AddCompressedFormat(&map, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR, 6, 6, 128, 4, GL_RGBA, GL_UNSIGNED_BYTE, true, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported); + AddCompressedFormat(&map, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR, 8, 5, 128, 4, GL_RGBA, GL_UNSIGNED_BYTE, true, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported); + AddCompressedFormat(&map, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR, 8, 6, 128, 4, GL_RGBA, GL_UNSIGNED_BYTE, true, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported); + AddCompressedFormat(&map, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR, 8, 8, 128, 4, GL_RGBA, GL_UNSIGNED_BYTE, true, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported); + AddCompressedFormat(&map, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR, 10, 5, 128, 4, GL_RGBA, GL_UNSIGNED_BYTE, true, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported); + AddCompressedFormat(&map, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR, 10, 6, 128, 4, GL_RGBA, GL_UNSIGNED_BYTE, true, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported); + AddCompressedFormat(&map, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR, 10, 8, 128, 4, GL_RGBA, GL_UNSIGNED_BYTE, true, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported); + AddCompressedFormat(&map, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR, 10, 10, 128, 4, GL_RGBA, GL_UNSIGNED_BYTE, true, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported); + AddCompressedFormat(&map, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR, 12, 10, 128, 4, GL_RGBA, GL_UNSIGNED_BYTE, true, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported); + AddCompressedFormat(&map, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR, 12, 12, 128, 4, GL_RGBA, GL_UNSIGNED_BYTE, true, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, 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))); + // | Internal format |sized|D |S |X | Format | Type | Component type | Supported | Renderable | Filterable | + AddDepthStencilFormat(&map, GL_STENCIL_INDEX8, true, 0, 8, 0, GL_STENCIL, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, RequireES<2, 0>, RequireES<2, 0>, NeverSupported); // From GL_ANGLE_lossy_etc_decode - map.insert(InternalFormatInfoPair(GL_ETC1_RGB8_LOSSY_DECODE_ANGLE, CompressedFormat(4, 4, 64, 3, GL_ETC1_RGB8_OES, GL_UNSIGNED_BYTE, false, RequireExt<&Extensions::lossyETCDecode>, NeverSupported, AlwaysSupported))); + // | Internal format |W |H |BS |CC| Format | Type | SRGB | Supported | Renderable | Filterable | + AddCompressedFormat(&map, GL_ETC1_RGB8_LOSSY_DECODE_ANGLE, 4, 4, 64, 3, GL_RGB, GL_UNSIGNED_BYTE, false, RequireExt<&Extensions::lossyETCDecode>, NeverSupported, AlwaysSupported); + AddCompressedFormat(&map, GL_COMPRESSED_RGB8_LOSSY_DECODE_ETC2_ANGLE, 4, 4, 64, 3, GL_RGB, GL_UNSIGNED_BYTE, false, RequireExt<&Extensions::lossyETCDecode>, NeverSupported, AlwaysSupported); + AddCompressedFormat(&map, GL_COMPRESSED_SRGB8_LOSSY_DECODE_ETC2_ANGLE, 4, 4, 64, 3, GL_RGB, GL_UNSIGNED_BYTE, true, RequireExt<&Extensions::lossyETCDecode>, NeverSupported, AlwaysSupported); + AddCompressedFormat(&map, GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE, 4, 4, 64, 3, GL_RGBA, GL_UNSIGNED_BYTE, false, RequireExt<&Extensions::lossyETCDecode>, NeverSupported, AlwaysSupported); + AddCompressedFormat(&map, GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE, 4, 4, 64, 3, GL_RGBA, GL_UNSIGNED_BYTE, true, RequireExt<&Extensions::lossyETCDecode>, NeverSupported, AlwaysSupported); + + // From GL_EXT_texture_norm16 + // | Internal format |sized| R | G | B | A |S | Format | Type | Component type | SRGB | Texture supported | Renderable | Filterable | + AddRGBAFormat(&map, GL_R16_EXT, true, 16, 0, 0, 0, 0, GL_RED, GL_UNSIGNED_SHORT, GL_UNSIGNED_NORMALIZED, false, RequireExt<&Extensions::textureNorm16>, RequireExt<&Extensions::textureNorm16>, AlwaysSupported); + AddRGBAFormat(&map, GL_R16_SNORM_EXT, true, 16, 0, 0, 0, 0, GL_RED, GL_SHORT, GL_SIGNED_NORMALIZED, false, RequireExt<&Extensions::textureNorm16>, NeverSupported, AlwaysSupported); + AddRGBAFormat(&map, GL_RG16_EXT, true, 16, 16, 0, 0, 0, GL_RG, GL_UNSIGNED_SHORT, GL_UNSIGNED_NORMALIZED, false, RequireExt<&Extensions::textureNorm16>, RequireExt<&Extensions::textureNorm16>, AlwaysSupported); + AddRGBAFormat(&map, GL_RG16_SNORM_EXT, true, 16, 16, 0, 0, 0, GL_RG, GL_SHORT, GL_SIGNED_NORMALIZED, false, RequireExt<&Extensions::textureNorm16>, NeverSupported, AlwaysSupported); + AddRGBAFormat(&map, GL_RGB16_EXT, true, 16, 16, 16, 0, 0, GL_RGB, GL_UNSIGNED_SHORT, GL_UNSIGNED_NORMALIZED, false, RequireExt<&Extensions::textureNorm16>, NeverSupported, AlwaysSupported); + AddRGBAFormat(&map, GL_RGB16_SNORM_EXT, true, 16, 16, 16, 0, 0, GL_RGB, GL_SHORT, GL_SIGNED_NORMALIZED, false, RequireExt<&Extensions::textureNorm16>, NeverSupported, AlwaysSupported); + AddRGBAFormat(&map, GL_RGBA16_EXT, true, 16, 16, 16, 16, 0, GL_RGBA, GL_UNSIGNED_SHORT, GL_UNSIGNED_NORMALIZED, false, RequireExt<&Extensions::textureNorm16>, RequireExt<&Extensions::textureNorm16>, AlwaysSupported); + AddRGBAFormat(&map, GL_RGBA16_SNORM_EXT, true, 16, 16, 16, 16, 0, GL_RGBA, GL_SHORT, GL_SIGNED_NORMALIZED, false, RequireExt<&Extensions::textureNorm16>, NeverSupported, AlwaysSupported); + // Unsized formats + // | Internal format |sized | R | G | B | A |S | Format | Type | Component type | SRGB | Texture supported | Renderable | Filterable | + AddRGBAFormat(&map, GL_RED, false, 8, 0, 0, 0, 0, GL_RED, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, false, RequireExt<&Extensions::textureRG>, AlwaysSupported, AlwaysSupported); + AddRGBAFormat(&map, GL_RED, false, 8, 0, 0, 0, 0, GL_RED, GL_BYTE, GL_SIGNED_NORMALIZED, false, NeverSupported, NeverSupported, NeverSupported ); + AddRGBAFormat(&map, GL_RG, false, 8, 8, 0, 0, 0, GL_RG, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, false, RequireExt<&Extensions::textureRG>, AlwaysSupported, AlwaysSupported); + AddRGBAFormat(&map, GL_RG, false, 8, 8, 0, 0, 0, GL_RG, GL_BYTE, GL_SIGNED_NORMALIZED, false, NeverSupported, NeverSupported, NeverSupported ); + AddRGBAFormat(&map, GL_RGB, false, 8, 8, 8, 0, 0, GL_RGB, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, false, RequireES<2, 0>, AlwaysSupported, AlwaysSupported); + AddRGBAFormat(&map, GL_RGB, false, 5, 6, 5, 0, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, GL_UNSIGNED_NORMALIZED, false, RequireES<2, 0>, RequireES<2, 0>, AlwaysSupported); + AddRGBAFormat(&map, GL_RGB, false, 8, 8, 8, 0, 0, GL_RGB, GL_BYTE, GL_SIGNED_NORMALIZED, false, NeverSupported, NeverSupported, NeverSupported ); + AddRGBAFormat(&map, GL_RGBA, false, 4, 4, 4, 4, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, GL_UNSIGNED_NORMALIZED, false, RequireES<2, 0>, RequireES<2, 0>, AlwaysSupported); + AddRGBAFormat(&map, GL_RGBA, false, 5, 5, 5, 1, 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, GL_UNSIGNED_NORMALIZED, false, RequireES<2, 0>, RequireES<2, 0>, AlwaysSupported); + AddRGBAFormat(&map, GL_RGBA, false, 8, 8, 8, 8, 0, GL_RGBA, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, false, RequireES<2, 0>, RequireES<2, 0>, AlwaysSupported); + AddRGBAFormat(&map, GL_RGBA, false, 10, 10, 10, 2, 0, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV, GL_UNSIGNED_NORMALIZED, false, RequireES<2, 0>, RequireES<2, 0>, AlwaysSupported); + AddRGBAFormat(&map, GL_RGBA, false, 8, 8, 8, 8, 0, GL_RGBA, GL_BYTE, GL_SIGNED_NORMALIZED, false, NeverSupported, NeverSupported, NeverSupported ); + AddRGBAFormat(&map, GL_SRGB, false, 8, 8, 8, 0, 0, GL_RGB, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, true, RequireExt<&Extensions::sRGB>, NeverSupported, AlwaysSupported); + AddRGBAFormat(&map, GL_SRGB_ALPHA_EXT, false, 8, 8, 8, 8, 0, GL_RGBA, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, true, RequireExt<&Extensions::sRGB>, RequireExt<&Extensions::sRGB>, AlwaysSupported); + + AddRGBAFormat(&map, GL_BGRA_EXT, false, 8, 8, 8, 8, 0, GL_BGRA_EXT, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, false, RequireExt<&Extensions::textureFormatBGRA8888>, RequireExt<&Extensions::textureFormatBGRA8888>, AlwaysSupported); + + // Unsized integer formats + // |Internal format |sized | R | G | B | A |S | Format | Type | Component type | SRGB | Texture | Renderable | Filterable | + AddRGBAFormat(&map, GL_RED_INTEGER, false, 8, 0, 0, 0, 0, GL_RED_INTEGER, GL_BYTE, GL_INT, false, RequireES<3, 0>, NeverSupported, NeverSupported); + AddRGBAFormat(&map, GL_RED_INTEGER, false, 8, 0, 0, 0, 0, GL_RED_INTEGER, GL_UNSIGNED_BYTE, GL_UNSIGNED_INT, false, RequireES<3, 0>, NeverSupported, NeverSupported); + AddRGBAFormat(&map, GL_RED_INTEGER, false, 16, 0, 0, 0, 0, GL_RED_INTEGER, GL_SHORT, GL_INT, false, RequireES<3, 0>, NeverSupported, NeverSupported); + AddRGBAFormat(&map, GL_RED_INTEGER, false, 16, 0, 0, 0, 0, GL_RED_INTEGER, GL_UNSIGNED_SHORT, GL_UNSIGNED_INT, false, RequireES<3, 0>, NeverSupported, NeverSupported); + AddRGBAFormat(&map, GL_RED_INTEGER, false, 32, 0, 0, 0, 0, GL_RED_INTEGER, GL_INT, GL_INT, false, RequireES<3, 0>, NeverSupported, NeverSupported); + AddRGBAFormat(&map, GL_RED_INTEGER, false, 32, 0, 0, 0, 0, GL_RED_INTEGER, GL_UNSIGNED_INT, GL_UNSIGNED_INT, false, RequireES<3, 0>, NeverSupported, NeverSupported); + AddRGBAFormat(&map, GL_RG_INTEGER, false, 8, 8, 0, 0, 0, GL_RG_INTEGER, GL_BYTE, GL_INT, false, RequireES<3, 0>, NeverSupported, NeverSupported); + AddRGBAFormat(&map, GL_RG_INTEGER, false, 8, 8, 0, 0, 0, GL_RG_INTEGER, GL_UNSIGNED_BYTE, GL_UNSIGNED_INT, false, RequireES<3, 0>, NeverSupported, NeverSupported); + AddRGBAFormat(&map, GL_RG_INTEGER, false, 16, 16, 0, 0, 0, GL_RG_INTEGER, GL_SHORT, GL_INT, false, RequireES<3, 0>, NeverSupported, NeverSupported); + AddRGBAFormat(&map, GL_RG_INTEGER, false, 16, 16, 0, 0, 0, GL_RG_INTEGER, GL_UNSIGNED_SHORT, GL_UNSIGNED_INT, false, RequireES<3, 0>, NeverSupported, NeverSupported); + AddRGBAFormat(&map, GL_RG_INTEGER, false, 32, 32, 0, 0, 0, GL_RG_INTEGER, GL_INT, GL_INT, false, RequireES<3, 0>, NeverSupported, NeverSupported); + AddRGBAFormat(&map, GL_RG_INTEGER, false, 32, 32, 0, 0, 0, GL_RG_INTEGER, GL_UNSIGNED_INT, GL_UNSIGNED_INT, false, RequireES<3, 0>, NeverSupported, NeverSupported); + AddRGBAFormat(&map, GL_RGB_INTEGER, false, 8, 8, 8, 0, 0, GL_RGB_INTEGER, GL_BYTE, GL_INT, false, RequireES<3, 0>, NeverSupported, NeverSupported); + AddRGBAFormat(&map, GL_RGB_INTEGER, false, 8, 8, 8, 0, 0, GL_RGB_INTEGER, GL_UNSIGNED_BYTE, GL_UNSIGNED_INT, false, RequireES<3, 0>, NeverSupported, NeverSupported); + AddRGBAFormat(&map, GL_RGB_INTEGER, false, 16, 16, 16, 0, 0, GL_RGB_INTEGER, GL_SHORT, GL_INT, false, RequireES<3, 0>, NeverSupported, NeverSupported); + AddRGBAFormat(&map, GL_RGB_INTEGER, false, 16, 16, 16, 0, 0, GL_RGB_INTEGER, GL_UNSIGNED_SHORT, GL_UNSIGNED_INT, false, RequireES<3, 0>, NeverSupported, NeverSupported); + AddRGBAFormat(&map, GL_RGB_INTEGER, false, 32, 32, 32, 0, 0, GL_RGB_INTEGER, GL_INT, GL_INT, false, RequireES<3, 0>, NeverSupported, NeverSupported); + AddRGBAFormat(&map, GL_RGB_INTEGER, false, 32, 32, 32, 0, 0, GL_RGB_INTEGER, GL_UNSIGNED_INT, GL_UNSIGNED_INT, false, RequireES<3, 0>, NeverSupported, NeverSupported); + AddRGBAFormat(&map, GL_RGBA_INTEGER, false, 8, 8, 8, 8, 0, GL_RGBA_INTEGER, GL_BYTE, GL_INT, false, RequireES<3, 0>, NeverSupported, NeverSupported); + AddRGBAFormat(&map, GL_RGBA_INTEGER, false, 8, 8, 8, 8, 0, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE, GL_UNSIGNED_INT, false, RequireES<3, 0>, NeverSupported, NeverSupported); + AddRGBAFormat(&map, GL_RGBA_INTEGER, false, 16, 16, 16, 16, 0, GL_RGBA_INTEGER, GL_SHORT, GL_INT, false, RequireES<3, 0>, NeverSupported, NeverSupported); + AddRGBAFormat(&map, GL_RGBA_INTEGER, false, 16, 16, 16, 16, 0, GL_RGBA_INTEGER, GL_UNSIGNED_SHORT, GL_UNSIGNED_INT, false, RequireES<3, 0>, NeverSupported, NeverSupported); + AddRGBAFormat(&map, GL_RGBA_INTEGER, false, 32, 32, 32, 32, 0, GL_RGBA_INTEGER, GL_INT, GL_INT, false, RequireES<3, 0>, NeverSupported, NeverSupported); + AddRGBAFormat(&map, GL_RGBA_INTEGER, false, 32, 32, 32, 32, 0, GL_RGBA_INTEGER, GL_UNSIGNED_INT, GL_UNSIGNED_INT, false, RequireES<3, 0>, NeverSupported, NeverSupported); + AddRGBAFormat(&map, GL_RGBA_INTEGER, false, 10, 10, 10, 2, 0, GL_RGBA_INTEGER, GL_UNSIGNED_INT_2_10_10_10_REV, GL_UNSIGNED_INT, false, RequireES<3, 0>, NeverSupported, NeverSupported); + + // Unsized floating point formats + // |Internal format |sized | R | G | B | A |S | Format | Type | Comp | SRGB | Texture supported | Renderable | Filterable | + AddRGBAFormat(&map, GL_RED, false, 16, 0, 0, 0, 0, GL_RED, GL_HALF_FLOAT, GL_FLOAT, false, NeverSupported, NeverSupported, NeverSupported ); + AddRGBAFormat(&map, GL_RG, false, 16, 16, 0, 0, 0, GL_RG, GL_HALF_FLOAT, GL_FLOAT, false, NeverSupported, NeverSupported, NeverSupported ); + AddRGBAFormat(&map, GL_RGB, false, 16, 16, 16, 0, 0, GL_RGB, GL_HALF_FLOAT, GL_FLOAT, false, NeverSupported, NeverSupported, NeverSupported ); + AddRGBAFormat(&map, GL_RGBA, false, 16, 16, 16, 16, 0, GL_RGBA, GL_HALF_FLOAT, GL_FLOAT, false, NeverSupported, NeverSupported, NeverSupported ); + AddRGBAFormat(&map, GL_RED, false, 16, 0, 0, 0, 0, GL_RED, GL_HALF_FLOAT_OES, GL_FLOAT, false, UnsizedHalfFloatOESRGSupport, UnsizedHalfFloatOESRGRenderableSupport, RequireESOrExt<3, 0, &Extensions::textureHalfFloatLinear>); + AddRGBAFormat(&map, GL_RG, false, 16, 16, 0, 0, 0, GL_RG, GL_HALF_FLOAT_OES, GL_FLOAT, false, UnsizedHalfFloatOESRGSupport, UnsizedHalfFloatOESRGRenderableSupport, RequireESOrExt<3, 0, &Extensions::textureHalfFloatLinear>); + AddRGBAFormat(&map, GL_RGB, false, 16, 16, 16, 0, 0, GL_RGB, GL_HALF_FLOAT_OES, GL_FLOAT, false, UnsizedHalfFloatOESSupport, UnsizedHalfFloatOESRenderableSupport, RequireESOrExt<3, 0, &Extensions::textureHalfFloatLinear>); + AddRGBAFormat(&map, GL_RGBA, false, 16, 16, 16, 16, 0, GL_RGBA, GL_HALF_FLOAT_OES, GL_FLOAT, false, UnsizedHalfFloatOESSupport, UnsizedHalfFloatOESRenderableSupport, RequireESOrExt<3, 0, &Extensions::textureHalfFloatLinear>); + AddRGBAFormat(&map, GL_RED, false, 32, 0, 0, 0, 0, GL_RED, GL_FLOAT, GL_FLOAT, false, UnsizedFloatRGSupport, UnsizedFloatRGRenderableSupport, RequireExt<&Extensions::textureFloatLinear> ); + AddRGBAFormat(&map, GL_RG, false, 32, 32, 0, 0, 0, GL_RG, GL_FLOAT, GL_FLOAT, false, UnsizedFloatRGSupport, UnsizedFloatRGRenderableSupport, RequireExt<&Extensions::textureFloatLinear> ); + AddRGBAFormat(&map, GL_RGB, false, 32, 32, 32, 0, 0, GL_RGB, GL_FLOAT, GL_FLOAT, false, UnsizedFloatSupport, UnsizedFloatRGBRenderableSupport, RequireExt<&Extensions::textureFloatLinear> ); + AddRGBAFormat(&map, GL_RGB, false, 9, 9, 9, 0, 5, GL_RGB, GL_UNSIGNED_INT_5_9_9_9_REV, GL_FLOAT, false, NeverSupported, NeverSupported, NeverSupported ); + AddRGBAFormat(&map, GL_RGB, false, 11, 11, 10, 0, 0, GL_RGB, GL_UNSIGNED_INT_10F_11F_11F_REV, GL_FLOAT, false, NeverSupported, NeverSupported, NeverSupported ); + AddRGBAFormat(&map, GL_RGBA, false, 32, 32, 32, 32, 0, GL_RGBA, GL_FLOAT, GL_FLOAT, false, UnsizedFloatSupport, UnsizedFloatRGBARenderableSupport, RequireExt<&Extensions::textureFloatLinear> ); + + // Unsized luminance alpha formats + // | Internal format |sized | L | A | Format | Type | Component type | Supported | Renderable | Filterable | + AddLUMAFormat(&map, GL_ALPHA, false, 0, 8, GL_ALPHA, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, RequireES<2, 0>, NeverSupported, AlwaysSupported ); + AddLUMAFormat(&map, GL_LUMINANCE, false, 8, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, RequireES<2, 0>, NeverSupported, AlwaysSupported ); + AddLUMAFormat(&map, GL_LUMINANCE_ALPHA, false, 8, 8, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, RequireES<2, 0>, NeverSupported, AlwaysSupported ); + AddLUMAFormat(&map, GL_ALPHA, false, 0, 16, GL_ALPHA, GL_HALF_FLOAT_OES, GL_FLOAT, RequireExt<&Extensions::textureHalfFloat>, NeverSupported, RequireExt<&Extensions::textureHalfFloatLinear>); + AddLUMAFormat(&map, GL_LUMINANCE, false, 16, 0, GL_LUMINANCE, GL_HALF_FLOAT_OES, GL_FLOAT, RequireExt<&Extensions::textureHalfFloat>, NeverSupported, RequireExt<&Extensions::textureHalfFloatLinear>); + AddLUMAFormat(&map, GL_LUMINANCE_ALPHA ,false, 16, 16, GL_LUMINANCE_ALPHA, GL_HALF_FLOAT_OES, GL_FLOAT, RequireExt<&Extensions::textureHalfFloat>, NeverSupported, RequireExt<&Extensions::textureHalfFloatLinear>); + AddLUMAFormat(&map, GL_ALPHA, false, 0, 32, GL_ALPHA, GL_FLOAT, GL_FLOAT, RequireExt<&Extensions::textureFloat>, NeverSupported, RequireExt<&Extensions::textureFloatLinear> ); + AddLUMAFormat(&map, GL_LUMINANCE, false, 32, 0, GL_LUMINANCE, GL_FLOAT, GL_FLOAT, RequireExt<&Extensions::textureFloat>, NeverSupported, RequireExt<&Extensions::textureFloatLinear> ); + AddLUMAFormat(&map, GL_LUMINANCE_ALPHA, false, 32, 32, GL_LUMINANCE_ALPHA, GL_FLOAT, GL_FLOAT, RequireExt<&Extensions::textureFloat>, NeverSupported, RequireExt<&Extensions::textureFloatLinear> ); + + // Unsized depth stencil formats + // | Internal format |sized | D |S | X | Format | Type | Component type | Supported | Renderable | Filterable | + AddDepthStencilFormat(&map, GL_DEPTH_COMPONENT, false, 16, 0, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, GL_UNSIGNED_NORMALIZED, RequireES<2, 0>, RequireES<2, 0>, AlwaysSupported); + AddDepthStencilFormat(&map, GL_DEPTH_COMPONENT, false, 24, 0, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, GL_UNSIGNED_NORMALIZED, RequireES<2, 0>, RequireES<2, 0>, AlwaysSupported); + AddDepthStencilFormat(&map, GL_DEPTH_COMPONENT, false, 32, 0, 0, GL_DEPTH_COMPONENT, GL_FLOAT, GL_FLOAT, RequireES<2, 0>, RequireES<2, 0>, AlwaysSupported); + AddDepthStencilFormat(&map, GL_DEPTH_STENCIL, false, 24, 8, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, GL_UNSIGNED_NORMALIZED, RequireESOrExt<3, 0, &Extensions::packedDepthStencil>, RequireESOrExt<3, 0, &Extensions::packedDepthStencil>, AlwaysSupported); + AddDepthStencilFormat(&map, GL_DEPTH_STENCIL, false, 32, 8, 24, GL_DEPTH_STENCIL, GL_FLOAT_32_UNSIGNED_INT_24_8_REV, GL_FLOAT, RequireESOrExt<3, 0, &Extensions::packedDepthStencil>, RequireESOrExt<3, 0, &Extensions::packedDepthStencil>, AlwaysSupported); + AddDepthStencilFormat(&map, GL_STENCIL, false, 0, 8, 0, GL_STENCIL, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, RequireES<2, 0>, RequireES<2, 0>, NeverSupported); // clang-format on return map; @@ -584,12 +940,18 @@ static FormatSet BuildAllSizedInternalFormatSet() { FormatSet result; - const InternalFormatInfoMap &formats = GetInternalFormatMap(); - for (InternalFormatInfoMap::const_iterator i = formats.begin(); i != formats.end(); i++) + for (const auto &internalFormat : GetInternalFormatMap()) { - if (i->second.pixelBytes > 0) + for (const auto &type : internalFormat.second) { - result.insert(i->first); + if (type.second.sized) + { + // TODO(jmadill): Fix this hack. + if (internalFormat.first == GL_BGR565_ANGLEX) + continue; + + result.insert(internalFormat.first); + } } } @@ -652,107 +1014,199 @@ const Type &GetTypeInfo(GLenum type) } } -const InternalFormat GetInternalFormatInfo(GLenum internalFormat) +const InternalFormat &GetSizedInternalFormatInfo(GLenum internalFormat) { + static const InternalFormat defaultInternalFormat; const InternalFormatInfoMap &formatMap = GetInternalFormatMap(); - InternalFormatInfoMap::const_iterator iter = formatMap.find(internalFormat); - if (iter != formatMap.end()) + auto iter = formatMap.find(internalFormat); + + // Sized internal formats only have one type per entry + if (iter == formatMap.end() || iter->second.size() != 1) { - return iter->second; + return defaultInternalFormat; } - else + + const InternalFormat &internalFormatInfo = iter->second.begin()->second; + if (!internalFormatInfo.sized) { - static const InternalFormat defaultInternalFormat; return defaultInternalFormat; } + + return internalFormatInfo; } -GLuint InternalFormat::computeRowPitch(GLenum formatType, GLsizei width, GLint alignment, GLint rowLength) const +const InternalFormat &GetInternalFormatInfo(GLenum internalFormat, GLenum type) { - ASSERT(alignment > 0 && isPow2(alignment)); - GLuint rowBytes; - if (rowLength > 0) + static const InternalFormat defaultInternalFormat; + const InternalFormatInfoMap &formatMap = GetInternalFormatMap(); + + auto internalFormatIter = formatMap.find(internalFormat); + if (internalFormatIter == formatMap.end()) { - ASSERT(!compressed); - rowBytes = pixelBytes * rowLength; + return defaultInternalFormat; } - else + + // If the internal format is sized, simply return it without the type check. + if (internalFormatIter->second.size() == 1 && internalFormatIter->second.begin()->second.sized) { - rowBytes = computeBlockSize(formatType, width, 1); + return internalFormatIter->second.begin()->second; } - return rx::roundUp(rowBytes, static_cast(alignment)); + + auto typeIter = internalFormatIter->second.find(type); + if (typeIter == internalFormatIter->second.end()) + { + return defaultInternalFormat; + } + + return typeIter->second; +} + +GLuint InternalFormat::computePixelBytes(GLenum formatType) const +{ + const auto &typeInfo = GetTypeInfo(formatType); + GLuint components = typeInfo.specialInterpretation ? 1u : componentCount; + return components * typeInfo.bytes; } -GLuint InternalFormat::computeDepthPitch(GLenum formatType, - GLsizei width, - GLsizei height, - GLint alignment, - GLint rowLength, - GLint imageHeight) const +ErrorOrResult InternalFormat::computeRowPitch(GLenum formatType, + GLsizei width, + GLint alignment, + GLint rowLength) const { - GLuint rows; - if (imageHeight > 0) + // Compressed images do not use pack/unpack parameters. + if (compressed) { - rows = imageHeight; + ASSERT(rowLength == 0); + return computeCompressedImageSize(Extents(width, 1, 1)); } - else + + CheckedNumeric checkedWidth(rowLength > 0 ? rowLength : width); + CheckedNumeric checkedRowBytes = checkedWidth * computePixelBytes(formatType); + + ASSERT(alignment > 0 && isPow2(alignment)); + CheckedNumeric checkedAlignment(alignment); + auto aligned = rx::roundUp(checkedRowBytes, checkedAlignment); + ANGLE_TRY_CHECKED_MATH(aligned); + return aligned.ValueOrDie(); +} + +ErrorOrResult InternalFormat::computeDepthPitch(GLsizei height, + GLint imageHeight, + GLuint rowPitch) const +{ + GLuint rows = + (imageHeight > 0 ? static_cast(imageHeight) : static_cast(height)); + CheckedNumeric checkedRowPitch(rowPitch); + + auto depthPitch = checkedRowPitch * rows; + ANGLE_TRY_CHECKED_MATH(depthPitch); + return depthPitch.ValueOrDie(); +} + +ErrorOrResult InternalFormat::computeDepthPitch(GLenum formatType, + GLsizei width, + GLsizei height, + GLint alignment, + GLint rowLength, + GLint imageHeight) const +{ + GLuint rowPitch = 0; + ANGLE_TRY_RESULT(computeRowPitch(formatType, width, alignment, rowLength), rowPitch); + return computeDepthPitch(height, imageHeight, rowPitch); +} + +ErrorOrResult InternalFormat::computeCompressedImageSize(const Extents &size) const +{ + CheckedNumeric checkedWidth(size.width); + CheckedNumeric checkedHeight(size.height); + CheckedNumeric checkedDepth(size.depth); + CheckedNumeric checkedBlockWidth(compressedBlockWidth); + CheckedNumeric checkedBlockHeight(compressedBlockHeight); + + ASSERT(compressed); + auto numBlocksWide = (checkedWidth + checkedBlockWidth - 1u) / checkedBlockWidth; + auto numBlocksHigh = (checkedHeight + checkedBlockHeight - 1u) / checkedBlockHeight; + auto bytes = numBlocksWide * numBlocksHigh * pixelBytes * checkedDepth; + ANGLE_TRY_CHECKED_MATH(bytes); + return bytes.ValueOrDie(); +} + +ErrorOrResult InternalFormat::computeSkipBytes(GLuint rowPitch, + GLuint depthPitch, + const PixelStoreStateBase &state, + bool is3D) const +{ + CheckedNumeric checkedRowPitch(rowPitch); + CheckedNumeric checkedDepthPitch(depthPitch); + CheckedNumeric checkedSkipImages(static_cast(state.skipImages)); + CheckedNumeric checkedSkipRows(static_cast(state.skipRows)); + CheckedNumeric checkedSkipPixels(static_cast(state.skipPixels)); + CheckedNumeric checkedPixelBytes(pixelBytes); + auto checkedSkipImagesBytes = checkedSkipImages * checkedDepthPitch; + if (!is3D) { - rows = height; + checkedSkipImagesBytes = 0; } - return computeRowPitch(formatType, width, alignment, rowLength) * rows; + auto skipBytes = checkedSkipImagesBytes + checkedSkipRows * checkedRowPitch + + checkedSkipPixels * checkedPixelBytes; + ANGLE_TRY_CHECKED_MATH(skipBytes); + return skipBytes.ValueOrDie(); } -GLuint InternalFormat::computeBlockSize(GLenum formatType, GLsizei width, GLsizei height) const +ErrorOrResult InternalFormat::computePackUnpackEndByte( + GLenum formatType, + const Extents &size, + const PixelStoreStateBase &state, + bool is3D) const { + GLuint rowPitch = 0; + ANGLE_TRY_RESULT(computeRowPitch(formatType, size.width, state.alignment, state.rowLength), + rowPitch); + + GLuint depthPitch = 0; + if (is3D) + { + ANGLE_TRY_RESULT(computeDepthPitch(size.height, state.imageHeight, rowPitch), depthPitch); + } + + CheckedNumeric checkedCopyBytes = 0; if (compressed) { - GLsizei numBlocksWide = (width + compressedBlockWidth - 1) / compressedBlockWidth; - GLsizei numBlocksHight = (height + compressedBlockHeight - 1) / compressedBlockHeight; - return (pixelBytes * numBlocksWide * numBlocksHight); + ANGLE_TRY_RESULT(computeCompressedImageSize(size), checkedCopyBytes); } - else + else if (size.height != 0 && (!is3D || size.depth != 0)) { - const Type &typeInfo = GetTypeInfo(formatType); - if (typeInfo.specialInterpretation) - { - return typeInfo.bytes * width * height; - } - else + CheckedNumeric bytes = computePixelBytes(formatType); + checkedCopyBytes += size.width * bytes; + + CheckedNumeric heightMinusOne = size.height - 1; + checkedCopyBytes += heightMinusOne * rowPitch; + + if (is3D) { - return componentCount * typeInfo.bytes * width * height; + CheckedNumeric depthMinusOne = size.depth - 1; + checkedCopyBytes += depthMinusOne * depthPitch; } } -} -GLuint InternalFormat::computeSkipPixels(GLint rowPitch, - GLint depthPitch, - GLint skipImages, - GLint skipRows, - GLint skipPixels) const -{ - return skipImages * depthPitch + skipRows * rowPitch + skipPixels * pixelBytes; + CheckedNumeric checkedSkipBytes = 0; + ANGLE_TRY_RESULT(computeSkipBytes(rowPitch, depthPitch, state, is3D), checkedSkipBytes); + + CheckedNumeric endByte = checkedCopyBytes + checkedSkipBytes; + + ANGLE_TRY_CHECKED_MATH(endByte); + return endByte.ValueOrDie(); } -GLenum GetSizedInternalFormat(GLenum internalFormat, GLenum type) +GLenum GetUnsizedFormat(GLenum internalFormat) { - const InternalFormat& formatInfo = GetInternalFormatInfo(internalFormat); - if (formatInfo.pixelBytes > 0) + auto sizedFormatInfo = GetSizedInternalFormatInfo(internalFormat); + if (sizedFormatInfo.internalFormat != GL_NONE) { - 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; - } + return sizedFormatInfo.format; } + + return internalFormat; } const FormatSet &GetAllSizedInternalFormats() @@ -1543,6 +1997,129 @@ const VertexFormat &GetVertexFormatFromType(VertexFormatType vertexFormatType) } } +size_t GetVertexFormatTypeSize(VertexFormatType vertexFormatType) +{ + switch (vertexFormatType) + { + case VERTEX_FORMAT_SBYTE1: + case VERTEX_FORMAT_SBYTE1_NORM: + case VERTEX_FORMAT_UBYTE1: + case VERTEX_FORMAT_UBYTE1_NORM: + case VERTEX_FORMAT_SBYTE1_INT: + case VERTEX_FORMAT_UBYTE1_INT: + return 1; + + case VERTEX_FORMAT_SBYTE2: + case VERTEX_FORMAT_SBYTE2_NORM: + case VERTEX_FORMAT_UBYTE2: + case VERTEX_FORMAT_UBYTE2_NORM: + case VERTEX_FORMAT_SBYTE2_INT: + case VERTEX_FORMAT_UBYTE2_INT: + case VERTEX_FORMAT_SSHORT1: + case VERTEX_FORMAT_SSHORT1_NORM: + case VERTEX_FORMAT_USHORT1: + case VERTEX_FORMAT_USHORT1_NORM: + case VERTEX_FORMAT_SSHORT1_INT: + case VERTEX_FORMAT_USHORT1_INT: + case VERTEX_FORMAT_HALF1: + return 2; + + case VERTEX_FORMAT_SBYTE3: + case VERTEX_FORMAT_SBYTE3_NORM: + case VERTEX_FORMAT_UBYTE3: + case VERTEX_FORMAT_UBYTE3_NORM: + case VERTEX_FORMAT_SBYTE3_INT: + case VERTEX_FORMAT_UBYTE3_INT: + return 3; + + case VERTEX_FORMAT_SBYTE4: + case VERTEX_FORMAT_SBYTE4_NORM: + case VERTEX_FORMAT_UBYTE4: + case VERTEX_FORMAT_UBYTE4_NORM: + case VERTEX_FORMAT_SBYTE4_INT: + case VERTEX_FORMAT_UBYTE4_INT: + case VERTEX_FORMAT_SSHORT2: + case VERTEX_FORMAT_SSHORT2_NORM: + case VERTEX_FORMAT_USHORT2: + case VERTEX_FORMAT_USHORT2_NORM: + case VERTEX_FORMAT_SSHORT2_INT: + case VERTEX_FORMAT_USHORT2_INT: + case VERTEX_FORMAT_SINT1: + case VERTEX_FORMAT_SINT1_NORM: + case VERTEX_FORMAT_UINT1: + case VERTEX_FORMAT_UINT1_NORM: + case VERTEX_FORMAT_SINT1_INT: + case VERTEX_FORMAT_UINT1_INT: + case VERTEX_FORMAT_HALF2: + case VERTEX_FORMAT_FIXED1: + case VERTEX_FORMAT_FLOAT1: + case VERTEX_FORMAT_SINT210: + case VERTEX_FORMAT_UINT210: + case VERTEX_FORMAT_SINT210_NORM: + case VERTEX_FORMAT_UINT210_NORM: + case VERTEX_FORMAT_SINT210_INT: + case VERTEX_FORMAT_UINT210_INT: + return 4; + + case VERTEX_FORMAT_SSHORT3: + case VERTEX_FORMAT_SSHORT3_NORM: + case VERTEX_FORMAT_USHORT3: + case VERTEX_FORMAT_USHORT3_NORM: + case VERTEX_FORMAT_SSHORT3_INT: + case VERTEX_FORMAT_USHORT3_INT: + case VERTEX_FORMAT_HALF3: + return 6; + + case VERTEX_FORMAT_SSHORT4: + case VERTEX_FORMAT_SSHORT4_NORM: + case VERTEX_FORMAT_USHORT4: + case VERTEX_FORMAT_USHORT4_NORM: + case VERTEX_FORMAT_SSHORT4_INT: + case VERTEX_FORMAT_USHORT4_INT: + case VERTEX_FORMAT_SINT2: + case VERTEX_FORMAT_SINT2_NORM: + case VERTEX_FORMAT_UINT2: + case VERTEX_FORMAT_UINT2_NORM: + case VERTEX_FORMAT_SINT2_INT: + case VERTEX_FORMAT_UINT2_INT: + case VERTEX_FORMAT_HALF4: + case VERTEX_FORMAT_FIXED2: + case VERTEX_FORMAT_FLOAT2: + return 8; + + case VERTEX_FORMAT_SINT3: + case VERTEX_FORMAT_SINT3_NORM: + case VERTEX_FORMAT_UINT3: + case VERTEX_FORMAT_UINT3_NORM: + case VERTEX_FORMAT_SINT3_INT: + case VERTEX_FORMAT_UINT3_INT: + case VERTEX_FORMAT_FIXED3: + case VERTEX_FORMAT_FLOAT3: + return 12; + + case VERTEX_FORMAT_SINT4: + case VERTEX_FORMAT_SINT4_NORM: + case VERTEX_FORMAT_UINT4: + case VERTEX_FORMAT_UINT4_NORM: + case VERTEX_FORMAT_SINT4_INT: + case VERTEX_FORMAT_UINT4_INT: + case VERTEX_FORMAT_FIXED4: + case VERTEX_FORMAT_FLOAT4: + return 16; + + case VERTEX_FORMAT_INVALID: + default: + UNREACHABLE(); + return 0; + } +} + +bool ValidES3InternalFormat(GLenum internalFormat) +{ + const InternalFormatInfoMap &formatMap = GetInternalFormatMap(); + return internalFormat != GL_NONE && formatMap.find(internalFormat) != formatMap.end(); +} + VertexFormat::VertexFormat(GLenum typeIn, GLboolean normalizedIn, GLuint componentsIn, bool pureIntegerIn) : type(typeIn), normalized(normalizedIn), diff --git a/src/3rdparty/angle/src/libANGLE/formatutils.h b/src/3rdparty/angle/src/libANGLE/formatutils.h index 2165e6badd..dbfe590846 100644 --- a/src/3rdparty/angle/src/libANGLE/formatutils.h +++ b/src/3rdparty/angle/src/libANGLE/formatutils.h @@ -9,16 +9,32 @@ #ifndef LIBANGLE_FORMATUTILS_H_ #define LIBANGLE_FORMATUTILS_H_ -#include "libANGLE/Caps.h" -#include "libANGLE/angletypes.h" - -#include "angle_gl.h" - #include +#include #include +#include "angle_gl.h" +#include "libANGLE/Caps.h" +#include "libANGLE/Error.h" +#include "libANGLE/Version.h" +#include "libANGLE/angletypes.h" + namespace gl { +struct VertexAttribute; + +struct FormatType final +{ + FormatType(); + FormatType(GLenum format_, GLenum type_); + FormatType(const FormatType &other) = default; + FormatType &operator=(const FormatType &other) = default; + + bool operator<(const FormatType &other) const; + + GLenum format; + GLenum type; +}; struct Type { @@ -30,9 +46,58 @@ struct Type }; const Type &GetTypeInfo(GLenum type); +// Information about an OpenGL internal format. Can be keyed on the internalFormat and type +// members. struct InternalFormat { InternalFormat(); + InternalFormat(const InternalFormat &other); + + GLuint computePixelBytes(GLenum formatType) const; + + ErrorOrResult computeRowPitch(GLenum formatType, + GLsizei width, + GLint alignment, + GLint rowLength) const; + ErrorOrResult computeDepthPitch(GLsizei height, + GLint imageHeight, + GLuint rowPitch) const; + ErrorOrResult computeDepthPitch(GLenum formatType, + GLsizei width, + GLsizei height, + GLint alignment, + GLint rowLength, + GLint imageHeight) const; + + ErrorOrResult computeCompressedImageSize(const Extents &size) const; + + ErrorOrResult computeSkipBytes(GLuint rowPitch, + GLuint depthPitch, + const PixelStoreStateBase &state, + bool is3D) const; + + ErrorOrResult computePackUnpackEndByte(GLenum formatType, + const Extents &size, + const PixelStoreStateBase &state, + bool is3D) const; + + bool isLUMA() const; + GLenum getReadPixelsFormat() const; + GLenum getReadPixelsType(const Version &version) const; + + // Return true if the format is a required renderbuffer format in the given version of the core + // spec. Note that it isn't always clear whether all the rules that apply to core required + // renderbuffer formats also apply to additional formats added by extensions. Because of this + // extension formats are conservatively not included. + bool isRequiredRenderbufferFormat(const Version &version) const; + + bool operator==(const InternalFormat &other) const; + bool operator!=(const InternalFormat &other) const; + + GLenum internalFormat; + + bool sized; + GLenum sizedInternalFormat; GLuint redBits; GLuint greenBits; @@ -60,28 +125,45 @@ struct InternalFormat GLenum componentType; GLenum colorEncoding; - typedef bool (*SupportCheckFunction)(GLuint, const Extensions &); + typedef bool (*SupportCheckFunction)(const Version &, const Extensions &); SupportCheckFunction textureSupport; SupportCheckFunction renderSupport; SupportCheckFunction filterSupport; +}; + +// A "Format" wraps an InternalFormat struct, querying it from either a sized internal format or +// unsized internal format and type. +// TODO(geofflang): Remove this, it doesn't add any more information than the InternalFormat object. +struct Format +{ + // Sized types only. + explicit Format(GLenum internalFormat); + + // Sized or unsized types. + explicit Format(const InternalFormat &internalFormat); + Format(GLenum internalFormat, GLenum type); + + Format(const Format &other); + Format &operator=(const Format &other); - GLuint computeRowPitch(GLenum formatType, GLsizei width, GLint alignment, GLint rowLength) const; - GLuint computeDepthPitch(GLenum formatType, - GLsizei width, - GLsizei height, - GLint alignment, - GLint rowLength, - GLint imageHeight) const; - GLuint computeBlockSize(GLenum formatType, GLsizei width, GLsizei height) const; - GLuint computeSkipPixels(GLint rowPitch, - GLint depthPitch, - GLint skipImages, - GLint skipRows, - GLint skipPixels) const; + bool valid() const; + + static Format Invalid(); + static bool SameSized(const Format &a, const Format &b); + static bool EquivalentForBlit(const Format &a, const Format &b); + + friend std::ostream &operator<<(std::ostream &os, const Format &fmt); + + // This is the sized info. + const InternalFormat *info; }; -const InternalFormat GetInternalFormatInfo(GLenum internalFormat); -GLenum GetSizedInternalFormat(GLenum internalFormat, GLenum type); +const InternalFormat &GetSizedInternalFormatInfo(GLenum internalFormat); +const InternalFormat &GetInternalFormatInfo(GLenum internalFormat, GLenum type); + +// Strip sizing information from an internal format. Doesn't necessarily validate that the internal +// format is valid. +GLenum GetUnsizedFormat(GLenum internalFormat); typedef std::set FormatSet; const FormatSet &GetAllSizedInternalFormats(); @@ -212,9 +294,9 @@ enum VertexFormatType VERTEX_FORMAT_UINT210_INT, }; -typedef std::vector InputLayout; +typedef std::vector InputLayout; -struct VertexFormat : angle::NonCopyable +struct VertexFormat : private angle::NonCopyable { VertexFormat(GLenum typeIn, GLboolean normalizedIn, GLuint componentsIn, bool pureIntegerIn); @@ -228,6 +310,19 @@ VertexFormatType GetVertexFormatType(GLenum type, GLboolean normalized, GLuint c VertexFormatType GetVertexFormatType(const VertexAttribute &attrib); VertexFormatType GetVertexFormatType(const VertexAttribute &attrib, GLenum currentValueType); const VertexFormat &GetVertexFormatFromType(VertexFormatType vertexFormatType); +size_t GetVertexFormatTypeSize(VertexFormatType vertexFormatType); + +// Check if an internal format is ever valid in ES3. Makes no checks about support for a specific +// context. +bool ValidES3InternalFormat(GLenum internalFormat); + +// Implemented in format_map_autogen.cpp +bool ValidES3Format(GLenum format); +bool ValidES3Type(GLenum type); +bool ValidES3FormatCombination(GLenum format, GLenum type, GLenum internalFormat); + +// Implemented in es3_copy_conversion_table_autogen.cpp +bool ValidES3CopyConversion(GLenum textureFormat, GLenum framebufferFormat); } // namespace gl diff --git a/src/3rdparty/angle/src/libANGLE/histogram_macros.h b/src/3rdparty/angle/src/libANGLE/histogram_macros.h index d1c952a6bd..fb428b46d2 100644 --- a/src/3rdparty/angle/src/libANGLE/histogram_macros.h +++ b/src/3rdparty/angle/src/libANGLE/histogram_macros.h @@ -41,18 +41,19 @@ #define ANGLE_HISTOGRAM_COUNTS_10000(name, sample) \ ANGLE_HISTOGRAM_CUSTOM_COUNTS(name, sample, 1, 10000, 50) -#define ANGLE_HISTOGRAM_CUSTOM_COUNTS(name, sample, min, max, bucket_count) \ - ANGLEPlatformCurrent()->histogramCustomCounts(\ - name, sample, min, max, bucket_count) +#define ANGLE_HISTOGRAM_CUSTOM_COUNTS(name, sample, min, max, bucket_count) \ + ANGLEPlatformCurrent()->histogramCustomCounts(ANGLEPlatformCurrent(), name, sample, min, max, \ + bucket_count) #define ANGLE_HISTOGRAM_PERCENTAGE(name, under_one_hundred) \ ANGLE_HISTOGRAM_ENUMERATION(name, under_one_hundred, 101) #define ANGLE_HISTOGRAM_BOOLEAN(name, sample) \ - ANGLEPlatformCurrent()->histogramBoolean(name, sample) + ANGLEPlatformCurrent()->histogramBoolean(ANGLEPlatformCurrent(), name, sample) -#define ANGLE_HISTOGRAM_ENUMERATION(name, sample, boundary_value) \ - ANGLEPlatformCurrent()->histogramEnumeration(name, sample, boundary_value) +#define ANGLE_HISTOGRAM_ENUMERATION(name, sample, boundary_value) \ + ANGLEPlatformCurrent()->histogramEnumeration(ANGLEPlatformCurrent(), name, sample, \ + boundary_value) #define ANGLE_HISTOGRAM_MEMORY_KB(name, sample) ANGLE_HISTOGRAM_CUSTOM_COUNTS( \ name, sample, 1000, 500000, 50) @@ -61,7 +62,7 @@ name, sample, 1, 1000, 50) #define ANGLE_HISTOGRAM_SPARSE_SLOWLY(name, sample) \ - ANGLEPlatformCurrent()->histogramSparse(name, sample) + ANGLEPlatformCurrent()->histogramSparse(ANGLEPlatformCurrent(), name, sample) // Scoped class which logs its time on this earth as a UMA statistic. This is // recommended for when you want a histogram which measures the time it takes @@ -79,29 +80,33 @@ #define SCOPED_ANGLE_HISTOGRAM_TIMER_EXPANDER(name, is_long, key) \ SCOPED_ANGLE_HISTOGRAM_TIMER_UNIQUE(name, is_long, key) -#define SCOPED_ANGLE_HISTOGRAM_TIMER_UNIQUE(name, is_long, key) \ - class ScopedHistogramTimer##key \ - { \ - public: \ - ScopedHistogramTimer##key() : constructed_(ANGLEPlatformCurrent()->currentTime()) {} \ - ~ScopedHistogramTimer##key() \ - { \ - if (constructed_ == 0) \ - return; \ - double elapsed = ANGLEPlatformCurrent()->currentTime() - constructed_; \ - int elapsedMS = static_cast(elapsed * 1000.0); \ - if (is_long) \ - { \ - ANGLE_HISTOGRAM_LONG_TIMES_100(name, elapsedMS); \ - } \ - else \ - { \ - ANGLE_HISTOGRAM_TIMES(name, elapsedMS); \ - } \ - } \ - \ - private: \ - double constructed_; \ +#define SCOPED_ANGLE_HISTOGRAM_TIMER_UNIQUE(name, is_long, key) \ + class ScopedHistogramTimer##key \ + { \ + public: \ + ScopedHistogramTimer##key() \ + : constructed_(ANGLEPlatformCurrent()->currentTime(ANGLEPlatformCurrent())) \ + { \ + } \ + ~ScopedHistogramTimer##key() \ + { \ + if (constructed_ == 0) \ + return; \ + auto *platform = ANGLEPlatformCurrent(); \ + double elapsed = platform->currentTime(platform) - constructed_; \ + int elapsedMS = static_cast(elapsed * 1000.0); \ + if (is_long) \ + { \ + ANGLE_HISTOGRAM_LONG_TIMES_100(name, elapsedMS); \ + } \ + else \ + { \ + ANGLE_HISTOGRAM_TIMES(name, elapsedMS); \ + } \ + } \ + \ + private: \ + double constructed_; \ } scoped_histogram_timer_##key -#endif // BASE_METRICS_HISTOGRAM_MACROS_H_ +#endif // LIBANGLE_HISTOGRAM_MACROS_H_ diff --git a/src/3rdparty/angle/src/libANGLE/packed_gl_enums.json b/src/3rdparty/angle/src/libANGLE/packed_gl_enums.json new file mode 100644 index 0000000000..7e77de2f36 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/packed_gl_enums.json @@ -0,0 +1,35 @@ +{ + "BufferBinding": + { + "Array": "GL_ARRAY_BUFFER", + "AtomicCounter": "GL_ATOMIC_COUNTER_BUFFER", + "CopyRead": "GL_COPY_READ_BUFFER", + "CopyWrite": "GL_COPY_WRITE_BUFFER", + "DispatchIndirect": "GL_DISPATCH_INDIRECT_BUFFER", + "DrawIndirect": "GL_DRAW_INDIRECT_BUFFER", + "ElementArray": "GL_ELEMENT_ARRAY_BUFFER", + "PixelPack": "GL_PIXEL_PACK_BUFFER", + "PixelUnpack": "GL_PIXEL_UNPACK_BUFFER", + "ShaderStorage": "GL_SHADER_STORAGE_BUFFER", + "TransformFeedback": "GL_TRANSFORM_FEEDBACK_BUFFER", + "Uniform": "GL_UNIFORM_BUFFER" + }, + "BufferUsage": + { + "DynamicCopy": "GL_DYNAMIC_COPY", + "DynamicDraw": "GL_DYNAMIC_DRAW", + "DynamicRead": "GL_DYNAMIC_READ", + "StaticCopy": "GL_STATIC_COPY", + "StaticDraw": "GL_STATIC_DRAW", + "StaticRead": "GL_STATIC_READ", + "StreamCopy": "GL_STREAM_COPY", + "StreamDraw": "GL_STREAM_DRAW", + "StreamRead": "GL_STREAM_READ" + }, + "CullFaceMode": + { + "Back": "GL_BACK", + "Front": "GL_FRONT", + "FrontAndBack": "GL_FRONT_AND_BACK" + } +} diff --git a/src/3rdparty/angle/src/libANGLE/params.cpp b/src/3rdparty/angle/src/libANGLE/params.cpp new file mode 100644 index 0000000000..a89d87e0a9 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/params.cpp @@ -0,0 +1,68 @@ +// +// Copyright 2017 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. +// +// params: +// Parameter wrapper structs for OpenGL ES. These helpers cache re-used values +// in entry point routines. + +#include "libANGLE/params.h" + +#include "common/utilities.h" +#include "libANGLE/Context.h" +#include "libANGLE/VertexArray.h" + +namespace gl +{ + +// static +constexpr ParamTypeInfo ParamsBase::TypeInfo; +constexpr ParamTypeInfo HasIndexRange::TypeInfo; + +HasIndexRange::HasIndexRange() + : ParamsBase(nullptr), mContext(nullptr), mCount(0), mType(GL_NONE), mIndices(nullptr) +{ +} + +HasIndexRange::HasIndexRange(Context *context, GLsizei count, GLenum type, const void *indices) + : ParamsBase(context), mContext(context), mCount(count), mType(type), mIndices(indices) +{ +} + +const Optional &HasIndexRange::getIndexRange() const +{ + if (mIndexRange.valid() || !mContext) + { + return mIndexRange; + } + + const State &state = mContext->getGLState(); + + const gl::VertexArray *vao = state.getVertexArray(); + gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get(); + + if (elementArrayBuffer) + { + uintptr_t offset = reinterpret_cast(mIndices); + IndexRange indexRange; + Error error = + elementArrayBuffer->getIndexRange(mContext, mType, static_cast(offset), mCount, + state.isPrimitiveRestartEnabled(), &indexRange); + if (error.isError()) + { + mContext->handleError(error); + return mIndexRange; + } + + mIndexRange = indexRange; + } + else + { + mIndexRange = ComputeIndexRange(mType, mIndices, mCount, state.isPrimitiveRestartEnabled()); + } + + return mIndexRange; +} + +} // namespace gl diff --git a/src/3rdparty/angle/src/libANGLE/params.h b/src/3rdparty/angle/src/libANGLE/params.h new file mode 100644 index 0000000000..27dba640ff --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/params.h @@ -0,0 +1,228 @@ +// +// Copyright 2017 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. +// +// params: +// Parameter wrapper structs for OpenGL ES. These helpers cache re-used values +// in entry point routines. + +#ifndef LIBANGLE_PARAMS_H_ +#define LIBANGLE_PARAMS_H_ + +#include "angle_gl.h" +#include "common/Optional.h" +#include "common/angleutils.h" +#include "common/mathutil.h" +#include "libANGLE/entry_points_enum_autogen.h" + +namespace gl +{ +class Context; + +template +struct EntryPointParam; + +template +using EntryPointParamType = typename EntryPointParam::Type; + +class ParamTypeInfo +{ + public: + constexpr ParamTypeInfo(const char *selfClass, const ParamTypeInfo *parentType) + : mSelfClass(selfClass), mParentTypeInfo(parentType) + { + } + + constexpr bool hasDynamicType(const ParamTypeInfo &typeInfo) const + { + return mSelfClass == typeInfo.mSelfClass || + (mParentTypeInfo && mParentTypeInfo->hasDynamicType(typeInfo)); + } + + constexpr bool isValid() const { return mSelfClass != nullptr; } + + private: + const char *mSelfClass; + const ParamTypeInfo *mParentTypeInfo; +}; + +#define ANGLE_PARAM_TYPE_INFO(NAME, BASENAME) \ + static constexpr ParamTypeInfo TypeInfo = {#NAME, &BASENAME::TypeInfo} + +class ParamsBase : angle::NonCopyable +{ + public: + ParamsBase(Context *context, ...){}; + + template + static void Factory(EntryPointParamType *objBuffer, ArgsT... args); + + static constexpr ParamTypeInfo TypeInfo = {nullptr, nullptr}; +}; + +// static +template +ANGLE_INLINE void ParamsBase::Factory(EntryPointParamType *objBuffer, ArgsT... args) +{ + new (objBuffer) EntryPointParamType(args...); +} + +class HasIndexRange : public ParamsBase +{ + public: + // Dummy placeholder that can't generate an index range. + HasIndexRange(); + HasIndexRange(Context *context, GLsizei count, GLenum type, const void *indices); + + template + static void Factory(HasIndexRange *objBuffer, ArgsT... args); + + const Optional &getIndexRange() const; + + ANGLE_PARAM_TYPE_INFO(HasIndexRange, ParamsBase); + + private: + Context *mContext; + GLsizei mCount; + GLenum mType; + const GLvoid *mIndices; + mutable Optional mIndexRange; +}; + +// Entry point funcs essentially re-map different entry point parameter arrays into +// the format the parameter type class expects. For example, for HasIndexRange, for the +// various indexed draw calls, they drop parameters that aren't useful and re-arrange +// the rest. +#define ANGLE_ENTRY_POINT_FUNC(NAME, CLASS, ...) \ + \ +template<> struct EntryPointParam \ + { \ + using Type = CLASS; \ + }; \ + \ +template<> inline void CLASS::Factory(__VA_ARGS__) + +ANGLE_ENTRY_POINT_FUNC(DrawElements, + HasIndexRange, + HasIndexRange *objBuffer, + Context *context, + GLenum /*mode*/, + GLsizei count, + GLenum type, + const void *indices) +{ + return ParamsBase::Factory(objBuffer, context, count, type, indices); +} + +ANGLE_ENTRY_POINT_FUNC(DrawElementsInstanced, + HasIndexRange, + HasIndexRange *objBuffer, + Context *context, + GLenum /*mode*/, + GLsizei count, + GLenum type, + const void *indices, + GLsizei /*instanceCount*/) +{ + return ParamsBase::Factory(objBuffer, context, count, type, + indices); +} + +ANGLE_ENTRY_POINT_FUNC(DrawElementsInstancedANGLE, + HasIndexRange, + HasIndexRange *objBuffer, + Context *context, + GLenum /*mode*/, + GLsizei count, + GLenum type, + const void *indices, + GLsizei /*instanceCount*/) +{ + return ParamsBase::Factory(objBuffer, context, count, + type, indices); +} + +ANGLE_ENTRY_POINT_FUNC(DrawRangeElements, + HasIndexRange, + HasIndexRange *objBuffer, + Context *context, + GLenum /*mode*/, + GLuint /*start*/, + GLuint /*end*/, + GLsizei count, + GLenum type, + const void *indices) +{ + return ParamsBase::Factory(objBuffer, context, count, type, + indices); +} + +#undef ANGLE_ENTRY_POINT_FUNC + +template +struct EntryPointParam +{ + using Type = ParamsBase; +}; + +// A template struct for determining the default value to return for each entry point. +template +struct DefaultReturnValue; + +// Default return values for each basic return type. +template +struct DefaultReturnValue +{ + static constexpr GLint kValue = -1; +}; + +// This doubles as the GLenum return value. +template +struct DefaultReturnValue +{ + static constexpr GLuint kValue = 0; +}; + +template +struct DefaultReturnValue +{ + static constexpr GLboolean kValue = GL_FALSE; +}; + +// Catch-all rules for pointer types. +template +struct DefaultReturnValue +{ + static constexpr const PointerType *kValue = nullptr; +}; + +template +struct DefaultReturnValue +{ + static constexpr PointerType *kValue = nullptr; +}; + +// Overloaded to return invalid index +template <> +struct DefaultReturnValue +{ + static constexpr GLuint kValue = GL_INVALID_INDEX; +}; + +// Specialized enum error value. +template <> +struct DefaultReturnValue +{ + static constexpr GLenum kValue = GL_WAIT_FAILED; +}; + +template +constexpr ANGLE_INLINE ReturnType GetDefaultReturnValue() +{ + return DefaultReturnValue::kValue; +} + +} // namespace gl + +#endif // LIBANGLE_PARAMS_H_ diff --git a/src/3rdparty/angle/src/libANGLE/queryconversions.cpp b/src/3rdparty/angle/src/libANGLE/queryconversions.cpp index 3a6059a89c..78d219365e 100644 --- a/src/3rdparty/angle/src/libANGLE/queryconversions.cpp +++ b/src/3rdparty/angle/src/libANGLE/queryconversions.cpp @@ -24,18 +24,9 @@ GLint64 ExpandFloatToInteger(GLfloat value) return static_cast((static_cast(0xFFFFFFFFULL) * value - 1.0) / 2.0); } -template -QueryT ClampToQueryRange(GLint64 value) -{ - const GLint64 min = static_cast(std::numeric_limits::min()); - const GLint64 max = static_cast(std::numeric_limits::max()); - return static_cast(clamp(value, min, max)); -} - template -QueryT CastStateValueToInt(GLenum pname, NativeT value) +QueryT CastFromStateValueToInt(GLenum pname, NativeT value) { - GLenum queryType = GLTypeToGLenum::value; GLenum nativeType = GLTypeToGLenum::value; if (nativeType == GL_FLOAT) @@ -43,37 +34,68 @@ QueryT CastStateValueToInt(GLenum pname, NativeT value) // 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 ClampToQueryRange(ExpandFloatToInteger(static_cast(value))); + return clampCast(ExpandFloatToInteger(static_cast(value))); } else { - return gl::iround(static_cast(value)); + return clampCast(std::round(value)); } } - // Clamp 64-bit int values when casting to int - if (nativeType == GL_INT_64_ANGLEX && queryType == GL_INT) + return clampCast(value); +} + +template +NativeT CastQueryValueToInt(GLenum pname, QueryT value) +{ + GLenum queryType = GLTypeToGLenum::value; + + if (queryType == GL_FLOAT) { - 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(std::round(value)); } - return static_cast(value); + return static_cast(value); +} + +} // anonymous namespace + +// ES 3.10 Section 2.2.2 +// When querying bitmasks(such as SAMPLE_MASK_VALUE or STENCIL_WRITEMASK) with GetIntegerv, the +// mask value is treated as a signed integer, so that mask values with the high bit set will not be +// clamped when returned as signed integers. +GLint CastMaskValue(const Context *context, GLuint value) +{ + return (context->getClientVersion() >= Version(3, 1) ? static_cast(value) + : clampCast(value)); +} + +template +QueryT CastFromGLintStateValue(GLenum pname, InternalT value) +{ + return CastFromStateValue(pname, clampCast(value)); } +template GLfloat CastFromGLintStateValue(GLenum pname, GLenum value); +template GLint CastFromGLintStateValue(GLenum pname, GLenum value); +template GLint64 CastFromGLintStateValue(GLenum pname, GLenum value); +template GLuint CastFromGLintStateValue(GLenum pname, GLenum value); +template GLfloat CastFromGLintStateValue(GLenum pname, bool value); +template GLuint CastFromGLintStateValue(GLenum pname, bool value); +template GLint CastFromGLintStateValue(GLenum pname, bool value); + template -QueryT CastStateValue(GLenum pname, NativeT value) +QueryT CastFromStateValue(GLenum pname, NativeT value) { GLenum queryType = GLTypeToGLenum::value; switch (queryType) { case GL_INT: - return CastStateValueToInt(pname, value); case GL_INT_64_ANGLEX: - return CastStateValueToInt(pname, value); + case GL_UNSIGNED_INT: + case GL_UINT_64_ANGLEX: + return CastFromStateValueToInt(pname, value); case GL_FLOAT: return static_cast(value); case GL_BOOL: @@ -83,19 +105,50 @@ QueryT CastStateValue(GLenum pname, NativeT value) return 0; } } +template GLint CastFromStateValue(GLenum pname, GLint value); +template GLint CastFromStateValue(GLenum pname, GLint64 value); +template GLint64 CastFromStateValue(GLenum pname, GLint value); +template GLint64 CastFromStateValue(GLenum pname, GLint64 value); +template GLfloat CastFromStateValue(GLenum pname, GLint value); +template GLfloat CastFromStateValue(GLenum pname, GLfloat value); +template GLint CastFromStateValue(GLenum pname, GLfloat value); +template GLuint CastFromStateValue(GLenum pname, GLint value); +template GLuint CastFromStateValue(GLenum pname, GLuint value); +template GLint CastFromStateValue(GLenum pname, GLboolean value); +template GLint64 CastFromStateValue(GLenum pname, GLboolean value); +template GLint CastFromStateValue(GLenum pname, GLuint value); +template GLint64 CastFromStateValue(GLenum pname, GLuint value); +template GLuint64 CastFromStateValue(GLenum pname, GLuint value); -} // anonymous namespace +template +NativeT CastQueryValueTo(GLenum pname, QueryT value) +{ + GLenum nativeType = GLTypeToGLenum::value; + + switch (nativeType) + { + case GL_INT: + case GL_INT_64_ANGLEX: + case GL_UNSIGNED_INT: + case GL_UINT_64_ANGLEX: + return CastQueryValueToInt(pname, value); + case GL_FLOAT: + return static_cast(value); + case GL_BOOL: + return static_cast(value == static_cast(0) ? GL_FALSE : GL_TRUE); + default: + UNREACHABLE(); + return 0; + } +} -template <> -GLenum GLTypeToGLenum::value = GL_INT; -template <> -GLenum GLTypeToGLenum::value = GL_UNSIGNED_INT; -template <> -GLenum GLTypeToGLenum::value = GL_BOOL; -template <> -GLenum GLTypeToGLenum::value = GL_INT_64_ANGLEX; -template <> -GLenum GLTypeToGLenum::value = GL_FLOAT; +template GLint CastQueryValueTo(GLenum pname, GLfloat value); +template GLboolean CastQueryValueTo(GLenum pname, GLint value); +template GLint CastQueryValueTo(GLenum pname, GLint value); +template GLfloat CastQueryValueTo(GLenum pname, GLint value); +template GLfloat CastQueryValueTo(GLenum pname, GLfloat value); +template GLuint CastQueryValueTo(GLenum pname, GLint value); +template GLuint CastQueryValueTo(GLenum pname, GLfloat value); template void CastStateValues(Context *context, GLenum nativeType, GLenum pname, @@ -104,17 +157,17 @@ void CastStateValues(Context *context, GLenum nativeType, GLenum pname, if (nativeType == GL_INT) { std::vector intParams(numParams, 0); - context->getIntegerv(pname, intParams.data()); + context->getIntegervImpl(pname, intParams.data()); for (unsigned int i = 0; i < numParams; ++i) { - outParams[i] = CastStateValue(pname, intParams[i]); + outParams[i] = CastFromStateValue(pname, intParams[i]); } } else if (nativeType == GL_BOOL) { std::vector boolParams(numParams, GL_FALSE); - context->getBooleanv(pname, boolParams.data()); + context->getBooleanvImpl(pname, boolParams.data()); for (unsigned int i = 0; i < numParams; ++i) { @@ -124,11 +177,11 @@ void CastStateValues(Context *context, GLenum nativeType, GLenum pname, else if (nativeType == GL_FLOAT) { std::vector floatParams(numParams, 0.0f); - context->getFloatv(pname, floatParams.data()); + context->getFloatvImpl(pname, floatParams.data()); for (unsigned int i = 0; i < numParams; ++i) { - outParams[i] = CastStateValue(pname, floatParams[i]); + outParams[i] = CastFromStateValue(pname, floatParams[i]); } } else if (nativeType == GL_INT_64_ANGLEX) @@ -138,7 +191,7 @@ void CastStateValues(Context *context, GLenum nativeType, GLenum pname, for (unsigned int i = 0; i < numParams; ++i) { - outParams[i] = CastStateValue(pname, int64Params[i]); + outParams[i] = CastFromStateValue(pname, int64Params[i]); } } else UNREACHABLE(); @@ -146,7 +199,7 @@ void CastStateValues(Context *context, GLenum nativeType, GLenum pname, // 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 +// The GL state query API types are: bool, int, uint, float, int64, uint64 template void CastStateValues(Context *, GLenum, GLenum, unsigned int, GLboolean *); template void CastStateValues(Context *, GLenum, GLenum, unsigned int, GLint *); @@ -154,4 +207,77 @@ template void CastStateValues(Context *, GLenum, GLenum, unsigned int, G template void CastStateValues(Context *, GLenum, GLenum, unsigned int, GLfloat *); template void CastStateValues(Context *, GLenum, GLenum, unsigned int, GLint64 *); +template +void CastIndexedStateValues(Context *context, + GLenum nativeType, + GLenum pname, + GLuint index, + unsigned int numParams, + QueryT *outParams) +{ + if (nativeType == GL_INT) + { + std::vector intParams(numParams, 0); + context->getIntegeri_v(pname, index, intParams.data()); + + for (unsigned int i = 0; i < numParams; ++i) + { + outParams[i] = CastFromStateValue(pname, intParams[i]); + } + } + else if (nativeType == GL_BOOL) + { + std::vector boolParams(numParams, GL_FALSE); + context->getBooleani_v(pname, index, boolParams.data()); + + for (unsigned int i = 0; i < numParams; ++i) + { + outParams[i] = + (boolParams[i] == GL_FALSE ? static_cast(0) : static_cast(1)); + } + } + else if (nativeType == GL_INT_64_ANGLEX) + { + std::vector int64Params(numParams, 0); + context->getInteger64i_v(pname, index, int64Params.data()); + + for (unsigned int i = 0; i < numParams; ++i) + { + outParams[i] = CastFromStateValue(pname, int64Params[i]); + } + } + else + UNREACHABLE(); +} + +template void CastIndexedStateValues(Context *, + GLenum, + GLenum, + GLuint index, + unsigned int, + GLboolean *); +template void CastIndexedStateValues(Context *, + GLenum, + GLenum, + GLuint index, + unsigned int, + GLint *); +template void CastIndexedStateValues(Context *, + GLenum, + GLenum, + GLuint index, + unsigned int, + GLuint *); +template void CastIndexedStateValues(Context *, + GLenum, + GLenum, + GLuint index, + unsigned int, + GLfloat *); +template void CastIndexedStateValues(Context *, + GLenum, + GLenum, + GLuint index, + unsigned int, + GLint64 *); } diff --git a/src/3rdparty/angle/src/libANGLE/queryconversions.h b/src/3rdparty/angle/src/libANGLE/queryconversions.h index e0fdbe17e0..805f36cf02 100644 --- a/src/3rdparty/angle/src/libANGLE/queryconversions.h +++ b/src/3rdparty/angle/src/libANGLE/queryconversions.h @@ -18,19 +18,100 @@ class Context; // 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. +// We restrict our use to CastFromStateValue and CastQueryValueTo, where it eliminates +// duplicate parameters. template struct GLTypeToGLenum { - static GLenum value; + // static constexpr GLenum value; }; -// The GL state query API types are: bool, int, uint, float, int64 +template <> +struct GLTypeToGLenum +{ + static constexpr GLenum value = GL_INT; +}; +template <> +struct GLTypeToGLenum +{ + static constexpr GLenum value = GL_UNSIGNED_INT; +}; +template <> +struct GLTypeToGLenum +{ + static constexpr GLenum value = GL_BOOL; +}; +template <> +struct GLTypeToGLenum +{ + static constexpr GLenum value = GL_INT_64_ANGLEX; +}; +template <> +struct GLTypeToGLenum +{ + static constexpr GLenum value = GL_UINT_64_ANGLEX; +}; +template <> +struct GLTypeToGLenum +{ + static constexpr GLenum value = GL_FLOAT; +}; + +GLint CastMaskValue(const Context *context, GLuint value); + +template +QueryT CastFromGLintStateValue(GLenum pname, InternalT value); + +template +QueryT CastFromStateValue(GLenum pname, NativeT value); + +template +NativeT CastQueryValueTo(GLenum pname, QueryT value); + +template +GLenum ConvertToGLenum(GLenum pname, ParamType param) +{ + return static_cast(CastQueryValueTo(pname, param)); +} + +template +GLenum ConvertToGLenum(ParamType param) +{ + return ConvertToGLenum(GL_NONE, param); +} + +template +GLenum ConvertToGLint(ParamType param) +{ + return CastQueryValueTo(GL_NONE, param); +} + +template +bool ConvertToBool(ParamType param) +{ + return param != GL_FALSE; +} + +template +GLboolean ConvertToGLBoolean(ParamType param) +{ + return param ? GL_TRUE : GL_FALSE; +} + +// The GL state query API types are: bool, int, uint, float, int64, uint64 template void CastStateValues(Context *context, GLenum nativeType, GLenum pname, unsigned int numParams, QueryT *outParams); +// The GL state query API types are: bool, int, uint, float, int64, uint64 +template +void CastIndexedStateValues(Context *context, + GLenum nativeType, + GLenum pname, + GLuint index, + unsigned int numParams, + QueryT *outParams); } #endif // LIBANGLE_QUERY_CONVERSIONS_H_ diff --git a/src/3rdparty/angle/src/libANGLE/queryutils.cpp b/src/3rdparty/angle/src/libANGLE/queryutils.cpp new file mode 100644 index 0000000000..16a989c688 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/queryutils.cpp @@ -0,0 +1,1916 @@ +// +// Copyright (c) 2016 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. +// + +// queryutils.cpp: Utilities for querying values from GL objects + +#include "libANGLE/queryutils.h" + +#include "common/utilities.h" + +#include "libANGLE/Buffer.h" +#include "libANGLE/Config.h" +#include "libANGLE/Context.h" +#include "libANGLE/Fence.h" +#include "libANGLE/Framebuffer.h" +#include "libANGLE/Program.h" +#include "libANGLE/Renderbuffer.h" +#include "libANGLE/Sampler.h" +#include "libANGLE/Shader.h" +#include "libANGLE/Surface.h" +#include "libANGLE/Texture.h" +#include "libANGLE/Uniform.h" +#include "libANGLE/VertexAttribute.h" +#include "libANGLE/queryconversions.h" + +namespace gl +{ + +namespace +{ + +template +void QueryTexLevelParameterBase(const Texture *texture, + GLenum target, + GLint level, + GLenum pname, + ParamType *params) +{ + ASSERT(texture != nullptr); + const InternalFormat *info = texture->getTextureState().getImageDesc(target, level).format.info; + + switch (pname) + { + case GL_TEXTURE_RED_TYPE: + *params = CastFromGLintStateValue( + pname, info->redBits ? info->componentType : GL_NONE); + break; + case GL_TEXTURE_GREEN_TYPE: + *params = CastFromGLintStateValue( + pname, info->greenBits ? info->componentType : GL_NONE); + break; + case GL_TEXTURE_BLUE_TYPE: + *params = CastFromGLintStateValue( + pname, info->blueBits ? info->componentType : GL_NONE); + break; + case GL_TEXTURE_ALPHA_TYPE: + *params = CastFromGLintStateValue( + pname, info->alphaBits ? info->componentType : GL_NONE); + break; + case GL_TEXTURE_DEPTH_TYPE: + *params = CastFromGLintStateValue( + pname, info->depthBits ? info->componentType : GL_NONE); + break; + case GL_TEXTURE_RED_SIZE: + *params = CastFromGLintStateValue(pname, info->redBits); + break; + case GL_TEXTURE_GREEN_SIZE: + *params = CastFromGLintStateValue(pname, info->greenBits); + break; + case GL_TEXTURE_BLUE_SIZE: + *params = CastFromGLintStateValue(pname, info->blueBits); + break; + case GL_TEXTURE_ALPHA_SIZE: + *params = CastFromGLintStateValue(pname, info->alphaBits); + break; + case GL_TEXTURE_DEPTH_SIZE: + *params = CastFromGLintStateValue(pname, info->depthBits); + break; + case GL_TEXTURE_STENCIL_SIZE: + *params = CastFromGLintStateValue(pname, info->stencilBits); + break; + case GL_TEXTURE_SHARED_SIZE: + *params = CastFromGLintStateValue(pname, info->sharedBits); + break; + case GL_TEXTURE_INTERNAL_FORMAT: + *params = CastFromGLintStateValue( + pname, info->internalFormat ? info->internalFormat : GL_RGBA); + break; + case GL_TEXTURE_WIDTH: + *params = CastFromGLintStateValue( + pname, static_cast(texture->getWidth(target, level))); + break; + case GL_TEXTURE_HEIGHT: + *params = CastFromGLintStateValue( + pname, static_cast(texture->getHeight(target, level))); + break; + case GL_TEXTURE_DEPTH: + *params = CastFromGLintStateValue( + pname, static_cast(texture->getDepth(target, level))); + break; + case GL_TEXTURE_SAMPLES: + *params = CastFromStateValue(pname, texture->getSamples(target, level)); + break; + case GL_TEXTURE_FIXED_SAMPLE_LOCATIONS: + *params = CastFromStateValue( + pname, static_cast(texture->getFixedSampleLocations(target, level))); + break; + case GL_TEXTURE_COMPRESSED: + *params = CastFromStateValue(pname, static_cast(info->compressed)); + break; + default: + UNREACHABLE(); + break; + } +} + +template +void QueryTexParameterBase(const Texture *texture, GLenum pname, ParamType *params) +{ + ASSERT(texture != nullptr); + + switch (pname) + { + case GL_TEXTURE_MAG_FILTER: + *params = CastFromGLintStateValue(pname, texture->getMagFilter()); + break; + case GL_TEXTURE_MIN_FILTER: + *params = CastFromGLintStateValue(pname, texture->getMinFilter()); + break; + case GL_TEXTURE_WRAP_S: + *params = CastFromGLintStateValue(pname, texture->getWrapS()); + break; + case GL_TEXTURE_WRAP_T: + *params = CastFromGLintStateValue(pname, texture->getWrapT()); + break; + case GL_TEXTURE_WRAP_R: + *params = CastFromGLintStateValue(pname, texture->getWrapR()); + break; + case GL_TEXTURE_IMMUTABLE_FORMAT: + *params = CastFromGLintStateValue(pname, texture->getImmutableFormat()); + break; + case GL_TEXTURE_IMMUTABLE_LEVELS: + *params = CastFromGLintStateValue(pname, texture->getImmutableLevels()); + break; + case GL_TEXTURE_USAGE_ANGLE: + *params = CastFromGLintStateValue(pname, texture->getUsage()); + break; + case GL_TEXTURE_MAX_ANISOTROPY_EXT: + *params = CastFromStateValue(pname, texture->getMaxAnisotropy()); + break; + case GL_TEXTURE_SWIZZLE_R: + *params = CastFromGLintStateValue(pname, texture->getSwizzleRed()); + break; + case GL_TEXTURE_SWIZZLE_G: + *params = CastFromGLintStateValue(pname, texture->getSwizzleGreen()); + break; + case GL_TEXTURE_SWIZZLE_B: + *params = CastFromGLintStateValue(pname, texture->getSwizzleBlue()); + break; + case GL_TEXTURE_SWIZZLE_A: + *params = CastFromGLintStateValue(pname, texture->getSwizzleAlpha()); + break; + case GL_TEXTURE_BASE_LEVEL: + *params = CastFromGLintStateValue(pname, texture->getBaseLevel()); + break; + case GL_TEXTURE_MAX_LEVEL: + *params = CastFromGLintStateValue(pname, texture->getMaxLevel()); + break; + case GL_TEXTURE_MIN_LOD: + *params = CastFromStateValue(pname, texture->getSamplerState().minLod); + break; + case GL_TEXTURE_MAX_LOD: + *params = CastFromStateValue(pname, texture->getSamplerState().maxLod); + break; + case GL_TEXTURE_COMPARE_MODE: + *params = CastFromGLintStateValue(pname, texture->getCompareMode()); + break; + case GL_TEXTURE_COMPARE_FUNC: + *params = CastFromGLintStateValue(pname, texture->getCompareFunc()); + break; + case GL_TEXTURE_SRGB_DECODE_EXT: + *params = CastFromGLintStateValue(pname, texture->getSRGBDecode()); + break; + default: + UNREACHABLE(); + break; + } +} + +template +void SetTexParameterBase(Context *context, Texture *texture, GLenum pname, const ParamType *params) +{ + ASSERT(texture != nullptr); + + switch (pname) + { + case GL_TEXTURE_WRAP_S: + texture->setWrapS(ConvertToGLenum(pname, params[0])); + break; + case GL_TEXTURE_WRAP_T: + texture->setWrapT(ConvertToGLenum(pname, params[0])); + break; + case GL_TEXTURE_WRAP_R: + texture->setWrapR(ConvertToGLenum(pname, params[0])); + break; + case GL_TEXTURE_MIN_FILTER: + texture->setMinFilter(ConvertToGLenum(pname, params[0])); + break; + case GL_TEXTURE_MAG_FILTER: + texture->setMagFilter(ConvertToGLenum(pname, params[0])); + break; + case GL_TEXTURE_USAGE_ANGLE: + texture->setUsage(ConvertToGLenum(pname, params[0])); + break; + case GL_TEXTURE_MAX_ANISOTROPY_EXT: + texture->setMaxAnisotropy(CastQueryValueTo(pname, params[0])); + break; + case GL_TEXTURE_COMPARE_MODE: + texture->setCompareMode(ConvertToGLenum(pname, params[0])); + break; + case GL_TEXTURE_COMPARE_FUNC: + texture->setCompareFunc(ConvertToGLenum(pname, params[0])); + break; + case GL_TEXTURE_SWIZZLE_R: + texture->setSwizzleRed(ConvertToGLenum(pname, params[0])); + break; + case GL_TEXTURE_SWIZZLE_G: + texture->setSwizzleGreen(ConvertToGLenum(pname, params[0])); + break; + case GL_TEXTURE_SWIZZLE_B: + texture->setSwizzleBlue(ConvertToGLenum(pname, params[0])); + break; + case GL_TEXTURE_SWIZZLE_A: + texture->setSwizzleAlpha(ConvertToGLenum(pname, params[0])); + break; + case GL_TEXTURE_BASE_LEVEL: + { + context->handleError(texture->setBaseLevel( + context, clampCast(CastQueryValueTo(pname, params[0])))); + break; + } + case GL_TEXTURE_MAX_LEVEL: + texture->setMaxLevel(clampCast(CastQueryValueTo(pname, params[0]))); + break; + case GL_TEXTURE_MIN_LOD: + texture->setMinLod(CastQueryValueTo(pname, params[0])); + break; + case GL_TEXTURE_MAX_LOD: + texture->setMaxLod(CastQueryValueTo(pname, params[0])); + break; + case GL_DEPTH_STENCIL_TEXTURE_MODE: + texture->setDepthStencilTextureMode(ConvertToGLenum(pname, params[0])); + break; + case GL_TEXTURE_SRGB_DECODE_EXT: + texture->setSRGBDecode(ConvertToGLenum(pname, params[0])); + break; + default: + UNREACHABLE(); + break; + } +} + +template +void QuerySamplerParameterBase(const Sampler *sampler, GLenum pname, ParamType *params) +{ + switch (pname) + { + case GL_TEXTURE_MIN_FILTER: + *params = CastFromGLintStateValue(pname, sampler->getMinFilter()); + break; + case GL_TEXTURE_MAG_FILTER: + *params = CastFromGLintStateValue(pname, sampler->getMagFilter()); + break; + case GL_TEXTURE_WRAP_S: + *params = CastFromGLintStateValue(pname, sampler->getWrapS()); + break; + case GL_TEXTURE_WRAP_T: + *params = CastFromGLintStateValue(pname, sampler->getWrapT()); + break; + case GL_TEXTURE_WRAP_R: + *params = CastFromGLintStateValue(pname, sampler->getWrapR()); + break; + case GL_TEXTURE_MAX_ANISOTROPY_EXT: + *params = CastFromStateValue(pname, sampler->getMaxAnisotropy()); + break; + case GL_TEXTURE_MIN_LOD: + *params = CastFromStateValue(pname, sampler->getMinLod()); + break; + case GL_TEXTURE_MAX_LOD: + *params = CastFromStateValue(pname, sampler->getMaxLod()); + break; + case GL_TEXTURE_COMPARE_MODE: + *params = CastFromGLintStateValue(pname, sampler->getCompareMode()); + break; + case GL_TEXTURE_COMPARE_FUNC: + *params = CastFromGLintStateValue(pname, sampler->getCompareFunc()); + break; + case GL_TEXTURE_SRGB_DECODE_EXT: + *params = CastFromGLintStateValue(pname, sampler->getSRGBDecode()); + break; + default: + UNREACHABLE(); + break; + } +} + +template +void SetSamplerParameterBase(Sampler *sampler, GLenum pname, const ParamType *params) +{ + switch (pname) + { + case GL_TEXTURE_WRAP_S: + sampler->setWrapS(ConvertToGLenum(pname, params[0])); + break; + case GL_TEXTURE_WRAP_T: + sampler->setWrapT(ConvertToGLenum(pname, params[0])); + break; + case GL_TEXTURE_WRAP_R: + sampler->setWrapR(ConvertToGLenum(pname, params[0])); + break; + case GL_TEXTURE_MIN_FILTER: + sampler->setMinFilter(ConvertToGLenum(pname, params[0])); + break; + case GL_TEXTURE_MAG_FILTER: + sampler->setMagFilter(ConvertToGLenum(pname, params[0])); + break; + case GL_TEXTURE_MAX_ANISOTROPY_EXT: + sampler->setMaxAnisotropy(CastQueryValueTo(pname, params[0])); + break; + case GL_TEXTURE_COMPARE_MODE: + sampler->setCompareMode(ConvertToGLenum(pname, params[0])); + break; + case GL_TEXTURE_COMPARE_FUNC: + sampler->setCompareFunc(ConvertToGLenum(pname, params[0])); + break; + case GL_TEXTURE_MIN_LOD: + sampler->setMinLod(CastQueryValueTo(pname, params[0])); + break; + case GL_TEXTURE_MAX_LOD: + sampler->setMaxLod(CastQueryValueTo(pname, params[0])); + break; + case GL_TEXTURE_SRGB_DECODE_EXT: + sampler->setSRGBDecode(ConvertToGLenum(pname, params[0])); + break; + default: + UNREACHABLE(); + break; + } +} + +// Warning: you should ensure binding really matches attrib.bindingIndex before using this function. +template +void QueryVertexAttribBase(const VertexAttribute &attrib, + const VertexBinding &binding, + const CurrentDataType (¤tValueData)[CurrentValueCount], + GLenum pname, + ParamType *params) +{ + switch (pname) + { + case GL_CURRENT_VERTEX_ATTRIB: + for (size_t i = 0; i < CurrentValueCount; ++i) + { + params[i] = CastFromStateValue(pname, currentValueData[i]); + } + break; + case GL_VERTEX_ATTRIB_ARRAY_ENABLED: + *params = CastFromStateValue(pname, static_cast(attrib.enabled)); + break; + case GL_VERTEX_ATTRIB_ARRAY_SIZE: + *params = CastFromGLintStateValue(pname, attrib.size); + break; + case GL_VERTEX_ATTRIB_ARRAY_STRIDE: + *params = CastFromGLintStateValue(pname, attrib.vertexAttribArrayStride); + break; + case GL_VERTEX_ATTRIB_ARRAY_TYPE: + *params = CastFromGLintStateValue(pname, attrib.type); + break; + case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED: + *params = CastFromStateValue(pname, static_cast(attrib.normalized)); + break; + case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING: + *params = CastFromGLintStateValue(pname, binding.getBuffer().id()); + break; + case GL_VERTEX_ATTRIB_ARRAY_DIVISOR: + *params = CastFromGLintStateValue(pname, binding.getDivisor()); + break; + case GL_VERTEX_ATTRIB_ARRAY_INTEGER: + *params = CastFromGLintStateValue(pname, attrib.pureInteger); + break; + case GL_VERTEX_ATTRIB_BINDING: + *params = CastFromGLintStateValue(pname, attrib.bindingIndex); + break; + case GL_VERTEX_ATTRIB_RELATIVE_OFFSET: + *params = CastFromGLintStateValue(pname, attrib.relativeOffset); + break; + default: + UNREACHABLE(); + break; + } +} + +template +void QueryBufferParameterBase(const Buffer *buffer, GLenum pname, ParamType *params) +{ + ASSERT(buffer != nullptr); + + switch (pname) + { + case GL_BUFFER_USAGE: + *params = CastFromGLintStateValue(pname, ToGLenum(buffer->getUsage())); + break; + case GL_BUFFER_SIZE: + *params = CastFromStateValue(pname, buffer->getSize()); + break; + case GL_BUFFER_ACCESS_FLAGS: + *params = CastFromGLintStateValue(pname, buffer->getAccessFlags()); + break; + case GL_BUFFER_ACCESS_OES: + *params = CastFromGLintStateValue(pname, buffer->getAccess()); + break; + case GL_BUFFER_MAPPED: + *params = CastFromStateValue(pname, buffer->isMapped()); + break; + case GL_BUFFER_MAP_OFFSET: + *params = CastFromStateValue(pname, buffer->getMapOffset()); + break; + case GL_BUFFER_MAP_LENGTH: + *params = CastFromStateValue(pname, buffer->getMapLength()); + break; + default: + UNREACHABLE(); + break; + } +} + +GLint GetCommonVariableProperty(const sh::ShaderVariable &var, GLenum prop) +{ + switch (prop) + { + case GL_TYPE: + return clampCast(var.type); + + case GL_ARRAY_SIZE: + // Queryable variables are guaranteed not to be arrays of arrays or arrays of structs, + // see GLES 3.1 spec section 7.3.1.1 page 77. + return clampCast(var.getBasicTypeElementCount()); + + case GL_NAME_LENGTH: + // ES31 spec p84: This counts the terminating null char. + return clampCast(var.name.size() + 1u); + + default: + UNREACHABLE(); + return GL_INVALID_VALUE; + } +} + +GLint GetInputResourceProperty(const Program *program, GLuint index, GLenum prop) +{ + const auto &attribute = program->getInputResource(index); + switch (prop) + { + case GL_TYPE: + case GL_ARRAY_SIZE: + case GL_NAME_LENGTH: + return GetCommonVariableProperty(attribute, prop); + + case GL_LOCATION: + return program->getAttributeLocation(attribute.name); + + case GL_REFERENCED_BY_VERTEX_SHADER: + return 1; + + case GL_REFERENCED_BY_FRAGMENT_SHADER: + case GL_REFERENCED_BY_COMPUTE_SHADER: + return 0; + + default: + UNREACHABLE(); + return GL_INVALID_VALUE; + } +} + +GLint GetOutputResourceProperty(const Program *program, GLuint index, const GLenum prop) +{ + const auto &outputVariable = program->getOutputResource(index); + switch (prop) + { + case GL_TYPE: + case GL_ARRAY_SIZE: + case GL_NAME_LENGTH: + return GetCommonVariableProperty(outputVariable, prop); + + case GL_LOCATION: + return program->getFragDataLocation(outputVariable.name); + + case GL_REFERENCED_BY_VERTEX_SHADER: + return 0; + + case GL_REFERENCED_BY_FRAGMENT_SHADER: + return 1; + + case GL_REFERENCED_BY_COMPUTE_SHADER: + return 0; + + default: + UNREACHABLE(); + return GL_INVALID_VALUE; + } +} + +GLint QueryProgramInterfaceActiveResources(const Program *program, GLenum programInterface) +{ + switch (programInterface) + { + case GL_PROGRAM_INPUT: + return clampCast(program->getAttributes().size()); + + case GL_PROGRAM_OUTPUT: + return clampCast(program->getState().getOutputVariables().size()); + + case GL_UNIFORM: + return clampCast(program->getState().getUniforms().size()); + + case GL_UNIFORM_BLOCK: + return clampCast(program->getState().getUniformBlocks().size()); + + case GL_ATOMIC_COUNTER_BUFFER: + return clampCast(program->getState().getAtomicCounterBuffers().size()); + + case GL_BUFFER_VARIABLE: + return clampCast(program->getState().getBufferVariables().size()); + + case GL_SHADER_STORAGE_BLOCK: + return clampCast(program->getState().getShaderStorageBlocks().size()); + + // TODO(jie.a.chen@intel.com): more interfaces. + case GL_TRANSFORM_FEEDBACK_VARYING: + UNIMPLEMENTED(); + return 0; + + default: + UNREACHABLE(); + return 0; + } +} + +template +GLint FindMaxSize(const std::vector &resources, M member) +{ + GLint max = 0; + for (const T &resource : resources) + { + max = std::max(max, clampCast((resource.*member).size())); + } + return max; +} + +GLint QueryProgramInterfaceMaxNameLength(const Program *program, GLenum programInterface) +{ + GLint maxNameLength = 0; + switch (programInterface) + { + case GL_PROGRAM_INPUT: + maxNameLength = FindMaxSize(program->getAttributes(), &sh::Attribute::name); + break; + + case GL_PROGRAM_OUTPUT: + maxNameLength = + FindMaxSize(program->getState().getOutputVariables(), &sh::OutputVariable::name); + break; + + case GL_UNIFORM: + maxNameLength = FindMaxSize(program->getState().getUniforms(), &LinkedUniform::name); + break; + + case GL_UNIFORM_BLOCK: + maxNameLength = + FindMaxSize(program->getState().getUniformBlocks(), &InterfaceBlock::name); + break; + + case GL_BUFFER_VARIABLE: + maxNameLength = + FindMaxSize(program->getState().getBufferVariables(), &BufferVariable::name); + break; + + case GL_SHADER_STORAGE_BLOCK: + maxNameLength = + FindMaxSize(program->getState().getShaderStorageBlocks(), &InterfaceBlock::name); + break; + + // TODO(jie.a.chen@intel.com): more interfaces. + case GL_TRANSFORM_FEEDBACK_VARYING: + UNIMPLEMENTED(); + return 0; + + default: + UNREACHABLE(); + return 0; + } + // This length includes an extra character for the null terminator. + return (maxNameLength == 0 ? 0 : maxNameLength + 1); +} + +GLint QueryProgramInterfaceMaxNumActiveVariables(const Program *program, GLenum programInterface) +{ + switch (programInterface) + { + case GL_UNIFORM_BLOCK: + return FindMaxSize(program->getState().getUniformBlocks(), + &InterfaceBlock::memberIndexes); + case GL_ATOMIC_COUNTER_BUFFER: + return FindMaxSize(program->getState().getAtomicCounterBuffers(), + &AtomicCounterBuffer::memberIndexes); + + case GL_SHADER_STORAGE_BLOCK: + return FindMaxSize(program->getState().getShaderStorageBlocks(), + &InterfaceBlock::memberIndexes); + + default: + UNREACHABLE(); + return 0; + } +} + +GLenum GetUniformPropertyEnum(GLenum prop) +{ + switch (prop) + { + case GL_UNIFORM_TYPE: + return GL_TYPE; + case GL_UNIFORM_SIZE: + return GL_ARRAY_SIZE; + case GL_UNIFORM_NAME_LENGTH: + return GL_NAME_LENGTH; + case GL_UNIFORM_BLOCK_INDEX: + return GL_BLOCK_INDEX; + case GL_UNIFORM_OFFSET: + return GL_OFFSET; + case GL_UNIFORM_ARRAY_STRIDE: + return GL_ARRAY_STRIDE; + case GL_UNIFORM_MATRIX_STRIDE: + return GL_MATRIX_STRIDE; + case GL_UNIFORM_IS_ROW_MAJOR: + return GL_IS_ROW_MAJOR; + + default: + return prop; + } +} + +GLenum GetUniformBlockPropertyEnum(GLenum prop) +{ + switch (prop) + { + case GL_UNIFORM_BLOCK_BINDING: + return GL_BUFFER_BINDING; + + case GL_UNIFORM_BLOCK_DATA_SIZE: + return GL_BUFFER_DATA_SIZE; + + case GL_UNIFORM_BLOCK_NAME_LENGTH: + return GL_NAME_LENGTH; + + case GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS: + return GL_NUM_ACTIVE_VARIABLES; + + case GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES: + return GL_ACTIVE_VARIABLES; + + case GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER: + return GL_REFERENCED_BY_VERTEX_SHADER; + + case GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER: + return GL_REFERENCED_BY_FRAGMENT_SHADER; + + default: + return prop; + } +} + +void GetShaderVariableBufferResourceProperty(const ShaderVariableBuffer &buffer, + GLenum pname, + GLint *params, + GLsizei bufSize, + GLsizei *outputPosition) + +{ + switch (pname) + { + case GL_BUFFER_BINDING: + params[(*outputPosition)++] = buffer.binding; + break; + case GL_BUFFER_DATA_SIZE: + params[(*outputPosition)++] = clampCast(buffer.dataSize); + break; + case GL_NUM_ACTIVE_VARIABLES: + params[(*outputPosition)++] = buffer.numActiveVariables(); + break; + case GL_ACTIVE_VARIABLES: + for (size_t memberIndex = 0; + memberIndex < buffer.memberIndexes.size() && *outputPosition < bufSize; + ++memberIndex) + { + params[(*outputPosition)++] = clampCast(buffer.memberIndexes[memberIndex]); + } + break; + case GL_REFERENCED_BY_VERTEX_SHADER: + params[(*outputPosition)++] = static_cast(buffer.vertexStaticUse); + break; + case GL_REFERENCED_BY_FRAGMENT_SHADER: + params[(*outputPosition)++] = static_cast(buffer.fragmentStaticUse); + break; + case GL_REFERENCED_BY_COMPUTE_SHADER: + params[(*outputPosition)++] = static_cast(buffer.computeStaticUse); + break; + default: + UNREACHABLE(); + break; + } +} + +void GetInterfaceBlockResourceProperty(const InterfaceBlock &block, + GLenum pname, + GLint *params, + GLsizei bufSize, + GLsizei *outputPosition) +{ + if (pname == GL_NAME_LENGTH) + { + params[(*outputPosition)++] = clampCast(block.nameWithArrayIndex().size() + 1); + return; + } + GetShaderVariableBufferResourceProperty(block, pname, params, bufSize, outputPosition); +} + +void GetUniformBlockResourceProperty(const Program *program, + GLuint blockIndex, + GLenum pname, + GLint *params, + GLsizei bufSize, + GLsizei *outputPosition) + +{ + ASSERT(*outputPosition < bufSize); + const auto &block = program->getUniformBlockByIndex(blockIndex); + GetInterfaceBlockResourceProperty(block, pname, params, bufSize, outputPosition); +} + +void GetShaderStorageBlockResourceProperty(const Program *program, + GLuint blockIndex, + GLenum pname, + GLint *params, + GLsizei bufSize, + GLsizei *outputPosition) + +{ + ASSERT(*outputPosition < bufSize); + const auto &block = program->getShaderStorageBlockByIndex(blockIndex); + GetInterfaceBlockResourceProperty(block, pname, params, bufSize, outputPosition); +} + +void GetAtomicCounterBufferResourceProperty(const Program *program, + GLuint index, + GLenum pname, + GLint *params, + GLsizei bufSize, + GLsizei *outputPosition) + +{ + ASSERT(*outputPosition < bufSize); + const auto &buffer = program->getState().getAtomicCounterBuffers()[index]; + GetShaderVariableBufferResourceProperty(buffer, pname, params, bufSize, outputPosition); +} + +} // anonymous namespace + +void QueryFramebufferAttachmentParameteriv(const Framebuffer *framebuffer, + GLenum attachment, + GLenum pname, + GLint *params) +{ + ASSERT(framebuffer); + + const FramebufferAttachment *attachmentObject = framebuffer->getAttachment(attachment); + if (attachmentObject == nullptr) + { + // ES 2.0.25 spec pg 127 states that if the value of FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE + // is NONE, then querying any other pname will generate INVALID_ENUM. + + // ES 3.0.2 spec pg 235 states that if the attachment type is none, + // GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME will return zero and be an + // INVALID_OPERATION for all other pnames + + switch (pname) + { + case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE: + *params = GL_NONE; + break; + + case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME: + *params = 0; + break; + + default: + UNREACHABLE(); + break; + } + + return; + } + + switch (pname) + { + case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE: + *params = attachmentObject->type(); + break; + + case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME: + *params = attachmentObject->id(); + break; + + case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL: + *params = attachmentObject->mipLevel(); + break; + + case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE: + *params = attachmentObject->cubeMapFace(); + break; + + case GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE: + *params = attachmentObject->getRedSize(); + break; + + case GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE: + *params = attachmentObject->getGreenSize(); + break; + + case GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE: + *params = attachmentObject->getBlueSize(); + break; + + case GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE: + *params = attachmentObject->getAlphaSize(); + break; + + case GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE: + *params = attachmentObject->getDepthSize(); + break; + + case GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE: + *params = attachmentObject->getStencilSize(); + break; + + case GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE: + *params = attachmentObject->getComponentType(); + break; + + case GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING: + *params = attachmentObject->getColorEncoding(); + break; + + case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER: + *params = attachmentObject->layer(); + break; + + case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_NUM_VIEWS_ANGLE: + *params = attachmentObject->getNumViews(); + break; + + case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_MULTIVIEW_LAYOUT_ANGLE: + *params = static_cast(attachmentObject->getMultiviewLayout()); + break; + + case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_BASE_VIEW_INDEX_ANGLE: + *params = attachmentObject->getBaseViewIndex(); + break; + + case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_VIEWPORT_OFFSETS_ANGLE: + { + const std::vector &offsets = attachmentObject->getMultiviewViewportOffsets(); + for (size_t i = 0u; i < offsets.size(); ++i) + { + params[i * 2u] = offsets[i].x; + params[i * 2u + 1u] = offsets[i].y; + } + } + break; + + default: + UNREACHABLE(); + break; + } +} + +void QueryBufferParameteriv(const Buffer *buffer, GLenum pname, GLint *params) +{ + QueryBufferParameterBase(buffer, pname, params); +} + +void QueryBufferParameteri64v(const Buffer *buffer, GLenum pname, GLint64 *params) +{ + QueryBufferParameterBase(buffer, pname, params); +} + +void QueryBufferPointerv(const Buffer *buffer, GLenum pname, void **params) +{ + switch (pname) + { + case GL_BUFFER_MAP_POINTER: + *params = buffer->getMapPointer(); + break; + + default: + UNREACHABLE(); + break; + } +} + +void QueryProgramiv(const Context *context, const Program *program, GLenum pname, GLint *params) +{ + ASSERT(program != nullptr); + + switch (pname) + { + case GL_DELETE_STATUS: + *params = program->isFlaggedForDeletion(); + return; + case GL_LINK_STATUS: + *params = program->isLinked(); + return; + case GL_VALIDATE_STATUS: + *params = program->isValidated(); + return; + case GL_INFO_LOG_LENGTH: + *params = program->getInfoLogLength(); + return; + case GL_ATTACHED_SHADERS: + *params = program->getAttachedShadersCount(); + return; + case GL_ACTIVE_ATTRIBUTES: + *params = program->getActiveAttributeCount(); + return; + case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH: + *params = program->getActiveAttributeMaxLength(); + return; + case GL_ACTIVE_UNIFORMS: + *params = program->getActiveUniformCount(); + return; + case GL_ACTIVE_UNIFORM_MAX_LENGTH: + *params = program->getActiveUniformMaxLength(); + return; + case GL_PROGRAM_BINARY_LENGTH_OES: + *params = program->getBinaryLength(context); + return; + case GL_ACTIVE_UNIFORM_BLOCKS: + *params = program->getActiveUniformBlockCount(); + return; + case GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH: + *params = program->getActiveUniformBlockMaxLength(); + break; + case GL_TRANSFORM_FEEDBACK_BUFFER_MODE: + *params = program->getTransformFeedbackBufferMode(); + break; + case GL_TRANSFORM_FEEDBACK_VARYINGS: + *params = program->getTransformFeedbackVaryingCount(); + break; + case GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH: + *params = program->getTransformFeedbackVaryingMaxLength(); + break; + case GL_PROGRAM_BINARY_RETRIEVABLE_HINT: + *params = program->getBinaryRetrievableHint(); + break; + case GL_PROGRAM_SEPARABLE: + *params = program->isSeparable(); + break; + case GL_COMPUTE_WORK_GROUP_SIZE: + { + const sh::WorkGroupSize &localSize = program->getComputeShaderLocalSize(); + params[0] = localSize[0]; + params[1] = localSize[1]; + params[2] = localSize[2]; + } + break; + case GL_ACTIVE_ATOMIC_COUNTER_BUFFERS: + *params = program->getActiveAtomicCounterBufferCount(); + break; + default: + UNREACHABLE(); + break; + } +} + +void QueryRenderbufferiv(const Context *context, + const Renderbuffer *renderbuffer, + GLenum pname, + GLint *params) +{ + ASSERT(renderbuffer != nullptr); + + switch (pname) + { + case GL_RENDERBUFFER_WIDTH: + *params = renderbuffer->getWidth(); + break; + case GL_RENDERBUFFER_HEIGHT: + *params = renderbuffer->getHeight(); + break; + case GL_RENDERBUFFER_INTERNAL_FORMAT: + // Special case the WebGL 1 DEPTH_STENCIL format. + if (context->isWebGL1() && + renderbuffer->getFormat().info->internalFormat == GL_DEPTH24_STENCIL8) + { + *params = GL_DEPTH_STENCIL; + } + else + { + *params = renderbuffer->getFormat().info->internalFormat; + } + break; + case GL_RENDERBUFFER_RED_SIZE: + *params = renderbuffer->getRedSize(); + break; + case GL_RENDERBUFFER_GREEN_SIZE: + *params = renderbuffer->getGreenSize(); + break; + case GL_RENDERBUFFER_BLUE_SIZE: + *params = renderbuffer->getBlueSize(); + break; + case GL_RENDERBUFFER_ALPHA_SIZE: + *params = renderbuffer->getAlphaSize(); + break; + case GL_RENDERBUFFER_DEPTH_SIZE: + *params = renderbuffer->getDepthSize(); + break; + case GL_RENDERBUFFER_STENCIL_SIZE: + *params = renderbuffer->getStencilSize(); + break; + case GL_RENDERBUFFER_SAMPLES_ANGLE: + *params = renderbuffer->getSamples(); + break; + default: + UNREACHABLE(); + break; + } +} + +void QueryShaderiv(const Context *context, Shader *shader, GLenum pname, GLint *params) +{ + ASSERT(shader != nullptr); + + switch (pname) + { + case GL_SHADER_TYPE: + *params = shader->getType(); + return; + case GL_DELETE_STATUS: + *params = shader->isFlaggedForDeletion(); + return; + case GL_COMPILE_STATUS: + *params = shader->isCompiled(context) ? GL_TRUE : GL_FALSE; + return; + case GL_INFO_LOG_LENGTH: + *params = shader->getInfoLogLength(context); + return; + case GL_SHADER_SOURCE_LENGTH: + *params = shader->getSourceLength(); + return; + case GL_TRANSLATED_SHADER_SOURCE_LENGTH_ANGLE: + *params = shader->getTranslatedSourceWithDebugInfoLength(context); + return; + default: + UNREACHABLE(); + break; + } +} + +void QueryTexLevelParameterfv(const Texture *texture, + GLenum target, + GLint level, + GLenum pname, + GLfloat *params) +{ + QueryTexLevelParameterBase(texture, target, level, pname, params); +} + +void QueryTexLevelParameteriv(const Texture *texture, + GLenum target, + GLint level, + GLenum pname, + GLint *params) +{ + QueryTexLevelParameterBase(texture, target, level, pname, params); +} + +void QueryTexParameterfv(const Texture *texture, GLenum pname, GLfloat *params) +{ + QueryTexParameterBase(texture, pname, params); +} + +void QueryTexParameteriv(const Texture *texture, GLenum pname, GLint *params) +{ + QueryTexParameterBase(texture, pname, params); +} + +void QuerySamplerParameterfv(const Sampler *sampler, GLenum pname, GLfloat *params) +{ + QuerySamplerParameterBase(sampler, pname, params); +} + +void QuerySamplerParameteriv(const Sampler *sampler, GLenum pname, GLint *params) +{ + QuerySamplerParameterBase(sampler, pname, params); +} + +void QueryVertexAttribfv(const VertexAttribute &attrib, + const VertexBinding &binding, + const VertexAttribCurrentValueData ¤tValueData, + GLenum pname, + GLfloat *params) +{ + QueryVertexAttribBase(attrib, binding, currentValueData.FloatValues, pname, params); +} + +void QueryVertexAttribiv(const VertexAttribute &attrib, + const VertexBinding &binding, + const VertexAttribCurrentValueData ¤tValueData, + GLenum pname, + GLint *params) +{ + QueryVertexAttribBase(attrib, binding, currentValueData.FloatValues, pname, params); +} + +void QueryVertexAttribPointerv(const VertexAttribute &attrib, GLenum pname, void **pointer) +{ + switch (pname) + { + case GL_VERTEX_ATTRIB_ARRAY_POINTER: + *pointer = const_cast(attrib.pointer); + break; + + default: + UNREACHABLE(); + break; + } +} + +void QueryVertexAttribIiv(const VertexAttribute &attrib, + const VertexBinding &binding, + const VertexAttribCurrentValueData ¤tValueData, + GLenum pname, + GLint *params) +{ + QueryVertexAttribBase(attrib, binding, currentValueData.IntValues, pname, params); +} + +void QueryVertexAttribIuiv(const VertexAttribute &attrib, + const VertexBinding &binding, + const VertexAttribCurrentValueData ¤tValueData, + GLenum pname, + GLuint *params) +{ + QueryVertexAttribBase(attrib, binding, currentValueData.UnsignedIntValues, pname, params); +} + +void QueryActiveUniformBlockiv(const Program *program, + GLuint uniformBlockIndex, + GLenum pname, + GLint *params) +{ + GLenum prop = GetUniformBlockPropertyEnum(pname); + QueryProgramResourceiv(program, GL_UNIFORM_BLOCK, uniformBlockIndex, 1, &prop, + std::numeric_limits::max(), nullptr, params); +} + +void QueryInternalFormativ(const TextureCaps &format, GLenum pname, GLsizei bufSize, GLint *params) +{ + switch (pname) + { + case GL_NUM_SAMPLE_COUNTS: + if (bufSize != 0) + { + *params = clampCast(format.sampleCounts.size()); + } + break; + + case GL_SAMPLES: + { + size_t returnCount = std::min(bufSize, format.sampleCounts.size()); + auto sampleReverseIt = format.sampleCounts.rbegin(); + for (size_t sampleIndex = 0; sampleIndex < returnCount; ++sampleIndex) + { + params[sampleIndex] = *sampleReverseIt++; + } + } + break; + + default: + UNREACHABLE(); + break; + } +} + +void QueryFramebufferParameteriv(const Framebuffer *framebuffer, GLenum pname, GLint *params) +{ + ASSERT(framebuffer); + + switch (pname) + { + case GL_FRAMEBUFFER_DEFAULT_WIDTH: + *params = framebuffer->getDefaultWidth(); + break; + case GL_FRAMEBUFFER_DEFAULT_HEIGHT: + *params = framebuffer->getDefaultHeight(); + break; + case GL_FRAMEBUFFER_DEFAULT_SAMPLES: + *params = framebuffer->getDefaultSamples(); + break; + case GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS: + *params = ConvertToGLBoolean(framebuffer->getDefaultFixedSampleLocations()); + break; + default: + UNREACHABLE(); + break; + } +} + +Error QuerySynciv(const Sync *sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values) +{ + ASSERT(sync); + + // All queries return one value, exit early if the buffer can't fit anything. + if (bufSize < 1) + { + if (length != nullptr) + { + *length = 0; + } + return NoError(); + } + + switch (pname) + { + case GL_OBJECT_TYPE: + *values = clampCast(GL_SYNC_FENCE); + break; + case GL_SYNC_CONDITION: + *values = clampCast(sync->getCondition()); + break; + case GL_SYNC_FLAGS: + *values = clampCast(sync->getFlags()); + break; + case GL_SYNC_STATUS: + ANGLE_TRY(sync->getStatus(values)); + break; + + default: + UNREACHABLE(); + break; + } + + if (length != nullptr) + { + *length = 1; + } + + return NoError(); +} + +void SetTexParameterf(Context *context, Texture *texture, GLenum pname, GLfloat param) +{ + SetTexParameterBase(context, texture, pname, ¶m); +} + +void SetTexParameterfv(Context *context, Texture *texture, GLenum pname, const GLfloat *params) +{ + SetTexParameterBase(context, texture, pname, params); +} + +void SetTexParameteri(Context *context, Texture *texture, GLenum pname, GLint param) +{ + SetTexParameterBase(context, texture, pname, ¶m); +} + +void SetTexParameteriv(Context *context, Texture *texture, GLenum pname, const GLint *params) +{ + SetTexParameterBase(context, texture, pname, params); +} + +void SetSamplerParameterf(Sampler *sampler, GLenum pname, GLfloat param) +{ + SetSamplerParameterBase(sampler, pname, ¶m); +} + +void SetSamplerParameterfv(Sampler *sampler, GLenum pname, const GLfloat *params) +{ + SetSamplerParameterBase(sampler, pname, params); +} + +void SetSamplerParameteri(Sampler *sampler, GLenum pname, GLint param) +{ + SetSamplerParameterBase(sampler, pname, ¶m); +} + +void SetSamplerParameteriv(Sampler *sampler, GLenum pname, const GLint *params) +{ + SetSamplerParameterBase(sampler, pname, params); +} + +void SetFramebufferParameteri(Framebuffer *framebuffer, GLenum pname, GLint param) +{ + ASSERT(framebuffer); + + switch (pname) + { + case GL_FRAMEBUFFER_DEFAULT_WIDTH: + framebuffer->setDefaultWidth(param); + break; + case GL_FRAMEBUFFER_DEFAULT_HEIGHT: + framebuffer->setDefaultHeight(param); + break; + case GL_FRAMEBUFFER_DEFAULT_SAMPLES: + framebuffer->setDefaultSamples(param); + break; + case GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS: + framebuffer->setDefaultFixedSampleLocations(ConvertToBool(param)); + break; + default: + UNREACHABLE(); + break; + } +} + +void SetProgramParameteri(Program *program, GLenum pname, GLint value) +{ + ASSERT(program); + + switch (pname) + { + case GL_PROGRAM_BINARY_RETRIEVABLE_HINT: + program->setBinaryRetrievableHint(ConvertToBool(value)); + break; + case GL_PROGRAM_SEPARABLE: + program->setSeparable(ConvertToBool(value)); + break; + default: + UNREACHABLE(); + break; + } +} + +GLint GetUniformResourceProperty(const Program *program, GLuint index, const GLenum prop) +{ + const auto &uniform = program->getUniformByIndex(index); + GLenum resourceProp = GetUniformPropertyEnum(prop); + switch (resourceProp) + { + case GL_TYPE: + case GL_ARRAY_SIZE: + case GL_NAME_LENGTH: + return GetCommonVariableProperty(uniform, resourceProp); + + case GL_LOCATION: + return program->getUniformLocation(uniform.name); + + case GL_BLOCK_INDEX: + return (uniform.isAtomicCounter() ? -1 : uniform.bufferIndex); + + case GL_OFFSET: + return uniform.blockInfo.offset; + + case GL_ARRAY_STRIDE: + return uniform.blockInfo.arrayStride; + + case GL_MATRIX_STRIDE: + return uniform.blockInfo.matrixStride; + + case GL_IS_ROW_MAJOR: + return static_cast(uniform.blockInfo.isRowMajorMatrix); + + case GL_REFERENCED_BY_VERTEX_SHADER: + return uniform.vertexStaticUse; + + case GL_REFERENCED_BY_FRAGMENT_SHADER: + return uniform.fragmentStaticUse; + + case GL_REFERENCED_BY_COMPUTE_SHADER: + return uniform.computeStaticUse; + + case GL_ATOMIC_COUNTER_BUFFER_INDEX: + return (uniform.isAtomicCounter() ? uniform.bufferIndex : -1); + + default: + UNREACHABLE(); + return 0; + } +} + +GLint GetBufferVariableResourceProperty(const Program *program, GLuint index, const GLenum prop) +{ + const auto &bufferVariable = program->getBufferVariableByIndex(index); + switch (prop) + { + case GL_TYPE: + case GL_ARRAY_SIZE: + case GL_NAME_LENGTH: + return GetCommonVariableProperty(bufferVariable, prop); + + case GL_BLOCK_INDEX: + return bufferVariable.bufferIndex; + + case GL_OFFSET: + return bufferVariable.blockInfo.offset; + + case GL_ARRAY_STRIDE: + return bufferVariable.blockInfo.arrayStride; + + case GL_MATRIX_STRIDE: + return bufferVariable.blockInfo.matrixStride; + + case GL_IS_ROW_MAJOR: + return static_cast(bufferVariable.blockInfo.isRowMajorMatrix); + + case GL_REFERENCED_BY_VERTEX_SHADER: + return bufferVariable.vertexStaticUse; + + case GL_REFERENCED_BY_FRAGMENT_SHADER: + return bufferVariable.fragmentStaticUse; + + case GL_REFERENCED_BY_COMPUTE_SHADER: + return bufferVariable.computeStaticUse; + + case GL_TOP_LEVEL_ARRAY_SIZE: + return bufferVariable.topLevelArraySize; + + case GL_TOP_LEVEL_ARRAY_STRIDE: + return bufferVariable.blockInfo.topLevelArrayStride; + + default: + UNREACHABLE(); + return 0; + } +} + +GLuint QueryProgramResourceIndex(const Program *program, + GLenum programInterface, + const GLchar *name) +{ + switch (programInterface) + { + case GL_PROGRAM_INPUT: + return program->getInputResourceIndex(name); + + case GL_PROGRAM_OUTPUT: + return program->getOutputResourceIndex(name); + + case GL_UNIFORM: + return program->getState().getUniformIndexFromName(name); + + case GL_BUFFER_VARIABLE: + return program->getState().getBufferVariableIndexFromName(name); + + case GL_SHADER_STORAGE_BLOCK: + return program->getShaderStorageBlockIndex(name); + + case GL_UNIFORM_BLOCK: + return program->getUniformBlockIndex(name); + + // TODO(jie.a.chen@intel.com): more interfaces. + case GL_TRANSFORM_FEEDBACK_VARYING: + UNIMPLEMENTED(); + return GL_INVALID_INDEX; + + default: + UNREACHABLE(); + return GL_INVALID_INDEX; + } +} + +void QueryProgramResourceName(const Program *program, + GLenum programInterface, + GLuint index, + GLsizei bufSize, + GLsizei *length, + GLchar *name) +{ + switch (programInterface) + { + case GL_PROGRAM_INPUT: + program->getInputResourceName(index, bufSize, length, name); + break; + + case GL_PROGRAM_OUTPUT: + program->getOutputResourceName(index, bufSize, length, name); + break; + + case GL_UNIFORM: + program->getUniformResourceName(index, bufSize, length, name); + break; + + case GL_BUFFER_VARIABLE: + program->getBufferVariableResourceName(index, bufSize, length, name); + break; + + case GL_SHADER_STORAGE_BLOCK: + program->getActiveShaderStorageBlockName(index, bufSize, length, name); + break; + + case GL_UNIFORM_BLOCK: + program->getActiveUniformBlockName(index, bufSize, length, name); + break; + + // TODO(jie.a.chen@intel.com): more interfaces. + case GL_TRANSFORM_FEEDBACK_VARYING: + UNIMPLEMENTED(); + break; + + default: + UNREACHABLE(); + } +} + +GLint QueryProgramResourceLocation(const Program *program, + GLenum programInterface, + const GLchar *name) +{ + switch (programInterface) + { + case GL_PROGRAM_INPUT: + return program->getAttributeLocation(name); + + case GL_PROGRAM_OUTPUT: + return program->getFragDataLocation(name); + + case GL_UNIFORM: + return program->getUniformLocation(name); + + default: + UNREACHABLE(); + return -1; + } +} + +void QueryProgramResourceiv(const Program *program, + GLenum programInterface, + GLuint index, + GLsizei propCount, + const GLenum *props, + GLsizei bufSize, + GLsizei *length, + GLint *params) +{ + if (!program->isLinked()) + { + if (length != nullptr) + { + *length = 0; + } + return; + } + + GLsizei pos = 0; + for (GLsizei i = 0; i < propCount; i++) + { + switch (programInterface) + { + case GL_PROGRAM_INPUT: + params[i] = GetInputResourceProperty(program, index, props[i]); + ++pos; + break; + + case GL_PROGRAM_OUTPUT: + params[i] = GetOutputResourceProperty(program, index, props[i]); + ++pos; + break; + + case GL_UNIFORM: + params[i] = GetUniformResourceProperty(program, index, props[i]); + ++pos; + break; + + case GL_BUFFER_VARIABLE: + params[i] = GetBufferVariableResourceProperty(program, index, props[i]); + ++pos; + break; + + case GL_UNIFORM_BLOCK: + GetUniformBlockResourceProperty(program, index, props[i], params, bufSize, &pos); + break; + + case GL_SHADER_STORAGE_BLOCK: + GetShaderStorageBlockResourceProperty(program, index, props[i], params, bufSize, + &pos); + break; + + case GL_ATOMIC_COUNTER_BUFFER: + GetAtomicCounterBufferResourceProperty(program, index, props[i], params, bufSize, + &pos); + break; + // TODO(jie.a.chen@intel.com): more interfaces. + case GL_TRANSFORM_FEEDBACK_VARYING: + UNIMPLEMENTED(); + params[i] = GL_INVALID_VALUE; + break; + + default: + UNREACHABLE(); + params[i] = GL_INVALID_VALUE; + } + if (pos == bufSize) + { + // Most properties return one value, but GL_ACTIVE_VARIABLES returns an array of values. + // This checks not to break buffer bounds for such case. + break; + } + } + + if (length != nullptr) + { + *length = pos; + } +} + +void QueryProgramInterfaceiv(const Program *program, + GLenum programInterface, + GLenum pname, + GLint *params) +{ + switch (pname) + { + case GL_ACTIVE_RESOURCES: + *params = QueryProgramInterfaceActiveResources(program, programInterface); + break; + + case GL_MAX_NAME_LENGTH: + *params = QueryProgramInterfaceMaxNameLength(program, programInterface); + break; + + case GL_MAX_NUM_ACTIVE_VARIABLES: + *params = QueryProgramInterfaceMaxNumActiveVariables(program, programInterface); + break; + + default: + UNREACHABLE(); + } +} + +} // namespace gl + +namespace egl +{ + +void QueryConfigAttrib(const Config *config, EGLint attribute, EGLint *value) +{ + ASSERT(config != nullptr); + switch (attribute) + { + case EGL_BUFFER_SIZE: + *value = config->bufferSize; + break; + case EGL_ALPHA_SIZE: + *value = config->alphaSize; + break; + case EGL_BLUE_SIZE: + *value = config->blueSize; + break; + case EGL_GREEN_SIZE: + *value = config->greenSize; + break; + case EGL_RED_SIZE: + *value = config->redSize; + break; + case EGL_DEPTH_SIZE: + *value = config->depthSize; + break; + case EGL_STENCIL_SIZE: + *value = config->stencilSize; + break; + case EGL_CONFIG_CAVEAT: + *value = config->configCaveat; + break; + case EGL_CONFIG_ID: + *value = config->configID; + break; + case EGL_LEVEL: + *value = config->level; + break; + case EGL_NATIVE_RENDERABLE: + *value = config->nativeRenderable; + break; + case EGL_NATIVE_VISUAL_ID: + *value = config->nativeVisualID; + break; + case EGL_NATIVE_VISUAL_TYPE: + *value = config->nativeVisualType; + break; + case EGL_SAMPLES: + *value = config->samples; + break; + case EGL_SAMPLE_BUFFERS: + *value = config->sampleBuffers; + break; + case EGL_SURFACE_TYPE: + *value = config->surfaceType; + break; + case EGL_TRANSPARENT_TYPE: + *value = config->transparentType; + break; + case EGL_TRANSPARENT_BLUE_VALUE: + *value = config->transparentBlueValue; + break; + case EGL_TRANSPARENT_GREEN_VALUE: + *value = config->transparentGreenValue; + break; + case EGL_TRANSPARENT_RED_VALUE: + *value = config->transparentRedValue; + break; + case EGL_BIND_TO_TEXTURE_RGB: + *value = config->bindToTextureRGB; + break; + case EGL_BIND_TO_TEXTURE_RGBA: + *value = config->bindToTextureRGBA; + break; + case EGL_MIN_SWAP_INTERVAL: + *value = config->minSwapInterval; + break; + case EGL_MAX_SWAP_INTERVAL: + *value = config->maxSwapInterval; + break; + case EGL_LUMINANCE_SIZE: + *value = config->luminanceSize; + break; + case EGL_ALPHA_MASK_SIZE: + *value = config->alphaMaskSize; + break; + case EGL_COLOR_BUFFER_TYPE: + *value = config->colorBufferType; + break; + case EGL_RENDERABLE_TYPE: + *value = config->renderableType; + break; + case EGL_MATCH_NATIVE_PIXMAP: + *value = false; + UNIMPLEMENTED(); + break; + case EGL_CONFORMANT: + *value = config->conformant; + break; + case EGL_MAX_PBUFFER_WIDTH: + *value = config->maxPBufferWidth; + break; + case EGL_MAX_PBUFFER_HEIGHT: + *value = config->maxPBufferHeight; + break; + case EGL_MAX_PBUFFER_PIXELS: + *value = config->maxPBufferPixels; + break; + case EGL_OPTIMAL_SURFACE_ORIENTATION_ANGLE: + *value = config->optimalOrientation; + break; + case EGL_COLOR_COMPONENT_TYPE_EXT: + *value = config->colorComponentType; + break; + default: + UNREACHABLE(); + break; + } +} + +void QueryContextAttrib(const gl::Context *context, EGLint attribute, EGLint *value) +{ + switch (attribute) + { + case EGL_CONFIG_ID: + *value = context->getConfig()->configID; + break; + case EGL_CONTEXT_CLIENT_TYPE: + *value = context->getClientType(); + break; + case EGL_CONTEXT_CLIENT_VERSION: + *value = context->getClientMajorVersion(); + break; + case EGL_RENDER_BUFFER: + *value = context->getRenderBuffer(); + break; + case EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE: + *value = context->isRobustResourceInitEnabled(); + break; + default: + UNREACHABLE(); + break; + } +} + +void QuerySurfaceAttrib(const Surface *surface, EGLint attribute, EGLint *value) +{ + switch (attribute) + { + case EGL_GL_COLORSPACE: + *value = surface->getGLColorspace(); + break; + case EGL_VG_ALPHA_FORMAT: + *value = surface->getVGAlphaFormat(); + break; + case EGL_VG_COLORSPACE: + *value = surface->getVGColorspace(); + break; + case EGL_CONFIG_ID: + *value = surface->getConfig()->configID; + break; + case EGL_HEIGHT: + *value = surface->getHeight(); + break; + case EGL_HORIZONTAL_RESOLUTION: + *value = surface->getHorizontalResolution(); + break; + case EGL_LARGEST_PBUFFER: + // The EGL spec states that value is not written if the surface is not a pbuffer + if (surface->getType() == EGL_PBUFFER_BIT) + { + *value = surface->getLargestPbuffer(); + } + break; + case EGL_MIPMAP_TEXTURE: + // The EGL spec states that value is not written if the surface is not a pbuffer + if (surface->getType() == EGL_PBUFFER_BIT) + { + *value = surface->getMipmapTexture(); + } + break; + case EGL_MIPMAP_LEVEL: + // The EGL spec states that value is not written if the surface is not a pbuffer + if (surface->getType() == EGL_PBUFFER_BIT) + { + *value = surface->getMipmapLevel(); + } + break; + case EGL_MULTISAMPLE_RESOLVE: + *value = surface->getMultisampleResolve(); + break; + case EGL_PIXEL_ASPECT_RATIO: + *value = surface->getPixelAspectRatio(); + break; + case EGL_RENDER_BUFFER: + *value = surface->getRenderBuffer(); + break; + case EGL_SWAP_BEHAVIOR: + *value = surface->getSwapBehavior(); + break; + case EGL_TEXTURE_FORMAT: + // The EGL spec states that value is not written if the surface is not a pbuffer + if (surface->getType() == EGL_PBUFFER_BIT) + { + *value = surface->getTextureFormat(); + } + break; + case EGL_TEXTURE_TARGET: + // The EGL spec states that value is not written if the surface is not a pbuffer + if (surface->getType() == EGL_PBUFFER_BIT) + { + *value = surface->getTextureTarget(); + } + break; + case EGL_VERTICAL_RESOLUTION: + *value = surface->getVerticalResolution(); + break; + case EGL_WIDTH: + *value = surface->getWidth(); + break; + case EGL_POST_SUB_BUFFER_SUPPORTED_NV: + *value = surface->isPostSubBufferSupported(); + break; + case EGL_FIXED_SIZE_ANGLE: + *value = surface->isFixedSize(); + break; + case EGL_FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE: + *value = surface->flexibleSurfaceCompatibilityRequested(); + break; + case EGL_SURFACE_ORIENTATION_ANGLE: + *value = surface->getOrientation(); + break; + case EGL_DIRECT_COMPOSITION_ANGLE: + *value = surface->directComposition(); + break; + case EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE: + *value = surface->isRobustResourceInitEnabled(); + break; + default: + UNREACHABLE(); + break; + } +} + +void SetSurfaceAttrib(Surface *surface, EGLint attribute, EGLint value) +{ + switch (attribute) + { + case EGL_MIPMAP_LEVEL: + surface->setMipmapLevel(value); + break; + case EGL_MULTISAMPLE_RESOLVE: + surface->setMultisampleResolve(value); + break; + case EGL_SWAP_BEHAVIOR: + surface->setSwapBehavior(value); + break; + default: + UNREACHABLE(); + break; + } +} + +} // namespace egl diff --git a/src/3rdparty/angle/src/libANGLE/queryutils.h b/src/3rdparty/angle/src/libANGLE/queryutils.h new file mode 100644 index 0000000000..990cbc169e --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/queryutils.h @@ -0,0 +1,162 @@ +// +// Copyright (c) 2016 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. +// + +// queryutils.h: Utilities for querying values from GL objects + +#ifndef LIBANGLE_QUERYUTILS_H_ +#define LIBANGLE_QUERYUTILS_H_ + +#include "angle_gl.h" +#include "common/angleutils.h" + +#include + +namespace gl +{ +class Buffer; +class Context; +class Error; +class Sync; +class Framebuffer; +class Program; +class Renderbuffer; +class Sampler; +class Shader; +class Texture; +struct TextureCaps; +struct UniformBlock; +struct VertexAttribute; +class VertexBinding; +struct VertexAttribCurrentValueData; + +void QueryFramebufferAttachmentParameteriv(const Framebuffer *framebuffer, + GLenum attachment, + GLenum pname, + GLint *params); +void QueryBufferParameteriv(const Buffer *buffer, GLenum pname, GLint *params); +void QueryBufferParameteri64v(const Buffer *buffer, GLenum pname, GLint64 *params); +void QueryBufferPointerv(const Buffer *buffer, GLenum pname, void **params); +void QueryProgramiv(const Context *context, const Program *program, GLenum pname, GLint *params); +void QueryRenderbufferiv(const Context *context, + const Renderbuffer *renderbuffer, + GLenum pname, + GLint *params); +void QueryShaderiv(const Context *context, Shader *shader, GLenum pname, GLint *params); +void QueryTexLevelParameterfv(const Texture *texture, + GLenum target, + GLint level, + GLenum pname, + GLfloat *params); +void QueryTexLevelParameteriv(const Texture *texture, + GLenum target, + GLint level, + GLenum pname, + GLint *params); +void QueryTexParameterfv(const Texture *texture, GLenum pname, GLfloat *params); +void QueryTexParameteriv(const Texture *texture, GLenum pname, GLint *params); +void QuerySamplerParameterfv(const Sampler *sampler, GLenum pname, GLfloat *params); +void QuerySamplerParameteriv(const Sampler *sampler, GLenum pname, GLint *params); + +// Warning: you should ensure binding really matches attrib.bindingIndex before using the following +// functions. +void QueryVertexAttribfv(const VertexAttribute &attrib, + const VertexBinding &binding, + const VertexAttribCurrentValueData ¤tValueData, + GLenum pname, + GLfloat *params); + +void QueryVertexAttribiv(const VertexAttribute &attrib, + const VertexBinding &binding, + const VertexAttribCurrentValueData ¤tValueData, + GLenum pname, + GLint *params); + +void QueryVertexAttribPointerv(const VertexAttribute &attrib, GLenum pname, void **pointer); + +void QueryVertexAttribIiv(const VertexAttribute &attrib, + const VertexBinding &binding, + const VertexAttribCurrentValueData ¤tValueData, + GLenum pname, + GLint *params); + +void QueryVertexAttribIuiv(const VertexAttribute &attrib, + const VertexBinding &binding, + const VertexAttribCurrentValueData ¤tValueData, + GLenum pname, + GLuint *params); + +void QueryActiveUniformBlockiv(const Program *program, + GLuint uniformBlockIndex, + GLenum pname, + GLint *params); + +void QueryInternalFormativ(const TextureCaps &format, GLenum pname, GLsizei bufSize, GLint *params); + +void QueryFramebufferParameteriv(const Framebuffer *framebuffer, GLenum pname, GLint *params); + +Error QuerySynciv(const Sync *sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values); + +void SetTexParameterf(Context *context, Texture *texture, GLenum pname, GLfloat param); +void SetTexParameterfv(Context *context, Texture *texture, GLenum pname, const GLfloat *params); +void SetTexParameteri(Context *context, Texture *texture, GLenum pname, GLint param); +void SetTexParameteriv(Context *context, Texture *texture, GLenum pname, const GLint *params); + +void SetSamplerParameterf(Sampler *sampler, GLenum pname, GLfloat param); +void SetSamplerParameterfv(Sampler *sampler, GLenum pname, const GLfloat *params); +void SetSamplerParameteri(Sampler *sampler, GLenum pname, GLint param); +void SetSamplerParameteriv(Sampler *sampler, GLenum pname, const GLint *params); + +void SetFramebufferParameteri(Framebuffer *framebuffer, GLenum pname, GLint param); + +void SetProgramParameteri(Program *program, GLenum pname, GLint value); + +GLint GetUniformResourceProperty(const Program *program, GLuint index, const GLenum prop); + +GLuint QueryProgramResourceIndex(const Program *program, + GLenum programInterface, + const GLchar *name); + +void QueryProgramResourceName(const Program *program, + GLenum programInterface, + GLuint index, + GLsizei bufSize, + GLsizei *length, + GLchar *name); + +GLint QueryProgramResourceLocation(const Program *program, + GLenum programInterface, + const GLchar *name); +void QueryProgramResourceiv(const Program *program, + GLenum programInterface, + GLuint index, + GLsizei propCount, + const GLenum *props, + GLsizei bufSize, + GLsizei *length, + GLint *params); + +void QueryProgramInterfaceiv(const Program *program, + GLenum programInterface, + GLenum pname, + GLint *params); + +} // namespace gl + +namespace egl +{ +struct Config; +class Surface; + +void QueryConfigAttrib(const Config *config, EGLint attribute, EGLint *value); + +void QueryContextAttrib(const gl::Context *context, EGLint attribute, EGLint *value); + +void QuerySurfaceAttrib(const Surface *surface, EGLint attribute, EGLint *value); +void SetSurfaceAttrib(Surface *surface, EGLint attribute, EGLint value); + +} // namespace egl + +#endif // LIBANGLE_QUERYUTILS_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/BufferImpl.h b/src/3rdparty/angle/src/libANGLE/renderer/BufferImpl.h index d77f06cf09..f76fcdc8d7 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/BufferImpl.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/BufferImpl.h @@ -12,31 +12,58 @@ #include "common/angleutils.h" #include "common/mathutil.h" #include "libANGLE/Error.h" +#include "libANGLE/PackedGLEnums.h" #include -namespace rx +namespace gl { +class BufferState; +class Context; +} +namespace rx +{ class BufferImpl : angle::NonCopyable { public: - virtual ~BufferImpl() { } + BufferImpl(const gl::BufferState &state) : mState(state) {} + virtual ~BufferImpl() {} + virtual void destroy(const gl::Context *context) {} - 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(GLenum access, GLvoid **mapPtr) = 0; - virtual gl::Error mapRange(size_t offset, size_t length, GLbitfield access, GLvoid **mapPtr) = 0; - virtual gl::Error unmap(GLboolean *result) = 0; + virtual gl::Error setData(const gl::Context *context, + gl::BufferBinding target, + const void *data, + size_t size, + gl::BufferUsage usage) = 0; + virtual gl::Error setSubData(const gl::Context *context, + gl::BufferBinding target, + const void *data, + size_t size, + size_t offset) = 0; + virtual gl::Error copySubData(const gl::Context *context, + BufferImpl *source, + GLintptr sourceOffset, + GLintptr destOffset, + GLsizeiptr size) = 0; + virtual gl::Error map(const gl::Context *context, GLenum access, void **mapPtr) = 0; + virtual gl::Error mapRange(const gl::Context *context, + size_t offset, + size_t length, + GLbitfield access, + void **mapPtr) = 0; + virtual gl::Error unmap(const gl::Context *context, GLboolean *result) = 0; - virtual gl::Error getIndexRange(GLenum type, + virtual gl::Error getIndexRange(const gl::Context *context, + GLenum type, size_t offset, size_t count, bool primitiveRestartEnabled, gl::IndexRange *outRange) = 0; -}; + protected: + const gl::BufferState &mState; +}; } -#endif // LIBANGLE_RENDERER_BUFFERIMPL_H_ +#endif // LIBANGLE_RENDERER_BUFFERIMPL_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/BufferImpl_mock.h b/src/3rdparty/angle/src/libANGLE/renderer/BufferImpl_mock.h index a6387661ce..5a4e21003c 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/BufferImpl_mock.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/BufferImpl_mock.h @@ -11,28 +11,38 @@ #include "gmock/gmock.h" +#include "libANGLE/Buffer.h" #include "libANGLE/renderer/BufferImpl.h" namespace rx { - class MockBufferImpl : public BufferImpl { public: + MockBufferImpl() : BufferImpl(mMockState) {} ~MockBufferImpl() { destructor(); } - MOCK_METHOD3(setData, gl::Error(const void*, size_t, GLenum)); - MOCK_METHOD3(setSubData, gl::Error(const void*, size_t, size_t)); - MOCK_METHOD4(copySubData, gl::Error(BufferImpl *, GLintptr, GLintptr, GLsizeiptr)); - MOCK_METHOD2(map, gl::Error(GLenum, GLvoid **)); - MOCK_METHOD4(mapRange, gl::Error(size_t, size_t, GLbitfield, GLvoid **)); - MOCK_METHOD1(unmap, gl::Error(GLboolean *result)); - - MOCK_METHOD5(getIndexRange, gl::Error(GLenum, size_t, size_t, bool, gl::IndexRange *)); + MOCK_METHOD5( + setData, + gl::Error(const gl::Context *, gl::BufferBinding, const void *, size_t, gl::BufferUsage)); + MOCK_METHOD5(setSubData, + gl::Error(const gl::Context *, gl::BufferBinding, const void *, size_t, size_t)); + MOCK_METHOD5( + copySubData, + gl::Error(const gl::Context *contextImpl, BufferImpl *, GLintptr, GLintptr, GLsizeiptr)); + MOCK_METHOD3(map, gl::Error(const gl::Context *contextImpl, GLenum, void **)); + MOCK_METHOD5(mapRange, + gl::Error(const gl::Context *contextImpl, size_t, size_t, GLbitfield, void **)); + MOCK_METHOD2(unmap, gl::Error(const gl::Context *contextImpl, GLboolean *result)); + + MOCK_METHOD6(getIndexRange, + gl::Error(const gl::Context *, GLenum, size_t, size_t, bool, gl::IndexRange *)); MOCK_METHOD0(destructor, void()); -}; + protected: + gl::BufferState mMockState; +}; } -#endif // LIBANGLE_RENDERER_BUFFERIMPLMOCK_H_ +#endif // LIBANGLE_RENDERER_BUFFERIMPLMOCK_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/ContextImpl.cpp b/src/3rdparty/angle/src/libANGLE/renderer/ContextImpl.cpp new file mode 100644 index 0000000000..8d3df291d3 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/ContextImpl.cpp @@ -0,0 +1,119 @@ +// +// Copyright 2016 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. +// +// ContextImpl: +// Implementation-specific functionality associated with a GL Context. +// + +#include "libANGLE/renderer/ContextImpl.h" + +namespace rx +{ + +ContextImpl::ContextImpl(const gl::ContextState &state) + : mState(state), mMemoryProgramCache(nullptr) +{ +} + +ContextImpl::~ContextImpl() +{ +} + +void ContextImpl::stencilFillPath(const gl::Path *path, GLenum fillMode, GLuint mask) +{ + UNREACHABLE(); +} + +void ContextImpl::stencilStrokePath(const gl::Path *path, GLint reference, GLuint mask) +{ + UNREACHABLE(); +} + +void ContextImpl::coverFillPath(const gl::Path *path, GLenum coverMode) +{ + UNREACHABLE(); +} + +void ContextImpl::coverStrokePath(const gl::Path *path, GLenum coverMode) +{ + UNREACHABLE(); +} + +void ContextImpl::stencilThenCoverFillPath(const gl::Path *path, + GLenum fillMode, + GLuint mask, + GLenum coverMode) +{ + UNREACHABLE(); +} + +void ContextImpl::stencilThenCoverStrokePath(const gl::Path *path, + GLint reference, + GLuint mask, + GLenum coverMode) +{ + UNREACHABLE(); +} + +void ContextImpl::coverFillPathInstanced(const std::vector &paths, + GLenum coverMode, + GLenum transformType, + const GLfloat *transformValues) +{ + UNREACHABLE(); +} + +void ContextImpl::coverStrokePathInstanced(const std::vector &paths, + GLenum coverMode, + GLenum transformType, + const GLfloat *transformValues) +{ + UNREACHABLE(); +} + +void ContextImpl::stencilFillPathInstanced(const std::vector &paths, + GLenum fillMode, + GLuint mask, + GLenum transformType, + const GLfloat *transformValues) +{ + UNREACHABLE(); +} + +void ContextImpl::stencilStrokePathInstanced(const std::vector &paths, + GLint reference, + GLuint mask, + GLenum transformType, + const GLfloat *transformValues) +{ + UNREACHABLE(); +} + +void ContextImpl::stencilThenCoverFillPathInstanced(const std::vector &paths, + GLenum coverMode, + GLenum fillMode, + GLuint mask, + GLenum transformType, + const GLfloat *transformValues) +{ + UNREACHABLE(); +} + +void ContextImpl::stencilThenCoverStrokePathInstanced(const std::vector &paths, + GLenum coverMode, + GLint reference, + GLuint mask, + GLenum transformType, + const GLfloat *transformValues) +{ + UNREACHABLE(); +} + +void ContextImpl::setMemoryProgramCache(gl::MemoryProgramCache *memoryProgramCache) +{ + mMemoryProgramCache = memoryProgramCache; +} + +} // namespace rx diff --git a/src/3rdparty/angle/src/libANGLE/renderer/ContextImpl.h b/src/3rdparty/angle/src/libANGLE/renderer/ContextImpl.h new file mode 100644 index 0000000000..7ba4b5ad2d --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/ContextImpl.h @@ -0,0 +1,186 @@ +// +// Copyright 2016 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. +// +// ContextImpl: +// Implementation-specific functionality associated with a GL Context. +// + +#ifndef LIBANGLE_RENDERER_CONTEXTIMPL_H_ +#define LIBANGLE_RENDERER_CONTEXTIMPL_H_ + +#include + +#include "common/angleutils.h" +#include "libANGLE/ContextState.h" +#include "libANGLE/renderer/GLImplFactory.h" + +namespace gl +{ +class MemoryProgramCache; +class Path; +struct Workarounds; +} + +namespace rx +{ +class ContextImpl : public GLImplFactory +{ + public: + ContextImpl(const gl::ContextState &state); + ~ContextImpl() override; + + virtual void onDestroy(const gl::Context *context) {} + + virtual gl::Error initialize() = 0; + + // Flush and finish. + virtual gl::Error flush(const gl::Context *context) = 0; + virtual gl::Error finish(const gl::Context *context) = 0; + + // Drawing methods. + virtual gl::Error drawArrays(const gl::Context *context, + GLenum mode, + GLint first, + GLsizei count) = 0; + virtual gl::Error drawArraysInstanced(const gl::Context *context, + GLenum mode, + GLint first, + GLsizei count, + GLsizei instanceCount) = 0; + + virtual gl::Error drawElements(const gl::Context *context, + GLenum mode, + GLsizei count, + GLenum type, + const void *indices) = 0; + virtual gl::Error drawElementsInstanced(const gl::Context *context, + GLenum mode, + GLsizei count, + GLenum type, + const void *indices, + GLsizei instances) = 0; + virtual gl::Error drawRangeElements(const gl::Context *context, + GLenum mode, + GLuint start, + GLuint end, + GLsizei count, + GLenum type, + const void *indices) = 0; + + virtual gl::Error drawArraysIndirect(const gl::Context *context, + GLenum mode, + const void *indirect) = 0; + virtual gl::Error drawElementsIndirect(const gl::Context *context, + GLenum mode, + GLenum type, + const void *indirect) = 0; + + // CHROMIUM_path_rendering path drawing methods. + virtual void stencilFillPath(const gl::Path *path, GLenum fillMode, GLuint mask); + virtual void stencilStrokePath(const gl::Path *path, GLint reference, GLuint mask); + virtual void coverFillPath(const gl::Path *path, GLenum coverMode); + virtual void coverStrokePath(const gl::Path *path, GLenum coverMode); + virtual void stencilThenCoverFillPath(const gl::Path *path, + GLenum fillMode, + GLuint mask, + GLenum coverMode); + + virtual void stencilThenCoverStrokePath(const gl::Path *path, + GLint reference, + GLuint mask, + GLenum coverMode); + + virtual void coverFillPathInstanced(const std::vector &paths, + GLenum coverMode, + GLenum transformType, + const GLfloat *transformValues); + virtual void coverStrokePathInstanced(const std::vector &paths, + GLenum coverMode, + GLenum transformType, + const GLfloat *transformValues); + virtual void stencilFillPathInstanced(const std::vector &paths, + GLenum fillMode, + GLuint mask, + GLenum transformType, + const GLfloat *transformValues); + virtual void stencilStrokePathInstanced(const std::vector &paths, + GLint reference, + GLuint mask, + GLenum transformType, + const GLfloat *transformValues); + virtual void stencilThenCoverFillPathInstanced(const std::vector &paths, + GLenum coverMode, + GLenum fillMode, + GLuint mask, + GLenum transformType, + const GLfloat *transformValues); + virtual void stencilThenCoverStrokePathInstanced(const std::vector &paths, + GLenum coverMode, + GLint reference, + GLuint mask, + GLenum transformType, + const GLfloat *transformValues); + + // Device loss + virtual GLenum getResetStatus() = 0; + + // Vendor and description strings. + virtual std::string getVendorString() const = 0; + virtual std::string getRendererDescription() const = 0; + + // EXT_debug_marker + virtual void insertEventMarker(GLsizei length, const char *marker) = 0; + virtual void pushGroupMarker(GLsizei length, const char *marker) = 0; + virtual void popGroupMarker() = 0; + + // KHR_debug + virtual void pushDebugGroup(GLenum source, GLuint id, GLsizei length, const char *message) = 0; + virtual void popDebugGroup() = 0; + + // State sync with dirty bits. + virtual void syncState(const gl::Context *context, const gl::State::DirtyBits &dirtyBits) = 0; + + // Disjoint timer queries + virtual GLint getGPUDisjoint() = 0; + virtual GLint64 getTimestamp() = 0; + + // Context switching + virtual void onMakeCurrent(const gl::Context *context) = 0; + + // Native capabilities, unmodified by gl::Context. + virtual const gl::Caps &getNativeCaps() const = 0; + virtual const gl::TextureCapsMap &getNativeTextureCaps() const = 0; + virtual const gl::Extensions &getNativeExtensions() const = 0; + virtual const gl::Limitations &getNativeLimitations() const = 0; + + virtual void applyNativeWorkarounds(gl::Workarounds *workarounds) const {} + + virtual gl::Error dispatchCompute(const gl::Context *context, + GLuint numGroupsX, + GLuint numGroupsY, + GLuint numGroupsZ) = 0; + + const gl::ContextState &getContextState() { return mState; } + int getClientMajorVersion() const { return mState.getClientMajorVersion(); } + int getClientMinorVersion() const { return mState.getClientMinorVersion(); } + const gl::State &getGLState() const { return mState.getState(); } + const gl::Caps &getCaps() const { return mState.getCaps(); } + const gl::TextureCapsMap &getTextureCaps() const { return mState.getTextureCaps(); } + const gl::Extensions &getExtensions() const { return mState.getExtensions(); } + const gl::Limitations &getLimitations() const { return mState.getLimitations(); } + + // A common GL driver behaviour is to trigger dynamic shader recompilation on a draw call, + // based on the current render states. We store a mutable pointer to the program cache so + // on draw calls we can store the refreshed shaders in the cache. + void setMemoryProgramCache(gl::MemoryProgramCache *memoryProgramCache); + + protected: + const gl::ContextState &mState; + gl::MemoryProgramCache *mMemoryProgramCache; +}; + +} // namespace rx + +#endif // LIBANGLE_RENDERER_CONTEXTIMPL_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/DisplayImpl.cpp b/src/3rdparty/angle/src/libANGLE/renderer/DisplayImpl.cpp index 8061189f0a..5cc9da96dc 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/DisplayImpl.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/DisplayImpl.cpp @@ -8,26 +8,20 @@ #include "libANGLE/renderer/DisplayImpl.h" +#include "libANGLE/Display.h" #include "libANGLE/Surface.h" namespace rx { -DisplayImpl::DisplayImpl() - : mExtensionsInitialized(false), - mCapsInitialized(false) +DisplayImpl::DisplayImpl(const egl::DisplayState &state) + : mState(state), mExtensionsInitialized(false), mCapsInitialized(false) { } DisplayImpl::~DisplayImpl() { - ASSERT(mSurfaceSet.empty()); -} - -void DisplayImpl::destroySurface(egl::Surface *surface) -{ - mSurfaceSet.erase(surface); - surface->onDestroy(); + ASSERT(mState.surfaceSet.empty()); } const egl::DisplayExtensions &DisplayImpl::getExtensions() const @@ -41,6 +35,15 @@ const egl::DisplayExtensions &DisplayImpl::getExtensions() const return mExtensions; } +egl::Error DisplayImpl::validateClientBuffer(const egl::Config *configuration, + EGLenum buftype, + EGLClientBuffer clientBuffer, + const egl::AttributeMap &attribs) const +{ + UNREACHABLE(); + return egl::EglBadDisplay() << "DisplayImpl::validateClientBuffer unimplemented."; +} + const egl::Caps &DisplayImpl::getCaps() const { if (!mCapsInitialized) @@ -52,4 +55,4 @@ const egl::Caps &DisplayImpl::getCaps() const return mCaps; } -} +} // namespace rx diff --git a/src/3rdparty/angle/src/libANGLE/renderer/DisplayImpl.h b/src/3rdparty/angle/src/libANGLE/renderer/DisplayImpl.h index 9e38f63370..b1c49d9bc8 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/DisplayImpl.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/DisplayImpl.h @@ -13,7 +13,9 @@ #include "libANGLE/Caps.h" #include "libANGLE/Config.h" #include "libANGLE/Error.h" -#include "libANGLE/renderer/Renderer.h" +#include "libANGLE/renderer/EGLImplFactory.h" +#include "libANGLE/Stream.h" +#include "libANGLE/Version.h" #include #include @@ -22,9 +24,11 @@ namespace egl { class AttributeMap; class Display; +struct DisplayState; struct Config; class Surface; class ImageSibling; +class Thread; } namespace gl @@ -38,69 +42,43 @@ class SurfaceImpl; class ImageImpl; struct ConfigDesc; class DeviceImpl; +class StreamProducerImpl; -class DisplayImpl : angle::NonCopyable +class DisplayImpl : public EGLImplFactory { public: - DisplayImpl(); - virtual ~DisplayImpl(); + DisplayImpl(const egl::DisplayState &state); + ~DisplayImpl() override; virtual egl::Error initialize(egl::Display *display) = 0; virtual void terminate() = 0; - virtual SurfaceImpl *createWindowSurface(const egl::Config *configuration, - EGLNativeWindowType window, - const egl::AttributeMap &attribs) = 0; - virtual SurfaceImpl *createPbufferSurface(const egl::Config *configuration, - const egl::AttributeMap &attribs) = 0; - virtual SurfaceImpl *createPbufferFromClientBuffer(const egl::Config *configuration, - EGLClientBuffer shareHandle, - const egl::AttributeMap &attribs) = 0; - virtual SurfaceImpl *createPixmapSurface(const egl::Config *configuration, - NativePixmapType nativePixmap, - const egl::AttributeMap &attribs) = 0; - - virtual ImageImpl *createImage(EGLenum target, - egl::ImageSibling *buffer, - const egl::AttributeMap &attribs) = 0; - - virtual gl::Context *createContext(const egl::Config *config, - const gl::Context *shareContext, - const egl::AttributeMap &attribs) = 0; - virtual egl::Error makeCurrent(egl::Surface *drawSurface, egl::Surface *readSurface, gl::Context *context) = 0; - virtual egl::ConfigSet generateConfigs() const = 0; + virtual egl::ConfigSet generateConfigs() = 0; - virtual bool isDeviceLost() const = 0; virtual bool testDeviceLost() = 0; - virtual egl::Error restoreLostDevice() = 0; + virtual egl::Error restoreLostDevice(const egl::Display *display) = 0; virtual bool isValidNativeWindow(EGLNativeWindowType window) const = 0; + virtual egl::Error validateClientBuffer(const egl::Config *configuration, + EGLenum buftype, + EGLClientBuffer clientBuffer, + const egl::AttributeMap &attribs) const; virtual std::string getVendorString() const = 0; virtual egl::Error getDevice(DeviceImpl **device) = 0; - virtual egl::Error waitClient() const = 0; - virtual egl::Error waitNative(EGLint engine, - egl::Surface *drawSurface, - egl::Surface *readSurface) const = 0; - + virtual egl::Error waitClient(const gl::Context *context) const = 0; + virtual egl::Error waitNative(const gl::Context *context, EGLint engine) const = 0; + virtual gl::Version getMaxSupportedESVersion() 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; + const egl::DisplayState &mState; private: virtual void generateExtensions(egl::DisplayExtensions *outExtensions) const = 0; diff --git a/src/3rdparty/angle/src/libANGLE/renderer/EGLImplFactory.h b/src/3rdparty/angle/src/libANGLE/renderer/EGLImplFactory.h new file mode 100644 index 0000000000..0433364cd3 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/EGLImplFactory.h @@ -0,0 +1,68 @@ +// +// Copyright 2016 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. +// +// EGLImplFactory.h: +// Factory interface for EGL Impl objects. +// + +#ifndef LIBANGLE_RENDERER_EGLIMPLFACTORY_H_ +#define LIBANGLE_RENDERER_EGLIMPLFACTORY_H_ + +#include "libANGLE/Stream.h" + +namespace egl +{ +class AttributeMap; +struct Config; +class ImageSibling; +struct ImageState; +struct SurfaceState; +} + +namespace gl +{ +class Context; +class ContextState; +} + +namespace rx +{ +class ContextImpl; +class ImageImpl; +class SurfaceImpl; + +class EGLImplFactory : angle::NonCopyable +{ + public: + EGLImplFactory() {} + virtual ~EGLImplFactory() {} + + virtual SurfaceImpl *createWindowSurface(const egl::SurfaceState &state, + EGLNativeWindowType window, + const egl::AttributeMap &attribs) = 0; + virtual SurfaceImpl *createPbufferSurface(const egl::SurfaceState &state, + const egl::AttributeMap &attribs) = 0; + virtual SurfaceImpl *createPbufferFromClientBuffer(const egl::SurfaceState &state, + EGLenum buftype, + EGLClientBuffer clientBuffer, + const egl::AttributeMap &attribs) = 0; + virtual SurfaceImpl *createPixmapSurface(const egl::SurfaceState &state, + NativePixmapType nativePixmap, + const egl::AttributeMap &attribs) = 0; + + virtual ImageImpl *createImage(const egl::ImageState &state, + EGLenum target, + const egl::AttributeMap &attribs) = 0; + + virtual ContextImpl *createContext(const gl::ContextState &state) = 0; + + virtual StreamProducerImpl *createStreamProducerD3DTextureNV12( + egl::Stream::ConsumerType consumerType, + const egl::AttributeMap &attribs) = 0; +}; + +} // namespace rx + +#endif // LIBANGLE_RENDERER_EGLIMPLFACTORY_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/FenceSyncImpl.h b/src/3rdparty/angle/src/libANGLE/renderer/FenceSyncImpl.h deleted file mode 100644 index 6b78e69d47..0000000000 --- a/src/3rdparty/angle/src/libANGLE/renderer/FenceSyncImpl.h +++ /dev/null @@ -1,35 +0,0 @@ -// -// 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(GLenum condition, GLbitfield flags) = 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/Format.h b/src/3rdparty/angle/src/libANGLE/renderer/Format.h new file mode 100644 index 0000000000..66bdace3e9 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/Format.h @@ -0,0 +1,105 @@ +// +// Copyright 2016 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. +// +// Format: +// A universal description of typed GPU storage. Across multiple +// renderer back-ends, there are common formats and some distinct +// permutations, this enum encapsulates them all. Formats apply to +// textures, but could also apply to any typed data. + +#ifndef LIBANGLE_RENDERER_FORMAT_H_ +#define LIBANGLE_RENDERER_FORMAT_H_ + +#include "libANGLE/renderer/renderer_utils.h" + +namespace angle +{ + +struct Format final : private angle::NonCopyable +{ + enum class ID; + + constexpr Format(ID id, + GLenum glFormat, + GLenum fboFormat, + rx::MipGenerationFunction mipGen, + const rx::FastCopyFunctionMap &fastCopyFunctions, + rx::ColorReadFunction colorRead, + rx::ColorWriteFunction colorWrite, + GLenum componentType, + GLuint redBits, + GLuint greenBits, + GLuint blueBits, + GLuint alphaBits, + GLuint depthBits, + GLuint stencilBits); + + static const Format &Get(ID id); + static ID InternalFormatToID(GLenum internalFormat); + + ID id; + + // The closest matching GL internal format for the storage this format uses. Note that this + // may be a different internal format than the one this ANGLE format is used for. + GLenum glInternalFormat; + + // The format we should report to the GL layer when querying implementation formats from a FBO. + // This might not be the same as the glInternalFormat, since some DXGI formats don't have + // matching GL format enums, like BGRA4, BGR5A1 and B5G6R6. + GLenum fboImplementationInternalFormat; + + rx::MipGenerationFunction mipGenerationFunction; + rx::ColorReadFunction colorReadFunction; + rx::ColorWriteFunction colorWriteFunction; + + // A map from a gl::FormatType to a fast pixel copy function for this format. + const rx::FastCopyFunctionMap &fastCopyFunctions; + + GLenum componentType; + + GLuint redBits; + GLuint greenBits; + GLuint blueBits; + GLuint alphaBits; + GLuint depthBits; + GLuint stencilBits; +}; + +constexpr Format::Format(ID id, + GLenum glFormat, + GLenum fboFormat, + rx::MipGenerationFunction mipGen, + const rx::FastCopyFunctionMap &fastCopyFunctions, + rx::ColorReadFunction colorRead, + rx::ColorWriteFunction colorWrite, + GLenum componentType, + GLuint redBits, + GLuint greenBits, + GLuint blueBits, + GLuint alphaBits, + GLuint depthBits, + GLuint stencilBits) + : id(id), + glInternalFormat(glFormat), + fboImplementationInternalFormat(fboFormat), + mipGenerationFunction(mipGen), + colorReadFunction(colorRead), + colorWriteFunction(colorWrite), + fastCopyFunctions(fastCopyFunctions), + componentType(componentType), + redBits(redBits), + greenBits(greenBits), + blueBits(blueBits), + alphaBits(alphaBits), + depthBits(depthBits), + stencilBits(stencilBits) +{ +} + +} // namespace angle + +#include "libANGLE/renderer/Format_ID_autogen.inl" + +#endif // LIBANGLE_RENDERER_FORMAT_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/Format_ID_autogen.inl b/src/3rdparty/angle/src/libANGLE/renderer/Format_ID_autogen.inl new file mode 100644 index 0000000000..b2cbfb0410 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/Format_ID_autogen.inl @@ -0,0 +1,147 @@ +// GENERATED FILE - DO NOT EDIT. +// Generated by gen_angle_format_table.py using data from angle_format_data.json +// +// Copyright 2017 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. +// +// ANGLE format enumeration. + +namespace angle +{ + +enum class Format::ID +{ + NONE, + A16_FLOAT, + A32_FLOAT, + A8_UNORM, + ASTC_10x10_SRGB_BLOCK, + ASTC_10x10_UNORM_BLOCK, + ASTC_10x5_SRGB_BLOCK, + ASTC_10x5_UNORM_BLOCK, + ASTC_10x6_SRGB_BLOCK, + ASTC_10x6_UNORM_BLOCK, + ASTC_10x8_SRGB_BLOCK, + ASTC_10x8_UNORM_BLOCK, + ASTC_12x10_SRGB_BLOCK, + ASTC_12x10_UNORM_BLOCK, + ASTC_12x12_SRGB_BLOCK, + ASTC_12x12_UNORM_BLOCK, + ASTC_4x4_SRGB_BLOCK, + ASTC_4x4_UNORM_BLOCK, + ASTC_5x4_SRGB_BLOCK, + ASTC_5x4_UNORM_BLOCK, + ASTC_5x5_SRGB_BLOCK, + ASTC_5x5_UNORM_BLOCK, + ASTC_6x5_SRGB_BLOCK, + ASTC_6x5_UNORM_BLOCK, + ASTC_6x6_SRGB_BLOCK, + ASTC_6x6_UNORM_BLOCK, + ASTC_8x5_SRGB_BLOCK, + ASTC_8x5_UNORM_BLOCK, + ASTC_8x6_SRGB_BLOCK, + ASTC_8x6_UNORM_BLOCK, + ASTC_8x8_SRGB_BLOCK, + ASTC_8x8_UNORM_BLOCK, + B4G4R4A4_UNORM, + B5G5R5A1_UNORM, + B5G6R5_UNORM, + B8G8R8A8_UNORM, + B8G8R8A8_UNORM_SRGB, + B8G8R8X8_UNORM, + BC1_RGBA_UNORM_BLOCK, + BC1_RGBA_UNORM_SRGB_BLOCK, + BC1_RGB_UNORM_BLOCK, + BC1_RGB_UNORM_SRGB_BLOCK, + BC2_RGBA_UNORM_BLOCK, + BC2_RGBA_UNORM_SRGB_BLOCK, + BC3_RGBA_UNORM_BLOCK, + BC3_RGBA_UNORM_SRGB_BLOCK, + D16_UNORM, + D24_UNORM, + D24_UNORM_S8_UINT, + D32_FLOAT, + D32_FLOAT_S8X24_UINT, + D32_UNORM, + EAC_R11G11_SNORM_BLOCK, + EAC_R11G11_UNORM_BLOCK, + EAC_R11_SNORM_BLOCK, + EAC_R11_UNORM_BLOCK, + ETC1_LOSSY_DECODE_R8G8B8_UNORM_BLOCK, + ETC1_R8G8B8_UNORM_BLOCK, + ETC2_R8G8B8A1_SRGB_BLOCK, + ETC2_R8G8B8A1_UNORM_BLOCK, + ETC2_R8G8B8A8_SRGB_BLOCK, + ETC2_R8G8B8A8_UNORM_BLOCK, + ETC2_R8G8B8_SRGB_BLOCK, + ETC2_R8G8B8_UNORM_BLOCK, + L16A16_FLOAT, + L16_FLOAT, + L32A32_FLOAT, + L32_FLOAT, + L8A8_UNORM, + L8_UNORM, + R10G10B10A2_UINT, + R10G10B10A2_UNORM, + R11G11B10_FLOAT, + R16G16B16A16_FLOAT, + R16G16B16A16_SINT, + R16G16B16A16_SNORM, + R16G16B16A16_UINT, + R16G16B16A16_UNORM, + R16G16B16_FLOAT, + R16G16B16_SINT, + R16G16B16_SNORM, + R16G16B16_UINT, + R16G16B16_UNORM, + R16G16_FLOAT, + R16G16_SINT, + R16G16_SNORM, + R16G16_UINT, + R16G16_UNORM, + R16_FLOAT, + R16_SINT, + R16_SNORM, + R16_UINT, + R16_UNORM, + R32G32B32A32_FLOAT, + R32G32B32A32_SINT, + R32G32B32A32_UINT, + R32G32B32_FLOAT, + R32G32B32_SINT, + R32G32B32_UINT, + R32G32_FLOAT, + R32G32_SINT, + R32G32_UINT, + R32_FLOAT, + R32_SINT, + R32_UINT, + R4G4B4A4_UNORM, + R5G5B5A1_UNORM, + R5G6B5_UNORM, + R8G8B8A8_SINT, + R8G8B8A8_SNORM, + R8G8B8A8_UINT, + R8G8B8A8_UNORM, + R8G8B8A8_UNORM_SRGB, + R8G8B8_SINT, + R8G8B8_SNORM, + R8G8B8_UINT, + R8G8B8_UNORM, + R8G8B8_UNORM_SRGB, + R8G8_SINT, + R8G8_SNORM, + R8G8_UINT, + R8G8_UNORM, + R8_SINT, + R8_SNORM, + R8_UINT, + R8_UNORM, + R9G9B9E5_SHAREDEXP, + S8_UINT +}; + +constexpr uint32_t kNumANGLEFormats = 128; + +} // namespace angle diff --git a/src/3rdparty/angle/src/libANGLE/renderer/Format_table_autogen.cpp b/src/3rdparty/angle/src/libANGLE/renderer/Format_table_autogen.cpp new file mode 100644 index 0000000000..ecb3ad231a --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/Format_table_autogen.cpp @@ -0,0 +1,434 @@ +// GENERATED FILE - DO NOT EDIT. +// Generated by gen_angle_format_table.py using data from angle_format_data.json +// +// Copyright 2017 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. +// +// ANGLE Format table: +// Queries for typed format information from the ANGLE format enum. + +#include "libANGLE/renderer/Format.h" + +#include "image_util/copyimage.h" +#include "image_util/generatemip.h" +#include "image_util/loadimage.h" + +namespace angle +{ + +static constexpr rx::FastCopyFunctionMap::Entry BGRAEntry = {GL_RGBA, GL_UNSIGNED_BYTE, + CopyBGRA8ToRGBA8}; +static constexpr rx::FastCopyFunctionMap BGRACopyFunctions = {&BGRAEntry, 1}; +static constexpr rx::FastCopyFunctionMap NoCopyFunctions; + +constexpr Format g_formatInfoTable[] = { + // clang-format off + { Format::ID::NONE, GL_NONE, GL_NONE, nullptr, NoCopyFunctions, nullptr, nullptr, GL_NONE, 0, 0, 0, 0, 0, 0 }, + { Format::ID::A16_FLOAT, GL_ALPHA16F_EXT, GL_ALPHA16F_EXT, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_FLOAT, 0, 0, 0, 16, 0, 0 }, + { Format::ID::A32_FLOAT, GL_ALPHA32F_EXT, GL_ALPHA32F_EXT, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_FLOAT, 0, 0, 0, 32, 0, 0 }, + { Format::ID::A8_UNORM, GL_ALPHA8_EXT, GL_ALPHA8_EXT, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 8, 0, 0 }, + { Format::ID::ASTC_10x10_SRGB_BLOCK, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0 }, + { Format::ID::ASTC_10x10_UNORM_BLOCK, GL_COMPRESSED_RGBA_ASTC_10x10_KHR, GL_COMPRESSED_RGBA_ASTC_10x10_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0 }, + { Format::ID::ASTC_10x5_SRGB_BLOCK, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0 }, + { Format::ID::ASTC_10x5_UNORM_BLOCK, GL_COMPRESSED_RGBA_ASTC_10x5_KHR, GL_COMPRESSED_RGBA_ASTC_10x5_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0 }, + { Format::ID::ASTC_10x6_SRGB_BLOCK, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0 }, + { Format::ID::ASTC_10x6_UNORM_BLOCK, GL_COMPRESSED_RGBA_ASTC_10x6_KHR, GL_COMPRESSED_RGBA_ASTC_10x6_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0 }, + { Format::ID::ASTC_10x8_SRGB_BLOCK, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0 }, + { Format::ID::ASTC_10x8_UNORM_BLOCK, GL_COMPRESSED_RGBA_ASTC_10x8_KHR, GL_COMPRESSED_RGBA_ASTC_10x8_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0 }, + { Format::ID::ASTC_12x10_SRGB_BLOCK, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0 }, + { Format::ID::ASTC_12x10_UNORM_BLOCK, GL_COMPRESSED_RGBA_ASTC_12x10_KHR, GL_COMPRESSED_RGBA_ASTC_12x10_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0 }, + { Format::ID::ASTC_12x12_SRGB_BLOCK, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0 }, + { Format::ID::ASTC_12x12_UNORM_BLOCK, GL_COMPRESSED_RGBA_ASTC_12x12_KHR, GL_COMPRESSED_RGBA_ASTC_12x12_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0 }, + { Format::ID::ASTC_4x4_SRGB_BLOCK, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0 }, + { Format::ID::ASTC_4x4_UNORM_BLOCK, GL_COMPRESSED_RGBA_ASTC_4x4_KHR, GL_COMPRESSED_RGBA_ASTC_4x4_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0 }, + { Format::ID::ASTC_5x4_SRGB_BLOCK, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0 }, + { Format::ID::ASTC_5x4_UNORM_BLOCK, GL_COMPRESSED_RGBA_ASTC_5x4_KHR, GL_COMPRESSED_RGBA_ASTC_5x4_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0 }, + { Format::ID::ASTC_5x5_SRGB_BLOCK, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0 }, + { Format::ID::ASTC_5x5_UNORM_BLOCK, GL_COMPRESSED_RGBA_ASTC_5x5_KHR, GL_COMPRESSED_RGBA_ASTC_5x5_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0 }, + { Format::ID::ASTC_6x5_SRGB_BLOCK, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0 }, + { Format::ID::ASTC_6x5_UNORM_BLOCK, GL_COMPRESSED_RGBA_ASTC_6x5_KHR, GL_COMPRESSED_RGBA_ASTC_6x5_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0 }, + { Format::ID::ASTC_6x6_SRGB_BLOCK, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0 }, + { Format::ID::ASTC_6x6_UNORM_BLOCK, GL_COMPRESSED_RGBA_ASTC_6x6_KHR, GL_COMPRESSED_RGBA_ASTC_6x6_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0 }, + { Format::ID::ASTC_8x5_SRGB_BLOCK, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0 }, + { Format::ID::ASTC_8x5_UNORM_BLOCK, GL_COMPRESSED_RGBA_ASTC_8x5_KHR, GL_COMPRESSED_RGBA_ASTC_8x5_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0 }, + { Format::ID::ASTC_8x6_SRGB_BLOCK, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0 }, + { Format::ID::ASTC_8x6_UNORM_BLOCK, GL_COMPRESSED_RGBA_ASTC_8x6_KHR, GL_COMPRESSED_RGBA_ASTC_8x6_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0 }, + { Format::ID::ASTC_8x8_SRGB_BLOCK, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0 }, + { Format::ID::ASTC_8x8_UNORM_BLOCK, GL_COMPRESSED_RGBA_ASTC_8x8_KHR, GL_COMPRESSED_RGBA_ASTC_8x8_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0 }, + { Format::ID::B4G4R4A4_UNORM, GL_BGRA4_ANGLEX, GL_RGBA4, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_UNSIGNED_NORMALIZED, 4, 4, 4, 4, 0, 0 }, + { Format::ID::B5G5R5A1_UNORM, GL_BGR5_A1_ANGLEX, GL_RGB5_A1, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_UNSIGNED_NORMALIZED, 5, 5, 5, 1, 0, 0 }, + { Format::ID::B5G6R5_UNORM, GL_BGR565_ANGLEX, GL_RGB565, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_UNSIGNED_NORMALIZED, 5, 6, 5, 0, 0, 0 }, + { Format::ID::B8G8R8A8_UNORM, GL_BGRA8_EXT, GL_BGRA8_EXT, GenerateMip, BGRACopyFunctions, ReadColor, WriteColor, GL_UNSIGNED_NORMALIZED, 8, 8, 8, 8, 0, 0 }, + { Format::ID::B8G8R8A8_UNORM_SRGB, GL_BGRA8_SRGB_ANGLEX, GL_BGRA8_SRGB_ANGLEX, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_UNSIGNED_NORMALIZED, 8, 8, 8, 8, 0, 0 }, + { Format::ID::B8G8R8X8_UNORM, GL_BGRA8_EXT, GL_BGRA8_EXT, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_UNSIGNED_NORMALIZED, 8, 8, 8, 0, 0, 0 }, + { Format::ID::BC1_RGBA_UNORM_BLOCK, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0 }, + { Format::ID::BC1_RGBA_UNORM_SRGB_BLOCK, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0 }, + { Format::ID::BC1_RGB_UNORM_BLOCK, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0 }, + { Format::ID::BC1_RGB_UNORM_SRGB_BLOCK, GL_COMPRESSED_SRGB_S3TC_DXT1_EXT, GL_COMPRESSED_SRGB_S3TC_DXT1_EXT, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0 }, + { Format::ID::BC2_RGBA_UNORM_BLOCK, GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE, GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0 }, + { Format::ID::BC2_RGBA_UNORM_SRGB_BLOCK, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0 }, + { Format::ID::BC3_RGBA_UNORM_BLOCK, GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE, GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0 }, + { Format::ID::BC3_RGBA_UNORM_SRGB_BLOCK, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0 }, + { Format::ID::D16_UNORM, GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT16, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 16, 0 }, + { Format::ID::D24_UNORM, GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT24, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 24, 0 }, + { Format::ID::D24_UNORM_S8_UINT, GL_DEPTH24_STENCIL8, GL_DEPTH24_STENCIL8, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 24, 8 }, + { Format::ID::D32_FLOAT, GL_DEPTH_COMPONENT32F, GL_DEPTH_COMPONENT32F, nullptr, NoCopyFunctions, nullptr, nullptr, GL_FLOAT, 0, 0, 0, 0, 32, 0 }, + { Format::ID::D32_FLOAT_S8X24_UINT, GL_DEPTH32F_STENCIL8, GL_DEPTH32F_STENCIL8, nullptr, NoCopyFunctions, nullptr, nullptr, GL_FLOAT, 0, 0, 0, 0, 32, 8 }, + { Format::ID::D32_UNORM, GL_DEPTH_COMPONENT32_OES, GL_DEPTH_COMPONENT32_OES, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 32, 0 }, + { Format::ID::EAC_R11G11_SNORM_BLOCK, GL_COMPRESSED_SIGNED_RG11_EAC, GL_COMPRESSED_SIGNED_RG11_EAC, nullptr, NoCopyFunctions, nullptr, nullptr, GL_SIGNED_NORMALIZED, 11, 11, 0, 0, 0, 0 }, + { Format::ID::EAC_R11G11_UNORM_BLOCK, GL_COMPRESSED_RG11_EAC, GL_COMPRESSED_RG11_EAC, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 11, 11, 0, 0, 0, 0 }, + { Format::ID::EAC_R11_SNORM_BLOCK, GL_COMPRESSED_SIGNED_R11_EAC, GL_COMPRESSED_SIGNED_R11_EAC, nullptr, NoCopyFunctions, nullptr, nullptr, GL_SIGNED_NORMALIZED, 11, 0, 0, 0, 0, 0 }, + { Format::ID::EAC_R11_UNORM_BLOCK, GL_COMPRESSED_R11_EAC, GL_COMPRESSED_R11_EAC, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 11, 0, 0, 0, 0, 0 }, + { Format::ID::ETC1_LOSSY_DECODE_R8G8B8_UNORM_BLOCK, GL_ETC1_RGB8_LOSSY_DECODE_ANGLE, GL_ETC1_RGB8_LOSSY_DECODE_ANGLE, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 8, 8, 8, 0, 0, 0 }, + { Format::ID::ETC1_R8G8B8_UNORM_BLOCK, GL_ETC1_RGB8_OES, GL_ETC1_RGB8_OES, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 8, 8, 8, 0, 0, 0 }, + { Format::ID::ETC2_R8G8B8A1_SRGB_BLOCK, GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2, GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 8, 8, 8, 1, 0, 0 }, + { Format::ID::ETC2_R8G8B8A1_UNORM_BLOCK, GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2, GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 8, 8, 8, 1, 0, 0 }, + { Format::ID::ETC2_R8G8B8A8_SRGB_BLOCK, GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC, GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 8, 8, 8, 8, 0, 0 }, + { Format::ID::ETC2_R8G8B8A8_UNORM_BLOCK, GL_COMPRESSED_RGBA8_ETC2_EAC, GL_COMPRESSED_RGBA8_ETC2_EAC, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 8, 8, 8, 8, 0, 0 }, + { Format::ID::ETC2_R8G8B8_SRGB_BLOCK, GL_COMPRESSED_SRGB8_ETC2, GL_COMPRESSED_SRGB8_ETC2, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 8, 8, 8, 0, 0, 0 }, + { Format::ID::ETC2_R8G8B8_UNORM_BLOCK, GL_COMPRESSED_RGB8_ETC2, GL_COMPRESSED_RGB8_ETC2, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 8, 8, 8, 0, 0, 0 }, + { Format::ID::L16A16_FLOAT, GL_LUMINANCE_ALPHA16F_EXT, GL_LUMINANCE_ALPHA16F_EXT, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_FLOAT, 0, 0, 0, 16, 0, 0 }, + { Format::ID::L16_FLOAT, GL_LUMINANCE16F_EXT, GL_LUMINANCE16F_EXT, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_FLOAT, 0, 0, 0, 0, 0, 0 }, + { Format::ID::L32A32_FLOAT, GL_LUMINANCE_ALPHA32F_EXT, GL_LUMINANCE_ALPHA32F_EXT, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_FLOAT, 0, 0, 0, 32, 0, 0 }, + { Format::ID::L32_FLOAT, GL_LUMINANCE32F_EXT, GL_LUMINANCE32F_EXT, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_FLOAT, 0, 0, 0, 0, 0, 0 }, + { Format::ID::L8A8_UNORM, GL_LUMINANCE8_ALPHA8_EXT, GL_LUMINANCE8_ALPHA8_EXT, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 8, 0, 0 }, + { Format::ID::L8_UNORM, GL_LUMINANCE8_EXT, GL_LUMINANCE8_EXT, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0 }, + { Format::ID::R10G10B10A2_UINT, GL_RGB10_A2UI, GL_RGB10_A2UI, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_UNSIGNED_INT, 10, 10, 10, 2, 0, 0 }, + { Format::ID::R10G10B10A2_UNORM, GL_RGB10_A2, GL_RGB10_A2, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_UNSIGNED_NORMALIZED, 10, 10, 10, 2, 0, 0 }, + { Format::ID::R11G11B10_FLOAT, GL_R11F_G11F_B10F, GL_R11F_G11F_B10F, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_FLOAT, 11, 11, 10, 0, 0, 0 }, + { Format::ID::R16G16B16A16_FLOAT, GL_RGBA16F, GL_RGBA16F, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_FLOAT, 16, 16, 16, 16, 0, 0 }, + { Format::ID::R16G16B16A16_SINT, GL_RGBA16I, GL_RGBA16I, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_INT, 16, 16, 16, 16, 0, 0 }, + { Format::ID::R16G16B16A16_SNORM, GL_RGBA16_SNORM_EXT, GL_RGBA16_SNORM_EXT, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_SIGNED_NORMALIZED, 16, 16, 16, 16, 0, 0 }, + { Format::ID::R16G16B16A16_UINT, GL_RGBA16UI, GL_RGBA16UI, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_UNSIGNED_INT, 16, 16, 16, 16, 0, 0 }, + { Format::ID::R16G16B16A16_UNORM, GL_RGBA16_EXT, GL_RGBA16_EXT, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_UNSIGNED_NORMALIZED, 16, 16, 16, 16, 0, 0 }, + { Format::ID::R16G16B16_FLOAT, GL_RGB16F, GL_RGB16F, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_FLOAT, 16, 16, 16, 0, 0, 0 }, + { Format::ID::R16G16B16_SINT, GL_RGB16I, GL_RGB16I, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_INT, 16, 16, 16, 0, 0, 0 }, + { Format::ID::R16G16B16_SNORM, GL_RGB16_SNORM_EXT, GL_RGB16_SNORM_EXT, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_SIGNED_NORMALIZED, 16, 16, 16, 0, 0, 0 }, + { Format::ID::R16G16B16_UINT, GL_RGB16UI, GL_RGB16UI, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_UNSIGNED_INT, 16, 16, 16, 0, 0, 0 }, + { Format::ID::R16G16B16_UNORM, GL_RGB16_EXT, GL_RGB16_EXT, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_UNSIGNED_NORMALIZED, 16, 16, 16, 0, 0, 0 }, + { Format::ID::R16G16_FLOAT, GL_RG16F, GL_RG16F, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_FLOAT, 16, 16, 0, 0, 0, 0 }, + { Format::ID::R16G16_SINT, GL_RG16I, GL_RG16I, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_INT, 16, 16, 0, 0, 0, 0 }, + { Format::ID::R16G16_SNORM, GL_RG16_SNORM_EXT, GL_RG16_SNORM_EXT, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_SIGNED_NORMALIZED, 16, 16, 0, 0, 0, 0 }, + { Format::ID::R16G16_UINT, GL_RG16UI, GL_RG16UI, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_UNSIGNED_INT, 16, 16, 0, 0, 0, 0 }, + { Format::ID::R16G16_UNORM, GL_RG16_EXT, GL_RG16_EXT, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_UNSIGNED_NORMALIZED, 16, 16, 0, 0, 0, 0 }, + { Format::ID::R16_FLOAT, GL_R16F, GL_R16F, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_FLOAT, 16, 0, 0, 0, 0, 0 }, + { Format::ID::R16_SINT, GL_R16I, GL_R16I, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_INT, 16, 0, 0, 0, 0, 0 }, + { Format::ID::R16_SNORM, GL_R16_SNORM_EXT, GL_R16_SNORM_EXT, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_SIGNED_NORMALIZED, 16, 0, 0, 0, 0, 0 }, + { Format::ID::R16_UINT, GL_R16UI, GL_R16UI, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_UNSIGNED_INT, 16, 0, 0, 0, 0, 0 }, + { Format::ID::R16_UNORM, GL_R16_EXT, GL_R16_EXT, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_UNSIGNED_NORMALIZED, 16, 0, 0, 0, 0, 0 }, + { Format::ID::R32G32B32A32_FLOAT, GL_RGBA32F, GL_RGBA32F, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_FLOAT, 32, 32, 32, 32, 0, 0 }, + { Format::ID::R32G32B32A32_SINT, GL_RGBA32I, GL_RGBA32I, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_INT, 32, 32, 32, 32, 0, 0 }, + { Format::ID::R32G32B32A32_UINT, GL_RGBA32UI, GL_RGBA32UI, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_UNSIGNED_INT, 32, 32, 32, 32, 0, 0 }, + { Format::ID::R32G32B32_FLOAT, GL_RGB32F, GL_RGB32F, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_FLOAT, 32, 32, 32, 0, 0, 0 }, + { Format::ID::R32G32B32_SINT, GL_RGB32I, GL_RGB32I, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_INT, 32, 32, 32, 0, 0, 0 }, + { Format::ID::R32G32B32_UINT, GL_RGB32UI, GL_RGB32UI, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_UNSIGNED_INT, 32, 32, 32, 0, 0, 0 }, + { Format::ID::R32G32_FLOAT, GL_RG32F, GL_RG32F, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_FLOAT, 32, 32, 0, 0, 0, 0 }, + { Format::ID::R32G32_SINT, GL_RG32I, GL_RG32I, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_INT, 32, 32, 0, 0, 0, 0 }, + { Format::ID::R32G32_UINT, GL_RG32UI, GL_RG32UI, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_UNSIGNED_INT, 32, 32, 0, 0, 0, 0 }, + { Format::ID::R32_FLOAT, GL_R32F, GL_R32F, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_FLOAT, 32, 0, 0, 0, 0, 0 }, + { Format::ID::R32_SINT, GL_R32I, GL_R32I, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_INT, 32, 0, 0, 0, 0, 0 }, + { Format::ID::R32_UINT, GL_R32UI, GL_R32UI, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_UNSIGNED_INT, 32, 0, 0, 0, 0, 0 }, + { Format::ID::R4G4B4A4_UNORM, GL_RGBA4, GL_RGBA4, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_UNSIGNED_NORMALIZED, 4, 4, 4, 4, 0, 0 }, + { Format::ID::R5G5B5A1_UNORM, GL_RGB5_A1, GL_RGB5_A1, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_UNSIGNED_NORMALIZED, 5, 5, 5, 1, 0, 0 }, + { Format::ID::R5G6B5_UNORM, GL_RGB565, GL_RGB565, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_UNSIGNED_NORMALIZED, 5, 6, 5, 0, 0, 0 }, + { Format::ID::R8G8B8A8_SINT, GL_RGBA8I, GL_RGBA8I, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_INT, 8, 8, 8, 8, 0, 0 }, + { Format::ID::R8G8B8A8_SNORM, GL_RGBA8_SNORM, GL_RGBA8_SNORM, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_SIGNED_NORMALIZED, 8, 8, 8, 8, 0, 0 }, + { Format::ID::R8G8B8A8_UINT, GL_RGBA8UI, GL_RGBA8UI, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_UNSIGNED_INT, 8, 8, 8, 8, 0, 0 }, + { Format::ID::R8G8B8A8_UNORM, GL_RGBA8, GL_RGBA8, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_UNSIGNED_NORMALIZED, 8, 8, 8, 8, 0, 0 }, + { Format::ID::R8G8B8A8_UNORM_SRGB, GL_SRGB8_ALPHA8, GL_SRGB8_ALPHA8, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_UNSIGNED_NORMALIZED, 8, 8, 8, 8, 0, 0 }, + { Format::ID::R8G8B8_SINT, GL_RGB8I, GL_RGB8I, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_INT, 8, 8, 8, 0, 0, 0 }, + { Format::ID::R8G8B8_SNORM, GL_RGB8_SNORM, GL_RGB8_SNORM, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_SIGNED_NORMALIZED, 8, 8, 8, 0, 0, 0 }, + { Format::ID::R8G8B8_UINT, GL_RGB8UI, GL_RGB8UI, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_UNSIGNED_INT, 8, 8, 8, 0, 0, 0 }, + { Format::ID::R8G8B8_UNORM, GL_RGB8, GL_RGB8, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_UNSIGNED_NORMALIZED, 8, 8, 8, 0, 0, 0 }, + { Format::ID::R8G8B8_UNORM_SRGB, GL_SRGB8, GL_SRGB8, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_UNSIGNED_NORMALIZED, 8, 8, 8, 0, 0, 0 }, + { Format::ID::R8G8_SINT, GL_RG8I, GL_RG8I, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_INT, 8, 8, 0, 0, 0, 0 }, + { Format::ID::R8G8_SNORM, GL_RG8_SNORM, GL_RG8_SNORM, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_SIGNED_NORMALIZED, 8, 8, 0, 0, 0, 0 }, + { Format::ID::R8G8_UINT, GL_RG8UI, GL_RG8UI, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_UNSIGNED_INT, 8, 8, 0, 0, 0, 0 }, + { Format::ID::R8G8_UNORM, GL_RG8, GL_RG8, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_UNSIGNED_NORMALIZED, 8, 8, 0, 0, 0, 0 }, + { Format::ID::R8_SINT, GL_R8I, GL_R8I, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_INT, 8, 0, 0, 0, 0, 0 }, + { Format::ID::R8_SNORM, GL_R8_SNORM, GL_R8_SNORM, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_SIGNED_NORMALIZED, 8, 0, 0, 0, 0, 0 }, + { Format::ID::R8_UINT, GL_R8UI, GL_R8UI, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_UNSIGNED_INT, 8, 0, 0, 0, 0, 0 }, + { Format::ID::R8_UNORM, GL_R8, GL_R8, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_UNSIGNED_NORMALIZED, 8, 0, 0, 0, 0, 0 }, + { Format::ID::R9G9B9E5_SHAREDEXP, GL_RGB9_E5, GL_RGB9_E5, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_FLOAT, 9, 9, 9, 0, 0, 0 }, + { Format::ID::S8_UINT, GL_STENCIL_INDEX8, GL_STENCIL_INDEX8, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_INT, 0, 0, 0, 0, 0, 8 }, + // clang-format on +}; + +// static +Format::ID Format::InternalFormatToID(GLenum internalFormat) +{ + switch (internalFormat) + { + case GL_RGBA16_EXT: + return Format::ID::R16G16B16A16_UNORM; + case GL_ETC1_RGB8_LOSSY_DECODE_ANGLE: + return Format::ID::ETC1_LOSSY_DECODE_R8G8B8_UNORM_BLOCK; + case GL_RG8I: + return Format::ID::R8G8_SINT; + case GL_R16F: + return Format::ID::R16_FLOAT; + case GL_RGBA8I: + return Format::ID::R8G8B8A8_SINT; + case GL_RG8UI: + return Format::ID::R8G8_UINT; + case GL_RGBA8_SNORM: + return Format::ID::R8G8B8A8_SNORM; + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR: + return Format::ID::ASTC_12x10_SRGB_BLOCK; + case GL_RG8_SNORM: + return Format::ID::R8G8_SNORM; + case GL_BGR565_ANGLEX: + return Format::ID::B5G6R5_UNORM; + case GL_DEPTH_COMPONENT24: + return Format::ID::D24_UNORM; + case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2: + return Format::ID::ETC2_R8G8B8A1_UNORM_BLOCK; + case GL_COMPRESSED_RGBA_ASTC_10x10_KHR: + return Format::ID::ASTC_10x10_UNORM_BLOCK; + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR: + return Format::ID::ASTC_8x6_SRGB_BLOCK; + case GL_RGB32UI: + return Format::ID::R32G32B32_UINT; + case GL_COMPRESSED_RGBA_ASTC_6x5_KHR: + return Format::ID::ASTC_6x5_UNORM_BLOCK; + case GL_ALPHA32F_EXT: + return Format::ID::A32_FLOAT; + case GL_R16UI: + return Format::ID::R16_UINT; + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR: + return Format::ID::ASTC_5x4_SRGB_BLOCK; + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR: + return Format::ID::ASTC_5x5_SRGB_BLOCK; + case GL_COMPRESSED_R11_EAC: + return Format::ID::EAC_R11_UNORM_BLOCK; + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR: + return Format::ID::ASTC_10x10_SRGB_BLOCK; + case GL_RGBA32UI: + return Format::ID::R32G32B32A32_UINT; + case GL_R8_SNORM: + return Format::ID::R8_SNORM; + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT: + return Format::ID::BC1_RGBA_UNORM_SRGB_BLOCK; + case GL_LUMINANCE32F_EXT: + return Format::ID::L32_FLOAT; + case GL_RG16_EXT: + return Format::ID::R16G16_UNORM; + case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2: + return Format::ID::ETC2_R8G8B8A1_SRGB_BLOCK; + case GL_SRGB8: + return Format::ID::R8G8B8_UNORM_SRGB; + case GL_LUMINANCE8_ALPHA8_EXT: + return Format::ID::L8A8_UNORM; + case GL_BGRX8_ANGLEX: + return Format::ID::B8G8R8X8_UNORM; + case GL_RGB16_SNORM_EXT: + return Format::ID::R16G16B16_SNORM; + case GL_RGBA8UI: + return Format::ID::R8G8B8A8_UINT; + case GL_BGRA4_ANGLEX: + return Format::ID::B4G4R4A4_UNORM; + case GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC: + return Format::ID::ETC2_R8G8B8A8_SRGB_BLOCK; + case GL_LUMINANCE8_EXT: + return Format::ID::L8_UNORM; + case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: + return Format::ID::BC3_RGBA_UNORM_BLOCK; + case GL_R16I: + return Format::ID::R16_SINT; + case GL_RGB5_A1: + return Format::ID::R5G5B5A1_UNORM; + case GL_RGB16UI: + return Format::ID::R16G16B16_UINT; + case GL_COMPRESSED_RGBA_ASTC_4x4_KHR: + return Format::ID::ASTC_4x4_UNORM_BLOCK; + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT: + return Format::ID::BC2_RGBA_UNORM_SRGB_BLOCK; + case GL_R16_SNORM_EXT: + return Format::ID::R16_SNORM; + case GL_COMPRESSED_RGB8_ETC2: + return Format::ID::ETC2_R8G8B8_UNORM_BLOCK; + case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT: + return Format::ID::BC1_RGB_UNORM_SRGB_BLOCK; + case GL_RGBA32F: + return Format::ID::R32G32B32A32_FLOAT; + case GL_RGBA32I: + return Format::ID::R32G32B32A32_SINT; + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT: + return Format::ID::BC3_RGBA_UNORM_SRGB_BLOCK; + case GL_COMPRESSED_RGBA_ASTC_8x5_KHR: + return Format::ID::ASTC_8x5_UNORM_BLOCK; + case GL_RG8: + return Format::ID::R8G8_UNORM; + case GL_COMPRESSED_RGBA_ASTC_8x8_KHR: + return Format::ID::ASTC_8x8_UNORM_BLOCK; + case GL_RGB10_A2: + return Format::ID::R10G10B10A2_UNORM; + case GL_COMPRESSED_SIGNED_RG11_EAC: + return Format::ID::EAC_R11G11_SNORM_BLOCK; + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR: + return Format::ID::ASTC_6x6_SRGB_BLOCK; + case GL_DEPTH_COMPONENT16: + return Format::ID::D16_UNORM; + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR: + return Format::ID::ASTC_10x5_SRGB_BLOCK; + case GL_RGB32I: + return Format::ID::R32G32B32_SINT; + case GL_R8: + return Format::ID::R8_UNORM; + case GL_RGB32F: + return Format::ID::R32G32B32_FLOAT; + case GL_R16_EXT: + return Format::ID::R16_UNORM; + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR: + return Format::ID::ASTC_8x8_SRGB_BLOCK; + case GL_COMPRESSED_RGBA_ASTC_10x5_KHR: + return Format::ID::ASTC_10x5_UNORM_BLOCK; + case GL_R11F_G11F_B10F: + return Format::ID::R11G11B10_FLOAT; + case GL_RGB8: + return Format::ID::R8G8B8_UNORM; + case GL_COMPRESSED_RGBA_ASTC_5x5_KHR: + return Format::ID::ASTC_5x5_UNORM_BLOCK; + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR: + return Format::ID::ASTC_8x5_SRGB_BLOCK; + case GL_RGBA16I: + return Format::ID::R16G16B16A16_SINT; + case GL_R8I: + return Format::ID::R8_SINT; + case GL_RGB8_SNORM: + return Format::ID::R8G8B8_SNORM; + case GL_RG32F: + return Format::ID::R32G32_FLOAT; + case GL_DEPTH_COMPONENT32F: + return Format::ID::D32_FLOAT; + case GL_RG32I: + return Format::ID::R32G32_SINT; + case GL_ALPHA8_EXT: + return Format::ID::A8_UNORM; + case GL_RGB16_EXT: + return Format::ID::R16G16B16_UNORM; + case GL_BGRA8_EXT: + return Format::ID::B8G8R8A8_UNORM; + case GL_RG32UI: + return Format::ID::R32G32_UINT; + case GL_RGBA16UI: + return Format::ID::R16G16B16A16_UINT; + case GL_COMPRESSED_RGBA8_ETC2_EAC: + return Format::ID::ETC2_R8G8B8A8_UNORM_BLOCK; + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: + return Format::ID::BC1_RGBA_UNORM_BLOCK; + case GL_COMPRESSED_RGBA_ASTC_10x6_KHR: + return Format::ID::ASTC_10x6_UNORM_BLOCK; + case GL_COMPRESSED_SRGB8_ETC2: + return Format::ID::ETC2_R8G8B8_SRGB_BLOCK; + case GL_BGRA8_SRGB_ANGLEX: + return Format::ID::B8G8R8A8_UNORM_SRGB; + case GL_DEPTH32F_STENCIL8: + return Format::ID::D32_FLOAT_S8X24_UINT; + case GL_COMPRESSED_RGBA_ASTC_6x6_KHR: + return Format::ID::ASTC_6x6_UNORM_BLOCK; + case GL_R32UI: + return Format::ID::R32_UINT; + case GL_BGR5_A1_ANGLEX: + return Format::ID::B5G5R5A1_UNORM; + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR: + return Format::ID::ASTC_12x12_SRGB_BLOCK; + case GL_COMPRESSED_RG11_EAC: + return Format::ID::EAC_R11G11_UNORM_BLOCK; + case GL_SRGB8_ALPHA8: + return Format::ID::R8G8B8A8_UNORM_SRGB; + case GL_LUMINANCE_ALPHA16F_EXT: + return Format::ID::L16A16_FLOAT; + case GL_RGBA: + return Format::ID::R8G8B8A8_UNORM; + case GL_ETC1_RGB8_OES: + return Format::ID::ETC1_R8G8B8_UNORM_BLOCK; + case GL_DEPTH24_STENCIL8: + return Format::ID::D24_UNORM_S8_UINT; + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR: + return Format::ID::ASTC_4x4_SRGB_BLOCK; + case GL_RGB16I: + return Format::ID::R16G16B16_SINT; + case GL_R8UI: + return Format::ID::R8_UINT; + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR: + return Format::ID::ASTC_10x6_SRGB_BLOCK; + case GL_RGBA16F: + return Format::ID::R16G16B16A16_FLOAT; + case GL_COMPRESSED_SIGNED_R11_EAC: + return Format::ID::EAC_R11_SNORM_BLOCK; + case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: + return Format::ID::BC1_RGB_UNORM_BLOCK; + case GL_RGB8I: + return Format::ID::R8G8B8_SINT; + case GL_COMPRESSED_RGBA_ASTC_8x6_KHR: + return Format::ID::ASTC_8x6_UNORM_BLOCK; + case GL_STENCIL_INDEX8: + return Format::ID::S8_UINT; + case GL_LUMINANCE_ALPHA32F_EXT: + return Format::ID::L32A32_FLOAT; + case GL_ALPHA16F_EXT: + return Format::ID::A16_FLOAT; + case GL_RGB8UI: + return Format::ID::R8G8B8_UINT; + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR: + return Format::ID::ASTC_10x8_SRGB_BLOCK; + case GL_COMPRESSED_RGBA_ASTC_12x10_KHR: + return Format::ID::ASTC_12x10_UNORM_BLOCK; + case GL_RGB9_E5: + return Format::ID::R9G9B9E5_SHAREDEXP; + case GL_RGBA16_SNORM_EXT: + return Format::ID::R16G16B16A16_SNORM; + case GL_R32I: + return Format::ID::R32_SINT; + case GL_DEPTH_COMPONENT32_OES: + return Format::ID::D32_UNORM; + case GL_R32F: + return Format::ID::R32_FLOAT; + case GL_NONE: + return Format::ID::NONE; + case GL_RG16F: + return Format::ID::R16G16_FLOAT; + case GL_RGB: + return Format::ID::R8G8B8_UNORM; + case GL_RGB565: + return Format::ID::R5G6B5_UNORM; + case GL_LUMINANCE16F_EXT: + return Format::ID::L16_FLOAT; + case GL_RG16UI: + return Format::ID::R16G16_UINT; + case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: + return Format::ID::BC2_RGBA_UNORM_BLOCK; + case GL_RG16I: + return Format::ID::R16G16_SINT; + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR: + return Format::ID::ASTC_6x5_SRGB_BLOCK; + case GL_RG16_SNORM_EXT: + return Format::ID::R16G16_SNORM; + case GL_COMPRESSED_RGBA_ASTC_12x12_KHR: + return Format::ID::ASTC_12x12_UNORM_BLOCK; + case GL_COMPRESSED_RGBA_ASTC_5x4_KHR: + return Format::ID::ASTC_5x4_UNORM_BLOCK; + case GL_COMPRESSED_RGBA_ASTC_10x8_KHR: + return Format::ID::ASTC_10x8_UNORM_BLOCK; + case GL_RGBA4: + return Format::ID::R4G4B4A4_UNORM; + case GL_RGBA8: + return Format::ID::R8G8B8A8_UNORM; + case GL_RGB16F: + return Format::ID::R16G16B16_FLOAT; + case GL_RGB10_A2UI: + return Format::ID::R10G10B10A2_UINT; + default: + return Format::ID::NONE; + } +} + +// static +const Format &Format::Get(ID id) +{ + return g_formatInfoTable[static_cast(id)]; +} + +} // namespace angle diff --git a/src/3rdparty/angle/src/libANGLE/renderer/FramebufferAttachmentObjectImpl.h b/src/3rdparty/angle/src/libANGLE/renderer/FramebufferAttachmentObjectImpl.h new file mode 100644 index 0000000000..056ddc833a --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/FramebufferAttachmentObjectImpl.h @@ -0,0 +1,54 @@ +// +// Copyright 2016 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. +// +// FramebufferAttachmentObjectImpl.h: +// Common ancenstor for all implementations of FBO attachable-objects. +// This means Surfaces, Textures and Renderbuffers. +// + +#ifndef LIBANGLE_RENDERER_FRAMEBUFFER_ATTACHMENT_OBJECT_IMPL_H_ +#define LIBANGLE_RENDERER_FRAMEBUFFER_ATTACHMENT_OBJECT_IMPL_H_ + +#include "libANGLE/FramebufferAttachment.h" + +namespace rx +{ + +class FramebufferAttachmentObjectImpl : angle::NonCopyable +{ + public: + FramebufferAttachmentObjectImpl() {} + virtual ~FramebufferAttachmentObjectImpl() {} + + virtual gl::Error getAttachmentRenderTarget(const gl::Context *context, + GLenum binding, + const gl::ImageIndex &imageIndex, + FramebufferAttachmentRenderTarget **rtOut); + + virtual gl::Error initializeContents(const gl::Context *context, + const gl::ImageIndex &imageIndex); +}; + +inline gl::Error FramebufferAttachmentObjectImpl::getAttachmentRenderTarget( + const gl::Context *context, + GLenum binding, + const gl::ImageIndex &imageIndex, + FramebufferAttachmentRenderTarget **rtOut) +{ + UNIMPLEMENTED(); + return gl::OutOfMemory() << "getAttachmentRenderTarget not supported."; +} + +inline gl::Error FramebufferAttachmentObjectImpl::initializeContents( + const gl::Context *context, + const gl::ImageIndex &imageIndex) +{ + UNIMPLEMENTED(); + return gl::OutOfMemory() << "initialize not supported."; +} + +} // namespace rx + +#endif // LIBANGLE_RENDERER_FRAMEBUFFER_ATTACHMENT_OBJECT_IMPL_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/FramebufferImpl.h b/src/3rdparty/angle/src/libANGLE/renderer/FramebufferImpl.h index 680122d0ed..ebb166ca80 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/FramebufferImpl.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/FramebufferImpl.h @@ -24,53 +24,72 @@ struct Rectangle; namespace rx { +class DisplayImpl; class FramebufferImpl : angle::NonCopyable { public: - explicit FramebufferImpl(const gl::Framebuffer::Data &data) : mData(data) { } - virtual ~FramebufferImpl() { } - - virtual gl::Error discard(size_t count, const GLenum *attachments) = 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::Data &data, + explicit FramebufferImpl(const gl::FramebufferState &state) : mState(state) {} + virtual ~FramebufferImpl() {} + virtual void destroy(const gl::Context *context) {} + virtual void destroyDefault(const egl::Display *display) {} + + virtual gl::Error discard(const gl::Context *context, + size_t count, + const GLenum *attachments) = 0; + virtual gl::Error invalidate(const gl::Context *context, + size_t count, + const GLenum *attachments) = 0; + virtual gl::Error invalidateSub(const gl::Context *context, + size_t count, + const GLenum *attachments, + const gl::Rectangle &area) = 0; + + virtual gl::Error clear(const gl::Context *context, GLbitfield mask) = 0; + virtual gl::Error clearBufferfv(const gl::Context *context, GLenum buffer, GLint drawbuffer, const GLfloat *values) = 0; - virtual gl::Error clearBufferuiv(const gl::Data &data, + virtual gl::Error clearBufferuiv(const gl::Context *context, GLenum buffer, GLint drawbuffer, const GLuint *values) = 0; - virtual gl::Error clearBufferiv(const gl::Data &data, + virtual gl::Error clearBufferiv(const gl::Context *context, GLenum buffer, GLint drawbuffer, const GLint *values) = 0; - virtual gl::Error clearBufferfi(const gl::Data &data, + virtual gl::Error clearBufferfi(const gl::Context *context, 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 GLenum getImplementationColorReadFormat(const gl::Context *context) const = 0; + virtual GLenum getImplementationColorReadType(const gl::Context *context) const = 0; + virtual gl::Error readPixels(const gl::Context *context, + const gl::Rectangle &area, + GLenum format, + GLenum type, + void *pixels) = 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 gl::Error blit(const gl::Context *context, + const gl::Rectangle &sourceArea, + const gl::Rectangle &destArea, + GLbitfield mask, + GLenum filter) = 0; - virtual bool checkStatus() const = 0; + virtual bool checkStatus(const gl::Context *context) const = 0; - virtual void syncState(const gl::Framebuffer::DirtyBits &dirtyBits) = 0; + virtual void syncState(const gl::Context *context, + const gl::Framebuffer::DirtyBits &dirtyBits) = 0; - const gl::Framebuffer::Data &getData() const { return mData; } + virtual gl::Error getSamplePosition(size_t index, GLfloat *xy) const = 0; + + const gl::FramebufferState &getState() const { return mState; } protected: - const gl::Framebuffer::Data &mData; + const gl::FramebufferState &mState; }; - } -#endif // LIBANGLE_RENDERER_FRAMEBUFFERIMPL_H_ +#endif // LIBANGLE_RENDERER_FRAMEBUFFERIMPL_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/FramebufferImpl_mock.h b/src/3rdparty/angle/src/libANGLE/renderer/FramebufferImpl_mock.h index 57c95342d7..c2d069676e 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/FramebufferImpl_mock.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/FramebufferImpl_mock.h @@ -20,38 +20,39 @@ namespace rx class MockFramebufferImpl : public rx::FramebufferImpl { public: - MockFramebufferImpl() : rx::FramebufferImpl(gl::Framebuffer::Data()) {} - virtual ~MockFramebufferImpl() { destroy(); } - - MOCK_METHOD2(discard, gl::Error(size_t, const GLenum *)); - MOCK_METHOD2(invalidate, gl::Error(size_t, const GLenum *)); - MOCK_METHOD3(invalidateSub, gl::Error(size_t, const GLenum *, const gl::Rectangle &)); - - MOCK_METHOD2(clear, gl::Error(const gl::Data &, GLbitfield)); - MOCK_METHOD4(clearBufferfv, gl::Error(const gl::Data &, GLenum, GLint, const GLfloat *)); - MOCK_METHOD4(clearBufferuiv, gl::Error(const gl::Data &, GLenum, GLint, const GLuint *)); - MOCK_METHOD4(clearBufferiv, gl::Error(const gl::Data &, GLenum, GLint, const GLint *)); - MOCK_METHOD5(clearBufferfi, gl::Error(const gl::Data &, GLenum, GLint, GLfloat, GLint)); - - MOCK_CONST_METHOD0(getImplementationColorReadFormat, GLenum()); - MOCK_CONST_METHOD0(getImplementationColorReadType, GLenum()); - MOCK_CONST_METHOD5( - readPixels, - gl::Error(const gl::State &, const gl::Rectangle &, GLenum, GLenum, GLvoid *)); - - MOCK_METHOD6(blit, - gl::Error(const gl::State &, + MockFramebufferImpl() : rx::FramebufferImpl(gl::FramebufferState()) {} + virtual ~MockFramebufferImpl() { destructor(); } + + MOCK_METHOD3(discard, gl::Error(const gl::Context *, size_t, const GLenum *)); + MOCK_METHOD3(invalidate, gl::Error(const gl::Context *, size_t, const GLenum *)); + MOCK_METHOD4(invalidateSub, + gl::Error(const gl::Context *, size_t, const GLenum *, const gl::Rectangle &)); + + MOCK_METHOD2(clear, gl::Error(const gl::Context *, GLbitfield)); + MOCK_METHOD4(clearBufferfv, gl::Error(const gl::Context *, GLenum, GLint, const GLfloat *)); + MOCK_METHOD4(clearBufferuiv, gl::Error(const gl::Context *, GLenum, GLint, const GLuint *)); + MOCK_METHOD4(clearBufferiv, gl::Error(const gl::Context *, GLenum, GLint, const GLint *)); + MOCK_METHOD5(clearBufferfi, gl::Error(const gl::Context *, GLenum, GLint, GLfloat, GLint)); + + MOCK_CONST_METHOD1(getImplementationColorReadFormat, GLenum(const gl::Context *)); + MOCK_CONST_METHOD1(getImplementationColorReadType, GLenum(const gl::Context *)); + MOCK_METHOD5(readPixels, + gl::Error(const gl::Context *, const gl::Rectangle &, GLenum, GLenum, void *)); + + MOCK_CONST_METHOD2(getSamplePosition, gl::Error(size_t, GLfloat *)); + + MOCK_METHOD5(blit, + gl::Error(const gl::Context *, const gl::Rectangle &, const gl::Rectangle &, GLbitfield, - GLenum, - const gl::Framebuffer *)); + GLenum)); - MOCK_CONST_METHOD0(checkStatus, bool()); + MOCK_CONST_METHOD1(checkStatus, bool(const gl::Context *)); - MOCK_METHOD1(syncState, void(const gl::Framebuffer::DirtyBits &)); + MOCK_METHOD2(syncState, void(const gl::Context *, const gl::Framebuffer::DirtyBits &)); - MOCK_METHOD0(destroy, void()); + MOCK_METHOD0(destructor, void()); }; inline ::testing::NiceMock *MakeFramebufferMock() @@ -59,10 +60,10 @@ inline ::testing::NiceMock *MakeFramebufferMock() ::testing::NiceMock *framebufferImpl = new ::testing::NiceMock(); // TODO(jmadill): add ON_CALLS for other returning methods - ON_CALL(*framebufferImpl, checkStatus()).WillByDefault(::testing::Return(true)); + ON_CALL(*framebufferImpl, checkStatus(testing::_)).WillByDefault(::testing::Return(true)); // We must mock the destructor since NiceMock doesn't work for destructors. - EXPECT_CALL(*framebufferImpl, destroy()).Times(1).RetiresOnSaturation(); + EXPECT_CALL(*framebufferImpl, destructor()).Times(1).RetiresOnSaturation(); return framebufferImpl; } diff --git a/src/3rdparty/angle/src/libANGLE/renderer/GLImplFactory.h b/src/3rdparty/angle/src/libANGLE/renderer/GLImplFactory.h new file mode 100644 index 0000000000..b9a135f596 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/GLImplFactory.h @@ -0,0 +1,93 @@ +// +// 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. +// +// GLImplFactory.h: +// Factory interface for OpenGL ES Impl objects. +// + +#ifndef LIBANGLE_RENDERER_GLIMPLFACTORY_H_ +#define LIBANGLE_RENDERER_GLIMPLFACTORY_H_ + +#include + +#include "angle_gl.h" +#include "libANGLE/Framebuffer.h" +#include "libANGLE/Program.h" +#include "libANGLE/ProgramPipeline.h" +#include "libANGLE/Shader.h" +#include "libANGLE/TransformFeedback.h" +#include "libANGLE/VertexArray.h" + +namespace gl +{ +class ContextState; +} + +namespace rx +{ +class BufferImpl; +class CompilerImpl; +class ContextImpl; +class FenceNVImpl; +class SyncImpl; +class FramebufferImpl; +class PathImpl; +class ProgramImpl; +class ProgramPipelineImpl; +class QueryImpl; +class RenderbufferImpl; +class SamplerImpl; +class ShaderImpl; +class TextureImpl; +class TransformFeedbackImpl; +class VertexArrayImpl; + +class GLImplFactory : angle::NonCopyable +{ + public: + GLImplFactory() {} + virtual ~GLImplFactory() {} + + // Shader creation + virtual CompilerImpl *createCompiler() = 0; + virtual ShaderImpl *createShader(const gl::ShaderState &data) = 0; + virtual ProgramImpl *createProgram(const gl::ProgramState &data) = 0; + + // Framebuffer creation + virtual FramebufferImpl *createFramebuffer(const gl::FramebufferState &data) = 0; + + // Texture creation + virtual TextureImpl *createTexture(const gl::TextureState &state) = 0; + + // Renderbuffer creation + virtual RenderbufferImpl *createRenderbuffer() = 0; + + // Buffer creation + virtual BufferImpl *createBuffer(const gl::BufferState &state) = 0; + + // Vertex Array creation + virtual VertexArrayImpl *createVertexArray(const gl::VertexArrayState &data) = 0; + + // Query and Fence creation + virtual QueryImpl *createQuery(GLenum type) = 0; + virtual FenceNVImpl *createFenceNV() = 0; + virtual SyncImpl *createSync() = 0; + + // Transform Feedback creation + virtual TransformFeedbackImpl *createTransformFeedback( + const gl::TransformFeedbackState &state) = 0; + + // Sampler object creation + virtual SamplerImpl *createSampler(const gl::SamplerState &state) = 0; + + // Program Pipeline object creation + virtual ProgramPipelineImpl *createProgramPipeline(const gl::ProgramPipelineState &data) = 0; + + virtual std::vector createPaths(GLsizei range) = 0; +}; + +} // namespace rx + +#endif // LIBANGLE_RENDERER_GLIMPLFACTORY_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/Image.h b/src/3rdparty/angle/src/libANGLE/renderer/Image.h deleted file mode 100644 index 62d854c9b6..0000000000 --- a/src/3rdparty/angle/src/libANGLE/renderer/Image.h +++ /dev/null @@ -1,77 +0,0 @@ -// -// 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/ImageImpl.h b/src/3rdparty/angle/src/libANGLE/renderer/ImageImpl.h index e48f1946a8..79694eaebf 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/ImageImpl.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/ImageImpl.h @@ -12,21 +12,31 @@ #include "common/angleutils.h" #include "libANGLE/Error.h" +namespace gl +{ +class Context; +} // namespace gl + namespace egl { class ImageSibling; -} +struct ImageState; +} // namespace egl namespace rx { class ImageImpl : angle::NonCopyable { public: + ImageImpl(const egl::ImageState &state) : mState(state) {} virtual ~ImageImpl() {} virtual egl::Error initialize() = 0; - virtual gl::Error orphan(egl::ImageSibling *sibling) = 0; + virtual gl::Error orphan(const gl::Context *context, egl::ImageSibling *sibling) = 0; + + protected: + const egl::ImageState &mState; }; -} +} // namespace rx #endif // LIBANGLE_RENDERER_IMAGEIMPL_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/ImageImpl_mock.h b/src/3rdparty/angle/src/libANGLE/renderer/ImageImpl_mock.h index 27fe6a3947..30c0cc2594 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/ImageImpl_mock.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/ImageImpl_mock.h @@ -18,11 +18,17 @@ namespace rx class MockImageImpl : public ImageImpl { public: + MockImageImpl(const egl::ImageState &state, + EGLenum /*target*/, + const egl::AttributeMap & /*attribs*/) + : ImageImpl(state) + { + } virtual ~MockImageImpl() { destructor(); } MOCK_METHOD0(initialize, egl::Error(void)); - MOCK_METHOD1(orphan, gl::Error(egl::ImageSibling *)); + MOCK_METHOD2(orphan, gl::Error(const gl::Context *, egl::ImageSibling *)); MOCK_METHOD0(destructor, void()); }; -} +} // namespace rx #endif // LIBANGLE_RENDERER_IMAGEIMPLMOCK_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/ImplFactory.h b/src/3rdparty/angle/src/libANGLE/renderer/ImplFactory.h deleted file mode 100644 index b988fcf97f..0000000000 --- a/src/3rdparty/angle/src/libANGLE/renderer/ImplFactory.h +++ /dev/null @@ -1,74 +0,0 @@ -// -// 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" -#include "libANGLE/Program.h" -#include "libANGLE/Shader.h" -#include "libANGLE/VertexArray.h" - -namespace rx -{ -class BufferImpl; -class CompilerImpl; -class FenceNVImpl; -class FenceSyncImpl; -class FramebufferImpl; -class ProgramImpl; -class QueryImpl; -class RenderbufferImpl; -class SamplerImpl; -class ShaderImpl; -class TextureImpl; -class TransformFeedbackImpl; -class VertexArrayImpl; - -class ImplFactory : angle::NonCopyable -{ - public: - ImplFactory() {} - virtual ~ImplFactory() {} - - // Shader creation - virtual CompilerImpl *createCompiler() = 0; - virtual ShaderImpl *createShader(const gl::Shader::Data &data) = 0; - virtual ProgramImpl *createProgram(const gl::Program::Data &data) = 0; - - // Framebuffer creation - 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(const gl::VertexArray::Data &data) = 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; - - // Sampler object creation - virtual SamplerImpl *createSampler() = 0; -}; - -} - -#endif // LIBANGLE_RENDERER_IMPLFACTORY_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/PathImpl.h b/src/3rdparty/angle/src/libANGLE/renderer/PathImpl.h new file mode 100644 index 0000000000..3607f69a2b --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/PathImpl.h @@ -0,0 +1,36 @@ +// +// Copyright (c) 2002-2016 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. +// + +// PathImpl.h: Defines the Path implementation interface for +// CHROMIUM_path_rendering path objects. + +#ifndef LIBANGLE_RENDERER_PATHIMPL_H_ +#define LIBANGLE_RENDERER_PATHIMPL_H_ + +#include "angle_gl.h" +#include "common/angleutils.h" +#include "libANGLE/Error.h" + +namespace rx +{ + +class PathImpl : angle::NonCopyable +{ + public: + virtual ~PathImpl() {} + + virtual gl::Error setCommands(GLsizei numCommands, + const GLubyte *commands, + GLsizei numCoords, + GLenum coordType, + const void *coords) = 0; + + virtual void setPathParameter(GLenum pname, GLfloat value) = 0; +}; + +} // namespace rx + +#endif // LIBANGLE_RENDERER_PATHIMPL_H_ \ No newline at end of file diff --git a/src/3rdparty/angle/src/libANGLE/renderer/ProgramImpl.cpp b/src/3rdparty/angle/src/libANGLE/renderer/ProgramImpl.cpp deleted file mode 100644 index 8fbc53768f..0000000000 --- a/src/3rdparty/angle/src/libANGLE/renderer/ProgramImpl.cpp +++ /dev/null @@ -1,152 +0,0 @@ -// -// 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 index 1e688045a1..2371b2759c 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/ProgramImpl.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/ProgramImpl.h @@ -14,32 +14,39 @@ #include "libANGLE/Constants.h" #include "libANGLE/Program.h" #include "libANGLE/Shader.h" -#include "libANGLE/renderer/Renderer.h" #include -namespace rx +namespace gl { +class Context; +struct ProgramLinkedResources; +} -struct LinkResult +namespace sh { - LinkResult(bool linkSuccess, const gl::Error &error) : linkSuccess(linkSuccess), error(error) {} - - bool linkSuccess; - gl::Error error; -}; +struct BlockMemberInfo; +} +namespace rx +{ class ProgramImpl : angle::NonCopyable { public: - ProgramImpl(const gl::Program::Data &data) : mData(data) {} + ProgramImpl(const gl::ProgramState &state) : mState(state) {} virtual ~ProgramImpl() {} + virtual void destroy(const gl::Context *context) {} - virtual LinkResult load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream) = 0; - virtual gl::Error save(gl::BinaryOutputStream *stream) = 0; + virtual gl::LinkResult load(const gl::Context *context, + gl::InfoLog &infoLog, + gl::BinaryInputStream *stream) = 0; + virtual void save(const gl::Context *context, gl::BinaryOutputStream *stream) = 0; virtual void setBinaryRetrievableHint(bool retrievable) = 0; + virtual void setSeparable(bool separable) = 0; - virtual LinkResult link(const gl::Data &data, gl::InfoLog &infoLog) = 0; + virtual gl::LinkResult link(const gl::Context *context, + const gl::ProgramLinkedResources &resources, + gl::InfoLog &infoLog) = 0; virtual GLboolean validate(const gl::Caps &caps, gl::InfoLog *infoLog) = 0; virtual void setUniform1fv(GLint location, GLsizei count, const GLfloat *v) = 0; @@ -64,22 +71,37 @@ class ProgramImpl : angle::NonCopyable 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; + // Done in the back-end to avoid having to keep a system copy of uniform data. + virtual void getUniformfv(const gl::Context *context, + GLint location, + GLfloat *params) const = 0; + virtual void getUniformiv(const gl::Context *context, GLint location, GLint *params) const = 0; + virtual void getUniformuiv(const gl::Context *context, + GLint location, + GLuint *params) const = 0; + // TODO: synchronize in syncState when dirty bits exist. virtual void setUniformBlockBinding(GLuint uniformBlockIndex, GLuint uniformBlockBinding) = 0; - // May only be called after a successful link operation. - // Return false for inactive blocks. - virtual bool getUniformBlockSize(const std::string &blockName, size_t *sizeOut) const = 0; - - // May only be called after a successful link operation. - // Returns false for inactive members. - virtual bool getUniformBlockMemberInfo(const std::string &memberUniformName, - sh::BlockMemberInfo *memberInfoOut) const = 0; + // CHROMIUM_path_rendering + // Set parameters to control fragment shader input variable interpolation + virtual void setPathFragmentInputGen(const std::string &inputName, + GLenum genMode, + GLint components, + const GLfloat *coeffs) = 0; + + // Implementation-specific method for ignoring unreferenced uniforms. Some implementations may + // perform more extensive analysis and ignore some locations that ANGLE doesn't detect as + // unreferenced. This method is not required to be overriden by a back-end. + virtual void markUnusedUniformLocations(std::vector *uniformLocations, + std::vector *samplerBindings) + { + } protected: - const gl::Program::Data &mData; + const gl::ProgramState &mState; }; -} +} // namespace rx #endif // LIBANGLE_RENDERER_PROGRAMIMPL_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/ProgramImpl_mock.h b/src/3rdparty/angle/src/libANGLE/renderer/ProgramImpl_mock.h index d6aa238f64..4717ab8843 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/ProgramImpl_mock.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/ProgramImpl_mock.h @@ -12,6 +12,7 @@ #include "gmock/gmock.h" +#include "libANGLE/ProgramLinkedResources.h" #include "libANGLE/renderer/ProgramImpl.h" namespace rx @@ -20,14 +21,18 @@ namespace rx class MockProgramImpl : public rx::ProgramImpl { public: - MockProgramImpl() : ProgramImpl(gl::Program::Data()) {} - virtual ~MockProgramImpl() { destroy(); } + MockProgramImpl() : ProgramImpl(gl::ProgramState()) {} + virtual ~MockProgramImpl() { destructor(); } - MOCK_METHOD2(load, LinkResult(gl::InfoLog &, gl::BinaryInputStream *)); - MOCK_METHOD1(save, gl::Error(gl::BinaryOutputStream *)); + MOCK_METHOD3(load, gl::LinkResult(const gl::Context *, gl::InfoLog &, gl::BinaryInputStream *)); + MOCK_METHOD2(save, void(const gl::Context *, gl::BinaryOutputStream *)); MOCK_METHOD1(setBinaryRetrievableHint, void(bool)); + MOCK_METHOD1(setSeparable, void(bool)); - MOCK_METHOD2(link, LinkResult(const gl::Data &, gl::InfoLog &)); + MOCK_METHOD3(link, + gl::LinkResult(const gl::Context *, + const gl::ProgramLinkedResources &, + gl::InfoLog &)); MOCK_METHOD2(validate, GLboolean(const gl::Caps &, gl::InfoLog *)); MOCK_METHOD3(setUniform1fv, void(GLint, GLsizei, const GLfloat *)); @@ -53,11 +58,15 @@ class MockProgramImpl : public rx::ProgramImpl MOCK_METHOD4(setUniformMatrix3x4fv, void(GLint, GLsizei, GLboolean, const GLfloat *)); MOCK_METHOD4(setUniformMatrix4x3fv, void(GLint, GLsizei, GLboolean, const GLfloat *)); + MOCK_CONST_METHOD3(getUniformfv, void(const gl::Context *, GLint, GLfloat *)); + MOCK_CONST_METHOD3(getUniformiv, void(const gl::Context *, GLint, GLint *)); + MOCK_CONST_METHOD3(getUniformuiv, void(const gl::Context *, GLint, GLuint *)); + MOCK_METHOD2(setUniformBlockBinding, void(GLuint, GLuint)); - MOCK_CONST_METHOD2(getUniformBlockSize, bool(const std::string &, size_t *)); - MOCK_CONST_METHOD2(getUniformBlockMemberInfo, bool(const std::string &, sh::BlockMemberInfo *)); + MOCK_METHOD4(setPathFragmentInputGen, + void(const std::string &, GLenum, GLint, const GLfloat *)); - MOCK_METHOD0(destroy, void()); + MOCK_METHOD0(destructor, void()); }; inline ::testing::NiceMock *MakeProgramMock() @@ -65,7 +74,7 @@ inline ::testing::NiceMock *MakeProgramMock() ::testing::NiceMock *programImpl = new ::testing::NiceMock(); // TODO(jmadill): add ON_CALLS for returning methods // We must mock the destructor since NiceMock doesn't work for destructors. - EXPECT_CALL(*programImpl, destroy()).Times(1).RetiresOnSaturation(); + EXPECT_CALL(*programImpl, destructor()).Times(1).RetiresOnSaturation(); return programImpl; } diff --git a/src/3rdparty/angle/src/libANGLE/renderer/ProgramPipelineImpl.h b/src/3rdparty/angle/src/libANGLE/renderer/ProgramPipelineImpl.h new file mode 100644 index 0000000000..242e9260f1 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/ProgramPipelineImpl.h @@ -0,0 +1,32 @@ +// +// Copyright 2017 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. +// + +// ProgramPipelineImpl.h: Defines the abstract rx::ProgramPipelineImpl class. + +#ifndef LIBANGLE_RENDERER_PROGRAMPIPELINEIMPL_H_ +#define LIBANGLE_RENDERER_PROGRAMPIPELINEIMPL_H_ + +#include "common/angleutils.h" +#include "libANGLE/ProgramPipeline.h" + +namespace rx +{ +class ContextImpl; + +class ProgramPipelineImpl : public angle::NonCopyable +{ + public: + ProgramPipelineImpl(const gl::ProgramPipelineState &state) : mState(state) {} + virtual ~ProgramPipelineImpl() {} + virtual void destroy(const ContextImpl *contextImpl) {} + + protected: + const gl::ProgramPipelineState &mState; +}; + +} // namespace rx + +#endif // LIBANGLE_RENDERER_PROGRAMPIPELINEIMPL_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/RenderbufferImpl.cpp b/src/3rdparty/angle/src/libANGLE/renderer/RenderbufferImpl.cpp deleted file mode 100644 index ea5a40a21a..0000000000 --- a/src/3rdparty/angle/src/libANGLE/renderer/RenderbufferImpl.cpp +++ /dev/null @@ -1,21 +0,0 @@ -// -// 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 index 75b4cdcfee..a70ab1d0f0 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/RenderbufferImpl.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/RenderbufferImpl.h @@ -12,7 +12,7 @@ #include "angle_gl.h" #include "common/angleutils.h" #include "libANGLE/Error.h" -#include "libANGLE/FramebufferAttachment.h" +#include "libANGLE/renderer/FramebufferAttachmentObjectImpl.h" namespace egl { @@ -26,13 +26,25 @@ class RenderbufferImpl : public FramebufferAttachmentObjectImpl { public: RenderbufferImpl() {} - virtual ~RenderbufferImpl() {} - - 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; - virtual gl::Error setStorageEGLImageTarget(egl::Image *image) = 0; + ~RenderbufferImpl() override {} + virtual gl::Error onDestroy(const gl::Context *context); + + virtual gl::Error setStorage(const gl::Context *context, + GLenum internalformat, + size_t width, + size_t height) = 0; + virtual gl::Error setStorageMultisample(const gl::Context *context, + size_t samples, + GLenum internalformat, + size_t width, + size_t height) = 0; + virtual gl::Error setStorageEGLImageTarget(const gl::Context *context, egl::Image *image) = 0; }; +inline gl::Error RenderbufferImpl::onDestroy(const gl::Context *context) +{ + return gl::NoError(); +} } #endif // LIBANGLE_RENDERER_RENDERBUFFERIMPL_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/RenderbufferImpl_mock.h b/src/3rdparty/angle/src/libANGLE/renderer/RenderbufferImpl_mock.h index c2c67cc76a..408b9a5fe9 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/RenderbufferImpl_mock.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/RenderbufferImpl_mock.h @@ -21,11 +21,16 @@ class MockRenderbufferImpl : public RenderbufferImpl { public: virtual ~MockRenderbufferImpl() { destructor(); } - MOCK_METHOD3(setStorage, gl::Error(GLenum, size_t, size_t)); - MOCK_METHOD4(setStorageMultisample, gl::Error(size_t, GLenum, size_t, size_t)); - MOCK_METHOD1(setStorageEGLImageTarget, gl::Error(egl::Image *)); - - MOCK_METHOD2(getAttachmentRenderTarget, gl::Error(const gl::FramebufferAttachment::Target &, FramebufferAttachmentRenderTarget **)); + MOCK_METHOD4(setStorage, gl::Error(const gl::Context *, GLenum, size_t, size_t)); + MOCK_METHOD5(setStorageMultisample, + gl::Error(const gl::Context *, size_t, GLenum, size_t, size_t)); + MOCK_METHOD2(setStorageEGLImageTarget, gl::Error(const gl::Context *, egl::Image *)); + + MOCK_METHOD4(getAttachmentRenderTarget, + gl::Error(const gl::Context *, + GLenum, + const gl::ImageIndex &, + FramebufferAttachmentRenderTarget **)); MOCK_METHOD0(destructor, void()); }; diff --git a/src/3rdparty/angle/src/libANGLE/renderer/Renderer.cpp b/src/3rdparty/angle/src/libANGLE/renderer/Renderer.cpp deleted file mode 100644 index f3f7f55bb9..0000000000 --- a/src/3rdparty/angle/src/libANGLE/renderer/Renderer.cpp +++ /dev/null @@ -1,62 +0,0 @@ -// -// 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) -{ -} - -Renderer::~Renderer() -{ -} - -void Renderer::ensureCapsInitialized() const -{ - if (!mCapsInitialized) - { - generateCaps(&mCaps, &mTextureCaps, &mExtensions, &mLimitations); - mCapsInitialized = true; - } -} - -const gl::Caps &Renderer::getRendererCaps() const -{ - ensureCapsInitialized(); - - return mCaps; -} - -const gl::TextureCapsMap &Renderer::getRendererTextureCaps() const -{ - ensureCapsInitialized(); - - return mTextureCaps; -} - -const gl::Extensions &Renderer::getRendererExtensions() const -{ - ensureCapsInitialized(); - - return mExtensions; -} - -const gl::Limitations &Renderer::getRendererLimitations() const -{ - ensureCapsInitialized(); - - return mLimitations; -} - -} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/Renderer.h b/src/3rdparty/angle/src/libANGLE/renderer/Renderer.h deleted file mode 100644 index d0da2b140c..0000000000 --- a/src/3rdparty/angle/src/libANGLE/renderer/Renderer.h +++ /dev/null @@ -1,121 +0,0 @@ -// -// 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/State.h" -#include "libANGLE/Uniform.h" -#include "libANGLE/angletypes.h" -#include "libANGLE/renderer/ImplFactory.h" -#include "common/mathutil.h" - -#include - -#include - -namespace egl -{ -class AttributeMap; -class Display; -class Surface; -} - -namespace rx -{ -struct TranslatedIndexData; -struct SourceIndexData; -struct WorkaroundsD3D; -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) = 0; - virtual gl::Error drawArraysInstanced(const gl::Data &data, - GLenum mode, - GLint first, - GLsizei count, - GLsizei instanceCount) = 0; - - virtual gl::Error drawElements(const gl::Data &data, - GLenum mode, - GLsizei count, - GLenum type, - const GLvoid *indices, - const gl::IndexRange &indexRange) = 0; - virtual gl::Error drawElementsInstanced(const gl::Data &data, - GLenum mode, - GLsizei count, - GLenum type, - const GLvoid *indices, - GLsizei instances, - const gl::IndexRange &indexRange) = 0; - virtual gl::Error drawRangeElements(const gl::Data &data, - GLenum mode, - GLuint start, - GLuint end, - GLsizei count, - GLenum type, - const GLvoid *indices, - const gl::IndexRange &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 std::string getVendorString() const = 0; - virtual std::string getRendererDescription() const = 0; - - virtual void insertEventMarker(GLsizei length, const char *marker) = 0; - virtual void pushGroupMarker(GLsizei length, const char *marker) = 0; - virtual void popGroupMarker() = 0; - - virtual void syncState(const gl::State &state, const gl::State::DirtyBits &dirtyBits) = 0; - - // Disjoint timer queries - virtual GLint getGPUDisjoint() = 0; - virtual GLint64 getTimestamp() = 0; - - // Context switching - virtual void onMakeCurrent(const gl::Data &data) = 0; - - // Renderer capabilities - const gl::Caps &getRendererCaps() const; - const gl::TextureCapsMap &getRendererTextureCaps() const; - const gl::Extensions &getRendererExtensions() const; - const gl::Limitations &getRendererLimitations() const; - - private: - void ensureCapsInitialized() const; - virtual void generateCaps(gl::Caps *outCaps, gl::TextureCapsMap* outTextureCaps, - gl::Extensions *outExtensions, - gl::Limitations *outLimitations) const = 0; - - mutable bool mCapsInitialized; - mutable gl::Caps mCaps; - mutable gl::TextureCapsMap mTextureCaps; - mutable gl::Extensions mExtensions; - mutable gl::Limitations mLimitations; -}; - -} -#endif // LIBANGLE_RENDERER_RENDERER_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/SamplerImpl.h b/src/3rdparty/angle/src/libANGLE/renderer/SamplerImpl.h index 85383cf8e5..66e1079b64 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/SamplerImpl.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/SamplerImpl.h @@ -11,15 +11,29 @@ #include "common/angleutils.h" +namespace gl +{ +class Context; +struct SamplerState; +} // namespace gl + namespace rx { -class SamplerImpl : public angle::NonCopyable +class SamplerImpl : angle::NonCopyable { public: - SamplerImpl() {} + SamplerImpl(const gl::SamplerState &state) : mState(state) {} virtual ~SamplerImpl() {} + + virtual void syncState(const gl::Context *context) + { + // Default implementation: no-op. + } + + protected: + const gl::SamplerState &mState; }; -} +} // namespace rx #endif // LIBANGLE_RENDERER_SAMPLERIMPL_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/ShaderImpl.h b/src/3rdparty/angle/src/libANGLE/renderer/ShaderImpl.h index 5a466377a5..77e02d0237 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/ShaderImpl.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/ShaderImpl.h @@ -18,21 +18,21 @@ namespace rx class ShaderImpl : angle::NonCopyable { public: - ShaderImpl(const gl::Shader::Data &data) : mData(data) {} + ShaderImpl(const gl::ShaderState &data) : mData(data) {} virtual ~ShaderImpl() { } - // Returns additional ShCompile options. - virtual int prepareSourceAndReturnOptions(std::stringstream *sourceStream, - std::string *sourcePath) = 0; + // Returns additional sh::Compile options. + virtual ShCompileOptions prepareSourceAndReturnOptions(std::stringstream *sourceStream, + std::string *sourcePath) = 0; // Returns success for compiling on the driver. Returns success. virtual bool postTranslateCompile(gl::Compiler *compiler, std::string *infoLog) = 0; virtual std::string getDebugInfo() const = 0; - const gl::Shader::Data &getData() const { return mData; } + const gl::ShaderState &getData() const { return mData; } protected: - const gl::Shader::Data &mData; + const gl::ShaderState &mData; }; } diff --git a/src/3rdparty/angle/src/libANGLE/renderer/StreamProducerImpl.h b/src/3rdparty/angle/src/libANGLE/renderer/StreamProducerImpl.h new file mode 100644 index 0000000000..1915bf75d3 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/StreamProducerImpl.h @@ -0,0 +1,39 @@ +// +// Copyright (c) 2016 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. +// + +// StreamProducerImpl.h: Defines the abstract rx::StreamProducerImpl class. + +#ifndef LIBANGLE_RENDERER_STREAMPRODUCERIMPL_H_ +#define LIBANGLE_RENDERER_STREAMPRODUCERIMPL_H_ + +#include "common/angleutils.h" +#include "libANGLE/Stream.h" + +namespace rx +{ + +class StreamProducerImpl : angle::NonCopyable +{ + public: + explicit StreamProducerImpl() {} + virtual ~StreamProducerImpl() {} + + // Validates the ability for the producer to accept an arbitrary pointer to a frame. All + // pointers should be validated through this function before being used to produce a frame. + virtual egl::Error validateD3DNV12Texture(void *pointer) const = 0; + + // Constructs a frame from an arbitrary external pointer that points to producer specific frame + // data. Replaces the internal frame with the new one. + virtual void postD3DNV12Texture(void *pointer, const egl::AttributeMap &attributes) = 0; + + // Returns an OpenGL texture interpretation of some frame attributes for the purpose of + // constructing an OpenGL texture from a frame. Depending on the producer and consumer, some + // frames may have multiple "planes" with different OpenGL texture representations. + virtual egl::Stream::GLTextureDescription getGLFrameDescription(int planeIndex) = 0; +}; +} // namespace rx + +#endif // LIBANGLE_RENDERER_STREAMPRODUCERIMPL_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/SurfaceImpl.cpp b/src/3rdparty/angle/src/libANGLE/renderer/SurfaceImpl.cpp index 36f5fdca3f..cd2fa3dde6 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/SurfaceImpl.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/SurfaceImpl.cpp @@ -11,7 +11,7 @@ namespace rx { -SurfaceImpl::SurfaceImpl() +SurfaceImpl::SurfaceImpl(const egl::SurfaceState &state) : mState(state) { } @@ -19,4 +19,10 @@ SurfaceImpl::~SurfaceImpl() { } +egl::Error SurfaceImpl::swapWithDamage(const gl::Context *context, EGLint *rects, EGLint n_rects) +{ + UNREACHABLE(); + return egl::EglBadSurface() << "swapWithDamage implementation missing."; } + +} // namespace rx diff --git a/src/3rdparty/angle/src/libANGLE/renderer/SurfaceImpl.h b/src/3rdparty/angle/src/libANGLE/renderer/SurfaceImpl.h index 32125d542c..eaa27de281 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/SurfaceImpl.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/SurfaceImpl.h @@ -9,35 +9,51 @@ #ifndef LIBANGLE_RENDERER_SURFACEIMPL_H_ #define LIBANGLE_RENDERER_SURFACEIMPL_H_ +#include +#include + #include "common/angleutils.h" #include "libANGLE/Error.h" -#include "libANGLE/Framebuffer.h" #include "libANGLE/FramebufferAttachment.h" +#include "libANGLE/renderer/FramebufferAttachmentObjectImpl.h" + +namespace gl +{ +class FramebufferState; +} namespace egl { class Display; struct Config; +struct SurfaceState; +class Thread; } namespace rx { - class FramebufferImpl; class SurfaceImpl : public FramebufferAttachmentObjectImpl { public: - SurfaceImpl(); - virtual ~SurfaceImpl(); + SurfaceImpl(const egl::SurfaceState &surfaceState); + ~SurfaceImpl() override; + virtual void destroy(const egl::Display *display) {} - virtual egl::Error initialize() = 0; - virtual FramebufferImpl *createDefaultFramebuffer(const gl::Framebuffer::Data &data) = 0; - virtual egl::Error swap() = 0; - virtual egl::Error postSubBuffer(EGLint x, EGLint y, EGLint width, EGLint height) = 0; + virtual egl::Error initialize(const egl::Display *display) = 0; + virtual FramebufferImpl *createDefaultFramebuffer(const gl::FramebufferState &state) = 0; + virtual egl::Error swap(const gl::Context *context) = 0; + virtual egl::Error swapWithDamage(const gl::Context *context, EGLint *rects, EGLint n_rects); + virtual egl::Error postSubBuffer(const gl::Context *context, + EGLint x, + EGLint y, + EGLint width, + EGLint height) = 0; virtual egl::Error querySurfacePointerANGLE(EGLint attribute, void **value) = 0; virtual egl::Error bindTexImage(gl::Texture *texture, EGLint buffer) = 0; virtual egl::Error releaseTexImage(EGLint buffer) = 0; + virtual egl::Error getSyncValues(EGLuint64KHR *ust, EGLuint64KHR *msc, EGLuint64KHR *sbc) = 0; virtual void setSwapInterval(EGLint interval) = 0; // width and height can change with client window resizing @@ -46,6 +62,9 @@ class SurfaceImpl : public FramebufferAttachmentObjectImpl virtual EGLint isPostSubBufferSupported() const = 0; virtual EGLint getSwapBehavior() const = 0; + + protected: + const egl::SurfaceState &mState; }; } diff --git a/src/3rdparty/angle/src/libANGLE/renderer/SyncImpl.h b/src/3rdparty/angle/src/libANGLE/renderer/SyncImpl.h new file mode 100644 index 0000000000..22c92c3729 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/SyncImpl.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. +// + +// SyncImpl.h: Defines the rx::SyncImpl 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 SyncImpl : angle::NonCopyable +{ + public: + SyncImpl(){}; + virtual ~SyncImpl(){}; + + virtual gl::Error set(GLenum condition, GLbitfield flags) = 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/TextureImpl.cpp b/src/3rdparty/angle/src/libANGLE/renderer/TextureImpl.cpp new file mode 100644 index 0000000000..830d30e6d1 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/TextureImpl.cpp @@ -0,0 +1,63 @@ +// +// Copyright 2016 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.cpp: Defines the abstract rx::TextureImpl classes. + +#include "libANGLE/renderer/TextureImpl.h" + +namespace rx +{ + +TextureImpl::TextureImpl(const gl::TextureState &state) : mState(state) +{ +} + +TextureImpl::~TextureImpl() +{ +} + +gl::Error TextureImpl::onDestroy(const gl::Context *context) +{ + return gl::NoError(); +} + +gl::Error TextureImpl::copyTexture(const gl::Context *context, + GLenum target, + size_t level, + GLenum internalFormat, + GLenum type, + size_t sourceLevel, + bool unpackFlipY, + bool unpackPremultiplyAlpha, + bool unpackUnmultiplyAlpha, + const gl::Texture *source) +{ + UNREACHABLE(); + return gl::InternalError() << "CHROMIUM_copy_texture exposed but not implemented."; +} + +gl::Error TextureImpl::copySubTexture(const gl::Context *context, + GLenum target, + size_t level, + const gl::Offset &destOffset, + size_t sourceLevel, + const gl::Rectangle &sourceArea, + bool unpackFlipY, + bool unpackPremultiplyAlpha, + bool unpackUnmultiplyAlpha, + const gl::Texture *source) +{ + UNREACHABLE(); + return gl::InternalError() << "CHROMIUM_copy_texture exposed but not implemented."; +} + +gl::Error TextureImpl::copyCompressedTexture(const gl::Context *context, const gl::Texture *source) +{ + UNREACHABLE(); + return gl::InternalError() << "CHROMIUM_copy_compressed_texture exposed but not implemented."; +} + +} // namespace rx diff --git a/src/3rdparty/angle/src/libANGLE/renderer/TextureImpl.h b/src/3rdparty/angle/src/libANGLE/renderer/TextureImpl.h index ad4ec8d830..3b4f28f5f7 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/TextureImpl.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/TextureImpl.h @@ -14,8 +14,10 @@ #include "angle_gl.h" #include "common/angleutils.h" #include "libANGLE/Error.h" -#include "libANGLE/FramebufferAttachment.h" #include "libANGLE/ImageIndex.h" +#include "libANGLE/Stream.h" +#include "libANGLE/Texture.h" +#include "libANGLE/renderer/FramebufferAttachmentObjectImpl.h" namespace egl { @@ -36,38 +38,120 @@ struct TextureState; namespace rx { +class ContextImpl; class TextureImpl : public FramebufferAttachmentObjectImpl { public: - TextureImpl() {} - 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, size_t imageSize, const uint8_t *pixels) = 0; - virtual gl::Error setCompressedSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format, - const gl::PixelUnpackState &unpack, size_t imageSize, const uint8_t *pixels) = 0; - - virtual gl::Error copyImage(GLenum target, size_t level, const gl::Rectangle &sourceArea, GLenum internalFormat, + TextureImpl(const gl::TextureState &state); + ~TextureImpl() override; + + virtual gl::Error onDestroy(const gl::Context *context); + + virtual gl::Error setImage(const gl::Context *context, + 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(const gl::Context *context, + 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(const gl::Context *context, + GLenum target, + size_t level, + GLenum internalFormat, + const gl::Extents &size, + const gl::PixelUnpackState &unpack, + size_t imageSize, + const uint8_t *pixels) = 0; + virtual gl::Error setCompressedSubImage(const gl::Context *context, + GLenum target, + size_t level, + const gl::Box &area, + GLenum format, + const gl::PixelUnpackState &unpack, + size_t imageSize, + const uint8_t *pixels) = 0; + + virtual gl::Error copyImage(const gl::Context *context, + 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, + virtual gl::Error copySubImage(const gl::Context *context, + 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 setEGLImageTarget(GLenum target, egl::Image *image) = 0; - - virtual gl::Error generateMipmaps(const gl::TextureState &textureState) = 0; - - virtual void bindTexImage(egl::Surface *surface) = 0; - virtual void releaseTexImage() = 0; + virtual gl::Error copyTexture(const gl::Context *context, + GLenum target, + size_t level, + GLenum internalFormat, + GLenum type, + size_t sourceLevel, + bool unpackFlipY, + bool unpackPremultiplyAlpha, + bool unpackUnmultiplyAlpha, + const gl::Texture *source); + virtual gl::Error copySubTexture(const gl::Context *context, + GLenum target, + size_t level, + const gl::Offset &destOffset, + size_t sourceLevel, + const gl::Rectangle &sourceArea, + bool unpackFlipY, + bool unpackPremultiplyAlpha, + bool unpackUnmultiplyAlpha, + const gl::Texture *source); + + virtual gl::Error copyCompressedTexture(const gl::Context *context, const gl::Texture *source); + + virtual gl::Error setStorage(const gl::Context *context, + GLenum target, + size_t levels, + GLenum internalFormat, + const gl::Extents &size) = 0; + + virtual gl::Error setStorageMultisample(const gl::Context *context, + GLenum target, + GLsizei samples, + GLint internalformat, + const gl::Extents &size, + bool fixedSampleLocations) = 0; + + virtual gl::Error setEGLImageTarget(const gl::Context *context, + GLenum target, + egl::Image *image) = 0; + + virtual gl::Error setImageExternal(const gl::Context *context, + GLenum target, + egl::Stream *stream, + const egl::Stream::GLTextureDescription &desc) = 0; + + virtual gl::Error generateMipmap(const gl::Context *context) = 0; + + virtual gl::Error setBaseLevel(const gl::Context *context, GLuint baseLevel) = 0; + + virtual gl::Error bindTexImage(const gl::Context *context, egl::Surface *surface) = 0; + virtual gl::Error releaseTexImage(const gl::Context *context) = 0; + + virtual void syncState(const gl::Texture::DirtyBits &dirtyBits) = 0; + + protected: + const gl::TextureState &mState; }; } diff --git a/src/3rdparty/angle/src/libANGLE/renderer/TextureImpl_mock.h b/src/3rdparty/angle/src/libANGLE/renderer/TextureImpl_mock.h index 3eb43f0033..e7fa441781 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/TextureImpl_mock.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/TextureImpl_mock.h @@ -19,23 +19,111 @@ namespace rx class MockTextureImpl : public TextureImpl { public: + MockTextureImpl() : TextureImpl(mMockState), mMockState(GL_TEXTURE_2D) {} virtual ~MockTextureImpl() { destructor(); } - MOCK_METHOD1(setUsage, void(GLenum)); - MOCK_METHOD8(setImage, gl::Error(GLenum, size_t, GLenum, const gl::Extents &, GLenum, GLenum, const gl::PixelUnpackState &, const uint8_t *)); - MOCK_METHOD7(setSubImage, gl::Error(GLenum, size_t, const gl::Box &, GLenum, GLenum, const gl::PixelUnpackState &, const uint8_t *)); - MOCK_METHOD7(setCompressedImage, gl::Error(GLenum, size_t, GLenum, const gl::Extents &, const gl::PixelUnpackState &, size_t, const uint8_t *)); - MOCK_METHOD7(setCompressedSubImage, gl::Error(GLenum, size_t, const gl::Box &, GLenum, const gl::PixelUnpackState &, size_t, const uint8_t *)); - MOCK_METHOD5(copyImage, gl::Error(GLenum, size_t, const gl::Rectangle &, GLenum, const gl::Framebuffer *)); - MOCK_METHOD5(copySubImage, gl::Error(GLenum, size_t, const gl::Offset &, const gl::Rectangle &, const gl::Framebuffer *)); - MOCK_METHOD4(setStorage, gl::Error(GLenum, size_t, GLenum, const gl::Extents &)); - MOCK_METHOD2(setEGLImageTarget, gl::Error(GLenum, egl::Image *)); - MOCK_METHOD1(generateMipmaps, gl::Error(const gl::TextureState &)); - MOCK_METHOD1(bindTexImage, void(egl::Surface *)); - MOCK_METHOD0(releaseTexImage, void(void)); - - MOCK_METHOD2(getAttachmentRenderTarget, gl::Error(const gl::FramebufferAttachment::Target &, FramebufferAttachmentRenderTarget **)); + MOCK_METHOD9(setImage, + gl::Error(const gl::Context *, + GLenum, + size_t, + GLenum, + const gl::Extents &, + GLenum, + GLenum, + const gl::PixelUnpackState &, + const uint8_t *)); + MOCK_METHOD8(setSubImage, + gl::Error(const gl::Context *, + GLenum, + size_t, + const gl::Box &, + GLenum, + GLenum, + const gl::PixelUnpackState &, + const uint8_t *)); + MOCK_METHOD8(setCompressedImage, + gl::Error(const gl::Context *, + GLenum, + size_t, + GLenum, + const gl::Extents &, + const gl::PixelUnpackState &, + size_t, + const uint8_t *)); + MOCK_METHOD8(setCompressedSubImage, + gl::Error(const gl::Context *, + GLenum, + size_t, + const gl::Box &, + GLenum, + const gl::PixelUnpackState &, + size_t, + const uint8_t *)); + MOCK_METHOD6(copyImage, + gl::Error(const gl::Context *, + GLenum, + size_t, + const gl::Rectangle &, + GLenum, + const gl::Framebuffer *)); + MOCK_METHOD6(copySubImage, + gl::Error(const gl::Context *, + GLenum, + size_t, + const gl::Offset &, + const gl::Rectangle &, + const gl::Framebuffer *)); + MOCK_METHOD10(copyTexture, + gl::Error(const gl::Context *, + GLenum, + size_t, + GLenum, + GLenum, + size_t, + bool, + bool, + bool, + const gl::Texture *)); + MOCK_METHOD10(copySubTexture, + gl::Error(const gl::Context *, + GLenum, + size_t, + const gl::Offset &, + size_t, + const gl::Rectangle &, + bool, + bool, + bool, + const gl::Texture *)); + MOCK_METHOD2(copyCompressedTexture, gl::Error(const gl::Context *, const gl::Texture *source)); + MOCK_METHOD5(setStorage, + gl::Error(const gl::Context *, GLenum, size_t, GLenum, const gl::Extents &)); + MOCK_METHOD4(setImageExternal, + gl::Error(const gl::Context *, + GLenum, + egl::Stream *, + const egl::Stream::GLTextureDescription &)); + MOCK_METHOD3(setEGLImageTarget, gl::Error(const gl::Context *, GLenum, egl::Image *)); + MOCK_METHOD1(generateMipmap, gl::Error(const gl::Context *)); + MOCK_METHOD2(bindTexImage, gl::Error(const gl::Context *, egl::Surface *)); + MOCK_METHOD1(releaseTexImage, gl::Error(const gl::Context *)); + + MOCK_METHOD4(getAttachmentRenderTarget, + gl::Error(const gl::Context *, + GLenum, + const gl::ImageIndex &, + FramebufferAttachmentRenderTarget **)); + + MOCK_METHOD6(setStorageMultisample, + gl::Error(const gl::Context *, GLenum, GLsizei, GLint, const gl::Extents &, bool)); + + MOCK_METHOD2(setBaseLevel, gl::Error(const gl::Context *, GLuint)); + + MOCK_METHOD1(syncState, void(const gl::Texture::DirtyBits &)); MOCK_METHOD0(destructor, void()); + + protected: + gl::TextureState mMockState; }; } diff --git a/src/3rdparty/angle/src/libANGLE/renderer/TransformFeedbackImpl.h b/src/3rdparty/angle/src/libANGLE/renderer/TransformFeedbackImpl.h index 5df7cad87b..ad371e9b36 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/TransformFeedbackImpl.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/TransformFeedbackImpl.h @@ -18,6 +18,7 @@ namespace rx class TransformFeedbackImpl : angle::NonCopyable { public: + TransformFeedbackImpl(const gl::TransformFeedbackState &state) : mState(state) {} virtual ~TransformFeedbackImpl() { } virtual void begin(GLenum primitiveMode) = 0; @@ -25,8 +26,12 @@ class TransformFeedbackImpl : angle::NonCopyable virtual void pause() = 0; virtual void resume() = 0; - virtual void bindGenericBuffer(const BindingPointer &binding) = 0; - virtual void bindIndexedBuffer(size_t index, const OffsetBindingPointer &binding) = 0; + virtual void bindGenericBuffer(const gl::BindingPointer &binding) = 0; + virtual void bindIndexedBuffer(size_t index, + const gl::OffsetBindingPointer &binding) = 0; + + protected: + const gl::TransformFeedbackState &mState; }; } diff --git a/src/3rdparty/angle/src/libANGLE/renderer/TransformFeedbackImpl_mock.h b/src/3rdparty/angle/src/libANGLE/renderer/TransformFeedbackImpl_mock.h index c7d2fc620d..2de3ad79a9 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/TransformFeedbackImpl_mock.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/TransformFeedbackImpl_mock.h @@ -19,6 +19,10 @@ namespace rx class MockTransformFeedbackImpl : public TransformFeedbackImpl { public: + MockTransformFeedbackImpl(const gl::TransformFeedbackState &state) + : TransformFeedbackImpl(state) + { + } ~MockTransformFeedbackImpl() { destructor(); } MOCK_METHOD1(begin, void(GLenum primitiveMode)); @@ -26,8 +30,8 @@ class MockTransformFeedbackImpl : public TransformFeedbackImpl MOCK_METHOD0(pause, void()); MOCK_METHOD0(resume, void()); - MOCK_METHOD1(bindGenericBuffer, void(const BindingPointer &)); - MOCK_METHOD2(bindIndexedBuffer, void(size_t, const OffsetBindingPointer &)); + MOCK_METHOD1(bindGenericBuffer, void(const gl::BindingPointer &)); + MOCK_METHOD2(bindIndexedBuffer, void(size_t, const gl::OffsetBindingPointer &)); MOCK_METHOD0(destructor, void()); }; diff --git a/src/3rdparty/angle/src/libANGLE/renderer/VertexArrayImpl.h b/src/3rdparty/angle/src/libANGLE/renderer/VertexArrayImpl.h index 13617c7ecb..e48cc53d6c 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/VertexArrayImpl.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/VertexArrayImpl.h @@ -15,15 +15,21 @@ namespace rx { +class ContextImpl; class VertexArrayImpl : angle::NonCopyable { public: - VertexArrayImpl(const gl::VertexArray::Data &data) : mData(data) { } - virtual ~VertexArrayImpl() { } - virtual void syncState(const gl::VertexArray::DirtyBits &dirtyBits) {} + VertexArrayImpl(const gl::VertexArrayState &state) : mState(state) {} + virtual void syncState(const gl::Context *context, const gl::VertexArray::DirtyBits &dirtyBits) + { + } + + virtual void destroy(const gl::Context *context) {} + virtual ~VertexArrayImpl() {} + protected: - const gl::VertexArray::Data &mData; + const gl::VertexArrayState &mState; }; } diff --git a/src/3rdparty/angle/src/libANGLE/renderer/Workarounds.h b/src/3rdparty/angle/src/libANGLE/renderer/Workarounds.h deleted file mode 100644 index b73f4a5472..0000000000 --- a/src/3rdparty/angle/src/libANGLE/renderer/Workarounds.h +++ /dev/null @@ -1,74 +0,0 @@ -// -// 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/angle_format_data.json b/src/3rdparty/angle/src/libANGLE/renderer/angle_format_data.json new file mode 100644 index 0000000000..5b3a226e2e --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/angle_format_data.json @@ -0,0 +1,24 @@ +{ + "B5G6R5_UNORM": { + "fboImplementationInternalFormat": "GL_RGB565" + }, + "B5G5R5A1_UNORM": { + "fboImplementationInternalFormat": "GL_RGB5_A1", + "channelStruct": "A1R5G5B5" + }, + "B8G8R8X8_UNORM": { + "glInternalFormat": "GL_BGRA8_EXT", + "channelStruct": "B8G8R8X8" + }, + "R9G9B9E5_SHAREDEXP": { + "componentType": "float", + "channelStruct": "R9G9B9E5" + }, + "B4G4R4A4_UNORM": { + "fboImplementationInternalFormat": "GL_RGBA4", + "channelStruct": "A4R4G4B4" + }, + "R8G8B8A8_UNORM_SRGB": { + "channelStruct": "R8G8B8A8SRGB" + } +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/angle_format_map.json b/src/3rdparty/angle/src/libANGLE/renderer/angle_format_map.json new file mode 100644 index 0000000000..5a4e487cbd --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/angle_format_map.json @@ -0,0 +1,132 @@ +[ + [ "GL_ALPHA16F_EXT", "A16_FLOAT" ], + [ "GL_ALPHA32F_EXT", "A32_FLOAT" ], + [ "GL_ALPHA8_EXT", "A8_UNORM" ], + [ "GL_BGR565_ANGLEX", "B5G6R5_UNORM" ], + [ "GL_BGR5_A1_ANGLEX", "B5G5R5A1_UNORM" ], + [ "GL_BGRA4_ANGLEX", "B4G4R4A4_UNORM" ], + [ "GL_BGRA8_EXT", "B8G8R8A8_UNORM" ], + [ "GL_BGRA8_SRGB_ANGLEX", "B8G8R8A8_UNORM_SRGB"], + [ "GL_BGRX8_ANGLEX", "B8G8R8X8_UNORM" ], + [ "GL_COMPRESSED_R11_EAC", "EAC_R11_UNORM_BLOCK" ], + [ "GL_COMPRESSED_RG11_EAC", "EAC_R11G11_UNORM_BLOCK" ], + [ "GL_COMPRESSED_RGB8_ETC2", "ETC2_R8G8B8_UNORM_BLOCK" ], + [ "GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2", "ETC2_R8G8B8A1_UNORM_BLOCK" ], + [ "GL_COMPRESSED_RGBA8_ETC2_EAC", "ETC2_R8G8B8A8_UNORM_BLOCK" ], + [ "GL_COMPRESSED_RGBA_S3TC_DXT1_EXT", "BC1_RGBA_UNORM_BLOCK" ], + [ "GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE", "BC2_RGBA_UNORM_BLOCK" ], + [ "GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE", "BC3_RGBA_UNORM_BLOCK" ], + [ "GL_COMPRESSED_RGBA_ASTC_4x4_KHR", "ASTC_4x4_UNORM_BLOCK" ], + [ "GL_COMPRESSED_RGBA_ASTC_5x4_KHR", "ASTC_5x4_UNORM_BLOCK" ], + [ "GL_COMPRESSED_RGBA_ASTC_5x5_KHR", "ASTC_5x5_UNORM_BLOCK" ], + [ "GL_COMPRESSED_RGBA_ASTC_6x5_KHR", "ASTC_6x5_UNORM_BLOCK" ], + [ "GL_COMPRESSED_RGBA_ASTC_6x6_KHR", "ASTC_6x6_UNORM_BLOCK" ], + [ "GL_COMPRESSED_RGBA_ASTC_8x5_KHR", "ASTC_8x5_UNORM_BLOCK" ], + [ "GL_COMPRESSED_RGBA_ASTC_8x6_KHR", "ASTC_8x6_UNORM_BLOCK" ], + [ "GL_COMPRESSED_RGBA_ASTC_8x8_KHR", "ASTC_8x8_UNORM_BLOCK" ], + [ "GL_COMPRESSED_RGBA_ASTC_10x5_KHR", "ASTC_10x5_UNORM_BLOCK" ], + [ "GL_COMPRESSED_RGBA_ASTC_10x6_KHR", "ASTC_10x6_UNORM_BLOCK" ], + [ "GL_COMPRESSED_RGBA_ASTC_10x8_KHR", "ASTC_10x8_UNORM_BLOCK" ], + [ "GL_COMPRESSED_RGBA_ASTC_10x10_KHR", "ASTC_10x10_UNORM_BLOCK" ], + [ "GL_COMPRESSED_RGBA_ASTC_12x10_KHR", "ASTC_12x10_UNORM_BLOCK" ], + [ "GL_COMPRESSED_RGBA_ASTC_12x12_KHR", "ASTC_12x12_UNORM_BLOCK" ], + [ "GL_COMPRESSED_RGB_S3TC_DXT1_EXT", "BC1_RGB_UNORM_BLOCK" ], + [ "GL_COMPRESSED_SIGNED_R11_EAC", "EAC_R11_SNORM_BLOCK" ], + [ "GL_COMPRESSED_SIGNED_RG11_EAC", "EAC_R11G11_SNORM_BLOCK" ], + [ "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR", "ASTC_4x4_SRGB_BLOCK" ], + [ "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR", "ASTC_5x4_SRGB_BLOCK" ], + [ "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR", "ASTC_5x5_SRGB_BLOCK" ], + [ "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR", "ASTC_6x5_SRGB_BLOCK" ], + [ "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR", "ASTC_6x6_SRGB_BLOCK" ], + [ "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR", "ASTC_8x5_SRGB_BLOCK" ], + [ "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR", "ASTC_8x6_SRGB_BLOCK" ], + [ "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR", "ASTC_8x8_SRGB_BLOCK" ], + [ "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR", "ASTC_10x5_SRGB_BLOCK" ], + [ "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR", "ASTC_10x6_SRGB_BLOCK" ], + [ "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR", "ASTC_10x8_SRGB_BLOCK" ], + [ "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR", "ASTC_10x10_SRGB_BLOCK" ], + [ "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR", "ASTC_12x10_SRGB_BLOCK" ], + [ "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR", "ASTC_12x12_SRGB_BLOCK" ], + [ "GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC", "ETC2_R8G8B8A8_SRGB_BLOCK" ], + [ "GL_COMPRESSED_SRGB8_ETC2", "ETC2_R8G8B8_SRGB_BLOCK" ], + [ "GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2", "ETC2_R8G8B8A1_SRGB_BLOCK" ], + [ "GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT", "BC1_RGBA_UNORM_SRGB_BLOCK" ], + [ "GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT", "BC2_RGBA_UNORM_SRGB_BLOCK" ], + [ "GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT", "BC3_RGBA_UNORM_SRGB_BLOCK" ], + [ "GL_COMPRESSED_SRGB_S3TC_DXT1_EXT", "BC1_RGB_UNORM_SRGB_BLOCK" ], + [ "GL_DEPTH24_STENCIL8", "D24_UNORM_S8_UINT" ], + [ "GL_DEPTH32F_STENCIL8", "D32_FLOAT_S8X24_UINT" ], + [ "GL_DEPTH_COMPONENT16", "D16_UNORM" ], + [ "GL_DEPTH_COMPONENT24", "D24_UNORM" ], + [ "GL_DEPTH_COMPONENT32F", "D32_FLOAT" ], + [ "GL_DEPTH_COMPONENT32_OES", "D32_UNORM" ], + [ "GL_ETC1_RGB8_OES", "ETC1_R8G8B8_UNORM_BLOCK" ], + [ "GL_ETC1_RGB8_LOSSY_DECODE_ANGLE", "ETC1_LOSSY_DECODE_R8G8B8_UNORM_BLOCK" ], + [ "GL_LUMINANCE16F_EXT", "L16_FLOAT" ], + [ "GL_LUMINANCE32F_EXT", "L32_FLOAT" ], + [ "GL_LUMINANCE8_ALPHA8_EXT", "L8A8_UNORM" ], + [ "GL_LUMINANCE8_EXT", "L8_UNORM" ], + [ "GL_LUMINANCE_ALPHA16F_EXT", "L16A16_FLOAT" ], + [ "GL_LUMINANCE_ALPHA32F_EXT", "L32A32_FLOAT" ], + [ "GL_NONE", "NONE" ], + [ "GL_R11F_G11F_B10F", "R11G11B10_FLOAT" ], + [ "GL_R16F", "R16_FLOAT" ], + [ "GL_R16I", "R16_SINT" ], + [ "GL_R16UI", "R16_UINT" ], + [ "GL_R32F", "R32_FLOAT" ], + [ "GL_R32I", "R32_SINT" ], + [ "GL_R32UI", "R32_UINT" ], + [ "GL_R8", "R8_UNORM" ], + [ "GL_R8I", "R8_SINT" ], + [ "GL_R8UI", "R8_UINT" ], + [ "GL_R8_SNORM", "R8_SNORM" ], + [ "GL_RG16F", "R16G16_FLOAT" ], + [ "GL_RG16I", "R16G16_SINT" ], + [ "GL_RG16UI", "R16G16_UINT" ], + [ "GL_RG32F", "R32G32_FLOAT" ], + [ "GL_RG32I", "R32G32_SINT" ], + [ "GL_RG32UI", "R32G32_UINT" ], + [ "GL_RG8", "R8G8_UNORM" ], + [ "GL_RG8I", "R8G8_SINT" ], + [ "GL_RG8UI", "R8G8_UINT" ], + [ "GL_RG8_SNORM", "R8G8_SNORM" ], + [ "GL_RGB", "R8G8B8_UNORM" ], + [ "GL_RGB10_A2", "R10G10B10A2_UNORM" ], + [ "GL_RGB10_A2UI", "R10G10B10A2_UINT" ], + [ "GL_RGB16F", "R16G16B16_FLOAT" ], + [ "GL_RGB16I", "R16G16B16_SINT" ], + [ "GL_RGB16UI", "R16G16B16_UINT" ], + [ "GL_RGB32F", "R32G32B32_FLOAT" ], + [ "GL_RGB32I", "R32G32B32_SINT" ], + [ "GL_RGB32UI", "R32G32B32_UINT" ], + [ "GL_RGB565", "R5G6B5_UNORM" ], + [ "GL_RGB5_A1", "R5G5B5A1_UNORM" ], + [ "GL_RGB8", "R8G8B8_UNORM" ], + [ "GL_RGB8I", "R8G8B8_SINT" ], + [ "GL_RGB8UI", "R8G8B8_UINT" ], + [ "GL_RGB8_SNORM", "R8G8B8_SNORM" ], + [ "GL_RGB9_E5", "R9G9B9E5_SHAREDEXP" ], + [ "GL_RGBA", "R8G8B8A8_UNORM" ], + [ "GL_RGBA16F", "R16G16B16A16_FLOAT" ], + [ "GL_RGBA16I", "R16G16B16A16_SINT" ], + [ "GL_RGBA16UI", "R16G16B16A16_UINT" ], + [ "GL_RGBA32F", "R32G32B32A32_FLOAT" ], + [ "GL_RGBA32I", "R32G32B32A32_SINT" ], + [ "GL_RGBA32UI", "R32G32B32A32_UINT" ], + [ "GL_RGBA4", "R4G4B4A4_UNORM" ], + [ "GL_RGBA8", "R8G8B8A8_UNORM" ], + [ "GL_RGBA8I", "R8G8B8A8_SINT" ], + [ "GL_RGBA8UI", "R8G8B8A8_UINT" ], + [ "GL_RGBA8_SNORM", "R8G8B8A8_SNORM" ], + [ "GL_SRGB8", "R8G8B8_UNORM_SRGB" ], + [ "GL_SRGB8_ALPHA8", "R8G8B8A8_UNORM_SRGB" ], + [ "GL_STENCIL_INDEX8", "S8_UINT" ], + [ "GL_R16_EXT", "R16_UNORM" ], + [ "GL_RG16_EXT", "R16G16_UNORM" ], + [ "GL_RGB16_EXT", "R16G16B16_UNORM" ], + [ "GL_RGBA16_EXT", "R16G16B16A16_UNORM" ], + [ "GL_R16_SNORM_EXT", "R16_SNORM" ], + [ "GL_RG16_SNORM_EXT", "R16G16_SNORM" ], + [ "GL_RGB16_SNORM_EXT", "R16G16B16_SNORM" ], + [ "GL_RGBA16_SNORM_EXT", "R16G16B16A16_SNORM" ] +] diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/BufferD3D.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/BufferD3D.cpp index ffca99c3ac..7769ab2b75 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/BufferD3D.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/BufferD3D.cpp @@ -12,42 +12,33 @@ #include "common/utilities.h" #include "libANGLE/renderer/d3d/IndexBuffer.h" #include "libANGLE/renderer/d3d/VertexBuffer.h" +#include "libANGLE/renderer/d3d/RendererD3D.h" namespace rx { unsigned int BufferD3D::mNextSerial = 1; -BufferD3D::BufferD3D(BufferFactoryD3D *factory) - : BufferImpl(), +BufferD3D::BufferD3D(const gl::BufferState &state, BufferFactoryD3D *factory) + : BufferImpl(state), mFactory(factory), - mStaticVertexBuffer(nullptr), mStaticIndexBuffer(nullptr), - mStaticBufferCache(nullptr), mStaticBufferCacheTotalSize(0), mStaticVertexBufferOutOfDate(false), mUnmodifiedDataUse(0), - mUsage(D3D_BUFFER_USAGE_STATIC) + mUsage(D3DBufferUsage::STATIC) { updateSerial(); } BufferD3D::~BufferD3D() { - SafeDelete(mStaticVertexBuffer); SafeDelete(mStaticIndexBuffer); - - emptyStaticBufferCache(); } void BufferD3D::emptyStaticBufferCache() { - if (mStaticBufferCache != nullptr) - { - SafeDeleteContainer(*mStaticBufferCache); - SafeDelete(mStaticBufferCache); - } - + mStaticVertexBuffers.clear(); mStaticBufferCacheTotalSize = 0; } @@ -56,35 +47,37 @@ void BufferD3D::updateSerial() mSerial = mNextSerial++; } -void BufferD3D::updateD3DBufferUsage(GLenum usage) +void BufferD3D::updateD3DBufferUsage(const gl::Context *context, gl::BufferUsage usage) { switch (usage) { - case GL_STATIC_DRAW: - case GL_STATIC_READ: - case GL_STATIC_COPY: - mUsage = D3D_BUFFER_USAGE_STATIC; - initializeStaticData(); + case gl::BufferUsage::StaticCopy: + case gl::BufferUsage::StaticDraw: + case gl::BufferUsage::StaticRead: + mUsage = D3DBufferUsage::STATIC; + initializeStaticData(context); break; - case GL_STREAM_DRAW: - case GL_STREAM_READ: - case GL_STREAM_COPY: - case GL_DYNAMIC_READ: - case GL_DYNAMIC_COPY: - case GL_DYNAMIC_DRAW: - mUsage = D3D_BUFFER_USAGE_DYNAMIC; + case gl::BufferUsage::DynamicCopy: + case gl::BufferUsage::DynamicDraw: + case gl::BufferUsage::DynamicRead: + case gl::BufferUsage::StreamCopy: + case gl::BufferUsage::StreamDraw: + case gl::BufferUsage::StreamRead: + mUsage = D3DBufferUsage::DYNAMIC; break; default: UNREACHABLE(); } } -void BufferD3D::initializeStaticData() +void BufferD3D::initializeStaticData(const gl::Context *context) { - if (!mStaticVertexBuffer) + if (mStaticVertexBuffers.empty()) { - mStaticVertexBuffer = new StaticVertexBufferInterface(mFactory); + StaticVertexBufferInterface *newStaticBuffer = new StaticVertexBufferInterface(mFactory); + mStaticVertexBuffers.push_back( + std::unique_ptr(newStaticBuffer)); } if (!mStaticIndexBuffer) { @@ -97,168 +90,101 @@ StaticIndexBufferInterface *BufferD3D::getStaticIndexBuffer() return mStaticIndexBuffer; } -StaticVertexBufferInterface *BufferD3D::getStaticVertexBuffer( - const gl::VertexAttribute &attribute, - D3DStaticBufferCreationType creationType) +StaticVertexBufferInterface *BufferD3D::getStaticVertexBuffer(const gl::VertexAttribute &attribute, + const gl::VertexBinding &binding) { - if (!mStaticVertexBuffer) + if (mStaticVertexBuffers.empty()) { // Early out if there aren't any static buffers at all - ASSERT(mStaticBufferCache == nullptr); return nullptr; } - if (mStaticBufferCache == nullptr && !mStaticVertexBuffer->isCommitted()) + // Early out, the attribute can be added to mStaticVertexBuffer. + if (mStaticVertexBuffers.size() == 1 && mStaticVertexBuffers[0]->empty()) { - // Early out, the attribute can be added to mStaticVertexBuffer or is already in there - return mStaticVertexBuffer; + return mStaticVertexBuffers[0].get(); } - // At this point, see if any of the existing static buffers contains the attribute data + // Cache size limiting: track the total allocated buffer sizes. + size_t currentTotalSize = 0; - // If the default static vertex buffer contains the attribute, then return it - if (mStaticVertexBuffer->lookupAttribute(attribute, nullptr)) - { - return mStaticVertexBuffer; - } - - if (mStaticBufferCache != nullptr) + // At this point, see if any of the existing static buffers contains the attribute data + // If there is a cached static buffer that already contains the attribute, then return it + for (const auto &staticBuffer : mStaticVertexBuffers) { - // If there is a cached static buffer that already contains the attribute, then return it - for (StaticVertexBufferInterface *staticBuffer : *mStaticBufferCache) + if (staticBuffer->matchesAttribute(attribute, binding)) { - if (staticBuffer->lookupAttribute(attribute, nullptr)) - { - return staticBuffer; - } + return staticBuffer.get(); } - } - if (!mStaticVertexBuffer->isCommitted()) - { - // None of the existing static buffers contain the attribute data and we are able to add - // the data to mStaticVertexBuffer, so we should just do so - return mStaticVertexBuffer; + currentTotalSize += staticBuffer->getBufferSize(); } - // At this point, we must create a new static buffer for the attribute data - if (creationType != D3D_BUFFER_CREATE_IF_NECESSARY) - { - return nullptr; - } + // Cache size limiting: Clean-up threshold is four times the base buffer size, with a minimum. + ASSERT(getSize() < std::numeric_limits::max() / 4u); + size_t sizeThreshold = std::max(getSize() * 4u, static_cast(0x1000u)); - ASSERT(mStaticVertexBuffer); - ASSERT(mStaticVertexBuffer->isCommitted()); - unsigned int staticVertexBufferSize = mStaticVertexBuffer->getBufferSize(); - if (IsUnsignedAdditionSafe(staticVertexBufferSize, mStaticBufferCacheTotalSize)) + // If we're past the threshold, clear the buffer cache. Note that this will release buffers + // that are currenly bound, and in an edge case can even translate the same attribute twice + // in the same draw call. It will not delete currently bound buffers, however, because they + // are ref counted. + if (currentTotalSize > sizeThreshold) { - // Ensure that the total size of the static buffer cache remains less than 4x the - // size of the original buffer - unsigned int maxStaticCacheSize = - IsUnsignedMultiplicationSafe(static_cast(getSize()), 4u) - ? 4u * static_cast(getSize()) - : std::numeric_limits::max(); - - // We can't reuse the default static vertex buffer, so we add it to the cache - if (staticVertexBufferSize + mStaticBufferCacheTotalSize <= maxStaticCacheSize) - { - if (mStaticBufferCache == nullptr) - { - mStaticBufferCache = new std::vector(); - } - - mStaticBufferCacheTotalSize += staticVertexBufferSize; - (*mStaticBufferCache).push_back(mStaticVertexBuffer); - mStaticVertexBuffer = nullptr; - - // Then reinitialize the static buffers to create a new static vertex buffer - initializeStaticData(); - - // Return the default static vertex buffer - return mStaticVertexBuffer; - } + emptyStaticBufferCache(); } - // At this point: - // - mStaticVertexBuffer is committed and can't be altered - // - mStaticBufferCache is full (or nearly overflowing) - // The inputted attribute should be put in some static buffer at some point, but it can't - // go in one right now, since mStaticBufferCache is full and we can't delete mStaticVertexBuffer - // in case another attribute is relying upon it for the current draw. - // We therefore mark mStaticVertexBuffer for deletion at the next possible time. - mStaticVertexBufferOutOfDate = true; - return nullptr; + // At this point, we must create a new static buffer for the attribute data. + StaticVertexBufferInterface *newStaticBuffer = new StaticVertexBufferInterface(mFactory); + newStaticBuffer->setAttribute(attribute, binding); + mStaticVertexBuffers.push_back(std::unique_ptr(newStaticBuffer)); + return newStaticBuffer; } -void BufferD3D::reinitOutOfDateStaticData() +void BufferD3D::invalidateStaticData(const gl::Context *context) { - if (mStaticVertexBufferOutOfDate) - { - // During the last draw the caller tried to use some attribute with static data, but neither - // the static buffer cache nor mStaticVertexBuffer contained that data. - // Therefore, invalidate mStaticVertexBuffer so that if the caller tries to use that - // attribute in the next draw, it'll successfully get put into mStaticVertexBuffer. - invalidateStaticData(D3D_BUFFER_INVALIDATE_DEFAULT_BUFFER_ONLY); - mStaticVertexBufferOutOfDate = false; - } -} + emptyStaticBufferCache(); -void BufferD3D::invalidateStaticData(D3DBufferInvalidationType invalidationType) -{ - if (invalidationType == D3D_BUFFER_INVALIDATE_WHOLE_CACHE && mStaticBufferCache != nullptr) + if (mStaticIndexBuffer && mStaticIndexBuffer->getBufferSize() != 0) { - emptyStaticBufferCache(); + SafeDelete(mStaticIndexBuffer); } - if ((mStaticVertexBuffer && mStaticVertexBuffer->getBufferSize() != 0) || (mStaticIndexBuffer && mStaticIndexBuffer->getBufferSize() != 0)) + // If the buffer was created with a static usage then we recreate the static + // buffers so that they are populated the next time we use this buffer. + if (mUsage == D3DBufferUsage::STATIC) { - SafeDelete(mStaticVertexBuffer); - SafeDelete(mStaticIndexBuffer); - - // If the buffer was created with a static usage then we recreate the static - // buffers so that they are populated the next time we use this buffer. - if (mUsage == D3D_BUFFER_USAGE_STATIC) - { - initializeStaticData(); - } + initializeStaticData(context); } mUnmodifiedDataUse = 0; } // Creates static buffers if sufficient used data has been left unmodified -void BufferD3D::promoteStaticUsage(int dataSize) +void BufferD3D::promoteStaticUsage(const gl::Context *context, int dataSize) { - if (!mStaticVertexBuffer && !mStaticIndexBuffer) + if (mUsage == D3DBufferUsage::DYNAMIC) { - // There isn't any scenario that involves promoting static usage and the static buffer cache - // being non-empty - ASSERT(mStaticBufferCache == nullptr); - mUnmodifiedDataUse += dataSize; if (mUnmodifiedDataUse > 3 * getSize()) { - initializeStaticData(); + updateD3DBufferUsage(context, gl::BufferUsage::StaticDraw); } } } -gl::Error BufferD3D::getIndexRange(GLenum type, +gl::Error BufferD3D::getIndexRange(const gl::Context *context, + GLenum type, size_t offset, size_t count, bool primitiveRestartEnabled, gl::IndexRange *outRange) { const uint8_t *data = nullptr; - gl::Error error = getData(&data); - if (error.isError()) - { - return error; - } + ANGLE_TRY(getData(context, &data)); *outRange = gl::ComputeIndexRange(type, data + offset, count, primitiveRestartEnabled); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -} +} // namespace rx diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/BufferD3D.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/BufferD3D.h index a27ca9857a..60153748e6 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/BufferD3D.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/BufferD3D.h @@ -15,71 +15,69 @@ #include #include +namespace gl +{ +struct VertexAttribute; +class VertexBinding; +} + namespace rx { class BufferFactoryD3D; class StaticIndexBufferInterface; class StaticVertexBufferInterface; -enum D3DBufferUsage -{ - D3D_BUFFER_USAGE_STATIC, - D3D_BUFFER_USAGE_DYNAMIC, -}; - -enum D3DBufferInvalidationType +enum class D3DBufferUsage { - D3D_BUFFER_INVALIDATE_WHOLE_CACHE, - D3D_BUFFER_INVALIDATE_DEFAULT_BUFFER_ONLY, -}; - -enum D3DStaticBufferCreationType -{ - D3D_BUFFER_CREATE_IF_NECESSARY, - D3D_BUFFER_DO_NOT_CREATE, + STATIC, + DYNAMIC, }; class BufferD3D : public BufferImpl { public: - BufferD3D(BufferFactoryD3D *factory); - virtual ~BufferD3D(); + BufferD3D(const gl::BufferState &state, BufferFactoryD3D *factory); + ~BufferD3D() override; unsigned int getSerial() const { return mSerial; } virtual size_t getSize() const = 0; virtual bool supportsDirectBinding() const = 0; - virtual void markTransformFeedbackUsage() = 0; - virtual gl::Error getData(const uint8_t **outData) = 0; + virtual gl::Error markTransformFeedbackUsage(const gl::Context *context) = 0; + virtual gl::Error getData(const gl::Context *context, const uint8_t **outData) = 0; + // Warning: you should ensure binding really matches attrib.bindingIndex before using this + // function. StaticVertexBufferInterface *getStaticVertexBuffer(const gl::VertexAttribute &attribute, - D3DStaticBufferCreationType creationType); + const gl::VertexBinding &binding); StaticIndexBufferInterface *getStaticIndexBuffer(); - void initializeStaticData(); - void invalidateStaticData(D3DBufferInvalidationType invalidationType); - void reinitOutOfDateStaticData(); + virtual void initializeStaticData(const gl::Context *context); + virtual void invalidateStaticData(const gl::Context *context); - void promoteStaticUsage(int dataSize); + void promoteStaticUsage(const gl::Context *context, int dataSize); - gl::Error getIndexRange(GLenum type, + gl::Error getIndexRange(const gl::Context *context, + GLenum type, size_t offset, size_t count, bool primitiveRestartEnabled, gl::IndexRange *outRange) override; + BufferFactoryD3D *getFactory() const { return mFactory; } + D3DBufferUsage getUsage() const { return mUsage; } + protected: void updateSerial(); - void updateD3DBufferUsage(GLenum usage); + void updateD3DBufferUsage(const gl::Context *context, gl::BufferUsage usage); void emptyStaticBufferCache(); BufferFactoryD3D *mFactory; unsigned int mSerial; static unsigned int mNextSerial; - StaticVertexBufferInterface *mStaticVertexBuffer; + std::vector> mStaticVertexBuffers; StaticIndexBufferInterface *mStaticIndexBuffer; - std::vector *mStaticBufferCache; unsigned int mStaticBufferCacheTotalSize; unsigned int mStaticVertexBufferOutOfDate; unsigned int mUnmodifiedDataUse; diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/CompilerD3D.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/CompilerD3D.cpp index 6f8d1717cd..8ceeec3c39 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/CompilerD3D.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/CompilerD3D.cpp @@ -17,4 +17,14 @@ CompilerD3D::CompilerD3D(ShShaderOutput translatorOutputType) { } +gl::Error CompilerD3D::release() +{ + return gl::NoError(); +} + +ShShaderOutput CompilerD3D::getTranslatorOutputType() const +{ + return mTranslatorOutputType; +} + } // namespace rx diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/CompilerD3D.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/CompilerD3D.h index 8f4334963d..bcfe810d04 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/CompilerD3D.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/CompilerD3D.h @@ -21,8 +21,8 @@ class CompilerD3D : public CompilerImpl CompilerD3D(ShShaderOutput translatorOutputType); ~CompilerD3D() override {} - gl::Error release() override { return gl::Error(GL_NO_ERROR); } - ShShaderOutput getTranslatorOutputType() const override { return mTranslatorOutputType; } + gl::Error release() override; + ShShaderOutput getTranslatorOutputType() const override; private: ShShaderOutput mTranslatorOutputType; diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/DeviceD3D.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/DeviceD3D.cpp index f40e6e6cab..5a06b15279 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/DeviceD3D.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/DeviceD3D.cpp @@ -39,11 +39,11 @@ egl::Error DeviceD3D::getDevice(void **outValue) if (!mIsInitialized) { *outValue = nullptr; - return egl::Error(EGL_BAD_DEVICE_EXT); + return egl::EglBadDevice(); } *outValue = mDevice; - return egl::Error(EGL_SUCCESS); + return egl::NoError(); } egl::Error DeviceD3D::initialize(void *device, @@ -53,15 +53,11 @@ egl::Error DeviceD3D::initialize(void *device, ASSERT(!mIsInitialized); if (mIsInitialized) { - return egl::Error(EGL_BAD_DEVICE_EXT); + return egl::EglBadDevice(); } - mDevice = device; - mDeviceType = deviceType; - mDeviceExternallySourced = !!deviceExternallySourced; - #if defined(ANGLE_ENABLE_D3D11) - if (mDeviceType == EGL_D3D11_DEVICE_ANGLE) + if (deviceType == EGL_D3D11_DEVICE_ANGLE) { // Validate the device IUnknown *iunknown = reinterpret_cast(device); @@ -71,7 +67,7 @@ egl::Error DeviceD3D::initialize(void *device, iunknown->QueryInterface(__uuidof(ID3D11Device), reinterpret_cast(&d3dDevice)); if (FAILED(hr)) { - return egl::Error(EGL_BAD_ATTRIBUTE, "Invalid D3D device passed into EGLDeviceEXT"); + return egl::EglBadAttribute() << "Invalid D3D device passed into EGLDeviceEXT"; } // The QI to ID3D11Device adds a ref to the D3D11 device. @@ -81,12 +77,15 @@ egl::Error DeviceD3D::initialize(void *device, else #endif { - ASSERT(!mDeviceExternallySourced); + ASSERT(deviceExternallySourced == EGL_FALSE); } - mIsInitialized = true; + mDevice = device; + mDeviceType = deviceType; + mDeviceExternallySourced = !!deviceExternallySourced; + mIsInitialized = true; - return egl::Error(EGL_SUCCESS); + return egl::NoError(); } EGLint DeviceD3D::getType() @@ -99,4 +98,8 @@ void DeviceD3D::generateExtensions(egl::DeviceExtensions *outExtensions) const outExtensions->deviceD3D = true; } +bool DeviceD3D::deviceExternallySourced() +{ + return mDeviceExternallySourced; +} } diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/DeviceD3D.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/DeviceD3D.h index 1dd9979708..15eaf9210a 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/DeviceD3D.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/DeviceD3D.h @@ -25,7 +25,7 @@ class DeviceD3D : public DeviceImpl egl::Error getDevice(void **outValue) override; EGLint getType() override; void generateExtensions(egl::DeviceExtensions *outExtensions) const override; - bool deviceExternallySourced() override { return mDeviceExternallySourced; } + bool deviceExternallySourced() override; private: void *mDevice; diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/DisplayD3D.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/DisplayD3D.cpp index d4dc702582..0edda9c584 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/DisplayD3D.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/DisplayD3D.cpp @@ -8,18 +8,19 @@ #include "libANGLE/renderer/d3d/DisplayD3D.h" -#include "libANGLE/Context.h" +#include + #include "libANGLE/Config.h" +#include "libANGLE/Context.h" #include "libANGLE/Display.h" #include "libANGLE/Surface.h" +#include "libANGLE/Thread.h" #include "libANGLE/histogram_macros.h" +#include "libANGLE/renderer/d3d/DeviceD3D.h" #include "libANGLE/renderer/d3d/EGLImageD3D.h" #include "libANGLE/renderer/d3d/RendererD3D.h" #include "libANGLE/renderer/d3d/SurfaceD3D.h" #include "libANGLE/renderer/d3d/SwapChainD3D.h" -#include "libANGLE/renderer/d3d/DeviceD3D.h" - -#include #if defined (ANGLE_ENABLE_D3D9) # include "libANGLE/renderer/d3d/d3d9/Renderer9.h" @@ -29,10 +30,6 @@ # 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 1 @@ -60,8 +57,8 @@ egl::Error CreateRendererD3D(egl::Display *display, RendererD3D **outRenderer) const auto &attribMap = display->getAttributeMap(); EGLNativeDisplayType nativeDisplay = display->getNativeDisplayId(); - EGLint requestedDisplayType = - attribMap.get(EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE); + EGLint requestedDisplayType = static_cast( + 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 || @@ -117,11 +114,10 @@ egl::Error CreateRendererD3D(egl::Display *display, RendererD3D **outRenderer) UNIMPLEMENTED(); } - 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(); + egl::Error result = renderer->initialize(); # if defined(ANGLE_ENABLE_D3D11) if (renderer->getRendererClass() == RENDERER_D3D11) @@ -146,70 +142,45 @@ egl::Error CreateRendererD3D(egl::Display *display, RendererD3D **outRenderer) if (!result.isError()) { *outRenderer = renderer; - break; - } - else - { - // Failed to create the renderer, try the next - SafeDelete(renderer); + return result; } + + // Failed to create the renderer, try the next + SafeDelete(renderer); } - return result; + return egl::EglNotInitialized() << "No available renderers."; } -DisplayD3D::DisplayD3D() : mRenderer(nullptr) +DisplayD3D::DisplayD3D(const egl::DisplayState &state) : DisplayImpl(state), mRenderer(nullptr) { } - -SurfaceImpl *DisplayD3D::createWindowSurface(const egl::Config *configuration, +SurfaceImpl *DisplayD3D::createWindowSurface(const egl::SurfaceState &state, EGLNativeWindowType window, const egl::AttributeMap &attribs) { 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); - EGLint orientation = attribs.get(EGL_SURFACE_ORIENTATION_ANGLE, 0); - EGLint directComposition = attribs.get(EGL_DIRECT_COMPOSITION_ANGLE, EGL_FALSE); - - if (!fixedSize) - { - width = -1; - height = -1; - } - - return SurfaceD3D::createFromWindow(mRenderer, mDisplay, configuration, window, fixedSize, - directComposition, width, height, orientation); + return new WindowSurfaceD3D(state, mRenderer, mDisplay, window, attribs); } -SurfaceImpl *DisplayD3D::createPbufferSurface(const egl::Config *configuration, +SurfaceImpl *DisplayD3D::createPbufferSurface(const egl::SurfaceState &state, const egl::AttributeMap &attribs) { ASSERT(mRenderer != nullptr); - - EGLint width = attribs.get(EGL_WIDTH, 0); - EGLint height = attribs.get(EGL_HEIGHT, 0); - - return SurfaceD3D::createOffscreen(mRenderer, mDisplay, configuration, nullptr, width, height); + return new PbufferSurfaceD3D(state, mRenderer, mDisplay, 0, nullptr, attribs); } -SurfaceImpl *DisplayD3D::createPbufferFromClientBuffer(const egl::Config *configuration, - EGLClientBuffer shareHandle, +SurfaceImpl *DisplayD3D::createPbufferFromClientBuffer(const egl::SurfaceState &state, + EGLenum buftype, + EGLClientBuffer clientBuffer, const egl::AttributeMap &attribs) { ASSERT(mRenderer != nullptr); - - EGLint width = attribs.get(EGL_WIDTH, 0); - EGLint height = attribs.get(EGL_HEIGHT, 0); - - return SurfaceD3D::createOffscreen( - mRenderer, mDisplay, configuration, shareHandle, width, height); + return new PbufferSurfaceD3D(state, mRenderer, mDisplay, buftype, clientBuffer, attribs); } -SurfaceImpl *DisplayD3D::createPixmapSurface(const egl::Config *configuration, +SurfaceImpl *DisplayD3D::createPixmapSurface(const egl::SurfaceState &state, NativePixmapType nativePixmap, const egl::AttributeMap &attribs) { @@ -217,11 +188,11 @@ SurfaceImpl *DisplayD3D::createPixmapSurface(const egl::Config *configuration, return nullptr; } -ImageImpl *DisplayD3D::createImage(EGLenum target, - egl::ImageSibling *buffer, +ImageImpl *DisplayD3D::createImage(const egl::ImageState &state, + EGLenum target, const egl::AttributeMap &attribs) { - return new EGLImageD3D(mRenderer, target, buffer, attribs); + return new EGLImageD3D(state, target, attribs, mRenderer); } egl::Error DisplayD3D::getDevice(DeviceImpl **device) @@ -229,30 +200,31 @@ egl::Error DisplayD3D::getDevice(DeviceImpl **device) return mRenderer->getEGLDevice(device); } -gl::Context *DisplayD3D::createContext(const egl::Config *config, - const gl::Context *shareContext, - const egl::AttributeMap &attribs) +ContextImpl *DisplayD3D::createContext(const gl::ContextState &state) { ASSERT(mRenderer != nullptr); - return new gl::Context(config, shareContext, mRenderer, attribs); + return mRenderer->createContext(state); +} + +StreamProducerImpl *DisplayD3D::createStreamProducerD3DTextureNV12( + egl::Stream::ConsumerType consumerType, + const egl::AttributeMap &attribs) +{ + ASSERT(mRenderer != nullptr); + return mRenderer->createStreamProducerD3DTextureNV12(consumerType, attribs); } egl::Error DisplayD3D::makeCurrent(egl::Surface *drawSurface, egl::Surface *readSurface, gl::Context *context) { - return egl::Error(EGL_SUCCESS); + return egl::NoError(); } egl::Error DisplayD3D::initialize(egl::Display *display) { ASSERT(mRenderer == nullptr && display != nullptr); mDisplay = display; - egl::Error error = CreateRendererD3D(display, &mRenderer); - if (error.isError()) - { - return error; - } - - return egl::Error(EGL_SUCCESS); + ANGLE_TRY(CreateRendererD3D(display, &mRenderer)); + return egl::NoError(); } void DisplayD3D::terminate() @@ -260,32 +232,26 @@ void DisplayD3D::terminate() SafeDelete(mRenderer); } -egl::ConfigSet DisplayD3D::generateConfigs() const +egl::ConfigSet DisplayD3D::generateConfigs() { 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() +egl::Error DisplayD3D::restoreLostDevice(const egl::Display *display) { // Release surface resources to make the Reset() succeed - for (auto &surface : mSurfaceSet) + for (egl::Surface *surface : mState.surfaceSet) { if (surface->getBoundTexture()) { - surface->releaseTexImage(EGL_BACK_BUFFER); + ANGLE_TRY(surface->releaseTexImage(display->getProxyContext(), EGL_BACK_BUFFER)); } SurfaceD3D *surfaceD3D = GetImplAs(surface); surfaceD3D->releaseSwapChain(); @@ -293,27 +259,43 @@ egl::Error DisplayD3D::restoreLostDevice() if (!mRenderer->resetDevice()) { - return egl::Error(EGL_BAD_ALLOC); + return egl::EglBadAlloc(); } // Restore any surfaces that may have been lost - for (const auto &surface : mSurfaceSet) + for (const egl::Surface *surface : mState.surfaceSet) { SurfaceD3D *surfaceD3D = GetImplAs(surface); - egl::Error error = surfaceD3D->resetSwapChain(); - if (error.isError()) - { - return error; - } + ANGLE_TRY(surfaceD3D->resetSwapChain(display)); } - return egl::Error(EGL_SUCCESS); + return egl::NoError(); } bool DisplayD3D::isValidNativeWindow(EGLNativeWindowType window) const { - return NativeWindow::isValidNativeWindow(window); + return mRenderer->isValidNativeWindow(window); +} + +egl::Error DisplayD3D::validateClientBuffer(const egl::Config *configuration, + EGLenum buftype, + EGLClientBuffer clientBuffer, + const egl::AttributeMap &attribs) const +{ + switch (buftype) + { + case EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE: + return mRenderer->validateShareHandle(configuration, static_cast(clientBuffer), + attribs); + + case EGL_D3D_TEXTURE_ANGLE: + return mRenderer->getD3DTextureInfo( + configuration, static_cast(clientBuffer), nullptr, nullptr, nullptr); + + default: + return DisplayImpl::validateClientBuffer(configuration, buftype, clientBuffer, attribs); + } } void DisplayD3D::generateExtensions(egl::DisplayExtensions *outExtensions) const @@ -337,20 +319,43 @@ void DisplayD3D::generateCaps(egl::Caps *outCaps) const // Display must be initialized to generate caps ASSERT(mRenderer != nullptr); - outCaps->textureNPOT = mRenderer->getRendererExtensions().textureNPOT; + outCaps->textureNPOT = mRenderer->getNativeExtensions().textureNPOT; } -egl::Error DisplayD3D::waitClient() const +egl::Error DisplayD3D::waitClient(const gl::Context *context) const { - // Unimplemented as it is a noop on D3D - return egl::Error(EGL_SUCCESS); + for (egl::Surface *surface : mState.surfaceSet) + { + SurfaceD3D *surfaceD3D = GetImplAs(surface); + ANGLE_TRY(surfaceD3D->checkForOutOfDateSwapChain(context)); + } + + return egl::NoError(); } -egl::Error DisplayD3D::waitNative(EGLint engine, - egl::Surface *drawSurface, - egl::Surface *readSurface) const +egl::Error DisplayD3D::waitNative(const gl::Context *context, EGLint engine) const { - // Unimplemented as it is a noop on D3D - return egl::Error(EGL_SUCCESS); + egl::Surface *drawSurface = context->getCurrentDrawSurface(); + egl::Surface *readSurface = context->getCurrentReadSurface(); + + if (drawSurface != nullptr) + { + SurfaceD3D *drawSurfaceD3D = GetImplAs(drawSurface); + ANGLE_TRY(drawSurfaceD3D->checkForOutOfDateSwapChain(context)); + } + + if (readSurface != nullptr) + { + SurfaceD3D *readSurfaceD3D = GetImplAs(readSurface); + ANGLE_TRY(readSurfaceD3D->checkForOutOfDateSwapChain(context)); + } + + return egl::NoError(); } + +gl::Version DisplayD3D::getMaxSupportedESVersion() const +{ + return mRenderer->getMaxSupportedESVersion(); } + +} // namespace rx diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/DisplayD3D.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/DisplayD3D.h index 0ce196dea2..7090522312 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/DisplayD3D.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/DisplayD3D.h @@ -19,50 +19,55 @@ class RendererD3D; class DisplayD3D : public DisplayImpl { public: - DisplayD3D(); + DisplayD3D(const egl::DisplayState &state); egl::Error initialize(egl::Display *display) override; - virtual void terminate() override; + void terminate() override; // Surface creation - SurfaceImpl *createWindowSurface(const egl::Config *configuration, + SurfaceImpl *createWindowSurface(const egl::SurfaceState &state, EGLNativeWindowType window, const egl::AttributeMap &attribs) override; - SurfaceImpl *createPbufferSurface(const egl::Config *configuration, + SurfaceImpl *createPbufferSurface(const egl::SurfaceState &state, const egl::AttributeMap &attribs) override; - SurfaceImpl *createPbufferFromClientBuffer(const egl::Config *configuration, - EGLClientBuffer shareHandle, + SurfaceImpl *createPbufferFromClientBuffer(const egl::SurfaceState &state, + EGLenum buftype, + EGLClientBuffer clientBuffer, const egl::AttributeMap &attribs) override; - SurfaceImpl *createPixmapSurface(const egl::Config *configuration, + SurfaceImpl *createPixmapSurface(const egl::SurfaceState &state, NativePixmapType nativePixmap, const egl::AttributeMap &attribs) override; - ImageImpl *createImage(EGLenum target, - egl::ImageSibling *buffer, + ImageImpl *createImage(const egl::ImageState &state, + EGLenum target, const egl::AttributeMap &attribs) override; - gl::Context *createContext(const egl::Config *config, - const gl::Context *shareContext, - const egl::AttributeMap &attribs) override; + ContextImpl *createContext(const gl::ContextState &state) override; + + StreamProducerImpl *createStreamProducerD3DTextureNV12( + egl::Stream::ConsumerType consumerType, + const egl::AttributeMap &attribs) override; egl::Error makeCurrent(egl::Surface *drawSurface, egl::Surface *readSurface, gl::Context *context) override; - egl::ConfigSet generateConfigs() const override; + egl::ConfigSet generateConfigs() override; - bool isDeviceLost() const override; bool testDeviceLost() override; - egl::Error restoreLostDevice() override; + egl::Error restoreLostDevice(const egl::Display *display) override; bool isValidNativeWindow(EGLNativeWindowType window) const override; + egl::Error validateClientBuffer(const egl::Config *configuration, + EGLenum buftype, + EGLClientBuffer clientBuffer, + const egl::AttributeMap &attribs) const override; egl::Error getDevice(DeviceImpl **device) override; std::string getVendorString() const override; - egl::Error waitClient() const override; - egl::Error waitNative(EGLint engine, - egl::Surface *drawSurface, - egl::Surface *readSurface) const override; + egl::Error waitClient(const gl::Context *context) const override; + egl::Error waitNative(const gl::Context *context, EGLint engine) const override; + gl::Version getMaxSupportedESVersion() const override; private: void generateExtensions(egl::DisplayExtensions *outExtensions) const override; diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/DynamicHLSL.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/DynamicHLSL.cpp index 42a534f573..b4143a3f5f 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/DynamicHLSL.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/DynamicHLSL.cpp @@ -8,15 +8,17 @@ #include "libANGLE/renderer/d3d/DynamicHLSL.h" +#include "common/string_utils.h" #include "common/utilities.h" #include "compiler/translator/blocklayoutHLSL.h" +#include "libANGLE/Context.h" #include "libANGLE/Program.h" #include "libANGLE/Shader.h" +#include "libANGLE/VaryingPacking.h" #include "libANGLE/formatutils.h" #include "libANGLE/renderer/d3d/ProgramD3D.h" #include "libANGLE/renderer/d3d/RendererD3D.h" #include "libANGLE/renderer/d3d/ShaderD3D.h" -#include "libANGLE/renderer/d3d/VaryingPacking.h" using namespace gl; @@ -26,7 +28,28 @@ namespace rx namespace { -std::string HLSLComponentTypeString(GLenum componentType) +// This class needs to match OutputHLSL::decorate +class DecorateVariable final : angle::NonCopyable +{ + public: + explicit DecorateVariable(const std::string &str) : mName(str) {} + const std::string &getName() const { return mName; } + + private: + const std::string &mName; +}; + +std::ostream &operator<<(std::ostream &o, const DecorateVariable &dv) +{ + if (dv.getName().compare(0, 3, "gl_") != 0) + { + o << "_"; + } + o << dv.getName(); + return o; +} + +const char *HLSLComponentTypeString(GLenum componentType) { switch (componentType) { @@ -44,12 +67,16 @@ std::string HLSLComponentTypeString(GLenum componentType) } } -std::string HLSLComponentTypeString(GLenum componentType, int componentCount) +void HLSLComponentTypeString(std::ostringstream &ostream, GLenum componentType, int componentCount) { - return HLSLComponentTypeString(componentType) + (componentCount > 1 ? Str(componentCount) : ""); + ostream << HLSLComponentTypeString(componentType); + if (componentCount > 1) + { + ostream << componentCount; + } } -std::string HLSLMatrixTypeString(GLenum type) +const char *HLSLMatrixTypeString(GLenum type) { switch (type) { @@ -77,15 +104,16 @@ std::string HLSLMatrixTypeString(GLenum type) } } -std::string HLSLTypeString(GLenum type) +void HLSLTypeString(std::ostringstream &ostream, GLenum type) { if (gl::IsMatrixType(type)) { - return HLSLMatrixTypeString(type); + ostream << HLSLMatrixTypeString(type); + return; } - return HLSLComponentTypeString(gl::VariableComponentType(type), - gl::VariableComponentCount(type)); + HLSLComponentTypeString(ostream, gl::VariableComponentType(type), + gl::VariableComponentCount(type)); } const PixelShaderOutputVariable *FindOutputAtLocation( @@ -103,7 +131,7 @@ const PixelShaderOutputVariable *FindOutputAtLocation( return nullptr; } -void WriteArrayString(std::stringstream &strstr, unsigned int i) +void WriteArrayString(std::ostringstream &strstr, unsigned int i) { static_assert(GL_INVALID_INDEX == UINT_MAX, "GL_INVALID_INDEX must be equal to the max unsigned int."); @@ -117,16 +145,14 @@ void WriteArrayString(std::stringstream &strstr, unsigned int i) strstr << "]"; } -const std::string VERTEX_ATTRIBUTE_STUB_STRING = "@@ VERTEX ATTRIBUTES @@"; -const std::string PIXEL_OUTPUT_STUB_STRING = "@@ PIXEL OUTPUT @@"; +constexpr const char *VERTEX_ATTRIBUTE_STUB_STRING = "@@ VERTEX ATTRIBUTES @@"; +constexpr const char *PIXEL_OUTPUT_STUB_STRING = "@@ PIXEL OUTPUT @@"; } // anonymous namespace -std::string GetVaryingSemantic(int majorShaderModel, bool programUsesPointSize) -{ - // SM3 reserves the TEXCOORD semantic for point sprite texcoords (gl_PointCoord) - // In D3D11 we manually compute gl_PointCoord in the GS. - return ((programUsesPointSize && majorShaderModel < 4) ? "COLOR" : "TEXCOORD"); -} +// BuiltinInfo implementation + +BuiltinInfo::BuiltinInfo() = default; +BuiltinInfo::~BuiltinInfo() = default; // DynamicHLSL implementation @@ -134,55 +160,13 @@ DynamicHLSL::DynamicHLSL(RendererD3D *const renderer) : mRenderer(renderer) { } -void DynamicHLSL::generateVaryingHLSL(const VaryingPacking &varyingPacking, - std::stringstream &hlslStream) const -{ - std::string varyingSemantic = - GetVaryingSemantic(mRenderer->getMajorShaderModel(), varyingPacking.usesPointSize()); - - for (const PackedVaryingRegister ®isterInfo : varyingPacking.getRegisterList()) - { - const auto &varying = *registerInfo.packedVarying->varying; - ASSERT(!varying.isStruct()); - - // 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 (registerInfo.packedVarying->interpolation) - { - case sh::INTERPOLATION_SMOOTH: - hlslStream << " "; - break; - case sh::INTERPOLATION_FLAT: - hlslStream << " nointerpolation "; - break; - case sh::INTERPOLATION_CENTROID: - hlslStream << " centroid "; - break; - default: - UNREACHABLE(); - } - - GLenum transposedType = gl::TransposeMatrixType(varying.type); - GLenum componentType = gl::VariableComponentType(transposedType); - int columnCount = gl::VariableColumnCount(transposedType); - hlslStream << HLSLComponentTypeString(componentType, columnCount); - unsigned int semanticIndex = registerInfo.semanticIndex; - hlslStream << " v" << semanticIndex << " : " << varyingSemantic << semanticIndex << ";\n"; - } -} - std::string DynamicHLSL::generateVertexShaderForInputLayout( const std::string &sourceShader, const InputLayout &inputLayout, const std::vector &shaderAttributes) const { - std::stringstream structStream; - std::stringstream initStream; + std::ostringstream structStream; + std::ostringstream initStream; structStream << "struct VS_INPUT\n" << "{\n"; @@ -231,26 +215,31 @@ std::string DynamicHLSL::generateVertexShaderForInputLayout( { GLenum componentType = mRenderer->getVertexComponentType(vertexFormatType); - if (shaderAttribute.name == "gl_InstanceID") + if (shaderAttribute.name == "gl_InstanceID" || + shaderAttribute.name == "gl_VertexID") { - // The input type of the instance ID in HLSL (uint) differs from the one in ESSL - // (int). + // The input types of the instance ID and vertex ID in HLSL (uint) differs from + // the ones in ESSL (int). structStream << " uint"; } else { - structStream << " " << HLSLComponentTypeString( - componentType, - VariableComponentCount(shaderAttribute.type)); + structStream << " "; + HLSLComponentTypeString(structStream, componentType, + VariableComponentCount(shaderAttribute.type)); } } - structStream << " " << decorateVariable(shaderAttribute.name) << " : "; + structStream << " " << DecorateVariable(shaderAttribute.name) << " : "; if (shaderAttribute.name == "gl_InstanceID") { structStream << "SV_InstanceID"; } + else if (shaderAttribute.name == "gl_VertexID") + { + structStream << "SV_VertexID"; + } else { structStream << "TEXCOORD" << semanticIndex; @@ -260,7 +249,7 @@ std::string DynamicHLSL::generateVertexShaderForInputLayout( structStream << ";\n"; // HLSL code for initialization - initStream << " " << decorateVariable(shaderAttribute.name) << " = "; + initStream << " " << DecorateVariable(shaderAttribute.name) << " = "; // Mismatched vertex attribute to vertex input may result in an undefined // data reinterpretation (eg for pure integer->float, float->pure integer) @@ -268,11 +257,11 @@ std::string DynamicHLSL::generateVertexShaderForInputLayout( if (IsMatrixType(shaderAttribute.type) || (mRenderer->getVertexConversionType(vertexFormatType) & VERTEX_CONVERT_GPU) != 0) { - initStream << generateAttributeConversionHLSL(vertexFormatType, shaderAttribute); + GenerateAttributeConversionHLSL(vertexFormatType, shaderAttribute, initStream); } else { - initStream << "input." << decorateVariable(shaderAttribute.name); + initStream << "input." << DecorateVariable(shaderAttribute.name); } initStream << ";\n"; @@ -289,8 +278,9 @@ std::string DynamicHLSL::generateVertexShaderForInputLayout( std::string vertexHLSL(sourceShader); - size_t copyInsertionPos = vertexHLSL.find(VERTEX_ATTRIBUTE_STUB_STRING); - vertexHLSL.replace(copyInsertionPos, VERTEX_ATTRIBUTE_STUB_STRING.length(), structStream.str()); + bool success = + angle::ReplaceSubstring(&vertexHLSL, VERTEX_ATTRIBUTE_STUB_STRING, structStream.str()); + ASSERT(success); return vertexHLSL; } @@ -305,22 +295,32 @@ std::string DynamicHLSL::generatePixelShaderForOutputSignature( std::string targetSemantic = (shaderModel >= 4) ? "SV_TARGET" : "COLOR"; std::string depthSemantic = (shaderModel >= 4) ? "SV_Depth" : "DEPTH"; - std::stringstream declarationStream; - std::stringstream copyStream; + std::ostringstream declarationStream; + std::ostringstream copyStream; declarationStream << "struct PS_OUTPUT\n" "{\n"; - for (size_t layoutIndex = 0; layoutIndex < outputLayout.size(); ++layoutIndex) + size_t numOutputs = outputLayout.size(); + + // Workaround for HLSL 3.x: We can't do a depth/stencil only render, the runtime will complain. + if (numOutputs == 0 && (shaderModel == 3 || !mRenderer->getShaderModelSuffix().empty())) + { + numOutputs = 1u; + } + const PixelShaderOutputVariable defaultOutput(GL_FLOAT_VEC4, "dummy", "float4(0, 0, 0, 1)", 0); + + for (size_t layoutIndex = 0; layoutIndex < numOutputs; ++layoutIndex) { - GLenum binding = outputLayout[layoutIndex]; + GLenum binding = outputLayout.empty() ? GL_COLOR_ATTACHMENT0 : outputLayout[layoutIndex]; if (binding != GL_NONE) { unsigned int location = (binding - GL_COLOR_ATTACHMENT0); const PixelShaderOutputVariable *outputVariable = - FindOutputAtLocation(outputVariables, location); + outputLayout.empty() ? &defaultOutput + : FindOutputAtLocation(outputVariables, location); // OpenGL ES 3.0 spec $4.2.1 // If [...] not all user-defined output variables are written, the values of fragment @@ -328,8 +328,9 @@ std::string DynamicHLSL::generatePixelShaderForOutputSignature( // corresponding to unwritten variables are similarly undefined. if (outputVariable) { - declarationStream << " " + HLSLTypeString(outputVariable->type) << " " - << outputVariable->name << " : " << targetSemantic + declarationStream << " "; + HLSLTypeString(declarationStream, outputVariable->type); + declarationStream << " " << outputVariable->name << " : " << targetSemantic << static_cast(layoutIndex) << ";\n"; copyStream << " output." << outputVariable->name << " = " @@ -354,61 +355,113 @@ std::string DynamicHLSL::generatePixelShaderForOutputSignature( std::string pixelHLSL(sourceShader); - size_t outputInsertionPos = pixelHLSL.find(PIXEL_OUTPUT_STUB_STRING); - pixelHLSL.replace(outputInsertionPos, PIXEL_OUTPUT_STUB_STRING.length(), - declarationStream.str()); + bool success = + angle::ReplaceSubstring(&pixelHLSL, PIXEL_OUTPUT_STUB_STRING, declarationStream.str()); + ASSERT(success); return pixelHLSL; } -void DynamicHLSL::generateVaryingLinkHLSL(ShaderType shaderType, - const VaryingPacking &varyingPacking, - std::stringstream &linkStream) const +void DynamicHLSL::generateVaryingLinkHLSL(const VaryingPacking &varyingPacking, + const BuiltinInfo &builtins, + bool programUsesPointSize, + std::ostringstream &hlslStream) const { - const auto &builtins = varyingPacking.builtins(shaderType); ASSERT(builtins.dxPosition.enabled); - linkStream << "{\n" + hlslStream << "{\n" << " float4 dx_Position : " << builtins.dxPosition.str() << ";\n"; if (builtins.glPosition.enabled) { - linkStream << " float4 gl_Position : " << builtins.glPosition.str() << ";\n"; + hlslStream << " float4 gl_Position : " << builtins.glPosition.str() << ";\n"; } if (builtins.glFragCoord.enabled) { - linkStream << " float4 gl_FragCoord : " << builtins.glFragCoord.str() << ";\n"; + hlslStream << " float4 gl_FragCoord : " << builtins.glFragCoord.str() << ";\n"; } if (builtins.glPointCoord.enabled) { - linkStream << " float2 gl_PointCoord : " << builtins.glPointCoord.str() << ";\n"; + hlslStream << " float2 gl_PointCoord : " << builtins.glPointCoord.str() << ";\n"; } if (builtins.glPointSize.enabled) { - linkStream << " float gl_PointSize : " << builtins.glPointSize.str() << ";\n"; + hlslStream << " float gl_PointSize : " << builtins.glPointSize.str() << ";\n"; + } + + if (builtins.glViewIDOVR.enabled) + { + hlslStream << " nointerpolation uint gl_ViewID_OVR : " << builtins.glViewIDOVR.str() + << ";\n"; + } + + if (builtins.glViewportIndex.enabled) + { + hlslStream << " nointerpolation uint gl_ViewportIndex : " + << builtins.glViewportIndex.str() << ";\n"; + } + + if (builtins.glLayer.enabled) + { + hlslStream << " nointerpolation uint gl_Layer : " << builtins.glLayer.str() << ";\n"; } - // Do this after glPointSize, to potentially combine gl_PointCoord and gl_PointSize into the - // same register. - generateVaryingHLSL(varyingPacking, linkStream); + std::string varyingSemantic = + GetVaryingSemantic(mRenderer->getMajorShaderModel(), programUsesPointSize); - linkStream << "};\n"; + for (const PackedVaryingRegister ®isterInfo : varyingPacking.getRegisterList()) + { + const auto &varying = *registerInfo.packedVarying->varying; + ASSERT(!varying.isStruct()); + + // 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 (registerInfo.packedVarying->interpolation) + { + case sh::INTERPOLATION_SMOOTH: + hlslStream << " "; + break; + case sh::INTERPOLATION_FLAT: + hlslStream << " nointerpolation "; + break; + case sh::INTERPOLATION_CENTROID: + hlslStream << " centroid "; + break; + default: + UNREACHABLE(); + } + + GLenum transposedType = gl::TransposeMatrixType(varying.type); + GLenum componentType = gl::VariableComponentType(transposedType); + int columnCount = gl::VariableColumnCount(transposedType); + HLSLComponentTypeString(hlslStream, componentType, columnCount); + unsigned int semanticIndex = registerInfo.semanticIndex; + hlslStream << " v" << semanticIndex << " : " << varyingSemantic << semanticIndex << ";\n"; + } + + hlslStream << "};\n"; } -bool DynamicHLSL::generateShaderLinkHLSL(const gl::Data &data, - const gl::Program::Data &programData, +void DynamicHLSL::generateShaderLinkHLSL(const gl::Context *context, + const gl::ProgramState &programData, const ProgramD3DMetadata &programMetadata, const VaryingPacking &varyingPacking, + const BuiltinVaryingsD3D &builtinsD3D, std::string *pixelHLSL, std::string *vertexHLSL) const { ASSERT(pixelHLSL->empty() && vertexHLSL->empty()); - const gl::Shader *vertexShaderGL = programData.getAttachedVertexShader(); - const ShaderD3D *vertexShader = GetImplAs(vertexShaderGL); - const gl::Shader *fragmentShaderGL = programData.getAttachedFragmentShader(); + const auto &data = context->getContextState(); + gl::Shader *vertexShaderGL = programData.getAttachedVertexShader(); + gl::Shader *fragmentShaderGL = programData.getAttachedFragmentShader(); const ShaderD3D *fragmentShader = GetImplAs(fragmentShaderGL); const int shaderModel = mRenderer->getMajorShaderModel(); @@ -422,48 +475,59 @@ bool DynamicHLSL::generateShaderLinkHLSL(const gl::Data &data, // Validation done in the compiler ASSERT(!fragmentShader->usesFragColor() || !fragmentShader->usesFragData()); - std::stringstream vertexStream; - vertexStream << vertexShaderGL->getTranslatedSource(); + std::ostringstream vertexStream; + vertexStream << vertexShaderGL->getTranslatedSource(context); // Instanced PointSprite emulation requires additional entries originally generated in the // GeometryShader HLSL. These include pointsize clamp values. if (useInstancedPointSpriteEmulation) { vertexStream << "static float minPointSize = " - << static_cast(data.caps->minAliasedPointSize) << ".0f;\n" + << static_cast(data.getCaps().minAliasedPointSize) << ".0f;\n" << "static float maxPointSize = " - << static_cast(data.caps->maxAliasedPointSize) << ".0f;\n"; + << static_cast(data.getCaps().maxAliasedPointSize) << ".0f;\n"; } // Add stub string to be replaced when shader is dynamically defined by its layout - vertexStream << "\n" << VERTEX_ATTRIBUTE_STUB_STRING + "\n"; + vertexStream << "\n" << std::string(VERTEX_ATTRIBUTE_STUB_STRING) << "\n"; + + const auto &vertexBuiltins = builtinsD3D[gl::SHADER_VERTEX]; // Write the HLSL input/output declarations vertexStream << "struct VS_OUTPUT\n"; - generateVaryingLinkHLSL(SHADER_VERTEX, varyingPacking, vertexStream); + generateVaryingLinkHLSL(varyingPacking, vertexBuiltins, builtinsD3D.usesPointSize(), + vertexStream); vertexStream << "\n" << "VS_OUTPUT main(VS_INPUT input)\n" << "{\n" << " initAttributes(input);\n"; - if (vertexShader->usesDeferredInit()) - { - vertexStream << "\n" - << " initializeDeferredGlobals();\n"; - } - vertexStream << "\n" << " gl_main();\n" << "\n" << " VS_OUTPUT output;\n"; - const auto &vertexBuiltins = varyingPacking.builtins(SHADER_VERTEX); - if (vertexBuiltins.glPosition.enabled) { vertexStream << " output.gl_Position = gl_Position;\n"; } + if (vertexBuiltins.glViewIDOVR.enabled) + { + vertexStream << " output.gl_ViewID_OVR = _ViewID_OVR;\n"; + } + if (programMetadata.hasANGLEMultiviewEnabled() && programMetadata.canSelectViewInVertexShader()) + { + ASSERT(vertexBuiltins.glViewportIndex.enabled && vertexBuiltins.glLayer.enabled); + vertexStream << " if (multiviewSelectViewportIndex)\n" + << " {\n" + << " output.gl_ViewportIndex = _ViewID_OVR;\n" + << " } else {\n" + << " output.gl_ViewportIndex = 0;\n" + << " output.gl_Layer = _ViewID_OVR;\n" + << " }\n"; + } + // On D3D9 or D3D11 Feature Level 9, we need to emulate large viewports using dx_ViewAdjust. if (shaderModel >= 4 && mRenderer->getShaderModelSuffix() == "") { @@ -528,10 +592,10 @@ bool DynamicHLSL::generateShaderLinkHLSL(const gl::Data &data, if (packedVarying.isStructField()) { - vertexStream << decorateVariable(packedVarying.parentStructName) << "."; + vertexStream << DecorateVariable(packedVarying.parentStructName) << "."; } - vertexStream << decorateVariable(varying.name); + vertexStream << DecorateVariable(varying.name); if (varying.isArray()) { @@ -593,13 +657,16 @@ bool DynamicHLSL::generateShaderLinkHLSL(const gl::Data &data, << " return output;\n" << "}\n"; - std::stringstream pixelStream; - pixelStream << fragmentShaderGL->getTranslatedSource(); + const auto &pixelBuiltins = builtinsD3D[gl::SHADER_FRAGMENT]; + + std::ostringstream pixelStream; + pixelStream << fragmentShaderGL->getTranslatedSource(context); pixelStream << "struct PS_INPUT\n"; - generateVaryingLinkHLSL(SHADER_PIXEL, varyingPacking, pixelStream); + generateVaryingLinkHLSL(varyingPacking, pixelBuiltins, builtinsD3D.usesPointSize(), + pixelStream); pixelStream << "\n"; - pixelStream << PIXEL_OUTPUT_STUB_STRING + "\n"; + pixelStream << std::string(PIXEL_OUTPUT_STUB_STRING) << "\n"; if (fragmentShader->usesFrontFacing()) { @@ -620,7 +687,11 @@ bool DynamicHLSL::generateShaderLinkHLSL(const gl::Data &data, << "{\n"; } - const auto &pixelBuiltins = varyingPacking.builtins(SHADER_PIXEL); + if (fragmentShader->usesViewID()) + { + ASSERT(pixelBuiltins.glViewIDOVR.enabled); + pixelStream << " _ViewID_OVR = input.gl_ViewID_OVR;\n"; + } if (pixelBuiltins.glFragCoord.enabled) { @@ -721,18 +792,19 @@ bool DynamicHLSL::generateShaderLinkHLSL(const gl::Data &data, const auto &varying = *packedVarying.varying; ASSERT(!varying.isBuiltIn() && !varying.isStruct()); - // Don't reference VS-only transform feedback varyings in the PS. - if (registerInfo.packedVarying->vertexOnly) + // Don't reference VS-only transform feedback varyings in the PS. Note that we're relying on + // that the staticUse flag is set according to usage in the fragment shader. + if (packedVarying.vertexOnly || !varying.staticUse) continue; pixelStream << " "; if (packedVarying.isStructField()) { - pixelStream << decorateVariable(packedVarying.parentStructName) << "."; + pixelStream << DecorateVariable(packedVarying.parentStructName) << "."; } - pixelStream << decorateVariable(varying.name); + pixelStream << DecorateVariable(varying.name); if (varying.isArray()) { @@ -766,12 +838,6 @@ bool DynamicHLSL::generateShaderLinkHLSL(const gl::Data &data, pixelStream << ";\n"; } - if (fragmentShader->usesDeferredInit()) - { - pixelStream << "\n" - << " initializeDeferredGlobals();\n"; - } - pixelStream << "\n" << " gl_main();\n" << "\n" @@ -780,34 +846,126 @@ bool DynamicHLSL::generateShaderLinkHLSL(const gl::Data &data, *vertexHLSL = vertexStream.str(); *pixelHLSL = pixelStream.str(); +} + +std::string DynamicHLSL::generateComputeShaderLinkHLSL(const gl::Context *context, + const gl::ProgramState &programData) const +{ + gl::Shader *computeShaderGL = programData.getAttachedComputeShader(); + std::stringstream computeStream; + std::string translatedSource = computeShaderGL->getTranslatedSource(context); + computeStream << translatedSource; + + bool usesWorkGroupID = translatedSource.find("GL_USES_WORK_GROUP_ID") != std::string::npos; + bool usesLocalInvocationID = + translatedSource.find("GL_USES_LOCAL_INVOCATION_ID") != std::string::npos; + bool usesGlobalInvocationID = + translatedSource.find("GL_USES_GLOBAL_INVOCATION_ID") != std::string::npos; + bool usesLocalInvocationIndex = + translatedSource.find("GL_USES_LOCAL_INVOCATION_INDEX") != std::string::npos; + + computeStream << "\nstruct CS_INPUT\n{\n"; + if (usesWorkGroupID) + { + computeStream << " uint3 dx_WorkGroupID : " + << "SV_GroupID;\n"; + } - return true; + if (usesLocalInvocationID) + { + computeStream << " uint3 dx_LocalInvocationID : " + << "SV_GroupThreadID;\n"; + } + + if (usesGlobalInvocationID) + { + computeStream << " uint3 dx_GlobalInvocationID : " + << "SV_DispatchThreadID;\n"; + } + + if (usesLocalInvocationIndex) + { + computeStream << " uint dx_LocalInvocationIndex : " + << "SV_GroupIndex;\n"; + } + + computeStream << "};\n\n"; + + const sh::WorkGroupSize &localSize = computeShaderGL->getWorkGroupSize(context); + computeStream << "[numthreads(" << localSize[0] << ", " << localSize[1] << ", " << localSize[2] + << ")]\n"; + + computeStream << "void main(CS_INPUT input)\n" + << "{\n"; + + if (usesWorkGroupID) + { + computeStream << " gl_WorkGroupID = input.dx_WorkGroupID;\n"; + } + if (usesLocalInvocationID) + { + computeStream << " gl_LocalInvocationID = input.dx_LocalInvocationID;\n"; + } + if (usesGlobalInvocationID) + { + computeStream << " gl_GlobalInvocationID = input.dx_GlobalInvocationID;\n"; + } + if (usesLocalInvocationIndex) + { + computeStream << " gl_LocalInvocationIndex = input.dx_LocalInvocationIndex;\n"; + } + + computeStream << "\n" + << " gl_main();\n" + << "}\n"; + + return computeStream.str(); } -std::string DynamicHLSL::generateGeometryShaderPreamble(const VaryingPacking &varyingPacking) const +std::string DynamicHLSL::generateGeometryShaderPreamble(const VaryingPacking &varyingPacking, + const BuiltinVaryingsD3D &builtinsD3D, + const bool hasANGLEMultiviewEnabled, + const bool selectViewInVS) const { ASSERT(mRenderer->getMajorShaderModel() >= 4); - std::stringstream preambleStream; + std::ostringstream preambleStream; - const auto &builtins = varyingPacking.builtins(SHADER_VERTEX); + const auto &vertexBuiltins = builtinsD3D[gl::SHADER_VERTEX]; preambleStream << "struct GS_INPUT\n"; - generateVaryingLinkHLSL(SHADER_VERTEX, varyingPacking, preambleStream); + generateVaryingLinkHLSL(varyingPacking, vertexBuiltins, builtinsD3D.usesPointSize(), + preambleStream); preambleStream << "\n" << "struct GS_OUTPUT\n"; - generateVaryingLinkHLSL(SHADER_GEOMETRY, varyingPacking, preambleStream); + generateVaryingLinkHLSL(varyingPacking, builtinsD3D[gl::SHADER_GEOMETRY], + builtinsD3D.usesPointSize(), preambleStream); preambleStream << "\n" << "void copyVertex(inout GS_OUTPUT output, GS_INPUT input, GS_INPUT flatinput)\n" << "{\n" << " output.gl_Position = input.gl_Position;\n"; - if (builtins.glPointSize.enabled) + if (vertexBuiltins.glPointSize.enabled) { preambleStream << " output.gl_PointSize = input.gl_PointSize;\n"; } + if (hasANGLEMultiviewEnabled) + { + preambleStream << " output.gl_ViewID_OVR = input.gl_ViewID_OVR;\n"; + if (selectViewInVS) + { + ASSERT(builtinsD3D[gl::SHADER_GEOMETRY].glViewportIndex.enabled && + builtinsD3D[gl::SHADER_GEOMETRY].glLayer.enabled); + + // If the view is already selected in the VS, then we just pass the gl_ViewportIndex and + // gl_Layer to the output. + preambleStream << " output.gl_ViewportIndex = input.gl_ViewportIndex;\n" + << " output.gl_Layer = input.gl_Layer;\n"; + } + } + for (const PackedVaryingRegister &varyingRegister : varyingPacking.getRegisterList()) { preambleStream << " output.v" << varyingRegister.semanticIndex << " = "; @@ -818,7 +976,7 @@ std::string DynamicHLSL::generateGeometryShaderPreamble(const VaryingPacking &va preambleStream << "input.v" << varyingRegister.semanticIndex << "; \n"; } - if (builtins.glFragCoord.enabled) + if (vertexBuiltins.glFragCoord.enabled) { preambleStream << " output.gl_FragCoord = input.gl_FragCoord;\n"; } @@ -829,20 +987,46 @@ std::string DynamicHLSL::generateGeometryShaderPreamble(const VaryingPacking &va << "#endif // ANGLE_POINT_SPRITE_SHADER\n" << "}\n"; + if (hasANGLEMultiviewEnabled && !selectViewInVS) + { + ASSERT(builtinsD3D[gl::SHADER_GEOMETRY].glViewportIndex.enabled && + builtinsD3D[gl::SHADER_GEOMETRY].glLayer.enabled); + + // According to the HLSL reference, using SV_RenderTargetArrayIndex is only valid if the + // render target is an array resource. Because of this we do not write to gl_Layer if we are + // taking the side-by-side code path. We still select the viewport index in the layered code + // path as that is always valid. See: + // https://msdn.microsoft.com/en-us/library/windows/desktop/bb509647(v=vs.85).aspx + preambleStream << "\n" + << "void selectView(inout GS_OUTPUT output, GS_INPUT input)\n" + << "{\n" + << " if (multiviewSelectViewportIndex)\n" + << " {\n" + << " output.gl_ViewportIndex = input.gl_ViewID_OVR;\n" + << " } else {\n" + << " output.gl_ViewportIndex = 0;\n" + << " output.gl_Layer = input.gl_ViewID_OVR;\n" + << " }\n" + << "}\n"; + } + return preambleStream.str(); } -std::string DynamicHLSL::generateGeometryShaderHLSL(gl::PrimitiveType primitiveType, - const gl::Data &data, - const gl::Program::Data &programData, +std::string DynamicHLSL::generateGeometryShaderHLSL(const gl::Context *context, + gl::PrimitiveType primitiveType, + const gl::ProgramState &programData, const bool useViewScale, + const bool hasANGLEMultiviewEnabled, + const bool selectViewInVS, + const bool pointSpriteEmulation, const std::string &preambleString) const { ASSERT(mRenderer->getMajorShaderModel() >= 4); std::stringstream shaderStream; - const bool pointSprites = (primitiveType == PRIMITIVE_POINTS); + const bool pointSprites = (primitiveType == PRIMITIVE_POINTS) && pointSpriteEmulation; const bool usesPointCoord = preambleString.find("gl_PointCoord") != std::string::npos; const char *inputPT = nullptr; @@ -854,9 +1038,19 @@ std::string DynamicHLSL::generateGeometryShaderHLSL(gl::PrimitiveType primitiveT { case PRIMITIVE_POINTS: inputPT = "point"; - outputPT = "Triangle"; inputSize = 1; - maxVertexOutput = 4; + + if (pointSprites) + { + outputPT = "Triangle"; + maxVertexOutput = 4; + } + else + { + outputPT = "Point"; + maxVertexOutput = 1; + } + break; case PRIMITIVE_LINES: @@ -882,18 +1076,34 @@ std::string DynamicHLSL::generateGeometryShaderHLSL(gl::PrimitiveType primitiveT break; } - if (pointSprites) + if (pointSprites || hasANGLEMultiviewEnabled) { - shaderStream << "#define ANGLE_POINT_SPRITE_SHADER\n" - "\n" - "uniform float4 dx_ViewCoords : register(c1);\n"; + shaderStream << "cbuffer DriverConstants : register(b0)\n" + "{\n"; + + if (pointSprites) + { + shaderStream << " float4 dx_ViewCoords : packoffset(c1);\n"; + if (useViewScale) + { + shaderStream << " float2 dx_ViewScale : packoffset(c3);\n"; + } + } - if (useViewScale) + if (hasANGLEMultiviewEnabled) { - shaderStream << "uniform float2 dx_ViewScale : register(c3);\n"; + // We have to add a value which we can use to keep track of which multi-view code path + // is to be selected in the GS. + shaderStream << " float multiviewSelectViewportIndex : packoffset(c3.z);\n"; } - shaderStream << "\n" + shaderStream << "};\n\n"; + } + + if (pointSprites) + { + shaderStream << "#define ANGLE_POINT_SPRITE_SHADER\n" + "\n" "static float2 pointSpriteCorners[] = \n" "{\n" " float2( 0.5f, -0.5f),\n" @@ -911,10 +1121,10 @@ std::string DynamicHLSL::generateGeometryShaderHLSL(gl::PrimitiveType primitiveT "};\n" "\n" "static float minPointSize = " - << static_cast(data.caps->minAliasedPointSize) + << static_cast(context->getCaps().minAliasedPointSize) << ".0f;\n" "static float maxPointSize = " - << static_cast(data.caps->maxAliasedPointSize) << ".0f;\n" + << static_cast(context->getCaps().maxAliasedPointSize) << ".0f;\n" << "\n"; } @@ -944,7 +1154,10 @@ std::string DynamicHLSL::generateGeometryShaderHLSL(gl::PrimitiveType primitiveT { shaderStream << " copyVertex(output, input[" << vertexIndex << "], input[lastVertexIndex]);\n"; - + if (hasANGLEMultiviewEnabled && !selectViewInVS) + { + shaderStream << " selectView(output, input[" << vertexIndex << "]);\n"; + } if (!pointSprites) { ASSERT(inputSize == maxVertexOutput); @@ -995,50 +1208,38 @@ std::string DynamicHLSL::generateGeometryShaderHLSL(gl::PrimitiveType primitiveT return shaderStream.str(); } -// 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( - gl::VertexFormatType vertexFormatType, - const sh::ShaderVariable &shaderAttrib) const +// static +void DynamicHLSL::GenerateAttributeConversionHLSL(gl::VertexFormatType vertexFormatType, + const sh::ShaderVariable &shaderAttrib, + std::ostringstream &outStream) { - const gl::VertexFormat &vertexFormat = gl::GetVertexFormatFromType(vertexFormatType); - std::string attribString = "input." + decorateVariable(shaderAttrib.name); - // Matrix if (IsMatrixType(shaderAttrib.type)) { - return "transpose(" + attribString + ")"; + outStream << "transpose(input." << DecorateVariable(shaderAttrib.name) << ")"; + return; } GLenum shaderComponentType = VariableComponentType(shaderAttrib.type); int shaderComponentCount = VariableComponentCount(shaderAttrib.type); + const gl::VertexFormat &vertexFormat = gl::GetVertexFormatFromType(vertexFormatType); // Perform integer to float conversion (if necessary) - bool requiresTypeConversion = - (shaderComponentType == GL_FLOAT && vertexFormat.type != GL_FLOAT); - - if (requiresTypeConversion) + if (shaderComponentType == GL_FLOAT && vertexFormat.type != GL_FLOAT) { // TODO: normalization for 32-bit integer formats ASSERT(!vertexFormat.normalized && !vertexFormat.pureInteger); - return "float" + Str(shaderComponentCount) + "(" + attribString + ")"; + outStream << "float" << shaderComponentCount << "(input." + << DecorateVariable(shaderAttrib.name) << ")"; + return; } // No conversion necessary - return attribString; + outStream << "input." << DecorateVariable(shaderAttrib.name); } -void DynamicHLSL::getPixelShaderOutputKey(const gl::Data &data, - const gl::Program::Data &programData, +void DynamicHLSL::getPixelShaderOutputKey(const gl::ContextState &data, + const gl::ProgramState &programData, const ProgramD3DMetadata &metadata, std::vector *outPixelShaderKey) { @@ -1047,7 +1248,7 @@ void DynamicHLSL::getPixelShaderOutputKey(const gl::Data &data, // - with a 2.0 context, the output color is broadcast to all channels bool broadcast = metadata.usesBroadcast(data); const unsigned int numRenderTargets = - (broadcast || metadata.usesMultipleFragmentOuts() ? data.caps->maxDrawBuffers : 1); + (broadcast || metadata.usesMultipleFragmentOuts() ? data.getCaps().maxDrawBuffers : 1); if (metadata.getMajorShaderVersion() < 300) { @@ -1069,25 +1270,158 @@ void DynamicHLSL::getPixelShaderOutputKey(const gl::Data &data, const auto &shaderOutputVars = metadata.getFragmentShader()->getData().getActiveOutputVariables(); - for (auto outputPair : programData.getOutputVariables()) + for (size_t outputLocationIndex = 0u; + outputLocationIndex < programData.getOutputLocations().size(); ++outputLocationIndex) { - const VariableLocation &outputLocation = outputPair.second; + const VariableLocation &outputLocation = + programData.getOutputLocations().at(outputLocationIndex); + if (!outputLocation.used()) + { + continue; + } const sh::ShaderVariable &outputVariable = shaderOutputVars[outputLocation.index]; - const std::string &variableName = "out_" + outputLocation.name; + const std::string &variableName = "out_" + outputVariable.name; + + // Fragment outputs can't be arrays of arrays. ESSL 3.10 section 4.3.6. const std::string &elementString = - (outputLocation.element == GL_INVALID_INDEX ? "" : Str(outputLocation.element)); + (outputVariable.isArray() ? Str(outputLocation.arrayIndex) : ""); ASSERT(outputVariable.staticUse); PixelShaderOutputVariable outputKeyVariable; outputKeyVariable.type = outputVariable.type; outputKeyVariable.name = variableName + elementString; - outputKeyVariable.source = variableName + ArrayString(outputLocation.element); - outputKeyVariable.outputIndex = outputPair.first; + outputKeyVariable.source = + variableName + + (outputVariable.isArray() ? ArrayString(outputLocation.arrayIndex) : ""); + outputKeyVariable.outputIndex = outputLocationIndex; outPixelShaderKey->push_back(outputKeyVariable); } } } +// BuiltinVarying Implementation. +BuiltinVarying::BuiltinVarying() : enabled(false), index(0), systemValue(false) +{ +} + +std::string BuiltinVarying::str() const +{ + return (systemValue ? semantic : (semantic + Str(index))); +} + +void BuiltinVarying::enableSystem(const std::string &systemValueSemantic) +{ + enabled = true; + semantic = systemValueSemantic; + systemValue = true; +} + +void BuiltinVarying::enable(const std::string &semanticVal, unsigned int indexVal) +{ + enabled = true; + semantic = semanticVal; + index = indexVal; +} + +// BuiltinVaryingsD3D Implementation. +BuiltinVaryingsD3D::BuiltinVaryingsD3D(const ProgramD3DMetadata &metadata, + const VaryingPacking &packing) +{ + updateBuiltins(gl::SHADER_VERTEX, metadata, packing); + updateBuiltins(gl::SHADER_FRAGMENT, metadata, packing); + if (metadata.getRendererMajorShaderModel() >= 4) + { + updateBuiltins(gl::SHADER_GEOMETRY, metadata, packing); + } +} + +BuiltinVaryingsD3D::~BuiltinVaryingsD3D() = default; + +void BuiltinVaryingsD3D::updateBuiltins(gl::ShaderType shaderType, + const ProgramD3DMetadata &metadata, + const VaryingPacking &packing) +{ + const std::string &userSemantic = GetVaryingSemantic(metadata.getRendererMajorShaderModel(), + metadata.usesSystemValuePointSize()); + + unsigned int reservedSemanticIndex = packing.getMaxSemanticIndex(); + + BuiltinInfo *builtins = &mBuiltinInfo[shaderType]; + + if (metadata.getRendererMajorShaderModel() >= 4) + { + builtins->dxPosition.enableSystem("SV_Position"); + } + else if (shaderType == gl::SHADER_FRAGMENT) + { + builtins->dxPosition.enableSystem("VPOS"); + } + else + { + builtins->dxPosition.enableSystem("POSITION"); + } + + if (metadata.usesTransformFeedbackGLPosition()) + { + builtins->glPosition.enable(userSemantic, reservedSemanticIndex++); + } + + if (metadata.usesFragCoord()) + { + builtins->glFragCoord.enable(userSemantic, reservedSemanticIndex++); + } + + if (shaderType == gl::SHADER_VERTEX ? metadata.addsPointCoordToVertexShader() + : metadata.usesPointCoord()) + { + // SM3 reserves the TEXCOORD semantic for point sprite texcoords (gl_PointCoord) + // In D3D11 we manually compute gl_PointCoord in the GS. + if (metadata.getRendererMajorShaderModel() >= 4) + { + builtins->glPointCoord.enable(userSemantic, reservedSemanticIndex++); + } + else + { + builtins->glPointCoord.enable("TEXCOORD", 0); + } + } + + if (shaderType == gl::SHADER_VERTEX && metadata.hasANGLEMultiviewEnabled()) + { + builtins->glViewIDOVR.enable(userSemantic, reservedSemanticIndex++); + if (metadata.canSelectViewInVertexShader()) + { + builtins->glViewportIndex.enableSystem("SV_ViewportArrayIndex"); + builtins->glLayer.enableSystem("SV_RenderTargetArrayIndex"); + } + } + + if (shaderType == gl::SHADER_FRAGMENT && metadata.hasANGLEMultiviewEnabled()) + { + builtins->glViewIDOVR.enable(userSemantic, reservedSemanticIndex++); + } + + if (shaderType == gl::SHADER_GEOMETRY && metadata.hasANGLEMultiviewEnabled()) + { + // Although it is possible to retrieve gl_ViewID_OVR from the value of + // SV_ViewportArrayIndex or SV_RenderTargetArrayIndex based on the multi-view state in the + // driver constant buffer, it is easier and cleaner to pass it as a varying. + builtins->glViewIDOVR.enable(userSemantic, reservedSemanticIndex++); + + // gl_Layer and gl_ViewportIndex are necessary so that we can write to either based on the + // multiview state in the driver constant buffer. + builtins->glViewportIndex.enableSystem("SV_ViewportArrayIndex"); + builtins->glLayer.enableSystem("SV_RenderTargetArrayIndex"); + } + + // Special case: do not include PSIZE semantic in HLSL 3 pixel shaders + if (metadata.usesSystemValuePointSize() && + (shaderType != gl::SHADER_FRAGMENT || metadata.getRendererMajorShaderModel() >= 4)) + { + builtins->glPointSize.enableSystem("PSIZE"); + } +} + } // namespace rx diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/DynamicHLSL.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/DynamicHLSL.h index 69d941c06a..fe8d9cb0a3 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/DynamicHLSL.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/DynamicHLSL.h @@ -16,6 +16,7 @@ #include "common/angleutils.h" #include "libANGLE/Constants.h" #include "libANGLE/Program.h" +#include "libANGLE/angletypes.h" #include "libANGLE/formatutils.h" #include "libANGLE/renderer/d3d/RendererD3D.h" @@ -29,23 +30,88 @@ namespace gl { class InfoLog; struct VariableLocation; +class VaryingPacking; struct VertexAttribute; -struct Data; } namespace rx { -struct PackedVarying; class ProgramD3DMetadata; class ShaderD3D; -class VaryingPacking; struct PixelShaderOutputVariable { - GLenum type; + PixelShaderOutputVariable() {} + PixelShaderOutputVariable(GLenum typeIn, + const std::string &nameIn, + const std::string &sourceIn, + size_t outputIndexIn) + : type(typeIn), name(nameIn), source(sourceIn), outputIndex(outputIndexIn) + { + } + + GLenum type = GL_NONE; std::string name; std::string source; - size_t outputIndex; + size_t outputIndex = 0; +}; + +struct BuiltinVarying final : private angle::NonCopyable +{ + BuiltinVarying(); + + std::string str() const; + void enableSystem(const std::string &systemValueSemantic); + void enable(const std::string &semanticVal, unsigned int indexVal); + + bool enabled; + std::string semantic; + unsigned int index; + bool systemValue; +}; + +struct BuiltinInfo +{ + BuiltinInfo(); + ~BuiltinInfo(); + + BuiltinVarying dxPosition; + BuiltinVarying glPosition; + BuiltinVarying glFragCoord; + BuiltinVarying glPointCoord; + BuiltinVarying glPointSize; + BuiltinVarying glViewIDOVR; + BuiltinVarying glViewportIndex; + BuiltinVarying glLayer; +}; + +inline std::string GetVaryingSemantic(int majorShaderModel, bool programUsesPointSize) +{ + // SM3 reserves the TEXCOORD semantic for point sprite texcoords (gl_PointCoord) + // In D3D11 we manually compute gl_PointCoord in the GS. + return ((programUsesPointSize && majorShaderModel < 4) ? "COLOR" : "TEXCOORD"); +} + +class BuiltinVaryingsD3D +{ + public: + BuiltinVaryingsD3D(const ProgramD3DMetadata &metadata, const gl::VaryingPacking &packing); + ~BuiltinVaryingsD3D(); + + bool usesPointSize() const { return mBuiltinInfo[gl::SHADER_VERTEX].glPointSize.enabled; } + + const BuiltinInfo &operator[](gl::ShaderType shaderType) const + { + return mBuiltinInfo[shaderType]; + } + BuiltinInfo &operator[](gl::ShaderType shaderType) { return mBuiltinInfo[shaderType]; } + + private: + void updateBuiltins(gl::ShaderType shaderType, + const ProgramD3DMetadata &metadata, + const gl::VaryingPacking &packing); + + std::array mBuiltinInfo; }; class DynamicHLSL : angle::NonCopyable @@ -62,43 +128,48 @@ class DynamicHLSL : angle::NonCopyable const std::vector &outputVariables, bool usesFragDepth, const std::vector &outputLayout) const; - bool generateShaderLinkHLSL(const gl::Data &data, - const gl::Program::Data &programData, + void generateShaderLinkHLSL(const gl::Context *context, + const gl::ProgramState &programData, const ProgramD3DMetadata &programMetadata, - const VaryingPacking &varyingPacking, + const gl::VaryingPacking &varyingPacking, + const BuiltinVaryingsD3D &builtinsD3D, std::string *pixelHLSL, std::string *vertexHLSL) const; + std::string generateComputeShaderLinkHLSL(const gl::Context *context, + const gl::ProgramState &programData) const; - std::string generateGeometryShaderPreamble(const VaryingPacking &varyingPacking) const; + std::string generateGeometryShaderPreamble(const gl::VaryingPacking &varyingPacking, + const BuiltinVaryingsD3D &builtinsD3D, + const bool hasANGLEMultiviewEnabled, + const bool selectViewInVS) const; - std::string generateGeometryShaderHLSL(gl::PrimitiveType primitiveType, - const gl::Data &data, - const gl::Program::Data &programData, + std::string generateGeometryShaderHLSL(const gl::Context *context, + gl::PrimitiveType primitiveType, + const gl::ProgramState &programData, const bool useViewScale, + const bool hasANGLEMultiviewEnabled, + const bool selectViewInVS, + const bool pointSpriteEmulation, const std::string &preambleString) const; - void getPixelShaderOutputKey(const gl::Data &data, - const gl::Program::Data &programData, + void getPixelShaderOutputKey(const gl::ContextState &data, + const gl::ProgramState &programData, const ProgramD3DMetadata &metadata, std::vector *outPixelShaderKey); private: RendererD3D *const mRenderer; - void generateVaryingLinkHLSL(ShaderType shaderType, - const VaryingPacking &varyingPacking, - std::stringstream &linkStream) const; - void generateVaryingHLSL(const VaryingPacking &varyingPacking, - std::stringstream &hlslStream) const; - - // Prepend an underscore - static std::string decorateVariable(const std::string &name); + void generateVaryingLinkHLSL(const gl::VaryingPacking &varyingPacking, + const BuiltinInfo &builtins, + bool programUsesPointSize, + std::ostringstream &hlslStream) const; - std::string generateAttributeConversionHLSL(gl::VertexFormatType vertexFormatType, - const sh::ShaderVariable &shaderAttrib) const; + static void GenerateAttributeConversionHLSL(gl::VertexFormatType vertexFormatType, + const sh::ShaderVariable &shaderAttrib, + std::ostringstream &outStream); }; -std::string GetVaryingSemantic(int majorShaderModel, bool programUsesPointSize); -} +} // namespace rx #endif // LIBANGLE_RENDERER_D3D_DYNAMICHLSL_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/EGLImageD3D.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/EGLImageD3D.cpp index ca4b16987f..fcc2456bd6 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/EGLImageD3D.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/EGLImageD3D.cpp @@ -22,46 +22,14 @@ namespace rx { -static gl::ImageIndex GetImageIndex(GLenum target, size_t mip, size_t layer) -{ - if (target == GL_TEXTURE_3D) - { - return gl::ImageIndex::Make3D(static_cast(mip), static_cast(layer)); - } - else - { - ASSERT(layer == 0); - return gl::ImageIndex::MakeGeneric(target, static_cast(mip)); - } -} -EGLImageD3D::EGLImageD3D(RendererD3D *renderer, +EGLImageD3D::EGLImageD3D(const egl::ImageState &state, EGLenum target, - egl::ImageSibling *buffer, - const egl::AttributeMap &attribs) - : mRenderer(renderer), mBuffer(buffer), mAttachmentBuffer(nullptr), mRenderTarget(nullptr) + const egl::AttributeMap &attribs, + RendererD3D *renderer) + : ImageImpl(state), mRenderer(renderer), mRenderTarget(nullptr) { ASSERT(renderer != nullptr); - ASSERT(buffer != nullptr); - - if (egl::IsTextureTarget(target)) - { - mAttachmentBuffer = GetImplAs(GetAs(buffer)); - mAttachmentTarget = gl::FramebufferAttachment::Target( - GL_NONE, GetImageIndex(egl_gl::EGLImageTargetToGLTextureTarget(target), - attribs.get(EGL_GL_TEXTURE_LEVEL_KHR, 0), - attribs.get(EGL_GL_TEXTURE_ZOFFSET_KHR, 0))); - } - else if (egl::IsRenderbufferTarget(target)) - { - mAttachmentBuffer = GetImplAs(GetAs(buffer)); - mAttachmentTarget = - gl::FramebufferAttachment::Target(GL_NONE, gl::ImageIndex::MakeInvalid()); - } - else - { - UNREACHABLE(); - } } EGLImageD3D::~EGLImageD3D() @@ -71,62 +39,49 @@ EGLImageD3D::~EGLImageD3D() egl::Error EGLImageD3D::initialize() { - return egl::Error(EGL_SUCCESS); + return egl::NoError(); } -gl::Error EGLImageD3D::orphan(egl::ImageSibling *sibling) +gl::Error EGLImageD3D::orphan(const gl::Context *context, egl::ImageSibling *sibling) { - if (sibling == mBuffer) + if (sibling == mState.source.get()) { - gl::Error error = copyToLocalRendertarget(); - if (error.isError()) - { - return error; - } + ANGLE_TRY(copyToLocalRendertarget(context)); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error EGLImageD3D::getRenderTarget(RenderTargetD3D **outRT) const +gl::Error EGLImageD3D::getRenderTarget(const gl::Context *context, RenderTargetD3D **outRT) const { - if (mAttachmentBuffer) + if (mState.source.get()) { + ASSERT(!mRenderTarget); FramebufferAttachmentRenderTarget *rt = nullptr; - gl::Error error = mAttachmentBuffer->getAttachmentRenderTarget(mAttachmentTarget, &rt); - if (error.isError()) - { - return error; - } - + ANGLE_TRY( + mState.source->getAttachmentRenderTarget(context, GL_NONE, mState.imageIndex, &rt)); *outRT = static_cast(rt); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } else { ASSERT(mRenderTarget); *outRT = mRenderTarget; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } } -gl::Error EGLImageD3D::copyToLocalRendertarget() +gl::Error EGLImageD3D::copyToLocalRendertarget(const gl::Context *context) { - ASSERT(mBuffer != nullptr); - ASSERT(mAttachmentBuffer != nullptr); + ASSERT(mState.source.get() != nullptr); ASSERT(mRenderTarget == nullptr); RenderTargetD3D *curRenderTarget = nullptr; - gl::Error error = getRenderTarget(&curRenderTarget); - if (error.isError()) - { - return error; - } + ANGLE_TRY(getRenderTarget(context, &curRenderTarget)); - // Clear the source image buffers - mBuffer = nullptr; - mAttachmentBuffer = nullptr; + // This only currently applies do D3D11, where it invalidates FBOs with this Image attached. + curRenderTarget->signalDirty(context); return mRenderer->createRenderTargetCopy(curRenderTarget, &mRenderTarget); } -} +} // namespace rx diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/EGLImageD3D.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/EGLImageD3D.h index 6ec33e08f2..1ee7984426 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/EGLImageD3D.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/EGLImageD3D.h @@ -9,9 +9,13 @@ #ifndef LIBANGLE_RENDERER_D3D_EGLIMAGED3D_H_ #define LIBANGLE_RENDERER_D3D_EGLIMAGED3D_H_ -#include "libANGLE/FramebufferAttachment.h" #include "libANGLE/renderer/ImageImpl.h" +namespace gl +{ +class Context; +} + namespace egl { class AttributeMap; @@ -19,6 +23,7 @@ class AttributeMap; namespace rx { +class FramebufferAttachmentObjectImpl; class TextureD3D; class RenderbufferD3D; class RendererD3D; @@ -27,30 +32,24 @@ class RenderTargetD3D; class EGLImageD3D final : public ImageImpl { public: - EGLImageD3D(RendererD3D *renderer, + EGLImageD3D(const egl::ImageState &state, EGLenum target, - egl::ImageSibling *buffer, - const egl::AttributeMap &attribs); + const egl::AttributeMap &attribs, + RendererD3D *renderer); ~EGLImageD3D() override; egl::Error initialize() override; - gl::Error orphan(egl::ImageSibling *sibling) override; + gl::Error orphan(const gl::Context *context, egl::ImageSibling *sibling) override; - gl::Error getRenderTarget(RenderTargetD3D **outRT) const; + gl::Error getRenderTarget(const gl::Context *context, RenderTargetD3D **outRT) const; private: - gl::Error copyToLocalRendertarget(); + gl::Error copyToLocalRendertarget(const gl::Context *context); RendererD3D *mRenderer; - - egl::ImageSibling *mBuffer; - - gl::FramebufferAttachment::Target mAttachmentTarget; - FramebufferAttachmentObjectImpl *mAttachmentBuffer; - RenderTargetD3D *mRenderTarget; }; -} +} // namespace rx #endif // LIBANGLE_RENDERER_D3D_EGLIMAGED3D_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/FramebufferD3D.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/FramebufferD3D.cpp index 82967aced0..3d73b2c840 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/FramebufferD3D.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/FramebufferD3D.cpp @@ -8,14 +8,16 @@ #include "libANGLE/renderer/d3d/FramebufferD3D.h" -#include "common/BitSetIterator.h" -#include "libANGLE/formatutils.h" +#include "common/bitset_utils.h" +#include "libANGLE/Context.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/formatutils.h" +#include "libANGLE/renderer/ContextImpl.h" #include "libANGLE/renderer/d3d/RenderTargetD3D.h" +#include "libANGLE/renderer/d3d/RenderbufferD3D.h" +#include "libANGLE/renderer/d3d/RendererD3D.h" #include "libANGLE/renderer/d3d/SurfaceD3D.h" #include "libANGLE/renderer/d3d/SwapChainD3D.h" #include "libANGLE/renderer/d3d/TextureD3D.h" @@ -37,19 +39,19 @@ ClearParameters GetClearParameters(const gl::State &state, GLbitfield mask) { 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.colorF = state.getColorClearValue(); + clearParams.colorType = GL_FLOAT; + clearParams.colorMaskRed = blendState.colorMaskRed; + clearParams.colorMaskGreen = blendState.colorMaskGreen; + clearParams.colorMaskBlue = blendState.colorMaskBlue; + clearParams.colorMaskAlpha = blendState.colorMaskAlpha; + clearParams.clearDepth = false; + clearParams.depthValue = state.getDepthClearValue(); + clearParams.clearStencil = false; + clearParams.stencilValue = state.getStencilClearValue(); clearParams.stencilWriteMask = state.getDepthStencilState().stencilWritemask; - clearParams.scissorEnabled = state.isScissorTestEnabled(); - clearParams.scissor = state.getScissor(); + clearParams.scissorEnabled = state.isScissorTestEnabled(); + clearParams.scissor = state.getScissor(); const gl::Framebuffer *framebufferObject = state.getDrawFramebuffer(); if (mask & GL_COLOR_BUFFER_BIT) @@ -65,7 +67,8 @@ ClearParameters GetClearParameters(const gl::State &state, GLbitfield mask) if (mask & GL_DEPTH_BUFFER_BIT) { - if (state.getDepthStencilState().depthMask && framebufferObject->getDepthbuffer() != NULL) + if (state.getDepthStencilState().depthMask && + framebufferObject->getDepthbuffer() != nullptr) { clearParams.clearDepth = true; } @@ -73,7 +76,7 @@ ClearParameters GetClearParameters(const gl::State &state, GLbitfield mask) if (mask & GL_STENCIL_BUFFER_BIT) { - if (framebufferObject->getStencilbuffer() != NULL && + if (framebufferObject->getStencilbuffer() != nullptr && framebufferObject->getStencilbuffer()->getStencilSize() > 0) { clearParams.clearStencil = true; @@ -82,10 +85,13 @@ ClearParameters GetClearParameters(const gl::State &state, GLbitfield mask) return clearParams; } - } -FramebufferD3D::FramebufferD3D(const gl::Framebuffer::Data &data, RendererD3D *renderer) +ClearParameters::ClearParameters() = default; + +ClearParameters::ClearParameters(const ClearParameters &other) = default; + +FramebufferD3D::FramebufferD3D(const gl::FramebufferState &data, RendererD3D *renderer) : FramebufferImpl(data), mRenderer(renderer) { } @@ -94,20 +100,19 @@ FramebufferD3D::~FramebufferD3D() { } -gl::Error FramebufferD3D::clear(const gl::Data &data, GLbitfield mask) +gl::Error FramebufferD3D::clear(const gl::Context *context, GLbitfield mask) { - const gl::State &state = *data.state; - ClearParameters clearParams = GetClearParameters(state, mask); - return clear(data, clearParams); + ClearParameters clearParams = GetClearParameters(context->getGLState(), mask); + return clearImpl(context, clearParams); } -gl::Error FramebufferD3D::clearBufferfv(const gl::Data &data, +gl::Error FramebufferD3D::clearBufferfv(const gl::Context *context, GLenum buffer, GLint drawbuffer, const GLfloat *values) { // glClearBufferfv can be called to clear the color buffer or depth buffer - ClearParameters clearParams = GetClearParameters(*data.state, 0); + ClearParameters clearParams = GetClearParameters(context->getGLState(), 0); if (buffer == GL_COLOR) { @@ -115,43 +120,43 @@ gl::Error FramebufferD3D::clearBufferfv(const gl::Data &data, { clearParams.clearColor[i] = (drawbuffer == static_cast(i)); } - clearParams.colorFClearValue = gl::ColorF(values[0], values[1], values[2], values[3]); - clearParams.colorClearType = GL_FLOAT; + clearParams.colorF = gl::ColorF(values[0], values[1], values[2], values[3]); + clearParams.colorType = GL_FLOAT; } if (buffer == GL_DEPTH) { clearParams.clearDepth = true; - clearParams.depthClearValue = values[0]; + clearParams.depthValue = values[0]; } - return clear(data, clearParams); + return clearImpl(context, clearParams); } -gl::Error FramebufferD3D::clearBufferuiv(const gl::Data &data, +gl::Error FramebufferD3D::clearBufferuiv(const gl::Context *context, GLenum buffer, GLint drawbuffer, const GLuint *values) { // glClearBufferuiv can only be called to clear a color buffer - ClearParameters clearParams = GetClearParameters(*data.state, 0); + ClearParameters clearParams = GetClearParameters(context->getGLState(), 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; + clearParams.colorUI = gl::ColorUI(values[0], values[1], values[2], values[3]); + clearParams.colorType = GL_UNSIGNED_INT; - return clear(data, clearParams); + return clearImpl(context, clearParams); } -gl::Error FramebufferD3D::clearBufferiv(const gl::Data &data, +gl::Error FramebufferD3D::clearBufferiv(const gl::Context *context, GLenum buffer, GLint drawbuffer, const GLint *values) { // glClearBufferiv can be called to clear the color buffer or stencil buffer - ClearParameters clearParams = GetClearParameters(*data.state, 0); + ClearParameters clearParams = GetClearParameters(context->getGLState(), 0); if (buffer == GL_COLOR) { @@ -159,167 +164,154 @@ gl::Error FramebufferD3D::clearBufferiv(const gl::Data &data, { clearParams.clearColor[i] = (drawbuffer == static_cast(i)); } - clearParams.colorIClearValue = gl::ColorI(values[0], values[1], values[2], values[3]); - clearParams.colorClearType = GL_INT; + clearParams.colorI = gl::ColorI(values[0], values[1], values[2], values[3]); + clearParams.colorType = GL_INT; } if (buffer == GL_STENCIL) { clearParams.clearStencil = true; - clearParams.stencilClearValue = values[1]; + clearParams.stencilValue = values[0]; } - return clear(data, clearParams); + return clearImpl(context, clearParams); } -gl::Error FramebufferD3D::clearBufferfi(const gl::Data &data, +gl::Error FramebufferD3D::clearBufferfi(const gl::Context *context, GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil) { // glClearBufferfi can only be called to clear a depth stencil buffer - ClearParameters clearParams = GetClearParameters(*data.state, 0); - clearParams.clearDepth = true; - clearParams.depthClearValue = depth; - clearParams.clearStencil = true; - clearParams.stencilClearValue = stencil; + ClearParameters clearParams = GetClearParameters(context->getGLState(), 0); + clearParams.clearDepth = true; + clearParams.depthValue = depth; + clearParams.clearStencil = true; + clearParams.stencilValue = stencil; - return clear(data, clearParams); + return clearImpl(context, clearParams); } -GLenum FramebufferD3D::getImplementationColorReadFormat() const +GLenum FramebufferD3D::getImplementationColorReadFormat(const gl::Context *context) const { - const gl::FramebufferAttachment *readAttachment = mData.getReadAttachment(); + const gl::FramebufferAttachment *readAttachment = mState.getReadAttachment(); if (readAttachment == nullptr) { return GL_NONE; } - RenderTargetD3D *attachmentRenderTarget = NULL; - gl::Error error = readAttachment->getRenderTarget(&attachmentRenderTarget); + RenderTargetD3D *attachmentRenderTarget = nullptr; + gl::Error error = readAttachment->getRenderTarget(context, &attachmentRenderTarget); if (error.isError()) { return GL_NONE; } GLenum implementationFormat = getRenderTargetImplementationFormat(attachmentRenderTarget); - const gl::InternalFormat &implementationFormatInfo = gl::GetInternalFormatInfo(implementationFormat); + const gl::InternalFormat &implementationFormatInfo = + gl::GetSizedInternalFormatInfo(implementationFormat); - return implementationFormatInfo.format; + return implementationFormatInfo.getReadPixelsFormat(); } -GLenum FramebufferD3D::getImplementationColorReadType() const +GLenum FramebufferD3D::getImplementationColorReadType(const gl::Context *context) const { - const gl::FramebufferAttachment *readAttachment = mData.getReadAttachment(); + const gl::FramebufferAttachment *readAttachment = mState.getReadAttachment(); if (readAttachment == nullptr) { return GL_NONE; } - RenderTargetD3D *attachmentRenderTarget = NULL; - gl::Error error = readAttachment->getRenderTarget(&attachmentRenderTarget); + RenderTargetD3D *attachmentRenderTarget = nullptr; + gl::Error error = readAttachment->getRenderTarget(context, &attachmentRenderTarget); if (error.isError()) { return GL_NONE; } GLenum implementationFormat = getRenderTargetImplementationFormat(attachmentRenderTarget); - const gl::InternalFormat &implementationFormatInfo = gl::GetInternalFormatInfo(implementationFormat); + const gl::InternalFormat &implementationFormatInfo = + gl::GetSizedInternalFormatInfo(implementationFormat); - return implementationFormatInfo.type; + return implementationFormatInfo.getReadPixelsType(context->getClientVersion()); } -gl::Error FramebufferD3D::readPixels(const gl::State &state, const gl::Rectangle &area, GLenum format, GLenum type, GLvoid *pixels) const +gl::Error FramebufferD3D::readPixels(const gl::Context *context, + const gl::Rectangle &origArea, + GLenum format, + GLenum type, + void *pixels) { - const gl::PixelPackState &packState = state.getPackState(); - - GLenum sizedInternalFormat = gl::GetSizedInternalFormat(format, type); - const gl::InternalFormat &sizedFormatInfo = gl::GetInternalFormatInfo(sizedInternalFormat); - GLuint outputPitch = - sizedFormatInfo.computeRowPitch(type, area.width, packState.alignment, packState.rowLength); - GLsizei outputSkipBytes = sizedFormatInfo.computeSkipPixels( - outputPitch, 0, 0, packState.skipRows, packState.skipPixels); - - return readPixelsImpl(area, format, type, outputPitch, packState, - reinterpret_cast(pixels) + outputSkipBytes); -} - -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) + // Clip read area to framebuffer. + const gl::Extents fbSize = getState().getReadAttachment()->getSize(); + const gl::Rectangle fbRect(0, 0, fbSize.width, fbSize.height); + gl::Rectangle area; + if (!ClipRectangle(origArea, fbRect, &area)) { - blitRenderTarget = true; + // nothing to read + return gl::NoError(); } - bool blitStencil = false; - if ((mask & GL_STENCIL_BUFFER_BIT) && - sourceFramebuffer->getStencilbuffer() != nullptr && - mData.getStencilAttachment() != nullptr) - { - blitStencil = true; - } + const gl::PixelPackState &packState = context->getGLState().getPackState(); - bool blitDepth = false; - if ((mask & GL_DEPTH_BUFFER_BIT) && - sourceFramebuffer->getDepthbuffer() != nullptr && - mData.getDepthAttachment() != nullptr) - { - blitDepth = true; - } + const gl::InternalFormat &sizedFormatInfo = gl::GetInternalFormatInfo(format, type); - 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; - } - } + GLuint outputPitch = 0; + ANGLE_TRY_RESULT(sizedFormatInfo.computeRowPitch(type, origArea.width, packState.alignment, + packState.rowLength), + outputPitch); + GLuint outputSkipBytes = 0; + ANGLE_TRY_RESULT(sizedFormatInfo.computeSkipBytes(outputPitch, 0, packState, false), + outputSkipBytes); + outputSkipBytes += + (area.x - origArea.x) * sizedFormatInfo.pixelBytes + (area.y - origArea.y) * outputPitch; + + return readPixelsImpl(context, area, format, type, outputPitch, packState, + reinterpret_cast(pixels) + outputSkipBytes); +} - return gl::Error(GL_NO_ERROR); +gl::Error FramebufferD3D::blit(const gl::Context *context, + const gl::Rectangle &sourceArea, + const gl::Rectangle &destArea, + GLbitfield mask, + GLenum filter) +{ + const auto &glState = context->getGLState(); + const gl::Framebuffer *sourceFramebuffer = glState.getReadFramebuffer(); + const gl::Rectangle *scissor = glState.isScissorTestEnabled() ? &glState.getScissor() : nullptr; + ANGLE_TRY(blitImpl(context, sourceArea, destArea, scissor, (mask & GL_COLOR_BUFFER_BIT) != 0, + (mask & GL_DEPTH_BUFFER_BIT) != 0, (mask & GL_STENCIL_BUFFER_BIT) != 0, + filter, sourceFramebuffer)); + + return gl::NoError(); } -bool FramebufferD3D::checkStatus() const +bool FramebufferD3D::checkStatus(const gl::Context *context) const { // 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 (mData.getDepthAttachment() != nullptr && mData.getStencilAttachment() != nullptr && - mData.getDepthStencilAttachment() == nullptr) + if (mState.getDepthAttachment() != nullptr && mState.getStencilAttachment() != nullptr && + mState.getDepthStencilAttachment() == nullptr) { return false; } - // D3D11 does not allow for overlapping RenderTargetViews, so ensure uniqueness - const auto &colorAttachments = mData.getColorAttachments(); - for (size_t colorAttachment = 0; colorAttachment < colorAttachments.size(); colorAttachment++) + // D3D11 does not allow for overlapping RenderTargetViews. + // If WebGL compatibility is enabled, this has already been checked at a higher level. + ASSERT(!context->getExtensions().webglCompatibility || mState.colorAttachmentsAreUniqueImages()); + if (!context->getExtensions().webglCompatibility) { - const gl::FramebufferAttachment &attachment = colorAttachments[colorAttachment]; - if (attachment.isAttached()) + if (!mState.colorAttachmentsAreUniqueImages()) { - for (size_t prevColorAttachment = 0; prevColorAttachment < colorAttachment; prevColorAttachment++) - { - const gl::FramebufferAttachment &prevAttachment = colorAttachments[prevColorAttachment]; - if (prevAttachment.isAttached() && - (attachment.id() == prevAttachment.id() && - attachment.type() == prevAttachment.type())) - { - return false; - } - } + return false; } } // D3D requires all render targets to have the same dimensions. - if (!mData.attachmentsHaveSameDimensions()) + if (!mState.attachmentsHaveSameDimensions()) { return false; } @@ -327,45 +319,52 @@ bool FramebufferD3D::checkStatus() const return true; } -void FramebufferD3D::syncState(const gl::Framebuffer::DirtyBits &dirtyBits) +void FramebufferD3D::syncState(const gl::Context *context, + const gl::Framebuffer::DirtyBits &dirtyBits) { - bool invalidateColorAttachmentCache = false; - if (!mColorAttachmentsForRender.valid()) { - invalidateColorAttachmentCache = true; + return; } - for (auto dirtyBit : angle::IterateBitSet(dirtyBits)) + for (auto dirtyBit : dirtyBits) { if ((dirtyBit >= gl::Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_0 && dirtyBit < gl::Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_MAX) || dirtyBit == gl::Framebuffer::DIRTY_BIT_DRAW_BUFFERS) { - invalidateColorAttachmentCache = true; + mColorAttachmentsForRender.reset(); } } +} - if (!invalidateColorAttachmentCache) +const gl::AttachmentList &FramebufferD3D::getColorAttachmentsForRender(const gl::Context *context) +{ + gl::DrawBufferMask activeProgramOutputs = + context->getContextState().getState().getProgram()->getActiveOutputVariables(); + + if (mColorAttachmentsForRender.valid() && mCurrentActiveProgramOutputs == activeProgramOutputs) { - return; + return mColorAttachmentsForRender.value(); } // Does not actually free memory gl::AttachmentList colorAttachmentsForRender; - const auto &colorAttachments = mData.getColorAttachments(); - const auto &drawBufferStates = mData.getDrawBufferStates(); + const auto &colorAttachments = mState.getColorAttachments(); + const auto &drawBufferStates = mState.getDrawBufferStates(); const auto &workarounds = mRenderer->getWorkarounds(); for (size_t attachmentIndex = 0; attachmentIndex < colorAttachments.size(); ++attachmentIndex) { - GLenum drawBufferState = drawBufferStates[attachmentIndex]; + GLenum drawBufferState = drawBufferStates[attachmentIndex]; const gl::FramebufferAttachment &colorAttachment = colorAttachments[attachmentIndex]; - if (colorAttachment.isAttached() && drawBufferState != GL_NONE) + if (colorAttachment.isAttached() && drawBufferState != GL_NONE && + activeProgramOutputs[attachmentIndex]) { - ASSERT(drawBufferState == GL_BACK || drawBufferState == (GL_COLOR_ATTACHMENT0_EXT + attachmentIndex)); + ASSERT(drawBufferState == GL_BACK || + drawBufferState == (GL_COLOR_ATTACHMENT0_EXT + attachmentIndex)); colorAttachmentsForRender.push_back(&colorAttachment); } else if (!workarounds.mrtPerfWorkaround) @@ -374,12 +373,32 @@ void FramebufferD3D::syncState(const gl::Framebuffer::DirtyBits &dirtyBits) } } + // When rendering with no render target on D3D, two bugs lead to incorrect behavior on Intel + // drivers < 4815. The rendering samples always pass neglecting discard statements in pixel + // shader. We add a dummy texture as render target in such case. + if (mRenderer->getWorkarounds().addDummyTextureNoRenderTarget && + colorAttachmentsForRender.empty()) + { + static_assert(static_cast(activeProgramOutputs.size()) <= 32, + "Size of active program outputs should less or equal than 32."); + GLenum i = static_cast( + gl::ScanForward(static_cast(activeProgramOutputs.bits()))); + + gl::Texture *dummyTex = nullptr; + // TODO(Jamie): Handle error if dummy texture can't be created. + ANGLE_SWALLOW_ERR(mRenderer->getIncompleteTexture(context, GL_TEXTURE_2D, &dummyTex)); + if (dummyTex) + { + gl::ImageIndex index = gl::ImageIndex::Make2D(0); + gl::FramebufferAttachment *dummyAttach = new gl::FramebufferAttachment( + context, GL_TEXTURE, GL_COLOR_ATTACHMENT0_EXT + i, index, dummyTex); + colorAttachmentsForRender.push_back(dummyAttach); + } + } + mColorAttachmentsForRender = std::move(colorAttachmentsForRender); -} + mCurrentActiveProgramOutputs = activeProgramOutputs; -const gl::AttachmentList &FramebufferD3D::getColorAttachmentsForRender() const -{ - ASSERT(mColorAttachmentsForRender.valid()); return mColorAttachmentsForRender.value(); } diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/FramebufferD3D.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/FramebufferD3D.h index eb839c4364..a7312fdef4 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/FramebufferD3D.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/FramebufferD3D.h @@ -9,9 +9,10 @@ #ifndef LIBANGLE_RENDERER_D3D_FRAMBUFFERD3D_H_ #define LIBANGLE_RENDERER_D3D_FRAMBUFFERD3D_H_ -#include #include +#include +#include "common/Color.h" #include "common/Optional.h" #include "libANGLE/angletypes.h" #include "libANGLE/renderer/FramebufferImpl.h" @@ -22,32 +23,33 @@ class FramebufferAttachment; struct PixelPackState; typedef std::vector AttachmentList; - } namespace rx { class RendererD3D; class RenderTargetD3D; -struct WorkaroundsD3D; struct ClearParameters { + ClearParameters(); + ClearParameters(const ClearParameters &other); + bool clearColor[gl::IMPLEMENTATION_MAX_DRAW_BUFFERS]; - gl::ColorF colorFClearValue; - gl::ColorI colorIClearValue; - gl::ColorUI colorUIClearValue; - GLenum colorClearType; + gl::ColorF colorF; + gl::ColorI colorI; + gl::ColorUI colorUI; + GLenum colorType; bool colorMaskRed; bool colorMaskGreen; bool colorMaskBlue; bool colorMaskAlpha; bool clearDepth; - float depthClearValue; + float depthValue; bool clearStencil; - GLint stencilClearValue; + GLint stencilValue; GLuint stencilWriteMask; bool scissorEnabled; @@ -57,61 +59,76 @@ struct ClearParameters class FramebufferD3D : public FramebufferImpl { public: - FramebufferD3D(const gl::Framebuffer::Data &data, RendererD3D *renderer); - virtual ~FramebufferD3D(); + FramebufferD3D(const gl::FramebufferState &data, RendererD3D *renderer); + ~FramebufferD3D() override; - gl::Error clear(const gl::Data &data, GLbitfield mask) override; - gl::Error clearBufferfv(const gl::Data &data, + gl::Error clear(const gl::Context *context, GLbitfield mask) override; + gl::Error clearBufferfv(const gl::Context *context, GLenum buffer, GLint drawbuffer, const GLfloat *values) override; - gl::Error clearBufferuiv(const gl::Data &data, + gl::Error clearBufferuiv(const gl::Context *context, GLenum buffer, GLint drawbuffer, const GLuint *values) override; - gl::Error clearBufferiv(const gl::Data &data, + gl::Error clearBufferiv(const gl::Context *context, GLenum buffer, GLint drawbuffer, const GLint *values) override; - gl::Error clearBufferfi(const gl::Data &data, + gl::Error clearBufferfi(const gl::Context *context, 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; + GLenum getImplementationColorReadFormat(const gl::Context *context) const override; + GLenum getImplementationColorReadType(const gl::Context *context) const override; + gl::Error readPixels(const gl::Context *context, + const gl::Rectangle &area, + GLenum format, + GLenum type, + void *pixels) 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; + gl::Error blit(const gl::Context *context, + const gl::Rectangle &sourceArea, + const gl::Rectangle &destArea, + GLbitfield mask, + GLenum filter) override; - bool checkStatus() const override; + bool checkStatus(const gl::Context *context) const override; - void syncState(const gl::Framebuffer::DirtyBits &dirtyBits) override; + void syncState(const gl::Context *context, + const gl::Framebuffer::DirtyBits &dirtyBits) override; - const gl::AttachmentList &getColorAttachmentsForRender() const; + const gl::AttachmentList &getColorAttachmentsForRender(const gl::Context *context); private: - virtual gl::Error clear(const gl::Data &data, const ClearParameters &clearParams) = 0; + virtual gl::Error clearImpl(const gl::Context *context, const ClearParameters &clearParams) = 0; - virtual gl::Error readPixelsImpl(const gl::Rectangle &area, + virtual gl::Error readPixelsImpl(const gl::Context *context, + 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; + uint8_t *pixels) = 0; + + virtual gl::Error blitImpl(const gl::Context *context, + 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; RendererD3D *mRenderer; Optional mColorAttachmentsForRender; + gl::DrawBufferMask mCurrentActiveProgramOutputs; }; - } -#endif // LIBANGLE_RENDERER_D3D_FRAMBUFFERD3D_H_ +#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 index df0257e370..b38765070b 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/HLSLCompiler.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/HLSLCompiler.cpp @@ -6,16 +6,14 @@ #include "libANGLE/renderer/d3d/HLSLCompiler.h" +#include + #include "common/utilities.h" #include "libANGLE/Program.h" #include "libANGLE/features.h" #include "libANGLE/histogram_macros.h" #include "third_party/trace_event/trace_event.h" -#ifndef QT_D3DCOMPILER_DLL -#define QT_D3DCOMPILER_DLL D3DCOMPILER_DLL -#endif - #if ANGLE_APPEND_ASSEMBLY_TO_SHADER_DEBUG_INFO == ANGLE_ENABLED namespace { @@ -25,15 +23,6 @@ namespace #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; @@ -119,11 +108,11 @@ HLSLCompiler::~HLSLCompiler() release(); } -gl::Error HLSLCompiler::initialize() +gl::Error HLSLCompiler::ensureInitialized() { if (mInitialized) { - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } TRACE_EVENT0("gpu.angle", "HLSLCompiler::initialize"); @@ -141,28 +130,6 @@ gl::Error HLSLCompiler::initialize() } #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. @@ -171,7 +138,8 @@ gl::Error HLSLCompiler::initialize() if (!mD3DCompilerModule) { - return gl::Error(GL_INVALID_OPERATION, "No D3D compiler module found - aborting!\n"); + ERR() << "D3D compiler module not found."; + return gl::OutOfMemory() << "D3D compiler module not found."; } mD3DCompileFunc = reinterpret_cast(GetProcAddress(mD3DCompilerModule, "D3DCompile")); @@ -190,11 +158,11 @@ gl::Error HLSLCompiler::initialize() if (mD3DCompileFunc == nullptr) { - return gl::Error(GL_INVALID_OPERATION, "Error finding D3DCompile entry point"); + return gl::OutOfMemory() << "Error finding D3DCompile entry point."; } mInitialized = true; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } void HLSLCompiler::release() @@ -213,11 +181,7 @@ gl::Error HLSLCompiler::compileToBinary(gl::InfoLog &infoLog, const std::string const std::vector &configs, const D3D_SHADER_MACRO *overrideMacros, ID3DBlob **outCompiledBlob, std::string *outDebugInfo) { - gl::Error error = initialize(); - if (error.isError()) - { - return error; - } + ASSERT(mInitialized); #if !defined(ANGLE_ENABLE_WINDOWS_STORE) ASSERT(mD3DCompilerModule); @@ -228,7 +192,9 @@ gl::Error HLSLCompiler::compileToBinary(gl::InfoLog &infoLog, const std::string if (gl::DebugAnnotationsActive()) { std::string sourcePath = getTempPath(); - std::string sourceText = FormatString("#line 2 \"%s\"\n\n%s", sourcePath.c_str(), hlsl.c_str()); + std::ostringstream stream; + stream << "#line 2 \"" << sourcePath << "\"\n\n" << hlsl; + std::string sourceText = stream.str(); writeFile(sourcePath.c_str(), sourceText.c_str(), sourceText.size()); } #endif @@ -255,8 +221,11 @@ gl::Error HLSLCompiler::compileToBinary(gl::InfoLog &infoLog, const std::string SafeRelease(errorMessage); infoLog.appendSanitized(message.c_str()); - TRACE("\n%s", hlsl.c_str()); - TRACE("\n%s", message.c_str()); + + // This produces unbelievable amounts of spam in about:gpu. + // WARN() << std::endl << hlsl; + + WARN() << std::endl << message; 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", @@ -304,20 +273,17 @@ gl::Error HLSLCompiler::compileToBinary(gl::InfoLog &infoLog, const std::string } std::string disassembly; - error = disassembleBinary(binary, &disassembly); - if (error.isError()) - { - return error; - } + ANGLE_TRY(disassembleBinary(binary, &disassembly)); (*outDebugInfo) += "\n" + disassembly + "\n// ASSEMBLY END\n"; #endif // ANGLE_APPEND_ASSEMBLY_TO_SHADER_DEBUG_INFO == ANGLE_ENABLED - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } if (result == E_OUTOFMEMORY) { *outCompiledBlob = nullptr; - return gl::Error(GL_OUT_OF_MEMORY, "HLSL compiler had an unexpected failure, result: 0x%X.", result); + return gl::OutOfMemory() + << "HLSL compiler had an unexpected failure, " << gl::FmtHR(result); } infoLog << "Warning: D3D shader compilation failed with " << configs[i].name << " flags. (" @@ -331,16 +297,12 @@ gl::Error HLSLCompiler::compileToBinary(gl::InfoLog &infoLog, const std::string // None of the configurations succeeded in compiling this shader but the compiler is still intact *outCompiledBlob = nullptr; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } gl::Error HLSLCompiler::disassembleBinary(ID3DBlob *shaderBinary, std::string *disassemblyOut) { - gl::Error error = initialize(); - if (error.isError()) - { - return error; - } + ANGLE_TRY(ensureInitialized()); // Retrieve disassembly UINT flags = D3D_DISASM_ENABLE_DEFAULT_VALUE_PRINTS | D3D_DISASM_ENABLE_INSTRUCTION_NUMBERING; @@ -361,7 +323,7 @@ gl::Error HLSLCompiler::disassembleBinary(ID3DBlob *shaderBinary, std::string *d SafeRelease(disassembly); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } } // namespace rx diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/HLSLCompiler.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/HLSLCompiler.h index 3c0d2adcac..c8f9eac290 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/HLSLCompiler.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/HLSLCompiler.h @@ -1,3 +1,11 @@ +// +// Copyright (c) 2016 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. +// +// HLSLCompiler: Wrapper for the D3DCompiler DLL. +// + #ifndef LIBANGLE_RENDERER_D3D_HLSLCOMPILER_H_ #define LIBANGLE_RENDERER_D3D_HLSLCOMPILER_H_ @@ -41,9 +49,9 @@ class HLSLCompiler : angle::NonCopyable ID3DBlob **outCompiledBlob, std::string *outDebugInfo); gl::Error disassembleBinary(ID3DBlob *shaderBinary, std::string *disassemblyOut); + gl::Error ensureInitialized(); private: - gl::Error initialize(); bool mInitialized; HMODULE mD3DCompilerModule; @@ -53,4 +61,4 @@ class HLSLCompiler : angle::NonCopyable } -#endif // LIBANGLE_RENDERER_D3D_HLSLCOMPILER_H_ +#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 index ead5db6453..dbbcbbed2a 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/ImageD3D.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/ImageD3D.cpp @@ -29,4 +29,34 @@ ImageD3D::ImageD3D() { } +gl::Error ImageD3D::setManagedSurface2D(const gl::Context *context, + TextureStorage *storage, + int level) +{ + return gl::NoError(); +} + +gl::Error ImageD3D::setManagedSurfaceCube(const gl::Context *context, + TextureStorage *storage, + int face, + int level) +{ + return gl::NoError(); +} + +gl::Error ImageD3D::setManagedSurface3D(const gl::Context *context, + TextureStorage *storage, + int level) +{ + return gl::NoError(); +} + +gl::Error ImageD3D::setManagedSurface2DArray(const gl::Context *context, + TextureStorage *storage, + int layer, + int level) +{ + return gl::NoError(); +} + } // namespace rx diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/ImageD3D.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/ImageD3D.h index 2afe1cfabf..1b7235fbaa 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/ImageD3D.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/ImageD3D.h @@ -17,6 +17,7 @@ namespace gl { +class Context; class Framebuffer; struct ImageIndex; struct Box; @@ -51,18 +52,40 @@ class ImageD3D : angle::NonCopyable 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 copyFromTexStorage(const gl::ImageIndex &imageIndex, + virtual gl::Error loadData(const gl::Context *context, + const gl::Box &area, + const gl::PixelUnpackState &unpack, + GLenum type, + const void *input, + bool applySkipImages) = 0; + virtual gl::Error loadCompressedData(const gl::Context *context, + const gl::Box &area, + const void *input) = 0; + + virtual gl::Error setManagedSurface2D(const gl::Context *context, + TextureStorage *storage, + int level); + virtual gl::Error setManagedSurfaceCube(const gl::Context *context, + TextureStorage *storage, + int face, + int level); + virtual gl::Error setManagedSurface3D(const gl::Context *context, + TextureStorage *storage, + int level); + virtual gl::Error setManagedSurface2DArray(const gl::Context *context, + TextureStorage *storage, + int layer, + int level); + virtual gl::Error copyToStorage(const gl::Context *context, + TextureStorage *storage, + const gl::ImageIndex &index, + const gl::Box ®ion) = 0; + + virtual gl::Error copyFromTexStorage(const gl::Context *context, + const gl::ImageIndex &imageIndex, TextureStorage *source) = 0; - virtual gl::Error copyFromFramebuffer(const gl::Offset &destOffset, + virtual gl::Error copyFromFramebuffer(const gl::Context *context, + const gl::Offset &destOffset, const gl::Rectangle &sourceArea, const gl::Framebuffer *source) = 0; diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/IndexBuffer.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/IndexBuffer.cpp index 677b8bb240..937512a96a 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/IndexBuffer.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/IndexBuffer.cpp @@ -71,7 +71,8 @@ gl::Error IndexBufferInterface::mapBuffer(unsigned int size, void **outMappedMem // 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."); + return gl::OutOfMemory() + << "Mapping of internal index buffer would cause an integer overflow."; } gl::Error error = mIndexBuffer->mapBuffer(mWritePosition, size, outMappedMemory); @@ -79,7 +80,7 @@ gl::Error IndexBufferInterface::mapBuffer(unsigned int size, void **outMappedMem { if (outMappedMemory) { - *outMappedMemory = NULL; + *outMappedMemory = nullptr; } return error; } @@ -90,7 +91,7 @@ gl::Error IndexBufferInterface::mapBuffer(unsigned int size, void **outMappedMem } mWritePosition += size; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } gl::Error IndexBufferInterface::unmapBuffer() @@ -145,24 +146,16 @@ gl::Error StreamingIndexBufferInterface::reserveBufferSpace(unsigned int size, G unsigned int writePos = getWritePosition(); if (size > curBufferSize) { - gl::Error error = setBufferSize(std::max(size, 2 * curBufferSize), indexType); - if (error.isError()) - { - return error; - } + ANGLE_TRY(setBufferSize(std::max(size, 2 * curBufferSize), indexType)); setWritePosition(0); } else if (writePos + size > curBufferSize || writePos + size < writePos) { - gl::Error error = discard(); - if (error.isError()) - { - return error; - } + ANGLE_TRY(discard()); setWritePosition(0); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } @@ -184,13 +177,13 @@ gl::Error StaticIndexBufferInterface::reserveBufferSpace(unsigned int size, GLen } else if (curSize >= size && indexType == getIndexType()) { - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } else { UNREACHABLE(); - return gl::Error(GL_INVALID_OPERATION, "Internal static index buffers can't be resized"); + return gl::InternalError() << "Internal static index buffers can't be resized"; } } -} +} // namespace rx diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/IndexBuffer.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/IndexBuffer.h index 0b7b28ddf0..969cf6ae63 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/IndexBuffer.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/IndexBuffer.h @@ -81,7 +81,7 @@ class StreamingIndexBufferInterface : public IndexBufferInterface { public: explicit StreamingIndexBufferInterface(BufferFactoryD3D *factory); - ~StreamingIndexBufferInterface(); + ~StreamingIndexBufferInterface() override; gl::Error reserveBufferSpace(unsigned int size, GLenum indexType) override; }; @@ -90,7 +90,7 @@ class StaticIndexBufferInterface : public IndexBufferInterface { public: explicit StaticIndexBufferInterface(BufferFactoryD3D *factory); - ~StaticIndexBufferInterface(); + ~StaticIndexBufferInterface() override; gl::Error reserveBufferSpace(unsigned int size, GLenum indexType) override; }; diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/IndexDataManager.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/IndexDataManager.cpp index f1ba3d3db0..e974097b45 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/IndexDataManager.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/IndexDataManager.cpp @@ -10,10 +10,12 @@ #include "libANGLE/renderer/d3d/IndexDataManager.h" #include "common/utilities.h" -#include "libANGLE/renderer/d3d/BufferD3D.h" -#include "libANGLE/renderer/d3d/IndexBuffer.h" #include "libANGLE/Buffer.h" +#include "libANGLE/Context.h" +#include "libANGLE/VertexArray.h" #include "libANGLE/formatutils.h" +#include "libANGLE/renderer/d3d/BufferD3D.h" +#include "libANGLE/renderer/d3d/IndexBuffer.h" namespace rx { @@ -76,11 +78,12 @@ void ConvertIndices(GLenum sourceType, ConvertIndexArray(input, sourceType, output, destinationType, count, usePrimitiveRestartFixedIndex); } - else UNREACHABLE(); + else + UNREACHABLE(); } gl::Error StreamInIndexBuffer(IndexBufferInterface *buffer, - const GLvoid *data, + const void *data, unsigned int count, GLenum srcType, GLenum dstType, @@ -91,50 +94,59 @@ gl::Error StreamInIndexBuffer(IndexBufferInterface *buffer, if (count > (std::numeric_limits::max() >> dstTypeInfo.bytesShift)) { - return gl::Error(GL_OUT_OF_MEMORY, - "Reserving %u indices of %u bytes each exceeds the maximum buffer size.", - count, dstTypeInfo.bytes); + return gl::OutOfMemory() << "Reserving " << count << " indices of " << dstTypeInfo.bytes + << " bytes each exceeds the maximum buffer size."; } unsigned int bufferSizeRequired = count << dstTypeInfo.bytesShift; - gl::Error error = buffer->reserveBufferSpace(bufferSizeRequired, dstType); - if (error.isError()) - { - return error; - } + ANGLE_TRY(buffer->reserveBufferSpace(bufferSizeRequired, dstType)); void *output = nullptr; - error = buffer->mapBuffer(bufferSizeRequired, &output, offset); - if (error.isError()) - { - return error; - } + ANGLE_TRY(buffer->mapBuffer(bufferSizeRequired, &output, offset)); ConvertIndices(srcType, dstType, data, count, output, usePrimitiveRestartFixedIndex); - error = buffer->unmapBuffer(); - if (error.isError()) + ANGLE_TRY(buffer->unmapBuffer()); + return gl::NoError(); +} + +unsigned int ElementTypeSize(GLenum elementType) +{ + switch (elementType) { - return error; + case GL_UNSIGNED_BYTE: + return sizeof(GLubyte); + case GL_UNSIGNED_SHORT: + return sizeof(GLushort); + case GL_UNSIGNED_INT: + return sizeof(GLuint); + default: + UNREACHABLE(); + return 0; } - - return gl::Error(GL_NO_ERROR); } } // anonymous namespace -IndexDataManager::IndexDataManager(BufferFactoryD3D *factory, RendererClass rendererClass) - : mFactory(factory), - mRendererClass(rendererClass), - mStreamingBufferShort(nullptr), - mStreamingBufferInt(nullptr) +bool IsOffsetAligned(GLenum elementType, unsigned int offset) +{ + return (offset % ElementTypeSize(elementType) == 0); +} + +// IndexDataManager implementation. +IndexDataManager::IndexDataManager(BufferFactoryD3D *factory) + : mFactory(factory), mStreamingBufferShort(), mStreamingBufferInt() { } IndexDataManager::~IndexDataManager() { - SafeDelete(mStreamingBufferShort); - SafeDelete(mStreamingBufferInt); +} + +void IndexDataManager::deinitialize() +{ + mStreamingBufferShort.reset(); + mStreamingBufferInt.reset(); } // This function translates a GL-style indices into DX-style indices, with their description @@ -143,43 +155,31 @@ IndexDataManager::~IndexDataManager() // possible in DX and requires streaming (Case 1). If the GL indices are specified with a buffer // (Case 2), in a format supported by DX (subcase a) then all is good. // When we have a buffer with an unsupported format (subcase b) then we need to do some translation: -// we will start by falling back to streaming, and after a while will start using a static translated -// copy of the index buffer. -gl::Error IndexDataManager::prepareIndexData(GLenum srcType, +// we will start by falling back to streaming, and after a while will start using a static +// translated copy of the index buffer. +gl::Error IndexDataManager::prepareIndexData(const gl::Context *context, + GLenum srcType, + GLenum dstType, GLsizei count, gl::Buffer *glBuffer, - const GLvoid *indices, - TranslatedIndexData *translated, - bool primitiveRestartFixedIndexEnabled) + const void *indices, + TranslatedIndexData *translated) { - // Avoid D3D11's primitive restart index value - // see http://msdn.microsoft.com/en-us/library/windows/desktop/bb205124(v=vs.85).aspx - bool hasPrimitiveRestartIndex = - translated->indexRange.vertexIndexCount < static_cast(count) || - translated->indexRange.end == gl::GetPrimitiveRestartIndex(srcType); - bool primitiveRestartWorkaround = mRendererClass == RENDERER_D3D11 && - !primitiveRestartFixedIndexEnabled && - hasPrimitiveRestartIndex && srcType == GL_UNSIGNED_SHORT; - - // We should never have to deal with MAX_UINT indices, since we restrict it via - // MAX_ELEMENT_INDEX. - ASSERT(!(mRendererClass == RENDERER_D3D11 && !primitiveRestartFixedIndexEnabled && - hasPrimitiveRestartIndex && srcType == GL_UNSIGNED_INT)); - - const GLenum dstType = (srcType == GL_UNSIGNED_INT || primitiveRestartWorkaround) ? - GL_UNSIGNED_INT : GL_UNSIGNED_SHORT; - const gl::Type &srcTypeInfo = gl::GetTypeInfo(srcType); const gl::Type &dstTypeInfo = gl::GetTypeInfo(dstType); BufferD3D *buffer = glBuffer ? GetImplAs(glBuffer) : nullptr; - translated->indexType = dstType; + translated->indexType = dstType; translated->srcIndexData.srcBuffer = buffer; translated->srcIndexData.srcIndices = indices; translated->srcIndexData.srcIndexType = srcType; translated->srcIndexData.srcCount = count; + // Context can be nullptr in perf tests. + bool primitiveRestartFixedIndexEnabled = + context ? context->getGLState().isPrimitiveRestartEnabled() : false; + // Case 1: the indices are passed by pointer, which forces the streaming of index data if (glBuffer == nullptr) { @@ -192,95 +192,69 @@ gl::Error IndexDataManager::prepareIndexData(GLenum srcType, unsigned int offset = static_cast(reinterpret_cast(indices)); ASSERT(srcTypeInfo.bytes * static_cast(count) + offset <= buffer->getSize()); - bool offsetAligned; - switch (srcType) - { - case GL_UNSIGNED_BYTE: offsetAligned = (offset % sizeof(GLubyte) == 0); break; - case GL_UNSIGNED_SHORT: offsetAligned = (offset % sizeof(GLushort) == 0); break; - case GL_UNSIGNED_INT: offsetAligned = (offset % sizeof(GLuint) == 0); break; - default: UNREACHABLE(); offsetAligned = false; - } + bool offsetAligned = IsOffsetAligned(srcType, offset); // Case 2a: the buffer can be used directly - if (offsetAligned && buffer->supportsDirectBinding() && - dstType == srcType && !primitiveRestartWorkaround) + if (offsetAligned && buffer->supportsDirectBinding() && dstType == srcType) { - translated->storage = buffer; + translated->storage = buffer; translated->indexBuffer = nullptr; - translated->serial = buffer->getSerial(); - translated->startIndex = (offset >> srcTypeInfo.bytesShift); + translated->serial = buffer->getSerial(); + translated->startIndex = (offset >> srcTypeInfo.bytesShift); translated->startOffset = offset; - buffer->promoteStaticUsage(count << srcTypeInfo.bytesShift); - return gl::Error(GL_NO_ERROR); - } - else - { - translated->storage = nullptr; + return gl::NoError(); } + translated->storage = nullptr; + // Case 2b: use a static translated copy or fall back to streaming StaticIndexBufferInterface *staticBuffer = buffer->getStaticIndexBuffer(); bool staticBufferInitialized = staticBuffer && staticBuffer->getBufferSize() != 0; - bool staticBufferUsable = staticBuffer && - offsetAligned && staticBuffer->getIndexType() == dstType; + bool staticBufferUsable = + staticBuffer && offsetAligned && staticBuffer->getIndexType() == dstType; if (staticBufferInitialized && !staticBufferUsable) { - buffer->invalidateStaticData(D3D_BUFFER_INVALIDATE_WHOLE_CACHE); + buffer->invalidateStaticData(context); staticBuffer = nullptr; } if (staticBuffer == nullptr || !offsetAligned) { const uint8_t *bufferData = nullptr; - gl::Error error = buffer->getData(&bufferData); - if (error.isError()) - { - return error; - } + ANGLE_TRY(buffer->getData(context, &bufferData)); ASSERT(bufferData != nullptr); - error = streamIndexData(bufferData + offset, count, srcType, dstType, - primitiveRestartFixedIndexEnabled, translated); - if (error.isError()) - { - return error; - } + ANGLE_TRY(streamIndexData(bufferData + offset, count, srcType, dstType, + primitiveRestartFixedIndexEnabled, translated)); + buffer->promoteStaticUsage(context, count << srcTypeInfo.bytesShift); } else { if (!staticBufferInitialized) { const uint8_t *bufferData = nullptr; - gl::Error error = buffer->getData(&bufferData); - if (error.isError()) - { - return error; - } + ANGLE_TRY(buffer->getData(context, &bufferData)); ASSERT(bufferData != nullptr); unsigned int convertCount = static_cast(buffer->getSize()) >> srcTypeInfo.bytesShift; - error = StreamInIndexBuffer(staticBuffer, bufferData, convertCount, srcType, dstType, - primitiveRestartFixedIndexEnabled, nullptr); - if (error.isError()) - { - return error; - } + ANGLE_TRY(StreamInIndexBuffer(staticBuffer, bufferData, convertCount, srcType, dstType, + primitiveRestartFixedIndexEnabled, nullptr)); } ASSERT(offsetAligned && staticBuffer->getIndexType() == dstType); translated->indexBuffer = staticBuffer->getIndexBuffer(); - translated->serial = staticBuffer->getSerial(); - translated->startIndex = (offset >> srcTypeInfo.bytesShift); + translated->serial = staticBuffer->getSerial(); + translated->startIndex = (offset >> srcTypeInfo.bytesShift); translated->startOffset = (offset >> srcTypeInfo.bytesShift) << dstTypeInfo.bytesShift; } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error IndexDataManager::streamIndexData(const GLvoid *data, +gl::Error IndexDataManager::streamIndexData(const void *data, unsigned int count, GLenum srcType, GLenum dstType, @@ -290,65 +264,57 @@ gl::Error IndexDataManager::streamIndexData(const GLvoid *data, const gl::Type &dstTypeInfo = gl::GetTypeInfo(dstType); IndexBufferInterface *indexBuffer = nullptr; - gl::Error error = getStreamingIndexBuffer(dstType, &indexBuffer); - if (error.isError()) - { - return error; - } + ANGLE_TRY(getStreamingIndexBuffer(dstType, &indexBuffer)); ASSERT(indexBuffer != nullptr); unsigned int offset; - StreamInIndexBuffer(indexBuffer, data, count, srcType, dstType, usePrimitiveRestartFixedIndex, - &offset); + ANGLE_TRY(StreamInIndexBuffer(indexBuffer, data, count, srcType, dstType, + usePrimitiveRestartFixedIndex, &offset)); translated->indexBuffer = indexBuffer->getIndexBuffer(); - translated->serial = indexBuffer->getSerial(); - translated->startIndex = (offset >> dstTypeInfo.bytesShift); + translated->serial = indexBuffer->getSerial(); + translated->startIndex = (offset >> dstTypeInfo.bytesShift); translated->startOffset = offset; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } 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; - } - } + ASSERT(destinationIndexType == GL_UNSIGNED_SHORT || destinationIndexType == GL_UNSIGNED_INT); - *outBuffer = mStreamingBufferInt; - return gl::Error(GL_NO_ERROR); - } - else + auto &streamingBuffer = + (destinationIndexType == GL_UNSIGNED_INT) ? mStreamingBufferInt : mStreamingBufferShort; + + if (!streamingBuffer) { - ASSERT(destinationIndexType == GL_UNSIGNED_SHORT); + StreamingBuffer newBuffer(new StreamingIndexBufferInterface(mFactory)); + ANGLE_TRY(newBuffer->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, destinationIndexType)); + streamingBuffer = std::move(newBuffer); + } - if (!mStreamingBufferShort) + *outBuffer = streamingBuffer.get(); + return gl::NoError(); +} + +GLenum GetIndexTranslationDestType(GLenum srcType, + const gl::HasIndexRange &lazyIndexRange, + bool usePrimitiveRestartWorkaround) +{ + // Avoid D3D11's primitive restart index value + // see http://msdn.microsoft.com/en-us/library/windows/desktop/bb205124(v=vs.85).aspx + if (usePrimitiveRestartWorkaround) + { + const gl::IndexRange &indexRange = lazyIndexRange.getIndexRange().value(); + if (indexRange.end == gl::GetPrimitiveRestartIndex(srcType)) { - mStreamingBufferShort = new StreamingIndexBufferInterface(mFactory); - gl::Error error = mStreamingBufferShort->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, - GL_UNSIGNED_SHORT); - if (error.isError()) - { - SafeDelete(mStreamingBufferShort); - return error; - } + return GL_UNSIGNED_INT; } - - *outBuffer = mStreamingBufferShort; - return gl::Error(GL_NO_ERROR); } -} + return (srcType == GL_UNSIGNED_INT) ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT; } + +} // namespace rx diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/IndexDataManager.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/IndexDataManager.h index 44eb68c071..77f05df92d 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/IndexDataManager.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/IndexDataManager.h @@ -19,7 +19,10 @@ namespace { - enum { INITIAL_INDEX_BUFFER_SIZE = 4096 * sizeof(GLuint) }; +enum +{ + INITIAL_INDEX_BUFFER_SIZE = 4096 * sizeof(GLuint) +}; } namespace gl @@ -39,7 +42,7 @@ class RendererD3D; struct SourceIndexData { BufferD3D *srcBuffer; - const GLvoid *srcIndices; + const void *srcIndices; unsigned int srcCount; GLenum srcIndexType; bool srcIndicesChanged; @@ -47,9 +50,8 @@ struct SourceIndexData struct TranslatedIndexData { - gl::IndexRange indexRange; unsigned int startIndex; - unsigned int startOffset; // In bytes + unsigned int startOffset; // In bytes IndexBuffer *indexBuffer; BufferD3D *storage; @@ -62,18 +64,21 @@ struct TranslatedIndexData class IndexDataManager : angle::NonCopyable { public: - explicit IndexDataManager(BufferFactoryD3D *factory, RendererClass rendererClass); + explicit IndexDataManager(BufferFactoryD3D *factory); virtual ~IndexDataManager(); - gl::Error prepareIndexData(GLenum srcType, + void deinitialize(); + + gl::Error prepareIndexData(const gl::Context *context, + GLenum srcType, + GLenum dstType, GLsizei count, gl::Buffer *glBuffer, - const GLvoid *indices, - TranslatedIndexData *translated, - bool primitiveRestartFixedIndexEnabled); + const void *indices, + TranslatedIndexData *translated); private: - gl::Error streamIndexData(const GLvoid *data, + gl::Error streamIndexData(const void *data, unsigned int count, GLenum srcType, GLenum dstType, @@ -82,12 +87,19 @@ class IndexDataManager : angle::NonCopyable gl::Error getStreamingIndexBuffer(GLenum destinationIndexType, IndexBufferInterface **outBuffer); + using StreamingBuffer = std::unique_ptr; + BufferFactoryD3D *const mFactory; - RendererClass mRendererClass; - StreamingIndexBufferInterface *mStreamingBufferShort; - StreamingIndexBufferInterface *mStreamingBufferInt; + std::unique_ptr mStreamingBufferShort; + std::unique_ptr mStreamingBufferInt; }; -} +GLenum GetIndexTranslationDestType(GLenum srcType, + const gl::HasIndexRange &lazyIndexRange, + bool usePrimitiveRestartWorkaround); + +bool IsOffsetAligned(GLenum elementType, unsigned int offset); + +} // namespace rx -#endif // LIBANGLE_INDEXDATAMANAGER_H_ +#endif // LIBANGLE_INDEXDATAMANAGER_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/NativeWindowD3D.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/NativeWindowD3D.cpp new file mode 100644 index 0000000000..113bad647c --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/NativeWindowD3D.cpp @@ -0,0 +1,23 @@ +// +// Copyright (c) 2016 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. +// + +// NativeWindowD3D.cpp: Defines NativeWindowD3D, a class for managing and performing operations on +// an EGLNativeWindowType for the D3D renderers. + +#include "libANGLE/renderer/d3d/NativeWindowD3D.h" + +namespace rx +{ + +NativeWindowD3D::NativeWindowD3D(EGLNativeWindowType window) : mWindow(window) +{ +} + +NativeWindowD3D::~NativeWindowD3D() +{ +} + +} // namespace rx diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/NativeWindowD3D.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/NativeWindowD3D.h new file mode 100644 index 0000000000..365448488d --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/NativeWindowD3D.h @@ -0,0 +1,38 @@ +// +// Copyright (c) 2016 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. +// + +// NativeWindowD3D.h: Defines NativeWindowD3D, a class for managing and performing operations on an +// EGLNativeWindowType for the D3D renderers. + +#ifndef LIBANGLE_RENDERER_D3D_NATIVEWINDOWD3D_H_ +#define LIBANGLE_RENDERER_D3D_NATIVEWINDOWD3D_H_ + +#include "common/debug.h" +#include "common/platform.h" + +#include +#include "libANGLE/Config.h" + +namespace rx +{ +class NativeWindowD3D : angle::NonCopyable +{ + public: + NativeWindowD3D(EGLNativeWindowType window); + virtual ~NativeWindowD3D(); + + virtual bool initialize() = 0; + virtual bool getClientRect(LPRECT rect) const = 0; + virtual bool isIconic() const = 0; + + inline EGLNativeWindowType getNativeWindow() const { return mWindow; } + + private: + EGLNativeWindowType mWindow; +}; +} // namespace rx + +#endif // LIBANGLE_RENDERER_D3D_NATIVEWINDOWD3D_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/ProgramD3D.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/ProgramD3D.cpp index 72c6f1a1a9..afc318d9fa 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/ProgramD3D.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/ProgramD3D.cpp @@ -8,31 +8,41 @@ #include "libANGLE/renderer/d3d/ProgramD3D.h" -#include "common/BitSetIterator.h" +#include "common/bitset_utils.h" +#include "common/string_utils.h" #include "common/utilities.h" +#include "libANGLE/Context.h" #include "libANGLE/Framebuffer.h" #include "libANGLE/FramebufferAttachment.h" #include "libANGLE/Program.h" +#include "libANGLE/ProgramLinkedResources.h" +#include "libANGLE/Uniform.h" #include "libANGLE/VertexArray.h" #include "libANGLE/features.h" +#include "libANGLE/queryconversions.h" +#include "libANGLE/renderer/ContextImpl.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/VaryingPacking.h" #include "libANGLE/renderer/d3d/VertexDataManager.h" +using namespace angle; + namespace rx { namespace { -gl::InputLayout GetDefaultInputLayoutFromShader(const gl::Shader *vertexShader) +void GetDefaultInputLayoutFromShader(const gl::Context *context, + gl::Shader *vertexShader, + gl::InputLayout *inputLayoutOut) { - gl::InputLayout defaultLayout; - for (const sh::Attribute &shaderAttr : vertexShader->getActiveAttributes()) + inputLayoutOut->clear(); + + for (const sh::Attribute &shaderAttr : vertexShader->getActiveAttributes(context)) { if (shaderAttr.type != GL_NONE) { @@ -47,301 +57,256 @@ gl::InputLayout GetDefaultInputLayoutFromShader(const gl::Shader *vertexShader) gl::VertexFormatType defaultType = gl::GetVertexFormatType(componentType, GL_FALSE, components, pureInt); - defaultLayout.push_back(defaultType); + inputLayoutOut->push_back(defaultType); } } } - - return defaultLayout; } -std::vector GetDefaultOutputLayoutFromShader( - const std::vector &shaderOutputVars) +void GetDefaultOutputLayoutFromShader( + const std::vector &shaderOutputVars, + std::vector *outputLayoutOut) { - std::vector defaultPixelOutput; + outputLayoutOut->clear(); if (!shaderOutputVars.empty()) { - defaultPixelOutput.push_back(GL_COLOR_ATTACHMENT0 + - static_cast(shaderOutputVars[0].outputIndex)); + outputLayoutOut->push_back(GL_COLOR_ATTACHMENT0 + + static_cast(shaderOutputVars[0].outputIndex)); } - - return defaultPixelOutput; } -bool IsRowMajorLayout(const sh::InterfaceBlockField &var) +template +bool TransposeExpandMatrix(T *target, const GLfloat *value) { - return var.isRowMajorLayout; -} + constexpr int targetWidth = 4; + constexpr int targetHeight = rows; + constexpr int srcWidth = rows; + constexpr int srcHeight = cols; -bool IsRowMajorLayout(const sh::ShaderVariable &var) -{ - return false; -} + constexpr int copyWidth = std::min(targetHeight, srcWidth); + constexpr int copyHeight = std::min(targetWidth, srcHeight); -struct AttributeSorter -{ - AttributeSorter(const ProgramD3D::SemanticIndexArray &semanticIndices) - : originalIndices(&semanticIndices) + T staging[targetWidth * targetHeight] = {0}; + + for (int x = 0; x < copyWidth; x++) { + for (int y = 0; y < copyHeight; y++) + { + staging[x * targetWidth + y] = static_cast(value[y * srcWidth + x]); + } } - bool operator()(int a, int b) + if (memcmp(target, staging, targetWidth * targetHeight * sizeof(T)) == 0) { - int indexA = (*originalIndices)[a]; - int indexB = (*originalIndices)[b]; - - if (indexA == -1) - return false; - if (indexB == -1) - return true; - return (indexA < indexB); + return false; } - const ProgramD3D::SemanticIndexArray *originalIndices; -}; - -// true if varying x has a higher priority in packing than y -bool ComparePackedVarying(const PackedVarying &x, const PackedVarying &y) -{ - return gl::CompareShaderVar(*x.varying, *y.varying); + memcpy(target, staging, targetWidth * targetHeight * sizeof(T)); + return true; } -std::vector MergeVaryings(const gl::Shader &vertexShader, - const gl::Shader &fragmentShader, - const std::vector &tfVaryings) +template +bool ExpandMatrix(T *target, const GLfloat *value) { - std::vector packedVaryings; - - for (const sh::Varying &output : vertexShader.getVaryings()) - { - bool packed = false; + constexpr int targetWidth = 4; + constexpr int targetHeight = rows; + constexpr int srcWidth = cols; + constexpr int srcHeight = rows; - // Built-in varyings obey special rules - if (output.isBuiltIn()) - { - continue; - } + constexpr int copyWidth = std::min(targetWidth, srcWidth); + constexpr int copyHeight = std::min(targetHeight, srcHeight); - for (const sh::Varying &input : fragmentShader.getVaryings()) - { - if (output.name == input.name) - { - if (output.isStruct()) - { - ASSERT(!output.isArray()); - for (const auto &field : output.fields) - { - ASSERT(!field.isStruct() && !field.isArray()); - packedVaryings.push_back( - PackedVarying(field, input.interpolation, input.name)); - } - } - else - { - packedVaryings.push_back(PackedVarying(input, input.interpolation)); - } - packed = true; - break; - } - } + T staging[targetWidth * targetHeight] = {0}; - // Keep Transform FB varyings in the merged list always. - if (!packed) + for (int y = 0; y < copyHeight; y++) + { + for (int x = 0; x < copyWidth; x++) { - for (const std::string &tfVarying : tfVaryings) - { - if (tfVarying == output.name) - { - // Transform feedback for varying structs is underspecified. - // See Khronos bug 9856. - // TODO(jmadill): Figure out how to be spec-compliant here. - if (!output.isStruct()) - { - packedVaryings.push_back(PackedVarying(output, output.interpolation)); - packedVaryings.back().vertexOnly = true; - } - break; - } - } + staging[y * targetWidth + x] = static_cast(value[y * srcWidth + x]); } } - std::sort(packedVaryings.begin(), packedVaryings.end(), ComparePackedVarying); + if (memcmp(target, staging, targetWidth * targetHeight * sizeof(T)) == 0) + { + return false; + } - return packedVaryings; + memcpy(target, staging, targetWidth * targetHeight * sizeof(T)); + return true; } -template -void GetUniformBlockInfo(const std::vector &fields, - const std::string &prefix, - sh::BlockLayoutEncoder *encoder, - bool inRowMajorLayout, - std::map *blockInfoOut) +gl::PrimitiveType GetGeometryShaderTypeFromDrawMode(GLenum drawMode) { - for (const VarT &field : fields) + switch (drawMode) { - const std::string &fieldName = (prefix.empty() ? field.name : prefix + "." + field.name); + // Uses the point sprite geometry shader. + case GL_POINTS: + return gl::PRIMITIVE_POINTS; - if (field.isStruct()) - { - bool rowMajorLayout = (inRowMajorLayout || IsRowMajorLayout(field)); + // All line drawing uses the same geometry shader. + case GL_LINES: + case GL_LINE_STRIP: + case GL_LINE_LOOP: + return gl::PRIMITIVE_LINES; - for (unsigned int arrayElement = 0; arrayElement < field.elementCount(); arrayElement++) - { - encoder->enterAggregateType(); + // The triangle fan primitive is emulated with strips in D3D11. + case GL_TRIANGLES: + case GL_TRIANGLE_FAN: + return gl::PRIMITIVE_TRIANGLES; - const std::string uniformElementName = - fieldName + (field.isArray() ? ArrayString(arrayElement) : ""); - GetUniformBlockInfo(field.fields, uniformElementName, encoder, rowMajorLayout, - blockInfoOut); + // Special case for triangle strips. + case GL_TRIANGLE_STRIP: + return gl::PRIMITIVE_TRIANGLE_STRIP; - encoder->exitAggregateType(); - } - } - else - { - bool isRowMajorMatrix = (gl::IsMatrixType(field.type) && inRowMajorLayout); - (*blockInfoOut)[fieldName] = - encoder->encodeType(field.type, field.arraySize, isRowMajorMatrix); - } + default: + UNREACHABLE(); + return gl::PRIMITIVE_TYPE_MAX; } } -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 -bool TransposeMatrix(T *target, - const GLfloat *value, - int targetWidth, - int targetHeight, - int srcWidth, - int srcHeight) +bool FindFlatInterpolationVarying(const std::vector &varyings) { - 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++) + // Note: this assumes nested structs can only be packed with one interpolation. + for (const auto &varying : varyings) { - for (int x = copyHeight; x < targetWidth; x++) + if (varying.interpolation == sh::INTERPOLATION_FLAT) { - SetIfDirty(target + (y * targetWidth + x), static_cast(0), &dirty); + return true; } } - // clear unfilled bottom. - for (int y = copyWidth; y < targetHeight; y++) + + return false; +} + +// Helper method to de-tranpose a matrix uniform for an API query. +void GetMatrixUniform(GLint columns, GLint rows, GLfloat *dataOut, const GLfloat *source) +{ + for (GLint col = 0; col < columns; ++col) { - for (int x = 0; x < targetWidth; x++) + for (GLint row = 0; row < rows; ++row) { - SetIfDirty(target + (y * targetWidth + x), static_cast(0), &dirty); + GLfloat *outptr = dataOut + ((col * rows) + row); + const GLfloat *inptr = source + ((row * 4) + col); + *outptr = *inptr; } } +} - return dirty; +template +void GetMatrixUniform(GLint columns, GLint rows, NonFloatT *dataOut, const NonFloatT *source) +{ + UNREACHABLE(); } -template -bool ExpandMatrix(T *target, - const GLfloat *value, - int targetWidth, - int targetHeight, - int srcWidth, - int srcHeight) +class UniformBlockInfo final : angle::NonCopyable { - bool dirty = false; - int copyWidth = std::min(targetWidth, srcWidth); - int copyHeight = std::min(targetHeight, srcHeight); + public: + UniformBlockInfo() {} - for (int y = 0; y < copyHeight; y++) + void getShaderBlockInfo(const gl::Context *context, gl::Shader *shader); + + bool getBlockSize(const std::string &name, const std::string &mappedName, size_t *sizeOut); + bool getBlockMemberInfo(const std::string &name, + const std::string &mappedName, + sh::BlockMemberInfo *infoOut); + + private: + size_t getBlockInfo(const sh::InterfaceBlock &interfaceBlock); + + std::map mBlockSizes; + sh::BlockLayoutMap mBlockLayout; +}; + +void UniformBlockInfo::getShaderBlockInfo(const gl::Context *context, gl::Shader *shader) +{ + for (const sh::InterfaceBlock &interfaceBlock : shader->getUniformBlocks(context)) { - for (int x = 0; x < copyWidth; x++) - { - SetIfDirty(target + (y * targetWidth + x), static_cast(value[y * srcWidth + x]), - &dirty); - } + if (!interfaceBlock.staticUse && interfaceBlock.layout == sh::BLOCKLAYOUT_PACKED) + continue; + + if (mBlockSizes.count(interfaceBlock.name) > 0) + continue; + + size_t dataSize = getBlockInfo(interfaceBlock); + mBlockSizes[interfaceBlock.name] = dataSize; } - // clear unfilled right side - for (int y = 0; y < copyHeight; y++) +} + +size_t UniformBlockInfo::getBlockInfo(const sh::InterfaceBlock &interfaceBlock) +{ + ASSERT(interfaceBlock.staticUse || interfaceBlock.layout != sh::BLOCKLAYOUT_PACKED); + + // define member uniforms + sh::Std140BlockEncoder std140Encoder; + sh::HLSLBlockEncoder hlslEncoder(sh::HLSLBlockEncoder::ENCODE_PACKED, false); + sh::BlockLayoutEncoder *encoder = nullptr; + + if (interfaceBlock.layout == sh::BLOCKLAYOUT_STD140) { - for (int x = copyWidth; x < targetWidth; x++) - { - SetIfDirty(target + (y * targetWidth + x), static_cast(0), &dirty); - } + encoder = &std140Encoder; } - // clear unfilled bottom. - for (int y = copyHeight; y < targetHeight; y++) + else { - for (int x = 0; x < targetWidth; x++) - { - SetIfDirty(target + (y * targetWidth + x), static_cast(0), &dirty); - } + encoder = &hlslEncoder; } - return dirty; + sh::GetUniformBlockInfo(interfaceBlock.fields, interfaceBlock.fieldPrefix(), encoder, + interfaceBlock.isRowMajorLayout, &mBlockLayout); + + return encoder->getBlockSize(); } -gl::PrimitiveType GetGeometryShaderTypeFromDrawMode(GLenum drawMode) +bool UniformBlockInfo::getBlockSize(const std::string &name, + const std::string &mappedName, + size_t *sizeOut) { - switch (drawMode) + size_t nameLengthWithoutArrayIndex; + gl::ParseArrayIndex(name, &nameLengthWithoutArrayIndex); + std::string baseName = name.substr(0u, nameLengthWithoutArrayIndex); + auto sizeIter = mBlockSizes.find(baseName); + if (sizeIter == mBlockSizes.end()) { - // Uses the point sprite geometry shader. - case GL_POINTS: - return gl::PRIMITIVE_POINTS; - - // All line drawing uses the same geometry shader. - case GL_LINES: - case GL_LINE_STRIP: - case GL_LINE_LOOP: - return gl::PRIMITIVE_LINES; - - // The triangle fan primitive is emulated with strips in D3D11. - case GL_TRIANGLES: - case GL_TRIANGLE_FAN: - return gl::PRIMITIVE_TRIANGLES; + *sizeOut = 0; + return false; + } - // Special case for triangle strips. - case GL_TRIANGLE_STRIP: - return gl::PRIMITIVE_TRIANGLE_STRIP; + *sizeOut = sizeIter->second; + return true; +}; - default: - UNREACHABLE(); - return gl::PRIMITIVE_TYPE_MAX; +bool UniformBlockInfo::getBlockMemberInfo(const std::string &name, + const std::string &mappedName, + sh::BlockMemberInfo *infoOut) +{ + auto infoIter = mBlockLayout.find(name); + if (infoIter == mBlockLayout.end()) + { + *infoOut = sh::BlockMemberInfo::getDefaultBlockInfo(); + return false; } -} + + *infoOut = infoIter->second; + return true; +}; } // anonymous namespace // D3DUniform Implementation -D3DUniform::D3DUniform(GLenum typeIn, +D3DUniform::D3DUniform(GLenum type, const std::string &nameIn, - unsigned int arraySizeIn, + const std::vector &arraySizesIn, bool defaultBlock) - : type(typeIn), + : typeInfo(gl::GetUniformTypeInfo(type)), name(nameIn), - arraySize(arraySizeIn), - data(nullptr), - dirty(true), + arraySizes(arraySizesIn), + vsData(nullptr), + psData(nullptr), + csData(nullptr), vsRegisterIndex(GL_INVALID_INDEX), psRegisterIndex(GL_INVALID_INDEX), + csRegisterIndex(GL_INVALID_INDEX), registerCount(0), registerElement(0) { @@ -350,23 +315,36 @@ D3DUniform::D3DUniform(GLenum typeIn, // Uniform blocks/buffers are treated separately by the Renderer (ES3 path only) if (defaultBlock) { - size_t bytes = gl::VariableInternalSize(type) * elementCount(); - data = new uint8_t[bytes]; - memset(data, 0, bytes); - - // TODO(jmadill): is this correct with non-square matrices? - registerCount = gl::VariableRowCount(type) * elementCount(); + // Use the row count as register count, will work for non-square matrices. + registerCount = typeInfo.rowCount * getArraySizeProduct(); } } D3DUniform::~D3DUniform() { - SafeDeleteArray(data); +} + +unsigned int D3DUniform::getArraySizeProduct() const +{ + return gl::ArraySizeProduct(arraySizes); +} + +const uint8_t *D3DUniform::getDataPtrToElement(size_t elementIndex) const +{ + ASSERT((!isArray() && elementIndex == 0) || + (isArray() && elementIndex < getArraySizeProduct())); + + if (isSampler()) + { + return reinterpret_cast(&mSamplerData[elementIndex]); + } + + return firstNonNullData() + (elementIndex > 0 ? (typeInfo.internalSize * elementIndex) : 0u); } bool D3DUniform::isSampler() const { - return gl::IsSamplerType(type); + return typeInfo.isSampler; } bool D3DUniform::isReferencedByVertexShader() const @@ -379,6 +357,23 @@ bool D3DUniform::isReferencedByFragmentShader() const return psRegisterIndex != GL_INVALID_INDEX; } +bool D3DUniform::isReferencedByComputeShader() const +{ + return csRegisterIndex != GL_INVALID_INDEX; +} + +const uint8_t *D3DUniform::firstNonNullData() const +{ + ASSERT(vsData || psData || csData || !mSamplerData.empty()); + + if (!mSamplerData.empty()) + { + return reinterpret_cast(mSamplerData.data()); + } + + return vsData ? vsData : (psData ? psData : csData); +} + // D3DVarying Implementation D3DVarying::D3DVarying() : semanticIndex(0), componentCount(0), outputSlot(0) @@ -398,16 +393,17 @@ D3DVarying::D3DVarying(const std::string &semanticNameIn, // ProgramD3DMetadata Implementation -ProgramD3DMetadata::ProgramD3DMetadata(int rendererMajorShaderModel, - const std::string &shaderModelSuffix, - bool usesInstancedPointSpriteEmulation, - bool usesViewScale, +ProgramD3DMetadata::ProgramD3DMetadata(RendererD3D *renderer, const ShaderD3D *vertexShader, const ShaderD3D *fragmentShader) - : mRendererMajorShaderModel(rendererMajorShaderModel), - mShaderModelSuffix(shaderModelSuffix), - mUsesInstancedPointSpriteEmulation(usesInstancedPointSpriteEmulation), - mUsesViewScale(usesViewScale), + : mRendererMajorShaderModel(renderer->getMajorShaderModel()), + mShaderModelSuffix(renderer->getShaderModelSuffix()), + mUsesInstancedPointSpriteEmulation( + renderer->getWorkarounds().useInstancedPointSpriteEmulation), + mUsesViewScale(renderer->presentPathFastEnabled()), + mHasANGLEMultiviewEnabled(vertexShader->hasANGLEMultiviewEnabled()), + mUsesViewID(fragmentShader->usesViewID()), + mCanSelectViewInVertexShader(renderer->canSelectViewInVertexShader()), mVertexShader(vertexShader), mFragmentShader(fragmentShader) { @@ -418,12 +414,13 @@ int ProgramD3DMetadata::getRendererMajorShaderModel() const return mRendererMajorShaderModel; } -bool ProgramD3DMetadata::usesBroadcast(const gl::Data &data) const +bool ProgramD3DMetadata::usesBroadcast(const gl::ContextState &data) const { - return (mFragmentShader->usesFragColor() && data.clientVersion < 3); + return (mFragmentShader->usesFragColor() && mFragmentShader->usesMultipleRenderTargets() && + data.getClientMajorVersion() < 3); } -bool ProgramD3DMetadata::usesFragDepth(const gl::Program::Data &programData) const +bool ProgramD3DMetadata::usesFragDepth() const { return mFragmentShader->usesFragDepth(); } @@ -445,7 +442,8 @@ bool ProgramD3DMetadata::usesPointSize() const bool ProgramD3DMetadata::usesInsertedPointCoordValue() const { - return !usesPointSize() && usesPointCoord() && mRendererMajorShaderModel >= 4; + return (!usesPointSize() || !mUsesInstancedPointSpriteEmulation) && usesPointCoord() && + mRendererMajorShaderModel >= 4; } bool ProgramD3DMetadata::usesViewScale() const @@ -453,15 +451,29 @@ bool ProgramD3DMetadata::usesViewScale() const return mUsesViewScale; } +bool ProgramD3DMetadata::hasANGLEMultiviewEnabled() const +{ + return mHasANGLEMultiviewEnabled; +} + +bool ProgramD3DMetadata::usesViewID() const +{ + return mUsesViewID; +} + +bool ProgramD3DMetadata::canSelectViewInVertexShader() const +{ + return mCanSelectViewInVertexShader; +} + bool ProgramD3DMetadata::addsPointCoordToVertexShader() const { - // Instanced PointSprite emulation requires that gl_PointCoord is present in the vertex shader + // PointSprite emulation requiress 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. + // Even with a geometry shader, the app can render triangles or lines and reference + // gl_PointCoord in the fragment shader, requiring us to provide a dummy value. For + // simplicity, we always add this to the vertex shader when the fragment shader + // references gl_PointCoord, even if we could skip it in the geometry shader. return (mUsesInstancedPointSpriteEmulation && usesPointCoord()) || usesInsertedPointCoordValue(); } @@ -508,25 +520,45 @@ ProgramD3D::VertexExecutable::~VertexExecutable() SafeDelete(mShaderExecutable); } +// static +ProgramD3D::VertexExecutable::HLSLAttribType ProgramD3D::VertexExecutable::GetAttribType( + GLenum type) +{ + switch (type) + { + case GL_INT: + return HLSLAttribType::SIGNED_INT; + case GL_UNSIGNED_INT: + return HLSLAttribType::UNSIGNED_INT; + case GL_SIGNED_NORMALIZED: + case GL_UNSIGNED_NORMALIZED: + case GL_FLOAT: + return HLSLAttribType::FLOAT; + default: + UNREACHABLE(); + return HLSLAttribType::FLOAT; + } +} + // static void ProgramD3D::VertexExecutable::getSignature(RendererD3D *renderer, const gl::InputLayout &inputLayout, Signature *signatureOut) { - signatureOut->resize(inputLayout.size()); + signatureOut->assign(inputLayout.size(), HLSLAttribType::FLOAT); for (size_t index = 0; index < inputLayout.size(); ++index) { gl::VertexFormatType vertexFormatType = inputLayout[index]; - bool converted = false; - if (vertexFormatType != gl::VERTEX_FORMAT_INVALID) - { - VertexConversionType conversionType = - renderer->getVertexConversionType(vertexFormatType); - converted = ((conversionType & VERTEX_CONVERT_GPU) != 0); - } + if (vertexFormatType == gl::VERTEX_FORMAT_INVALID) + continue; + + VertexConversionType conversionType = renderer->getVertexConversionType(vertexFormatType); + if ((conversionType & VERTEX_CONVERT_GPU) == 0) + continue; - (*signatureOut)[index] = converted; + GLenum componentType = renderer->getVertexComponentType(vertexFormatType); + (*signatureOut)[index] = GetAttribType(componentType); } } @@ -535,9 +567,9 @@ bool ProgramD3D::VertexExecutable::matchesSignature(const Signature &signature) size_t limit = std::max(mSignature.size(), signature.size()); for (size_t index = 0; index < limit; ++index) { - // treat undefined indexes as 'not converted' - bool a = index < signature.size() ? signature[index] : false; - bool b = index < mSignature.size() ? mSignature[index] : false; + // treat undefined indexes as FLOAT + auto a = index < signature.size() ? signature[index] : HLSLAttribType::FLOAT; + auto b = index < mSignature.size() ? mSignature[index] : HLSLAttribType::FLOAT; if (a != b) return false; } @@ -562,19 +594,25 @@ ProgramD3D::Sampler::Sampler() : active(false), logicalTextureUnit(0), textureTy unsigned int ProgramD3D::mCurrentSerial = 1; -ProgramD3D::ProgramD3D(const gl::Program::Data &data, RendererD3D *renderer) - : ProgramImpl(data), +ProgramD3D::ProgramD3D(const gl::ProgramState &state, RendererD3D *renderer) + : ProgramImpl(state), mRenderer(renderer), - mDynamicHLSL(NULL), - mGeometryExecutables(gl::PRIMITIVE_TYPE_MAX, nullptr), + mDynamicHLSL(nullptr), + mGeometryExecutables(gl::PRIMITIVE_TYPE_MAX), + mComputeExecutable(nullptr), mUsesPointSize(false), mUsesFlatInterpolation(false), - mVertexUniformStorage(NULL), - mFragmentUniformStorage(NULL), + mVertexUniformStorage(nullptr), + mFragmentUniformStorage(nullptr), + mComputeUniformStorage(nullptr), mUsedVertexSamplerRange(0), mUsedPixelSamplerRange(0), + mUsedComputeSamplerRange(0), mDirtySamplerMapping(true), - mSerial(issueSerial()) + mSerial(issueSerial()), + mVertexUniformsDirty(true), + mFragmentUniformsDirty(true), + mComputeUniformsDirty(true) { mDynamicHLSL = new DynamicHLSL(renderer); } @@ -590,14 +628,22 @@ bool ProgramD3D::usesPointSpriteEmulation() const return mUsesPointSize && mRenderer->getMajorShaderModel() >= 4; } +bool ProgramD3D::usesGeometryShaderForPointSpriteEmulation() const +{ + return usesPointSpriteEmulation() && !usesInstancedPointSpriteEmulation(); +} + bool ProgramD3D::usesGeometryShader(GLenum drawMode) const { + if (mHasANGLEMultiviewEnabled && !mRenderer->canSelectViewInVertexShader()) + { + return true; + } if (drawMode != GL_POINTS) { return mUsesFlatInterpolation; } - - return usesPointSpriteEmulation() && !usesInstancedPointSpriteEmulation(); + return usesGeometryShaderForPointSpriteEmulation(); } bool ProgramD3D::usesInstancedPointSpriteEmulation() const @@ -627,6 +673,13 @@ GLint ProgramD3D::getSamplerMapping(gl::SamplerType type, logicalTextureUnit = mSamplersVS[samplerIndex].logicalTextureUnit; } break; + case gl::SAMPLER_COMPUTE: + ASSERT(samplerIndex < caps.maxComputeTextureImageUnits); + if (samplerIndex < mSamplersCS.size() && mSamplersCS[samplerIndex].active) + { + logicalTextureUnit = mSamplersCS[samplerIndex].logicalTextureUnit; + } + break; default: UNREACHABLE(); } @@ -654,6 +707,10 @@ GLenum ProgramD3D::getSamplerTextureType(gl::SamplerType type, unsigned int samp ASSERT(samplerIndex < mSamplersVS.size()); ASSERT(mSamplersVS[samplerIndex].active); return mSamplersVS[samplerIndex].textureType; + case gl::SAMPLER_COMPUTE: + ASSERT(samplerIndex < mSamplersCS.size()); + ASSERT(mSamplersCS[samplerIndex].active); + return mSamplersCS[samplerIndex].textureType; default: UNREACHABLE(); } @@ -661,7 +718,7 @@ GLenum ProgramD3D::getSamplerTextureType(gl::SamplerType type, unsigned int samp return GL_TEXTURE_2D; } -GLint ProgramD3D::getUsedSamplerRange(gl::SamplerType type) const +GLuint ProgramD3D::getUsedSamplerRange(gl::SamplerType type) const { switch (type) { @@ -669,17 +726,19 @@ GLint ProgramD3D::getUsedSamplerRange(gl::SamplerType type) const return mUsedPixelSamplerRange; case gl::SAMPLER_VERTEX: return mUsedVertexSamplerRange; + case gl::SAMPLER_COMPUTE: + return mUsedComputeSamplerRange; default: UNREACHABLE(); - return 0; + return 0u; } } -void ProgramD3D::updateSamplerMapping() +ProgramD3D::SamplerMapping ProgramD3D::updateSamplerMapping() { if (!mDirtySamplerMapping) { - return; + return SamplerMapping::WasClean; } mDirtySamplerMapping = false; @@ -687,14 +746,10 @@ void ProgramD3D::updateSamplerMapping() // Retrieve sampler uniform values for (const D3DUniform *d3dUniform : mD3DUniforms) { - if (!d3dUniform->dirty) - continue; - if (!d3dUniform->isSampler()) continue; - int count = d3dUniform->elementCount(); - const GLint(*v)[4] = reinterpret_cast(d3dUniform->data); + int count = d3dUniform->getArraySizeProduct(); if (d3dUniform->isReferencedByFragmentShader()) { @@ -707,7 +762,7 @@ void ProgramD3D::updateSamplerMapping() if (samplerIndex < mSamplersPS.size()) { ASSERT(mSamplersPS[samplerIndex].active); - mSamplersPS[samplerIndex].logicalTextureUnit = v[i][0]; + mSamplersPS[samplerIndex].logicalTextureUnit = d3dUniform->mSamplerData[i]; } } } @@ -723,15 +778,37 @@ void ProgramD3D::updateSamplerMapping() if (samplerIndex < mSamplersVS.size()) { ASSERT(mSamplersVS[samplerIndex].active); - mSamplersVS[samplerIndex].logicalTextureUnit = v[i][0]; + mSamplersVS[samplerIndex].logicalTextureUnit = d3dUniform->mSamplerData[i]; + } + } + } + + if (d3dUniform->isReferencedByComputeShader()) + { + unsigned int firstIndex = d3dUniform->csRegisterIndex; + + for (int i = 0; i < count; i++) + { + unsigned int samplerIndex = firstIndex + i; + + if (samplerIndex < mSamplersCS.size()) + { + ASSERT(mSamplersCS[samplerIndex].active); + mSamplersCS[samplerIndex].logicalTextureUnit = d3dUniform->mSamplerData[i]; } } } } + + return SamplerMapping::WasDirty; } -LinkResult ProgramD3D::load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream) +gl::LinkResult ProgramD3D::load(const gl::Context *context, + gl::InfoLog &infoLog, + gl::BinaryInputStream *stream) { + // TODO(jmadill): Use Renderer from contextImpl. + reset(); DeviceIdentifier binaryDeviceIdentifier = {0}; @@ -742,20 +819,19 @@ LinkResult ProgramD3D::load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream) if (memcmp(&identifier, &binaryDeviceIdentifier, sizeof(DeviceIdentifier)) != 0) { infoLog << "Invalid program binary, device configuration has changed."; - return LinkResult(false, gl::Error(GL_NO_ERROR)); + return false; } int compileFlags = stream->readInt(); if (compileFlags != ANGLE_COMPILE_OPTIMIZATION_LEVEL) { infoLog << "Mismatched compilation flags."; - return LinkResult(false, gl::Error(GL_NO_ERROR)); + return false; } - // TODO(jmadill): replace MAX_VERTEX_ATTRIBS - for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; ++i) + for (int &index : mAttribLocationToD3DSemantic) { - stream->readInt(&mSemanticIndexes[i]); + stream->readInt(&index); } const unsigned int psSamplerCount = stream->readInt(); @@ -777,27 +853,39 @@ LinkResult ProgramD3D::load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream) mSamplersVS.push_back(sampler); } + const unsigned int csSamplerCount = stream->readInt(); + for (unsigned int i = 0; i < csSamplerCount; ++i) + { + Sampler sampler; + stream->readBool(&sampler.active); + stream->readInt(&sampler.logicalTextureUnit); + stream->readInt(&sampler.textureType); + mSamplersCS.push_back(sampler); + } + stream->readInt(&mUsedVertexSamplerRange); stream->readInt(&mUsedPixelSamplerRange); + stream->readInt(&mUsedComputeSamplerRange); const unsigned int uniformCount = stream->readInt(); if (stream->error()) { infoLog << "Invalid program binary."; - return LinkResult(false, gl::Error(GL_NO_ERROR)); + return false; } - const auto &linkedUniforms = mData.getUniforms(); + const auto &linkedUniforms = mState.getUniforms(); ASSERT(mD3DUniforms.empty()); for (unsigned int uniformIndex = 0; uniformIndex < uniformCount; uniformIndex++) { const gl::LinkedUniform &linkedUniform = linkedUniforms[uniformIndex]; D3DUniform *d3dUniform = - new D3DUniform(linkedUniform.type, linkedUniform.name, linkedUniform.arraySize, + new D3DUniform(linkedUniform.type, linkedUniform.name, linkedUniform.arraySizes, linkedUniform.isInDefaultBlock()); stream->readInt(&d3dUniform->psRegisterIndex); stream->readInt(&d3dUniform->vsRegisterIndex); + stream->readInt(&d3dUniform->csRegisterIndex); stream->readInt(&d3dUniform->registerCount); stream->readInt(&d3dUniform->registerElement); @@ -808,7 +896,7 @@ LinkResult ProgramD3D::load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream) if (stream->error()) { infoLog << "Invalid program binary."; - return LinkResult(false, gl::Error(GL_NO_ERROR)); + return false; } ASSERT(mD3DUniformBlocks.empty()); @@ -817,6 +905,7 @@ LinkResult ProgramD3D::load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream) D3DUniformBlock uniformBlock; stream->readInt(&uniformBlock.psRegisterIndex); stream->readInt(&uniformBlock.vsRegisterIndex); + stream->readInt(&uniformBlock.csRegisterIndex); mD3DUniformBlocks.push_back(uniformBlock); } @@ -834,11 +923,13 @@ LinkResult ProgramD3D::load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream) stream->readString(&mVertexHLSL); stream->readBytes(reinterpret_cast(&mVertexWorkarounds), - sizeof(D3DCompilerWorkarounds)); + sizeof(angle::CompilerWorkaroundsD3D)); stream->readString(&mPixelHLSL); stream->readBytes(reinterpret_cast(&mPixelWorkarounds), - sizeof(D3DCompilerWorkarounds)); + sizeof(angle::CompilerWorkaroundsD3D)); stream->readBool(&mUsesFragDepth); + stream->readBool(&mHasANGLEMultiviewEnabled); + stream->readBool(&mUsesViewID); stream->readBool(&mUsesPointSize); stream->readBool(&mUsesFlatInterpolation); @@ -857,6 +948,8 @@ LinkResult ProgramD3D::load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream) const unsigned char *binary = reinterpret_cast(stream->data()); + bool separateAttribs = (mState.getTransformFeedbackBufferMode() == GL_SEPARATE_ATTRIBS); + const unsigned int vertexShaderCount = stream->readInt(); for (unsigned int vertexShaderIndex = 0; vertexShaderIndex < vertexShaderCount; vertexShaderIndex++) @@ -874,18 +967,14 @@ LinkResult ProgramD3D::load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream) ShaderExecutableD3D *shaderExecutable = nullptr; - gl::Error error = mRenderer->loadExecutable( - vertexShaderFunction, vertexShaderSize, SHADER_VERTEX, mStreamOutVaryings, - (mData.getTransformFeedbackBufferMode() == GL_SEPARATE_ATTRIBS), &shaderExecutable); - if (error.isError()) - { - return LinkResult(false, error); - } + ANGLE_TRY(mRenderer->loadExecutable(vertexShaderFunction, vertexShaderSize, + gl::SHADER_VERTEX, mStreamOutVaryings, separateAttribs, + &shaderExecutable)); if (!shaderExecutable) { infoLog << "Could not create vertex shader."; - return LinkResult(false, gl::Error(GL_NO_ERROR)); + return false; } // generated converted input layout @@ -893,8 +982,8 @@ LinkResult ProgramD3D::load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream) VertexExecutable::getSignature(mRenderer, inputLayout, &signature); // add new binary - mVertexExecutables.push_back( - new VertexExecutable(inputLayout, signature, shaderExecutable)); + mVertexExecutables.push_back(std::unique_ptr( + new VertexExecutable(inputLayout, signature, shaderExecutable))); stream->skip(vertexShaderSize); } @@ -913,22 +1002,19 @@ LinkResult ProgramD3D::load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream) const unsigned char *pixelShaderFunction = binary + stream->offset(); ShaderExecutableD3D *shaderExecutable = nullptr; - gl::Error error = mRenderer->loadExecutable( - pixelShaderFunction, pixelShaderSize, SHADER_PIXEL, mStreamOutVaryings, - (mData.getTransformFeedbackBufferMode() == GL_SEPARATE_ATTRIBS), &shaderExecutable); - if (error.isError()) - { - return LinkResult(false, error); - } + ANGLE_TRY(mRenderer->loadExecutable(pixelShaderFunction, pixelShaderSize, + gl::SHADER_FRAGMENT, mStreamOutVaryings, + separateAttribs, &shaderExecutable)); if (!shaderExecutable) { infoLog << "Could not create pixel shader."; - return LinkResult(false, gl::Error(GL_NO_ERROR)); + return false; } // add new binary - mPixelExecutables.push_back(new PixelExecutable(outputs, shaderExecutable)); + mPixelExecutables.push_back( + std::unique_ptr(new PixelExecutable(outputs, shaderExecutable))); stream->skip(pixelShaderSize); } @@ -939,36 +1025,52 @@ LinkResult ProgramD3D::load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream) unsigned int geometryShaderSize = stream->readInt(); if (geometryShaderSize == 0) { - mGeometryExecutables[geometryExeIndex] = nullptr; continue; } const unsigned char *geometryShaderFunction = binary + stream->offset(); - bool splitAttribs = (mData.getTransformFeedbackBufferMode() == GL_SEPARATE_ATTRIBS); - gl::Error error = mRenderer->loadExecutable( - geometryShaderFunction, geometryShaderSize, SHADER_GEOMETRY, mStreamOutVaryings, - splitAttribs, &mGeometryExecutables[geometryExeIndex]); - if (error.isError()) - { - return LinkResult(false, error); - } + ShaderExecutableD3D *geometryExecutable = nullptr; + ANGLE_TRY(mRenderer->loadExecutable(geometryShaderFunction, geometryShaderSize, + gl::SHADER_GEOMETRY, mStreamOutVaryings, + separateAttribs, &geometryExecutable)); - if (!mGeometryExecutables[geometryExeIndex]) + if (!geometryExecutable) { infoLog << "Could not create geometry shader."; - return LinkResult(false, gl::Error(GL_NO_ERROR)); + return false; } + + mGeometryExecutables[geometryExeIndex].reset(geometryExecutable); + stream->skip(geometryShaderSize); } + unsigned int computeShaderSize = stream->readInt(); + if (computeShaderSize > 0) + { + const unsigned char *computeShaderFunction = binary + stream->offset(); + + ShaderExecutableD3D *computeExecutable = nullptr; + ANGLE_TRY(mRenderer->loadExecutable(computeShaderFunction, computeShaderSize, + gl::SHADER_COMPUTE, std::vector(), false, + &computeExecutable)); + + if (!computeExecutable) + { + infoLog << "Could not create compute shader."; + return false; + } + + mComputeExecutable.reset(computeExecutable); + } + initializeUniformStorage(); - initAttributesByLayout(); - return LinkResult(true, gl::Error(GL_NO_ERROR)); + return true; } -gl::Error ProgramD3D::save(gl::BinaryOutputStream *stream) +void ProgramD3D::save(const gl::Context *context, gl::BinaryOutputStream *stream) { // Output the DeviceIdentifier before we output any shader code // When we load the binary again later, we can validate the device identifier before trying to @@ -979,10 +1081,9 @@ gl::Error ProgramD3D::save(gl::BinaryOutputStream *stream) stream->writeInt(ANGLE_COMPILE_OPTIMIZATION_LEVEL); - // TODO(jmadill): replace MAX_VERTEX_ATTRIBS - for (unsigned int i = 0; i < gl::MAX_VERTEX_ATTRIBS; ++i) + for (int d3dSemantic : mAttribLocationToD3DSemantic) { - stream->writeInt(mSemanticIndexes[i]); + stream->writeInt(d3dSemantic); } stream->writeInt(mSamplersPS.size()); @@ -1001,15 +1102,25 @@ gl::Error ProgramD3D::save(gl::BinaryOutputStream *stream) stream->writeInt(mSamplersVS[i].textureType); } + stream->writeInt(mSamplersCS.size()); + for (unsigned int i = 0; i < mSamplersCS.size(); ++i) + { + stream->writeInt(mSamplersCS[i].active); + stream->writeInt(mSamplersCS[i].logicalTextureUnit); + stream->writeInt(mSamplersCS[i].textureType); + } + stream->writeInt(mUsedVertexSamplerRange); stream->writeInt(mUsedPixelSamplerRange); + stream->writeInt(mUsedComputeSamplerRange); stream->writeInt(mD3DUniforms.size()); for (const D3DUniform *uniform : mD3DUniforms) { // Type, name and arraySize are redundant, so aren't stored in the binary. - stream->writeInt(uniform->psRegisterIndex); - stream->writeInt(uniform->vsRegisterIndex); + stream->writeIntOrNegOne(uniform->psRegisterIndex); + stream->writeIntOrNegOne(uniform->vsRegisterIndex); + stream->writeIntOrNegOne(uniform->csRegisterIndex); stream->writeInt(uniform->registerCount); stream->writeInt(uniform->registerElement); } @@ -1017,8 +1128,9 @@ gl::Error ProgramD3D::save(gl::BinaryOutputStream *stream) stream->writeInt(mD3DUniformBlocks.size()); for (const D3DUniformBlock &uniformBlock : mD3DUniformBlocks) { - stream->writeInt(uniformBlock.psRegisterIndex); - stream->writeInt(uniformBlock.vsRegisterIndex); + stream->writeIntOrNegOne(uniformBlock.psRegisterIndex); + stream->writeIntOrNegOne(uniformBlock.vsRegisterIndex); + stream->writeIntOrNegOne(uniformBlock.csRegisterIndex); } stream->writeInt(mStreamOutVaryings.size()); @@ -1032,11 +1144,13 @@ gl::Error ProgramD3D::save(gl::BinaryOutputStream *stream) stream->writeString(mVertexHLSL); stream->writeBytes(reinterpret_cast(&mVertexWorkarounds), - sizeof(D3DCompilerWorkarounds)); + sizeof(angle::CompilerWorkaroundsD3D)); stream->writeString(mPixelHLSL); stream->writeBytes(reinterpret_cast(&mPixelWorkarounds), - sizeof(D3DCompilerWorkarounds)); + sizeof(angle::CompilerWorkaroundsD3D)); stream->writeInt(mUsesFragDepth); + stream->writeInt(mHasANGLEMultiviewEnabled); + stream->writeInt(mUsesViewID); stream->writeInt(mUsesPointSize); stream->writeInt(mUsesFlatInterpolation); @@ -1058,14 +1172,14 @@ gl::Error ProgramD3D::save(gl::BinaryOutputStream *stream) for (size_t vertexExecutableIndex = 0; vertexExecutableIndex < mVertexExecutables.size(); vertexExecutableIndex++) { - VertexExecutable *vertexExecutable = mVertexExecutables[vertexExecutableIndex]; + VertexExecutable *vertexExecutable = mVertexExecutables[vertexExecutableIndex].get(); const auto &inputLayout = vertexExecutable->inputs(); stream->writeInt(inputLayout.size()); for (size_t inputIndex = 0; inputIndex < inputLayout.size(); inputIndex++) { - stream->writeInt(inputLayout[inputIndex]); + stream->writeInt(static_cast(inputLayout[inputIndex])); } size_t vertexShaderSize = vertexExecutable->shaderExecutable()->getLength(); @@ -1079,7 +1193,7 @@ gl::Error ProgramD3D::save(gl::BinaryOutputStream *stream) for (size_t pixelExecutableIndex = 0; pixelExecutableIndex < mPixelExecutables.size(); pixelExecutableIndex++) { - PixelExecutable *pixelExecutable = mPixelExecutables[pixelExecutableIndex]; + PixelExecutable *pixelExecutable = mPixelExecutables[pixelExecutableIndex].get(); const std::vector outputs = pixelExecutable->outputSignature(); stream->writeInt(outputs.size()); @@ -1095,150 +1209,120 @@ gl::Error ProgramD3D::save(gl::BinaryOutputStream *stream) stream->writeBytes(pixelBlob, pixelShaderSize); } - for (const ShaderExecutableD3D *geometryExe : mGeometryExecutables) + for (auto const &geometryExecutable : mGeometryExecutables) { - if (geometryExe == nullptr) + if (!geometryExecutable) { stream->writeInt(0); continue; } - size_t geometryShaderSize = geometryExe->getLength(); + size_t geometryShaderSize = geometryExecutable->getLength(); stream->writeInt(geometryShaderSize); - stream->writeBytes(geometryExe->getFunction(), geometryShaderSize); + stream->writeBytes(geometryExecutable->getFunction(), geometryShaderSize); } - return gl::Error(GL_NO_ERROR); + if (mComputeExecutable) + { + size_t computeShaderSize = mComputeExecutable->getLength(); + stream->writeInt(computeShaderSize); + stream->writeBytes(mComputeExecutable->getFunction(), computeShaderSize); + } + else + { + stream->writeInt(0); + } } void ProgramD3D::setBinaryRetrievableHint(bool /* retrievable */) { } -gl::Error ProgramD3D::getPixelExecutableForFramebuffer(const gl::Framebuffer *fbo, - ShaderExecutableD3D **outExecutable) +void ProgramD3D::setSeparable(bool /* separable */) { - mPixelShaderOutputFormatCache.clear(); - - const FramebufferD3D *fboD3D = GetImplAs(fbo); - const gl::AttachmentList &colorbuffers = fboD3D->getColorAttachmentsForRender(); - - 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) +gl::Error ProgramD3D::getPixelExecutableForCachedOutputLayout(ShaderExecutableD3D **outExecutable, + gl::InfoLog *infoLog) { - for (size_t executableIndex = 0; executableIndex < mPixelExecutables.size(); executableIndex++) + if (mCachedPixelExecutableIndex.valid()) { - if (mPixelExecutables[executableIndex]->matchesSignature(outputSignature)) - { - *outExectuable = mPixelExecutables[executableIndex]->shaderExecutable(); - return gl::Error(GL_NO_ERROR); - } + *outExecutable = mPixelExecutables[mCachedPixelExecutableIndex.value()]->shaderExecutable(); + return gl::NoError(); } std::string finalPixelHLSL = mDynamicHLSL->generatePixelShaderForOutputSignature( - mPixelHLSL, mPixelShaderKey, mUsesFragDepth, outputSignature); + mPixelHLSL, mPixelShaderKey, mUsesFragDepth, mPixelShaderOutputLayoutCache); // Generate new pixel executable - ShaderExecutableD3D *pixelExecutable = NULL; + ShaderExecutableD3D *pixelExecutable = nullptr; gl::InfoLog tempInfoLog; gl::InfoLog *currentInfoLog = infoLog ? infoLog : &tempInfoLog; - gl::Error error = mRenderer->compileToExecutable( - *currentInfoLog, finalPixelHLSL, SHADER_PIXEL, mStreamOutVaryings, - (mData.getTransformFeedbackBufferMode() == GL_SEPARATE_ATTRIBS), mPixelWorkarounds, - &pixelExecutable); - if (error.isError()) - { - return error; - } + ANGLE_TRY(mRenderer->compileToExecutable( + *currentInfoLog, finalPixelHLSL, gl::SHADER_FRAGMENT, mStreamOutVaryings, + (mState.getTransformFeedbackBufferMode() == GL_SEPARATE_ATTRIBS), mPixelWorkarounds, + &pixelExecutable)); if (pixelExecutable) { - mPixelExecutables.push_back(new PixelExecutable(outputSignature, pixelExecutable)); + mPixelExecutables.push_back(std::unique_ptr( + new PixelExecutable(mPixelShaderOutputLayoutCache, pixelExecutable))); + mCachedPixelExecutableIndex = mPixelExecutables.size() - 1; } else if (!infoLog) { - std::vector tempCharBuffer(tempInfoLog.getLength() + 3); - tempInfoLog.getLog(static_cast(tempInfoLog.getLength()), NULL, &tempCharBuffer[0]); - ERR("Error compiling dynamic pixel executable:\n%s\n", &tempCharBuffer[0]); + ERR() << "Error compiling dynamic pixel executable:" << std::endl + << tempInfoLog.str() << std::endl; } - *outExectuable = pixelExecutable; - return gl::Error(GL_NO_ERROR); + *outExecutable = pixelExecutable; + return gl::NoError(); } -gl::Error ProgramD3D::getVertexExecutableForInputLayout(const gl::InputLayout &inputLayout, - ShaderExecutableD3D **outExectuable, - gl::InfoLog *infoLog) +gl::Error ProgramD3D::getVertexExecutableForCachedInputLayout(ShaderExecutableD3D **outExectuable, + gl::InfoLog *infoLog) { - VertexExecutable::getSignature(mRenderer, inputLayout, &mCachedVertexSignature); - - for (size_t executableIndex = 0; executableIndex < mVertexExecutables.size(); executableIndex++) + if (mCachedVertexExecutableIndex.valid()) { - if (mVertexExecutables[executableIndex]->matchesSignature(mCachedVertexSignature)) - { - *outExectuable = mVertexExecutables[executableIndex]->shaderExecutable(); - return gl::Error(GL_NO_ERROR); - } + *outExectuable = + mVertexExecutables[mCachedVertexExecutableIndex.value()]->shaderExecutable(); + return gl::NoError(); } // Generate new dynamic layout with attribute conversions std::string finalVertexHLSL = mDynamicHLSL->generateVertexShaderForInputLayout( - mVertexHLSL, inputLayout, mData.getAttributes()); + mVertexHLSL, mCachedInputLayout, mState.getAttributes()); // Generate new vertex executable - ShaderExecutableD3D *vertexExecutable = NULL; + ShaderExecutableD3D *vertexExecutable = nullptr; gl::InfoLog tempInfoLog; gl::InfoLog *currentInfoLog = infoLog ? infoLog : &tempInfoLog; - gl::Error error = mRenderer->compileToExecutable( - *currentInfoLog, finalVertexHLSL, SHADER_VERTEX, mStreamOutVaryings, - (mData.getTransformFeedbackBufferMode() == GL_SEPARATE_ATTRIBS), mVertexWorkarounds, - &vertexExecutable); - if (error.isError()) - { - return error; - } + ANGLE_TRY(mRenderer->compileToExecutable( + *currentInfoLog, finalVertexHLSL, gl::SHADER_VERTEX, mStreamOutVaryings, + (mState.getTransformFeedbackBufferMode() == GL_SEPARATE_ATTRIBS), mVertexWorkarounds, + &vertexExecutable)); if (vertexExecutable) { - mVertexExecutables.push_back( - new VertexExecutable(inputLayout, mCachedVertexSignature, vertexExecutable)); + mVertexExecutables.push_back(std::unique_ptr( + new VertexExecutable(mCachedInputLayout, mCachedVertexSignature, vertexExecutable))); + mCachedVertexExecutableIndex = mVertexExecutables.size() - 1; } else if (!infoLog) { - std::vector tempCharBuffer(tempInfoLog.getLength() + 3); - tempInfoLog.getLog(static_cast(tempInfoLog.getLength()), NULL, &tempCharBuffer[0]); - ERR("Error compiling dynamic vertex executable:\n%s\n", &tempCharBuffer[0]); + ERR() << "Error compiling dynamic vertex executable:" << std::endl + << tempInfoLog.str() << std::endl; } *outExectuable = vertexExecutable; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error ProgramD3D::getGeometryExecutableForPrimitiveType(const gl::Data &data, +gl::Error ProgramD3D::getGeometryExecutableForPrimitiveType(const gl::Context *context, GLenum drawMode, ShaderExecutableD3D **outExecutable, gl::InfoLog *infoLog) @@ -1251,75 +1335,188 @@ gl::Error ProgramD3D::getGeometryExecutableForPrimitiveType(const gl::Data &data // Return a null shader if the current rendering doesn't use a geometry shader if (!usesGeometryShader(drawMode)) { - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } gl::PrimitiveType geometryShaderType = GetGeometryShaderTypeFromDrawMode(drawMode); - if (mGeometryExecutables[geometryShaderType] != nullptr) + if (mGeometryExecutables[geometryShaderType]) { if (outExecutable) { - *outExecutable = mGeometryExecutables[geometryShaderType]; + *outExecutable = mGeometryExecutables[geometryShaderType].get(); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } std::string geometryHLSL = mDynamicHLSL->generateGeometryShaderHLSL( - geometryShaderType, data, mData, mRenderer->presentPathFastEnabled(), - mGeometryShaderPreamble); + context, geometryShaderType, mState, mRenderer->presentPathFastEnabled(), + mHasANGLEMultiviewEnabled, mRenderer->canSelectViewInVertexShader(), + usesGeometryShaderForPointSpriteEmulation(), mGeometryShaderPreamble); gl::InfoLog tempInfoLog; gl::InfoLog *currentInfoLog = infoLog ? infoLog : &tempInfoLog; - gl::Error error = mRenderer->compileToExecutable( - *currentInfoLog, geometryHLSL, SHADER_GEOMETRY, mStreamOutVaryings, - (mData.getTransformFeedbackBufferMode() == GL_SEPARATE_ATTRIBS), D3DCompilerWorkarounds(), - &mGeometryExecutables[geometryShaderType]); + ShaderExecutableD3D *geometryExecutable = nullptr; + gl::Error error = mRenderer->compileToExecutable( + *currentInfoLog, geometryHLSL, gl::SHADER_GEOMETRY, mStreamOutVaryings, + (mState.getTransformFeedbackBufferMode() == GL_SEPARATE_ATTRIBS), + angle::CompilerWorkaroundsD3D(), &geometryExecutable); if (!infoLog && error.isError()) { - std::vector tempCharBuffer(tempInfoLog.getLength() + 3); - tempInfoLog.getLog(static_cast(tempInfoLog.getLength()), NULL, &tempCharBuffer[0]); - ERR("Error compiling dynamic geometry executable:\n%s\n", &tempCharBuffer[0]); + ERR() << "Error compiling dynamic geometry executable:" << std::endl + << tempInfoLog.str() << std::endl; + } + + if (geometryExecutable != nullptr) + { + mGeometryExecutables[geometryShaderType].reset(geometryExecutable); } if (outExecutable) { - *outExecutable = mGeometryExecutables[geometryShaderType]; + *outExecutable = mGeometryExecutables[geometryShaderType].get(); } return error; } -LinkResult ProgramD3D::compileProgramExecutables(const gl::Data &data, gl::InfoLog &infoLog) +class ProgramD3D::GetExecutableTask : public Closure +{ + public: + GetExecutableTask(ProgramD3D *program) + : mProgram(program), mError(gl::NoError()), mInfoLog(), mResult(nullptr) + { + } + + virtual gl::Error run() = 0; + + void operator()() override { mError = run(); } + + const gl::Error &getError() const { return mError; } + const gl::InfoLog &getInfoLog() const { return mInfoLog; } + ShaderExecutableD3D *getResult() { return mResult; } + + protected: + ProgramD3D *mProgram; + gl::Error mError; + gl::InfoLog mInfoLog; + ShaderExecutableD3D *mResult; +}; + +class ProgramD3D::GetVertexExecutableTask : public ProgramD3D::GetExecutableTask +{ + public: + GetVertexExecutableTask(ProgramD3D *program, const gl::Context *context) + : GetExecutableTask(program), mContext(context) + { + } + gl::Error run() override + { + mProgram->updateCachedInputLayoutFromShader(mContext); + + ANGLE_TRY(mProgram->getVertexExecutableForCachedInputLayout(&mResult, &mInfoLog)); + + return gl::NoError(); + } + + private: + const gl::Context *mContext; +}; + +void ProgramD3D::updateCachedInputLayoutFromShader(const gl::Context *context) +{ + GetDefaultInputLayoutFromShader(context, mState.getAttachedVertexShader(), &mCachedInputLayout); + VertexExecutable::getSignature(mRenderer, mCachedInputLayout, &mCachedVertexSignature); + updateCachedVertexExecutableIndex(); +} + +class ProgramD3D::GetPixelExecutableTask : public ProgramD3D::GetExecutableTask { - const gl::InputLayout &defaultInputLayout = - GetDefaultInputLayoutFromShader(mData.getAttachedVertexShader()); - ShaderExecutableD3D *defaultVertexExecutable = NULL; - gl::Error error = - getVertexExecutableForInputLayout(defaultInputLayout, &defaultVertexExecutable, &infoLog); - if (error.isError()) + public: + GetPixelExecutableTask(ProgramD3D *program) : GetExecutableTask(program) {} + gl::Error run() override { - return LinkResult(false, error); + mProgram->updateCachedOutputLayoutFromShader(); + + ANGLE_TRY(mProgram->getPixelExecutableForCachedOutputLayout(&mResult, &mInfoLog)); + + return gl::NoError(); } +}; + +void ProgramD3D::updateCachedOutputLayoutFromShader() +{ + GetDefaultOutputLayoutFromShader(mPixelShaderKey, &mPixelShaderOutputLayoutCache); + updateCachedPixelExecutableIndex(); +} - std::vector defaultPixelOutput = GetDefaultOutputLayoutFromShader(getPixelShaderKey()); - ShaderExecutableD3D *defaultPixelExecutable = NULL; - error = - getPixelExecutableForOutputLayout(defaultPixelOutput, &defaultPixelExecutable, &infoLog); - if (error.isError()) +class ProgramD3D::GetGeometryExecutableTask : public ProgramD3D::GetExecutableTask +{ + public: + GetGeometryExecutableTask(ProgramD3D *program, const gl::Context *context) + : GetExecutableTask(program), mContext(context) { - return LinkResult(false, error); } - // Auto-generate the geometry shader here, if we expect to be using point rendering in D3D11. - ShaderExecutableD3D *pointGS = nullptr; - if (usesGeometryShader(GL_POINTS)) + gl::Error run() override { - getGeometryExecutableForPrimitiveType(data, GL_POINTS, &pointGS, &infoLog); + // Auto-generate the geometry shader here, if we expect to be using point rendering in + // D3D11. + if (mProgram->usesGeometryShader(GL_POINTS)) + { + ANGLE_TRY(mProgram->getGeometryExecutableForPrimitiveType(mContext, GL_POINTS, &mResult, + &mInfoLog)); + } + + return gl::NoError(); } - const ShaderD3D *vertexShaderD3D = GetImplAs(mData.getAttachedVertexShader()); + private: + const gl::Context *mContext; +}; + +gl::Error ProgramD3D::getComputeExecutable(ShaderExecutableD3D **outExecutable) +{ + if (outExecutable) + { + *outExecutable = mComputeExecutable.get(); + } + + return gl::NoError(); +} + +gl::LinkResult ProgramD3D::compileProgramExecutables(const gl::Context *context, + gl::InfoLog &infoLog) +{ + // Ensure the compiler is initialized to avoid race conditions. + ANGLE_TRY(mRenderer->ensureHLSLCompilerInitialized()); + + WorkerThreadPool *workerPool = mRenderer->getWorkerThreadPool(); + + GetVertexExecutableTask vertexTask(this, context); + GetPixelExecutableTask pixelTask(this); + GetGeometryExecutableTask geometryTask(this, context); + + std::array waitEvents = {{workerPool->postWorkerTask(&vertexTask), + workerPool->postWorkerTask(&pixelTask), + workerPool->postWorkerTask(&geometryTask)}}; + + WaitableEvent::WaitMany(&waitEvents); + + infoLog << vertexTask.getInfoLog().str(); + infoLog << pixelTask.getInfoLog().str(); + infoLog << geometryTask.getInfoLog().str(); + + ANGLE_TRY(vertexTask.getError()); + ANGLE_TRY(pixelTask.getError()); + ANGLE_TRY(geometryTask.getError()); + + ShaderExecutableD3D *defaultVertexExecutable = vertexTask.getResult(); + ShaderExecutableD3D *defaultPixelExecutable = pixelTask.getResult(); + ShaderExecutableD3D *pointGS = geometryTask.getResult(); + + const ShaderD3D *vertexShaderD3D = GetImplAs(mState.getAttachedVertexShader()); if (usesGeometryShader(GL_POINTS) && pointGS) { @@ -1339,128 +1536,148 @@ LinkResult ProgramD3D::compileProgramExecutables(const gl::Data &data, gl::InfoL if (defaultPixelExecutable) { const ShaderD3D *fragmentShaderD3D = - GetImplAs(mData.getAttachedFragmentShader()); + GetImplAs(mState.getAttachedFragmentShader()); fragmentShaderD3D->appendDebugInfo(defaultPixelExecutable->getDebugInfo()); } - bool linkSuccess = (defaultVertexExecutable && defaultPixelExecutable && - (!usesGeometryShader(GL_POINTS) || pointGS)); - return LinkResult(linkSuccess, gl::Error(GL_NO_ERROR)); + return (defaultVertexExecutable && defaultPixelExecutable && + (!usesGeometryShader(GL_POINTS) || pointGS)); } -LinkResult ProgramD3D::link(const gl::Data &data, gl::InfoLog &infoLog) +gl::LinkResult ProgramD3D::compileComputeExecutable(const gl::Context *context, + gl::InfoLog &infoLog) { - reset(); + // Ensure the compiler is initialized to avoid race conditions. + ANGLE_TRY(mRenderer->ensureHLSLCompilerInitialized()); - // TODO(jmadill): structures containing samplers - for (const gl::LinkedUniform &linkedUniform : mData.getUniforms()) + std::string computeShader = mDynamicHLSL->generateComputeShaderLinkHLSL(context, mState); + + ShaderExecutableD3D *computeExecutable = nullptr; + ANGLE_TRY(mRenderer->compileToExecutable(infoLog, computeShader, gl::SHADER_COMPUTE, + std::vector(), false, + angle::CompilerWorkaroundsD3D(), &computeExecutable)); + + if (computeExecutable == nullptr) { - if (linkedUniform.isSampler() && linkedUniform.isField()) - { - infoLog << "Structures containing samplers not currently supported in D3D."; - return LinkResult(false, gl::Error(GL_NO_ERROR)); - } + ERR() << "Error compiling dynamic compute executable:" << std::endl + << infoLog.str() << std::endl; + } + else + { + const ShaderD3D *computeShaderD3D = GetImplAs(mState.getAttachedComputeShader()); + computeShaderD3D->appendDebugInfo(computeExecutable->getDebugInfo()); + mComputeExecutable.reset(computeExecutable); } - const gl::Shader *vertexShader = mData.getAttachedVertexShader(); - const gl::Shader *fragmentShader = mData.getAttachedFragmentShader(); - - const ShaderD3D *vertexShaderD3D = GetImplAs(vertexShader); - const ShaderD3D *fragmentShaderD3D = GetImplAs(fragmentShader); + return mComputeExecutable.get() != nullptr; +} - mSamplersVS.resize(data.caps->maxVertexTextureImageUnits); - mSamplersPS.resize(data.caps->maxTextureImageUnits); +gl::LinkResult ProgramD3D::link(const gl::Context *context, + const gl::ProgramLinkedResources &resources, + gl::InfoLog &infoLog) +{ + const auto &data = context->getContextState(); - vertexShaderD3D->generateWorkarounds(&mVertexWorkarounds); - fragmentShaderD3D->generateWorkarounds(&mPixelWorkarounds); + reset(); - if (mRenderer->getRendererLimitations().noFrontFacingSupport) + gl::Shader *computeShader = mState.getAttachedComputeShader(); + if (computeShader) { - if (fragmentShaderD3D->usesFrontFacing()) + mSamplersCS.resize(data.getCaps().maxComputeTextureImageUnits); + + defineUniformsAndAssignRegisters(context); + + gl::LinkResult result = compileComputeExecutable(context, infoLog); + if (result.isError()) + { + infoLog << result.getError().getMessage(); + return result; + } + else if (!result.getResult()) { - infoLog << "The current renderer doesn't support gl_FrontFacing"; - return LinkResult(false, gl::Error(GL_NO_ERROR)); + infoLog << "Failed to create D3D compute shader."; + return result; } } + else + { + gl::Shader *vertexShader = mState.getAttachedVertexShader(); + gl::Shader *fragmentShader = mState.getAttachedFragmentShader(); - std::vector packedVaryings = - MergeVaryings(*vertexShader, *fragmentShader, mData.getTransformFeedbackVaryingNames()); + const ShaderD3D *vertexShaderD3D = GetImplAs(vertexShader); + const ShaderD3D *fragmentShaderD3D = GetImplAs(fragmentShader); - // Map the varyings to the register file - VaryingPacking varyingPacking(data.caps->maxVaryingVectors); - if (!varyingPacking.packVaryings(infoLog, packedVaryings, - mData.getTransformFeedbackVaryingNames())) - { - return LinkResult(false, gl::Error(GL_NO_ERROR)); - } + mSamplersVS.resize(data.getCaps().maxVertexTextureImageUnits); + mSamplersPS.resize(data.getCaps().maxTextureImageUnits); - ProgramD3DMetadata metadata(mRenderer->getMajorShaderModel(), mRenderer->getShaderModelSuffix(), - usesInstancedPointSpriteEmulation(), - mRenderer->presentPathFastEnabled(), vertexShaderD3D, - fragmentShaderD3D); + vertexShaderD3D->generateWorkarounds(&mVertexWorkarounds); + fragmentShaderD3D->generateWorkarounds(&mPixelWorkarounds); - varyingPacking.enableBuiltins(SHADER_VERTEX, metadata); - varyingPacking.enableBuiltins(SHADER_PIXEL, metadata); + if (mRenderer->getNativeLimitations().noFrontFacingSupport) + { + if (fragmentShaderD3D->usesFrontFacing()) + { + infoLog << "The current renderer doesn't support gl_FrontFacing"; + return false; + } + } - if (static_cast(varyingPacking.getRegisterCount()) > data.caps->maxVaryingVectors) - { - infoLog << "No varying registers left to support gl_FragCoord/gl_PointCoord"; - return LinkResult(false, gl::Error(GL_NO_ERROR)); - } + // TODO(jmadill): Implement more sophisticated component packing in D3D9. + // We can fail here because we use one semantic per GLSL varying. D3D11 can pack varyings + // intelligently, but D3D9 assumes one semantic per register. + if (mRenderer->getRendererClass() == RENDERER_D3D9 && + resources.varyingPacking.getMaxSemanticIndex() > data.getCaps().maxVaryingVectors) + { + infoLog << "Cannot pack these varyings on D3D9."; + return false; + } - // TODO(jmadill): Implement more sophisticated component packing in D3D9. - // We can fail here because we use one semantic per GLSL varying. D3D11 can pack varyings - // intelligently, but D3D9 assumes one semantic per register. - if (mRenderer->getRendererClass() == RENDERER_D3D9 && - varyingPacking.getMaxSemanticIndex() > data.caps->maxVaryingVectors) - { - infoLog << "Cannot pack these varyings on D3D9."; - return LinkResult(false, gl::Error(GL_NO_ERROR)); - } + ProgramD3DMetadata metadata(mRenderer, vertexShaderD3D, fragmentShaderD3D); + BuiltinVaryingsD3D builtins(metadata, resources.varyingPacking); - if (!mDynamicHLSL->generateShaderLinkHLSL(data, mData, metadata, varyingPacking, &mPixelHLSL, - &mVertexHLSL)) - { - return LinkResult(false, gl::Error(GL_NO_ERROR)); - } + mDynamicHLSL->generateShaderLinkHLSL(context, mState, metadata, resources.varyingPacking, + builtins, &mPixelHLSL, &mVertexHLSL); - mUsesPointSize = vertexShaderD3D->usesPointSize(); - mDynamicHLSL->getPixelShaderOutputKey(data, mData, metadata, &mPixelShaderKey); - mUsesFragDepth = metadata.usesFragDepth(mData); + mUsesPointSize = vertexShaderD3D->usesPointSize(); + mDynamicHLSL->getPixelShaderOutputKey(data, mState, metadata, &mPixelShaderKey); + mUsesFragDepth = metadata.usesFragDepth(); + mUsesViewID = metadata.usesViewID(); + mHasANGLEMultiviewEnabled = metadata.hasANGLEMultiviewEnabled(); - // Cache if we use flat shading - mUsesFlatInterpolation = false; - for (const auto &varying : packedVaryings) - { - if (varying.interpolation == sh::INTERPOLATION_FLAT) + // Cache if we use flat shading + mUsesFlatInterpolation = + (FindFlatInterpolationVarying(fragmentShader->getInputVaryings(context)) || + FindFlatInterpolationVarying(vertexShader->getOutputVaryings(context))); + + if (mRenderer->getMajorShaderModel() >= 4) { - mUsesFlatInterpolation = true; - break; + mGeometryShaderPreamble = mDynamicHLSL->generateGeometryShaderPreamble( + resources.varyingPacking, builtins, mHasANGLEMultiviewEnabled, + metadata.canSelectViewInVertexShader()); } - } - if (mRenderer->getMajorShaderModel() >= 4) - { - varyingPacking.enableBuiltins(SHADER_GEOMETRY, metadata); - mGeometryShaderPreamble = mDynamicHLSL->generateGeometryShaderPreamble(varyingPacking); - } - - initSemanticIndex(); + initAttribLocationsToD3DSemantic(context); - defineUniformsAndAssignRegisters(); + defineUniformsAndAssignRegisters(context); - gatherTransformFeedbackVaryings(varyingPacking); + gatherTransformFeedbackVaryings(resources.varyingPacking, builtins[gl::SHADER_VERTEX]); - LinkResult result = compileProgramExecutables(data, infoLog); - if (result.error.isError() || !result.linkSuccess) - { - infoLog << "Failed to create D3D shaders."; - return result; + gl::LinkResult result = compileProgramExecutables(context, infoLog); + if (result.isError()) + { + infoLog << result.getError().getMessage(); + return result; + } + else if (!result.getResult()) + { + infoLog << "Failed to create D3D shaders."; + return result; + } } - initUniformBlockInfo(); + linkResources(context, resources); - return LinkResult(true, gl::Error(GL_NO_ERROR)); + return true; } GLboolean ProgramD3D::validate(const gl::Caps & /*caps*/, gl::InfoLog * /*infoLog*/) @@ -1469,46 +1686,22 @@ GLboolean ProgramD3D::validate(const gl::Caps & /*caps*/, gl::InfoLog * /*infoLo return GL_TRUE; } -void ProgramD3D::initUniformBlockInfo() +void ProgramD3D::initializeUniformBlocks() { - const gl::Shader *vertexShader = mData.getAttachedVertexShader(); - - for (const sh::InterfaceBlock &vertexBlock : vertexShader->getInterfaceBlocks()) - { - if (!vertexBlock.staticUse && vertexBlock.layout == sh::BLOCKLAYOUT_PACKED) - continue; - - if (mBlockDataSizes.count(vertexBlock.name) > 0) - continue; - - size_t dataSize = getUniformBlockInfo(vertexBlock); - mBlockDataSizes[vertexBlock.name] = dataSize; - } - - const gl::Shader *fragmentShader = mData.getAttachedFragmentShader(); - - for (const sh::InterfaceBlock &fragmentBlock : fragmentShader->getInterfaceBlocks()) + if (mState.getUniformBlocks().empty()) { - if (!fragmentBlock.staticUse && fragmentBlock.layout == sh::BLOCKLAYOUT_PACKED) - continue; - - if (mBlockDataSizes.count(fragmentBlock.name) > 0) - continue; - - size_t dataSize = getUniformBlockInfo(fragmentBlock); - mBlockDataSizes[fragmentBlock.name] = dataSize; + return; } -} -void ProgramD3D::assignUniformBlockRegisters() -{ - mD3DUniformBlocks.clear(); + ASSERT(mD3DUniformBlocks.empty()); // Assign registers and update sizes. - const ShaderD3D *vertexShaderD3D = GetImplAs(mData.getAttachedVertexShader()); - const ShaderD3D *fragmentShaderD3D = GetImplAs(mData.getAttachedFragmentShader()); + const ShaderD3D *vertexShaderD3D = SafeGetImplAs(mState.getAttachedVertexShader()); + const ShaderD3D *fragmentShaderD3D = + SafeGetImplAs(mState.getAttachedFragmentShader()); + const ShaderD3D *computeShaderD3D = SafeGetImplAs(mState.getAttachedComputeShader()); - for (const gl::UniformBlock &uniformBlock : mData.getUniformBlocks()) + for (const gl::InterfaceBlock &uniformBlock : mState.getUniformBlocks()) { unsigned int uniformBlockElement = uniformBlock.isArray ? uniformBlock.arrayElement : 0; @@ -1516,18 +1709,27 @@ void ProgramD3D::assignUniformBlockRegisters() if (uniformBlock.vertexStaticUse) { - unsigned int baseRegister = - vertexShaderD3D->getInterfaceBlockRegister(uniformBlock.name); + ASSERT(vertexShaderD3D != nullptr); + unsigned int baseRegister = vertexShaderD3D->getUniformBlockRegister(uniformBlock.name); d3dUniformBlock.vsRegisterIndex = baseRegister + uniformBlockElement; } if (uniformBlock.fragmentStaticUse) { + ASSERT(fragmentShaderD3D != nullptr); unsigned int baseRegister = - fragmentShaderD3D->getInterfaceBlockRegister(uniformBlock.name); + fragmentShaderD3D->getUniformBlockRegister(uniformBlock.name); d3dUniformBlock.psRegisterIndex = baseRegister + uniformBlockElement; } + if (uniformBlock.computeStaticUse) + { + ASSERT(computeShaderD3D != nullptr); + unsigned int baseRegister = + computeShaderD3D->getUniformBlockRegister(uniformBlock.name); + d3dUniformBlock.csRegisterIndex = baseRegister + uniformBlockElement; + } + mD3DUniformBlocks.push_back(d3dUniformBlock); } } @@ -1537,6 +1739,7 @@ void ProgramD3D::initializeUniformStorage() // Compute total default block size unsigned int vertexRegisters = 0; unsigned int fragmentRegisters = 0; + unsigned int computeRegisters = 0; for (const D3DUniform *d3dUniform : mD3DUniforms) { if (!d3dUniform->isSampler()) @@ -1551,55 +1754,67 @@ void ProgramD3D::initializeUniformStorage() fragmentRegisters = std::max( fragmentRegisters, d3dUniform->psRegisterIndex + d3dUniform->registerCount); } + if (d3dUniform->isReferencedByComputeShader()) + { + computeRegisters = std::max( + computeRegisters, d3dUniform->csRegisterIndex + d3dUniform->registerCount); + } } } - mVertexUniformStorage = mRenderer->createUniformStorage(vertexRegisters * 16u); - mFragmentUniformStorage = mRenderer->createUniformStorage(fragmentRegisters * 16u); -} - -gl::Error ProgramD3D::applyUniforms(GLenum drawMode) -{ - ASSERT(!mDirtySamplerMapping); - - gl::Error error = mRenderer->applyUniforms(*this, drawMode, mD3DUniforms); - if (error.isError()) - { - return error; - } + mVertexUniformStorage = + std::unique_ptr(mRenderer->createUniformStorage(vertexRegisters * 16u)); + mFragmentUniformStorage = std::unique_ptr( + mRenderer->createUniformStorage(fragmentRegisters * 16u)); + mComputeUniformStorage = + std::unique_ptr(mRenderer->createUniformStorage(computeRegisters * 16u)); + // Iterate the uniforms again to assign data pointers to default block uniforms. for (D3DUniform *d3dUniform : mD3DUniforms) { - d3dUniform->dirty = false; - } + if (d3dUniform->isSampler()) + { + d3dUniform->mSamplerData.resize(d3dUniform->getArraySizeProduct(), 0); + continue; + } - return gl::Error(GL_NO_ERROR); -} + if (d3dUniform->isReferencedByVertexShader()) + { + d3dUniform->vsData = mVertexUniformStorage->getDataPointer(d3dUniform->vsRegisterIndex, + d3dUniform->registerElement); + } -gl::Error ProgramD3D::applyUniformBuffers(const gl::Data &data) -{ - if (mData.getUniformBlocks().empty()) - { - return gl::Error(GL_NO_ERROR); + if (d3dUniform->isReferencedByFragmentShader()) + { + d3dUniform->psData = mFragmentUniformStorage->getDataPointer( + d3dUniform->psRegisterIndex, d3dUniform->registerElement); + } + + if (d3dUniform->isReferencedByComputeShader()) + { + d3dUniform->csData = mComputeUniformStorage->getDataPointer( + d3dUniform->csRegisterIndex, d3dUniform->registerElement); + } } +} - // Lazy init. - if (mD3DUniformBlocks.empty()) +void ProgramD3D::updateUniformBufferCache(const gl::Caps &caps, + unsigned int reservedVertex, + unsigned int reservedFragment) +{ + if (mState.getUniformBlocks().empty()) { - assignUniformBlockRegisters(); + return; } mVertexUBOCache.clear(); mFragmentUBOCache.clear(); - const unsigned int reservedBuffersInVS = mRenderer->getReservedVertexUniformBuffers(); - const unsigned int reservedBuffersInFS = mRenderer->getReservedFragmentUniformBuffers(); - for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < mD3DUniformBlocks.size(); uniformBlockIndex++) { const D3DUniformBlock &uniformBlock = mD3DUniformBlocks[uniformBlockIndex]; - GLuint blockBinding = mData.getUniformBlockBinding(uniformBlockIndex); + GLuint blockBinding = mState.getUniformBlockBinding(uniformBlockIndex); // Unnecessary to apply an unreferenced standard or shared UBO if (!uniformBlock.vertexStaticUse() && !uniformBlock.fragmentStaticUse()) @@ -1609,8 +1824,8 @@ gl::Error ProgramD3D::applyUniformBuffers(const gl::Data &data) if (uniformBlock.vertexStaticUse()) { - unsigned int registerIndex = uniformBlock.vsRegisterIndex - reservedBuffersInVS; - ASSERT(registerIndex < data.caps->maxVertexUniformBlocks); + unsigned int registerIndex = uniformBlock.vsRegisterIndex - reservedVertex; + ASSERT(registerIndex < caps.maxVertexUniformBlocks); if (mVertexUBOCache.size() <= registerIndex) { @@ -1623,8 +1838,8 @@ gl::Error ProgramD3D::applyUniformBuffers(const gl::Data &data) if (uniformBlock.fragmentStaticUse()) { - unsigned int registerIndex = uniformBlock.psRegisterIndex - reservedBuffersInFS; - ASSERT(registerIndex < data.caps->maxFragmentUniformBlocks); + unsigned int registerIndex = uniformBlock.psRegisterIndex - reservedFragment; + ASSERT(registerIndex < caps.maxFragmentUniformBlocks); if (mFragmentUBOCache.size() <= registerIndex) { @@ -1635,36 +1850,50 @@ gl::Error ProgramD3D::applyUniformBuffers(const gl::Data &data) mFragmentUBOCache[registerIndex] = blockBinding; } } +} + +const std::vector &ProgramD3D::getVertexUniformBufferCache() const +{ + return mVertexUBOCache; +} - return mRenderer->setUniformBuffers(data, mVertexUBOCache, mFragmentUBOCache); +const std::vector &ProgramD3D::getFragmentUniformBufferCache() const +{ + return mFragmentUBOCache; } void ProgramD3D::dirtyAllUniforms() { - for (D3DUniform *d3dUniform : mD3DUniforms) - { - d3dUniform->dirty = true; - } + mVertexUniformsDirty = true; + mFragmentUniformsDirty = true; + mComputeUniformsDirty = true; +} + +void ProgramD3D::markUniformsClean() +{ + mVertexUniformsDirty = false; + mFragmentUniformsDirty = false; + mComputeUniformsDirty = false; } void ProgramD3D::setUniform1fv(GLint location, GLsizei count, const GLfloat *v) { - setUniform(location, count, v, GL_FLOAT); + setUniformInternal(location, count, v, GL_FLOAT); } void ProgramD3D::setUniform2fv(GLint location, GLsizei count, const GLfloat *v) { - setUniform(location, count, v, GL_FLOAT_VEC2); + setUniformInternal(location, count, v, GL_FLOAT_VEC2); } void ProgramD3D::setUniform3fv(GLint location, GLsizei count, const GLfloat *v) { - setUniform(location, count, v, GL_FLOAT_VEC3); + setUniformInternal(location, count, v, GL_FLOAT_VEC3); } void ProgramD3D::setUniform4fv(GLint location, GLsizei count, const GLfloat *v) { - setUniform(location, count, v, GL_FLOAT_VEC4); + setUniformInternal(location, count, v, GL_FLOAT_VEC4); } void ProgramD3D::setUniformMatrix2fv(GLint location, @@ -1672,7 +1901,7 @@ void ProgramD3D::setUniformMatrix2fv(GLint location, GLboolean transpose, const GLfloat *value) { - setUniformMatrixfv<2, 2>(location, count, transpose, value, GL_FLOAT_MAT2); + setUniformMatrixfvInternal<2, 2>(location, count, transpose, value, GL_FLOAT_MAT2); } void ProgramD3D::setUniformMatrix3fv(GLint location, @@ -1680,7 +1909,7 @@ void ProgramD3D::setUniformMatrix3fv(GLint location, GLboolean transpose, const GLfloat *value) { - setUniformMatrixfv<3, 3>(location, count, transpose, value, GL_FLOAT_MAT3); + setUniformMatrixfvInternal<3, 3>(location, count, transpose, value, GL_FLOAT_MAT3); } void ProgramD3D::setUniformMatrix4fv(GLint location, @@ -1688,7 +1917,7 @@ void ProgramD3D::setUniformMatrix4fv(GLint location, GLboolean transpose, const GLfloat *value) { - setUniformMatrixfv<4, 4>(location, count, transpose, value, GL_FLOAT_MAT4); + setUniformMatrixfvInternal<4, 4>(location, count, transpose, value, GL_FLOAT_MAT4); } void ProgramD3D::setUniformMatrix2x3fv(GLint location, @@ -1696,7 +1925,7 @@ void ProgramD3D::setUniformMatrix2x3fv(GLint location, GLboolean transpose, const GLfloat *value) { - setUniformMatrixfv<2, 3>(location, count, transpose, value, GL_FLOAT_MAT2x3); + setUniformMatrixfvInternal<2, 3>(location, count, transpose, value, GL_FLOAT_MAT2x3); } void ProgramD3D::setUniformMatrix3x2fv(GLint location, @@ -1704,7 +1933,7 @@ void ProgramD3D::setUniformMatrix3x2fv(GLint location, GLboolean transpose, const GLfloat *value) { - setUniformMatrixfv<3, 2>(location, count, transpose, value, GL_FLOAT_MAT3x2); + setUniformMatrixfvInternal<3, 2>(location, count, transpose, value, GL_FLOAT_MAT3x2); } void ProgramD3D::setUniformMatrix2x4fv(GLint location, @@ -1712,7 +1941,7 @@ void ProgramD3D::setUniformMatrix2x4fv(GLint location, GLboolean transpose, const GLfloat *value) { - setUniformMatrixfv<2, 4>(location, count, transpose, value, GL_FLOAT_MAT2x4); + setUniformMatrixfvInternal<2, 4>(location, count, transpose, value, GL_FLOAT_MAT2x4); } void ProgramD3D::setUniformMatrix4x2fv(GLint location, @@ -1720,7 +1949,7 @@ void ProgramD3D::setUniformMatrix4x2fv(GLint location, GLboolean transpose, const GLfloat *value) { - setUniformMatrixfv<4, 2>(location, count, transpose, value, GL_FLOAT_MAT4x2); + setUniformMatrixfvInternal<4, 2>(location, count, transpose, value, GL_FLOAT_MAT4x2); } void ProgramD3D::setUniformMatrix3x4fv(GLint location, @@ -1728,7 +1957,7 @@ void ProgramD3D::setUniformMatrix3x4fv(GLint location, GLboolean transpose, const GLfloat *value) { - setUniformMatrixfv<3, 4>(location, count, transpose, value, GL_FLOAT_MAT3x4); + setUniformMatrixfvInternal<3, 4>(location, count, transpose, value, GL_FLOAT_MAT3x4); } void ProgramD3D::setUniformMatrix4x3fv(GLint location, @@ -1736,47 +1965,47 @@ void ProgramD3D::setUniformMatrix4x3fv(GLint location, GLboolean transpose, const GLfloat *value) { - setUniformMatrixfv<4, 3>(location, count, transpose, value, GL_FLOAT_MAT4x3); + setUniformMatrixfvInternal<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); + setUniformInternal(location, count, v, GL_INT); } void ProgramD3D::setUniform2iv(GLint location, GLsizei count, const GLint *v) { - setUniform(location, count, v, GL_INT_VEC2); + setUniformInternal(location, count, v, GL_INT_VEC2); } void ProgramD3D::setUniform3iv(GLint location, GLsizei count, const GLint *v) { - setUniform(location, count, v, GL_INT_VEC3); + setUniformInternal(location, count, v, GL_INT_VEC3); } void ProgramD3D::setUniform4iv(GLint location, GLsizei count, const GLint *v) { - setUniform(location, count, v, GL_INT_VEC4); + setUniformInternal(location, count, v, GL_INT_VEC4); } void ProgramD3D::setUniform1uiv(GLint location, GLsizei count, const GLuint *v) { - setUniform(location, count, v, GL_UNSIGNED_INT); + setUniformInternal(location, count, v, GL_UNSIGNED_INT); } void ProgramD3D::setUniform2uiv(GLint location, GLsizei count, const GLuint *v) { - setUniform(location, count, v, GL_UNSIGNED_INT_VEC2); + setUniformInternal(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); + setUniformInternal(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); + setUniformInternal(location, count, v, GL_UNSIGNED_INT_VEC4); } void ProgramD3D::setUniformBlockBinding(GLuint /*uniformBlockIndex*/, @@ -1784,35 +2013,58 @@ void ProgramD3D::setUniformBlockBinding(GLuint /*uniformBlockIndex*/, { } -void ProgramD3D::defineUniformsAndAssignRegisters() +void ProgramD3D::defineUniformsAndAssignRegisters(const gl::Context *context) { D3DUniformMap uniformMap; - const gl::Shader *vertexShader = mData.getAttachedVertexShader(); - for (const sh::Uniform &vertexUniform : vertexShader->getUniforms()) - + gl::Shader *computeShader = mState.getAttachedComputeShader(); + if (computeShader) { - if (vertexUniform.staticUse) + for (const sh::Uniform &computeUniform : computeShader->getUniforms(context)) { - defineUniformBase(vertexShader, vertexUniform, &uniformMap); + if (computeUniform.staticUse) + { + defineUniformBase(computeShader, computeUniform, &uniformMap); + } } } - - const gl::Shader *fragmentShader = mData.getAttachedFragmentShader(); - for (const sh::Uniform &fragmentUniform : fragmentShader->getUniforms()) + else { - if (fragmentUniform.staticUse) + gl::Shader *vertexShader = mState.getAttachedVertexShader(); + for (const sh::Uniform &vertexUniform : vertexShader->getUniforms(context)) + { + if (vertexUniform.staticUse) + { + defineUniformBase(vertexShader, vertexUniform, &uniformMap); + } + } + + gl::Shader *fragmentShader = mState.getAttachedFragmentShader(); + for (const sh::Uniform &fragmentUniform : fragmentShader->getUniforms(context)) { - defineUniformBase(fragmentShader, fragmentUniform, &uniformMap); + if (fragmentUniform.staticUse) + { + defineUniformBase(fragmentShader, fragmentUniform, &uniformMap); + } } } // Initialize the D3DUniform list to mirror the indexing of the GL layer. - for (const gl::LinkedUniform &glUniform : mData.getUniforms()) + for (const gl::LinkedUniform &glUniform : mState.getUniforms()) { if (!glUniform.isInDefaultBlock()) continue; - auto mapEntry = uniformMap.find(glUniform.name); + std::string name = glUniform.name; + if (glUniform.isArray()) + { + // In the program state, array uniform names include [0] as in the program resource + // spec. Here we don't include it. + // TODO(oetuaho@nvidia.com): consider using the same uniform naming here as in the GL + // layer. + ASSERT(angle::EndsWith(name, "[0]")); + name.resize(name.length() - 3); + } + auto mapEntry = uniformMap.find(name); ASSERT(mapEntry != uniformMap.end()); mD3DUniforms.push_back(mapEntry->second); } @@ -1825,7 +2077,8 @@ void ProgramD3D::defineUniformBase(const gl::Shader *shader, const sh::Uniform &uniform, D3DUniformMap *uniformMap) { - if (uniform.isBuiltIn()) + // Samplers get their registers assigned in assignAllSamplerRegisters. + if (uniform.isBuiltIn() || gl::IsSamplerType(uniform.type)) { defineUniform(shader->getType(), uniform, uniform.name, nullptr, uniformMap); return; @@ -1835,7 +2088,7 @@ void ProgramD3D::defineUniformBase(const gl::Shader *shader, unsigned int startRegister = shaderD3D->getUniformRegister(uniform.name); ShShaderOutput outputType = shaderD3D->getCompilerOutputType(); - sh::HLSLBlockEncoder encoder(sh::HLSLBlockEncoder::GetStrategyFor(outputType)); + sh::HLSLBlockEncoder encoder(sh::HLSLBlockEncoder::GetStrategyFor(outputType), true); encoder.skipRegisters(startRegister); defineUniform(shader->getType(), uniform, uniform.name, &encoder, uniformMap); @@ -1854,6 +2107,84 @@ D3DUniform *ProgramD3D::getD3DUniformByName(const std::string &name) return nullptr; } +void ProgramD3D::defineStructUniformFields(GLenum shaderType, + const std::vector &fields, + const std::string &namePrefix, + sh::HLSLBlockEncoder *encoder, + D3DUniformMap *uniformMap) +{ + if (encoder) + encoder->enterAggregateType(); + + for (size_t fieldIndex = 0; fieldIndex < fields.size(); fieldIndex++) + { + const sh::ShaderVariable &field = fields[fieldIndex]; + const std::string &fieldFullName = (namePrefix + "." + field.name); + + // Samplers get their registers assigned in assignAllSamplerRegisters. + // Also they couldn't use the same encoder as the rest of the struct, since they are + // extracted out of the struct by the shader translator. + if (gl::IsSamplerType(field.type)) + { + defineUniform(shaderType, field, fieldFullName, nullptr, uniformMap); + } + else + { + defineUniform(shaderType, field, fieldFullName, encoder, uniformMap); + } + } + + if (encoder) + encoder->exitAggregateType(); +} + +void ProgramD3D::defineArrayOfStructsUniformFields(GLenum shaderType, + const sh::ShaderVariable &uniform, + unsigned int arrayNestingIndex, + const std::string &prefix, + sh::HLSLBlockEncoder *encoder, + D3DUniformMap *uniformMap) +{ + // Nested arrays are processed starting from outermost (arrayNestingIndex 0u) and ending at the + // innermost. + const unsigned int currentArraySize = uniform.getNestedArraySize(arrayNestingIndex); + for (unsigned int arrayElement = 0u; arrayElement < currentArraySize; ++arrayElement) + { + const std::string &elementString = prefix + ArrayString(arrayElement); + if (arrayNestingIndex + 1u < uniform.arraySizes.size()) + { + defineArrayOfStructsUniformFields(shaderType, uniform, arrayNestingIndex + 1u, + elementString, encoder, uniformMap); + } + else + { + defineStructUniformFields(shaderType, uniform.fields, elementString, encoder, + uniformMap); + } + } +} + +void ProgramD3D::defineArrayUniformElements(GLenum shaderType, + const sh::ShaderVariable &uniform, + const std::string &fullName, + sh::HLSLBlockEncoder *encoder, + D3DUniformMap *uniformMap) +{ + if (encoder) + encoder->enterAggregateType(); + + sh::ShaderVariable uniformElement = uniform; + uniformElement.arraySizes.pop_back(); + for (unsigned int arrayIndex = 0u; arrayIndex < uniform.getOutermostArraySize(); ++arrayIndex) + { + std::string elementFullName = fullName + ArrayString(arrayIndex); + defineUniform(shaderType, uniformElement, elementFullName, encoder, uniformMap); + } + + if (encoder) + encoder->exitAggregateType(); +} + void ProgramD3D::defineUniform(GLenum shaderType, const sh::ShaderVariable &uniform, const std::string &fullName, @@ -1862,26 +2193,22 @@ void ProgramD3D::defineUniform(GLenum shaderType, { if (uniform.isStruct()) { - for (unsigned int elementIndex = 0; elementIndex < uniform.elementCount(); elementIndex++) + if (uniform.isArray()) { - const std::string &elementString = (uniform.isArray() ? ArrayString(elementIndex) : ""); - - if (encoder) - 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(shaderType, field, fieldFullName, encoder, uniformMap); - } - - if (encoder) - encoder->exitAggregateType(); + defineArrayOfStructsUniformFields(shaderType, uniform, 0u, fullName, encoder, + uniformMap); + } + else + { + defineStructUniformFields(shaderType, uniform.fields, fullName, encoder, uniformMap); } return; } + if (uniform.isArrayOfArrays()) + { + defineArrayUniformElements(shaderType, uniform, fullName, encoder, uniformMap); + return; + } // Not a struct. Arrays are treated as aggregate types. if (uniform.isArray() && encoder) @@ -1891,7 +2218,7 @@ void ProgramD3D::defineUniform(GLenum shaderType, // Advance the uniform offset, to track registers allocation for structs sh::BlockMemberInfo blockInfo = - encoder ? encoder->encodeType(uniform.type, uniform.arraySize, false) + encoder ? encoder->encodeType(uniform.type, uniform.arraySizes, false) : sh::BlockMemberInfo::getDefaultBlockInfo(); auto uniformMapEntry = uniformMap->find(fullName); @@ -1903,7 +2230,7 @@ void ProgramD3D::defineUniform(GLenum shaderType, } else { - d3dUniform = new D3DUniform(uniform.type, fullName, uniform.arraySize, true); + d3dUniform = new D3DUniform(uniform.type, fullName, uniform.arraySizes, true); (*uniformMap)[fullName] = d3dUniform; } @@ -1917,11 +2244,15 @@ void ProgramD3D::defineUniform(GLenum shaderType, { d3dUniform->psRegisterIndex = reg; } - else + else if (shaderType == GL_VERTEX_SHADER) { - ASSERT(shaderType == GL_VERTEX_SHADER); d3dUniform->vsRegisterIndex = reg; } + else + { + ASSERT(shaderType == GL_COMPUTE_SHADER); + d3dUniform->csRegisterIndex = reg; + } // Arrays are treated as aggregate types if (uniform.isArray()) @@ -1931,177 +2262,223 @@ void ProgramD3D::defineUniform(GLenum shaderType, } } +// Assume count is already clamped. template -void ProgramD3D::setUniform(GLint location, GLsizei countIn, const T *v, GLenum targetUniformType) +void ProgramD3D::setUniformImpl(const gl::VariableLocation &locationInfo, + GLsizei count, + const T *v, + uint8_t *targetData, + GLenum uniformType) { - const int components = gl::VariableComponentCount(targetUniformType); - const GLenum targetBoolType = gl::VariableBoolVectorType(targetUniformType); - - D3DUniform *targetUniform = getD3DUniformFromLocation(location); - - unsigned int elementCount = targetUniform->elementCount(); - unsigned int arrayElement = mData.getUniformLocations()[location].element; - unsigned int count = std::min(elementCount - arrayElement, static_cast(countIn)); + D3DUniform *targetUniform = mD3DUniforms[locationInfo.index]; + const int components = targetUniform->typeInfo.componentCount; + const unsigned int arrayElementOffset = locationInfo.arrayIndex; - if (targetUniform->type == targetUniformType) + if (targetUniform->typeInfo.type == uniformType) { - T *target = reinterpret_cast(targetUniform->data) + arrayElement * 4; + T *dest = reinterpret_cast(targetData) + arrayElementOffset * 4; + const T *source = v; - for (unsigned int i = 0; i < count; i++) + for (GLint i = 0; i < count; i++, dest += 4, source += components) { - 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); - } + memcpy(dest, source, components * sizeof(T)); } } - else if (targetUniform->type == targetBoolType) + else { - GLint *boolParams = reinterpret_cast(targetUniform->data) + arrayElement * 4; + ASSERT(targetUniform->typeInfo.type == gl::VariableBoolVectorType(uniformType)); + GLint *boolParams = reinterpret_cast(targetData) + arrayElementOffset * 4; - for (unsigned int i = 0; i < count; i++) + for (GLint 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); + dest[c] = (source[c] == static_cast(0)) ? GL_FALSE : GL_TRUE; } } } - else if (targetUniform->isSampler()) - { - ASSERT(targetUniformType == GL_INT); - - GLint *target = reinterpret_cast(targetUniform->data) + arrayElement * 4; - - bool wasDirty = targetUniform->dirty; - - for (unsigned 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); - } +template +void ProgramD3D::setUniformInternal(GLint location, GLsizei count, const T *v, GLenum uniformType) +{ + const gl::VariableLocation &locationInfo = mState.getUniformLocations()[location]; + D3DUniform *targetUniform = mD3DUniforms[locationInfo.index]; - if (!wasDirty && targetUniform->dirty) + if (targetUniform->typeInfo.isSampler) + { + ASSERT(uniformType == GL_INT); + size_t size = count * sizeof(T); + GLint *dest = &targetUniform->mSamplerData[locationInfo.arrayIndex]; + if (memcmp(dest, v, size) != 0) { + memcpy(dest, v, size); mDirtySamplerMapping = true; } + return; + } + + if (targetUniform->vsData) + { + setUniformImpl(locationInfo, count, v, targetUniform->vsData, uniformType); + mVertexUniformsDirty = true; + } + + if (targetUniform->psData) + { + setUniformImpl(locationInfo, count, v, targetUniform->psData, uniformType); + mFragmentUniformsDirty = true; + } + + if (targetUniform->csData) + { + setUniformImpl(locationInfo, count, v, targetUniform->csData, uniformType); + mComputeUniformsDirty = true; } - else - UNREACHABLE(); } template -void ProgramD3D::setUniformMatrixfv(GLint location, - GLsizei countIn, - GLboolean transpose, - const GLfloat *value, - GLenum targetUniformType) +bool ProgramD3D::setUniformMatrixfvImpl(GLint location, + GLsizei countIn, + GLboolean transpose, + const GLfloat *value, + uint8_t *targetData, + GLenum targetUniformType) { D3DUniform *targetUniform = getD3DUniformFromLocation(location); - unsigned int elementCount = targetUniform->elementCount(); - unsigned int arrayElement = mData.getUniformLocations()[location].element; - unsigned int count = std::min(elementCount - arrayElement, static_cast(countIn)); + unsigned int elementCount = targetUniform->getArraySizeProduct(); + unsigned int arrayElementOffset = mState.getUniformLocations()[location].arrayIndex; + unsigned int count = + std::min(elementCount - arrayElementOffset, static_cast(countIn)); const unsigned int targetMatrixStride = (4 * rows); - GLfloat *target = - (GLfloat *)(targetUniform->data + arrayElement * sizeof(GLfloat) * targetMatrixStride); + GLfloat *target = reinterpret_cast( + targetData + arrayElementOffset * sizeof(GLfloat) * targetMatrixStride); + + bool dirty = false; for (unsigned 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; + dirty = TransposeExpandMatrix(target, value) || dirty; } else { - targetUniform->dirty = - ExpandMatrix(target, value, 4, rows, cols, rows) || targetUniform->dirty; + dirty = ExpandMatrix(target, value) || dirty; } target += targetMatrixStride; value += cols * rows; } + + return dirty; } -size_t ProgramD3D::getUniformBlockInfo(const sh::InterfaceBlock &interfaceBlock) +template +void ProgramD3D::setUniformMatrixfvInternal(GLint location, + GLsizei countIn, + GLboolean transpose, + const GLfloat *value, + GLenum targetUniformType) { - ASSERT(interfaceBlock.staticUse || interfaceBlock.layout != sh::BLOCKLAYOUT_PACKED); - - // define member uniforms - sh::Std140BlockEncoder std140Encoder; - sh::HLSLBlockEncoder hlslEncoder(sh::HLSLBlockEncoder::ENCODE_PACKED); - sh::BlockLayoutEncoder *encoder = nullptr; + D3DUniform *targetUniform = getD3DUniformFromLocation(location); - if (interfaceBlock.layout == sh::BLOCKLAYOUT_STANDARD) + if (targetUniform->vsData) { - encoder = &std140Encoder; + if (setUniformMatrixfvImpl(location, countIn, transpose, value, + targetUniform->vsData, targetUniformType)) + { + mVertexUniformsDirty = true; + } } - else + + if (targetUniform->psData) { - encoder = &hlslEncoder; + if (setUniformMatrixfvImpl(location, countIn, transpose, value, + targetUniform->psData, targetUniformType)) + { + mFragmentUniformsDirty = true; + } } - GetUniformBlockInfo(interfaceBlock.fields, interfaceBlock.fieldPrefix(), encoder, - interfaceBlock.isRowMajorLayout, &mBlockInfo); - - return encoder->getBlockSize(); + if (targetUniform->csData) + { + if (setUniformMatrixfvImpl(location, countIn, transpose, value, + targetUniform->csData, targetUniformType)) + { + mComputeUniformsDirty = true; + } + } } void ProgramD3D::assignAllSamplerRegisters() { - for (const D3DUniform *d3dUniform : mD3DUniforms) + for (size_t uniformIndex = 0; uniformIndex < mD3DUniforms.size(); ++uniformIndex) { - if (d3dUniform->isSampler()) + if (mD3DUniforms[uniformIndex]->isSampler()) { - assignSamplerRegisters(d3dUniform); + assignSamplerRegisters(uniformIndex); } } } -void ProgramD3D::assignSamplerRegisters(const D3DUniform *d3dUniform) +void ProgramD3D::assignSamplerRegisters(size_t uniformIndex) { + D3DUniform *d3dUniform = mD3DUniforms[uniformIndex]; ASSERT(d3dUniform->isSampler()); - ASSERT(d3dUniform->vsRegisterIndex != GL_INVALID_INDEX || - d3dUniform->psRegisterIndex != GL_INVALID_INDEX); - - if (d3dUniform->vsRegisterIndex != GL_INVALID_INDEX) - { - AssignSamplers(d3dUniform->vsRegisterIndex, d3dUniform->type, d3dUniform->arraySize, - mSamplersVS, &mUsedVertexSamplerRange); + // If the uniform is an array of arrays, then we have separate entries for each inner array in + // mD3DUniforms. However, the sampler register info is stored in the shader only for the + // outermost array. + std::vector subscripts; + const std::string baseName = gl::ParseResourceName(d3dUniform->name, &subscripts); + unsigned int registerOffset = mState.getUniforms()[uniformIndex].flattenedOffsetInParentArrays * + d3dUniform->getArraySizeProduct(); + + const gl::Shader *computeShader = mState.getAttachedComputeShader(); + if (computeShader) + { + const ShaderD3D *computeShaderD3D = GetImplAs(mState.getAttachedComputeShader()); + ASSERT(computeShaderD3D->hasUniform(baseName)); + d3dUniform->csRegisterIndex = + computeShaderD3D->getUniformRegister(baseName) + registerOffset; + ASSERT(d3dUniform->csRegisterIndex != GL_INVALID_INDEX); + AssignSamplers(d3dUniform->csRegisterIndex, d3dUniform->typeInfo, + d3dUniform->getArraySizeProduct(), mSamplersCS, &mUsedComputeSamplerRange); } - - if (d3dUniform->psRegisterIndex != GL_INVALID_INDEX) + else { - AssignSamplers(d3dUniform->psRegisterIndex, d3dUniform->type, d3dUniform->arraySize, - mSamplersPS, &mUsedPixelSamplerRange); + const ShaderD3D *vertexShaderD3D = GetImplAs(mState.getAttachedVertexShader()); + const ShaderD3D *fragmentShaderD3D = + GetImplAs(mState.getAttachedFragmentShader()); + ASSERT(vertexShaderD3D->hasUniform(baseName) || fragmentShaderD3D->hasUniform(baseName)); + if (vertexShaderD3D->hasUniform(baseName)) + { + d3dUniform->vsRegisterIndex = + vertexShaderD3D->getUniformRegister(baseName) + registerOffset; + ASSERT(d3dUniform->vsRegisterIndex != GL_INVALID_INDEX); + AssignSamplers(d3dUniform->vsRegisterIndex, d3dUniform->typeInfo, + d3dUniform->getArraySizeProduct(), mSamplersVS, + &mUsedVertexSamplerRange); + } + if (fragmentShaderD3D->hasUniform(baseName)) + { + d3dUniform->psRegisterIndex = + fragmentShaderD3D->getUniformRegister(baseName) + registerOffset; + ASSERT(d3dUniform->psRegisterIndex != GL_INVALID_INDEX); + AssignSamplers(d3dUniform->psRegisterIndex, d3dUniform->typeInfo, + d3dUniform->getArraySizeProduct(), mSamplersPS, &mUsedPixelSamplerRange); + } } } // static void ProgramD3D::AssignSamplers(unsigned int startSamplerIndex, - GLenum samplerType, + const gl::UniformTypeInfo &typeInfo, unsigned int samplerCount, std::vector &outSamplers, GLuint *outUsedRange) @@ -2113,7 +2490,7 @@ void ProgramD3D::AssignSamplers(unsigned int startSamplerIndex, ASSERT(samplerIndex < outSamplers.size()); Sampler *sampler = &outSamplers[samplerIndex]; sampler->active = true; - sampler->textureType = gl::SamplerTypeToTextureType(samplerType); + sampler->textureType = typeInfo.samplerTextureType; sampler->logicalTextureUnit = 0; *outUsedRange = std::max(samplerIndex + 1, *outUsedRange); samplerIndex++; @@ -2122,20 +2499,24 @@ void ProgramD3D::AssignSamplers(unsigned int startSamplerIndex, void ProgramD3D::reset() { - SafeDeleteContainer(mVertexExecutables); - SafeDeleteContainer(mPixelExecutables); + mVertexExecutables.clear(); + mPixelExecutables.clear(); - for (auto &element : mGeometryExecutables) + for (auto &geometryExecutable : mGeometryExecutables) { - SafeDelete(element); + geometryExecutable.reset(nullptr); } + mComputeExecutable.reset(nullptr); + mVertexHLSL.clear(); - mVertexWorkarounds = D3DCompilerWorkarounds(); + mVertexWorkarounds = angle::CompilerWorkaroundsD3D(); mPixelHLSL.clear(); - mPixelWorkarounds = D3DCompilerWorkarounds(); + mPixelWorkarounds = angle::CompilerWorkaroundsD3D(); mUsesFragDepth = false; + mHasANGLEMultiviewEnabled = false; + mUsesViewID = false; mPixelShaderKey.clear(); mUsesPointSize = false; mUsesFlatInterpolation = false; @@ -2143,22 +2524,29 @@ void ProgramD3D::reset() SafeDeleteContainer(mD3DUniforms); mD3DUniformBlocks.clear(); - SafeDelete(mVertexUniformStorage); - SafeDelete(mFragmentUniformStorage); + mVertexUniformStorage.reset(nullptr); + mFragmentUniformStorage.reset(nullptr); + mComputeUniformStorage.reset(nullptr); mSamplersPS.clear(); mSamplersVS.clear(); + mSamplersCS.clear(); mUsedVertexSamplerRange = 0; mUsedPixelSamplerRange = 0; + mUsedComputeSamplerRange = 0; mDirtySamplerMapping = true; - std::fill(mSemanticIndexes, mSemanticIndexes + ArraySize(mSemanticIndexes), -1); - std::fill(mAttributesByLayout, mAttributesByLayout + ArraySize(mAttributesByLayout), -1); + mAttribLocationToD3DSemantic.fill(-1); mStreamOutVaryings.clear(); mGeometryShaderPreamble.clear(); + + dirtyAllUniforms(); + + mCachedPixelExecutableIndex.reset(); + mCachedVertexExecutableIndex.reset(); } unsigned int ProgramD3D::getSerial() const @@ -2171,84 +2559,96 @@ unsigned int ProgramD3D::issueSerial() return mCurrentSerial++; } -void ProgramD3D::initSemanticIndex() +void ProgramD3D::initAttribLocationsToD3DSemantic(const gl::Context *context) { - const gl::Shader *vertexShader = mData.getAttachedVertexShader(); + gl::Shader *vertexShader = mState.getAttachedVertexShader(); ASSERT(vertexShader != nullptr); // Init semantic index - for (const sh::Attribute &attribute : mData.getAttributes()) + int semanticIndex = 0; + for (const sh::Attribute &attribute : vertexShader->getActiveAttributes(context)) { - int attributeIndex = attribute.location; - int index = vertexShader->getSemanticIndex(attribute.name); - int regs = gl::VariableRegisterCount(attribute.type); + int regCount = gl::VariableRegisterCount(attribute.type); + GLuint location = mState.getAttributeLocation(attribute.name); + ASSERT(location != std::numeric_limits::max()); - for (int reg = 0; reg < regs; ++reg) + for (int reg = 0; reg < regCount; ++reg) { - mSemanticIndexes[attributeIndex + reg] = index + reg; + mAttribLocationToD3DSemantic[location + reg] = semanticIndex++; } } - - initAttributesByLayout(); } -void ProgramD3D::initAttributesByLayout() +void ProgramD3D::updateCachedInputLayout(Serial associatedSerial, const gl::State &state) { - for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) + if (mCurrentVertexArrayStateSerial == associatedSerial) { - mAttributesByLayout[i] = i; + return; } - std::sort(&mAttributesByLayout[0], &mAttributesByLayout[gl::MAX_VERTEX_ATTRIBS], - AttributeSorter(mSemanticIndexes)); -} + mCurrentVertexArrayStateSerial = associatedSerial; + mCachedInputLayout.clear(); -void ProgramD3D::sortAttributesByLayout( - const std::vector &unsortedAttributes, - int sortedSemanticIndicesOut[gl::MAX_VERTEX_ATTRIBS], - const rx::TranslatedAttribute *sortedAttributesOut[gl::MAX_VERTEX_ATTRIBS]) const -{ - for (size_t attribIndex = 0; attribIndex < unsortedAttributes.size(); ++attribIndex) + const auto &vertexAttributes = state.getVertexArray()->getVertexAttributes(); + + for (size_t locationIndex : mState.getActiveAttribLocationsMask()) { - int oldIndex = mAttributesByLayout[attribIndex]; - sortedSemanticIndicesOut[attribIndex] = mSemanticIndexes[oldIndex]; - sortedAttributesOut[attribIndex] = &unsortedAttributes[oldIndex]; + int d3dSemantic = mAttribLocationToD3DSemantic[locationIndex]; + + if (d3dSemantic != -1) + { + if (mCachedInputLayout.size() < static_cast(d3dSemantic + 1)) + { + mCachedInputLayout.resize(d3dSemantic + 1, gl::VERTEX_FORMAT_INVALID); + } + mCachedInputLayout[d3dSemantic] = + GetVertexFormatType(vertexAttributes[locationIndex], + state.getVertexAttribCurrentValue(locationIndex).Type); + } } + + VertexExecutable::getSignature(mRenderer, mCachedInputLayout, &mCachedVertexSignature); + + updateCachedVertexExecutableIndex(); } -void ProgramD3D::updateCachedInputLayout(const gl::State &state) +void ProgramD3D::updateCachedOutputLayout(const gl::Context *context, + const gl::Framebuffer *framebuffer) { - mCachedInputLayout.clear(); - const auto &vertexAttributes = state.getVertexArray()->getVertexAttributes(); + mPixelShaderOutputLayoutCache.clear(); - for (unsigned int attributeIndex : angle::IterateBitSet(mData.getActiveAttribLocationsMask())) + FramebufferD3D *fboD3D = GetImplAs(framebuffer); + const auto &colorbuffers = fboD3D->getColorAttachmentsForRender(context); + + for (size_t colorAttachment = 0; colorAttachment < colorbuffers.size(); ++colorAttachment) { - int semanticIndex = mSemanticIndexes[attributeIndex]; + const gl::FramebufferAttachment *colorbuffer = colorbuffers[colorAttachment]; - if (semanticIndex != -1) + if (colorbuffer) { - if (mCachedInputLayout.size() < static_cast(semanticIndex + 1)) - { - mCachedInputLayout.resize(semanticIndex + 1, gl::VERTEX_FORMAT_INVALID); - } - mCachedInputLayout[semanticIndex] = - GetVertexFormatType(vertexAttributes[attributeIndex], - state.getVertexAttribCurrentValue(attributeIndex).Type); + auto binding = colorbuffer->getBinding() == GL_BACK ? GL_COLOR_ATTACHMENT0 + : colorbuffer->getBinding(); + mPixelShaderOutputLayoutCache.push_back(binding); + } + else + { + mPixelShaderOutputLayoutCache.push_back(GL_NONE); } } + + updateCachedPixelExecutableIndex(); } -void ProgramD3D::gatherTransformFeedbackVaryings(const VaryingPacking &varyingPacking) +void ProgramD3D::gatherTransformFeedbackVaryings(const gl::VaryingPacking &varyingPacking, + const BuiltinInfo &builtins) { - const auto &builtins = varyingPacking.builtins(SHADER_VERTEX); - const std::string &varyingSemantic = GetVaryingSemantic(mRenderer->getMajorShaderModel(), usesPointSize()); // Gather the linked varyings that are used for transform feedback, they should all exist. mStreamOutVaryings.clear(); - const auto &tfVaryingNames = mData.getTransformFeedbackVaryingNames(); + const auto &tfVaryingNames = mState.getTransformFeedbackVaryingNames(); for (unsigned int outputSlot = 0; outputSlot < static_cast(tfVaryingNames.size()); ++outputSlot) { @@ -2278,7 +2678,14 @@ void ProgramD3D::gatherTransformFeedbackVaryings(const VaryingPacking &varyingPa } else { - for (const PackedVaryingRegister ®isterInfo : varyingPacking.getRegisterList()) + std::vector subscripts; + std::string baseName = gl::ParseResourceName(tfVaryingName, &subscripts); + size_t subscript = GL_INVALID_INDEX; + if (!subscripts.empty()) + { + subscript = subscripts.back(); + } + for (const auto ®isterInfo : varyingPacking.getRegisterList()) { const auto &varying = *registerInfo.packedVarying->varying; GLenum transposedType = gl::TransposeMatrixType(varying.type); @@ -2293,7 +2700,8 @@ void ProgramD3D::gatherTransformFeedbackVaryings(const VaryingPacking &varyingPa // There can be more than one register assigned to a particular varying, and each // register needs its own stream out entry. - if (tfVaryingName == varying.name) + if (baseName == registerInfo.packedVarying->varying->name && + (subscript == GL_INVALID_INDEX || subscript == registerInfo.varyingArrayIndex)) { mStreamOutVaryings.push_back(D3DVarying( varyingSemantic, registerInfo.semanticIndex, componentCount, outputSlot)); @@ -2305,36 +2713,155 @@ void ProgramD3D::gatherTransformFeedbackVaryings(const VaryingPacking &varyingPa D3DUniform *ProgramD3D::getD3DUniformFromLocation(GLint location) { - return mD3DUniforms[mData.getUniformLocations()[location].index]; + return mD3DUniforms[mState.getUniformLocations()[location].index]; +} + +const D3DUniform *ProgramD3D::getD3DUniformFromLocation(GLint location) const +{ + return mD3DUniforms[mState.getUniformLocations()[location].index]; } -bool ProgramD3D::getUniformBlockSize(const std::string &blockName, size_t *sizeOut) const +void ProgramD3D::setPathFragmentInputGen(const std::string &inputName, + GLenum genMode, + GLint components, + const GLfloat *coeffs) { - std::string baseName = blockName; - gl::ParseAndStripArrayIndex(&baseName); + UNREACHABLE(); +} - auto sizeIter = mBlockDataSizes.find(baseName); - if (sizeIter == mBlockDataSizes.end()) +bool ProgramD3D::hasVertexExecutableForCachedInputLayout() +{ + return mCachedVertexExecutableIndex.valid(); +} + +bool ProgramD3D::hasGeometryExecutableForPrimitiveType(GLenum drawMode) +{ + if (!usesGeometryShader(drawMode)) { - *sizeOut = 0; - return false; + // No shader necessary mean we have the required (null) executable. + return true; } - *sizeOut = sizeIter->second; - return true; + gl::PrimitiveType geometryShaderType = GetGeometryShaderTypeFromDrawMode(drawMode); + return mGeometryExecutables[geometryShaderType].get() != nullptr; } -bool ProgramD3D::getUniformBlockMemberInfo(const std::string &memberUniformName, - sh::BlockMemberInfo *memberInfoOut) const +bool ProgramD3D::hasPixelExecutableForCachedOutputLayout() { - auto infoIter = mBlockInfo.find(memberUniformName); - if (infoIter == mBlockInfo.end()) + return mCachedPixelExecutableIndex.valid(); +} + +template +void ProgramD3D::getUniformInternal(GLint location, DestT *dataOut) const +{ + const gl::VariableLocation &locationInfo = mState.getUniformLocations()[location]; + const gl::LinkedUniform &uniform = mState.getUniforms()[locationInfo.index]; + + const D3DUniform *targetUniform = getD3DUniformFromLocation(location); + const uint8_t *srcPointer = targetUniform->getDataPtrToElement(locationInfo.arrayIndex); + + if (gl::IsMatrixType(uniform.type)) { - *memberInfoOut = sh::BlockMemberInfo::getDefaultBlockInfo(); - return false; + GetMatrixUniform(gl::VariableColumnCount(uniform.type), gl::VariableRowCount(uniform.type), + dataOut, reinterpret_cast(srcPointer)); + } + else + { + memcpy(dataOut, srcPointer, uniform.getElementSize()); } +} - *memberInfoOut = infoIter->second; - return true; +void ProgramD3D::getUniformfv(const gl::Context *context, GLint location, GLfloat *params) const +{ + getUniformInternal(location, params); +} + +void ProgramD3D::getUniformiv(const gl::Context *context, GLint location, GLint *params) const +{ + getUniformInternal(location, params); +} + +void ProgramD3D::getUniformuiv(const gl::Context *context, GLint location, GLuint *params) const +{ + getUniformInternal(location, params); +} + +void ProgramD3D::updateCachedVertexExecutableIndex() +{ + mCachedVertexExecutableIndex.reset(); + for (size_t executableIndex = 0; executableIndex < mVertexExecutables.size(); executableIndex++) + { + if (mVertexExecutables[executableIndex]->matchesSignature(mCachedVertexSignature)) + { + mCachedVertexExecutableIndex = executableIndex; + break; + } + } +} + +void ProgramD3D::updateCachedPixelExecutableIndex() +{ + mCachedPixelExecutableIndex.reset(); + for (size_t executableIndex = 0; executableIndex < mPixelExecutables.size(); executableIndex++) + { + if (mPixelExecutables[executableIndex]->matchesSignature(mPixelShaderOutputLayoutCache)) + { + mCachedPixelExecutableIndex = executableIndex; + break; + } + } } + +void ProgramD3D::linkResources(const gl::Context *context, + const gl::ProgramLinkedResources &resources) +{ + UniformBlockInfo uniformBlockInfo; + + if (mState.getAttachedVertexShader()) + { + uniformBlockInfo.getShaderBlockInfo(context, mState.getAttachedVertexShader()); + } + + if (mState.getAttachedFragmentShader()) + { + uniformBlockInfo.getShaderBlockInfo(context, mState.getAttachedFragmentShader()); + } + + if (mState.getAttachedComputeShader()) + { + uniformBlockInfo.getShaderBlockInfo(context, mState.getAttachedComputeShader()); + } + + // Gather interface block info. + auto getUniformBlockSize = [&uniformBlockInfo](const std::string &name, + const std::string &mappedName, size_t *sizeOut) { + return uniformBlockInfo.getBlockSize(name, mappedName, sizeOut); + }; + + auto getUniformBlockMemberInfo = [&uniformBlockInfo](const std::string &name, + const std::string &mappedName, + sh::BlockMemberInfo *infoOut) { + return uniformBlockInfo.getBlockMemberInfo(name, mappedName, infoOut); + }; + + resources.uniformBlockLinker.linkBlocks(getUniformBlockSize, getUniformBlockMemberInfo); + initializeUniformBlocks(); + + // TODO(jiajia.qin@intel.com): Determine correct shader storage block info. + auto getShaderStorageBlockSize = [](const std::string &name, const std::string &mappedName, + size_t *sizeOut) { + *sizeOut = 0; + return true; + }; + + auto getShaderStorageBlockMemberInfo = + [](const std::string &name, const std::string &mappedName, sh::BlockMemberInfo *infoOut) { + *infoOut = sh::BlockMemberInfo::getDefaultBlockInfo(); + return true; + }; + + resources.shaderStorageBlockLinker.linkBlocks(getShaderStorageBlockSize, + getShaderStorageBlockMemberInfo); } + +} // namespace rx diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/ProgramD3D.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/ProgramD3D.h index 3dfe52db1c..829757a73e 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/ProgramD3D.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/ProgramD3D.h @@ -17,7 +17,7 @@ #include "libANGLE/formatutils.h" #include "libANGLE/renderer/ProgramImpl.h" #include "libANGLE/renderer/d3d/DynamicHLSL.h" -#include "libANGLE/renderer/d3d/WorkaroundsD3D.h" +#include "platform/WorkaroundsD3D.h" namespace rx { @@ -32,52 +32,71 @@ class ShaderExecutableD3D; #endif // Helper struct representing a single shader uniform -struct D3DUniform : angle::NonCopyable +// TODO(jmadill): Make uniform blocks shared between all programs, so we don't need separate +// register indices. +struct D3DUniform : private angle::NonCopyable { - D3DUniform(GLenum typeIn, + D3DUniform(GLenum type, const std::string &nameIn, - unsigned int arraySizeIn, + const std::vector &arraySizesIn, bool defaultBlock); ~D3DUniform(); bool isSampler() const; - unsigned int elementCount() const { return std::max(1u, arraySize); } + + bool isArray() const { return !arraySizes.empty(); } + unsigned int getArraySizeProduct() const; + bool isReferencedByVertexShader() const; bool isReferencedByFragmentShader() const; + bool isReferencedByComputeShader() const; - // Duplicated from the GL layer - GLenum type; - std::string name; - unsigned int arraySize; + const uint8_t *firstNonNullData() const; + const uint8_t *getDataPtrToElement(size_t elementIndex) const; - // Pointer to a system copy of the data. - // TODO(jmadill): remove this in favor of gl::LinkedUniform::data(). - uint8_t *data; + // Duplicated from the GL layer + const gl::UniformTypeInfo &typeInfo; + std::string name; // Names of arrays don't include [0], unlike at the GL layer. + std::vector arraySizes; - // Has the data been updated since the last sync? - bool dirty; + // Pointer to a system copies of the data. Separate pointers for each uniform storage type. + uint8_t *vsData; + uint8_t *psData; + uint8_t *csData; // Register information. unsigned int vsRegisterIndex; unsigned int psRegisterIndex; + unsigned int csRegisterIndex; 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; + + // Special buffer for sampler values. + std::vector mSamplerData; }; struct D3DUniformBlock { - D3DUniformBlock() : vsRegisterIndex(GL_INVALID_INDEX), psRegisterIndex(GL_INVALID_INDEX) {} + D3DUniformBlock() + : vsRegisterIndex(GL_INVALID_INDEX), + psRegisterIndex(GL_INVALID_INDEX), + csRegisterIndex(GL_INVALID_INDEX) + { + } bool vertexStaticUse() const { return vsRegisterIndex != GL_INVALID_INDEX; } bool fragmentStaticUse() const { return psRegisterIndex != GL_INVALID_INDEX; } + bool computeStaticUse() const { return csRegisterIndex != GL_INVALID_INDEX; } + unsigned int vsRegisterIndex; unsigned int psRegisterIndex; + unsigned int csRegisterIndex; }; struct D3DVarying final @@ -97,24 +116,24 @@ struct D3DVarying final unsigned int outputSlot; }; -class ProgramD3DMetadata : angle::NonCopyable +class ProgramD3DMetadata final : angle::NonCopyable { public: - ProgramD3DMetadata(int rendererMajorShaderModel, - const std::string &shaderModelSuffix, - bool usesInstancedPointSpriteEmulation, - bool usesViewScale, + ProgramD3DMetadata(RendererD3D *renderer, const ShaderD3D *vertexShader, const ShaderD3D *fragmentShader); int getRendererMajorShaderModel() const; - bool usesBroadcast(const gl::Data &data) const; - bool usesFragDepth(const gl::Program::Data &programData) const; + bool usesBroadcast(const gl::ContextState &data) const; + bool usesFragDepth() const; bool usesPointCoord() const; bool usesFragCoord() const; bool usesPointSize() const; bool usesInsertedPointCoordValue() const; bool usesViewScale() const; + bool hasANGLEMultiviewEnabled() const; + bool usesViewID() const; + bool canSelectViewInVertexShader() const; bool addsPointCoordToVertexShader() const; bool usesTransformFeedbackGLPosition() const; bool usesSystemValuePointSize() const; @@ -127,6 +146,9 @@ class ProgramD3DMetadata : angle::NonCopyable const std::string mShaderModelSuffix; const bool mUsesInstancedPointSpriteEmulation; const bool mUsesViewScale; + const bool mHasANGLEMultiviewEnabled; + const bool mUsesViewID; + const bool mCanSelectViewInVertexShader; const ShaderD3D *mVertexShader; const ShaderD3D *mFragmentShader; }; @@ -134,10 +156,8 @@ class ProgramD3DMetadata : angle::NonCopyable class ProgramD3D : public ProgramImpl { public: - typedef int SemanticIndexArray[gl::MAX_VERTEX_ATTRIBS]; - - ProgramD3D(const gl::Program::Data &data, RendererD3D *renderer); - virtual ~ProgramD3D(); + ProgramD3D(const gl::ProgramState &data, RendererD3D *renderer); + ~ProgramD3D() override; const std::vector &getPixelShaderKey() { return mPixelShaderKey; } @@ -145,116 +165,157 @@ class ProgramD3D : public ProgramImpl 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(); + GLuint getUsedSamplerRange(gl::SamplerType type) const; + + enum SamplerMapping + { + WasDirty, + WasClean, + }; + + SamplerMapping updateSamplerMapping(); bool usesPointSize() const { return mUsesPointSize; } bool usesPointSpriteEmulation() const; bool usesGeometryShader(GLenum drawMode) const; + bool usesGeometryShaderForPointSpriteEmulation() const; bool usesInstancedPointSpriteEmulation() const; - LinkResult load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream) override; - gl::Error save(gl::BinaryOutputStream *stream) override; + gl::LinkResult load(const gl::Context *context, + gl::InfoLog &infoLog, + gl::BinaryInputStream *stream) override; + void save(const gl::Context *context, gl::BinaryOutputStream *stream) override; void setBinaryRetrievableHint(bool retrievable) override; + void setSeparable(bool separable) override; - 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::InputLayout &inputLayout, - ShaderExecutableD3D **outExectuable, - gl::InfoLog *infoLog); - gl::Error getGeometryExecutableForPrimitiveType(const gl::Data &data, + gl::Error getVertexExecutableForCachedInputLayout(ShaderExecutableD3D **outExectuable, + gl::InfoLog *infoLog); + gl::Error getGeometryExecutableForPrimitiveType(const gl::Context *context, GLenum drawMode, ShaderExecutableD3D **outExecutable, gl::InfoLog *infoLog); - - LinkResult link(const gl::Data &data, gl::InfoLog &infoLog) override; + gl::Error getPixelExecutableForCachedOutputLayout(ShaderExecutableD3D **outExectuable, + gl::InfoLog *infoLog); + gl::Error getComputeExecutable(ShaderExecutableD3D **outExecutable); + gl::LinkResult link(const gl::Context *context, + const gl::ProgramLinkedResources &resources, + gl::InfoLog &infoLog) override; GLboolean validate(const gl::Caps &caps, gl::InfoLog *infoLog) override; - bool getUniformBlockSize(const std::string &blockName, size_t *sizeOut) const override; - bool getUniformBlockMemberInfo(const std::string &memberUniformName, - sh::BlockMemberInfo *memberInfoOut) const override; + void setPathFragmentInputGen(const std::string &inputName, + GLenum genMode, + GLint components, + const GLfloat *coeffs) override; void initializeUniformStorage(); - gl::Error applyUniforms(GLenum drawMode); - gl::Error applyUniformBuffers(const gl::Data &data); + void updateUniformBufferCache(const gl::Caps &caps, + unsigned int reservedVertex, + unsigned int reservedFragment); + const std::vector &getVertexUniformBufferCache() const; + const std::vector &getFragmentUniformBufferCache() const; + 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 setUniform1fv(GLint location, GLsizei count, const GLfloat *v) override; + void setUniform2fv(GLint location, GLsizei count, const GLfloat *v) override; + void setUniform3fv(GLint location, GLsizei count, const GLfloat *v) override; + void setUniform4fv(GLint location, GLsizei count, const GLfloat *v) override; + void setUniform1iv(GLint location, GLsizei count, const GLint *v) override; + void setUniform2iv(GLint location, GLsizei count, const GLint *v) override; + void setUniform3iv(GLint location, GLsizei count, const GLint *v) override; + void setUniform4iv(GLint location, GLsizei count, const GLint *v) override; + void setUniform1uiv(GLint location, GLsizei count, const GLuint *v) override; + void setUniform2uiv(GLint location, GLsizei count, const GLuint *v) override; + void setUniform3uiv(GLint location, GLsizei count, const GLuint *v) override; + void setUniform4uiv(GLint location, GLsizei count, const GLuint *v) override; void setUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, - const GLfloat *value); + const GLfloat *value) override; void setUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, - const GLfloat *value); + const GLfloat *value) override; void setUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, - const GLfloat *value); + const GLfloat *value) override; void setUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, - const GLfloat *value); + const GLfloat *value) override; void setUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, - const GLfloat *value); + const GLfloat *value) override; void setUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, - const GLfloat *value); + const GLfloat *value) override; void setUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, - const GLfloat *value); + const GLfloat *value) override; void setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, - const GLfloat *value); + const GLfloat *value) override; void setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, - const GLfloat *value); + const GLfloat *value) override; + + void getUniformfv(const gl::Context *context, GLint location, GLfloat *params) const override; + void getUniformiv(const gl::Context *context, GLint location, GLint *params) const override; + void getUniformuiv(const gl::Context *context, GLint location, GLuint *params) const override; void setUniformBlockBinding(GLuint uniformBlockIndex, GLuint uniformBlockBinding) override; - const UniformStorageD3D &getVertexUniformStorage() const { return *mVertexUniformStorage; } - const UniformStorageD3D &getFragmentUniformStorage() const { return *mFragmentUniformStorage; } + UniformStorageD3D &getVertexUniformStorage() const { return *mVertexUniformStorage.get(); } + UniformStorageD3D &getFragmentUniformStorage() const { return *mFragmentUniformStorage.get(); } + UniformStorageD3D &getComputeUniformStorage() const { return *mComputeUniformStorage.get(); } unsigned int getSerial() const; - void sortAttributesByLayout( - const std::vector &unsortedAttributes, - int sortedSemanticIndicesOut[gl::MAX_VERTEX_ATTRIBS], - const rx::TranslatedAttribute *sortedAttributesOut[gl::MAX_VERTEX_ATTRIBS]) const; - const SemanticIndexArray &getSemanticIndexes() const { return mSemanticIndexes; } - const SemanticIndexArray &getAttributesByLayout() const { return mAttributesByLayout; } + const AttribIndexArray &getAttribLocationToD3DSemantics() const + { + return mAttribLocationToD3DSemantic; + } - void updateCachedInputLayout(const gl::State &state); - const gl::InputLayout &getCachedInputLayout() const { return mCachedInputLayout; } + void updateCachedInputLayout(Serial associatedSerial, const gl::State &state); + void updateCachedOutputLayout(const gl::Context *context, const gl::Framebuffer *framebuffer); bool isSamplerMappingDirty() { return mDirtySamplerMapping; } + // Checks if we need to recompile certain shaders. + bool hasVertexExecutableForCachedInputLayout(); + bool hasGeometryExecutableForPrimitiveType(GLenum drawMode); + bool hasPixelExecutableForCachedOutputLayout(); + + bool areVertexUniformsDirty() const { return mVertexUniformsDirty; } + bool areFragmentUniformsDirty() const { return mFragmentUniformsDirty; } + bool areComputeUniformsDirty() const { return mComputeUniformsDirty; } + const std::vector &getD3DUniforms() const { return mD3DUniforms; } + void markUniformsClean(); + private: + // These forward-declared tasks are used for multi-thread shader compiles. + class GetExecutableTask; + class GetVertexExecutableTask; + class GetPixelExecutableTask; + class GetGeometryExecutableTask; + class VertexExecutable { public: - typedef std::vector Signature; + enum HLSLAttribType + { + FLOAT, + UNSIGNED_INT, + SIGNED_INT, + }; + + typedef std::vector Signature; VertexExecutable(const gl::InputLayout &inputLayout, const Signature &signature, @@ -271,6 +332,8 @@ class ProgramD3D : public ProgramImpl ShaderExecutableD3D *shaderExecutable() const { return mShaderExecutable; } private: + static HLSLAttribType GetAttribType(GLenum type); + gl::InputLayout mInputs; Signature mSignature; ShaderExecutableD3D *mShaderExecutable; @@ -307,62 +370,105 @@ class ProgramD3D : public ProgramImpl typedef std::map D3DUniformMap; - void defineUniformsAndAssignRegisters(); + void defineUniformsAndAssignRegisters(const gl::Context *context); void defineUniformBase(const gl::Shader *shader, const sh::Uniform &uniform, D3DUniformMap *uniformMap); + void defineStructUniformFields(GLenum shaderType, + const std::vector &fields, + const std::string &namePrefix, + sh::HLSLBlockEncoder *encoder, + D3DUniformMap *uniformMap); + void defineArrayOfStructsUniformFields(GLenum shaderType, + const sh::ShaderVariable &uniform, + unsigned int arrayNestingIndex, + const std::string &prefix, + sh::HLSLBlockEncoder *encoder, + D3DUniformMap *uniformMap); + void defineArrayUniformElements(GLenum shaderType, + const sh::ShaderVariable &uniform, + const std::string &fullName, + sh::HLSLBlockEncoder *encoder, + D3DUniformMap *uniformMap); void defineUniform(GLenum shaderType, const sh::ShaderVariable &uniform, const std::string &fullName, sh::HLSLBlockEncoder *encoder, D3DUniformMap *uniformMap); void assignAllSamplerRegisters(); - void assignSamplerRegisters(const D3DUniform *d3dUniform); + void assignSamplerRegisters(size_t uniformIndex); static void AssignSamplers(unsigned int startSamplerIndex, - GLenum samplerType, + const gl::UniformTypeInfo &typeInfo, unsigned int samplerCount, std::vector &outSamplers, GLuint *outUsedRange); + template + void getUniformInternal(GLint location, DestT *dataOut) const; + + template + void setUniformImpl(const gl::VariableLocation &locationInfo, + GLsizei count, + const T *v, + uint8_t *targetData, + GLenum uniformType); + template - void setUniform(GLint location, GLsizei count, const T *v, GLenum targetUniformType); + void setUniformInternal(GLint location, GLsizei count, const T *v, GLenum uniformType); template - void setUniformMatrixfv(GLint location, - GLsizei count, - GLboolean transpose, - const GLfloat *value, - GLenum targetUniformType); + bool setUniformMatrixfvImpl(GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value, + uint8_t *targetData, + GLenum targetUniformType); - LinkResult compileProgramExecutables(const gl::Data &data, gl::InfoLog &infoLog); + template + void setUniformMatrixfvInternal(GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value, + GLenum targetUniformType); - void gatherTransformFeedbackVaryings(const VaryingPacking &varyings); + gl::LinkResult compileProgramExecutables(const gl::Context *context, gl::InfoLog &infoLog); + gl::LinkResult compileComputeExecutable(const gl::Context *context, gl::InfoLog &infoLog); + + void gatherTransformFeedbackVaryings(const gl::VaryingPacking &varyings, + const BuiltinInfo &builtins); D3DUniform *getD3DUniformByName(const std::string &name); D3DUniform *getD3DUniformFromLocation(GLint location); + const D3DUniform *getD3DUniformFromLocation(GLint location) const; - void initSemanticIndex(); - void initAttributesByLayout(); + void initAttribLocationsToD3DSemantic(const gl::Context *context); void reset(); - void assignUniformBlockRegisters(); + void initializeUniformBlocks(); + + void updateCachedInputLayoutFromShader(const gl::Context *context); + void updateCachedOutputLayoutFromShader(); + void updateCachedVertexExecutableIndex(); + void updateCachedPixelExecutableIndex(); - void initUniformBlockInfo(); - size_t getUniformBlockInfo(const sh::InterfaceBlock &interfaceBlock); + void linkResources(const gl::Context *context, const gl::ProgramLinkedResources &resources); RendererD3D *mRenderer; DynamicHLSL *mDynamicHLSL; - std::vector mVertexExecutables; - std::vector mPixelExecutables; - std::vector mGeometryExecutables; + std::vector> mVertexExecutables; + std::vector> mPixelExecutables; + std::vector> mGeometryExecutables; + std::unique_ptr mComputeExecutable; std::string mVertexHLSL; - D3DCompilerWorkarounds mVertexWorkarounds; + angle::CompilerWorkaroundsD3D mVertexWorkarounds; std::string mPixelHLSL; - D3DCompilerWorkarounds mPixelWorkarounds; + angle::CompilerWorkaroundsD3D mPixelWorkarounds; bool mUsesFragDepth; + bool mHasANGLEMultiviewEnabled; + bool mUsesViewID; std::vector mPixelShaderKey; // Common code for all dynamic geometry shaders. Consists mainly of the GS input and output @@ -373,20 +479,23 @@ class ProgramD3D : public ProgramImpl bool mUsesPointSize; bool mUsesFlatInterpolation; - UniformStorageD3D *mVertexUniformStorage; - UniformStorageD3D *mFragmentUniformStorage; + std::unique_ptr mVertexUniformStorage; + std::unique_ptr mFragmentUniformStorage; + std::unique_ptr mComputeUniformStorage; std::vector mSamplersPS; std::vector mSamplersVS; + std::vector mSamplersCS; GLuint mUsedVertexSamplerRange; GLuint mUsedPixelSamplerRange; + GLuint mUsedComputeSamplerRange; bool mDirtySamplerMapping; - // Cache for getPixelExecutableForFramebuffer - std::vector mPixelShaderOutputFormatCache; + // Cache for pixel shader output layout to save reallocations. + std::vector mPixelShaderOutputLayoutCache; + Optional mCachedPixelExecutableIndex; - SemanticIndexArray mSemanticIndexes; - SemanticIndexArray mAttributesByLayout; + AttribIndexArray mAttribLocationToD3DSemantic; unsigned int mSerial; @@ -394,17 +503,21 @@ class ProgramD3D : public ProgramImpl std::vector mFragmentUBOCache; VertexExecutable::Signature mCachedVertexSignature; gl::InputLayout mCachedInputLayout; + Optional mCachedVertexExecutableIndex; std::vector mStreamOutVaryings; std::vector mD3DUniforms; std::vector mD3DUniformBlocks; - std::map mBlockInfo; - std::map mBlockDataSizes; + bool mVertexUniformsDirty; + bool mFragmentUniformsDirty; + bool mComputeUniformsDirty; static unsigned int issueSerial(); static unsigned int mCurrentSerial; + + Serial mCurrentVertexArrayStateSerial; }; -} +} // namespace rx #endif // LIBANGLE_RENDERER_D3D_PROGRAMD3D_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/RenderTargetD3D.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/RenderTargetD3D.h index b2d895d9c6..fde96133b0 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/RenderTargetD3D.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/RenderTargetD3D.h @@ -21,7 +21,7 @@ class RenderTargetD3D : public FramebufferAttachmentRenderTarget { public: RenderTargetD3D(); - virtual ~RenderTargetD3D(); + ~RenderTargetD3D() override; virtual GLsizei getWidth() const = 0; virtual GLsizei getHeight() const = 0; @@ -29,10 +29,14 @@ class RenderTargetD3D : public FramebufferAttachmentRenderTarget virtual GLenum getInternalFormat() const = 0; virtual GLsizei getSamples() const = 0; gl::Extents getExtents() const { return gl::Extents(getWidth(), getHeight(), getDepth()); } + bool isMultisampled() const { return getSamples() > 0; } virtual unsigned int getSerial() const; static unsigned int issueSerials(unsigned int count); + // Only currently applies to D3D11. + virtual void signalDirty(const gl::Context *context) {} + private: const unsigned int mSerial; static unsigned int mCurrentSerial; diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/RenderbufferD3D.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/RenderbufferD3D.cpp index 991801a091..d799e0b992 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/RenderbufferD3D.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/RenderbufferD3D.cpp @@ -27,12 +27,25 @@ RenderbufferD3D::~RenderbufferD3D() mImage = nullptr; } -gl::Error RenderbufferD3D::setStorage(GLenum internalformat, size_t width, size_t height) +gl::Error RenderbufferD3D::onDestroy(const gl::Context *context) { - return setStorageMultisample(0, internalformat, width, height); + deleteRenderTarget(context); + return gl::NoError(); } -gl::Error RenderbufferD3D::setStorageMultisample(size_t samples, GLenum internalformat, size_t width, size_t height) +gl::Error RenderbufferD3D::setStorage(const gl::Context *context, + GLenum internalformat, + size_t width, + size_t height) +{ + return setStorageMultisample(context, 0, internalformat, width, height); +} + +gl::Error RenderbufferD3D::setStorageMultisample(const gl::Context *context, + 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 @@ -48,54 +61,70 @@ gl::Error RenderbufferD3D::setStorageMultisample(size_t samples, GLenum internal // the specified storage. // Because ES 3.0 already knows the exact number of supported samples, it would already have been // validated and generated GL_INVALID_VALUE. - const gl::TextureCaps &formatCaps = mRenderer->getRendererTextureCaps().get(creationFormat); + const gl::TextureCaps &formatCaps = mRenderer->getNativeTextureCaps().get(creationFormat); if (samples > formatCaps.getMaxSamples()) { - return gl::Error(GL_OUT_OF_MEMORY, "Renderbuffer format does not support %u samples, %u is the maximum.", - samples, formatCaps.getMaxSamples()); + return gl::OutOfMemory() << "Renderbuffer format does not support " << samples + << " samples, " << formatCaps.getMaxSamples() + << " is the maximum."; } - RenderTargetD3D *newRT = NULL; - gl::Error error = - mRenderer->createRenderTarget(static_cast(width), static_cast(height), - creationFormat, static_cast(samples), &newRT); - if (error.isError()) - { - return error; - } + RenderTargetD3D *newRT = nullptr; + ANGLE_TRY(mRenderer->createRenderTarget(static_cast(width), static_cast(height), + creationFormat, static_cast(samples), &newRT)); - SafeDelete(mRenderTarget); + deleteRenderTarget(context); mImage = nullptr; mRenderTarget = newRT; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error RenderbufferD3D::setStorageEGLImageTarget(egl::Image *image) +gl::Error RenderbufferD3D::setStorageEGLImageTarget(const gl::Context *context, egl::Image *image) { mImage = GetImplAs(image); - SafeDelete(mRenderTarget); + deleteRenderTarget(context); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error RenderbufferD3D::getRenderTarget(RenderTargetD3D **outRenderTarget) +gl::Error RenderbufferD3D::getRenderTarget(const gl::Context *context, + RenderTargetD3D **outRenderTarget) { if (mImage) { - return mImage->getRenderTarget(outRenderTarget); + return mImage->getRenderTarget(context, outRenderTarget); } else { *outRenderTarget = mRenderTarget; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } } -gl::Error RenderbufferD3D::getAttachmentRenderTarget(const gl::FramebufferAttachment::Target &target, +gl::Error RenderbufferD3D::getAttachmentRenderTarget(const gl::Context *context, + GLenum /*binding*/, + const gl::ImageIndex & /*imageIndex*/, FramebufferAttachmentRenderTarget **rtOut) { - return getRenderTarget(reinterpret_cast(rtOut)); + return getRenderTarget(context, reinterpret_cast(rtOut)); } +void RenderbufferD3D::deleteRenderTarget(const gl::Context *context) +{ + if (mRenderTarget) + { + mRenderTarget->signalDirty(context); + SafeDelete(mRenderTarget); + } } + +gl::Error RenderbufferD3D::initializeContents(const gl::Context *context, + const gl::ImageIndex &imageIndex) +{ + RenderTargetD3D *renderTarget = nullptr; + ANGLE_TRY(getRenderTarget(context, &renderTarget)); + return mRenderer->initRenderTarget(renderTarget); +} + +} // namespace rx diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/RenderbufferD3D.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/RenderbufferD3D.h index 20f6a10b2d..b50eff7db7 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/RenderbufferD3D.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/RenderbufferD3D.h @@ -25,20 +25,33 @@ class RenderbufferD3D : public RenderbufferImpl { public: RenderbufferD3D(RendererD3D *renderer); - virtual ~RenderbufferD3D(); + ~RenderbufferD3D() override; - gl::Error setStorage(GLenum internalformat, size_t width, size_t height) override; - gl::Error setStorageMultisample(size_t samples, + gl::Error onDestroy(const gl::Context *context) override; + + gl::Error setStorage(const gl::Context *context, + GLenum internalformat, + size_t width, + size_t height) override; + gl::Error setStorageMultisample(const gl::Context *context, + size_t samples, GLenum internalformat, size_t width, size_t height) override; - gl::Error setStorageEGLImageTarget(egl::Image *image) override; + gl::Error setStorageEGLImageTarget(const gl::Context *context, egl::Image *image) override; - gl::Error getRenderTarget(RenderTargetD3D **outRenderTarget); - gl::Error getAttachmentRenderTarget(const gl::FramebufferAttachment::Target &target, + gl::Error getRenderTarget(const gl::Context *context, RenderTargetD3D **outRenderTarget); + gl::Error getAttachmentRenderTarget(const gl::Context *context, + GLenum binding, + const gl::ImageIndex &imageIndex, FramebufferAttachmentRenderTarget **rtOut) override; + gl::Error initializeContents(const gl::Context *context, + const gl::ImageIndex &imageIndex) override; + private: + void deleteRenderTarget(const gl::Context *context); + RendererD3D *mRenderer; RenderTargetD3D *mRenderTarget; EGLImageD3D *mImage; diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/RendererD3D.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/RendererD3D.cpp index 105587f62c..2167200a91 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/RendererD3D.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/RendererD3D.cpp @@ -8,43 +8,39 @@ #include "libANGLE/renderer/d3d/RendererD3D.h" -#include "common/debug.h" #include "common/MemoryBuffer.h" +#include "common/debug.h" #include "common/utilities.h" +#include "libANGLE/Context.h" #include "libANGLE/Display.h" -#include "libANGLE/formatutils.h" #include "libANGLE/Framebuffer.h" #include "libANGLE/FramebufferAttachment.h" +#include "libANGLE/ImageIndex.h" +#include "libANGLE/ResourceManager.h" +#include "libANGLE/State.h" +#include "libANGLE/VertexArray.h" +#include "libANGLE/formatutils.h" +#include "libANGLE/renderer/ContextImpl.h" +#include "libANGLE/renderer/TextureImpl.h" #include "libANGLE/renderer/d3d/BufferD3D.h" #include "libANGLE/renderer/d3d/DeviceD3D.h" #include "libANGLE/renderer/d3d/DisplayD3D.h" #include "libANGLE/renderer/d3d/IndexDataManager.h" #include "libANGLE/renderer/d3d/ProgramD3D.h" #include "libANGLE/renderer/d3d/SamplerD3D.h" -#include "libANGLE/ResourceManager.h" -#include "libANGLE/State.h" -#include "libANGLE/VertexArray.h" +#include "libANGLE/renderer/d3d/TextureD3D.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; - -} // anonymous namespace - RendererD3D::RendererD3D(egl::Display *display) : mDisplay(display), - mDeviceLost(false), - mAnnotator(nullptr), mPresentPathFastEnabled(false), - mScratchMemoryBufferResetCounter(0), + mCapsInitialized(false), mWorkaroundsInitialized(false), - mDisjoint(false) + mDisjoint(false), + mDeviceLost(false), + mWorkerThreadPool(4) { } @@ -55,451 +51,29 @@ RendererD3D::~RendererD3D() void RendererD3D::cleanup() { - mScratchMemoryBuffer.resize(0); - for (auto &incompleteTexture : mIncompleteTextures) - { - incompleteTexture.second.set(NULL); - } - mIncompleteTextures.clear(); - - if (mAnnotator != nullptr) - { - gl::UninitializeDebugAnnotations(); - SafeDelete(mAnnotator); - } -} - -SamplerImpl *RendererD3D::createSampler() -{ - return new SamplerD3D(); -} - -gl::Error RendererD3D::drawArrays(const gl::Data &data, GLenum mode, GLint first, GLsizei count) -{ - return genericDrawArrays(data, mode, first, count, 0); -} - -gl::Error RendererD3D::drawArraysInstanced(const gl::Data &data, - GLenum mode, - GLint first, - GLsizei count, - GLsizei instanceCount) -{ - return genericDrawArrays(data, mode, first, count, instanceCount); -} - -gl::Error RendererD3D::drawElements(const gl::Data &data, - GLenum mode, - GLsizei count, - GLenum type, - const GLvoid *indices, - const gl::IndexRange &indexRange) -{ - return genericDrawElements(data, mode, count, type, indices, 0, indexRange); -} - -gl::Error RendererD3D::drawElementsInstanced(const gl::Data &data, - GLenum mode, - GLsizei count, - GLenum type, - const GLvoid *indices, - GLsizei instances, - const gl::IndexRange &indexRange) -{ - return genericDrawElements(data, mode, count, type, indices, instances, indexRange); -} - -gl::Error RendererD3D::drawRangeElements(const gl::Data &data, - GLenum mode, - GLuint start, - GLuint end, - GLsizei count, - GLenum type, - const GLvoid *indices, - const gl::IndexRange &indexRange) -{ - return genericDrawElements(data, mode, count, type, indices, 0, indexRange); -} - -gl::Error RendererD3D::genericDrawElements(const gl::Data &data, - GLenum mode, - GLsizei count, - GLenum type, - const GLvoid *indices, - GLsizei instances, - const gl::IndexRange &indexRange) -{ - gl::Program *program = data.state->getProgram(); - ASSERT(program != nullptr); - ProgramD3D *programD3D = GetImplAs(program); - bool usesPointSize = programD3D->usesPointSize(); - - programD3D->updateSamplerMapping(); - - gl::Error error = generateSwizzles(data); - if (error.isError()) - { - return error; - } - - if (!applyPrimitiveType(mode, count, usesPointSize)) - { - return gl::Error(GL_NO_ERROR); - } - - error = updateState(data, mode); - if (error.isError()) - { - return error; - } - - TranslatedIndexData indexInfo; - indexInfo.indexRange = indexRange; - - error = applyIndexBuffer(data, indices, 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()); - - size_t vertexCount = indexInfo.indexRange.vertexCount(); - error = applyVertexBuffer(*data.state, mode, static_cast(indexInfo.indexRange.start), - static_cast(vertexCount), instances, &indexInfo); - if (error.isError()) - { - return error; - } - - error = applyTextures(data); - if (error.isError()) - { - return error; - } - - error = applyShaders(data, mode); - if (error.isError()) - { - return error; - } - - error = programD3D->applyUniformBuffers(data); - if (error.isError()) - { - return error; - } - - if (!skipDraw(data, mode)) - { - error = drawElementsImpl(data, indexInfo, mode, count, type, indices, instances); - if (error.isError()) - { - return error; - } - } - - return gl::Error(GL_NO_ERROR); -} - -gl::Error RendererD3D::genericDrawArrays(const gl::Data &data, - GLenum mode, - GLint first, - GLsizei count, - GLsizei instances) -{ - gl::Program *program = data.state->getProgram(); - ASSERT(program != nullptr); - ProgramD3D *programD3D = GetImplAs(program); - bool usesPointSize = programD3D->usesPointSize(); - - programD3D->updateSamplerMapping(); - - gl::Error error = generateSwizzles(data); - if (error.isError()) - { - return error; - } - - if (!applyPrimitiveType(mode, count, usesPointSize)) - { - return gl::Error(GL_NO_ERROR); - } - - error = updateState(data, mode); - if (error.isError()) - { - return error; - } - - applyTransformFeedbackBuffers(*data.state); - - error = applyVertexBuffer(*data.state, mode, first, count, instances, nullptr); - if (error.isError()) - { - return error; - } - - error = applyTextures(data); - if (error.isError()) - { - return error; - } - - error = applyShaders(data, mode); - if (error.isError()) - { - return error; - } - - error = programD3D->applyUniformBuffers(data); - if (error.isError()) - { - return error; - } - - if (!skipDraw(data, mode)) - { - error = drawArraysImpl(data, mode, count, instances); - 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) -{ - ProgramD3D *programD3D = GetImplAs(data.state->getProgram()); - - unsigned int samplerRange = static_cast(programD3D->getUsedSamplerRange(type)); - - for (unsigned int i = 0; i < samplerRange; i++) - { - GLenum textureType = programD3D->getSamplerTextureType(type, i); - GLint textureUnit = programD3D->getSamplerMapping(type, i, *data.caps); - if (textureUnit != -1) - { - gl::Texture *texture = data.state->getSamplerTexture(textureUnit, textureType); - ASSERT(texture); - if (texture->getTextureState().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); -} - -unsigned int RendererD3D::GetBlendSampleMask(const gl::Data &data, int samples) -{ - unsigned int mask = 0; - if (data.state->isSampleCoverageEnabled()) - { - GLclampf coverageValue = data.state->getSampleCoverageValue(); - 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; - } - } - } - - bool coverageInvert = data.state->getSampleCoverageInvert(); - if (coverageInvert) - { - mask = ~mask; - } - } - else - { - mask = 0xFFFFFFFF; - } - - return mask; -} - -// Applies the shaders and shader constants to the Direct3D device -gl::Error RendererD3D::applyShaders(const gl::Data &data, GLenum drawMode) -{ - gl::Program *program = data.state->getProgram(); - ProgramD3D *programD3D = GetImplAs(program); - programD3D->updateCachedInputLayout(*data.state); - - gl::Error error = applyShadersImpl(data, drawMode); - if (error.isError()) - { - return error; - } - - return programD3D->applyUniforms(drawMode); -} - -// 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). -// Sampler mapping needs to be up-to-date on the program object before this is called. -gl::Error RendererD3D::applyTextures(const gl::Data &data, gl::SamplerType shaderType, - const FramebufferTextureArray &framebufferTextures, size_t framebufferTextureCount) -{ - ProgramD3D *programD3D = GetImplAs(data.state->getProgram()); - - ASSERT(!programD3D->isSamplerMappingDirty()); - - unsigned int samplerRange = programD3D->getUsedSamplerRange(shaderType); - for (unsigned int samplerIndex = 0; samplerIndex < samplerRange; samplerIndex++) - { - GLenum textureType = programD3D->getSamplerTextureType(shaderType, samplerIndex); - GLint textureUnit = programD3D->getSamplerMapping(shaderType, samplerIndex, *data.caps); - if (textureUnit != -1) - { - gl::Texture *texture = data.state->getSamplerTexture(textureUnit, textureType); - ASSERT(texture); - - gl::Sampler *samplerObject = data.state->getSampler(textureUnit); - - const gl::SamplerState &samplerState = - samplerObject ? samplerObject->getSamplerState() : texture->getSamplerState(); - - // TODO: std::binary_search may become unavailable using older versions of GCC - if (texture->isSamplerComplete(samplerState, data) && - !std::binary_search(framebufferTextures.begin(), - framebufferTextures.begin() + framebufferTextureCount, texture)) - { - gl::Error error = setSamplerState(shaderType, samplerIndex, texture, samplerState); - 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 = setSamplerState(shaderType, samplerIndex, incompleteTexture, - incompleteTexture->getSamplerState()); - if (error.isError()) - { - return 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; - clearTextures(shaderType, samplerRange, samplerCount); - - return gl::Error(GL_NO_ERROR); -} - -gl::Error RendererD3D::applyTextures(const gl::Data &data) -{ - FramebufferTextureArray framebufferTextures; - size_t framebufferSerialCount = getBoundFramebufferTextures(data, &framebufferTextures); - - gl::Error error = applyTextures(data, gl::SAMPLER_VERTEX, framebufferTextures, framebufferSerialCount); - if (error.isError()) - { - return error; - } - - error = applyTextures(data, gl::SAMPLER_PIXEL, framebufferTextures, framebufferSerialCount); - if (error.isError()) - { - return error; - } - - return gl::Error(GL_NO_ERROR); + mIncompleteTextures.onDestroy(mDisplay->getProxyContext()); } -bool RendererD3D::skipDraw(const gl::Data &data, GLenum drawMode) +bool RendererD3D::skipDraw(const gl::State &glState, GLenum drawMode) { - const gl::State &state = *data.state; - if (drawMode == GL_POINTS) { - bool usesPointSize = GetImplAs(state.getProgram())->usesPointSize(); + bool usesPointSize = GetImplAs(glState.getProgram())->usesPointSize(); // 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 (!usesPointSize && !state.isTransformFeedbackActiveUnpaused()) + if (!usesPointSize && !glState.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."); - + // Notify developers of risking undefined behavior. + WARN() << "Point rendering without writing to gl_PointSize."; return true; } } else if (gl::IsTriangleMode(drawMode)) { - if (state.getRasterizerState().cullFace && - state.getRasterizerState().cullMode == GL_FRONT_AND_BACK) + if (glState.getRasterizerState().cullFace && + glState.getRasterizerState().cullMode == gl::CullFaceMode::FrontAndBack) { return true; } @@ -508,196 +82,179 @@ bool RendererD3D::skipDraw(const gl::Data &data, GLenum drawMode) return false; } -void RendererD3D::markTransformFeedbackUsage(const gl::Data &data) +gl::Error RendererD3D::getIncompleteTexture(const gl::Context *context, + GLenum type, + gl::Texture **textureOut) { - const gl::TransformFeedback *transformFeedback = data.state->getCurrentTransformFeedback(); - for (size_t i = 0; i < transformFeedback->getIndexedBufferCount(); i++) - { - const OffsetBindingPointer &binding = transformFeedback->getIndexedBuffer(i); - if (binding.get() != nullptr) - { - BufferD3D *bufferD3D = GetImplAs(binding.get()); - bufferD3D->markTransformFeedbackUsage(); - } - } + return mIncompleteTextures.getIncompleteTexture(context, type, this, textureOut); } -size_t RendererD3D::getBoundFramebufferTextures(const gl::Data &data, FramebufferTextureArray *outTextureArray) +GLenum RendererD3D::getResetStatus() { - size_t textureCount = 0; - - const gl::Framebuffer *drawFramebuffer = data.state->getDrawFramebuffer(); - for (size_t i = 0; i < drawFramebuffer->getNumColorBuffers(); i++) + if (!mDeviceLost) { - const gl::FramebufferAttachment *attachment = drawFramebuffer->getColorbuffer(i); - if (attachment && attachment->type() == GL_TEXTURE) + if (testDeviceLost()) { - (*outTextureArray)[textureCount++] = attachment->getTexture(); + mDeviceLost = true; + notifyDeviceLost(); + return GL_UNKNOWN_CONTEXT_RESET_EXT; } + return GL_NO_ERROR; } - const gl::FramebufferAttachment *depthStencilAttachment = drawFramebuffer->getDepthOrStencilbuffer(); - if (depthStencilAttachment && depthStencilAttachment->type() == GL_TEXTURE) + if (testDeviceResettable()) { - (*outTextureArray)[textureCount++] = depthStencilAttachment->getTexture(); + return GL_NO_ERROR; } - std::sort(outTextureArray->begin(), outTextureArray->begin() + textureCount); - - return textureCount; -} - -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 unpack(1, 0); - const gl::Box area(0, 0, 0, 1, 1, 1); - - // Skip the API layer to avoid needing to pass the Context and mess with dirty bits. - gl::Texture *t = - new gl::Texture(createTexture(type), std::numeric_limits::max(), type); - t->setStorage(type, 1, GL_RGBA8, colorSize); - - if (type == GL_TEXTURE_CUBE_MAP) - { - for (GLenum face = GL_TEXTURE_CUBE_MAP_POSITIVE_X; face <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z; face++) - { - t->getImplementation()->setSubImage(face, 0, area, GL_RGBA8, GL_UNSIGNED_BYTE, - unpack, color); - } - } - else - { - t->getImplementation()->setSubImage(type, 0, area, GL_RGBA8, GL_UNSIGNED_BYTE, unpack, - color); - } - - mIncompleteTextures[type].set(t); - } - - return mIncompleteTextures[type].get(); -} - -bool RendererD3D::isDeviceLost() const -{ - return mDeviceLost; + return GL_UNKNOWN_CONTEXT_RESET_EXT; } void RendererD3D::notifyDeviceLost() { - mDeviceLost = true; mDisplay->notifyDeviceLost(); } std::string RendererD3D::getVendorString() const { - LUID adapterLuid = { 0 }; + LUID adapterLuid = {0}; if (getLUID(&adapterLuid)) { char adapterLuidString[64]; - sprintf_s(adapterLuidString, sizeof(adapterLuidString), "(adapter LUID: %08x%08x)", adapterLuid.HighPart, adapterLuid.LowPart); + 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) +void RendererD3D::setGPUDisjoint() { - if (mScratchMemoryBuffer.size() == requestedSize) - { - mScratchMemoryBufferResetCounter = ScratchMemoryBufferLifetime; - *bufferOut = &mScratchMemoryBuffer; - return gl::Error(GL_NO_ERROR); - } - - if (mScratchMemoryBuffer.size() > requestedSize) - { - mScratchMemoryBufferResetCounter--; - } + mDisjoint = true; +} - 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; - } +GLint RendererD3D::getGPUDisjoint() +{ + bool disjoint = mDisjoint; - ASSERT(mScratchMemoryBuffer.size() >= requestedSize); + // Disjoint flag is cleared when read + mDisjoint = false; - *bufferOut = &mScratchMemoryBuffer; - return gl::Error(GL_NO_ERROR); + return disjoint; } -void RendererD3D::insertEventMarker(GLsizei length, const char *marker) +GLint64 RendererD3D::getTimestamp() { - std::vector wcstring (length + 1); - size_t convertedChars = 0; - errno_t err = mbstowcs_s(&convertedChars, wcstring.data(), length + 1, marker, _TRUNCATE); - if (err == 0) - { - getAnnotator()->setMarker(wcstring.data()); - } + // D3D has no way to get an actual timestamp reliably so 0 is returned + return 0; } -void RendererD3D::pushGroupMarker(GLsizei length, const char *marker) +void RendererD3D::ensureCapsInitialized() const { - std::vector wcstring(length + 1); - size_t convertedChars = 0; - errno_t err = mbstowcs_s(&convertedChars, wcstring.data(), length + 1, marker, _TRUNCATE); - if (err == 0) + if (!mCapsInitialized) { - getAnnotator()->beginEvent(wcstring.data()); + generateCaps(&mNativeCaps, &mNativeTextureCaps, &mNativeExtensions, &mNativeLimitations); + mCapsInitialized = true; } } -void RendererD3D::popGroupMarker() +const gl::Caps &RendererD3D::getNativeCaps() const { - getAnnotator()->endEvent(); + ensureCapsInitialized(); + return mNativeCaps; } -void RendererD3D::setGPUDisjoint() +const gl::TextureCapsMap &RendererD3D::getNativeTextureCaps() const { - mDisjoint = true; + ensureCapsInitialized(); + return mNativeTextureCaps; } -GLint RendererD3D::getGPUDisjoint() +const gl::Extensions &RendererD3D::getNativeExtensions() const { - bool disjoint = mDisjoint; + ensureCapsInitialized(); + return mNativeExtensions; +} - // Disjoint flag is cleared when read - mDisjoint = false; +const gl::Limitations &RendererD3D::getNativeLimitations() const +{ + ensureCapsInitialized(); + return mNativeLimitations; +} - return disjoint; +angle::WorkerThreadPool *RendererD3D::getWorkerThreadPool() +{ + return &mWorkerThreadPool; } -GLint64 RendererD3D::getTimestamp() +Serial RendererD3D::generateSerial() { - // D3D has no way to get an actual timestamp reliably so 0 is returned - return 0; + return mSerialFactory.generate(); } -void RendererD3D::onMakeCurrent(const gl::Data &data) +bool InstancedPointSpritesActive(ProgramD3D *programD3D, GLenum mode) { + return programD3D->usesPointSize() && programD3D->usesInstancedPointSpriteEmulation() && + mode == GL_POINTS; } -void RendererD3D::initializeDebugAnnotator() +gl::Error RendererD3D::initRenderTarget(RenderTargetD3D *renderTarget) { - createAnnotator(); - ASSERT(mAnnotator); - gl::InitializeDebugAnnotations(mAnnotator); + return clearRenderTarget(renderTarget, gl::ColorF(0, 0, 0, 0), 1, 0); } -gl::DebugAnnotator *RendererD3D::getAnnotator() +gl::Error RendererD3D::initializeMultisampleTextureToBlack(const gl::Context *context, + gl::Texture *glTexture) { - ASSERT(mAnnotator); - return mAnnotator; + ASSERT(glTexture->getTarget() == GL_TEXTURE_2D_MULTISAMPLE); + TextureD3D *textureD3D = GetImplAs(glTexture); + gl::ImageIndex index = gl::ImageIndex::Make2DMultisample(); + RenderTargetD3D *renderTarget = nullptr; + ANGLE_TRY(textureD3D->getRenderTarget(context, index, &renderTarget)); + return clearRenderTarget(renderTarget, gl::ColorF(0.0f, 0.0f, 0.0f, 1.0f), 1.0f, 0); } + +unsigned int GetBlendSampleMask(const gl::State &glState, int samples) +{ + unsigned int mask = 0; + if (glState.isSampleCoverageEnabled()) + { + GLfloat coverageValue = glState.getSampleCoverageValue(); + 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; + } + } + } + + bool coverageInvert = glState.getSampleCoverageInvert(); + if (coverageInvert) + { + mask = ~mask; + } + } + else + { + mask = 0xFFFFFFFF; + } + + if (glState.isSampleMaskEnabled()) + { + mask &= glState.getSampleMaskWord(0); + } + + return mask; } + +} // namespace rx diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/RendererD3D.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/RendererD3D.h index f956f037e2..dcc98f2ec6 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/RendererD3D.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/RendererD3D.h @@ -9,19 +9,21 @@ #ifndef LIBANGLE_RENDERER_D3D_RENDERERD3D_H_ #define LIBANGLE_RENDERER_D3D_RENDERERD3D_H_ -#include "common/debug.h" +#include + +#include "common/Color.h" #include "common/MemoryBuffer.h" -#include "libANGLE/Data.h" +#include "common/debug.h" +#include "libANGLE/ContextState.h" #include "libANGLE/Device.h" +#include "libANGLE/Version.h" +#include "libANGLE/WorkerThread.h" +#include "libANGLE/angletypes.h" #include "libANGLE/formatutils.h" -#include "libANGLE/renderer/Renderer.h" #include "libANGLE/renderer/d3d/VertexDataManager.h" #include "libANGLE/renderer/d3d/formatutilsD3D.h" -#include "libANGLE/renderer/d3d/WorkaroundsD3D.h" -#include "libANGLE/renderer/d3d/d3d11/NativeWindow.h" - -//FIXME(jmadill): std::array is currently prohibited by Chromium style guide -#include +#include "libANGLE/renderer/renderer_utils.h" +#include "platform/WorkaroundsD3D.h" namespace egl { @@ -30,7 +32,7 @@ class ConfigSet; namespace gl { -class DebugAnnotator; +class FramebufferState; class InfoLog; class Texture; struct LinkedVarying; @@ -38,28 +40,24 @@ struct LinkedVarying; namespace rx { +class ContextImpl; struct D3DUniform; struct D3DVarying; class DeviceD3D; class EGLImageD3D; +class FramebufferImpl; class ImageD3D; class IndexBuffer; +class NativeWindowD3D; class ProgramD3D; class RenderTargetD3D; class ShaderExecutableD3D; class SwapChainD3D; class TextureStorage; +struct TranslatedIndexData; class UniformStorageD3D; class VertexBuffer; -enum ShaderType -{ - SHADER_VERTEX, - SHADER_PIXEL, - SHADER_GEOMETRY, - SHADER_TYPE_MAX -}; - struct DeviceIdentifier { UINT VendorId; @@ -76,7 +74,7 @@ enum RendererClass }; // Useful for unit testing -class BufferFactoryD3D +class BufferFactoryD3D : angle::NonCopyable { public: BufferFactoryD3D() {} @@ -88,52 +86,32 @@ class BufferFactoryD3D // TODO(jmadill): add VertexFormatCaps virtual VertexConversionType getVertexConversionType(gl::VertexFormatType vertexFormatType) const = 0; virtual GLenum getVertexComponentType(gl::VertexFormatType vertexFormatType) const = 0; + + // Warning: you should ensure binding really matches attrib.bindingIndex before using this + // function. + virtual gl::ErrorOrResult getVertexSpaceRequired( + const gl::VertexAttribute &attrib, + const gl::VertexBinding &binding, + GLsizei count, + GLsizei instances) const = 0; }; -class RendererD3D : public Renderer, public BufferFactoryD3D +using AttribIndexArray = std::array; + +class RendererD3D : public BufferFactoryD3D, public MultisampleTextureInitializer { public: explicit RendererD3D(egl::Display *display); - virtual ~RendererD3D(); + ~RendererD3D() override; virtual egl::Error initialize() = 0; - virtual egl::ConfigSet generateConfigs() const = 0; + virtual egl::ConfigSet generateConfigs() = 0; virtual void generateDisplayExtensions(egl::DisplayExtensions *outExtensions) const = 0; - gl::Error drawArrays(const gl::Data &data, GLenum mode, GLint first, GLsizei count) override; - gl::Error drawArraysInstanced(const gl::Data &data, - GLenum mode, - GLint first, - GLsizei count, - GLsizei instanceCount) override; - - gl::Error drawElements(const gl::Data &data, - GLenum mode, - GLsizei count, - GLenum type, - const GLvoid *indices, - const gl::IndexRange &indexRange) override; - gl::Error drawElementsInstanced(const gl::Data &data, - GLenum mode, - GLsizei count, - GLenum type, - const GLvoid *indices, - GLsizei instances, - const gl::IndexRange &indexRange) override; - gl::Error drawRangeElements(const gl::Data &data, - GLenum mode, - GLuint start, - GLuint end, - GLsizei count, - GLenum type, - const GLvoid *indices, - const gl::IndexRange &indexRange) override; - - bool isDeviceLost() const override; - std::string getVendorString() const override; - - SamplerImpl *createSampler() override; + virtual ContextImpl *createContext(const gl::ContextState &state) = 0; + + std::string getVendorString() const; virtual int getMinorShaderModel() const = 0; virtual std::string getShaderModelSuffix() const = 0; @@ -141,204 +119,241 @@ class RendererD3D : public Renderer, public BufferFactoryD3D // Direct3D Specific methods virtual DeviceIdentifier getAdapterIdentifier() const = 0; - virtual SwapChainD3D *createSwapChain(NativeWindow nativeWindow, + virtual bool isValidNativeWindow(EGLNativeWindowType window) const = 0; + virtual NativeWindowD3D *createNativeWindow(EGLNativeWindowType window, + const egl::Config *config, + const egl::AttributeMap &attribs) const = 0; + + virtual SwapChainD3D *createSwapChain(NativeWindowD3D *nativeWindow, HANDLE shareHandle, + IUnknown *d3dTexture, GLenum backBufferFormat, GLenum depthBufferFormat, - EGLint orientation) = 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 std::vector &vertexUniformBuffers, - const std::vector &fragmentUniformBuffers) = 0; - - virtual gl::Error updateState(const gl::Data &data, GLenum drawMode) = 0; - - virtual gl::Error applyRenderTarget(const gl::Framebuffer *frameBuffer) = 0; - virtual gl::Error applyUniforms(const ProgramD3D &programD3D, - GLenum drawMode, - 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, - TranslatedIndexData *indexInfo) = 0; - virtual gl::Error applyIndexBuffer(const gl::Data &data, - const GLvoid *indices, - GLsizei count, - GLenum mode, - GLenum type, - TranslatedIndexData *indexInfo) = 0; - virtual void applyTransformFeedbackBuffers(const gl::State& state) = 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; + EGLint orientation, + EGLint samples) = 0; + virtual egl::Error getD3DTextureInfo(const egl::Config *configuration, + IUnknown *d3dTexture, + EGLint *width, + EGLint *height, + GLenum *fboFormat) const = 0; + virtual egl::Error validateShareHandle(const egl::Config *config, + HANDLE shareHandle, + const egl::AttributeMap &attribs) const = 0; virtual int getMajorShaderModel() const = 0; - const WorkaroundsD3D &getWorkarounds() const; + const angle::WorkaroundsD3D &getWorkarounds() 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) = 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; + virtual gl::Error copyImage2D(const gl::Context *context, + 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::Context *context, + 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::Context *context, + 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::Context *context, + const gl::Framebuffer *framebuffer, + const gl::Rectangle &sourceRect, + GLenum destFormat, + const gl::Offset &destOffset, + TextureStorage *storage, + GLint level) = 0; + + virtual gl::Error copyTexture(const gl::Context *context, + const gl::Texture *source, + GLint sourceLevel, + const gl::Rectangle &sourceRect, + GLenum destFormat, + const gl::Offset &destOffset, + TextureStorage *storage, + GLenum destTarget, + GLint destLevel, + bool unpackFlipY, + bool unpackPremultiplyAlpha, + bool unpackUnmultiplyAlpha) = 0; + virtual gl::Error copyCompressedTexture(const gl::Context *context, + const gl::Texture *source, + GLint sourceLevel, + TextureStorage *storage, + GLint destLevel) = 0; // RenderTarget creation virtual gl::Error createRenderTarget(int width, int height, GLenum format, GLsizei samples, RenderTargetD3D **outRT) = 0; virtual gl::Error createRenderTargetCopy(RenderTargetD3D *source, RenderTargetD3D **outRT) = 0; // Shader operations - virtual gl::Error loadExecutable(const void *function, + virtual gl::Error loadExecutable(const uint8_t *function, size_t length, - ShaderType type, + gl::ShaderType type, const std::vector &streamOutVaryings, bool separatedOutputBuffers, - ShaderExecutableD3D **outExecutable) = 0; + ShaderExecutableD3D **outExecutable) = 0; virtual gl::Error compileToExecutable(gl::InfoLog &infoLog, const std::string &shaderHLSL, - ShaderType type, + gl::ShaderType type, const std::vector &streamOutVaryings, bool separatedOutputBuffers, - const D3DCompilerWorkarounds &workarounds, + const angle::CompilerWorkaroundsD3D &workarounds, ShaderExecutableD3D **outExectuable) = 0; + virtual gl::Error ensureHLSLCompilerInitialized() = 0; + virtual UniformStorageD3D *createUniformStorage(size_t storageSize) = 0; // Image operations virtual ImageD3D *createImage() = 0; - virtual gl::Error generateMipmap(ImageD3D *dest, ImageD3D *source) = 0; - virtual gl::Error generateMipmapsUsingD3D(TextureStorage *storage, - const gl::TextureState &textureState) = 0; + virtual gl::Error generateMipmap(const gl::Context *context, + ImageD3D *dest, + ImageD3D *source) = 0; + virtual gl::Error generateMipmapUsingD3D(const gl::Context *context, + TextureStorage *storage, + const gl::TextureState &textureState) = 0; + virtual gl::Error copyImage(const gl::Context *context, + ImageD3D *dest, + ImageD3D *source, + const gl::Rectangle &sourceRect, + const gl::Offset &destOffset, + bool unpackFlipY, + bool unpackPremultiplyAlpha, + bool unpackUnmultiplyAlpha) = 0; virtual TextureStorage *createTextureStorage2D(SwapChainD3D *swapChain) = 0; - virtual TextureStorage *createTextureStorageEGLImage(EGLImageD3D *eglImage) = 0; + virtual TextureStorage *createTextureStorageEGLImage(EGLImageD3D *eglImage, + RenderTargetD3D *renderTargetD3D) = 0; + virtual TextureStorage *createTextureStorageExternal( + egl::Stream *stream, + const egl::Stream::GLTextureDescription &desc) = 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; + virtual TextureStorage *createTextureStorage2DMultisample(GLenum internalformat, + GLsizei width, + GLsizei height, + int levels, + int samples, + bool fixedSampleLocations) = 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; + virtual gl::Error fastCopyBufferToTexture(const gl::Context *context, + const gl::PixelUnpackState &unpack, + unsigned int offset, + RenderTargetD3D *destRenderTarget, + GLenum destinationFormat, + GLenum sourcePixelsType, + const gl::Box &destArea) = 0; // Device lost - void notifyDeviceLost() override; + GLenum getResetStatus(); + void notifyDeviceLost(); virtual bool resetDevice() = 0; + virtual bool testDeviceLost() = 0; + virtual bool testDeviceResettable() = 0; + virtual RendererClass getRendererClass() const = 0; virtual void *getD3DDevice() = 0; - gl::Error getScratchMemoryBuffer(size_t requestedSize, MemoryBuffer **bufferOut); - - // EXT_debug_marker - void insertEventMarker(GLsizei length, const char *marker) override; - void pushGroupMarker(GLsizei length, const char *marker) override; - void popGroupMarker() override; - void setGPUDisjoint(); - GLint getGPUDisjoint() override; - GLint64 getTimestamp() override; - - void onMakeCurrent(const gl::Data &data) override; + GLint getGPUDisjoint(); + GLint64 getTimestamp(); - // In D3D11, faster than calling setTexture a jillion times - virtual gl::Error clearTextures(gl::SamplerType samplerType, size_t rangeStart, size_t rangeEnd) = 0; + virtual gl::Error clearRenderTarget(RenderTargetD3D *renderTarget, + const gl::ColorF &clearColorValue, + const float clearDepthValue, + const unsigned int clearStencilValue) = 0; virtual egl::Error getEGLDevice(DeviceImpl **device) = 0; bool presentPathFastEnabled() const { return mPresentPathFastEnabled; } + // Stream creation + virtual StreamProducerImpl *createStreamProducerD3DTextureNV12( + egl::Stream::ConsumerType consumerType, + const egl::AttributeMap &attribs) = 0; + + const gl::Caps &getNativeCaps() const; + const gl::TextureCapsMap &getNativeTextureCaps() const; + const gl::Extensions &getNativeExtensions() const; + const gl::Limitations &getNativeLimitations() const; + + // Necessary hack for default framebuffers in D3D. + virtual FramebufferImpl *createDefaultFramebuffer(const gl::FramebufferState &state) = 0; + + virtual gl::Version getMaxSupportedESVersion() const = 0; + + gl::Error initRenderTarget(RenderTargetD3D *renderTarget); + + angle::WorkerThreadPool *getWorkerThreadPool(); + + gl::Error getIncompleteTexture(const gl::Context *context, + GLenum type, + gl::Texture **textureOut); + + Serial generateSerial(); + + virtual bool canSelectViewInVertexShader() const = 0; + + gl::Error initializeMultisampleTextureToBlack(const gl::Context *context, + gl::Texture *glTexture) override; + protected: virtual bool getLUID(LUID *adapterLuid) const = 0; - virtual gl::Error applyShadersImpl(const gl::Data &data, GLenum drawMode) = 0; + virtual void generateCaps(gl::Caps *outCaps, + gl::TextureCapsMap *outTextureCaps, + gl::Extensions *outExtensions, + gl::Limitations *outLimitations) const = 0; void cleanup(); - virtual void createAnnotator() = 0; - - static unsigned int GetBlendSampleMask(const gl::Data &data, int samples); - // dirtyPointer is a special value that will make the comparison with any valid pointer fail and force the renderer to re-apply the state. + bool skipDraw(const gl::State &glState, GLenum drawMode); egl::Display *mDisplay; - bool mDeviceLost; - - void initializeDebugAnnotator(); - gl::DebugAnnotator *mAnnotator; - - std::vector mTranslatedAttribCache; bool mPresentPathFastEnabled; private: - gl::Error genericDrawArrays(const gl::Data &data, - GLenum mode, - GLint first, - GLsizei count, - GLsizei instances); - - gl::Error genericDrawElements(const gl::Data &data, - GLenum mode, - GLsizei count, - GLenum type, - const GLvoid *indices, - GLsizei instances, - const gl::IndexRange &indexRange); - - virtual gl::Error drawArraysImpl(const gl::Data &data, - GLenum mode, - GLsizei count, - GLsizei instances) = 0; - virtual gl::Error drawElementsImpl(const gl::Data &data, - const TranslatedIndexData &indexInfo, - GLenum mode, - GLsizei count, - GLenum type, - const GLvoid *indices, - GLsizei instances) = 0; - - //FIXME(jmadill): std::array is currently prohibited by Chromium style guide - typedef std::array FramebufferTextureArray; - - gl::Error generateSwizzles(const gl::Data &data, gl::SamplerType type); - gl::Error generateSwizzles(const gl::Data &data); - - gl::Error applyState(const gl::Data &data, GLenum drawMode); - gl::Error applyShaders(const gl::Data &data, GLenum drawMode); - gl::Error applyTextures(const gl::Data &data, gl::SamplerType shaderType, - const FramebufferTextureArray &framebufferTextures, size_t framebufferTextureCount); - gl::Error applyTextures(const gl::Data &data); - - bool skipDraw(const gl::Data &data, GLenum drawMode); - void markTransformFeedbackUsage(const gl::Data &data); - - size_t getBoundFramebufferTextures(const gl::Data &data, FramebufferTextureArray *outTextureArray); - gl::Texture *getIncompleteTexture(GLenum type); - - gl::DebugAnnotator *getAnnotator(); - - virtual WorkaroundsD3D generateWorkarounds() const = 0; - - gl::TextureMap mIncompleteTextures; - MemoryBuffer mScratchMemoryBuffer; - unsigned int mScratchMemoryBufferResetCounter; + void ensureCapsInitialized() const; + + virtual angle::WorkaroundsD3D generateWorkarounds() const = 0; + + mutable bool mCapsInitialized; + mutable gl::Caps mNativeCaps; + mutable gl::TextureCapsMap mNativeTextureCaps; + mutable gl::Extensions mNativeExtensions; + mutable gl::Limitations mNativeLimitations; + + IncompleteTextureSet mIncompleteTextures; mutable bool mWorkaroundsInitialized; - mutable WorkaroundsD3D mWorkarounds; + mutable angle::WorkaroundsD3D mWorkarounds; bool mDisjoint; + bool mDeviceLost; + + angle::WorkerThreadPool mWorkerThreadPool; + + SerialFactory mSerialFactory; }; -} +unsigned int GetBlendSampleMask(const gl::State &glState, int samples); +bool InstancedPointSpritesActive(ProgramD3D *programD3D, GLenum mode); + +} // namespace rx #endif // LIBANGLE_RENDERER_D3D_RENDERERD3D_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/SamplerD3D.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/SamplerD3D.h index 7aabdc8132..3f8f5b9d8d 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/SamplerD3D.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/SamplerD3D.h @@ -17,7 +17,7 @@ namespace rx class SamplerD3D : public SamplerImpl { public: - SamplerD3D() {} + SamplerD3D(const gl::SamplerState &state) : SamplerImpl(state) {} ~SamplerD3D() override {} }; } diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/ShaderD3D.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/ShaderD3D.cpp index 1ecbfb7410..2a8f1fb11c 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/ShaderD3D.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/ShaderD3D.cpp @@ -9,9 +9,11 @@ #include "libANGLE/renderer/d3d/ShaderD3D.h" #include "common/utilities.h" +#include "libANGLE/Caps.h" #include "libANGLE/Compiler.h" #include "libANGLE/Shader.h" #include "libANGLE/features.h" +#include "libANGLE/renderer/d3d/ProgramD3D.h" #include "libANGLE/renderer/d3d/RendererD3D.h" // Definitions local to the translation unit @@ -28,6 +30,9 @@ const char *GetShaderTypeString(GLenum type) case GL_FRAGMENT_SHADER: return "FRAGMENT"; + case GL_COMPUTE_SHADER: + return "COMPUTE"; + default: UNREACHABLE(); return ""; @@ -39,9 +44,39 @@ const char *GetShaderTypeString(GLenum type) namespace rx { -ShaderD3D::ShaderD3D(const gl::Shader::Data &data) : ShaderImpl(data) +ShaderD3D::ShaderD3D(const gl::ShaderState &data, + const angle::WorkaroundsD3D &workarounds, + const gl::Extensions &extensions) + : ShaderImpl(data), mAdditionalOptions(0) { uncompile(); + + if (workarounds.expandIntegerPowExpressions) + { + mAdditionalOptions |= SH_EXPAND_SELECT_HLSL_INTEGER_POW_EXPRESSIONS; + } + + if (workarounds.getDimensionsIgnoresBaseLevel) + { + mAdditionalOptions |= SH_HLSL_GET_DIMENSIONS_IGNORES_BASE_LEVEL; + } + + if (workarounds.preAddTexelFetchOffsets) + { + mAdditionalOptions |= SH_REWRITE_TEXELFETCHOFFSET_TO_TEXELFETCH; + } + if (workarounds.rewriteUnaryMinusOperator) + { + mAdditionalOptions |= SH_REWRITE_INTEGER_UNARY_MINUS_OPERATOR; + } + if (workarounds.emulateIsnanFloat) + { + mAdditionalOptions |= SH_EMULATE_ISNAN_FLOAT_FUNCTION; + } + if (extensions.multiview) + { + mAdditionalOptions |= SH_INITIALIZE_BUILTINS_FOR_INSTANCED_MULTIVIEW; + } } ShaderD3D::~ShaderD3D() @@ -50,6 +85,11 @@ ShaderD3D::~ShaderD3D() std::string ShaderD3D::getDebugInfo() const { + if (mDebugInfo.empty()) + { + return ""; + } + return mDebugInfo + std::string("\n// ") + GetShaderTypeString(mData.getShaderType()) + " SHADER END\n"; } @@ -69,15 +109,16 @@ void ShaderD3D::uncompile() mUsesPointCoord = false; mUsesDepthRange = false; mUsesFragDepth = false; + mHasANGLEMultiviewEnabled = false; + mUsesViewID = false; mUsesDiscardRewriting = false; mUsesNestedBreak = false; - mUsesDeferredInit = false; mRequiresIEEEStrictCompiling = false; mDebugInfo.clear(); } -void ShaderD3D::generateWorkarounds(D3DCompilerWorkarounds *workarounds) const +void ShaderD3D::generateWorkarounds(angle::CompilerWorkaroundsD3D *workarounds) const { if (mUsesDiscardRewriting) { @@ -106,10 +147,10 @@ unsigned int ShaderD3D::getUniformRegister(const std::string &uniformName) const return mUniformRegisterMap.find(uniformName)->second; } -unsigned int ShaderD3D::getInterfaceBlockRegister(const std::string &blockName) const +unsigned int ShaderD3D::getUniformBlockRegister(const std::string &blockName) const { - ASSERT(mInterfaceBlockRegisterMap.count(blockName) > 0); - return mInterfaceBlockRegisterMap.find(blockName)->second; + ASSERT(mUniformBlockRegisterMap.count(blockName) > 0); + return mUniformBlockRegisterMap.find(blockName)->second; } ShShaderOutput ShaderD3D::getCompilerOutputType() const @@ -117,12 +158,12 @@ ShShaderOutput ShaderD3D::getCompilerOutputType() const return mCompilerOutputType; } -int ShaderD3D::prepareSourceAndReturnOptions(std::stringstream *shaderSourceStream, - std::string *sourcePath) +ShCompileOptions ShaderD3D::prepareSourceAndReturnOptions(std::stringstream *shaderSourceStream, + std::string *sourcePath) { uncompile(); - int additionalOptions = 0; + ShCompileOptions additionalOptions = 0; const std::string &source = mData.getSource(); @@ -135,10 +176,24 @@ int ShaderD3D::prepareSourceAndReturnOptions(std::stringstream *shaderSourceStre } #endif + additionalOptions |= mAdditionalOptions; + *shaderSourceStream << source; return additionalOptions; } +bool ShaderD3D::hasUniform(const std::string &name) const +{ + return mUniformRegisterMap.find(name) != mUniformRegisterMap.end(); +} + +const std::map &GetUniformRegisterMap( + const std::map *uniformRegisterMap) +{ + ASSERT(uniformRegisterMap); + return *uniformRegisterMap; +} + bool ShaderD3D::postTranslateCompile(gl::Compiler *compiler, std::string *infoLog) { // TODO(jmadill): We shouldn't need to cache this. @@ -154,41 +209,30 @@ bool ShaderD3D::postTranslateCompile(gl::Compiler *compiler, std::string *infoLo mUsesPointSize = translatedSource.find("GL_USES_POINT_SIZE") != std::string::npos; mUsesPointCoord = translatedSource.find("GL_USES_POINT_COORD") != std::string::npos; mUsesDepthRange = translatedSource.find("GL_USES_DEPTH_RANGE") != std::string::npos; - mUsesFragDepth = translatedSource.find("GL_USES_FRAG_DEPTH") != std::string::npos; + mUsesFragDepth = translatedSource.find("GL_USES_FRAG_DEPTH") != std::string::npos; + mHasANGLEMultiviewEnabled = + translatedSource.find("GL_ANGLE_MULTIVIEW_ENABLED") != std::string::npos; + mUsesViewID = translatedSource.find("GL_USES_VIEW_ID") != std::string::npos; mUsesDiscardRewriting = translatedSource.find("ANGLE_USES_DISCARD_REWRITING") != std::string::npos; mUsesNestedBreak = translatedSource.find("ANGLE_USES_NESTED_BREAK") != std::string::npos; - mUsesDeferredInit = translatedSource.find("ANGLE_USES_DEFERRED_INIT") != std::string::npos; mRequiresIEEEStrictCompiling = translatedSource.find("ANGLE_REQUIRES_IEEE_STRICT_COMPILING") != std::string::npos; ShHandle compilerHandle = compiler->getCompilerHandle(mData.getShaderType()); - for (const sh::Uniform &uniform : mData.getUniforms()) - { - if (uniform.staticUse && !uniform.isBuiltIn()) - { - unsigned int index = static_cast(-1); - bool getUniformRegisterResult = - ShGetUniformRegister(compilerHandle, uniform.name, &index); - UNUSED_ASSERTION_VARIABLE(getUniformRegisterResult); - ASSERT(getUniformRegisterResult); - - mUniformRegisterMap[uniform.name] = index; - } - } + mUniformRegisterMap = GetUniformRegisterMap(sh::GetUniformRegisterMap(compilerHandle)); - for (const sh::InterfaceBlock &interfaceBlock : mData.getInterfaceBlocks()) + for (const sh::InterfaceBlock &interfaceBlock : mData.getUniformBlocks()) { if (interfaceBlock.staticUse) { unsigned int index = static_cast(-1); bool blockRegisterResult = - ShGetInterfaceBlockRegister(compilerHandle, interfaceBlock.name, &index); - UNUSED_ASSERTION_VARIABLE(blockRegisterResult); + sh::GetUniformBlockRegister(compilerHandle, interfaceBlock.name, &index); ASSERT(blockRegisterResult); - mInterfaceBlockRegisterMap[interfaceBlock.name] = index; + mUniformBlockRegisterMap[interfaceBlock.name] = index; } } diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/ShaderD3D.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/ShaderD3D.h index 47a73dc27b..f7b0b20db4 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/ShaderD3D.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/ShaderD3D.h @@ -13,31 +13,50 @@ #include +namespace angle +{ +struct CompilerWorkaroundsD3D; +struct WorkaroundsD3D; +} + +namespace gl +{ +struct Extensions; +} + namespace rx { class DynamicHLSL; class RendererD3D; -struct D3DCompilerWorkarounds; +struct D3DUniform; class ShaderD3D : public ShaderImpl { public: - ShaderD3D(const gl::Shader::Data &data); - virtual ~ShaderD3D(); + ShaderD3D(const gl::ShaderState &data, + const angle::WorkaroundsD3D &workarounds, + const gl::Extensions &extensions); + ~ShaderD3D() override; // ShaderImpl implementation - int prepareSourceAndReturnOptions(std::stringstream *sourceStream, - std::string *sourcePath) override; + ShCompileOptions prepareSourceAndReturnOptions(std::stringstream *sourceStream, + std::string *sourcePath) override; bool postTranslateCompile(gl::Compiler *compiler, std::string *infoLog) override; std::string getDebugInfo() const override; // D3D-specific methods void uncompile(); + + bool hasUniform(const std::string &name) const; + + // Query regular uniforms with their name. Query sampler fields of structs with field selection + // using dot (.) operator. unsigned int getUniformRegister(const std::string &uniformName) const; - unsigned int getInterfaceBlockRegister(const std::string &blockName) const; + + unsigned int getUniformBlockRegister(const std::string &blockName) const; void appendDebugInfo(const std::string &info) const { mDebugInfo += info; } - void generateWorkarounds(D3DCompilerWorkarounds *workarounds) const; + void generateWorkarounds(angle::CompilerWorkaroundsD3D *workarounds) const; bool usesMultipleRenderTargets() const { return mUsesMultipleRenderTargets; } bool usesFragColor() const { return mUsesFragColor; } @@ -48,7 +67,8 @@ class ShaderD3D : public ShaderImpl bool usesPointCoord() const { return mUsesPointCoord; } bool usesDepthRange() const { return mUsesDepthRange; } bool usesFragDepth() const { return mUsesFragDepth; } - bool usesDeferredInit() const { return mUsesDeferredInit; } + bool usesViewID() const { return mUsesViewID; } + bool hasANGLEMultiviewEnabled() const { return mHasANGLEMultiviewEnabled; } ShShaderOutput getCompilerOutputType() const; @@ -62,16 +82,18 @@ class ShaderD3D : public ShaderImpl bool mUsesPointCoord; bool mUsesDepthRange; bool mUsesFragDepth; + bool mHasANGLEMultiviewEnabled; + bool mUsesViewID; bool mUsesDiscardRewriting; bool mUsesNestedBreak; - bool mUsesDeferredInit; bool mRequiresIEEEStrictCompiling; ShShaderOutput mCompilerOutputType; mutable std::string mDebugInfo; std::map mUniformRegisterMap; - std::map mInterfaceBlockRegisterMap; + std::map mUniformBlockRegisterMap; + ShCompileOptions mAdditionalOptions; }; -} +} // namespace rx #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 index 97ffdf5094..83a66bd1a5 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/ShaderExecutableD3D.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/ShaderExecutableD3D.cpp @@ -44,9 +44,13 @@ void ShaderExecutableD3D::appendDebugInfo(const std::string &info) mDebugInfo += info; } - -UniformStorageD3D::UniformStorageD3D(size_t initialSize) : mSize(initialSize) +UniformStorageD3D::UniformStorageD3D(size_t initialSize) : mUniformData() { + bool result = mUniformData.resize(initialSize); + ASSERT(result); + + // Uniform data is zero-initialized by default. + mUniformData.fill(0); } UniformStorageD3D::~UniformStorageD3D() @@ -55,7 +59,13 @@ UniformStorageD3D::~UniformStorageD3D() size_t UniformStorageD3D::size() const { - return mSize; + return mUniformData.size(); } +uint8_t *UniformStorageD3D::getDataPointer(unsigned int registerIndex, unsigned int registerElement) +{ + size_t offset = ((registerIndex * 4 + registerElement) * sizeof(float)); + return mUniformData.data() + offset; } + +} // namespace rx diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/ShaderExecutableD3D.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/ShaderExecutableD3D.h index 71b83b7954..b8097710e2 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/ShaderExecutableD3D.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/ShaderExecutableD3D.h @@ -10,6 +10,7 @@ #ifndef LIBANGLE_RENDERER_D3D_SHADEREXECUTABLED3D_H_ #define LIBANGLE_RENDERER_D3D_SHADEREXECUTABLED3D_H_ +#include "common/MemoryBuffer.h" #include "common/debug.h" #include @@ -45,10 +46,12 @@ class UniformStorageD3D : angle::NonCopyable size_t size() const; + uint8_t *getDataPointer(unsigned int registerIndex, unsigned int registerElement); + private: - size_t mSize; + angle::MemoryBuffer mUniformData; }; -} +} // namespace rx #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 index f567f47525..7657aef79e 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/SurfaceD3D.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/SurfaceD3D.cpp @@ -8,10 +8,11 @@ #include "libANGLE/renderer/d3d/SurfaceD3D.h" +#include "libANGLE/Context.h" #include "libANGLE/Display.h" #include "libANGLE/Surface.h" -#include "libANGLE/renderer/d3d/RendererD3D.h" #include "libANGLE/renderer/d3d/RenderTargetD3D.h" +#include "libANGLE/renderer/d3d/RendererD3D.h" #include "libANGLE/renderer/d3d/SwapChainD3D.h" #include @@ -21,60 +22,62 @@ 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, 0, EGL_FALSE, - shareHandle, NULL); -} - -SurfaceD3D *SurfaceD3D::createFromWindow(RendererD3D *renderer, - egl::Display *display, - const egl::Config *config, - EGLNativeWindowType window, - EGLint fixedSize, - EGLint directComposition, - EGLint width, - EGLint height, - EGLint orientation) -{ - return new SurfaceD3D(renderer, display, config, width, height, fixedSize, orientation, - directComposition, static_cast(0), window); -} - -SurfaceD3D::SurfaceD3D(RendererD3D *renderer, +SurfaceD3D::SurfaceD3D(const egl::SurfaceState &state, + RendererD3D *renderer, egl::Display *display, - const egl::Config *config, - EGLint width, - EGLint height, - EGLint fixedSize, - EGLint orientation, - EGLint directComposition, - EGLClientBuffer shareHandle, - EGLNativeWindowType window) - : SurfaceImpl(), + EGLNativeWindowType window, + EGLenum buftype, + EGLClientBuffer clientBuffer, + const egl::AttributeMap &attribs) + : SurfaceImpl(state), mRenderer(renderer), mDisplay(display), - mFixedSize(fixedSize == EGL_TRUE), - mOrientation(orientation), - mRenderTargetFormat(config->renderTargetFormat), - mDepthStencilFormat(config->depthStencilFormat), + mFixedSize(window == nullptr || attribs.get(EGL_FIXED_SIZE_ANGLE, EGL_FALSE) == EGL_TRUE), + mOrientation(static_cast(attribs.get(EGL_SURFACE_ORIENTATION_ANGLE, 0))), + mRenderTargetFormat(state.config->renderTargetFormat), + mDepthStencilFormat(state.config->depthStencilFormat), mSwapChain(nullptr), mSwapIntervalDirty(true), mWindowSubclassed(false), - mNativeWindow(window, config, directComposition == EGL_TRUE), - mWidth(width), - mHeight(height), + mNativeWindow(renderer->createNativeWindow(window, state.config, attribs)), + mWidth(static_cast(attribs.get(EGL_WIDTH, 0))), + mHeight(static_cast(attribs.get(EGL_HEIGHT, 0))), mSwapInterval(1), - mShareHandle(reinterpret_cast(shareHandle)) + mShareHandle(0), + mD3DTexture(nullptr) { subclassWindow(); + if (window != nullptr && !mFixedSize) + { + mWidth = -1; + mHeight = -1; + } + + switch (buftype) + { + case EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE: + mShareHandle = static_cast(clientBuffer); + break; + + case EGL_D3D_TEXTURE_ANGLE: + mD3DTexture = static_cast(clientBuffer); + ASSERT(mD3DTexture != nullptr); + mD3DTexture->AddRef(); + ANGLE_SWALLOW_ERR(mRenderer->getD3DTextureInfo(state.config, mD3DTexture, &mWidth, + &mHeight, &mRenderTargetFormat)); + break; + + default: + break; + } } SurfaceD3D::~SurfaceD3D() { unsubclassWindow(); releaseSwapChain(); + SafeDelete(mNativeWindow); + SafeRelease(mD3DTexture); } void SurfaceD3D::releaseSwapChain() @@ -82,41 +85,41 @@ void SurfaceD3D::releaseSwapChain() SafeDelete(mSwapChain); } -egl::Error SurfaceD3D::initialize() +egl::Error SurfaceD3D::initialize(const egl::Display *display) { - if (mNativeWindow.getNativeWindow()) + if (mNativeWindow->getNativeWindow()) { - if (!mNativeWindow.initialize()) + if (!mNativeWindow->initialize()) { - return egl::Error(EGL_BAD_SURFACE); + return egl::EglBadSurface(); } } - egl::Error error = resetSwapChain(); - if (error.isError()) - { - return error; - } - - return egl::Error(EGL_SUCCESS); + ANGLE_TRY(resetSwapChain(display)); + return egl::NoError(); } -FramebufferImpl *SurfaceD3D::createDefaultFramebuffer(const gl::Framebuffer::Data &data) +FramebufferImpl *SurfaceD3D::createDefaultFramebuffer(const gl::FramebufferState &data) { - return mRenderer->createFramebuffer(data); + return mRenderer->createDefaultFramebuffer(data); } egl::Error SurfaceD3D::bindTexImage(gl::Texture *, EGLint) { - return egl::Error(EGL_SUCCESS); + return egl::NoError(); } egl::Error SurfaceD3D::releaseTexImage(EGLint) { - return egl::Error(EGL_SUCCESS); + return egl::NoError(); +} + +egl::Error SurfaceD3D::getSyncValues(EGLuint64KHR *ust, EGLuint64KHR *msc, EGLuint64KHR *sbc) +{ + return mSwapChain->getSyncValues(ust, msc, sbc); } -egl::Error SurfaceD3D::resetSwapChain() +egl::Error SurfaceD3D::resetSwapChain(const egl::Display *display) { ASSERT(!mSwapChain); @@ -126,11 +129,11 @@ egl::Error SurfaceD3D::resetSwapChain() if (!mFixedSize) { RECT windowRect; - if (!mNativeWindow.getClientRect(&windowRect)) + if (!mNativeWindow->getClientRect(&windowRect)) { ASSERT(false); - return egl::Error(EGL_BAD_SURFACE, "Could not retrieve the window dimensions"); + return egl::EglBadSurface() << "Could not retrieve the window dimensions"; } width = windowRect.right - windowRect.left; @@ -143,29 +146,34 @@ egl::Error SurfaceD3D::resetSwapChain() height = mHeight; } - mSwapChain = mRenderer->createSwapChain(mNativeWindow, mShareHandle, mRenderTargetFormat, - mDepthStencilFormat, mOrientation); + mSwapChain = + mRenderer->createSwapChain(mNativeWindow, mShareHandle, mD3DTexture, mRenderTargetFormat, + mDepthStencilFormat, mOrientation, mState.config->samples); if (!mSwapChain) { - return egl::Error(EGL_BAD_ALLOC); + return egl::EglBadAlloc(); } - egl::Error error = resetSwapChain(width, height); + // This is a bit risky to pass the proxy context here, but it can happen at almost any time. + egl::Error error = resetSwapChain(display->getProxyContext(), width, height); if (error.isError()) { SafeDelete(mSwapChain); return error; } - return egl::Error(EGL_SUCCESS); + return egl::NoError(); } -egl::Error SurfaceD3D::resizeSwapChain(int backbufferWidth, int backbufferHeight) +egl::Error SurfaceD3D::resizeSwapChain(const gl::Context *context, + int backbufferWidth, + int backbufferHeight) { ASSERT(backbufferWidth >= 0 && backbufferHeight >= 0); ASSERT(mSwapChain); - EGLint status = mSwapChain->resize(std::max(1, backbufferWidth), std::max(1, backbufferHeight)); + EGLint status = + mSwapChain->resize(context, std::max(1, backbufferWidth), std::max(1, backbufferHeight)); if (status == EGL_CONTEXT_LOST) { @@ -180,15 +188,18 @@ egl::Error SurfaceD3D::resizeSwapChain(int backbufferWidth, int backbufferHeight mWidth = backbufferWidth; mHeight = backbufferHeight; - return egl::Error(EGL_SUCCESS); + return egl::NoError(); } -egl::Error SurfaceD3D::resetSwapChain(int backbufferWidth, int backbufferHeight) +egl::Error SurfaceD3D::resetSwapChain(const gl::Context *context, + int backbufferWidth, + int backbufferHeight) { ASSERT(backbufferWidth >= 0 && backbufferHeight >= 0); ASSERT(mSwapChain); - EGLint status = mSwapChain->reset(std::max(1, backbufferWidth), std::max(1, backbufferHeight), mSwapInterval); + EGLint status = mSwapChain->reset(context, std::max(1, backbufferWidth), + std::max(1, backbufferHeight), mSwapInterval); if (status == EGL_CONTEXT_LOST) { @@ -204,17 +215,20 @@ egl::Error SurfaceD3D::resetSwapChain(int backbufferWidth, int backbufferHeight) mHeight = backbufferHeight; mSwapIntervalDirty = false; - return egl::Error(EGL_SUCCESS); + return egl::NoError(); } -egl::Error SurfaceD3D::swapRect(EGLint x, EGLint y, EGLint width, EGLint height) +egl::Error SurfaceD3D::swapRect(const gl::Context *context, + EGLint x, + EGLint y, + EGLint width, + EGLint height) { if (!mSwapChain) { - return egl::Error(EGL_SUCCESS); + return egl::NoError(); } -#if !defined(ANGLE_ENABLE_WINDOWS_STORE) || (defined(ANGLE_ENABLE_WINDOWS_STORE) && WINAPI_FAMILY == WINAPI_FAMILY_PC_APP) // Qt WP: eglPostSubBufferNV comes here if (x + width > mWidth) { width = mWidth - x; @@ -224,11 +238,10 @@ egl::Error SurfaceD3D::swapRect(EGLint x, EGLint y, EGLint width, EGLint height) { height = mHeight - y; } -#endif if (width != 0 && height != 0) { - EGLint status = mSwapChain->swapRect(x, y, width, height); + EGLint status = mSwapChain->swapRect(context, x, y, width, height); if (status == EGL_CONTEXT_LOST) { @@ -241,34 +254,36 @@ egl::Error SurfaceD3D::swapRect(EGLint x, EGLint y, EGLint width, EGLint height) } } - checkForOutOfDateSwapChain(); + ANGLE_TRY(checkForOutOfDateSwapChain(context)); - return egl::Error(EGL_SUCCESS); + return egl::NoError(); } #if !defined(ANGLE_ENABLE_WINDOWS_STORE) #define kSurfaceProperty _TEXT("Egl::SurfaceOwner") #define kParentWndProc _TEXT("Egl::SurfaceParentWndProc") +#define kDisplayProperty _TEXT("Egl::Display") 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); + if (message == WM_SIZE) + { + SurfaceD3D* surf = reinterpret_cast(GetProp(hwnd, kSurfaceProperty)); + if(surf) + { + egl::Display *display = reinterpret_cast(GetProp(hwnd, kDisplayProperty)); + surf->checkForOutOfDateSwapChain(display->getProxyContext()); + } + } + 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(); + HWND window = mNativeWindow->getNativeWindow(); if (!window) { return; @@ -291,6 +306,7 @@ void SurfaceD3D::subclassWindow() SetProp(window, kSurfaceProperty, reinterpret_cast(this)); SetProp(window, kParentWndProc, reinterpret_cast(oldWndProc)); + SetProp(window, kDisplayProperty, reinterpret_cast(mDisplay)); mWindowSubclassed = true; #endif } @@ -303,7 +319,7 @@ void SurfaceD3D::unsubclassWindow() } #if !defined(ANGLE_ENABLE_WINDOWS_STORE) - HWND window = mNativeWindow.getNativeWindow(); + HWND window = mNativeWindow->getNativeWindow(); if (!window) { return; @@ -320,30 +336,31 @@ void SurfaceD3D::unsubclassWindow() 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); + RemoveProp(window, kDisplayProperty); #endif mWindowSubclassed = false; } -bool SurfaceD3D::checkForOutOfDateSwapChain() + +egl::Error SurfaceD3D::checkForOutOfDateSwapChain(const gl::Context *context) { RECT client; int clientWidth = getWidth(); int clientHeight = getHeight(); bool sizeDirty = false; - if (!mFixedSize && !mNativeWindow.isIconic()) + 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)) + if (!mNativeWindow->getClientRect(&client)) { - ASSERT(false); - return false; + UNREACHABLE(); + return egl::NoError(); } // Grow the buffer now, if the window has grown. We need to grow now to avoid losing information. @@ -352,28 +369,30 @@ bool SurfaceD3D::checkForOutOfDateSwapChain() sizeDirty = clientWidth != getWidth() || clientHeight != getHeight(); } - bool wasDirty = (mSwapIntervalDirty || sizeDirty); - if (mSwapIntervalDirty) { - resetSwapChain(clientWidth, clientHeight); + ANGLE_TRY(resetSwapChain(context, clientWidth, clientHeight)); } else if (sizeDirty) { - resizeSwapChain(clientWidth, clientHeight); + ANGLE_TRY(resizeSwapChain(context, clientWidth, clientHeight)); } - return wasDirty; + return egl::NoError(); } -egl::Error SurfaceD3D::swap() +egl::Error SurfaceD3D::swap(const gl::Context *context) { - return swapRect(0, 0, mWidth, mHeight); + return swapRect(context, 0, 0, mWidth, mHeight); } -egl::Error SurfaceD3D::postSubBuffer(EGLint x, EGLint y, EGLint width, EGLint height) +egl::Error SurfaceD3D::postSubBuffer(const gl::Context *context, + EGLint x, + EGLint y, + EGLint width, + EGLint height) { - return swapRect(x, y, width, height); + return swapRect(context, x, y, width, height); } rx::SwapChainD3D *SurfaceD3D::getSwapChain() const @@ -429,13 +448,15 @@ egl::Error SurfaceD3D::querySurfacePointerANGLE(EGLint attribute, void **value) } else UNREACHABLE(); - return egl::Error(EGL_SUCCESS); + return egl::NoError(); } -gl::Error SurfaceD3D::getAttachmentRenderTarget(const gl::FramebufferAttachment::Target &target, +gl::Error SurfaceD3D::getAttachmentRenderTarget(const gl::Context *context, + GLenum binding, + const gl::ImageIndex &imageIndex, FramebufferAttachmentRenderTarget **rtOut) { - if (target.binding() == GL_BACK) + if (binding == GL_BACK) { *rtOut = mSwapChain->getColorRenderTarget(); } @@ -443,7 +464,46 @@ gl::Error SurfaceD3D::getAttachmentRenderTarget(const gl::FramebufferAttachment: { *rtOut = mSwapChain->getDepthStencilRenderTarget(); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); +} + +WindowSurfaceD3D::WindowSurfaceD3D(const egl::SurfaceState &state, + RendererD3D *renderer, + egl::Display *display, + EGLNativeWindowType window, + const egl::AttributeMap &attribs) + : SurfaceD3D(state, + renderer, + display, + window, + 0, + static_cast(0), + attribs) +{ +} + +WindowSurfaceD3D::~WindowSurfaceD3D() +{ } +PbufferSurfaceD3D::PbufferSurfaceD3D(const egl::SurfaceState &state, + RendererD3D *renderer, + egl::Display *display, + EGLenum buftype, + EGLClientBuffer clientBuffer, + const egl::AttributeMap &attribs) + : SurfaceD3D(state, + renderer, + display, + static_cast(0), + buftype, + clientBuffer, + attribs) +{ } + +PbufferSurfaceD3D::~PbufferSurfaceD3D() +{ +} + +} // namespace rc diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/SurfaceD3D.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/SurfaceD3D.h index 67d408ddd9..01d2573244 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/SurfaceD3D.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/SurfaceD3D.h @@ -10,7 +10,7 @@ #define LIBANGLE_RENDERER_D3D_SURFACED3D_H_ #include "libANGLE/renderer/SurfaceImpl.h" -#include "libANGLE/renderer/d3d/d3d11/NativeWindow.h" +#include "libANGLE/renderer/d3d/NativeWindowD3D.h" namespace egl { @@ -25,28 +25,22 @@ class RendererD3D; class SurfaceD3D : public SurfaceImpl { public: - static SurfaceD3D *createFromWindow(RendererD3D *renderer, - egl::Display *display, - const egl::Config *config, - EGLNativeWindowType window, - EGLint fixedSize, - EGLint directComposition, - EGLint width, - EGLint height, - EGLint orientation); - 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; - FramebufferImpl *createDefaultFramebuffer(const gl::Framebuffer::Data &data) override; + egl::Error initialize(const egl::Display *display) override; + FramebufferImpl *createDefaultFramebuffer(const gl::FramebufferState &state) override; - egl::Error swap() override; - egl::Error postSubBuffer(EGLint x, EGLint y, EGLint width, EGLint height) override; + egl::Error swap(const gl::Context *context) override; + egl::Error postSubBuffer(const gl::Context *context, + EGLint x, + EGLint y, + EGLint width, + EGLint height) override; egl::Error querySurfacePointerANGLE(EGLint attribute, void **value) override; egl::Error bindTexImage(gl::Texture *texture, EGLint buffer) override; egl::Error releaseTexImage(EGLint buffer) override; + egl::Error getSyncValues(EGLuint64KHR *ust, EGLuint64KHR *msc, EGLuint64KHR *sbc) override; void setSwapInterval(EGLint interval) override; EGLint getWidth() const override; @@ -58,29 +52,35 @@ class SurfaceD3D : public SurfaceImpl // D3D implementations SwapChainD3D *getSwapChain() const; - egl::Error resetSwapChain(); + egl::Error resetSwapChain(const egl::Display *display); - // Returns true if swapchain changed due to resize or interval update - bool checkForOutOfDateSwapChain(); + egl::Error checkForOutOfDateSwapChain(const gl::Context *context); - gl::Error getAttachmentRenderTarget(const gl::FramebufferAttachment::Target &target, + gl::Error getAttachmentRenderTarget(const gl::Context *context, + GLenum binding, + const gl::ImageIndex &imageIndex, FramebufferAttachmentRenderTarget **rtOut) override; - private: - SurfaceD3D(RendererD3D *renderer, + protected: + SurfaceD3D(const egl::SurfaceState &state, + RendererD3D *renderer, egl::Display *display, - const egl::Config *config, - EGLint width, - EGLint height, - EGLint fixedSize, - EGLint orientation, - EGLint directComposition, - 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); + EGLNativeWindowType window, + EGLenum buftype, + EGLClientBuffer clientBuffer, + const egl::AttributeMap &attribs); + + egl::Error swapRect(const gl::Context *context, + EGLint x, + EGLint y, + EGLint width, + EGLint height); + egl::Error resetSwapChain(const gl::Context *context, + int backbufferWidth, + int backbufferHeight); + egl::Error resizeSwapChain(const gl::Context *context, + int backbufferWidth, + int backbufferHeight); void subclassWindow(); void unsubclassWindow(); @@ -96,18 +96,41 @@ class SurfaceD3D : public SurfaceImpl SwapChainD3D *mSwapChain; bool mSwapIntervalDirty; - bool mWindowSubclassed; // Indicates whether we successfully subclassed mWindow for WM_RESIZE hooking + bool mWindowSubclassed; // Indicates whether we successfully subclassed mWindow for WM_RESIZE hooking - NativeWindow mNativeWindow; // Handler for the Window that the surface is created for. + NativeWindowD3D *mNativeWindow; // Handler for the Window that the surface is created for. EGLint mWidth; EGLint mHeight; EGLint mSwapInterval; HANDLE mShareHandle; + IUnknown *mD3DTexture; }; +class WindowSurfaceD3D : public SurfaceD3D +{ + public: + WindowSurfaceD3D(const egl::SurfaceState &state, + RendererD3D *renderer, + egl::Display *display, + EGLNativeWindowType window, + const egl::AttributeMap &attribs); + ~WindowSurfaceD3D() override; +}; -} +class PbufferSurfaceD3D : public SurfaceD3D +{ + public: + PbufferSurfaceD3D(const egl::SurfaceState &state, + RendererD3D *renderer, + egl::Display *display, + EGLenum buftype, + EGLClientBuffer clientBuffer, + const egl::AttributeMap &attribs); + ~PbufferSurfaceD3D() override; +}; + +} // namespace rx #endif // LIBANGLE_RENDERER_D3D_SURFACED3D_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/SwapChainD3D.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/SwapChainD3D.cpp new file mode 100644 index 0000000000..de8534c3da --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/SwapChainD3D.cpp @@ -0,0 +1,34 @@ +// +// Copyright (c) 2016 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.cpp: Defines a back-end specific class that hides the details of the +// implementation-specific swapchain. + +#include "libANGLE/renderer/d3d/SwapChainD3D.h" + +namespace rx +{ + +SwapChainD3D::SwapChainD3D(HANDLE shareHandle, + IUnknown *d3dTexture, + GLenum backBufferFormat, + GLenum depthBufferFormat) + : mOffscreenRenderTargetFormat(backBufferFormat), + mDepthBufferFormat(depthBufferFormat), + mShareHandle(shareHandle), + mD3DTexture(d3dTexture) +{ + if (mD3DTexture) + { + mD3DTexture->AddRef(); + } +} + +SwapChainD3D::~SwapChainD3D() +{ + SafeRelease(mD3DTexture); +} +} // namespace rx diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/SwapChainD3D.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/SwapChainD3D.h index 171cab54dd..017737b878 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/SwapChainD3D.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/SwapChainD3D.h @@ -12,17 +12,26 @@ #include #include +#include #include "common/angleutils.h" #include "common/platform.h" - -// TODO: move out of D3D11 -#include "libANGLE/renderer/d3d/d3d11/NativeWindow.h" +#include "libANGLE/Error.h" #if !defined(ANGLE_FORCE_VSYNC_OFF) #define ANGLE_FORCE_VSYNC_OFF 0 #endif +namespace gl +{ +class Context; +} // namespace gl + +namespace egl +{ +class Display; +} // namespace egl + namespace rx { class RenderTargetD3D; @@ -30,35 +39,45 @@ class RenderTargetD3D; class SwapChainD3D : angle::NonCopyable { public: - SwapChainD3D(rx::NativeWindow nativeWindow, HANDLE shareHandle, GLenum backBufferFormat, GLenum depthBufferFormat) - : mNativeWindow(nativeWindow), mOffscreenRenderTargetFormat(backBufferFormat), mDepthBufferFormat(depthBufferFormat), mShareHandle(shareHandle) - { - } - - 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; + SwapChainD3D(HANDLE shareHandle, + IUnknown *d3dTexture, + GLenum backBufferFormat, + GLenum depthBufferFormat); + virtual ~SwapChainD3D(); + + virtual EGLint resize(const gl::Context *context, + EGLint backbufferWidth, + EGLint backbufferSize) = 0; + virtual EGLint reset(const gl::Context *context, + EGLint backbufferWidth, + EGLint backbufferHeight, + EGLint swapInterval) = 0; + virtual EGLint swapRect(const gl::Context *context, + EGLint x, + EGLint y, + EGLint width, + EGLint height) = 0; virtual void recreate() = 0; - virtual void *getDevice() { return NULL; } + virtual void *getDevice() { return nullptr; } virtual RenderTargetD3D *getColorRenderTarget() = 0; virtual RenderTargetD3D *getDepthStencilRenderTarget() = 0; - GLenum GetRenderTargetInternalFormat() const { return mOffscreenRenderTargetFormat; } - GLenum GetDepthBufferInternalFormat() const { return mDepthBufferFormat; } + GLenum getRenderTargetInternalFormat() const { return mOffscreenRenderTargetFormat; } + GLenum getDepthBufferInternalFormat() const { return mDepthBufferFormat; } HANDLE getShareHandle() { return mShareHandle; } virtual void *getKeyedMutex() = 0; + virtual egl::Error getSyncValues(EGLuint64KHR *ust, EGLuint64KHR *msc, EGLuint64KHR *sbc) = 0; + protected: - rx::NativeWindow mNativeWindow; // Handler for the Window that the surface is created for. const GLenum mOffscreenRenderTargetFormat; const GLenum mDepthBufferFormat; HANDLE mShareHandle; + IUnknown *mD3DTexture; }; -} +} // namespace rx #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 index 430576b318..bf44cbb5d2 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/TextureD3D.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/TextureD3D.cpp @@ -12,6 +12,7 @@ #include "common/utilities.h" #include "libANGLE/Buffer.h" #include "libANGLE/Config.h" +#include "libANGLE/Context.h" #include "libANGLE/Framebuffer.h" #include "libANGLE/Image.h" #include "libANGLE/Surface.h" @@ -21,8 +22,8 @@ #include "libANGLE/renderer/d3d/BufferD3D.h" #include "libANGLE/renderer/d3d/EGLImageD3D.h" #include "libANGLE/renderer/d3d/ImageD3D.h" -#include "libANGLE/renderer/d3d/RendererD3D.h" #include "libANGLE/renderer/d3d/RenderTargetD3D.h" +#include "libANGLE/renderer/d3d/RendererD3D.h" #include "libANGLE/renderer/d3d/SurfaceD3D.h" #include "libANGLE/renderer/d3d/TextureStorage.h" @@ -32,26 +33,24 @@ namespace rx namespace { -gl::Error GetUnpackPointer(const gl::PixelUnpackState &unpack, const uint8_t *pixels, - ptrdiff_t layerOffset, const uint8_t **pointerOut) +gl::Error GetUnpackPointer(const gl::Context *context, + const gl::PixelUnpackState &unpack, + gl::Buffer *unpackBuffer, + const uint8_t *pixels, + ptrdiff_t layerOffset, + const uint8_t **pointerOut) { - if (unpack.pixelBuffer.id() != 0) + if (unpackBuffer) { // 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); + BufferD3D *bufferD3D = GetImplAs(unpackBuffer); ASSERT(bufferD3D); - const uint8_t *bufferData = NULL; - gl::Error error = bufferD3D->getData(&bufferData); - if (error.isError()) - { - return error; - } - + const uint8_t *bufferData = nullptr; + ANGLE_TRY(bufferD3D->getData(context, &bufferData)); *pointerOut = bufferData + offset; } else @@ -65,7 +64,7 @@ gl::Error GetUnpackPointer(const gl::PixelUnpackState &unpack, const uint8_t *pi *pointerOut += layerOffset; } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } bool IsRenderTargetUsage(GLenum usage) @@ -75,41 +74,66 @@ bool IsRenderTargetUsage(GLenum usage) } -TextureD3D::TextureD3D(RendererD3D *renderer) - : mRenderer(renderer), - mUsage(GL_NONE), +TextureD3D::TextureD3D(const gl::TextureState &state, RendererD3D *renderer) + : TextureImpl(state), + mRenderer(renderer), mDirtyImages(true), mImmutable(false), - mTexStorage(NULL) + mTexStorage(nullptr), + mBaseLevel(0) { } TextureD3D::~TextureD3D() { + ASSERT(!mTexStorage); } -gl::Error TextureD3D::getNativeTexture(TextureStorage **outStorage) +gl::Error TextureD3D::getNativeTexture(const gl::Context *context, TextureStorage **outStorage) { // ensure the underlying texture is created - gl::Error error = initializeStorage(false); - if (error.isError()) - { - return error; - } + ANGLE_TRY(initializeStorage(context, false)); if (mTexStorage) { - error = updateStorage(); - if (error.isError()) - { - return error; - } + ANGLE_TRY(updateStorage(context)); } ASSERT(outStorage); *outStorage = mTexStorage; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); +} + +gl::Error TextureD3D::getImageAndSyncFromStorage(const gl::Context *context, + const gl::ImageIndex &index, + ImageD3D **outImage) +{ + ImageD3D *image = getImage(index); + if (mTexStorage && mTexStorage->isRenderTarget()) + { + ANGLE_TRY(image->copyFromTexStorage(context, index, mTexStorage)); + mDirtyImages = true; + } + *outImage = image; + return gl::NoError(); +} + +GLint TextureD3D::getLevelZeroWidth() const +{ + ASSERT(gl::CountLeadingZeros(static_cast(getBaseLevelWidth())) > getBaseLevel()); + return getBaseLevelWidth() << mBaseLevel; +} + +GLint TextureD3D::getLevelZeroHeight() const +{ + ASSERT(gl::CountLeadingZeros(static_cast(getBaseLevelHeight())) > getBaseLevel()); + return getBaseLevelHeight() << mBaseLevel; +} + +GLint TextureD3D::getLevelZeroDepth() const +{ + return getBaseLevelDepth(); } GLint TextureD3D::getBaseLevelWidth() const @@ -139,6 +163,27 @@ GLenum TextureD3D::getBaseLevelInternalFormat() const return (baseImage ? baseImage->getInternalFormat() : GL_NONE); } +gl::Error TextureD3D::setStorage(const gl::Context *context, + GLenum target, + size_t levels, + GLenum internalFormat, + const gl::Extents &size) +{ + UNREACHABLE(); + return gl::InternalError(); +} + +gl::Error TextureD3D::setStorageMultisample(const gl::Context *context, + GLenum target, + GLsizei samples, + GLint internalFormat, + const gl::Extents &size, + bool fixedSampleLocations) +{ + UNREACHABLE(); + return gl::InternalError(); +} + bool TextureD3D::shouldUseSetData(const ImageD3D *image) const { if (!mRenderer->getWorkarounds().setDataFasterThanImageUpload) @@ -146,7 +191,12 @@ bool TextureD3D::shouldUseSetData(const ImageD3D *image) const return false; } - gl::InternalFormat internalFormat = gl::GetInternalFormatInfo(image->getInternalFormat()); + if (image->isDirty()) + { + return false; + } + + gl::InternalFormat internalFormat = gl::GetSizedInternalFormatInfo(image->getInternalFormat()); // We can only handle full updates for depth-stencil textures, so to avoid complications // disable them entirely. @@ -159,173 +209,166 @@ bool TextureD3D::shouldUseSetData(const ImageD3D *image) const return (mTexStorage && !internalFormat.compressed); } -gl::Error TextureD3D::setImageImpl(const gl::ImageIndex &index, +gl::Error TextureD3D::setImageImpl(const gl::Context *context, + const gl::ImageIndex &index, GLenum type, const gl::PixelUnpackState &unpack, const uint8_t *pixels, ptrdiff_t layerOffset) { ImageD3D *image = getImage(index); + gl::Buffer *unpackBuffer = + context->getGLState().getTargetBuffer(gl::BufferBinding::PixelUnpack); ASSERT(image); // No-op if (image->getWidth() == 0 || image->getHeight() == 0 || image->getDepth() == 0) { - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } // 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; - } + const uint8_t *pixelData = nullptr; + ANGLE_TRY(GetUnpackPointer(context, unpack, unpackBuffer, pixels, layerOffset, &pixelData)); if (pixelData != nullptr) { if (shouldUseSetData(image)) { - error = mTexStorage->setData(index, image, NULL, type, unpack, pixelData); + ANGLE_TRY( + mTexStorage->setData(context, index, image, nullptr, 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; + ANGLE_TRY( + image->loadData(context, fullImageArea, unpack, type, pixelData, index.is3D())); } mDirtyImages = true; } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -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) +gl::Error TextureD3D::subImage(const gl::Context *context, + 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; - } + const uint8_t *pixelData = nullptr; + gl::Buffer *unpackBuffer = + context->getGLState().getTargetBuffer(gl::BufferBinding::PixelUnpack); + ANGLE_TRY(GetUnpackPointer(context, unpack, unpackBuffer, pixels, layerOffset, &pixelData)); - if (pixelData != NULL) + if (pixelData != nullptr) { 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; + return mTexStorage->setData(context, index, image, &area, type, unpack, pixelData); } + ANGLE_TRY(image->loadData(context, area, unpack, type, pixelData, index.is3D())); + ANGLE_TRY(commitRegion(context, index, area)); mDirtyImages = true; } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureD3D::setCompressedImageImpl(const gl::ImageIndex &index, +gl::Error TextureD3D::setCompressedImageImpl(const gl::Context *context, + const gl::ImageIndex &index, const gl::PixelUnpackState &unpack, const uint8_t *pixels, ptrdiff_t layerOffset) { - // 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()) + ImageD3D *image = getImage(index); + ASSERT(image); + + if (image->getWidth() == 0 || image->getHeight() == 0 || image->getDepth() == 0) { - return error; + return gl::NoError(); } - if (pixelData != NULL) - { - ImageD3D *image = getImage(index); - ASSERT(image); + // 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 = nullptr; + gl::Buffer *unpackBuffer = + context->getGLState().getTargetBuffer(gl::BufferBinding::PixelUnpack); + ANGLE_TRY(GetUnpackPointer(context, unpack, unpackBuffer, pixels, layerOffset, &pixelData)); + if (pixelData != nullptr) + { gl::Box fullImageArea(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth()); - error = image->loadCompressedData(fullImageArea, pixelData); - if (error.isError()) - { - return error; - } + ANGLE_TRY(image->loadCompressedData(context, fullImageArea, pixelData)); mDirtyImages = true; } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureD3D::subImageCompressed(const gl::ImageIndex &index, const gl::Box &area, GLenum format, - const gl::PixelUnpackState &unpack, const uint8_t *pixels, +gl::Error TextureD3D::subImageCompressed(const gl::Context *context, + const gl::ImageIndex &index, + const gl::Box &area, + GLenum format, + const gl::PixelUnpackState &unpack, + const uint8_t *pixels, ptrdiff_t layerOffset) { - const uint8_t *pixelData = NULL; - gl::Error error = GetUnpackPointer(unpack, pixels, layerOffset, &pixelData); - if (error.isError()) - { - return error; - } + const uint8_t *pixelData = nullptr; + gl::Buffer *unpackBuffer = + context->getGLState().getTargetBuffer(gl::BufferBinding::PixelUnpack); + ANGLE_TRY(GetUnpackPointer(context, unpack, unpackBuffer, pixels, layerOffset, &pixelData)); - if (pixelData != NULL) + if (pixelData != nullptr) { ImageD3D *image = getImage(index); ASSERT(image); - error = image->loadCompressedData(area, pixelData); - if (error.isError()) - { - return error; - } + ANGLE_TRY(image->loadCompressedData(context, area, pixelData)); mDirtyImages = true; } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -bool TextureD3D::isFastUnpackable(const gl::PixelUnpackState &unpack, GLenum sizedInternalFormat) +bool TextureD3D::isFastUnpackable(const gl::Buffer *unpackBuffer, GLenum sizedInternalFormat) { - return unpack.pixelBuffer.id() != 0 && mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat); + return unpackBuffer != nullptr && + 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) +gl::Error TextureD3D::fastUnpackPixels(const gl::Context *context, + const gl::PixelUnpackState &unpack, + const uint8_t *pixels, + const gl::Box &destArea, + GLenum sizedInternalFormat, + GLenum type, + RenderTargetD3D *destRenderTarget) { if (unpack.skipRows != 0 || unpack.skipPixels != 0 || unpack.imageHeight != 0 || unpack.skipImages != 0) { // TODO(jmadill): additional unpack parameters UNIMPLEMENTED(); - return gl::Error(GL_INVALID_OPERATION, - "Unimplemented pixel store parameters in fastUnpackPixels"); + return gl::InternalError() << "Unimplemented pixel store parameters in fastUnpackPixels"; } // No-op if (destArea.width <= 0 && destArea.height <= 0 && destArea.depth <= 0) { - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } // In order to perform the fast copy through the shader, we must have the right format, and be able @@ -334,18 +377,17 @@ gl::Error TextureD3D::fastUnpackPixels(const gl::PixelUnpackState &unpack, const uintptr_t offset = reinterpret_cast(pixels); - gl::Error error = mRenderer->fastCopyBufferToTexture(unpack, static_cast(offset), destRenderTarget, sizedInternalFormat, type, destArea); - if (error.isError()) - { - return error; - } + ANGLE_TRY(mRenderer->fastCopyBufferToTexture(context, unpack, static_cast(offset), + destRenderTarget, sizedInternalFormat, type, + destArea)); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } GLint TextureD3D::creationLevels(GLsizei width, GLsizei height, GLsizei depth) const { - if ((gl::isPow2(width) && gl::isPow2(height) && gl::isPow2(depth)) || mRenderer->getRendererExtensions().textureNPOT) + if ((gl::isPow2(width) && gl::isPow2(height) && gl::isPow2(depth)) || + mRenderer->getNativeExtensions().textureNPOT) { // Maximum number of levels return gl::log2(std::max(std::max(width, height), depth)) + 1; @@ -357,11 +399,6 @@ GLint TextureD3D::creationLevels(GLsizei width, GLsizei height, GLsizei depth) c } } -int TextureD3D::mipLevels() const -{ - return gl::log2(std::max(std::max(getBaseLevelWidth(), getBaseLevelHeight()), getBaseLevelDepth())) + 1; -} - TextureStorage *TextureD3D::getStorage() { ASSERT(mTexStorage); @@ -370,72 +407,60 @@ TextureStorage *TextureD3D::getStorage() ImageD3D *TextureD3D::getBaseLevelImage() const { - return getImage(getImageIndex(0, 0)); + if (mBaseLevel >= gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) + { + return nullptr; + } + return getImage(getImageIndex(mBaseLevel, 0)); } -gl::Error TextureD3D::generateMipmaps(const gl::TextureState &textureState) +gl::Error TextureD3D::setImageExternal(const gl::Context *context, + GLenum target, + egl::Stream *stream, + const egl::Stream::GLTextureDescription &desc) { - GLint mipCount = mipLevels(); + // Only external images can accept external textures + UNREACHABLE(); + return gl::InternalError(); +} - if (mipCount == 1) - { - return gl::Error(GL_NO_ERROR); // no-op - } +gl::Error TextureD3D::generateMipmap(const gl::Context *context) +{ + const GLuint baseLevel = mState.getEffectiveBaseLevel(); + const GLuint maxLevel = mState.getMipmapMaxLevel(); + ASSERT(maxLevel > baseLevel); // Should be checked before calling this. 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; - } + TextureStorage *textureStorage = nullptr; + ANGLE_TRY(getNativeTexture(context, &textureStorage)); + ANGLE_TRY(textureStorage->useLevelZeroWorkaroundTexture(context, false)); } // Set up proper mipmap chain in our Image array. - initMipmapsImages(); + ANGLE_TRY(initMipmapImages(context)); if (mTexStorage && mTexStorage->supportsNativeMipmapFunction()) { - gl::Error error = updateStorage(); - if (error.isError()) - { - return error; - } + ANGLE_TRY(updateStorage(context)); // Generate the mipmap chain using the ad-hoc DirectX function. - error = mRenderer->generateMipmapsUsingD3D(mTexStorage, textureState); - if (error.isError()) - { - return error; - } + ANGLE_TRY(mRenderer->generateMipmapUsingD3D(context, mTexStorage, mState)); } else { // Generate the mipmap chain, one level at a time. - gl::Error error = generateMipmapsUsingImages(); - if (error.isError()) - { - return error; - } + ANGLE_TRY(generateMipmapUsingImages(context, maxLevel)); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureD3D::generateMipmapsUsingImages() +gl::Error TextureD3D::generateMipmapUsingImages(const gl::Context *context, const GLuint maxLevel) { - GLint mipCount = mipLevels(); - // We know that all layers have the same dimension, for the texture to be complete - GLint layerCount = static_cast(getLayerCount(0)); + GLint layerCount = static_cast(getLayerCount(mBaseLevel)); // 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 @@ -447,23 +472,15 @@ gl::Error TextureD3D::generateMipmapsUsingImages() // Copy from the storage mip 0 to Image mip 0 for (GLint layer = 0; layer < layerCount; ++layer) { - gl::ImageIndex srcIndex = getImageIndex(0, layer); + gl::ImageIndex srcIndex = getImageIndex(mBaseLevel, layer); ImageD3D *image = getImage(srcIndex); - gl::Error error = image->copyFromTexStorage(srcIndex, mTexStorage); - if (error.isError()) - { - return error; - } + ANGLE_TRY(image->copyFromTexStorage(context, srcIndex, mTexStorage)); } } else { - gl::Error error = updateStorage(); - if (error.isError()) - { - return error; - } + ANGLE_TRY(updateStorage(context)); } } @@ -476,7 +493,7 @@ gl::Error TextureD3D::generateMipmapsUsingImages() for (GLint layer = 0; layer < layerCount; ++layer) { - for (GLint mip = 1; mip < mipCount; ++mip) + for (GLuint mip = mBaseLevel + 1; mip <= maxLevel; ++mip) { ASSERT(getLayerCount(mip) == layerCount); @@ -486,30 +503,25 @@ gl::Error TextureD3D::generateMipmapsUsingImages() if (renderableStorage) { // GPU-side mipmapping - gl::Error error = mTexStorage->generateMipmap(sourceIndex, destIndex); - if (error.isError()) - { - return error; - } + ANGLE_TRY(mTexStorage->generateMipmap(context, sourceIndex, destIndex)); } else { // CPU-side mipmapping - gl::Error error = mRenderer->generateMipmap(getImage(destIndex), getImage(sourceIndex)); - if (error.isError()) - { - return error; - } + ANGLE_TRY( + mRenderer->generateMipmap(context, getImage(destIndex), getImage(sourceIndex))); } } } + mDirtyImages = true; + if (mTexStorage) { - updateStorage(); + ANGLE_TRY(updateStorage(context)); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } bool TextureD3D::isBaseImageZeroSize() const @@ -531,7 +543,7 @@ bool TextureD3D::isBaseImageZeroSize() const return true; } - if (baseImage->getTarget() == GL_TEXTURE_2D_ARRAY && getLayerCount(0) <= 0) + if (baseImage->getTarget() == GL_TEXTURE_2D_ARRAY && getLayerCount(getBaseLevel()) <= 0) { return true; } @@ -539,12 +551,16 @@ bool TextureD3D::isBaseImageZeroSize() const return false; } -gl::Error TextureD3D::ensureRenderTarget() +gl::Error TextureD3D::ensureRenderTarget(const gl::Context *context) { - gl::Error error = initializeStorage(true); - if (error.isError()) + ANGLE_TRY(initializeStorage(context, true)); + + // initializeStorage can fail with NoError if the texture is not complete. This is not + // an error for incomplete sampling, but it is a big problem for rendering. + if (!mTexStorage) { - return error; + UNREACHABLE(); + return gl::InternalError() << "Cannot render to incomplete texture."; } if (!isBaseImageZeroSize()) @@ -552,94 +568,210 @@ gl::Error TextureD3D::ensureRenderTarget() 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; - } + TexStoragePointer newRenderTargetStorage(context); + ANGLE_TRY(createCompleteStorage(true, &newRenderTargetStorage)); - error = setCompleteTexStorage(newRenderTargetStorage); - if (error.isError()) - { - SafeDelete(newRenderTargetStorage); - return error; - } + ANGLE_TRY(mTexStorage->copyToStorage(context, newRenderTargetStorage.get())); + ANGLE_TRY(setCompleteTexStorage(context, newRenderTargetStorage.get())); + newRenderTargetStorage.release(); } } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } bool TextureD3D::canCreateRenderTargetForImage(const gl::ImageIndex &index) const { + if (index.type == GL_TEXTURE_2D_MULTISAMPLE) + return true; + ImageD3D *image = getImage(index); + ASSERT(image); bool levelsComplete = (isImageComplete(index) && isImageComplete(getImageIndex(0, 0))); return (image->isRenderableFormat() && levelsComplete); } -gl::Error TextureD3D::commitRegion(const gl::ImageIndex &index, const gl::Box ®ion) +gl::Error TextureD3D::commitRegion(const gl::Context *context, + 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; - } - + ANGLE_TRY(image->copyToStorage(context, mTexStorage, index, region)); image->markClean(); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureD3D::getAttachmentRenderTarget(const gl::FramebufferAttachment::Target &target, +gl::Error TextureD3D::getAttachmentRenderTarget(const gl::Context *context, + GLenum /*binding*/, + const gl::ImageIndex &imageIndex, FramebufferAttachmentRenderTarget **rtOut) { RenderTargetD3D *rtD3D = nullptr; - gl::Error error = getRenderTarget(target.textureIndex(), &rtD3D); + gl::Error error = getRenderTarget(context, imageIndex, &rtD3D); *rtOut = static_cast(rtD3D); return error; } -TextureD3D_2D::TextureD3D_2D(RendererD3D *renderer) - : TextureD3D(renderer) +gl::Error TextureD3D::setBaseLevel(const gl::Context *context, GLuint baseLevel) +{ + const int oldStorageWidth = std::max(1, getLevelZeroWidth()); + const int oldStorageHeight = std::max(1, getLevelZeroHeight()); + const int oldStorageDepth = std::max(1, getLevelZeroDepth()); + const int oldStorageFormat = getBaseLevelInternalFormat(); + mBaseLevel = baseLevel; + + // When the base level changes, the texture storage might not be valid anymore, since it could + // have been created based on the dimensions of the previous specified level range. + const int newStorageWidth = std::max(1, getLevelZeroWidth()); + const int newStorageHeight = std::max(1, getLevelZeroHeight()); + const int newStorageDepth = std::max(1, getLevelZeroDepth()); + const int newStorageFormat = getBaseLevelInternalFormat(); + if (mTexStorage && + (newStorageWidth != oldStorageWidth || newStorageHeight != oldStorageHeight || + newStorageDepth != oldStorageDepth || newStorageFormat != oldStorageFormat)) + { + markAllImagesDirty(); + ANGLE_TRY(releaseTexStorage(context)); + } + + return gl::NoError(); +} + +void TextureD3D::syncState(const gl::Texture::DirtyBits &dirtyBits) +{ + // TODO(geofflang): Use dirty bits +} + +gl::Error TextureD3D::releaseTexStorage(const gl::Context *context) +{ + if (!mTexStorage) + { + return gl::NoError(); + } + auto err = mTexStorage->onDestroy(context); + SafeDelete(mTexStorage); + return err; +} + +gl::Error TextureD3D::onDestroy(const gl::Context *context) +{ + return releaseTexStorage(context); +} + +gl::Error TextureD3D::initializeContents(const gl::Context *context, + const gl::ImageIndex &imageIndexIn) +{ + gl::ImageIndex imageIndex = imageIndexIn; + + // Special case for D3D11 3D textures. We can't create render targets for individual layers of a + // 3D texture, so force the clear to the entire mip. There shouldn't ever be a case where we + // would lose existing data. + if (imageIndex.type == GL_TEXTURE_3D) + { + imageIndex.layerIndex = gl::ImageIndex::ENTIRE_LEVEL; + } + else if (imageIndex.type == GL_TEXTURE_2D_ARRAY && + imageIndex.layerIndex == gl::ImageIndex::ENTIRE_LEVEL) + { + GLsizei layerCount = getLayerCount(imageIndex.mipIndex); + for (imageIndex.layerIndex = 0; imageIndex.layerIndex < layerCount; ++imageIndex.layerIndex) + { + ANGLE_TRY(initializeContents(context, imageIndex)); + } + return gl::NoError(); + } + + // Force image clean. + ImageD3D *image = getImage(imageIndex); + if (image) + { + image->markClean(); + } + + // Fast path: can use a render target clear. + if (canCreateRenderTargetForImage(imageIndex)) + { + ANGLE_TRY(ensureRenderTarget(context)); + ASSERT(mTexStorage); + RenderTargetD3D *renderTarget = nullptr; + ANGLE_TRY(mTexStorage->getRenderTarget(context, imageIndex, &renderTarget)); + ANGLE_TRY(mRenderer->initRenderTarget(renderTarget)); + return gl::NoError(); + } + + // Slow path: non-renderable texture or the texture levels aren't set up. + const auto &formatInfo = gl::GetSizedInternalFormatInfo(image->getInternalFormat()); + + size_t imageBytes = 0; + ANGLE_TRY_RESULT(formatInfo.computeRowPitch(formatInfo.type, image->getWidth(), 1, 0), + imageBytes); + imageBytes *= image->getHeight() * image->getDepth(); + + gl::PixelUnpackState defaultUnpackState; + + angle::MemoryBuffer *zeroBuffer = nullptr; + ANGLE_TRY(context->getZeroFilledBuffer(imageBytes, &zeroBuffer)); + if (shouldUseSetData(image)) + { + ANGLE_TRY(mTexStorage->setData(context, imageIndex, image, nullptr, formatInfo.type, + defaultUnpackState, zeroBuffer->data())); + } + else + { + gl::Box fullImageArea(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth()); + ANGLE_TRY(image->loadData(context, fullImageArea, defaultUnpackState, formatInfo.type, + zeroBuffer->data(), false)); + + // Force an update to the tex storage so we avoid problems with subImage and dirty regions. + if (mTexStorage) + { + ANGLE_TRY(commitRegion(context, imageIndex, fullImageArea)); + image->markClean(); + } + else + { + mDirtyImages = true; + } + } + return gl::NoError(); +} + +TextureD3D_2D::TextureD3D_2D(const gl::TextureState &state, RendererD3D *renderer) + : TextureD3D(state, renderer) { mEGLImageTarget = false; - for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i) + for (auto &image : mImageArray) { - mImageArray[i] = renderer->createImage(); + image.reset(renderer->createImage()); } } -TextureD3D_2D::~TextureD3D_2D() +gl::Error TextureD3D_2D::onDestroy(const gl::Context *context) { - // 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 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 (auto &image : mImageArray) { - delete mImageArray[i]; + image.reset(); } + return TextureD3D::onDestroy(context); +} - SafeDelete(mTexStorage); +TextureD3D_2D::~TextureD3D_2D() +{ } ImageD3D *TextureD3D_2D::getImage(int level, int layer) const { ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); ASSERT(layer == 0); - return mImageArray[level]; + return mImageArray[level].get(); } ImageD3D *TextureD3D_2D::getImage(const gl::ImageIndex &index) const @@ -647,7 +779,7 @@ 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]; + return mImageArray[index.mipIndex].get(); } GLsizei TextureD3D_2D::getLayerCount(int level) const @@ -682,10 +814,16 @@ GLenum TextureD3D_2D::getInternalFormat(GLint level) const bool TextureD3D_2D::isDepth(GLint level) const { - return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0; + return gl::GetSizedInternalFormatInfo(getInternalFormat(level)).depthBits > 0; +} + +bool TextureD3D_2D::isSRGB(GLint level) const +{ + return gl::GetSizedInternalFormatInfo(getInternalFormat(level)).colorEncoding == GL_SRGB; } -gl::Error TextureD3D_2D::setImage(GLenum target, +gl::Error TextureD3D_2D::setImage(const gl::Context *context, + GLenum target, size_t imageLevel, GLenum internalFormat, const gl::Extents &size, @@ -696,33 +834,29 @@ gl::Error TextureD3D_2D::setImage(GLenum target, { ASSERT(target == GL_TEXTURE_2D && size.depth == 1); - GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type); + const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(internalFormat, type); bool fastUnpacked = false; GLint level = static_cast(imageLevel); - redefineImage(level, sizedInternalFormat, size, false); + ANGLE_TRY(redefineImage(context, level, internalFormatInfo.sizedInternalFormat, size, false)); 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)) + gl::Buffer *unpackBuffer = + context->getGLState().getTargetBuffer(gl::BufferBinding::PixelUnpack); + if (isFastUnpackable(unpackBuffer, internalFormatInfo.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; - } + RenderTargetD3D *destRenderTarget = nullptr; + ANGLE_TRY(getRenderTarget(context, index, &destRenderTarget)); gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), 1); - error = fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget); - if (error.isError()) - { - return error; - } + ANGLE_TRY(fastUnpackPixels(context, unpack, pixels, destArea, + internalFormatInfo.sizedInternalFormat, type, destRenderTarget)); // Ensure we don't overwrite our newly initialized data mImageArray[level]->markClean(); @@ -732,17 +866,14 @@ gl::Error TextureD3D_2D::setImage(GLenum target, if (!fastUnpacked) { - gl::Error error = setImageImpl(index, type, unpack, pixels, 0); - if (error.isError()) - { - return error; - } + ANGLE_TRY(setImageImpl(context, index, type, unpack, pixels, 0)); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureD3D_2D::setSubImage(GLenum target, +gl::Error TextureD3D_2D::setSubImage(const gl::Context *context, + GLenum target, size_t imageLevel, const gl::Box &area, GLenum format, @@ -754,26 +885,26 @@ gl::Error TextureD3D_2D::setSubImage(GLenum target, GLint level = static_cast(imageLevel); 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; - } + gl::Buffer *unpackBuffer = + context->getGLState().getTargetBuffer(gl::BufferBinding::PixelUnpack); + if (isFastUnpackable(unpackBuffer, getInternalFormat(level)) && isLevelComplete(level)) + { + RenderTargetD3D *renderTarget = nullptr; + ANGLE_TRY(getRenderTarget(context, index, &renderTarget)); ASSERT(!mImageArray[level]->isDirty()); - return fastUnpackPixels(unpack, pixels, area, getInternalFormat(level), type, renderTarget); + return fastUnpackPixels(context, unpack, pixels, area, getInternalFormat(level), type, + renderTarget); } else { - return TextureD3D::subImage(index, area, format, type, unpack, pixels, 0); + return TextureD3D::subImage(context, index, area, format, type, unpack, pixels, 0); } } -gl::Error TextureD3D_2D::setCompressedImage(GLenum target, +gl::Error TextureD3D_2D::setCompressedImage(const gl::Context *context, + GLenum target, size_t imageLevel, GLenum internalFormat, const gl::Extents &size, @@ -785,84 +916,120 @@ gl::Error TextureD3D_2D::setCompressedImage(GLenum target, GLint level = static_cast(imageLevel); // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly - redefineImage(level, internalFormat, size, false); + ANGLE_TRY(redefineImage(context, level, internalFormat, size, false)); - return setCompressedImageImpl(gl::ImageIndex::Make2D(level), unpack, pixels, 0); + return setCompressedImageImpl(context, 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, size_t imageSize, const uint8_t *pixels) +gl::Error TextureD3D_2D::setCompressedSubImage(const gl::Context *context, + GLenum target, + size_t level, + const gl::Box &area, + GLenum format, + const gl::PixelUnpackState &unpack, + size_t imageSize, + const uint8_t *pixels) { ASSERT(target == GL_TEXTURE_2D && area.depth == 1 && area.z == 0); gl::ImageIndex index = gl::ImageIndex::Make2D(static_cast(level)); - gl::Error error = TextureD3D::subImageCompressed(index, area, format, unpack, pixels, 0); - if (error.isError()) - { - return error; - } + ANGLE_TRY(TextureD3D::subImageCompressed(context, index, area, format, unpack, pixels, 0)); - return commitRegion(index, area); + return commitRegion(context, index, area); } -gl::Error TextureD3D_2D::copyImage(GLenum target, +gl::Error TextureD3D_2D::copyImage(const gl::Context *context, + GLenum target, size_t imageLevel, - const gl::Rectangle &sourceArea, + const gl::Rectangle &origSourceArea, GLenum internalFormat, const gl::Framebuffer *source) { ASSERT(target == GL_TEXTURE_2D); - GLint level = static_cast(imageLevel); - GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, GL_UNSIGNED_BYTE); - redefineImage(level, sizedInternalFormat, gl::Extents(sourceArea.width, sourceArea.height, 1), - false); + GLint level = static_cast(imageLevel); + const gl::InternalFormat &internalFormatInfo = + gl::GetInternalFormatInfo(internalFormat, GL_UNSIGNED_BYTE); + gl::Extents sourceExtents(origSourceArea.width, origSourceArea.height, 1); + ANGLE_TRY(redefineImage(context, level, internalFormatInfo.sizedInternalFormat, sourceExtents, + false)); + + gl::Extents fbSize = source->getReadColorbuffer()->getSize(); + + // Does the read area extend beyond the framebuffer? + bool outside = origSourceArea.x < 0 || origSourceArea.y < 0 || + origSourceArea.x + origSourceArea.width > fbSize.width || + origSourceArea.y + origSourceArea.height > fbSize.height; + + // In WebGL mode we need to zero the texture outside the framebuffer. + // If we have robust resource init, it was already zeroed by redefineImage() above, otherwise + // zero it explicitly. + // TODO(fjhenigman): When robust resource is fully implemented look into making it a + // prerequisite for WebGL and deleting this code. + if (outside && + (context->getExtensions().webglCompatibility || context->isRobustResourceInitEnabled())) + { + angle::MemoryBuffer *zero; + ANGLE_TRY(context->getZeroFilledBuffer( + origSourceArea.width * origSourceArea.height * internalFormatInfo.pixelBytes, &zero)); + gl::PixelUnpackState unpack; + unpack.alignment = 1; + ANGLE_TRY(setImage(context, target, imageLevel, internalFormat, sourceExtents, + internalFormatInfo.format, internalFormatInfo.type, unpack, + zero->data())); + } + + gl::Rectangle sourceArea; + if (!ClipRectangle(origSourceArea, gl::Rectangle(0, 0, fbSize.width, fbSize.height), + &sourceArea)) + { + // Empty source area, nothing to do. + return gl::NoError(); + } gl::ImageIndex index = gl::ImageIndex::Make2D(level); - gl::Offset destOffset(0, 0, 0); + gl::Offset destOffset(sourceArea.x - origSourceArea.x, sourceArea.y - origSourceArea.y, 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]->copyFromFramebuffer(destOffset, sourceArea, source); - if (error.isError()) - { - return error; - } - + ANGLE_TRY(mImageArray[level]->copyFromFramebuffer(context, destOffset, sourceArea, source)); mDirtyImages = true; } else { - gl::Error error = ensureRenderTarget(); - if (error.isError()) - { - return error; - } - - mImageArray[level]->markClean(); + ANGLE_TRY(ensureRenderTarget(context)); if (sourceArea.width != 0 && sourceArea.height != 0 && isValidLevel(level)) { - error = mRenderer->copyImage2D(source, sourceArea, internalFormat, destOffset, mTexStorage, level); - if (error.isError()) - { - return error; - } + ANGLE_TRY(updateStorageLevel(context, level)); + ANGLE_TRY(mRenderer->copyImage2D(context, source, sourceArea, internalFormat, + destOffset, mTexStorage, level)); } } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureD3D_2D::copySubImage(GLenum target, +gl::Error TextureD3D_2D::copySubImage(const gl::Context *context, + GLenum target, size_t imageLevel, - const gl::Offset &destOffset, - const gl::Rectangle &sourceArea, + const gl::Offset &origDestOffset, + const gl::Rectangle &origSourceArea, const gl::Framebuffer *source) { - ASSERT(target == GL_TEXTURE_2D && destOffset.z == 0); + ASSERT(target == GL_TEXTURE_2D && origDestOffset.z == 0); + + gl::Extents fbSize = source->getReadColorbuffer()->getSize(); + gl::Rectangle sourceArea; + if (!ClipRectangle(origSourceArea, gl::Rectangle(0, 0, fbSize.width, fbSize.height), + &sourceArea)) + { + return gl::NoError(); + } + const gl::Offset destOffset(origDestOffset.x + sourceArea.x - origSourceArea.x, + origDestOffset.y + sourceArea.y - origSourceArea.y, 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) @@ -874,174 +1041,287 @@ gl::Error TextureD3D_2D::copySubImage(GLenum target, // so we should use the non-rendering copy path. if (!canCreateRenderTargetForImage(index) || mRenderer->getWorkarounds().zeroMaxLodWorkaround) { - gl::Error error = mImageArray[level]->copyFromFramebuffer(destOffset, sourceArea, source); - if (error.isError()) - { - return error; - } - + ANGLE_TRY(mImageArray[level]->copyFromFramebuffer(context, destOffset, sourceArea, source)); mDirtyImages = true; } else { - gl::Error error = ensureRenderTarget(); - if (error.isError()) - { - return error; - } + ANGLE_TRY(ensureRenderTarget(context)); 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; - } + ANGLE_TRY(updateStorageLevel(context, level)); + ANGLE_TRY(mRenderer->copyImage2D(context, source, sourceArea, + gl::GetUnsizedFormat(getBaseLevelInternalFormat()), + destOffset, mTexStorage, level)); } } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureD3D_2D::setStorage(GLenum target, size_t levels, GLenum internalFormat, const gl::Extents &size) +gl::Error TextureD3D_2D::copyTexture(const gl::Context *context, + GLenum target, + size_t level, + GLenum internalFormat, + GLenum type, + size_t sourceLevel, + bool unpackFlipY, + bool unpackPremultiplyAlpha, + bool unpackUnmultiplyAlpha, + const gl::Texture *source) { - ASSERT(GL_TEXTURE_2D && size.depth == 1); + ASSERT(target == GL_TEXTURE_2D); - for (size_t level = 0; level < levels; level++) - { - gl::Extents levelSize(std::max(1, size.width >> level), - std::max(1, size.height >> level), - 1); - redefineImage(level, internalFormat, levelSize, true); - } + GLenum sourceTarget = source->getTarget(); - for (size_t level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) - { - redefineImage(level, GL_NONE, gl::Extents(0, 0, 1), true); - } + GLint destLevel = static_cast(level); - // TODO(geofflang): Verify storage creation had no errors - bool renderTarget = IsRenderTargetUsage(mUsage); - TextureStorage *storage = mRenderer->createTextureStorage2D( - internalFormat, renderTarget, size.width, size.height, static_cast(levels), false); + const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(internalFormat, type); + gl::Extents size(static_cast(source->getWidth(sourceTarget, sourceLevel)), + static_cast(source->getHeight(sourceTarget, sourceLevel)), 1); + ANGLE_TRY( + redefineImage(context, destLevel, internalFormatInfo.sizedInternalFormat, size, false)); + + gl::Rectangle sourceRect(0, 0, size.width, size.height); + gl::Offset destOffset(0, 0, 0); - gl::Error error = setCompleteTexStorage(storage); - if (error.isError()) + if (!isSRGB(destLevel) && canCreateRenderTargetForImage(gl::ImageIndex::Make2D(destLevel))) { - SafeDelete(storage); - return error; + ANGLE_TRY(ensureRenderTarget(context)); + ASSERT(isValidLevel(destLevel)); + ANGLE_TRY(updateStorageLevel(context, destLevel)); + + ANGLE_TRY(mRenderer->copyTexture(context, source, static_cast(sourceLevel), + sourceRect, internalFormatInfo.format, destOffset, + mTexStorage, target, destLevel, unpackFlipY, + unpackPremultiplyAlpha, unpackUnmultiplyAlpha)); } + else + { + gl::ImageIndex sourceImageIndex = gl::ImageIndex::Make2D(static_cast(sourceLevel)); + TextureD3D *sourceD3D = GetImplAs(source); + ImageD3D *sourceImage = nullptr; + ANGLE_TRY(sourceD3D->getImageAndSyncFromStorage(context, sourceImageIndex, &sourceImage)); - error = updateStorage(); + gl::ImageIndex destImageIndex = gl::ImageIndex::Make2D(static_cast(destLevel)); + ImageD3D *destImage = nullptr; + ANGLE_TRY(getImageAndSyncFromStorage(context, destImageIndex, &destImage)); - if (error.isError()) - { - return error; - } + ANGLE_TRY(mRenderer->copyImage(context, destImage, sourceImage, sourceRect, destOffset, + unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha)); - mImmutable = true; + mDirtyImages = true; + + gl::Box destRegion(destOffset, size); + ANGLE_TRY(commitRegion(context, destImageIndex, destRegion)); + } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -void TextureD3D_2D::bindTexImage(egl::Surface *surface) +gl::Error TextureD3D_2D::copySubTexture(const gl::Context *context, + GLenum target, + size_t level, + const gl::Offset &destOffset, + size_t sourceLevel, + const gl::Rectangle &sourceArea, + bool unpackFlipY, + bool unpackPremultiplyAlpha, + bool unpackUnmultiplyAlpha, + const gl::Texture *source) { - GLenum internalformat = surface->getConfig()->renderTargetFormat; + ASSERT(target == GL_TEXTURE_2D); - gl::Extents size(surface->getWidth(), surface->getHeight(), 1); - redefineImage(0, internalformat, size, true); + GLint destLevel = static_cast(level); - if (mTexStorage) + if (!isSRGB(destLevel) && canCreateRenderTargetForImage(gl::ImageIndex::Make2D(destLevel))) + { + ANGLE_TRY(ensureRenderTarget(context)); + ASSERT(isValidLevel(destLevel)); + ANGLE_TRY(updateStorageLevel(context, destLevel)); + + ANGLE_TRY(mRenderer->copyTexture( + context, source, static_cast(sourceLevel), sourceArea, + gl::GetUnsizedFormat(getInternalFormat(destLevel)), destOffset, mTexStorage, target, + destLevel, unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha)); + } + else + { + gl::ImageIndex sourceImageIndex = gl::ImageIndex::Make2D(static_cast(sourceLevel)); + TextureD3D *sourceD3D = GetImplAs(source); + ImageD3D *sourceImage = nullptr; + ANGLE_TRY(sourceD3D->getImageAndSyncFromStorage(context, sourceImageIndex, &sourceImage)); + + gl::ImageIndex destImageIndex = gl::ImageIndex::Make2D(static_cast(destLevel)); + ImageD3D *destImage = nullptr; + ANGLE_TRY(getImageAndSyncFromStorage(context, destImageIndex, &destImage)); + + ANGLE_TRY(mRenderer->copyImage(context, destImage, sourceImage, sourceArea, destOffset, + unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha)); + + mDirtyImages = true; + + gl::Box destRegion(destOffset.x, destOffset.y, 0, sourceArea.width, sourceArea.height, 1); + ANGLE_TRY(commitRegion(context, destImageIndex, destRegion)); + } + + return gl::NoError(); +} + +gl::Error TextureD3D_2D::copyCompressedTexture(const gl::Context *context, + const gl::Texture *source) +{ + GLenum sourceTarget = source->getTarget(); + GLint sourceLevel = 0; + + GLint destLevel = 0; + + GLenum sizedInternalFormat = + source->getFormat(sourceTarget, sourceLevel).info->sizedInternalFormat; + gl::Extents size(static_cast(source->getWidth(sourceTarget, sourceLevel)), + static_cast(source->getHeight(sourceTarget, sourceLevel)), 1); + ANGLE_TRY(redefineImage(context, destLevel, sizedInternalFormat, size, false)); + + ANGLE_TRY(initializeStorage(context, false)); + ASSERT(mTexStorage); + + ANGLE_TRY( + mRenderer->copyCompressedTexture(context, source, sourceLevel, mTexStorage, destLevel)); + + return gl::NoError(); +} + +gl::Error TextureD3D_2D::setStorage(const gl::Context *context, + 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); + ANGLE_TRY(redefineImage(context, level, internalFormat, levelSize, true)); + } + + for (size_t level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) { - SafeDelete(mTexStorage); + ANGLE_TRY(redefineImage(context, level, GL_NONE, gl::Extents(0, 0, 1), true)); } + // TODO(geofflang): Verify storage creation had no errors + bool renderTarget = IsRenderTargetUsage(mState.getUsage()); + TexStoragePointer storage(context); + storage.reset(mRenderer->createTextureStorage2D(internalFormat, renderTarget, size.width, + size.height, static_cast(levels), false)); + + ANGLE_TRY(setCompleteTexStorage(context, storage.get())); + storage.release(); + + ANGLE_TRY(updateStorage(context)); + + mImmutable = true; + + return gl::NoError(); +} + +gl::Error TextureD3D_2D::bindTexImage(const gl::Context *context, egl::Surface *surface) +{ + GLenum internalformat = surface->getConfig()->renderTargetFormat; + + gl::Extents size(surface->getWidth(), surface->getHeight(), 1); + ANGLE_TRY(redefineImage(context, 0, internalformat, size, true)); + + ANGLE_TRY(releaseTexStorage(context)); + SurfaceD3D *surfaceD3D = GetImplAs(surface); ASSERT(surfaceD3D); mTexStorage = mRenderer->createTextureStorage2D(surfaceD3D->getSwapChain()); mEGLImageTarget = false; - mDirtyImages = true; + mDirtyImages = false; + mImageArray[0]->markClean(); + + return gl::NoError(); } -void TextureD3D_2D::releaseTexImage() +gl::Error TextureD3D_2D::releaseTexImage(const gl::Context *context) { if (mTexStorage) { - SafeDelete(mTexStorage); + ANGLE_TRY(releaseTexStorage(context)); } for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) { - redefineImage(i, GL_NONE, gl::Extents(0, 0, 1), true); + ANGLE_TRY(redefineImage(context, i, GL_NONE, gl::Extents(0, 0, 1), true)); } + + return gl::NoError(); } -gl::Error TextureD3D_2D::setEGLImageTarget(GLenum target, egl::Image *image) +gl::Error TextureD3D_2D::setEGLImageTarget(const gl::Context *context, + GLenum target, + egl::Image *image) { EGLImageD3D *eglImaged3d = GetImplAs(image); // Set the properties of the base mip level from the EGL image - GLenum internalformat = image->getInternalFormat(); + const auto &format = image->getFormat(); gl::Extents size(static_cast(image->getWidth()), static_cast(image->getHeight()), 1); - redefineImage(0, internalformat, size, true); + ANGLE_TRY(redefineImage(context, 0, format.info->sizedInternalFormat, size, true)); // Clear all other images. - for (size_t level = 1; level < ArraySize(mImageArray); level++) + for (size_t level = 1; level < mImageArray.size(); level++) { - redefineImage(level, GL_NONE, gl::Extents(0, 0, 1), true); + ANGLE_TRY(redefineImage(context, level, GL_NONE, gl::Extents(0, 0, 1), true)); } - SafeDelete(mTexStorage); + ANGLE_TRY(releaseTexStorage(context)); mImageArray[0]->markClean(); - mTexStorage = mRenderer->createTextureStorageEGLImage(eglImaged3d); + // Pass in the RenderTargetD3D here: createTextureStorage can't generate an error. + RenderTargetD3D *renderTargetD3D = nullptr; + ANGLE_TRY(eglImaged3d->getRenderTarget(context, &renderTargetD3D)); + + mTexStorage = mRenderer->createTextureStorageEGLImage(eglImaged3d, renderTargetD3D); mEGLImageTarget = true; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -void TextureD3D_2D::initMipmapsImages() +gl::Error TextureD3D_2D::initMipmapImages(const gl::Context *context) { - // 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++) + const GLuint baseLevel = mState.getEffectiveBaseLevel(); + const GLuint maxLevel = mState.getMipmapMaxLevel(); + // Purge array levels baseLevel + 1 through q and reset them to represent the generated mipmap + // levels. + for (GLuint level = baseLevel + 1; level <= maxLevel; level++) { - gl::Extents levelSize(std::max(getBaseLevelWidth() >> level, 1), - std::max(getBaseLevelHeight() >> level, 1), - 1); + gl::Extents levelSize(std::max(getLevelZeroWidth() >> level, 1), + std::max(getLevelZeroHeight() >> level, 1), 1); - redefineImage(level, getBaseLevelInternalFormat(), levelSize, false); + ANGLE_TRY(redefineImage(context, level, getBaseLevelInternalFormat(), levelSize, false)); } + return gl::NoError(); } -gl::Error TextureD3D_2D::getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT) +gl::Error TextureD3D_2D::getRenderTarget(const gl::Context *context, + const gl::ImageIndex &index, + RenderTargetD3D **outRT) { ASSERT(!index.hasLayer()); // ensure the underlying texture is created - gl::Error error = ensureRenderTarget(); - if (error.isError()) - { - return error; - } + ANGLE_TRY(ensureRenderTarget(context)); + ANGLE_TRY(updateStorageLevel(context, index.mipIndex)); - error = updateStorageLevel(index.mipIndex); - if (error.isError()) - { - return error; - } - - return mTexStorage->getRenderTarget(index, outRT); + return mTexStorage->getRenderTarget(context, index, outRT); } bool TextureD3D_2D::isValidLevel(int level) const @@ -1056,10 +1336,8 @@ bool TextureD3D_2D::isLevelComplete(int level) const return true; } - const ImageD3D *baseImage = getBaseLevelImage(); - - GLsizei width = baseImage->getWidth(); - GLsizei height = baseImage->getHeight(); + GLsizei width = getLevelZeroWidth(); + GLsizei height = getLevelZeroHeight(); if (width <= 0 || height <= 0) { @@ -1067,15 +1345,16 @@ bool TextureD3D_2D::isLevelComplete(int level) const } // The base image level is complete if the width and height are positive - if (level == 0) + if (level == static_cast(getBaseLevel())) { return true; } - ASSERT(level >= 1 && level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL); - ImageD3D *image = mImageArray[level]; + ASSERT(level >= 0 && level <= static_cast(mImageArray.size()) && + mImageArray[level] != nullptr); + ImageD3D *image = mImageArray[level].get(); - if (image->getInternalFormat() != baseImage->getInternalFormat()) + if (image->getInternalFormat() != getBaseLevelInternalFormat()) { return false; } @@ -1099,52 +1378,41 @@ bool TextureD3D_2D::isImageComplete(const gl::ImageIndex &index) const } // Constructs a native texture resource from the texture images -gl::Error TextureD3D_2D::initializeStorage(bool renderTarget) +gl::Error TextureD3D_2D::initializeStorage(const gl::Context *context, 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); + return gl::NoError(); } // do not attempt to create storage for nonexistant data - if (!isLevelComplete(0)) + if (!isLevelComplete(getBaseLevel())) { - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } - bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage)); + bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mState.getUsage())); - TextureStorage *storage = NULL; - gl::Error error = createCompleteStorage(createRenderTarget, &storage); - if (error.isError()) - { - return error; - } + TexStoragePointer storage(context); + ANGLE_TRY(createCompleteStorage(createRenderTarget, &storage)); - error = setCompleteTexStorage(storage); - if (error.isError()) - { - SafeDelete(storage); - return error; - } + ANGLE_TRY(setCompleteTexStorage(context, storage.get())); + storage.release(); ASSERT(mTexStorage); // flush image data to the storage - error = updateStorage(); - if (error.isError()) - { - return error; - } + ANGLE_TRY(updateStorage(context)); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureD3D_2D::createCompleteStorage(bool renderTarget, TextureStorage **outTexStorage) const +gl::Error TextureD3D_2D::createCompleteStorage(bool renderTarget, + TexStoragePointer *outStorage) const { - GLsizei width = getBaseLevelWidth(); - GLsizei height = getBaseLevelHeight(); + GLsizei width = getLevelZeroWidth(); + GLsizei height = getLevelZeroHeight(); GLenum internalFormat = getBaseLevelInternalFormat(); ASSERT(width > 0 && height > 0); @@ -1165,84 +1433,83 @@ gl::Error TextureD3D_2D::createCompleteStorage(bool renderTarget, TextureStorage } // TODO(geofflang): Determine if the texture creation succeeded - *outTexStorage = mRenderer->createTextureStorage2D(internalFormat, renderTarget, width, height, levels, hintLevelZeroOnly); + outStorage->reset(mRenderer->createTextureStorage2D(internalFormat, renderTarget, width, height, + levels, hintLevelZeroOnly)); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureD3D_2D::setCompleteTexStorage(TextureStorage *newCompleteTexStorage) +gl::Error TextureD3D_2D::setCompleteTexStorage(const gl::Context *context, + 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; - } + ANGLE_TRY( + mImageArray[level]->setManagedSurface2D(context, newCompleteTexStorage, level)); } } - SafeDelete(mTexStorage); + ANGLE_TRY(releaseTexStorage(context)); mTexStorage = newCompleteTexStorage; mDirtyImages = true; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureD3D_2D::updateStorage() +gl::Error TextureD3D_2D::updateStorage(const gl::Context *context) { - ASSERT(mTexStorage != NULL); + if (!mDirtyImages) + { + return gl::NoError(); + } + + ASSERT(mTexStorage != nullptr); 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; - } + ANGLE_TRY(updateStorageLevel(context, level)); } } - return gl::Error(GL_NO_ERROR); + mDirtyImages = false; + return gl::NoError(); } -gl::Error TextureD3D_2D::updateStorageLevel(int level) +gl::Error TextureD3D_2D::updateStorageLevel(const gl::Context *context, int level) { - ASSERT(level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL); + ASSERT(level <= static_cast(mImageArray.size()) && mImageArray[level] != nullptr); 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; - } + ANGLE_TRY(commitRegion(context, index, region)); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -void TextureD3D_2D::redefineImage(size_t level, - GLenum internalformat, - const gl::Extents &size, - bool forceRelease) +gl::Error TextureD3D_2D::redefineImage(const gl::Context *context, + size_t level, + GLenum internalformat, + const gl::Extents &size, + bool forceRelease) { 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 int storageWidth = std::max(1, getLevelZeroWidth() >> level); + const int storageHeight = std::max(1, getLevelZeroHeight() >> level); const GLenum storageFormat = getBaseLevelInternalFormat(); mImageArray[level]->redefine(GL_TEXTURE_2D, internalformat, size, forceRelease); + mDirtyImages = mDirtyImages || mImageArray[level]->isDirty(); if (mTexStorage) { @@ -1252,27 +1519,23 @@ void TextureD3D_2D::redefineImage(size_t level, // while orphaning if (level != 0 && mEGLImageTarget) { - // TODO(jmadill): Don't discard error. - mImageArray[0]->copyFromTexStorage(gl::ImageIndex::Make2D(0), mTexStorage); + ANGLE_TRY(mImageArray[0]->copyFromTexStorage(context, gl::ImageIndex::Make2D(0), + mTexStorage)); } - if ((level >= storageLevels && storageLevels != 0) || - size.width != storageWidth || + if ((level >= storageLevels && storageLevels != 0) || size.width != storageWidth || size.height != storageHeight || - internalformat != storageFormat) // Discard mismatched storage + internalformat != storageFormat) // Discard mismatched storage { - for (size_t i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) - { - mImageArray[i]->markDirty(); - } - - SafeDelete(mTexStorage); - mDirtyImages = true; + ANGLE_TRY(releaseTexStorage(context)); + markAllImagesDirty(); } } // Can't be an EGL image target after being redefined mEGLImageTarget = false; + + return gl::NoError(); } gl::ImageIndexIterator TextureD3D_2D::imageIterator() const @@ -1292,46 +1555,58 @@ bool TextureD3D_2D::isValidIndex(const gl::ImageIndex &index) const index.mipIndex >= 0 && index.mipIndex < mTexStorage->getLevelCount()); } -TextureD3D_Cube::TextureD3D_Cube(RendererD3D *renderer) - : TextureD3D(renderer) +void TextureD3D_2D::markAllImagesDirty() +{ + for (size_t i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) + { + mImageArray[i]->markDirty(); + } + mDirtyImages = true; +} + +TextureD3D_Cube::TextureD3D_Cube(const gl::TextureState &state, RendererD3D *renderer) + : TextureD3D(state, renderer) { - for (int i = 0; i < 6; i++) + for (auto &face : mImageArray) { - for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j) + for (auto &image : face) { - mImageArray[i][j] = renderer->createImage(); + image.reset(renderer->createImage()); } } } -TextureD3D_Cube::~TextureD3D_Cube() +gl::Error TextureD3D_Cube::onDestroy(const gl::Context *context) { - // 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++) + // 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 (auto &face : mImageArray) { - for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j) + for (auto &image : face) { - SafeDelete(mImageArray[i][j]); + image.reset(); } } + return TextureD3D::onDestroy(context); +} - SafeDelete(mTexStorage); +TextureD3D_Cube::~TextureD3D_Cube() +{ } 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]; + return mImageArray[layer][level].get(); } 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]; + return mImageArray[index.layerIndex][index.mipIndex].get(); } GLsizei TextureD3D_Cube::getLayerCount(int level) const @@ -1350,128 +1625,191 @@ GLenum TextureD3D_Cube::getInternalFormat(GLint level, GLint layer) const bool TextureD3D_Cube::isDepth(GLint level, GLint layer) const { - return gl::GetInternalFormatInfo(getInternalFormat(level, layer)).depthBits > 0; + return gl::GetSizedInternalFormatInfo(getInternalFormat(level, layer)).depthBits > 0; } -gl::Error TextureD3D_Cube::setEGLImageTarget(GLenum target, egl::Image *image) +bool TextureD3D_Cube::isSRGB(GLint level, GLint layer) const +{ + return gl::GetSizedInternalFormatInfo(getInternalFormat(level, layer)).colorEncoding == GL_SRGB; +} + +gl::Error TextureD3D_Cube::setEGLImageTarget(const gl::Context *context, + GLenum target, + egl::Image *image) { UNREACHABLE(); - return gl::Error(GL_INVALID_OPERATION); + return gl::InternalError(); } -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) +gl::Error TextureD3D_Cube::setImage(const gl::Context *context, + 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); + const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(internalFormat, type); gl::ImageIndex index = gl::ImageIndex::MakeCube(target, static_cast(level)); - redefineImage(index.layerIndex, static_cast(level), sizedInternalFormat, size); + ANGLE_TRY(redefineImage(context, index.layerIndex, static_cast(level), + internalFormatInfo.sizedInternalFormat, size, false)); - return setImageImpl(index, type, unpack, pixels, 0); + return setImageImpl(context, 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) +gl::Error TextureD3D_Cube::setSubImage(const gl::Context *context, + 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, static_cast(level)); - return TextureD3D::subImage(index, area, format, type, unpack, pixels, 0); + return TextureD3D::subImage(context, 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, size_t imageSize, const uint8_t *pixels) +gl::Error TextureD3D_Cube::setCompressedImage(const gl::Context *context, + GLenum target, + size_t level, + GLenum internalFormat, + const gl::Extents &size, + const gl::PixelUnpackState &unpack, + size_t imageSize, + 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(static_cast(faceIndex), static_cast(level), internalFormat, size); + ANGLE_TRY(redefineImage(context, static_cast(faceIndex), static_cast(level), + internalFormat, size, false)); gl::ImageIndex index = gl::ImageIndex::MakeCube(target, static_cast(level)); - return setCompressedImageImpl(index, unpack, pixels, 0); + return setCompressedImageImpl(context, index, unpack, pixels, 0); } -gl::Error TextureD3D_Cube::setCompressedSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format, - const gl::PixelUnpackState &unpack, size_t imageSize, const uint8_t *pixels) +gl::Error TextureD3D_Cube::setCompressedSubImage(const gl::Context *context, + GLenum target, + size_t level, + const gl::Box &area, + GLenum format, + const gl::PixelUnpackState &unpack, + size_t imageSize, + const uint8_t *pixels) { ASSERT(area.depth == 1 && area.z == 0); gl::ImageIndex index = gl::ImageIndex::MakeCube(target, static_cast(level)); - gl::Error error = TextureD3D::subImageCompressed(index, area, format, unpack, pixels, 0); - if (error.isError()) - { - return error; - } - - return commitRegion(index, area); + ANGLE_TRY(TextureD3D::subImageCompressed(context, index, area, format, unpack, pixels, 0)); + return commitRegion(context, index, area); } -gl::Error TextureD3D_Cube::copyImage(GLenum target, +gl::Error TextureD3D_Cube::copyImage(const gl::Context *context, + GLenum target, size_t imageLevel, - const gl::Rectangle &sourceArea, + const gl::Rectangle &origSourceArea, GLenum internalFormat, const gl::Framebuffer *source) { int faceIndex = static_cast(gl::CubeMapTextureTargetToLayerIndex(target)); - GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, GL_UNSIGNED_BYTE); + const gl::InternalFormat &internalFormatInfo = + gl::GetInternalFormatInfo(internalFormat, GL_UNSIGNED_BYTE); GLint level = static_cast(imageLevel); - gl::Extents size(sourceArea.width, sourceArea.height, 1); - redefineImage(static_cast(faceIndex), level, sizedInternalFormat, size); + gl::Extents size(origSourceArea.width, origSourceArea.height, 1); + ANGLE_TRY(redefineImage(context, static_cast(faceIndex), level, + internalFormatInfo.sizedInternalFormat, size, false)); + + gl::Extents fbSize = source->getReadColorbuffer()->getSize(); + + // Does the read area extend beyond the framebuffer? + bool outside = origSourceArea.x < 0 || origSourceArea.y < 0 || + origSourceArea.x + origSourceArea.width > fbSize.width || + origSourceArea.y + origSourceArea.height > fbSize.height; + + // In WebGL mode we need to zero the texture outside the framebuffer. + // If we have robust resource init, it was already zeroed by redefineImage() above, otherwise + // zero it explicitly. + // TODO(fjhenigman): When robust resource is fully implemented look into making it a + // prerequisite for WebGL and deleting this code. + if (outside && context->getExtensions().webglCompatibility && + !context->isRobustResourceInitEnabled()) + { + angle::MemoryBuffer *zero; + ANGLE_TRY(context->getZeroFilledBuffer( + origSourceArea.width * origSourceArea.height * internalFormatInfo.pixelBytes, &zero)); + gl::PixelUnpackState unpack; + unpack.alignment = 1; + ANGLE_TRY(setImage(context, target, imageLevel, internalFormat, size, + internalFormatInfo.format, internalFormatInfo.type, unpack, + zero->data())); + } + + gl::Rectangle sourceArea; + if (!ClipRectangle(origSourceArea, gl::Rectangle(0, 0, fbSize.width, fbSize.height), + &sourceArea)) + { + // Empty source area, nothing to do. + return gl::NoError(); + } gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level); - gl::Offset destOffset(0, 0, 0); + gl::Offset destOffset(sourceArea.x - origSourceArea.x, sourceArea.y - origSourceArea.y, 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]->copyFromFramebuffer(destOffset, sourceArea, source); - if (error.isError()) - { - return error; - } - + ANGLE_TRY(mImageArray[faceIndex][level]->copyFromFramebuffer(context, destOffset, + sourceArea, source)); mDirtyImages = true; } else { - gl::Error error = ensureRenderTarget(); - if (error.isError()) - { - return error; - } - - mImageArray[faceIndex][level]->markClean(); + ANGLE_TRY(ensureRenderTarget(context)); 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; - } + ANGLE_TRY(updateStorageFaceLevel(context, faceIndex, level)); + ANGLE_TRY(mRenderer->copyImageCube(context, source, sourceArea, internalFormat, + destOffset, mTexStorage, target, level)); } } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureD3D_Cube::copySubImage(GLenum target, +gl::Error TextureD3D_Cube::copySubImage(const gl::Context *context, + GLenum target, size_t imageLevel, - const gl::Offset &destOffset, - const gl::Rectangle &sourceArea, + const gl::Offset &origDestOffset, + const gl::Rectangle &origSourceArea, const gl::Framebuffer *source) { + gl::Extents fbSize = source->getReadColorbuffer()->getSize(); + gl::Rectangle sourceArea; + if (!ClipRectangle(origSourceArea, gl::Rectangle(0, 0, fbSize.width, fbSize.height), + &sourceArea)) + { + return gl::NoError(); + } + const gl::Offset destOffset(origDestOffset.x + sourceArea.x - origSourceArea.x, + origDestOffset.y + sourceArea.y - origSourceArea.y, 0); + int faceIndex = static_cast(gl::CubeMapTextureTargetToLayerIndex(target)); GLint level = static_cast(imageLevel); @@ -1481,44 +1819,145 @@ gl::Error TextureD3D_Cube::copySubImage(GLenum target, // so we should use the non-rendering copy path. if (!canCreateRenderTargetForImage(index) || mRenderer->getWorkarounds().zeroMaxLodWorkaround) { - gl::Error error = - mImageArray[faceIndex][level]->copyFromFramebuffer(destOffset, sourceArea, source); - if (error.isError()) + ANGLE_TRY(mImageArray[faceIndex][level]->copyFromFramebuffer(context, destOffset, + sourceArea, source)); + mDirtyImages = true; + } + else + { + ANGLE_TRY(ensureRenderTarget(context)); + if (isValidFaceLevel(faceIndex, level)) { - return error; + ANGLE_TRY(updateStorageFaceLevel(context, faceIndex, level)); + ANGLE_TRY(mRenderer->copyImageCube(context, source, sourceArea, + gl::GetUnsizedFormat(getBaseLevelInternalFormat()), + destOffset, mTexStorage, target, level)); } + } + + return gl::NoError(); +} + +gl::Error TextureD3D_Cube::copyTexture(const gl::Context *context, + GLenum target, + size_t level, + GLenum internalFormat, + GLenum type, + size_t sourceLevel, + bool unpackFlipY, + bool unpackPremultiplyAlpha, + bool unpackUnmultiplyAlpha, + const gl::Texture *source) +{ + ASSERT(gl::IsCubeMapTextureTarget(target)); + + GLenum sourceTarget = source->getTarget(); + + GLint destLevel = static_cast(level); + int faceIndex = static_cast(gl::CubeMapTextureTargetToLayerIndex(target)); + + const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(internalFormat, type); + gl::Extents size(static_cast(source->getWidth(sourceTarget, sourceLevel)), + static_cast(source->getHeight(sourceTarget, sourceLevel)), 1); + ANGLE_TRY(redefineImage(context, faceIndex, destLevel, internalFormatInfo.sizedInternalFormat, + size, false)); + + gl::Rectangle sourceRect(0, 0, size.width, size.height); + gl::Offset destOffset(0, 0, 0); + + if (!isSRGB(destLevel, faceIndex) && + canCreateRenderTargetForImage(gl::ImageIndex::MakeCube(target, destLevel))) + { + ANGLE_TRY(ensureRenderTarget(context)); + ASSERT(isValidFaceLevel(faceIndex, destLevel)); + ANGLE_TRY(updateStorageFaceLevel(context, faceIndex, destLevel)); + + ANGLE_TRY(mRenderer->copyTexture(context, source, static_cast(sourceLevel), + sourceRect, internalFormatInfo.format, destOffset, + mTexStorage, target, destLevel, unpackFlipY, + unpackPremultiplyAlpha, unpackUnmultiplyAlpha)); + } + else + { + gl::ImageIndex sourceImageIndex = gl::ImageIndex::Make2D(static_cast(sourceLevel)); + TextureD3D *sourceD3D = GetImplAs(source); + ImageD3D *sourceImage = nullptr; + ANGLE_TRY(sourceD3D->getImageAndSyncFromStorage(context, sourceImageIndex, &sourceImage)); + + gl::ImageIndex destImageIndex = + gl::ImageIndex::MakeCube(target, static_cast(destLevel)); + ImageD3D *destImage = nullptr; + ANGLE_TRY(getImageAndSyncFromStorage(context, destImageIndex, &destImage)); + + ANGLE_TRY(mRenderer->copyImage(context, destImage, sourceImage, sourceRect, destOffset, + unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha)); mDirtyImages = true; + + gl::Box destRegion(destOffset, size); + ANGLE_TRY(commitRegion(context, destImageIndex, destRegion)); + } + + return gl::NoError(); +} + +gl::Error TextureD3D_Cube::copySubTexture(const gl::Context *context, + GLenum target, + size_t level, + const gl::Offset &destOffset, + size_t sourceLevel, + const gl::Rectangle &sourceArea, + bool unpackFlipY, + bool unpackPremultiplyAlpha, + bool unpackUnmultiplyAlpha, + const gl::Texture *source) +{ + ASSERT(gl::IsCubeMapTextureTarget(target)); + + GLint destLevel = static_cast(level); + int faceIndex = static_cast(gl::CubeMapTextureTargetToLayerIndex(target)); + + if (!isSRGB(destLevel, faceIndex) && + canCreateRenderTargetForImage(gl::ImageIndex::MakeCube(target, destLevel))) + { + ANGLE_TRY(ensureRenderTarget(context)); + ASSERT(isValidFaceLevel(faceIndex, destLevel)); + ANGLE_TRY(updateStorageFaceLevel(context, faceIndex, destLevel)); + + ANGLE_TRY(mRenderer->copyTexture( + context, source, static_cast(sourceLevel), sourceArea, + gl::GetUnsizedFormat(getInternalFormat(destLevel, faceIndex)), destOffset, mTexStorage, + target, destLevel, unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha)); } else { - gl::Error error = ensureRenderTarget(); - if (error.isError()) - { - return error; - } + gl::ImageIndex sourceImageIndex = gl::ImageIndex::Make2D(static_cast(sourceLevel)); + TextureD3D *sourceD3D = GetImplAs(source); + ImageD3D *sourceImage = nullptr; + ANGLE_TRY(sourceD3D->getImageAndSyncFromStorage(context, sourceImageIndex, &sourceImage)); - if (isValidFaceLevel(faceIndex, level)) - { - error = updateStorageFaceLevel(faceIndex, level); - if (error.isError()) - { - return error; - } + gl::ImageIndex destImageIndex = + gl::ImageIndex::MakeCube(target, static_cast(destLevel)); + ImageD3D *destImage = nullptr; + ANGLE_TRY(getImageAndSyncFromStorage(context, destImageIndex, &destImage)); - error = mRenderer->copyImageCube(source, sourceArea, gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format, - destOffset, mTexStorage, target, level); - if (error.isError()) - { - return error; - } - } + ANGLE_TRY(mRenderer->copyImage(context, destImage, sourceImage, sourceArea, destOffset, + unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha)); + + mDirtyImages = true; + + gl::Box destRegion(destOffset.x, destOffset.y, 0, sourceArea.width, sourceArea.height, 1); + ANGLE_TRY(commitRegion(context, destImageIndex, destRegion)); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureD3D_Cube::setStorage(GLenum target, size_t levels, GLenum internalFormat, const gl::Extents &size) +gl::Error TextureD3D_Cube::setStorage(const gl::Context *context, + GLenum target, + size_t levels, + GLenum internalFormat, + const gl::Extents &size) { ASSERT(size.width == size.height); ASSERT(size.depth == 1); @@ -1541,28 +1980,20 @@ gl::Error TextureD3D_Cube::setStorage(GLenum target, size_t levels, GLenum inter } // TODO(geofflang): Verify storage creation had no errors - bool renderTarget = IsRenderTargetUsage(mUsage); + bool renderTarget = IsRenderTargetUsage(mState.getUsage()); - TextureStorage *storage = mRenderer->createTextureStorageCube( - internalFormat, renderTarget, size.width, static_cast(levels), false); - - gl::Error error = setCompleteTexStorage(storage); - if (error.isError()) - { - SafeDelete(storage); - return error; - } + TexStoragePointer storage(context); + storage.reset(mRenderer->createTextureStorageCube(internalFormat, renderTarget, size.width, + static_cast(levels), false)); - error = updateStorage(); + ANGLE_TRY(setCompleteTexStorage(context, storage.get())); + storage.release(); - if (error.isError()) - { - return error; - } + ANGLE_TRY(updateStorage(context)); mImmutable = true; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } // Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81. @@ -1579,7 +2010,7 @@ bool TextureD3D_Cube::isCubeComplete() const for (int faceIndex = 1; faceIndex < 6; faceIndex++) { - const ImageD3D &faceBaseImage = *mImageArray[faceIndex][0]; + const ImageD3D &faceBaseImage = *mImageArray[faceIndex][getBaseLevel()]; if (faceBaseImage.getWidth() != baseWidth || faceBaseImage.getHeight() != baseHeight || @@ -1592,97 +2023,85 @@ bool TextureD3D_Cube::isCubeComplete() const return true; } -void TextureD3D_Cube::bindTexImage(egl::Surface *surface) +gl::Error TextureD3D_Cube::bindTexImage(const gl::Context *context, egl::Surface *surface) { UNREACHABLE(); + return gl::InternalError(); } -void TextureD3D_Cube::releaseTexImage() +gl::Error TextureD3D_Cube::releaseTexImage(const gl::Context *context) { UNREACHABLE(); + return gl::InternalError(); } - -void TextureD3D_Cube::initMipmapsImages() +gl::Error TextureD3D_Cube::initMipmapImages(const gl::Context *context) { - // Purge array levels 1 through q and reset them to represent the generated mipmap levels. - int levelCount = mipLevels(); + const GLuint baseLevel = mState.getEffectiveBaseLevel(); + const GLuint maxLevel = mState.getMipmapMaxLevel(); + // Purge array levels baseLevel + 1 through q and reset them to represent the generated mipmap + // levels. for (int faceIndex = 0; faceIndex < 6; faceIndex++) { - for (int level = 1; level < levelCount; level++) + for (GLuint level = baseLevel + 1; level <= maxLevel; level++) { - int faceLevelSize = (std::max(mImageArray[faceIndex][0]->getWidth() >> level, 1)); - redefineImage(faceIndex, level, mImageArray[faceIndex][0]->getInternalFormat(), - gl::Extents(faceLevelSize, faceLevelSize, 1)); + int faceLevelSize = + (std::max(mImageArray[faceIndex][baseLevel]->getWidth() >> (level - baseLevel), 1)); + ANGLE_TRY(redefineImage(context, faceIndex, level, + mImageArray[faceIndex][baseLevel]->getInternalFormat(), + gl::Extents(faceLevelSize, faceLevelSize, 1), false)); } } + return gl::NoError(); } -gl::Error TextureD3D_Cube::getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT) +gl::Error TextureD3D_Cube::getRenderTarget(const gl::Context *context, + 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; - } + ANGLE_TRY(ensureRenderTarget(context)); + ANGLE_TRY(updateStorageFaceLevel(context, index.layerIndex, index.mipIndex)); - return mTexStorage->getRenderTarget(index, outRT); + return mTexStorage->getRenderTarget(context, index, outRT); } -gl::Error TextureD3D_Cube::initializeStorage(bool renderTarget) +gl::Error TextureD3D_Cube::initializeStorage(const gl::Context *context, 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); + return gl::NoError(); } // do not attempt to create storage for nonexistant data - if (!isFaceLevelComplete(0, 0)) + if (!isFaceLevelComplete(0, getBaseLevel())) { - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } - bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage)); + bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mState.getUsage())); - TextureStorage *storage = NULL; - gl::Error error = createCompleteStorage(createRenderTarget, &storage); - if (error.isError()) - { - return error; - } + TexStoragePointer storage(context); + ANGLE_TRY(createCompleteStorage(createRenderTarget, &storage)); - error = setCompleteTexStorage(storage); - if (error.isError()) - { - SafeDelete(storage); - return error; - } + ANGLE_TRY(setCompleteTexStorage(context, storage.get())); + storage.release(); ASSERT(mTexStorage); // flush image data to the storage - error = updateStorage(); - if (error.isError()) - { - return error; - } + ANGLE_TRY(updateStorage(context)); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureD3D_Cube::createCompleteStorage(bool renderTarget, TextureStorage **outTexStorage) const +gl::Error TextureD3D_Cube::createCompleteStorage(bool renderTarget, + TexStoragePointer *outStorage) const { - GLsizei size = getBaseLevelWidth(); + GLsizei size = getLevelZeroWidth(); ASSERT(size > 0); @@ -1705,12 +2124,14 @@ gl::Error TextureD3D_Cube::createCompleteStorage(bool renderTarget, TextureStora } // TODO (geofflang): detect if storage creation succeeded - *outTexStorage = mRenderer->createTextureStorageCube(getBaseLevelInternalFormat(), renderTarget, size, levels, hintLevelZeroOnly); + outStorage->reset(mRenderer->createTextureStorageCube( + getBaseLevelInternalFormat(), renderTarget, size, levels, hintLevelZeroOnly)); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureD3D_Cube::setCompleteTexStorage(TextureStorage *newCompleteTexStorage) +gl::Error TextureD3D_Cube::setCompleteTexStorage(const gl::Context *context, + TextureStorage *newCompleteTexStorage) { if (newCompleteTexStorage && newCompleteTexStorage->isManaged()) { @@ -1718,25 +2139,27 @@ gl::Error TextureD3D_Cube::setCompleteTexStorage(TextureStorage *newCompleteTexS { for (int level = 0; level < newCompleteTexStorage->getLevelCount(); level++) { - gl::Error error = mImageArray[faceIndex][level]->setManagedSurfaceCube(newCompleteTexStorage, faceIndex, level); - if (error.isError()) - { - return error; - } + ANGLE_TRY(mImageArray[faceIndex][level]->setManagedSurfaceCube( + context, newCompleteTexStorage, faceIndex, level)); } } } - SafeDelete(mTexStorage); + ANGLE_TRY(releaseTexStorage(context)); mTexStorage = newCompleteTexStorage; mDirtyImages = true; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureD3D_Cube::updateStorage() +gl::Error TextureD3D_Cube::updateStorage(const gl::Context *context) { - ASSERT(mTexStorage != NULL); + if (!mDirtyImages) + { + return gl::NoError(); + } + + ASSERT(mTexStorage != nullptr); GLint storageLevels = mTexStorage->getLevelCount(); for (int face = 0; face < 6; face++) { @@ -1744,16 +2167,13 @@ gl::Error TextureD3D_Cube::updateStorage() { if (mImageArray[face][level]->isDirty() && isFaceLevelComplete(face, level)) { - gl::Error error = updateStorageFaceLevel(face, level); - if (error.isError()) - { - return error; - } + ANGLE_TRY(updateStorageFaceLevel(context, face, level)); } } } - return gl::Error(GL_NO_ERROR); + mDirtyImages = false; + return gl::NoError(); } bool TextureD3D_Cube::isValidFaceLevel(int faceIndex, int level) const @@ -1763,16 +2183,21 @@ bool TextureD3D_Cube::isValidFaceLevel(int faceIndex, int level) const bool TextureD3D_Cube::isFaceLevelComplete(int faceIndex, int level) const { - ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL); + if (getBaseLevel() >= gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) + { + return false; + } + ASSERT(level >= 0 && faceIndex < 6 && level < static_cast(mImageArray[faceIndex].size()) && + mImageArray[faceIndex][level] != nullptr); if (isImmutable()) { return true; } - int baseSize = getBaseLevelWidth(); + int levelZeroSize = getLevelZeroWidth(); - if (baseSize <= 0) + if (levelZeroSize <= 0) { return false; } @@ -1786,14 +2211,14 @@ bool TextureD3D_Cube::isFaceLevelComplete(int faceIndex, int level) const } // Check that non-zero levels are consistent with the base level. - const ImageD3D *faceLevelImage = mImageArray[faceIndex][level]; + const ImageD3D *faceLevelImage = mImageArray[faceIndex][level].get(); if (faceLevelImage->getInternalFormat() != getBaseLevelInternalFormat()) { return false; } - if (faceLevelImage->getWidth() != std::max(1, baseSize >> level)) + if (faceLevelImage->getWidth() != std::max(1, levelZeroSize >> level)) { return false; } @@ -1806,57 +2231,55 @@ bool TextureD3D_Cube::isImageComplete(const gl::ImageIndex &index) const return isFaceLevelComplete(index.layerIndex, index.mipIndex); } -gl::Error TextureD3D_Cube::updateStorageFaceLevel(int faceIndex, int level) +gl::Error TextureD3D_Cube::updateStorageFaceLevel(const gl::Context *context, + int faceIndex, + int level) { - ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL); - ImageD3D *image = mImageArray[faceIndex][level]; + ASSERT(level >= 0 && faceIndex < 6 && level < static_cast(mImageArray[faceIndex].size()) && + mImageArray[faceIndex][level] != nullptr); + ImageD3D *image = mImageArray[faceIndex][level].get(); 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; - } + ANGLE_TRY(commitRegion(context, index, region)); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -void TextureD3D_Cube::redefineImage(int faceIndex, GLint level, GLenum internalformat, const gl::Extents &size) +gl::Error TextureD3D_Cube::redefineImage(const gl::Context *context, + int faceIndex, + GLint level, + GLenum internalformat, + const gl::Extents &size, + bool forceRelease) { // 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 storageWidth = std::max(1, getLevelZeroWidth() >> level); + const int storageHeight = std::max(1, getLevelZeroHeight() >> level); const GLenum storageFormat = getBaseLevelInternalFormat(); - mImageArray[faceIndex][level]->redefine(GL_TEXTURE_CUBE_MAP, internalformat, size, false); + mImageArray[faceIndex][level]->redefine(GL_TEXTURE_CUBE_MAP, internalformat, size, + forceRelease); + mDirtyImages = mDirtyImages || mImageArray[faceIndex][level]->isDirty(); if (mTexStorage) { const int storageLevels = mTexStorage->getLevelCount(); - if ((level >= storageLevels && storageLevels != 0) || - size.width != storageWidth || + if ((level >= storageLevels && storageLevels != 0) || size.width != storageWidth || size.height != storageHeight || - internalformat != storageFormat) // Discard mismatched storage + 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; + markAllImagesDirty(); + ANGLE_TRY(releaseTexStorage(context)); } } + + return gl::NoError(); } gl::ImageIndexIterator TextureD3D_Cube::imageIterator() const @@ -1876,33 +2299,48 @@ bool TextureD3D_Cube::isValidIndex(const gl::ImageIndex &index) const index.mipIndex >= 0 && index.mipIndex < mTexStorage->getLevelCount()); } -TextureD3D_3D::TextureD3D_3D(RendererD3D *renderer) - : TextureD3D(renderer) +void TextureD3D_Cube::markAllImagesDirty() { - for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i) + for (int dirtyLevel = 0; dirtyLevel < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; dirtyLevel++) { - mImageArray[i] = renderer->createImage(); + for (int dirtyFace = 0; dirtyFace < 6; dirtyFace++) + { + mImageArray[dirtyFace][dirtyLevel]->markDirty(); + } } + mDirtyImages = true; } -TextureD3D_3D::~TextureD3D_3D() +TextureD3D_3D::TextureD3D_3D(const gl::TextureState &state, RendererD3D *renderer) + : TextureD3D(state, renderer) { - // 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]; + mImageArray[i].reset(renderer->createImage()); } +} - SafeDelete(mTexStorage); +gl::Error TextureD3D_3D::onDestroy(const gl::Context *context) +{ + // 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 (auto &image : mImageArray) + { + image.reset(); + } + return TextureD3D::onDestroy(context); +} + +TextureD3D_3D::~TextureD3D_3D() +{ } ImageD3D *TextureD3D_3D::getImage(int level, int layer) const { ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); ASSERT(layer == 0); - return mImageArray[level]; + return mImageArray[level].get(); } ImageD3D *TextureD3D_3D::getImage(const gl::ImageIndex &index) const @@ -1910,7 +2348,7 @@ 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]; + return mImageArray[index.mipIndex].get(); } GLsizei TextureD3D_3D::getLayerCount(int level) const @@ -1953,16 +2391,19 @@ GLenum TextureD3D_3D::getInternalFormat(GLint level) const bool TextureD3D_3D::isDepth(GLint level) const { - return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0; + return gl::GetSizedInternalFormatInfo(getInternalFormat(level)).depthBits > 0; } -gl::Error TextureD3D_3D::setEGLImageTarget(GLenum target, egl::Image *image) +gl::Error TextureD3D_3D::setEGLImageTarget(const gl::Context *context, + GLenum target, + egl::Image *image) { UNREACHABLE(); - return gl::Error(GL_INVALID_OPERATION); + return gl::InternalError(); } -gl::Error TextureD3D_3D::setImage(GLenum target, +gl::Error TextureD3D_3D::setImage(const gl::Context *context, + GLenum target, size_t imageLevel, GLenum internalFormat, const gl::Extents &size, @@ -1972,33 +2413,29 @@ gl::Error TextureD3D_3D::setImage(GLenum target, const uint8_t *pixels) { ASSERT(target == GL_TEXTURE_3D); - GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type); + const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(internalFormat, type); GLint level = static_cast(imageLevel); - redefineImage(level, sizedInternalFormat, size); + ANGLE_TRY(redefineImage(context, level, internalFormatInfo.sizedInternalFormat, size, false)); 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()) + gl::Buffer *unpackBuffer = + context->getGLState().getTargetBuffer(gl::BufferBinding::PixelUnpack); + if (isFastUnpackable(unpackBuffer, internalFormatInfo.sizedInternalFormat) && !size.empty() && + 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; - } + RenderTargetD3D *destRenderTarget = nullptr; + ANGLE_TRY(getRenderTarget(context, index, &destRenderTarget)); 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; - } + ANGLE_TRY(fastUnpackPixels(context, unpack, pixels, destArea, + internalFormatInfo.sizedInternalFormat, type, destRenderTarget)); // Ensure we don't overwrite our newly initialized data mImageArray[level]->markClean(); @@ -2008,17 +2445,14 @@ gl::Error TextureD3D_3D::setImage(GLenum target, if (!fastUnpacked) { - gl::Error error = setImageImpl(index, type, unpack, pixels, 0); - if (error.isError()) - { - return error; - } + ANGLE_TRY(setImageImpl(context, index, type, unpack, pixels, 0)); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureD3D_3D::setSubImage(GLenum target, +gl::Error TextureD3D_3D::setSubImage(const gl::Context *context, + GLenum target, size_t imageLevel, const gl::Box &area, GLenum format, @@ -2032,26 +2466,25 @@ gl::Error TextureD3D_3D::setSubImage(GLenum target, 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))) + gl::Buffer *unpackBuffer = + context->getGLState().getTargetBuffer(gl::BufferBinding::PixelUnpack); + if (isFastUnpackable(unpackBuffer, getInternalFormat(level)) && isLevelComplete(level)) { - RenderTargetD3D *destRenderTarget = NULL; - gl::Error error = getRenderTarget(index, &destRenderTarget); - if (error.isError()) - { - return error; - } - + RenderTargetD3D *destRenderTarget = nullptr; + ANGLE_TRY(getRenderTarget(context, index, &destRenderTarget)); ASSERT(!mImageArray[level]->isDirty()); - return fastUnpackPixels(unpack, pixels, area, getInternalFormat(level), type, destRenderTarget); + return fastUnpackPixels(context, unpack, pixels, area, getInternalFormat(level), type, + destRenderTarget); } else { - return TextureD3D::subImage(index, area, format, type, unpack, pixels, 0); + return TextureD3D::subImage(context, index, area, format, type, unpack, pixels, 0); } } -gl::Error TextureD3D_3D::setCompressedImage(GLenum target, +gl::Error TextureD3D_3D::setCompressedImage(const gl::Context *context, + GLenum target, size_t imageLevel, GLenum internalFormat, const gl::Extents &size, @@ -2063,35 +2496,41 @@ gl::Error TextureD3D_3D::setCompressedImage(GLenum target, GLint level = static_cast(imageLevel); // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly - redefineImage(level, internalFormat, size); + ANGLE_TRY(redefineImage(context, level, internalFormat, size, false)); gl::ImageIndex index = gl::ImageIndex::Make3D(level); - return setCompressedImageImpl(index, unpack, pixels, 0); + return setCompressedImageImpl(context, index, unpack, pixels, 0); } -gl::Error TextureD3D_3D::setCompressedSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format, - const gl::PixelUnpackState &unpack, size_t imageSize, const uint8_t *pixels) +gl::Error TextureD3D_3D::setCompressedSubImage(const gl::Context *context, + GLenum target, + size_t level, + const gl::Box &area, + GLenum format, + const gl::PixelUnpackState &unpack, + size_t imageSize, + const uint8_t *pixels) { ASSERT(target == GL_TEXTURE_3D); gl::ImageIndex index = gl::ImageIndex::Make3D(static_cast(level)); - gl::Error error = TextureD3D::subImageCompressed(index, area, format, unpack, pixels, 0); - if (error.isError()) - { - return error; - } - - return commitRegion(index, area); + ANGLE_TRY(TextureD3D::subImageCompressed(context, index, area, format, unpack, pixels, 0)); + return commitRegion(context, index, area); } -gl::Error TextureD3D_3D::copyImage(GLenum target, size_t level, const gl::Rectangle &sourceArea, GLenum internalFormat, +gl::Error TextureD3D_3D::copyImage(const gl::Context *context, + 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."); + return gl::InternalError() << "Copying 3D textures is unimplemented."; } -gl::Error TextureD3D_3D::copySubImage(GLenum target, +gl::Error TextureD3D_3D::copySubImage(const gl::Context *context, + GLenum target, size_t imageLevel, const gl::Offset &destOffset, const gl::Rectangle &sourceArea, @@ -2099,49 +2538,47 @@ gl::Error TextureD3D_3D::copySubImage(GLenum target, { ASSERT(target == GL_TEXTURE_3D); - GLint level = static_cast(imageLevel); - gl::ImageIndex index = gl::ImageIndex::Make3D(level); + GLint level = static_cast(imageLevel); - if (canCreateRenderTargetForImage(index)) + gl::Extents fbSize = source->getReadColorbuffer()->getSize(); + gl::Rectangle clippedSourceArea; + if (!ClipRectangle(sourceArea, gl::Rectangle(0, 0, fbSize.width, fbSize.height), + &clippedSourceArea)) { - gl::Error error = mImageArray[level]->copyFromFramebuffer(destOffset, sourceArea, source); - if (error.isError()) - { - return error; - } + return gl::NoError(); + } + const gl::Offset clippedDestOffset(destOffset.x + clippedSourceArea.x - sourceArea.x, + destOffset.y + clippedSourceArea.y - sourceArea.y, + destOffset.z); - mDirtyImages = true; + // Currently, copying directly to the storage is not possible because it's not possible to + // create an SRV from a single layer of a 3D texture. Instead, make sure the image is up to + // date before the copy and then copy back to the storage afterwards if needed. + // TODO: Investigate 3D blits in D3D11. + + bool syncTexStorage = mTexStorage && isLevelComplete(level); + if (syncTexStorage) + { + gl::ImageIndex index = gl::ImageIndex::Make3D(level); + ANGLE_TRY(mImageArray[level]->copyFromTexStorage(context, index, mTexStorage)); } - else + ANGLE_TRY(mImageArray[level]->copyFromFramebuffer(context, clippedDestOffset, clippedSourceArea, + source)); + mDirtyImages = true; + + if (syncTexStorage) { - 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; - } - } + ANGLE_TRY(updateStorageLevel(context, level)); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureD3D_3D::setStorage(GLenum target, size_t levels, GLenum internalFormat, const gl::Extents &size) +gl::Error TextureD3D_3D::setStorage(const gl::Context *context, + GLenum target, + size_t levels, + GLenum internalFormat, + const gl::Extents &size) { ASSERT(target == GL_TEXTURE_3D); @@ -2159,130 +2596,106 @@ gl::Error TextureD3D_3D::setStorage(GLenum target, size_t levels, GLenum interna } // TODO(geofflang): Verify storage creation had no errors - bool renderTarget = IsRenderTargetUsage(mUsage); - TextureStorage *storage = - mRenderer->createTextureStorage3D(internalFormat, renderTarget, size.width, size.height, - size.depth, static_cast(levels)); + bool renderTarget = IsRenderTargetUsage(mState.getUsage()); + TexStoragePointer storage(context); + storage.reset(mRenderer->createTextureStorage3D(internalFormat, renderTarget, size.width, + size.height, size.depth, + static_cast(levels))); - gl::Error error = setCompleteTexStorage(storage); - if (error.isError()) - { - SafeDelete(storage); - return error; - } + ANGLE_TRY(setCompleteTexStorage(context, storage.get())); + storage.release(); - error = updateStorage(); - - if (error.isError()) - { - return error; - } + ANGLE_TRY(updateStorage(context)); mImmutable = true; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -void TextureD3D_3D::bindTexImage(egl::Surface *surface) +gl::Error TextureD3D_3D::bindTexImage(const gl::Context *context, egl::Surface *surface) { UNREACHABLE(); + return gl::InternalError(); } -void TextureD3D_3D::releaseTexImage() +gl::Error TextureD3D_3D::releaseTexImage(const gl::Context *context) { UNREACHABLE(); + return gl::InternalError(); } - -void TextureD3D_3D::initMipmapsImages() +gl::Error TextureD3D_3D::initMipmapImages(const gl::Context *context) { - // 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++) + const GLuint baseLevel = mState.getEffectiveBaseLevel(); + const GLuint maxLevel = mState.getMipmapMaxLevel(); + // Purge array levels baseLevel + 1 through q and reset them to represent the generated mipmap + // levels. + for (GLuint level = baseLevel + 1; level <= maxLevel; level++) { - gl::Extents levelSize(std::max(getBaseLevelWidth() >> level, 1), - std::max(getBaseLevelHeight() >> level, 1), - std::max(getBaseLevelDepth() >> level, 1)); - redefineImage(level, getBaseLevelInternalFormat(), levelSize); + gl::Extents levelSize(std::max(getLevelZeroWidth() >> level, 1), + std::max(getLevelZeroHeight() >> level, 1), + std::max(getLevelZeroDepth() >> level, 1)); + ANGLE_TRY(redefineImage(context, level, getBaseLevelInternalFormat(), levelSize, false)); } + + return gl::NoError(); } -gl::Error TextureD3D_3D::getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT) +gl::Error TextureD3D_3D::getRenderTarget(const gl::Context *context, + const gl::ImageIndex &index, + RenderTargetD3D **outRT) { // ensure the underlying texture is created - gl::Error error = ensureRenderTarget(); - if (error.isError()) - { - return error; - } + ANGLE_TRY(ensureRenderTarget(context)); if (index.hasLayer()) { - error = updateStorage(); - if (error.isError()) - { - return error; - } + ANGLE_TRY(updateStorage(context)); } else { - error = updateStorageLevel(index.mipIndex); - if (error.isError()) - { - return error; - } + ANGLE_TRY(updateStorageLevel(context, index.mipIndex)); } - return mTexStorage->getRenderTarget(index, outRT); + return mTexStorage->getRenderTarget(context, index, outRT); } -gl::Error TextureD3D_3D::initializeStorage(bool renderTarget) +gl::Error TextureD3D_3D::initializeStorage(const gl::Context *context, 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); + return gl::NoError(); } // do not attempt to create storage for nonexistant data - if (!isLevelComplete(0)) + if (!isLevelComplete(getBaseLevel())) { - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } - bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage)); + bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mState.getUsage())); - TextureStorage *storage = NULL; - gl::Error error = createCompleteStorage(createRenderTarget, &storage); - if (error.isError()) - { - return error; - } + TexStoragePointer storage(context); + ANGLE_TRY(createCompleteStorage(createRenderTarget, &storage)); - error = setCompleteTexStorage(storage); - if (error.isError()) - { - SafeDelete(storage); - return error; - } + ANGLE_TRY(setCompleteTexStorage(context, storage.get())); + storage.release(); ASSERT(mTexStorage); // flush image data to the storage - error = updateStorage(); - if (error.isError()) - { - return error; - } + ANGLE_TRY(updateStorage(context)); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureD3D_3D::createCompleteStorage(bool renderTarget, TextureStorage **outStorage) const +gl::Error TextureD3D_3D::createCompleteStorage(bool renderTarget, + TexStoragePointer *outStorage) const { - GLsizei width = getBaseLevelWidth(); - GLsizei height = getBaseLevelHeight(); - GLsizei depth = getBaseLevelDepth(); + GLsizei width = getLevelZeroWidth(); + GLsizei height = getLevelZeroHeight(); + GLsizei depth = getLevelZeroDepth(); GLenum internalFormat = getBaseLevelInternalFormat(); ASSERT(width > 0 && height > 0 && depth > 0); @@ -2291,40 +2704,44 @@ gl::Error TextureD3D_3D::createCompleteStorage(bool renderTarget, TextureStorage 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); + outStorage->reset(mRenderer->createTextureStorage3D(internalFormat, renderTarget, width, height, + depth, levels)); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureD3D_3D::setCompleteTexStorage(TextureStorage *newCompleteTexStorage) +gl::Error TextureD3D_3D::setCompleteTexStorage(const gl::Context *context, + TextureStorage *newCompleteTexStorage) { - SafeDelete(mTexStorage); + ANGLE_TRY(releaseTexStorage(context)); 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); + return gl::NoError(); } -gl::Error TextureD3D_3D::updateStorage() +gl::Error TextureD3D_3D::updateStorage(const gl::Context *context) { - ASSERT(mTexStorage != NULL); + if (!mDirtyImages) + { + return gl::NoError(); + } + + ASSERT(mTexStorage != nullptr); 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; - } + ANGLE_TRY(updateStorageLevel(context, level)); } } - return gl::Error(GL_NO_ERROR); + mDirtyImages = false; + return gl::NoError(); } bool TextureD3D_3D::isValidLevel(int level) const @@ -2334,28 +2751,29 @@ bool TextureD3D_3D::isValidLevel(int level) const bool TextureD3D_3D::isLevelComplete(int level) const { - ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL); + ASSERT(level >= 0 && level < static_cast(mImageArray.size()) && + mImageArray[level] != nullptr); if (isImmutable()) { return true; } - GLsizei width = getBaseLevelWidth(); - GLsizei height = getBaseLevelHeight(); - GLsizei depth = getBaseLevelDepth(); + GLsizei width = getLevelZeroWidth(); + GLsizei height = getLevelZeroHeight(); + GLsizei depth = getLevelZeroDepth(); if (width <= 0 || height <= 0 || depth <= 0) { return false; } - if (level == 0) + if (level == static_cast(getBaseLevel())) { return true; } - ImageD3D *levelImage = mImageArray[level]; + ImageD3D *levelImage = mImageArray[level].get(); if (levelImage->getInternalFormat() != getBaseLevelInternalFormat()) { @@ -2385,54 +2803,51 @@ bool TextureD3D_3D::isImageComplete(const gl::ImageIndex &index) const return isLevelComplete(index.mipIndex); } -gl::Error TextureD3D_3D::updateStorageLevel(int level) +gl::Error TextureD3D_3D::updateStorageLevel(const gl::Context *context, int level) { - ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL); + ASSERT(level >= 0 && level < static_cast(mImageArray.size()) && + mImageArray[level] != nullptr); 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; - } + ANGLE_TRY(commitRegion(context, index, region)); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -void TextureD3D_3D::redefineImage(GLint level, GLenum internalformat, const gl::Extents &size) +gl::Error TextureD3D_3D::redefineImage(const gl::Context *context, + GLint level, + GLenum internalformat, + const gl::Extents &size, + bool forceRelease) { // 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 int storageWidth = std::max(1, getLevelZeroWidth() >> level); + const int storageHeight = std::max(1, getLevelZeroHeight() >> level); + const int storageDepth = std::max(1, getLevelZeroDepth() >> level); const GLenum storageFormat = getBaseLevelInternalFormat(); - mImageArray[level]->redefine(GL_TEXTURE_3D, internalformat, size, false); + mImageArray[level]->redefine(GL_TEXTURE_3D, internalformat, size, forceRelease); + mDirtyImages = mDirtyImages || mImageArray[level]->isDirty(); 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 + 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; + markAllImagesDirty(); + ANGLE_TRY(releaseTexStorage(context)); } } + + return gl::NoError(); } gl::ImageIndexIterator TextureD3D_3D::imageIterator() const @@ -2453,23 +2868,42 @@ bool TextureD3D_3D::isValidIndex(const gl::ImageIndex &index) const index.mipIndex >= 0 && index.mipIndex < mTexStorage->getLevelCount()); } -TextureD3D_2DArray::TextureD3D_2DArray(RendererD3D *renderer) - : TextureD3D(renderer) +void TextureD3D_3D::markAllImagesDirty() +{ + for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) + { + mImageArray[i]->markDirty(); + } + mDirtyImages = true; +} + +GLint TextureD3D_3D::getLevelZeroDepth() const +{ + ASSERT(gl::CountLeadingZeros(static_cast(getBaseLevelDepth())) > getBaseLevel()); + return getBaseLevelDepth() << getBaseLevel(); +} + +TextureD3D_2DArray::TextureD3D_2DArray(const gl::TextureState &state, RendererD3D *renderer) + : TextureD3D(state, renderer) { for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level) { mLayerCounts[level] = 0; - mImageArray[level] = NULL; + mImageArray[level] = nullptr; } } -TextureD3D_2DArray::~TextureD3D_2DArray() +gl::Error TextureD3D_2DArray::onDestroy(const gl::Context *context) { - // 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. + // 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); + return TextureD3D::onDestroy(context); +} + +TextureD3D_2DArray::~TextureD3D_2DArray() +{ } ImageD3D *TextureD3D_2DArray::getImage(int level, int layer) const @@ -2477,16 +2911,17 @@ 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); + return (mImageArray[level] ? mImageArray[level][layer] : nullptr); } ImageD3D *TextureD3D_2DArray::getImage(const gl::ImageIndex &index) const { ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); + ASSERT(index.layerIndex != gl::ImageIndex::ENTIRE_LEVEL); 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); + return (mImageArray[index.mipIndex] ? mImageArray[index.mipIndex][index.layerIndex] : nullptr); } GLsizei TextureD3D_2DArray::getLayerCount(int level) const @@ -2512,16 +2947,19 @@ GLenum TextureD3D_2DArray::getInternalFormat(GLint level) const bool TextureD3D_2DArray::isDepth(GLint level) const { - return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0; + return gl::GetSizedInternalFormatInfo(getInternalFormat(level)).depthBits > 0; } -gl::Error TextureD3D_2DArray::setEGLImageTarget(GLenum target, egl::Image *image) +gl::Error TextureD3D_2DArray::setEGLImageTarget(const gl::Context *context, + GLenum target, + egl::Image *image) { UNREACHABLE(); - return gl::Error(GL_INVALID_OPERATION); + return gl::InternalError(); } -gl::Error TextureD3D_2DArray::setImage(GLenum target, +gl::Error TextureD3D_2DArray::setImage(const gl::Context *context, + GLenum target, size_t imageLevel, GLenum internalFormat, const gl::Extents &size, @@ -2532,30 +2970,28 @@ gl::Error TextureD3D_2DArray::setImage(GLenum target, { ASSERT(target == GL_TEXTURE_2D_ARRAY); - GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type); + const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat, type); GLint level = static_cast(imageLevel); - redefineImage(level, sizedInternalFormat, size); + ANGLE_TRY(redefineImage(context, level, formatInfo.sizedInternalFormat, size, false)); - const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(sizedInternalFormat); - GLsizei inputDepthPitch = formatInfo.computeDepthPitch( - type, size.width, size.height, unpack.alignment, unpack.rowLength, unpack.imageHeight); + GLsizei inputDepthPitch = 0; + ANGLE_TRY_RESULT(formatInfo.computeDepthPitch(type, size.width, size.height, unpack.alignment, + unpack.rowLength, unpack.imageHeight), + inputDepthPitch); 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 = setImageImpl(index, type, unpack, pixels, layerOffset); - if (error.isError()) - { - return error; - } + ANGLE_TRY(setImageImpl(context, index, type, unpack, pixels, layerOffset)); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureD3D_2DArray::setSubImage(GLenum target, +gl::Error TextureD3D_2DArray::setSubImage(const gl::Context *context, + GLenum target, size_t imageLevel, const gl::Box &area, GLenum format, @@ -2565,9 +3001,12 @@ gl::Error TextureD3D_2DArray::setSubImage(GLenum target, { ASSERT(target == GL_TEXTURE_2D_ARRAY); GLint level = static_cast(imageLevel); - const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(getInternalFormat(level)); - GLsizei inputDepthPitch = formatInfo.computeDepthPitch( - type, area.width, area.height, unpack.alignment, unpack.rowLength, unpack.imageHeight); + const gl::InternalFormat &formatInfo = + gl::GetInternalFormatInfo(getInternalFormat(level), type); + GLsizei inputDepthPitch = 0; + ANGLE_TRY_RESULT(formatInfo.computeDepthPitch(type, area.width, area.height, unpack.alignment, + unpack.rowLength, unpack.imageHeight), + inputDepthPitch); for (int i = 0; i < area.depth; i++) { @@ -2577,17 +3016,15 @@ gl::Error TextureD3D_2DArray::setSubImage(GLenum target, 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; - } + ANGLE_TRY(TextureD3D::subImage(context, index, layerArea, format, type, unpack, pixels, + layerOffset)); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureD3D_2DArray::setCompressedImage(GLenum target, +gl::Error TextureD3D_2DArray::setCompressedImage(const gl::Context *context, + GLenum target, size_t imageLevel, GLenum internalFormat, const gl::Extents &size, @@ -2599,35 +3036,41 @@ gl::Error TextureD3D_2DArray::setCompressedImage(GLenum target, GLint level = static_cast(imageLevel); // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly - redefineImage(level, internalFormat, size); + ANGLE_TRY(redefineImage(context, level, internalFormat, size, false)); - const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat); - GLsizei inputDepthPitch = - formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, size.width, size.height, 1, 0, 0); + const gl::InternalFormat &formatInfo = gl::GetSizedInternalFormatInfo(internalFormat); + GLsizei inputDepthPitch = 0; + ANGLE_TRY_RESULT( + formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, size.width, size.height, 1, 0, 0), + inputDepthPitch); 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 = setCompressedImageImpl(index, unpack, pixels, layerOffset); - if (error.isError()) - { - return error; - } + ANGLE_TRY(setCompressedImageImpl(context, index, unpack, pixels, layerOffset)); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureD3D_2DArray::setCompressedSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format, - const gl::PixelUnpackState &unpack, size_t imageSize, const uint8_t *pixels) +gl::Error TextureD3D_2DArray::setCompressedSubImage(const gl::Context *context, + GLenum target, + size_t level, + const gl::Box &area, + GLenum format, + const gl::PixelUnpackState &unpack, + size_t imageSize, + 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, 0); + const gl::InternalFormat &formatInfo = gl::GetSizedInternalFormatInfo(format); + GLsizei inputDepthPitch = 0; + ANGLE_TRY_RESULT( + formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, area.width, area.height, 1, 0, 0), + inputDepthPitch); for (int i = 0; i < area.depth; i++) { @@ -2637,30 +3080,27 @@ gl::Error TextureD3D_2DArray::setCompressedSubImage(GLenum target, size_t level, gl::Box layerArea(area.x, area.y, 0, area.width, area.height, 1); gl::ImageIndex index = gl::ImageIndex::Make2DArray(static_cast(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; - } + ANGLE_TRY(TextureD3D::subImageCompressed(context, index, layerArea, format, unpack, pixels, + layerOffset)); + ANGLE_TRY(commitRegion(context, index, layerArea)); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureD3D_2DArray::copyImage(GLenum target, size_t level, const gl::Rectangle &sourceArea, GLenum internalFormat, +gl::Error TextureD3D_2DArray::copyImage(const gl::Context *context, + 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."); + return gl::InternalError() << "Copying 2D array textures is unimplemented."; } -gl::Error TextureD3D_2DArray::copySubImage(GLenum target, +gl::Error TextureD3D_2DArray::copySubImage(const gl::Context *context, + GLenum target, size_t imageLevel, const gl::Offset &destOffset, const gl::Rectangle &sourceArea, @@ -2671,46 +3111,45 @@ gl::Error TextureD3D_2DArray::copySubImage(GLenum target, GLint level = static_cast(imageLevel); gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, destOffset.z); - if (canCreateRenderTargetForImage(index)) + gl::Extents fbSize = source->getReadColorbuffer()->getSize(); + gl::Rectangle clippedSourceArea; + if (!ClipRectangle(sourceArea, gl::Rectangle(0, 0, fbSize.width, fbSize.height), + &clippedSourceArea)) { - gl::Offset destLayerOffset(destOffset.x, destOffset.y, 0); - gl::Error error = mImageArray[level][destOffset.z]->copyFromFramebuffer(destLayerOffset, - sourceArea, source); - if (error.isError()) - { - return error; - } + return gl::NoError(); + } + const gl::Offset clippedDestOffset(destOffset.x + clippedSourceArea.x - sourceArea.x, + destOffset.y + clippedSourceArea.y - sourceArea.y, + destOffset.z); + if (!canCreateRenderTargetForImage(index)) + { + gl::Offset destLayerOffset(clippedDestOffset.x, clippedDestOffset.y, 0); + ANGLE_TRY(mImageArray[level][clippedDestOffset.z]->copyFromFramebuffer( + context, destLayerOffset, clippedSourceArea, source)); mDirtyImages = true; } else { - gl::Error error = ensureRenderTarget(); - if (error.isError()) - { - return error; - } + ANGLE_TRY(ensureRenderTarget(context)); 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; - } + ANGLE_TRY(updateStorageLevel(context, level)); + ANGLE_TRY( + mRenderer->copyImage2DArray(context, source, clippedSourceArea, + gl::GetUnsizedFormat(getInternalFormat(getBaseLevel())), + clippedDestOffset, mTexStorage, level)); } } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureD3D_2DArray::setStorage(GLenum target, size_t levels, GLenum internalFormat, const gl::Extents &size) +gl::Error TextureD3D_2DArray::setStorage(const gl::Context *context, + GLenum target, + size_t levels, + GLenum internalFormat, + const gl::Extents &size) { ASSERT(target == GL_TEXTURE_2D_ARRAY); @@ -2738,124 +3177,103 @@ gl::Error TextureD3D_2DArray::setStorage(GLenum target, size_t levels, GLenum in } // TODO(geofflang): Verify storage creation had no errors - bool renderTarget = IsRenderTargetUsage(mUsage); - TextureStorage *storage = - mRenderer->createTextureStorage2DArray(internalFormat, renderTarget, size.width, - size.height, size.depth, static_cast(levels)); + bool renderTarget = IsRenderTargetUsage(mState.getUsage()); + TexStoragePointer storage(context); + storage.reset(mRenderer->createTextureStorage2DArray(internalFormat, renderTarget, size.width, + size.height, size.depth, + static_cast(levels))); - gl::Error error = setCompleteTexStorage(storage); - if (error.isError()) - { - SafeDelete(storage); - return error; - } + ANGLE_TRY(setCompleteTexStorage(context, storage.get())); + storage.release(); - error = updateStorage(); - - if (error.isError()) - { - return error; - } + ANGLE_TRY(updateStorage(context)); mImmutable = true; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -void TextureD3D_2DArray::bindTexImage(egl::Surface *surface) +gl::Error TextureD3D_2DArray::bindTexImage(const gl::Context *context, egl::Surface *surface) { UNREACHABLE(); + return gl::InternalError(); } -void TextureD3D_2DArray::releaseTexImage() +gl::Error TextureD3D_2DArray::releaseTexImage(const gl::Context *context) { UNREACHABLE(); + return gl::InternalError(); } - -void TextureD3D_2DArray::initMipmapsImages() +gl::Error TextureD3D_2DArray::initMipmapImages(const gl::Context *context) { - int baseWidth = getBaseLevelWidth(); - int baseHeight = getBaseLevelHeight(); - int baseDepth = getLayerCount(0); + const GLuint baseLevel = mState.getEffectiveBaseLevel(); + const GLuint maxLevel = mState.getMipmapMaxLevel(); + int baseWidth = getLevelZeroWidth(); + int baseHeight = getLevelZeroHeight(); + int baseDepth = getLayerCount(getBaseLevel()); 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++) + // Purge array levels baseLevel + 1 through q and reset them to represent the generated mipmap + // levels. + for (GLuint level = baseLevel + 1u; level <= maxLevel; level++) { + ASSERT((baseWidth >> level) > 0 || (baseHeight >> level) > 0); gl::Extents levelLayerSize(std::max(baseWidth >> level, 1), std::max(baseHeight >> level, 1), baseDepth); - redefineImage(level, baseFormat, levelLayerSize); + ANGLE_TRY(redefineImage(context, level, baseFormat, levelLayerSize, false)); } + + return gl::NoError(); } -gl::Error TextureD3D_2DArray::getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT) +gl::Error TextureD3D_2DArray::getRenderTarget(const gl::Context *context, + 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); + ANGLE_TRY(ensureRenderTarget(context)); + ANGLE_TRY(updateStorageLevel(context, index.mipIndex)); + return mTexStorage->getRenderTarget(context, index, outRT); } -gl::Error TextureD3D_2DArray::initializeStorage(bool renderTarget) +gl::Error TextureD3D_2DArray::initializeStorage(const gl::Context *context, 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); + return gl::NoError(); } // do not attempt to create storage for nonexistant data - if (!isLevelComplete(0)) + if (!isLevelComplete(getBaseLevel())) { - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } - bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage)); + bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mState.getUsage())); - TextureStorage *storage = NULL; - gl::Error error = createCompleteStorage(createRenderTarget, &storage); - if (error.isError()) - { - return error; - } + TexStoragePointer storage(context); + ANGLE_TRY(createCompleteStorage(createRenderTarget, &storage)); - error = setCompleteTexStorage(storage); - if (error.isError()) - { - SafeDelete(storage); - return error; - } + ANGLE_TRY(setCompleteTexStorage(context, storage.get())); + storage.release(); ASSERT(mTexStorage); // flush image data to the storage - error = updateStorage(); - if (error.isError()) - { - return error; - } + ANGLE_TRY(updateStorage(context)); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureD3D_2DArray::createCompleteStorage(bool renderTarget, TextureStorage **outStorage) const +gl::Error TextureD3D_2DArray::createCompleteStorage(bool renderTarget, + TexStoragePointer *outStorage) const { - GLsizei width = getBaseLevelWidth(); - GLsizei height = getBaseLevelHeight(); - GLsizei depth = getLayerCount(0); + GLsizei width = getLevelZeroWidth(); + GLsizei height = getLevelZeroHeight(); + GLsizei depth = getLayerCount(getBaseLevel()); GLenum internalFormat = getBaseLevelInternalFormat(); ASSERT(width > 0 && height > 0 && depth > 0); @@ -2864,40 +3282,44 @@ gl::Error TextureD3D_2DArray::createCompleteStorage(bool renderTarget, TextureSt GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1)); // TODO(geofflang): Verify storage creation succeeds - *outStorage = mRenderer->createTextureStorage2DArray(internalFormat, renderTarget, width, height, depth, levels); + outStorage->reset(mRenderer->createTextureStorage2DArray(internalFormat, renderTarget, width, + height, depth, levels)); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureD3D_2DArray::setCompleteTexStorage(TextureStorage *newCompleteTexStorage) +gl::Error TextureD3D_2DArray::setCompleteTexStorage(const gl::Context *context, + TextureStorage *newCompleteTexStorage) { - SafeDelete(mTexStorage); + ANGLE_TRY(releaseTexStorage(context)); 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); + return gl::NoError(); } -gl::Error TextureD3D_2DArray::updateStorage() +gl::Error TextureD3D_2DArray::updateStorage(const gl::Context *context) { - ASSERT(mTexStorage != NULL); + if (!mDirtyImages) + { + return gl::NoError(); + } + + ASSERT(mTexStorage != nullptr); GLint storageLevels = mTexStorage->getLevelCount(); for (int level = 0; level < storageLevels; level++) { if (isLevelComplete(level)) { - gl::Error error = updateStorageLevel(level); - if (error.isError()) - { - return error; - } + ANGLE_TRY(updateStorageLevel(context, level)); } } - return gl::Error(GL_NO_ERROR); + mDirtyImages = false; + return gl::NoError(); } bool TextureD3D_2DArray::isValidLevel(int level) const @@ -2914,21 +3336,29 @@ bool TextureD3D_2DArray::isLevelComplete(int level) const return true; } - GLsizei width = getBaseLevelWidth(); - GLsizei height = getBaseLevelHeight(); - GLsizei layers = getLayerCount(0); + GLsizei width = getLevelZeroWidth(); + GLsizei height = getLevelZeroHeight(); - if (width <= 0 || height <= 0 || layers <= 0) + if (width <= 0 || height <= 0) { return false; } - if (level == 0) + // Layers check needs to happen after the above checks, otherwise out-of-range base level may be + // queried. + GLsizei layers = getLayerCount(getBaseLevel()); + + if (layers <= 0) + { + return false; + } + + if (level == static_cast(getBaseLevel())) { return true; } - if (getInternalFormat(level) != getInternalFormat(0)) + if (getInternalFormat(level) != getInternalFormat(getBaseLevel())) { return false; } @@ -2956,27 +3386,23 @@ bool TextureD3D_2DArray::isImageComplete(const gl::ImageIndex &index) const return isLevelComplete(index.mipIndex); } -gl::Error TextureD3D_2DArray::updateStorageLevel(int level) +gl::Error TextureD3D_2DArray::updateStorageLevel(const gl::Context *context, int level) { - ASSERT(level >= 0 && level < (int)ArraySize(mLayerCounts)); + ASSERT(level >= 0 && level < static_cast(ArraySize(mLayerCounts))); ASSERT(isLevelComplete(level)); for (int layer = 0; layer < mLayerCounts[level]; layer++) { - ASSERT(mImageArray[level] != NULL && mImageArray[level][layer] != NULL); + ASSERT(mImageArray[level] != nullptr && mImageArray[level][layer] != nullptr); 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; - } + ANGLE_TRY(commitRegion(context, index, region)); } } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } void TextureD3D_2DArray::deleteImages() @@ -2988,18 +3414,26 @@ void TextureD3D_2DArray::deleteImages() delete mImageArray[level][layer]; } delete[] mImageArray[level]; - mImageArray[level] = NULL; + mImageArray[level] = nullptr; mLayerCounts[level] = 0; } } -void TextureD3D_2DArray::redefineImage(GLint level, GLenum internalformat, const gl::Extents &size) +gl::Error TextureD3D_2DArray::redefineImage(const gl::Context *context, + GLint level, + GLenum internalformat, + const gl::Extents &size, + bool forceRelease) { // 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(); + const int storageWidth = std::max(1, getLevelZeroWidth() >> level); + const int storageHeight = std::max(1, getLevelZeroHeight() >> level); + const GLuint baseLevel = getBaseLevel(); + int storageDepth = 0; + if (baseLevel < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) + { + storageDepth = getLayerCount(baseLevel); + } // Only reallocate the layers if the size doesn't match if (size.depth != mLayerCounts[level]) @@ -3026,33 +3460,27 @@ void TextureD3D_2DArray::redefineImage(GLint level, GLenum internalformat, const for (int layer = 0; layer < mLayerCounts[level]; layer++) { mImageArray[level][layer]->redefine(GL_TEXTURE_2D_ARRAY, internalformat, - gl::Extents(size.width, size.height, 1), false); + gl::Extents(size.width, size.height, 1), + forceRelease); + mDirtyImages = mDirtyImages || mImageArray[level][layer]->isDirty(); } } if (mTexStorage) { + const GLenum storageFormat = getBaseLevelInternalFormat(); const int storageLevels = mTexStorage->getLevelCount(); - if ((level >= storageLevels && storageLevels != 0) || - size.width != storageWidth || - size.height != storageHeight || - size.depth != storageDepth || - internalformat != storageFormat) // Discard mismatched storage + 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; + markAllImagesDirty(); + ANGLE_TRY(releaseTexStorage(context)); } } + + return gl::NoError(); } gl::ImageIndexIterator TextureD3D_2DArray::imageIterator() const @@ -3083,4 +3511,464 @@ bool TextureD3D_2DArray::isValidIndex(const gl::ImageIndex &index) const return (!index.hasLayer() || (index.layerIndex >= 0 && index.layerIndex < mLayerCounts[index.mipIndex])); } +void TextureD3D_2DArray::markAllImagesDirty() +{ + for (int dirtyLevel = 0; dirtyLevel < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; dirtyLevel++) + { + for (int dirtyLayer = 0; dirtyLayer < mLayerCounts[dirtyLevel]; dirtyLayer++) + { + mImageArray[dirtyLevel][dirtyLayer]->markDirty(); + } + } + mDirtyImages = true; } + +TextureD3D_External::TextureD3D_External(const gl::TextureState &state, RendererD3D *renderer) + : TextureD3D(state, renderer) +{ +} + +TextureD3D_External::~TextureD3D_External() +{ +} + +ImageD3D *TextureD3D_External::getImage(const gl::ImageIndex &index) const +{ + UNREACHABLE(); + return nullptr; +} + +GLsizei TextureD3D_External::getLayerCount(int level) const +{ + return 1; +} + +gl::Error TextureD3D_External::setImage(const gl::Context *context, + GLenum target, + size_t imageLevel, + GLenum internalFormat, + const gl::Extents &size, + GLenum format, + GLenum type, + const gl::PixelUnpackState &unpack, + const uint8_t *pixels) +{ + // Image setting is not supported for external images + UNREACHABLE(); + return gl::InternalError(); +} + +gl::Error TextureD3D_External::setSubImage(const gl::Context *context, + GLenum target, + size_t imageLevel, + const gl::Box &area, + GLenum format, + GLenum type, + const gl::PixelUnpackState &unpack, + const uint8_t *pixels) +{ + UNREACHABLE(); + return gl::InternalError(); +} + +gl::Error TextureD3D_External::setCompressedImage(const gl::Context *context, + GLenum target, + size_t imageLevel, + GLenum internalFormat, + const gl::Extents &size, + const gl::PixelUnpackState &unpack, + size_t imageSize, + const uint8_t *pixels) +{ + UNREACHABLE(); + return gl::InternalError(); +} + +gl::Error TextureD3D_External::setCompressedSubImage(const gl::Context *context, + GLenum target, + size_t level, + const gl::Box &area, + GLenum format, + const gl::PixelUnpackState &unpack, + size_t imageSize, + const uint8_t *pixels) +{ + UNREACHABLE(); + return gl::InternalError(); +} + +gl::Error TextureD3D_External::copyImage(const gl::Context *context, + GLenum target, + size_t imageLevel, + const gl::Rectangle &sourceArea, + GLenum internalFormat, + const gl::Framebuffer *source) +{ + UNREACHABLE(); + return gl::InternalError(); +} + +gl::Error TextureD3D_External::copySubImage(const gl::Context *context, + GLenum target, + size_t imageLevel, + const gl::Offset &destOffset, + const gl::Rectangle &sourceArea, + const gl::Framebuffer *source) +{ + UNREACHABLE(); + return gl::InternalError(); +} + +gl::Error TextureD3D_External::setStorage(const gl::Context *context, + GLenum target, + size_t levels, + GLenum internalFormat, + const gl::Extents &size) +{ + UNREACHABLE(); + return gl::InternalError(); +} + +gl::Error TextureD3D_External::setImageExternal(const gl::Context *context, + GLenum target, + egl::Stream *stream, + const egl::Stream::GLTextureDescription &desc) +{ + ASSERT(target == GL_TEXTURE_EXTERNAL_OES); + + ANGLE_TRY(releaseTexStorage(context)); + + // If the stream is null, the external image is unbound and we release the storage + if (stream != nullptr) + { + mTexStorage = mRenderer->createTextureStorageExternal(stream, desc); + } + + return gl::NoError(); +} + +gl::Error TextureD3D_External::bindTexImage(const gl::Context *context, egl::Surface *surface) +{ + UNREACHABLE(); + return gl::InternalError(); +} + +gl::Error TextureD3D_External::releaseTexImage(const gl::Context *context) +{ + UNREACHABLE(); + return gl::InternalError(); +} + +gl::Error TextureD3D_External::setEGLImageTarget(const gl::Context *context, + GLenum target, + egl::Image *image) +{ + EGLImageD3D *eglImaged3d = GetImplAs(image); + + // Pass in the RenderTargetD3D here: createTextureStorage can't generate an error. + RenderTargetD3D *renderTargetD3D = nullptr; + ANGLE_TRY(eglImaged3d->getRenderTarget(context, &renderTargetD3D)); + + ANGLE_TRY(releaseTexStorage(context)); + mTexStorage = mRenderer->createTextureStorageEGLImage(eglImaged3d, renderTargetD3D); + + return gl::NoError(); +} + +gl::Error TextureD3D_External::initMipmapImages(const gl::Context *context) +{ + UNREACHABLE(); + return gl::InternalError(); +} + +gl::Error TextureD3D_External::getRenderTarget(const gl::Context *context, + const gl::ImageIndex &index, + RenderTargetD3D **outRT) +{ + UNREACHABLE(); + return gl::InternalError(); +} + +bool TextureD3D_External::isImageComplete(const gl::ImageIndex &index) const +{ + return (index.mipIndex == 0) ? (mTexStorage != nullptr) : false; +} + +gl::Error TextureD3D_External::initializeStorage(const gl::Context *context, bool renderTarget) +{ + // Texture storage is created when an external image is bound + ASSERT(mTexStorage); + return gl::NoError(); +} + +gl::Error TextureD3D_External::createCompleteStorage(bool renderTarget, + TexStoragePointer *outStorage) const +{ + UNREACHABLE(); + return gl::NoError(); +} + +gl::Error TextureD3D_External::setCompleteTexStorage(const gl::Context *context, + TextureStorage *newCompleteTexStorage) +{ + UNREACHABLE(); + return gl::NoError(); +} + +gl::Error TextureD3D_External::updateStorage(const gl::Context *context) +{ + // Texture storage does not need to be updated since it is already loaded with the latest + // external image + ASSERT(mTexStorage); + return gl::NoError(); +} + +gl::ImageIndexIterator TextureD3D_External::imageIterator() const +{ + return gl::ImageIndexIterator::Make2D(0, mTexStorage->getLevelCount()); +} + +gl::ImageIndex TextureD3D_External::getImageIndex(GLint mip, GLint /*layer*/) const +{ + // "layer" does not apply to 2D Textures. + return gl::ImageIndex::Make2D(mip); +} + +bool TextureD3D_External::isValidIndex(const gl::ImageIndex &index) const +{ + return (mTexStorage && index.type == GL_TEXTURE_EXTERNAL_OES && index.mipIndex == 0); +} + +void TextureD3D_External::markAllImagesDirty() +{ + UNREACHABLE(); +} + +TextureD3D_2DMultisample::TextureD3D_2DMultisample(const gl::TextureState &state, + RendererD3D *renderer) + : TextureD3D(state, renderer) +{ +} + +TextureD3D_2DMultisample::~TextureD3D_2DMultisample() +{ +} + +ImageD3D *TextureD3D_2DMultisample::getImage(const gl::ImageIndex &index) const +{ + return nullptr; +} + +gl::Error TextureD3D_2DMultisample::setImage(const gl::Context *context, + GLenum target, + size_t level, + GLenum internalFormat, + const gl::Extents &size, + GLenum format, + GLenum type, + const gl::PixelUnpackState &unpack, + const uint8_t *pixels) +{ + UNREACHABLE(); + return gl::InternalError(); +} + +gl::Error TextureD3D_2DMultisample::setSubImage(const gl::Context *context, + GLenum target, + size_t level, + const gl::Box &area, + GLenum format, + GLenum type, + const gl::PixelUnpackState &unpack, + const uint8_t *pixels) +{ + UNREACHABLE(); + return gl::InternalError(); +} + +gl::Error TextureD3D_2DMultisample::setCompressedImage(const gl::Context *context, + GLenum target, + size_t level, + GLenum internalFormat, + const gl::Extents &size, + const gl::PixelUnpackState &unpack, + size_t imageSize, + const uint8_t *pixels) +{ + UNREACHABLE(); + return gl::InternalError(); +} + +gl::Error TextureD3D_2DMultisample::setCompressedSubImage(const gl::Context *context, + GLenum target, + size_t level, + const gl::Box &area, + GLenum format, + const gl::PixelUnpackState &unpack, + size_t imageSize, + const uint8_t *pixels) +{ + UNREACHABLE(); + return gl::InternalError(); +} + +gl::Error TextureD3D_2DMultisample::copyImage(const gl::Context *context, + GLenum target, + size_t level, + const gl::Rectangle &sourceArea, + GLenum internalFormat, + const gl::Framebuffer *source) +{ + UNREACHABLE(); + return gl::InternalError(); +} + +gl::Error TextureD3D_2DMultisample::copySubImage(const gl::Context *context, + GLenum target, + size_t level, + const gl::Offset &destOffset, + const gl::Rectangle &sourceArea, + const gl::Framebuffer *source) +{ + UNREACHABLE(); + return gl::InternalError(); +} + +gl::Error TextureD3D_2DMultisample::setStorageMultisample(const gl::Context *context, + GLenum target, + GLsizei samples, + GLint internalFormat, + const gl::Extents &size, + bool fixedSampleLocations) +{ + ASSERT(target == GL_TEXTURE_2D_MULTISAMPLE && size.depth == 1); + + TexStoragePointer storage(context); + storage.reset(mRenderer->createTextureStorage2DMultisample(internalFormat, size.width, + size.height, static_cast(0), + samples, fixedSampleLocations)); + + ANGLE_TRY(setCompleteTexStorage(context, storage.get())); + storage.release(); + + ANGLE_TRY(updateStorage(context)); + + mImmutable = false; + + return gl::NoError(); +} + +gl::Error TextureD3D_2DMultisample::bindTexImage(const gl::Context *context, egl::Surface *surface) +{ + UNREACHABLE(); + return gl::NoError(); +} + +gl::Error TextureD3D_2DMultisample::releaseTexImage(const gl::Context *context) +{ + UNREACHABLE(); + return gl::NoError(); +} + +gl::Error TextureD3D_2DMultisample::setEGLImageTarget(const gl::Context *context, + GLenum target, + egl::Image *image) +{ + UNREACHABLE(); + return gl::InternalError(); +} + +gl::Error TextureD3D_2DMultisample::getRenderTarget(const gl::Context *context, + const gl::ImageIndex &index, + RenderTargetD3D **outRT) +{ + ASSERT(!index.hasLayer()); + + // ensure the underlying texture is created + ANGLE_TRY(ensureRenderTarget(context)); + + return mTexStorage->getRenderTarget(context, index, outRT); +} + +gl::ImageIndexIterator TextureD3D_2DMultisample::imageIterator() const +{ + return gl::ImageIndexIterator::Make2DMultisample(); +} + +gl::ImageIndex TextureD3D_2DMultisample::getImageIndex(GLint mip, GLint layer) const +{ + return gl::ImageIndex::Make2DMultisample(); +} + +bool TextureD3D_2DMultisample::isValidIndex(const gl::ImageIndex &index) const +{ + return (mTexStorage && index.type == GL_TEXTURE_2D_MULTISAMPLE && index.mipIndex == 0); +} + +GLsizei TextureD3D_2DMultisample::getLayerCount(int level) const +{ + return 1; +} + +void TextureD3D_2DMultisample::markAllImagesDirty() +{ +} + +gl::Error TextureD3D_2DMultisample::initializeStorage(const gl::Context *context, bool renderTarget) +{ + // Only initialize the first time this texture is used as a render target or shader resource + if (mTexStorage) + { + return gl::NoError(); + } + + bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mState.getUsage())); + + TexStoragePointer storage(context); + ANGLE_TRY(createCompleteStorage(createRenderTarget, &storage)); + + ANGLE_TRY(setCompleteTexStorage(context, storage.get())); + storage.release(); + + ASSERT(mTexStorage); + + // flush image data to the storage + ANGLE_TRY(updateStorage(context)); + + return gl::NoError(); +} + +gl::Error TextureD3D_2DMultisample::createCompleteStorage(bool renderTarget, + TexStoragePointer *outStorage) const +{ + outStorage->reset(mTexStorage); + + return gl::NoError(); +} + +gl::Error TextureD3D_2DMultisample::setCompleteTexStorage(const gl::Context *context, + TextureStorage *newCompleteTexStorage) +{ + ANGLE_TRY(releaseTexStorage(context)); + mTexStorage = newCompleteTexStorage; + + return gl::NoError(); +} + +gl::Error TextureD3D_2DMultisample::updateStorage(const gl::Context *context) +{ + return gl::NoError(); +} + +gl::Error TextureD3D_2DMultisample::initMipmapImages(const gl::Context *context) +{ + UNIMPLEMENTED(); + return gl::NoError(); +} + +bool TextureD3D_2DMultisample::isImageComplete(const gl::ImageIndex &index) const +{ + return true; +} + +} // namespace rx diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/TextureD3D.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/TextureD3D.h index 1d5faee703..eb206a6ccc 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/TextureD3D.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/TextureD3D.h @@ -9,9 +9,12 @@ #ifndef LIBANGLE_RENDERER_D3D_TEXTURED3D_H_ #define LIBANGLE_RENDERER_D3D_TEXTURED3D_H_ -#include "libANGLE/renderer/TextureImpl.h" -#include "libANGLE/angletypes.h" +#include "common/Color.h" #include "libANGLE/Constants.h" +#include "libANGLE/Stream.h" +#include "libANGLE/angletypes.h" +#include "libANGLE/renderer/TextureImpl.h" +#include "libANGLE/renderer/d3d/TextureStorage.h" namespace gl { @@ -26,29 +29,51 @@ class RendererD3D; class RenderTargetD3D; class TextureStorage; +template +using TexLevelsArray = std::array; + class TextureD3D : public TextureImpl { public: - TextureD3D(RendererD3D *renderer); - virtual ~TextureD3D(); + TextureD3D(const gl::TextureState &data, RendererD3D *renderer); + ~TextureD3D() override; + + gl::Error onDestroy(const gl::Context *context) override; - gl::Error getNativeTexture(TextureStorage **outStorage); + gl::Error getNativeTexture(const gl::Context *context, 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; + gl::Error getImageAndSyncFromStorage(const gl::Context *context, + const gl::ImageIndex &index, + ImageD3D **outImage); + GLint getBaseLevelWidth() const; GLint getBaseLevelHeight() const; - GLint getBaseLevelDepth() const; GLenum getBaseLevelInternalFormat() const; + gl::Error setStorage(const gl::Context *context, + GLenum target, + size_t levels, + GLenum internalFormat, + const gl::Extents &size) override; + + gl::Error setStorageMultisample(const gl::Context *context, + GLenum target, + GLsizei samples, + GLint internalFormat, + const gl::Extents &size, + bool fixedSampleLocations) override; + bool isImmutable() const { return mImmutable; } - virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT) = 0; + virtual gl::Error getRenderTarget(const gl::Context *context, + const gl::ImageIndex &index, + RenderTargetD3D **outRT) = 0; // Returns an iterator over all "Images" for this particular Texture. virtual gl::ImageIndexIterator imageIterator() const = 0; @@ -58,47 +83,91 @@ class TextureD3D : public TextureImpl virtual gl::ImageIndex getImageIndex(GLint mip, GLint layer) const = 0; virtual bool isValidIndex(const gl::ImageIndex &index) const = 0; - gl::Error generateMipmaps(const gl::TextureState &textureState) override; + gl::Error setImageExternal(const gl::Context *context, + GLenum target, + egl::Stream *stream, + const egl::Stream::GLTextureDescription &desc) override; + gl::Error generateMipmap(const gl::Context *context) override; TextureStorage *getStorage(); ImageD3D *getBaseLevelImage() const; - gl::Error getAttachmentRenderTarget(const gl::FramebufferAttachment::Target &target, + gl::Error getAttachmentRenderTarget(const gl::Context *context, + GLenum binding, + const gl::ImageIndex &imageIndex, FramebufferAttachmentRenderTarget **rtOut) override; + gl::Error setBaseLevel(const gl::Context *context, GLuint baseLevel) override; + + void syncState(const gl::Texture::DirtyBits &dirtyBits) override; + + gl::Error initializeContents(const gl::Context *context, + const gl::ImageIndex &imageIndex) override; + protected: - gl::Error setImageImpl(const gl::ImageIndex &index, + gl::Error setImageImpl(const gl::Context *context, + 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 setCompressedImageImpl(const gl::ImageIndex &index, + gl::Error subImage(const gl::Context *context, + 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 setCompressedImageImpl(const gl::Context *context, + 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); + gl::Error subImageCompressed(const gl::Context *context, + 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::Buffer *unpackBuffer, GLenum sizedInternalFormat); + gl::Error fastUnpackPixels(const gl::Context *context, + const gl::PixelUnpackState &unpack, + const uint8_t *pixels, + const gl::Box &destArea, + GLenum sizedInternalFormat, + GLenum type, + RenderTargetD3D *destRenderTarget); + + GLint getLevelZeroWidth() const; + GLint getLevelZeroHeight() const; + virtual GLint getLevelZeroDepth() const; GLint creationLevels(GLsizei width, GLsizei height, GLsizei depth) const; - int mipLevels() const; - virtual void initMipmapsImages() = 0; + virtual gl::Error initMipmapImages(const gl::Context *context) = 0; bool isBaseImageZeroSize() const; virtual bool isImageComplete(const gl::ImageIndex &index) const = 0; bool canCreateRenderTargetForImage(const gl::ImageIndex &index) const; - virtual gl::Error ensureRenderTarget(); + gl::Error ensureRenderTarget(const gl::Context *context); - 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); + virtual gl::Error createCompleteStorage(bool renderTarget, + TexStoragePointer *outTexStorage) const = 0; + virtual gl::Error setCompleteTexStorage(const gl::Context *context, + TextureStorage *newCompleteTexStorage) = 0; + gl::Error commitRegion(const gl::Context *context, + const gl::ImageIndex &index, + const gl::Box ®ion); - RendererD3D *mRenderer; + gl::Error releaseTexStorage(const gl::Context *context); + + GLuint getBaseLevel() const { return mBaseLevel; }; - GLenum mUsage; + virtual void markAllImagesDirty() = 0; + + GLint getBaseLevelDepth() const; + + RendererD3D *mRenderer; bool mDirtyImages; @@ -106,154 +175,301 @@ class TextureD3D : public TextureImpl TextureStorage *mTexStorage; private: - virtual gl::Error initializeStorage(bool renderTarget) = 0; + virtual gl::Error initializeStorage(const gl::Context *context, bool renderTarget) = 0; - virtual gl::Error updateStorage() = 0; + virtual gl::Error updateStorage(const gl::Context *context) = 0; bool shouldUseSetData(const ImageD3D *image) const; - gl::Error generateMipmapsUsingImages(); + gl::Error generateMipmapUsingImages(const gl::Context *context, const GLuint maxLevel); + + GLuint mBaseLevel; }; class TextureD3D_2D : public TextureD3D { public: - TextureD3D_2D(RendererD3D *renderer); - virtual ~TextureD3D_2D(); + TextureD3D_2D(const gl::TextureState &data, RendererD3D *renderer); + ~TextureD3D_2D() override; - virtual ImageD3D *getImage(int level, int layer) const; - virtual ImageD3D *getImage(const gl::ImageIndex &index) const; - virtual GLsizei getLayerCount(int level) const; + gl::Error onDestroy(const gl::Context *context) override; + + ImageD3D *getImage(int level, int layer) const; + ImageD3D *getImage(const gl::ImageIndex &index) const override; + GLsizei getLayerCount(int level) const override; GLsizei getWidth(GLint level) const; GLsizei getHeight(GLint level) const; GLenum getInternalFormat(GLint level) const; bool isDepth(GLint level) const; + bool isSRGB(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, size_t imageSize, const uint8_t *pixels) override; - gl::Error setCompressedSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format, - const gl::PixelUnpackState &unpack, size_t imageSize, const uint8_t *pixels) override; - - gl::Error copyImage(GLenum target, size_t level, const gl::Rectangle &sourceArea, GLenum internalFormat, + gl::Error setImage(const gl::Context *context, + 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(const gl::Context *context, + 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(const gl::Context *context, + GLenum target, + size_t level, + GLenum internalFormat, + const gl::Extents &size, + const gl::PixelUnpackState &unpack, + size_t imageSize, + const uint8_t *pixels) override; + gl::Error setCompressedSubImage(const gl::Context *context, + GLenum target, + size_t level, + const gl::Box &area, + GLenum format, + const gl::PixelUnpackState &unpack, + size_t imageSize, + const uint8_t *pixels) override; + + gl::Error copyImage(const gl::Context *context, + 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, + gl::Error copySubImage(const gl::Context *context, + 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(); + gl::Error copyTexture(const gl::Context *context, + GLenum target, + size_t level, + GLenum internalFormat, + GLenum type, + size_t sourceLevel, + bool unpackFlipY, + bool unpackPremultiplyAlpha, + bool unpackUnmultiplyAlpha, + const gl::Texture *source) override; + gl::Error copySubTexture(const gl::Context *context, + GLenum target, + size_t level, + const gl::Offset &destOffset, + size_t sourceLevel, + const gl::Rectangle &sourceArea, + bool unpackFlipY, + bool unpackPremultiplyAlpha, + bool unpackUnmultiplyAlpha, + const gl::Texture *source) override; + gl::Error copyCompressedTexture(const gl::Context *context, const gl::Texture *source) override; + + gl::Error setStorage(const gl::Context *context, + GLenum target, + size_t levels, + GLenum internalFormat, + const gl::Extents &size) override; + + gl::Error bindTexImage(const gl::Context *context, egl::Surface *surface) override; + gl::Error releaseTexImage(const gl::Context *context) override; + + gl::Error setEGLImageTarget(const gl::Context *context, + GLenum target, + egl::Image *image) override; + + gl::Error getRenderTarget(const gl::Context *context, + const gl::ImageIndex &index, + RenderTargetD3D **outRT) override; + + gl::ImageIndexIterator imageIterator() const override; + gl::ImageIndex getImageIndex(GLint mip, GLint layer) const override; + bool isValidIndex(const gl::ImageIndex &index) const override; - gl::Error setEGLImageTarget(GLenum target, egl::Image *image) override; - - virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT); - - virtual gl::ImageIndexIterator imageIterator() const; - virtual gl::ImageIndex getImageIndex(GLint mip, GLint layer) const; - virtual bool isValidIndex(const gl::ImageIndex &index) const; + protected: + void markAllImagesDirty() override; private: - virtual gl::Error initializeStorage(bool renderTarget); - virtual gl::Error createCompleteStorage(bool renderTarget, TextureStorage **outTexStorage) const; - virtual gl::Error setCompleteTexStorage(TextureStorage *newCompleteTexStorage); + gl::Error initializeStorage(const gl::Context *context, bool renderTarget) override; + gl::Error createCompleteStorage(bool renderTarget, + TexStoragePointer *outTexStorage) const override; + gl::Error setCompleteTexStorage(const gl::Context *context, + TextureStorage *newCompleteTexStorage) override; - virtual gl::Error updateStorage(); - virtual void initMipmapsImages(); + gl::Error updateStorage(const gl::Context *context) override; + gl::Error initMipmapImages(const gl::Context *context) override; bool isValidLevel(int level) const; bool isLevelComplete(int level) const; - virtual bool isImageComplete(const gl::ImageIndex &index) const; + bool isImageComplete(const gl::ImageIndex &index) const override; - gl::Error updateStorageLevel(int level); + gl::Error updateStorageLevel(const gl::Context *context, int level); - void redefineImage(size_t level, - GLenum internalformat, - const gl::Extents &size, - bool forceRelease); + gl::Error redefineImage(const gl::Context *context, + size_t level, + GLenum internalformat, + const gl::Extents &size, + bool forceRelease); bool mEGLImageTarget; - ImageD3D *mImageArray[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; + TexLevelsArray> mImageArray; }; class TextureD3D_Cube : public TextureD3D { public: - TextureD3D_Cube(RendererD3D *renderer); - virtual ~TextureD3D_Cube(); + TextureD3D_Cube(const gl::TextureState &data, RendererD3D *renderer); + ~TextureD3D_Cube() override; - virtual ImageD3D *getImage(int level, int layer) const; - virtual ImageD3D *getImage(const gl::ImageIndex &index) const; - virtual GLsizei getLayerCount(int level) const; + gl::Error onDestroy(const gl::Context *context) override; - virtual bool hasDirtyImages() const { return mDirtyImages; } - virtual void resetDirty() { mDirtyImages = false; } - virtual void setUsage(GLenum usage) { mUsage = usage; } + ImageD3D *getImage(int level, int layer) const; + ImageD3D *getImage(const gl::ImageIndex &index) const override; + GLsizei getLayerCount(int level) const override; GLenum getInternalFormat(GLint level, GLint layer) const; bool isDepth(GLint level, GLint layer) const; + bool isSRGB(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, size_t imageSize, const uint8_t *pixels) override; - gl::Error setCompressedSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format, - const gl::PixelUnpackState &unpack, size_t imageSize, const uint8_t *pixels) override; - - gl::Error copyImage(GLenum target, size_t level, const gl::Rectangle &sourceArea, GLenum internalFormat, + gl::Error setImage(const gl::Context *context, + 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(const gl::Context *context, + 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(const gl::Context *context, + GLenum target, + size_t level, + GLenum internalFormat, + const gl::Extents &size, + const gl::PixelUnpackState &unpack, + size_t imageSize, + const uint8_t *pixels) override; + gl::Error setCompressedSubImage(const gl::Context *context, + GLenum target, + size_t level, + const gl::Box &area, + GLenum format, + const gl::PixelUnpackState &unpack, + size_t imageSize, + const uint8_t *pixels) override; + + gl::Error copyImage(const gl::Context *context, + 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, + gl::Error copySubImage(const gl::Context *context, + 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; + gl::Error copyTexture(const gl::Context *context, + GLenum target, + size_t level, + GLenum internalFormat, + GLenum type, + size_t sourceLevel, + bool unpackFlipY, + bool unpackPremultiplyAlpha, + bool unpackUnmultiplyAlpha, + const gl::Texture *source) override; + gl::Error copySubTexture(const gl::Context *context, + GLenum target, + size_t level, + const gl::Offset &destOffset, + size_t sourceLevel, + const gl::Rectangle &sourceArea, + bool unpackFlipY, + bool unpackPremultiplyAlpha, + bool unpackUnmultiplyAlpha, + const gl::Texture *source) override; + + gl::Error setStorage(const gl::Context *context, + GLenum target, + size_t levels, + GLenum internalFormat, + const gl::Extents &size) override; + + gl::Error bindTexImage(const gl::Context *context, egl::Surface *surface) override; + gl::Error releaseTexImage(const gl::Context *context) override; + + gl::Error setEGLImageTarget(const gl::Context *context, + GLenum target, + egl::Image *image) override; + + gl::Error getRenderTarget(const gl::Context *context, + const gl::ImageIndex &index, + RenderTargetD3D **outRT) override; + + gl::ImageIndexIterator imageIterator() const override; + gl::ImageIndex getImageIndex(GLint mip, GLint layer) const override; + bool isValidIndex(const gl::ImageIndex &index) const override; - virtual void bindTexImage(egl::Surface *surface); - virtual void releaseTexImage(); - - gl::Error setEGLImageTarget(GLenum target, egl::Image *image) override; - - virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT); - - virtual gl::ImageIndexIterator imageIterator() const; - virtual gl::ImageIndex getImageIndex(GLint mip, GLint layer) const; - virtual bool isValidIndex(const gl::ImageIndex &index) const; + protected: + void markAllImagesDirty() override; private: - virtual gl::Error initializeStorage(bool renderTarget); - virtual gl::Error createCompleteStorage(bool renderTarget, TextureStorage **outTexStorage) const; - virtual gl::Error setCompleteTexStorage(TextureStorage *newCompleteTexStorage); + gl::Error initializeStorage(const gl::Context *context, bool renderTarget) override; + gl::Error createCompleteStorage(bool renderTarget, + TexStoragePointer *outTexStorage) const override; + gl::Error setCompleteTexStorage(const gl::Context *context, + TextureStorage *newCompleteTexStorage) override; - virtual gl::Error updateStorage(); - virtual void initMipmapsImages(); + gl::Error updateStorage(const gl::Context *context) override; + gl::Error initMipmapImages(const gl::Context *context) override; 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); + bool isImageComplete(const gl::ImageIndex &index) const override; + gl::Error updateStorageFaceLevel(const gl::Context *context, int faceIndex, int level); - void redefineImage(int faceIndex, GLint level, GLenum internalformat, const gl::Extents &size); + gl::Error redefineImage(const gl::Context *context, + int faceIndex, + GLint level, + GLenum internalformat, + const gl::Extents &size, + bool forceRelease); - ImageD3D *mImageArray[6][gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; + std::array>, 6> mImageArray; }; class TextureD3D_3D : public TextureD3D { public: - TextureD3D_3D(RendererD3D *renderer); - virtual ~TextureD3D_3D(); + TextureD3D_3D(const gl::TextureState &data, RendererD3D *renderer); + ~TextureD3D_3D() override; - virtual ImageD3D *getImage(int level, int layer) const; - virtual ImageD3D *getImage(const gl::ImageIndex &index) const; - virtual GLsizei getLayerCount(int level) const; + gl::Error onDestroy(const gl::Context *context) override; + + ImageD3D *getImage(int level, int layer) const; + ImageD3D *getImage(const gl::ImageIndex &index) const override; + GLsizei getLayerCount(int level) const override; GLsizei getWidth(GLint level) const; GLsizei getHeight(GLint level) const; @@ -261,110 +477,213 @@ class TextureD3D_3D : public TextureD3D 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, size_t imageSize, const uint8_t *pixels) override; - gl::Error setCompressedSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format, - const gl::PixelUnpackState &unpack, size_t imageSize, const uint8_t *pixels) override; - - gl::Error copyImage(GLenum target, size_t level, const gl::Rectangle &sourceArea, GLenum internalFormat, + gl::Error setImage(const gl::Context *context, + 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(const gl::Context *context, + 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(const gl::Context *context, + GLenum target, + size_t level, + GLenum internalFormat, + const gl::Extents &size, + const gl::PixelUnpackState &unpack, + size_t imageSize, + const uint8_t *pixels) override; + gl::Error setCompressedSubImage(const gl::Context *context, + GLenum target, + size_t level, + const gl::Box &area, + GLenum format, + const gl::PixelUnpackState &unpack, + size_t imageSize, + const uint8_t *pixels) override; + + gl::Error copyImage(const gl::Context *context, + 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, + gl::Error copySubImage(const gl::Context *context, + 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; + gl::Error setStorage(const gl::Context *context, + GLenum target, + size_t levels, + GLenum internalFormat, + const gl::Extents &size) override; - virtual void bindTexImage(egl::Surface *surface); - virtual void releaseTexImage(); + gl::Error bindTexImage(const gl::Context *context, egl::Surface *surface) override; + gl::Error releaseTexImage(const gl::Context *context) override; - gl::Error setEGLImageTarget(GLenum target, egl::Image *image) override; + gl::Error setEGLImageTarget(const gl::Context *context, + GLenum target, + egl::Image *image) override; - virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT); + gl::Error getRenderTarget(const gl::Context *context, + const gl::ImageIndex &index, + RenderTargetD3D **outRT) override; - virtual gl::ImageIndexIterator imageIterator() const; - virtual gl::ImageIndex getImageIndex(GLint mip, GLint layer) const; - virtual bool isValidIndex(const gl::ImageIndex &index) const; + gl::ImageIndexIterator imageIterator() const override; + gl::ImageIndex getImageIndex(GLint mip, GLint layer) const override; + bool isValidIndex(const gl::ImageIndex &index) const override; + + protected: + void markAllImagesDirty() override; + GLint getLevelZeroDepth() const override; private: - virtual gl::Error initializeStorage(bool renderTarget); - virtual gl::Error createCompleteStorage(bool renderTarget, TextureStorage **outStorage) const; - virtual gl::Error setCompleteTexStorage(TextureStorage *newCompleteTexStorage); + gl::Error initializeStorage(const gl::Context *context, bool renderTarget) override; + gl::Error createCompleteStorage(bool renderTarget, + TexStoragePointer *outStorage) const override; + gl::Error setCompleteTexStorage(const gl::Context *context, + TextureStorage *newCompleteTexStorage) override; - virtual gl::Error updateStorage(); - virtual void initMipmapsImages(); + gl::Error updateStorage(const gl::Context *context) override; + gl::Error initMipmapImages(const gl::Context *context) override; bool isValidLevel(int level) const; bool isLevelComplete(int level) const; - virtual bool isImageComplete(const gl::ImageIndex &index) const; - gl::Error updateStorageLevel(int level); + bool isImageComplete(const gl::ImageIndex &index) const override; + gl::Error updateStorageLevel(const gl::Context *context, int level); - void redefineImage(GLint level, GLenum internalformat, const gl::Extents &size); + gl::Error redefineImage(const gl::Context *context, + GLint level, + GLenum internalformat, + const gl::Extents &size, + bool forceRelease); - ImageD3D *mImageArray[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; + TexLevelsArray> mImageArray; }; class TextureD3D_2DArray : public TextureD3D { public: - TextureD3D_2DArray(RendererD3D *renderer); - virtual ~TextureD3D_2DArray(); + TextureD3D_2DArray(const gl::TextureState &data, RendererD3D *renderer); + ~TextureD3D_2DArray() override; + + gl::Error onDestroy(const gl::Context *context) override; virtual ImageD3D *getImage(int level, int layer) const; - virtual ImageD3D *getImage(const gl::ImageIndex &index) const; - virtual GLsizei getLayerCount(int level) const; + ImageD3D *getImage(const gl::ImageIndex &index) const override; + GLsizei getLayerCount(int level) const override; 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, size_t imageSize, const uint8_t *pixels) override; - gl::Error setCompressedSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format, - const gl::PixelUnpackState &unpack, size_t imageSize, const uint8_t *pixels) override; - - gl::Error copyImage(GLenum target, size_t level, const gl::Rectangle &sourceArea, GLenum internalFormat, + gl::Error setImage(const gl::Context *context, + 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(const gl::Context *context, + 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(const gl::Context *context, + GLenum target, + size_t level, + GLenum internalFormat, + const gl::Extents &size, + const gl::PixelUnpackState &unpack, + size_t imageSize, + const uint8_t *pixels) override; + gl::Error setCompressedSubImage(const gl::Context *context, + GLenum target, + size_t level, + const gl::Box &area, + GLenum format, + const gl::PixelUnpackState &unpack, + size_t imageSize, + const uint8_t *pixels) override; + + gl::Error copyImage(const gl::Context *context, + 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, + gl::Error copySubImage(const gl::Context *context, + 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; + gl::Error setStorage(const gl::Context *context, + GLenum target, + size_t levels, + GLenum internalFormat, + const gl::Extents &size) override; + + gl::Error bindTexImage(const gl::Context *context, egl::Surface *surface) override; + gl::Error releaseTexImage(const gl::Context *context) override; - virtual void bindTexImage(egl::Surface *surface); - virtual void releaseTexImage(); + gl::Error setEGLImageTarget(const gl::Context *context, + GLenum target, + egl::Image *image) override; - gl::Error setEGLImageTarget(GLenum target, egl::Image *image) override; + gl::Error getRenderTarget(const gl::Context *context, + const gl::ImageIndex &index, + RenderTargetD3D **outRT) override; - virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT); + gl::ImageIndexIterator imageIterator() const override; + gl::ImageIndex getImageIndex(GLint mip, GLint layer) const override; + bool isValidIndex(const gl::ImageIndex &index) const override; - virtual gl::ImageIndexIterator imageIterator() const; - virtual gl::ImageIndex getImageIndex(GLint mip, GLint layer) const; - virtual bool isValidIndex(const gl::ImageIndex &index) const; + protected: + void markAllImagesDirty() override; private: - virtual gl::Error initializeStorage(bool renderTarget); - virtual gl::Error createCompleteStorage(bool renderTarget, TextureStorage **outStorage) const; - virtual gl::Error setCompleteTexStorage(TextureStorage *newCompleteTexStorage); + gl::Error initializeStorage(const gl::Context *context, bool renderTarget) override; + gl::Error createCompleteStorage(bool renderTarget, + TexStoragePointer *outStorage) const override; + gl::Error setCompleteTexStorage(const gl::Context *context, + TextureStorage *newCompleteTexStorage) override; - virtual gl::Error updateStorage(); - virtual void initMipmapsImages(); + gl::Error updateStorage(const gl::Context *context) override; + gl::Error initMipmapImages(const gl::Context *context) override; bool isValidLevel(int level) const; bool isLevelComplete(int level) const; - virtual bool isImageComplete(const gl::ImageIndex &index) const; - gl::Error updateStorageLevel(int level); + bool isImageComplete(const gl::ImageIndex &index) const override; + gl::Error updateStorageLevel(const gl::Context *context, int level); void deleteImages(); - void redefineImage(GLint level, GLenum internalformat, const gl::Extents &size); + gl::Error redefineImage(const gl::Context *context, + GLint level, + GLenum internalformat, + const gl::Extents &size, + bool forceRelease); // 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 @@ -374,6 +693,199 @@ class TextureD3D_2DArray : public TextureD3D ImageD3D **mImageArray[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; }; +class TextureD3D_External : public TextureD3D +{ + public: + TextureD3D_External(const gl::TextureState &data, RendererD3D *renderer); + ~TextureD3D_External() override; + + ImageD3D *getImage(const gl::ImageIndex &index) const override; + GLsizei getLayerCount(int level) const override; + + gl::Error setImage(const gl::Context *context, + 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(const gl::Context *context, + 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(const gl::Context *context, + GLenum target, + size_t level, + GLenum internalFormat, + const gl::Extents &size, + const gl::PixelUnpackState &unpack, + size_t imageSize, + const uint8_t *pixels) override; + gl::Error setCompressedSubImage(const gl::Context *context, + GLenum target, + size_t level, + const gl::Box &area, + GLenum format, + const gl::PixelUnpackState &unpack, + size_t imageSize, + const uint8_t *pixels) override; + + gl::Error copyImage(const gl::Context *context, + GLenum target, + size_t level, + const gl::Rectangle &sourceArea, + GLenum internalFormat, + const gl::Framebuffer *source) override; + gl::Error copySubImage(const gl::Context *context, + GLenum target, + size_t level, + const gl::Offset &destOffset, + const gl::Rectangle &sourceArea, + const gl::Framebuffer *source) override; + + gl::Error setStorage(const gl::Context *context, + GLenum target, + size_t levels, + GLenum internalFormat, + const gl::Extents &size) override; + + gl::Error setImageExternal(const gl::Context *context, + GLenum target, + egl::Stream *stream, + const egl::Stream::GLTextureDescription &desc) override; + + gl::Error bindTexImage(const gl::Context *context, egl::Surface *surface) override; + gl::Error releaseTexImage(const gl::Context *context) override; + + gl::Error setEGLImageTarget(const gl::Context *context, + GLenum target, + egl::Image *image) override; + + gl::Error getRenderTarget(const gl::Context *context, + const gl::ImageIndex &index, + RenderTargetD3D **outRT) override; + + gl::ImageIndexIterator imageIterator() const override; + gl::ImageIndex getImageIndex(GLint mip, GLint layer) const override; + bool isValidIndex(const gl::ImageIndex &index) const override; + + protected: + void markAllImagesDirty() override; + + private: + gl::Error initializeStorage(const gl::Context *context, bool renderTarget) override; + gl::Error createCompleteStorage(bool renderTarget, + TexStoragePointer *outTexStorage) const override; + gl::Error setCompleteTexStorage(const gl::Context *context, + TextureStorage *newCompleteTexStorage) override; + + gl::Error updateStorage(const gl::Context *context) override; + gl::Error initMipmapImages(const gl::Context *context) override; + + bool isImageComplete(const gl::ImageIndex &index) const override; +}; + +class TextureD3D_2DMultisample : public TextureD3D +{ + public: + TextureD3D_2DMultisample(const gl::TextureState &data, RendererD3D *renderer); + ~TextureD3D_2DMultisample() override; + + ImageD3D *getImage(const gl::ImageIndex &index) const override; + gl::Error setImage(const gl::Context *context, + 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(const gl::Context *context, + 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(const gl::Context *context, + GLenum target, + size_t level, + GLenum internalFormat, + const gl::Extents &size, + const gl::PixelUnpackState &unpack, + size_t imageSize, + const uint8_t *pixels) override; + gl::Error setCompressedSubImage(const gl::Context *context, + GLenum target, + size_t level, + const gl::Box &area, + GLenum format, + const gl::PixelUnpackState &unpack, + size_t imageSize, + const uint8_t *pixels) override; + + gl::Error copyImage(const gl::Context *context, + GLenum target, + size_t level, + const gl::Rectangle &sourceArea, + GLenum internalFormat, + const gl::Framebuffer *source) override; + gl::Error copySubImage(const gl::Context *context, + GLenum target, + size_t level, + const gl::Offset &destOffset, + const gl::Rectangle &sourceArea, + const gl::Framebuffer *source) override; + + gl::Error setStorageMultisample(const gl::Context *context, + GLenum target, + GLsizei samples, + GLint internalFormat, + const gl::Extents &size, + bool fixedSampleLocations) override; + + gl::Error bindTexImage(const gl::Context *context, egl::Surface *surface) override; + gl::Error releaseTexImage(const gl::Context *context) override; + + gl::Error setEGLImageTarget(const gl::Context *context, + GLenum target, + egl::Image *image) override; + + gl::Error getRenderTarget(const gl::Context *context, + const gl::ImageIndex &index, + RenderTargetD3D **outRT) override; + + gl::ImageIndexIterator imageIterator() const override; + gl::ImageIndex getImageIndex(GLint mip, GLint layer) const override; + bool isValidIndex(const gl::ImageIndex &index) const override; + + GLsizei getLayerCount(int level) const override; + + protected: + void markAllImagesDirty() override; + + private: + gl::Error initializeStorage(const gl::Context *context, bool renderTarget) override; + gl::Error createCompleteStorage(bool renderTarget, + TexStoragePointer *outTexStorage) const override; + gl::Error setCompleteTexStorage(const gl::Context *context, + TextureStorage *newCompleteTexStorage) override; + + gl::Error updateStorage(const gl::Context *context) override; + gl::Error initMipmapImages(const gl::Context *context) override; + + bool isImageComplete(const gl::ImageIndex &index) const override; +}; } #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 deleted file mode 100644 index abb83a14d5..0000000000 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/TextureStorage.cpp +++ /dev/null @@ -1,39 +0,0 @@ -// -// 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 index 417237495d..383fbc2141 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/TextureStorage.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/TextureStorage.h @@ -9,20 +9,19 @@ #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 "libANGLE/angletypes.h" #include #include namespace gl { +class Context; struct ImageIndex; struct Box; struct PixelUnpackState; -} +} // namespace gl namespace rx { @@ -36,23 +35,48 @@ class TextureStorage : angle::NonCopyable TextureStorage() {} virtual ~TextureStorage() {} + virtual gl::Error onDestroy(const gl::Context *context); + virtual int getTopLevel() const = 0; virtual bool isRenderTarget() const = 0; virtual bool isManaged() const = 0; virtual bool supportsNativeMipmapFunction() 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 getRenderTarget(const gl::Context *context, + const gl::ImageIndex &index, + RenderTargetD3D **outRT) = 0; + virtual gl::Error generateMipmap(const gl::Context *context, + 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; + virtual gl::Error copyToStorage(const gl::Context *context, TextureStorage *destStorage) = 0; + virtual gl::Error setData(const gl::Context *context, + const gl::ImageIndex &index, + ImageD3D *image, + const gl::Box *destBox, + GLenum type, + const gl::PixelUnpackState &unpack, + const uint8_t *pixelData) = 0; // 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); } + virtual gl::Error useLevelZeroWorkaroundTexture(const gl::Context *context, + bool useLevelZeroTexture); }; +inline gl::Error TextureStorage::onDestroy(const gl::Context *context) +{ + return gl::NoError(); } +inline gl::Error TextureStorage::useLevelZeroWorkaroundTexture(const gl::Context *context, + bool useLevelZeroTexture) +{ + return gl::NoError(); +} + +using TexStoragePointer = angle::UniqueObjectPointer; + +} // namespace rx + #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 deleted file mode 100644 index 80a4ec3ae1..0000000000 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/TransformFeedbackD3D.cpp +++ /dev/null @@ -1,46 +0,0 @@ -// -// 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() -{ -} - -void TransformFeedbackD3D::bindGenericBuffer(const BindingPointer &binding) -{ -} - -void TransformFeedbackD3D::bindIndexedBuffer(size_t index, const OffsetBindingPointer &binding) -{ -} - -} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/TransformFeedbackD3D.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/TransformFeedbackD3D.h deleted file mode 100644 index 6925966153..0000000000 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/TransformFeedbackD3D.h +++ /dev/null @@ -1,35 +0,0 @@ -// -// 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(); - - void begin(GLenum primitiveMode) override; - void end() override; - void pause() override; - void resume() override; - - void bindGenericBuffer(const BindingPointer &binding) override; - void bindIndexedBuffer(size_t index, const OffsetBindingPointer &binding) override; -}; - -} - -#endif // LIBANGLE_RENDERER_D3D_TRANSFORMFEEDBACKD3D_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/VaryingPacking.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/VaryingPacking.cpp deleted file mode 100644 index f2654d34e3..0000000000 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/VaryingPacking.cpp +++ /dev/null @@ -1,397 +0,0 @@ -// -// 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. -// -// VaryingPacking: -// Class which describes a mapping from varyings to registers in D3D -// for linking between shader stages. -// - -#include "libANGLE/renderer/d3d/VaryingPacking.h" - -#include "common/utilities.h" -#include "compiler/translator/blocklayoutHLSL.h" -#include "libANGLE/renderer/d3d/DynamicHLSL.h" -#include "libANGLE/renderer/d3d/ProgramD3D.h" - -namespace rx -{ - -// Implementation of VaryingPacking::BuiltinVarying -VaryingPacking::BuiltinVarying::BuiltinVarying() : enabled(false), index(0), systemValue(false) -{ -} - -std::string VaryingPacking::BuiltinVarying::str() const -{ - return (systemValue ? semantic : (semantic + Str(index))); -} - -void VaryingPacking::BuiltinVarying::enableSystem(const std::string &systemValueSemantic) -{ - enabled = true; - semantic = systemValueSemantic; - systemValue = true; -} - -void VaryingPacking::BuiltinVarying::enable(const std::string &semanticVal, unsigned int indexVal) -{ - enabled = true; - semantic = semanticVal; - index = indexVal; -} - -// Implementation of VaryingPacking -VaryingPacking::VaryingPacking(GLuint maxVaryingVectors) - : mRegisterMap(maxVaryingVectors), mBuiltinInfo(SHADER_TYPE_MAX) -{ -} - -// Packs varyings into generic varying registers, using the algorithm from -// See [OpenGL ES Shading Language 1.00 rev. 17] appendix A section 7 page 111 -// Also [OpenGL ES Shading Language 3.00 rev. 4] Section 11 page 119 -// Returns false if unsuccessful. -bool VaryingPacking::packVarying(const PackedVarying &packedVarying) -{ - unsigned int varyingRows = 0; - unsigned int varyingColumns = 0; - - const auto &varying = *packedVarying.varying; - - // "Non - square matrices of type matCxR consume the same space as a square matrix of type matN - // where N is the greater of C and R.Variables of type mat2 occupies 2 complete rows." - // Here we are a bit more conservative and allow packing non-square matrices more tightly. - // Make sure we use transposed matrix types to count registers correctly. - ASSERT(!varying.isStruct()); - GLenum transposedType = gl::TransposeMatrixType(varying.type); - varyingRows = gl::VariableRowCount(transposedType); - varyingColumns = gl::VariableColumnCount(transposedType); - - // "Arrays of size N are assumed to take N times the size of the base type" - varyingRows *= varying.elementCount(); - - unsigned int maxVaryingVectors = static_cast(mRegisterMap.size()); - - // "For 2, 3 and 4 component variables packing is started using the 1st column of the 1st row. - // Variables are then allocated to successive rows, aligning them to the 1st column." - if (varyingColumns >= 2 && varyingColumns <= 4) - { - for (unsigned int row = 0; row <= maxVaryingVectors - varyingRows; ++row) - { - if (isFree(row, 0, varyingRows, varyingColumns)) - { - insert(row, 0, packedVarying); - return true; - } - } - - // "For 2 component variables, when there are no spare rows, the strategy is switched to - // using the highest numbered row and the lowest numbered column where the variable will - // fit." - if (varyingColumns == 2) - { - for (unsigned int r = maxVaryingVectors - varyingRows + 1; r-- >= 1;) - { - if (isFree(r, 2, varyingRows, 2)) - { - insert(r, 2, packedVarying); - return true; - } - } - } - - return false; - } - - // "1 component variables have their own packing rule. They are packed in order of size, largest - // first. Each variable is placed in the column that leaves the least amount of space in the - // column and aligned to the lowest available rows within that column." - ASSERT(varyingColumns == 1); - unsigned int contiguousSpace[4] = {0}; - unsigned int bestContiguousSpace[4] = {0}; - unsigned int totalSpace[4] = {0}; - - for (unsigned int row = 0; row < maxVaryingVectors; ++row) - { - for (unsigned int column = 0; column < 4; ++column) - { - if (mRegisterMap[row][column]) - { - contiguousSpace[column] = 0; - } - else - { - contiguousSpace[column]++; - totalSpace[column]++; - - if (contiguousSpace[column] > bestContiguousSpace[column]) - { - bestContiguousSpace[column] = contiguousSpace[column]; - } - } - } - } - - unsigned int bestColumn = 0; - for (unsigned int column = 1; column < 4; ++column) - { - if (bestContiguousSpace[column] >= varyingRows && - (bestContiguousSpace[bestColumn] < varyingRows || - totalSpace[column] < totalSpace[bestColumn])) - { - bestColumn = column; - } - } - - if (bestContiguousSpace[bestColumn] >= varyingRows) - { - for (unsigned int row = 0; row < maxVaryingVectors; row++) - { - if (isFree(row, bestColumn, varyingRows, 1)) - { - for (unsigned int arrayIndex = 0; arrayIndex < varyingRows; ++arrayIndex) - { - // If varyingRows > 1, it must be an array. - PackedVaryingRegister registerInfo; - registerInfo.packedVarying = &packedVarying; - registerInfo.registerRow = row + arrayIndex; - registerInfo.registerColumn = bestColumn; - registerInfo.varyingArrayIndex = arrayIndex; - registerInfo.varyingRowIndex = 0; - mRegisterList.push_back(registerInfo); - mRegisterMap[row + arrayIndex][bestColumn] = true; - } - break; - } - } - return true; - } - - return false; -} - -bool VaryingPacking::isFree(unsigned int registerRow, - unsigned int registerColumn, - unsigned int varyingRows, - unsigned int varyingColumns) const -{ - for (unsigned int row = 0; row < varyingRows; ++row) - { - ASSERT(registerRow + row < mRegisterMap.size()); - for (unsigned int column = 0; column < varyingColumns; ++column) - { - ASSERT(registerColumn + column < 4); - if (mRegisterMap[registerRow + row][registerColumn + column]) - { - return false; - } - } - } - - return true; -} - -void VaryingPacking::insert(unsigned int registerRow, - unsigned int registerColumn, - const PackedVarying &packedVarying) -{ - unsigned int varyingRows = 0; - unsigned int varyingColumns = 0; - - const auto &varying = *packedVarying.varying; - ASSERT(!varying.isStruct()); - GLenum transposedType = gl::TransposeMatrixType(varying.type); - varyingRows = gl::VariableRowCount(transposedType); - varyingColumns = gl::VariableColumnCount(transposedType); - - PackedVaryingRegister registerInfo; - registerInfo.packedVarying = &packedVarying; - registerInfo.registerColumn = registerColumn; - - for (unsigned int arrayElement = 0; arrayElement < varying.elementCount(); ++arrayElement) - { - for (unsigned int varyingRow = 0; varyingRow < varyingRows; ++varyingRow) - { - registerInfo.registerRow = registerRow + (arrayElement * varyingRows) + varyingRow; - registerInfo.varyingRowIndex = varyingRow; - registerInfo.varyingArrayIndex = arrayElement; - mRegisterList.push_back(registerInfo); - - for (unsigned int columnIndex = 0; columnIndex < varyingColumns; ++columnIndex) - { - mRegisterMap[registerInfo.registerRow][registerColumn + columnIndex] = true; - } - } - } -} - -// See comment on packVarying. -bool VaryingPacking::packVaryings(gl::InfoLog &infoLog, - const std::vector &packedVaryings, - const std::vector &transformFeedbackVaryings) -{ - std::set uniqueVaryingNames; - - // "Variables are packed into the registers one at a time so that they each occupy a contiguous - // subrectangle. No splitting of variables is permitted." - for (const PackedVarying &packedVarying : packedVaryings) - { - const auto &varying = *packedVarying.varying; - - // Do not assign registers to built-in or unreferenced varyings - if (varying.isBuiltIn() || (!varying.staticUse && !packedVarying.isStructField())) - { - continue; - } - - ASSERT(!varying.isStruct()); - ASSERT(uniqueVaryingNames.count(varying.name) == 0); - - if (packVarying(packedVarying)) - { - uniqueVaryingNames.insert(varying.name); - } - else - { - infoLog << "Could not pack varying " << varying.name; - return false; - } - } - - for (const std::string &transformFeedbackVaryingName : transformFeedbackVaryings) - { - if (transformFeedbackVaryingName.compare(0, 3, "gl_") == 0) - { - // do not pack builtin XFB varyings - continue; - } - - for (const PackedVarying &packedVarying : packedVaryings) - { - const auto &varying = *packedVarying.varying; - - // Make sure transform feedback varyings aren't optimized out. - if (uniqueVaryingNames.count(transformFeedbackVaryingName) == 0) - { - bool found = false; - if (transformFeedbackVaryingName == varying.name) - { - if (!packVarying(packedVarying)) - { - infoLog << "Could not pack varying " << varying.name; - return false; - } - - found = true; - break; - } - if (!found) - { - infoLog << "Transform feedback varying " << transformFeedbackVaryingName - << " does not exist in the vertex shader."; - return false; - } - } - } - } - - // Sort the packed register list - std::sort(mRegisterList.begin(), mRegisterList.end()); - - // Assign semantic indices - for (unsigned int semanticIndex = 0; - semanticIndex < static_cast(mRegisterList.size()); ++semanticIndex) - { - mRegisterList[semanticIndex].semanticIndex = semanticIndex; - } - - return true; -} - -unsigned int VaryingPacking::getRegisterCount() const -{ - unsigned int count = 0; - - for (const Register ® : mRegisterMap) - { - if (reg.data[0] || reg.data[1] || reg.data[2] || reg.data[3]) - { - ++count; - } - } - - if (mBuiltinInfo[SHADER_PIXEL].glFragCoord.enabled) - { - ++count; - } - - if (mBuiltinInfo[SHADER_PIXEL].glPointCoord.enabled) - { - ++count; - } - - return count; -} - -void VaryingPacking::enableBuiltins(ShaderType shaderType, - const ProgramD3DMetadata &programMetadata) -{ - int majorShaderModel = programMetadata.getRendererMajorShaderModel(); - bool position = programMetadata.usesTransformFeedbackGLPosition(); - bool fragCoord = programMetadata.usesFragCoord(); - bool pointCoord = shaderType == SHADER_VERTEX ? programMetadata.addsPointCoordToVertexShader() - : programMetadata.usesPointCoord(); - bool pointSize = programMetadata.usesSystemValuePointSize(); - bool hlsl4 = (majorShaderModel >= 4); - const std::string &userSemantic = GetVaryingSemantic(majorShaderModel, pointSize); - - unsigned int reservedSemanticIndex = getMaxSemanticIndex(); - - BuiltinInfo *builtins = &mBuiltinInfo[shaderType]; - - if (hlsl4) - { - builtins->dxPosition.enableSystem("SV_Position"); - } - else if (shaderType == SHADER_PIXEL) - { - builtins->dxPosition.enableSystem("VPOS"); - } - else - { - builtins->dxPosition.enableSystem("POSITION"); - } - - if (position) - { - builtins->glPosition.enable(userSemantic, reservedSemanticIndex++); - } - - if (fragCoord) - { - builtins->glFragCoord.enable(userSemantic, reservedSemanticIndex++); - } - - 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) - { - builtins->glPointCoord.enable(userSemantic, reservedSemanticIndex++); - } - else - { - builtins->glPointCoord.enable("TEXCOORD", 0); - } - } - - // Special case: do not include PSIZE semantic in HLSL 3 pixel shaders - if (pointSize && (shaderType != SHADER_PIXEL || hlsl4)) - { - builtins->glPointSize.enableSystem("PSIZE"); - } -} - -} // namespace rx diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/VaryingPacking.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/VaryingPacking.h deleted file mode 100644 index ca4640b000..0000000000 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/VaryingPacking.h +++ /dev/null @@ -1,175 +0,0 @@ -// -// 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. -// -// VaryingPacking: -// Class which describes a mapping from varyings to registers in D3D -// for linking between shader stages. -// - -#ifndef LIBANGLE_RENDERER_D3D_VARYINGPACKING_H_ -#define LIBANGLE_RENDERER_D3D_VARYINGPACKING_H_ - -#include "libANGLE/renderer/d3d/RendererD3D.h" - -namespace rx -{ -class ProgramD3DMetadata; - -struct PackedVarying -{ - PackedVarying(const sh::ShaderVariable &varyingIn, sh::InterpolationType interpolationIn) - : varying(&varyingIn), vertexOnly(false), interpolation(interpolationIn) - { - } - PackedVarying(const sh::ShaderVariable &varyingIn, - sh::InterpolationType interpolationIn, - const std::string &parentStructNameIn) - : varying(&varyingIn), - vertexOnly(false), - interpolation(interpolationIn), - parentStructName(parentStructNameIn) - { - } - - bool isStructField() const { return !parentStructName.empty(); } - - const sh::ShaderVariable *varying; - - // Transform feedback varyings can be only referenced in the VS. - bool vertexOnly; - - // Cached so we can store sh::ShaderVariable to point to varying fields. - sh::InterpolationType interpolation; - - // Struct name - std::string parentStructName; -}; - -struct PackedVaryingRegister final -{ - PackedVaryingRegister() - : packedVarying(nullptr), - varyingArrayIndex(0), - varyingRowIndex(0), - registerRow(0), - registerColumn(0) - { - } - - PackedVaryingRegister(const PackedVaryingRegister &) = default; - PackedVaryingRegister &operator=(const PackedVaryingRegister &) = default; - - bool operator<(const PackedVaryingRegister &other) const - { - return sortOrder() < other.sortOrder(); - } - - unsigned int sortOrder() const - { - // TODO(jmadill): Handle interpolation types - return registerRow * 4 + registerColumn; - } - - bool isStructField() const { return !structFieldName.empty(); } - - // Index to the array of varyings. - const PackedVarying *packedVarying; - - // The array element of the packed varying. - unsigned int varyingArrayIndex; - - // The row of the array element of the packed varying. - unsigned int varyingRowIndex; - - // The register row to which we've assigned this packed varying. - unsigned int registerRow; - - // The column of the register row into which we've packed this varying. - unsigned int registerColumn; - - // Assigned after packing - unsigned int semanticIndex; - - // Struct member this varying corresponds to. - std::string structFieldName; -}; - -class VaryingPacking final : angle::NonCopyable -{ - public: - VaryingPacking(GLuint maxVaryingVectors); - - bool packVaryings(gl::InfoLog &infoLog, - const std::vector &packedVaryings, - const std::vector &transformFeedbackVaryings); - - struct Register - { - Register() { data[0] = data[1] = data[2] = data[3] = false; } - - bool &operator[](unsigned int index) { return data[index]; } - bool operator[](unsigned int index) const { return data[index]; } - - bool data[4]; - }; - - Register &operator[](unsigned int index) { return mRegisterMap[index]; } - const Register &operator[](unsigned int index) const { return mRegisterMap[index]; } - - const std::vector &getRegisterList() const { return mRegisterList; } - unsigned int getMaxSemanticIndex() const - { - return static_cast(mRegisterList.size()); - } - unsigned int getRegisterCount() const; - - void enableBuiltins(ShaderType shaderType, const ProgramD3DMetadata &programMetadata); - - struct BuiltinVarying final : angle::NonCopyable - { - BuiltinVarying(); - - std::string str() const; - void enableSystem(const std::string &systemValueSemantic); - void enable(const std::string &semanticVal, unsigned int indexVal); - - bool enabled; - std::string semantic; - unsigned int index; - bool systemValue; - }; - - struct BuiltinInfo - { - BuiltinVarying dxPosition; - BuiltinVarying glPosition; - BuiltinVarying glFragCoord; - BuiltinVarying glPointCoord; - BuiltinVarying glPointSize; - }; - - const BuiltinInfo &builtins(ShaderType shaderType) const { return mBuiltinInfo[shaderType]; } - - bool usesPointSize() const { return mBuiltinInfo[SHADER_VERTEX].glPointSize.enabled; } - - private: - bool packVarying(const PackedVarying &packedVarying); - bool isFree(unsigned int registerRow, - unsigned int registerColumn, - unsigned int varyingRows, - unsigned int varyingColumns) const; - void insert(unsigned int registerRow, - unsigned int registerColumn, - const PackedVarying &packedVarying); - - std::vector mRegisterMap; - std::vector mRegisterList; - - std::vector mBuiltinInfo; -}; - -} // namespace rx - -#endif // LIBANGLE_RENDERER_D3D_VARYINGPACKING_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/VertexBuffer.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/VertexBuffer.cpp index 9efee9db7c..7c2d5aec70 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/VertexBuffer.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/VertexBuffer.cpp @@ -8,18 +8,19 @@ // class with derivations, classes that perform graphics API agnostic vertex buffer operations. #include "libANGLE/renderer/d3d/VertexBuffer.h" + +#include "common/mathutil.h" #include "libANGLE/renderer/d3d/BufferD3D.h" #include "libANGLE/renderer/d3d/RendererD3D.h" #include "libANGLE/VertexAttribute.h" -#include "common/mathutil.h" - namespace rx { +// VertexBuffer Implementation unsigned int VertexBuffer::mNextSerial = 1; -VertexBuffer::VertexBuffer() +VertexBuffer::VertexBuffer() : mRefCount(1) { updateSerial(); } @@ -38,19 +39,34 @@ unsigned int VertexBuffer::getSerial() const return mSerial; } -VertexBufferInterface::VertexBufferInterface(BufferFactoryD3D *factory, bool dynamic) - : mFactory(factory) +void VertexBuffer::addRef() { - mDynamic = dynamic; - mWritePosition = 0; - mReservedSpace = 0; + mRefCount++; +} + +void VertexBuffer::release() +{ + ASSERT(mRefCount > 0); + mRefCount--; + + if (mRefCount == 0) + { + delete this; + } +} - mVertexBuffer = factory->createVertexBuffer(); +// VertexBufferInterface Implementation +VertexBufferInterface::VertexBufferInterface(BufferFactoryD3D *factory, bool dynamic) + : mFactory(factory), mVertexBuffer(factory->createVertexBuffer()), mDynamic(dynamic) +{ } VertexBufferInterface::~VertexBufferInterface() { - delete mVertexBuffer; + if (mVertexBuffer) + { + mVertexBuffer->release(); + } } unsigned int VertexBufferInterface::getSerial() const @@ -69,181 +85,172 @@ gl::Error VertexBufferInterface::setBufferSize(unsigned int size) { return mVertexBuffer->initialize(size, mDynamic); } - else + + return mVertexBuffer->setBufferSize(size); +} + +gl::ErrorOrResult VertexBufferInterface::getSpaceRequired( + const gl::VertexAttribute &attrib, + const gl::VertexBinding &binding, + GLsizei count, + GLsizei instances) const +{ + unsigned int spaceRequired = 0; + ANGLE_TRY_RESULT(mFactory->getVertexSpaceRequired(attrib, binding, count, instances), + spaceRequired); + + // Align to 16-byte boundary + unsigned int alignedSpaceRequired = roundUp(spaceRequired, 16u); + + if (alignedSpaceRequired < spaceRequired) { - return mVertexBuffer->setBufferSize(size); + return gl::OutOfMemory() + << "Vertex buffer overflow in VertexBufferInterface::getSpaceRequired."; } + + return alignedSpaceRequired; } -unsigned int VertexBufferInterface::getWritePosition() const +gl::Error VertexBufferInterface::discard() { - return mWritePosition; + return mVertexBuffer->discard(); } -void VertexBufferInterface::setWritePosition(unsigned int writePosition) +VertexBuffer *VertexBufferInterface::getVertexBuffer() const { - mWritePosition = writePosition; + return mVertexBuffer; } -gl::Error VertexBufferInterface::discard() +// StreamingVertexBufferInterface Implementation +StreamingVertexBufferInterface::StreamingVertexBufferInterface(BufferFactoryD3D *factory, + std::size_t initialSize) + : VertexBufferInterface(factory, true), mWritePosition(0), mReservedSpace(0) { - return mVertexBuffer->discard(); + // TODO(jmadill): Make an initialize method that can return an error. + ANGLE_SWALLOW_ERR(setBufferSize(static_cast(initialSize))); } -gl::Error VertexBufferInterface::storeVertexAttributes(const gl::VertexAttribute &attrib, - GLenum currentValueType, - GLint start, - GLsizei count, - GLsizei instances, - unsigned int *outStreamOffset, - const uint8_t *sourceData) +StreamingVertexBufferInterface::~StreamingVertexBufferInterface() { - gl::Error error(GL_NO_ERROR); +} - unsigned int spaceRequired; - error = mVertexBuffer->getSpaceRequired(attrib, count, instances, &spaceRequired); - if (error.isError()) +gl::Error StreamingVertexBufferInterface::reserveSpace(unsigned int size) +{ + unsigned int curBufferSize = getBufferSize(); + if (size > curBufferSize) + { + ANGLE_TRY(setBufferSize(std::max(size, 3 * curBufferSize / 2))); + mWritePosition = 0; + } + else if (mWritePosition + size > curBufferSize) { - return error; + ANGLE_TRY(discard()); + mWritePosition = 0; } - // Align to 16-byte boundary - unsigned int alignedSpaceRequired = roundUp(spaceRequired, 16u); + return gl::NoError(); +} + +gl::Error StreamingVertexBufferInterface::storeDynamicAttribute(const gl::VertexAttribute &attrib, + const gl::VertexBinding &binding, + GLenum currentValueType, + GLint start, + GLsizei count, + GLsizei instances, + unsigned int *outStreamOffset, + const uint8_t *sourceData) +{ + unsigned int spaceRequired = 0; + ANGLE_TRY_RESULT(getSpaceRequired(attrib, binding, count, instances), spaceRequired); // Protect against integer overflow - if (!IsUnsignedAdditionSafe(mWritePosition, alignedSpaceRequired) || - alignedSpaceRequired < spaceRequired) + angle::CheckedNumeric checkedPosition(mWritePosition); + checkedPosition += spaceRequired; + if (!checkedPosition.IsValid()) { - return gl::Error(GL_OUT_OF_MEMORY, "Internal error, new vertex buffer write position would overflow."); + return gl::OutOfMemory() + << "Internal error, new vertex buffer write position would overflow."; } - error = reserveSpace(mReservedSpace); - if (error.isError()) - { - return error; - } + ANGLE_TRY(reserveSpace(mReservedSpace)); mReservedSpace = 0; - error = mVertexBuffer->storeVertexAttributes(attrib, currentValueType, start, count, instances, mWritePosition, sourceData); - if (error.isError()) - { - return error; - } + ANGLE_TRY(mVertexBuffer->storeVertexAttributes(attrib, binding, currentValueType, start, count, + instances, mWritePosition, sourceData)); if (outStreamOffset) { *outStreamOffset = mWritePosition; } - mWritePosition += alignedSpaceRequired; + mWritePosition += spaceRequired; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error VertexBufferInterface::reserveVertexSpace(const gl::VertexAttribute &attrib, GLsizei count, GLsizei instances) +gl::Error StreamingVertexBufferInterface::reserveVertexSpace(const gl::VertexAttribute &attrib, + const gl::VertexBinding &binding, + 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; - } + unsigned int requiredSpace = 0; + ANGLE_TRY_RESULT(mFactory->getVertexSpaceRequired(attrib, binding, count, instances), + requiredSpace); // Align to 16-byte boundary - unsigned int alignedRequiredSpace = roundUp(requiredSpace, 16u); + auto alignedRequiredSpace = rx::CheckedRoundUp(requiredSpace, 16u); + alignedRequiredSpace += mReservedSpace; // Protect against integer overflow - if (!IsUnsignedAdditionSafe(mReservedSpace, alignedRequiredSpace) || - alignedRequiredSpace < requiredSpace) + if (!alignedRequiredSpace.IsValid()) { - return gl::Error(GL_OUT_OF_MEMORY, "Unable to reserve %u extra bytes in internal vertex buffer, " - "it would result in an overflow.", requiredSpace); + return gl::OutOfMemory() + << "Unable to reserve " << requiredSpace + << " extra bytes in internal vertex buffer, it would result in an overflow."; } - mReservedSpace += alignedRequiredSpace; + mReservedSpace = alignedRequiredSpace.ValueOrDie(); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -VertexBuffer* VertexBufferInterface::getVertexBuffer() const +// StaticVertexBufferInterface Implementation +StaticVertexBufferInterface::AttributeSignature::AttributeSignature() + : type(GL_NONE), size(0), stride(0), normalized(false), pureInteger(false), offset(0) { - return mVertexBuffer; } -bool VertexBufferInterface::directStoragePossible(const gl::VertexAttribute &attrib, - GLenum currentValueType) const +bool StaticVertexBufferInterface::AttributeSignature::matchesAttribute( + const gl::VertexAttribute &attrib, + const gl::VertexBinding &binding) const { - gl::Buffer *buffer = attrib.buffer.get(); - BufferD3D *storage = buffer ? GetImplAs(buffer) : NULL; + size_t attribStride = ComputeVertexAttributeStride(attrib, binding); - if (!storage || !storage->supportsDirectBinding()) + if (type != attrib.type || size != attrib.size || static_cast(stride) != attribStride || + normalized != attrib.normalized || pureInteger != attrib.pureInteger) { 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::VertexFormatType vertexFormatType = gl::GetVertexFormatType(attrib, currentValueType); - - unsigned int outputElementSize; - getVertexBuffer()->getSpaceRequired(attrib, 1, 0, &outputElementSize); - alignment = std::min(outputElementSize, 4); - - // TODO(jmadill): add VertexFormatCaps - requiresConversion = (mFactory->getVertexConversionType(vertexFormatType) & VERTEX_CONVERT_CPU) != 0; - } - - bool isAligned = (static_cast(ComputeVertexAttributeStride(attrib)) % alignment == 0) && - (static_cast(attrib.offset) % alignment == 0); - - return !requiresConversion && isAligned; + size_t attribOffset = + (static_cast(ComputeVertexAttributeOffset(attrib, binding)) % attribStride); + return (offset == attribOffset); } -StreamingVertexBufferInterface::StreamingVertexBufferInterface(BufferFactoryD3D *factory, std::size_t initialSize) - : VertexBufferInterface(factory, true) +void StaticVertexBufferInterface::AttributeSignature::set(const gl::VertexAttribute &attrib, + const gl::VertexBinding &binding) { - setBufferSize(static_cast(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); + type = attrib.type; + size = attrib.size; + normalized = attrib.normalized; + pureInteger = attrib.pureInteger; + offset = stride = static_cast(ComputeVertexAttributeStride(attrib, binding)); + offset = static_cast(ComputeVertexAttributeOffset(attrib, binding)) % + ComputeVertexAttributeStride(attrib, binding); } StaticVertexBufferInterface::StaticVertexBufferInterface(BufferFactoryD3D *factory) - : VertexBufferInterface(factory, false), mIsCommitted(false) + : VertexBufferInterface(factory, false) { } @@ -251,82 +258,36 @@ StaticVertexBufferInterface::~StaticVertexBufferInterface() { } -bool StaticVertexBufferInterface::lookupAttribute(const gl::VertexAttribute &attrib, unsigned int *outStreamOffset) +bool StaticVertexBufferInterface::matchesAttribute(const gl::VertexAttribute &attrib, + const gl::VertexBinding &binding) const { - for (unsigned int element = 0; element < mCache.size(); element++) - { - size_t attribStride = ComputeVertexAttributeStride(attrib); - - if (mCache[element].type == attrib.type && mCache[element].size == attrib.size && - mCache[element].stride == attribStride && - mCache[element].normalized == attrib.normalized && - mCache[element].pureInteger == attrib.pureInteger) - { - size_t offset = (static_cast(attrib.offset) % attribStride); - if (mCache[element].attributeOffset == offset) - { - if (outStreamOffset) - { - *outStreamOffset = mCache[element].streamOffset; - } - return true; - } - } - } - - return false; + return mSignature.matchesAttribute(attrib, binding); } -gl::Error StaticVertexBufferInterface::reserveSpace(unsigned int size) +void StaticVertexBufferInterface::setAttribute(const gl::VertexAttribute &attrib, + const gl::VertexBinding &binding) { - 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."); - } + return mSignature.set(attrib, binding); } -gl::Error StaticVertexBufferInterface::storeVertexAttributes(const gl::VertexAttribute &attrib, - GLenum currentValueType, - GLint start, - GLsizei count, - GLsizei instances, - unsigned int *outStreamOffset, - const uint8_t *sourceData) +gl::Error StaticVertexBufferInterface::storeStaticAttribute(const gl::VertexAttribute &attrib, + const gl::VertexBinding &binding, + GLint start, + GLsizei count, + GLsizei instances, + const uint8_t *sourceData) { - unsigned int streamOffset; - gl::Error error = VertexBufferInterface::storeVertexAttributes(attrib, currentValueType, start, count, instances, &streamOffset, sourceData); - if (error.isError()) - { - return error; - } + unsigned int spaceRequired = 0; + ANGLE_TRY_RESULT(getSpaceRequired(attrib, binding, count, instances), spaceRequired); + ANGLE_TRY(setBufferSize(spaceRequired)); - 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; - } + ASSERT(attrib.enabled); + ANGLE_TRY(mVertexBuffer->storeVertexAttributes(attrib, binding, GL_NONE, start, count, + instances, 0, sourceData)); - return gl::Error(GL_NO_ERROR); + mSignature.set(attrib, binding); + mVertexBuffer->hintUnmapResource(); + return gl::NoError(); } -void StaticVertexBufferInterface::commit() -{ - if (getBufferSize() > 0) - { - mIsCommitted = true; - } -} -} +} // namespace rx diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/VertexBuffer.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/VertexBuffer.h index 692b6ac506..df8085d3cb 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/VertexBuffer.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/VertexBuffer.h @@ -22,6 +22,7 @@ namespace gl { struct VertexAttribute; +class VertexBinding; struct VertexAttribCurrentValueData; } @@ -29,23 +30,25 @@ namespace rx { class BufferFactoryD3D; +// Use a ref-counting scheme with self-deletion on release. We do this so that we can more +// easily manage the static buffer cache, without deleting currently bound buffers. class VertexBuffer : angle::NonCopyable { public: VertexBuffer(); - virtual ~VertexBuffer(); virtual gl::Error initialize(unsigned int size, bool dynamicUsage) = 0; + // Warning: you should ensure binding really matches attrib.bindingIndex before using this + // function. virtual gl::Error storeVertexAttributes(const gl::VertexAttribute &attrib, + const gl::VertexBinding &binding, GLenum currentValueType, GLint start, GLsizei count, GLsizei instances, unsigned int offset, const uint8_t *sourceData) = 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; @@ -56,12 +59,18 @@ class VertexBuffer : angle::NonCopyable // This may be overridden (e.g. by VertexBuffer11) if necessary. virtual void hintUnmapResource() { }; + // Reference counting. + void addRef(); + void release(); + protected: void updateSerial(); + virtual ~VertexBuffer(); private: unsigned int mSerial; static unsigned int mNextSerial; + unsigned int mRefCount; }; class VertexBufferInterface : angle::NonCopyable @@ -70,42 +79,24 @@ class VertexBufferInterface : angle::NonCopyable VertexBufferInterface(BufferFactoryD3D *factory, bool dynamic); virtual ~VertexBufferInterface(); - gl::Error reserveVertexSpace(const gl::VertexAttribute &attribute, GLsizei count, GLsizei instances); - unsigned int getBufferSize() const; + bool empty() const { return getBufferSize() == 0; } unsigned int getSerial() const; - virtual gl::Error storeVertexAttributes(const gl::VertexAttribute &attrib, - GLenum currentValueType, - GLint start, - GLsizei count, - GLsizei instances, - unsigned int *outStreamOffset, - const uint8_t *sourceData); - - bool directStoragePossible(const gl::VertexAttribute &attrib, - GLenum currentValueType) const; - - VertexBuffer* getVertexBuffer() 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: + gl::ErrorOrResult getSpaceRequired(const gl::VertexAttribute &attrib, + const gl::VertexBinding &binding, + GLsizei count, + GLsizei instances) const; BufferFactoryD3D *const mFactory; - - VertexBuffer* mVertexBuffer; - - unsigned int mWritePosition; - unsigned int mReservedSpace; + VertexBuffer *mVertexBuffer; bool mDynamic; }; @@ -113,53 +104,72 @@ class StreamingVertexBufferInterface : public VertexBufferInterface { public: StreamingVertexBufferInterface(BufferFactoryD3D *factory, std::size_t initialSize); - ~StreamingVertexBufferInterface(); + ~StreamingVertexBufferInterface() override; - protected: + gl::Error storeDynamicAttribute(const gl::VertexAttribute &attrib, + const gl::VertexBinding &binding, + GLenum currentValueType, + GLint start, + GLsizei count, + GLsizei instances, + unsigned int *outStreamOffset, + const uint8_t *sourceData); + + gl::Error reserveVertexSpace(const gl::VertexAttribute &attribute, + const gl::VertexBinding &binding, + GLsizei count, + GLsizei instances); + + private: gl::Error reserveSpace(unsigned int size); + + unsigned int mWritePosition; + unsigned int mReservedSpace; }; class StaticVertexBufferInterface : public VertexBufferInterface { public: explicit StaticVertexBufferInterface(BufferFactoryD3D *factory); - ~StaticVertexBufferInterface(); + ~StaticVertexBufferInterface() override; - gl::Error storeVertexAttributes(const gl::VertexAttribute &attrib, - GLenum currentValueType, - GLint start, - GLsizei count, - GLsizei instances, - unsigned int *outStreamOffset, - const uint8_t *sourceData) override; - - bool lookupAttribute(const gl::VertexAttribute &attribute, unsigned int* outStreamFffset); + // Warning: you should ensure binding really matches attrib.bindingIndex before using these + // functions. + gl::Error storeStaticAttribute(const gl::VertexAttribute &attrib, + const gl::VertexBinding &binding, + GLint start, + GLsizei count, + GLsizei instances, + const uint8_t *sourceData); - // If a static vertex buffer is committed then no more attribute data can be added to it - // A new static vertex buffer should be created instead - void commit(); - bool isCommitted() { return mIsCommitted; } + bool matchesAttribute(const gl::VertexAttribute &attribute, + const gl::VertexBinding &binding) const; - protected: - gl::Error reserveSpace(unsigned int size); + void setAttribute(const gl::VertexAttribute &attribute, const gl::VertexBinding &binding); private: - struct VertexElement + class AttributeSignature final : angle::NonCopyable { + public: + AttributeSignature(); + + bool matchesAttribute(const gl::VertexAttribute &attrib, + const gl::VertexBinding &binding) const; + + void set(const gl::VertexAttribute &attrib, const gl::VertexBinding &binding); + + private: GLenum type; GLuint size; GLuint stride; bool normalized; bool pureInteger; - size_t attributeOffset; - - unsigned int streamOffset; + size_t offset; }; - bool mIsCommitted; - std::vector mCache; + AttributeSignature mSignature; }; -} +} // namespace rx #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 index b392d0f4da..54ad5e54f5 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/VertexDataManager.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/VertexDataManager.cpp @@ -9,25 +9,38 @@ #include "libANGLE/renderer/d3d/VertexDataManager.h" +#include "common/bitset_utils.h" #include "libANGLE/Buffer.h" +#include "libANGLE/Context.h" #include "libANGLE/Program.h" #include "libANGLE/State.h" -#include "libANGLE/VertexAttribute.h" #include "libANGLE/VertexArray.h" +#include "libANGLE/VertexAttribute.h" +#include "libANGLE/formatutils.h" #include "libANGLE/renderer/d3d/BufferD3D.h" +#include "libANGLE/renderer/d3d/RendererD3D.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 }; -} +using namespace angle; namespace rx { +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 +}; -static int ElementsInBuffer(const gl::VertexAttribute &attrib, unsigned int size) +// Warning: you should ensure binding really matches attrib.bindingIndex before using this function. +int ElementsInBuffer(const gl::VertexAttribute &attrib, + const gl::VertexBinding &binding, + unsigned int size) { // Size cannot be larger than a GLsizei if (size > static_cast(std::numeric_limits::max())) @@ -35,15 +48,139 @@ static int ElementsInBuffer(const gl::VertexAttribute &attrib, unsigned int size size = static_cast(std::numeric_limits::max()); } - GLsizei stride = static_cast(ComputeVertexAttributeStride(attrib)); - return (size - attrib.offset % stride + + GLsizei stride = static_cast(ComputeVertexAttributeStride(attrib, binding)); + GLsizei offset = static_cast(ComputeVertexAttributeOffset(attrib, binding)); + return (size - offset % stride + (stride - static_cast(ComputeVertexAttributeTypeSize(attrib)))) / stride; } -VertexDataManager::CurrentValueState::CurrentValueState() - : buffer(nullptr), - offset(0) +// Warning: you should ensure binding really matches attrib.bindingIndex before using this function. +bool DirectStoragePossible(const gl::VertexAttribute &attrib, const gl::VertexBinding &binding) +{ + // Current value attribs may not use direct storage. + if (!attrib.enabled) + { + return false; + } + + gl::Buffer *buffer = binding.getBuffer().get(); + if (!buffer) + { + return false; + } + + BufferD3D *bufferD3D = GetImplAs(buffer); + ASSERT(bufferD3D); + if (!bufferD3D->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; + + // TODO(jmadill): add VertexFormatCaps + BufferFactoryD3D *factory = bufferD3D->getFactory(); + + gl::VertexFormatType vertexFormatType = gl::GetVertexFormatType(attrib); + + // CPU-converted vertex data must be converted (naturally). + if ((factory->getVertexConversionType(vertexFormatType) & VERTEX_CONVERT_CPU) != 0) + { + return false; + } + + if (attrib.type != GL_FLOAT) + { + auto errorOrElementSize = factory->getVertexSpaceRequired(attrib, binding, 1, 0); + if (errorOrElementSize.isError()) + { + ERR() << "Unlogged error in DirectStoragePossible."; + return false; + } + + alignment = std::min(errorOrElementSize.getResult(), 4); + } + + GLintptr offset = ComputeVertexAttributeOffset(attrib, binding); + // Final alignment check - unaligned data must be converted. + return (static_cast(ComputeVertexAttributeStride(attrib, binding)) % alignment == 0) && + (static_cast(offset) % alignment == 0); +} +} // anonymous namespace + +TranslatedAttribute::TranslatedAttribute() + : active(false), + attribute(nullptr), + binding(nullptr), + currentValueType(GL_NONE), + baseOffset(0), + usesFirstVertexOffset(false), + stride(0), + vertexBuffer(), + storage(nullptr), + serial(0), + divisor(0) +{ +} + +TranslatedAttribute::TranslatedAttribute(const TranslatedAttribute &other) = default; + +gl::ErrorOrResult TranslatedAttribute::computeOffset(GLint startVertex) const +{ + if (!usesFirstVertexOffset) + { + return baseOffset; + } + + CheckedNumeric offset; + + offset = baseOffset + stride * static_cast(startVertex); + ANGLE_TRY_CHECKED_MATH(offset); + return offset.ValueOrDie(); +} + +// Warning: you should ensure binding really matches attrib.bindingIndex before using this function. +VertexStorageType ClassifyAttributeStorage(const gl::VertexAttribute &attrib, + const gl::VertexBinding &binding) +{ + // If attribute is disabled, we use the current value. + if (!attrib.enabled) + { + return VertexStorageType::CURRENT_VALUE; + } + + // If specified with immediate data, we must use dynamic storage. + auto *buffer = binding.getBuffer().get(); + if (!buffer) + { + return VertexStorageType::DYNAMIC; + } + + // Check if the buffer supports direct storage. + if (DirectStoragePossible(attrib, binding)) + { + return VertexStorageType::DIRECT; + } + + // Otherwise the storage is static or dynamic. + BufferD3D *bufferD3D = GetImplAs(buffer); + ASSERT(bufferD3D); + switch (bufferD3D->getUsage()) + { + case D3DBufferUsage::DYNAMIC: + return VertexStorageType::DYNAMIC; + case D3DBufferUsage::STATIC: + return VertexStorageType::STATIC; + default: + UNREACHABLE(); + return VertexStorageType::UNKNOWN; + } +} + +VertexDataManager::CurrentValueState::CurrentValueState() : buffer(), offset(0) { data.FloatValues[0] = std::numeric_limits::quiet_NaN(); data.FloatValues[1] = std::numeric_limits::quiet_NaN(); @@ -54,379 +191,456 @@ VertexDataManager::CurrentValueState::CurrentValueState() VertexDataManager::CurrentValueState::~CurrentValueState() { - SafeDelete(buffer); } VertexDataManager::VertexDataManager(BufferFactoryD3D *factory) - : mFactory(factory), - mStreamingBuffer(nullptr), - // TODO(jmadill): use context caps - mCurrentValueCache(gl::MAX_VERTEX_ATTRIBS) + : mFactory(factory), mStreamingBuffer(), mCurrentValueCache(gl::MAX_VERTEX_ATTRIBS) { - mStreamingBuffer = new StreamingVertexBufferInterface(factory, INITIAL_STREAM_BUFFER_SIZE); - - if (!mStreamingBuffer) - { - ERR("Failed to allocate the streaming vertex buffer."); - } - - // TODO(jmadill): use context caps - mActiveEnabledAttributes.reserve(gl::MAX_VERTEX_ATTRIBS); - mActiveDisabledAttributes.reserve(gl::MAX_VERTEX_ATTRIBS); } VertexDataManager::~VertexDataManager() { - SafeDelete(mStreamingBuffer); } -void VertexDataManager::hintUnmapAllResources(const std::vector &vertexAttributes) +gl::Error VertexDataManager::initialize() { - mStreamingBuffer->getVertexBuffer()->hintUnmapResource(); - - for (const TranslatedAttribute *translated : mActiveEnabledAttributes) + mStreamingBuffer.reset( + new StreamingVertexBufferInterface(mFactory, INITIAL_STREAM_BUFFER_SIZE)); + if (!mStreamingBuffer) { - gl::Buffer *buffer = translated->attribute->buffer.get(); - BufferD3D *storage = buffer ? GetImplAs(buffer) : nullptr; - StaticVertexBufferInterface *staticBuffer = - storage - ? storage->getStaticVertexBuffer(*translated->attribute, D3D_BUFFER_DO_NOT_CREATE) - : nullptr; - - if (staticBuffer) - { - // Commit all the static vertex buffers. This fixes them in size/contents, and forces - // ANGLE to use a new static buffer (or recreate the static buffers) next time - staticBuffer->commit(); - - staticBuffer->getVertexBuffer()->hintUnmapResource(); - } + return gl::OutOfMemory() << "Failed to allocate the streaming vertex buffer."; } - for (auto ¤tValue : mCurrentValueCache) - { - if (currentValue.buffer != nullptr) - { - currentValue.buffer->getVertexBuffer()->hintUnmapResource(); - } - } + return gl::NoError(); } -gl::Error VertexDataManager::prepareVertexData(const gl::State &state, +void VertexDataManager::deinitialize() +{ + mStreamingBuffer.reset(); + mCurrentValueCache.clear(); +} + +gl::Error VertexDataManager::prepareVertexData(const gl::Context *context, GLint start, GLsizei count, std::vector *translatedAttribs, GLsizei instances) { - if (!mStreamingBuffer) - { - return gl::Error(GL_OUT_OF_MEMORY, "Internal streaming vertex buffer is unexpectedly NULL."); - } + ASSERT(mStreamingBuffer); - // Compute active enabled and active disable attributes, for speed. - // TODO(jmadill): don't recompute if there was no state change + const gl::State &state = context->getGLState(); const gl::VertexArray *vertexArray = state.getVertexArray(); - const gl::Program *program = state.getProgram(); const auto &vertexAttributes = vertexArray->getVertexAttributes(); + const auto &vertexBindings = vertexArray->getVertexBindings(); + + mDynamicAttribsMaskCache.reset(); + const gl::Program *program = state.getProgram(); - mActiveEnabledAttributes.clear(); - mActiveDisabledAttributes.clear(); translatedAttribs->clear(); for (size_t attribIndex = 0; attribIndex < vertexAttributes.size(); ++attribIndex) { - if (program->isAttribLocationActive(attribIndex)) - { - // Resize automatically puts in empty attribs - translatedAttribs->resize(attribIndex + 1); + // Skip attrib locations the program doesn't use. + if (!program->isAttribLocationActive(attribIndex)) + continue; + + const auto &attrib = vertexAttributes[attribIndex]; + const auto &binding = vertexBindings[attrib.bindingIndex]; - TranslatedAttribute *translated = &(*translatedAttribs)[attribIndex]; + // Resize automatically puts in empty attribs + translatedAttribs->resize(attribIndex + 1); - // Record the attribute now - translated->active = true; - translated->attribute = &vertexAttributes[attribIndex]; - translated->currentValueType = - state.getVertexAttribCurrentValue(static_cast(attribIndex)).Type; - translated->divisor = vertexAttributes[attribIndex].divisor; + TranslatedAttribute *translated = &(*translatedAttribs)[attribIndex]; + auto currentValueData = state.getVertexAttribCurrentValue(attribIndex); - if (vertexAttributes[attribIndex].enabled) + // Record the attribute now + translated->active = true; + translated->attribute = &attrib; + translated->binding = &binding; + translated->currentValueType = currentValueData.Type; + translated->divisor = binding.getDivisor(); + + switch (ClassifyAttributeStorage(attrib, binding)) + { + case VertexStorageType::STATIC: { - mActiveEnabledAttributes.push_back(translated); - - gl::Buffer *buffer = vertexAttributes[attribIndex].buffer.get(); - if (buffer) - { - // Also reinitialize static buffers which didn't contain matching data - // last time they were used - BufferD3D *bufferImpl = GetImplAs(buffer); - bufferImpl->reinitOutOfDateStaticData(); - } + // Store static attribute. + ANGLE_TRY(StoreStaticAttrib(context, translated)); + break; } - else + case VertexStorageType::DYNAMIC: + // Dynamic attributes must be handled together. + mDynamicAttribsMaskCache.set(attribIndex); + break; + case VertexStorageType::DIRECT: + // Update translated data for direct attributes. + StoreDirectAttrib(translated); + break; + case VertexStorageType::CURRENT_VALUE: { - mActiveDisabledAttributes.push_back(attribIndex); + ANGLE_TRY(storeCurrentValue(currentValueData, translated, attribIndex)); + break; } + default: + UNREACHABLE(); + break; } } - // Reserve the required space in the buffers - for (const TranslatedAttribute *activeAttrib : mActiveEnabledAttributes) + if (mDynamicAttribsMaskCache.none()) { - gl::Error error = reserveSpaceForAttrib(*activeAttrib, count, instances); - if (error.isError()) - { - return error; - } + return gl::NoError(); } - // Perform the vertex data translations - for (TranslatedAttribute *activeAttrib : mActiveEnabledAttributes) + ANGLE_TRY(storeDynamicAttribs(context, translatedAttribs, mDynamicAttribsMaskCache, start, + count, instances)); + + PromoteDynamicAttribs(context, *translatedAttribs, mDynamicAttribsMaskCache, count); + + return gl::NoError(); +} + +// static +void VertexDataManager::StoreDirectAttrib(TranslatedAttribute *directAttrib) +{ + ASSERT(directAttrib->attribute && directAttrib->binding); + const auto &attrib = *directAttrib->attribute; + const auto &binding = *directAttrib->binding; + + gl::Buffer *buffer = binding.getBuffer().get(); + ASSERT(buffer); + BufferD3D *bufferD3D = GetImplAs(buffer); + + ASSERT(DirectStoragePossible(attrib, binding)); + directAttrib->vertexBuffer.set(nullptr); + directAttrib->storage = bufferD3D; + directAttrib->serial = bufferD3D->getSerial(); + directAttrib->stride = static_cast(ComputeVertexAttributeStride(attrib, binding)); + directAttrib->baseOffset = + static_cast(ComputeVertexAttributeOffset(attrib, binding)); + + // Instanced vertices do not apply the 'start' offset + directAttrib->usesFirstVertexOffset = (binding.getDivisor() == 0); +} + +// static +gl::Error VertexDataManager::StoreStaticAttrib(const gl::Context *context, + TranslatedAttribute *translated) +{ + ASSERT(translated->attribute && translated->binding); + const auto &attrib = *translated->attribute; + const auto &binding = *translated->binding; + + gl::Buffer *buffer = binding.getBuffer().get(); + ASSERT(buffer && attrib.enabled && !DirectStoragePossible(attrib, binding)); + BufferD3D *bufferD3D = GetImplAs(buffer); + + // Compute source data pointer + const uint8_t *sourceData = nullptr; + const int offset = static_cast(ComputeVertexAttributeOffset(attrib, binding)); + + ANGLE_TRY(bufferD3D->getData(context, &sourceData)); + sourceData += offset; + + unsigned int streamOffset = 0; + + translated->storage = nullptr; + ANGLE_TRY_RESULT(bufferD3D->getFactory()->getVertexSpaceRequired(attrib, binding, 1, 0), + translated->stride); + + auto *staticBuffer = bufferD3D->getStaticVertexBuffer(attrib, binding); + ASSERT(staticBuffer); + + if (staticBuffer->empty()) { - gl::Error error = storeAttribute(activeAttrib, start, count, instances); + // Convert the entire buffer + int totalCount = + ElementsInBuffer(attrib, binding, static_cast(bufferD3D->getSize())); + int startIndex = offset / static_cast(ComputeVertexAttributeStride(attrib, binding)); - if (error.isError()) - { - hintUnmapAllResources(vertexAttributes); - return error; - } + ANGLE_TRY(staticBuffer->storeStaticAttribute(attrib, binding, -startIndex, totalCount, 0, + sourceData)); } - for (size_t attribIndex : mActiveDisabledAttributes) + unsigned int firstElementOffset = + (static_cast(offset) / + static_cast(ComputeVertexAttributeStride(attrib, binding))) * + translated->stride; + + VertexBuffer *vertexBuffer = staticBuffer->getVertexBuffer(); + + CheckedNumeric checkedOffset(streamOffset); + checkedOffset += firstElementOffset; + + if (!checkedOffset.IsValid()) { - if (mCurrentValueCache[attribIndex].buffer == nullptr) - { - mCurrentValueCache[attribIndex].buffer = new StreamingVertexBufferInterface(mFactory, CONSTANT_VERTEX_BUFFER_SIZE); - } + return gl::InternalError() << "Integer overflow in VertexDataManager::StoreStaticAttrib"; + } + + translated->vertexBuffer.set(vertexBuffer); + translated->serial = vertexBuffer->getSerial(); + translated->baseOffset = streamOffset + firstElementOffset; + + // Instanced vertices do not apply the 'start' offset + translated->usesFirstVertexOffset = (binding.getDivisor() == 0); - gl::Error error = storeCurrentValue( - state.getVertexAttribCurrentValue(static_cast(attribIndex)), - &(*translatedAttribs)[attribIndex], &mCurrentValueCache[attribIndex]); - if (error.isError()) + return gl::NoError(); +} + +gl::Error VertexDataManager::storeDynamicAttribs( + const gl::Context *context, + std::vector *translatedAttribs, + const gl::AttributesMask &dynamicAttribsMask, + GLint start, + GLsizei count, + GLsizei instances) +{ + // Instantiating this class will ensure the streaming buffer is never left mapped. + class StreamingBufferUnmapper final : NonCopyable + { + public: + StreamingBufferUnmapper(StreamingVertexBufferInterface *streamingBuffer) + : mStreamingBuffer(streamingBuffer) { - hintUnmapAllResources(vertexAttributes); - return error; + ASSERT(mStreamingBuffer); } + ~StreamingBufferUnmapper() { mStreamingBuffer->getVertexBuffer()->hintUnmapResource(); } + + private: + StreamingVertexBufferInterface *mStreamingBuffer; + }; + + // Will trigger unmapping on return. + StreamingBufferUnmapper localUnmapper(mStreamingBuffer.get()); + + // Reserve the required space for the dynamic buffers. + for (auto attribIndex : dynamicAttribsMask) + { + const auto &dynamicAttrib = (*translatedAttribs)[attribIndex]; + ANGLE_TRY(reserveSpaceForAttrib(dynamicAttrib, start, count, instances)); + } + + // Store dynamic attributes + for (auto attribIndex : dynamicAttribsMask) + { + auto *dynamicAttrib = &(*translatedAttribs)[attribIndex]; + ANGLE_TRY(storeDynamicAttrib(context, dynamicAttrib, start, count, instances)); } - // Hint to unmap all the resources - hintUnmapAllResources(vertexAttributes); + return gl::NoError(); +} - for (const TranslatedAttribute *activeAttrib : mActiveEnabledAttributes) +void VertexDataManager::PromoteDynamicAttribs( + const gl::Context *context, + const std::vector &translatedAttribs, + const gl::AttributesMask &dynamicAttribsMask, + GLsizei count) +{ + for (auto attribIndex : dynamicAttribsMask) { - gl::Buffer *buffer = activeAttrib->attribute->buffer.get(); + const auto &dynamicAttrib = translatedAttribs[attribIndex]; + ASSERT(dynamicAttrib.attribute && dynamicAttrib.binding); + const auto &binding = *dynamicAttrib.binding; + gl::Buffer *buffer = binding.getBuffer().get(); if (buffer) { BufferD3D *bufferD3D = GetImplAs(buffer); - size_t typeSize = ComputeVertexAttributeTypeSize(*activeAttrib->attribute); - bufferD3D->promoteStaticUsage(count * static_cast(typeSize)); + size_t typeSize = ComputeVertexAttributeTypeSize(*dynamicAttrib.attribute); + bufferD3D->promoteStaticUsage(context, count * static_cast(typeSize)); } } - - return gl::Error(GL_NO_ERROR); } gl::Error VertexDataManager::reserveSpaceForAttrib(const TranslatedAttribute &translatedAttrib, + GLint start, GLsizei count, GLsizei instances) const { - const gl::VertexAttribute &attrib = *translatedAttrib.attribute; - gl::Buffer *buffer = attrib.buffer.get(); - BufferD3D *bufferImpl = buffer ? GetImplAs(buffer) : NULL; - StaticVertexBufferInterface *staticBuffer = - bufferImpl ? bufferImpl->getStaticVertexBuffer(attrib, D3D_BUFFER_CREATE_IF_NECESSARY) - : NULL; - VertexBufferInterface *vertexBuffer = staticBuffer ? staticBuffer : static_cast(mStreamingBuffer); - - if (!vertexBuffer->directStoragePossible(attrib, translatedAttrib.currentValueType)) + ASSERT(translatedAttrib.attribute && translatedAttrib.binding); + const auto &attrib = *translatedAttrib.attribute; + const auto &binding = *translatedAttrib.binding; + + ASSERT(!DirectStoragePossible(attrib, binding)); + + gl::Buffer *buffer = binding.getBuffer().get(); + BufferD3D *bufferD3D = buffer ? GetImplAs(buffer) : nullptr; + ASSERT(!bufferD3D || bufferD3D->getStaticVertexBuffer(attrib, binding) == nullptr); + + size_t totalCount = gl::ComputeVertexBindingElementCount( + binding.getDivisor(), static_cast(count), static_cast(instances)); + // TODO(jiajia.qin@intel.com): force the index buffer to clamp any out of range indices instead + // of invalid operation here. + if (bufferD3D) { - if (staticBuffer) + // Vertices do not apply the 'start' offset when the divisor is non-zero even when doing + // a non-instanced draw call + GLint firstVertexIndex = binding.getDivisor() > 0 ? 0 : start; + int64_t maxVertexCount = + static_cast(firstVertexIndex) + static_cast(totalCount); + int elementsInBuffer = + ElementsInBuffer(attrib, binding, static_cast(bufferD3D->getSize())); + + if (maxVertexCount > elementsInBuffer) { - if (staticBuffer->getBufferSize() == 0) - { - int totalCount = - ElementsInBuffer(attrib, static_cast(bufferImpl->getSize())); - gl::Error error = staticBuffer->reserveVertexSpace(attrib, totalCount, 0); - if (error.isError()) - { - return error; - } - } - } - else - { - size_t totalCount = ComputeVertexAttributeElementCount(attrib, count, instances); - ASSERT(!bufferImpl || - ElementsInBuffer(attrib, static_cast(bufferImpl->getSize())) >= - static_cast(totalCount)); - - gl::Error error = mStreamingBuffer->reserveVertexSpace( - attrib, static_cast(totalCount), instances); - if (error.isError()) - { - return error; - } + return gl::InvalidOperation() << "Vertex buffer is not big enough for the draw call."; } } - - return gl::Error(GL_NO_ERROR); + return mStreamingBuffer->reserveVertexSpace(attrib, binding, static_cast(totalCount), + instances); } -gl::Error VertexDataManager::storeAttribute(TranslatedAttribute *translated, - GLint start, - GLsizei count, - GLsizei instances) +gl::Error VertexDataManager::storeDynamicAttrib(const gl::Context *context, + TranslatedAttribute *translated, + GLint start, + GLsizei count, + GLsizei instances) { - const gl::VertexAttribute &attrib = *translated->attribute; + ASSERT(translated->attribute && translated->binding); + const auto &attrib = *translated->attribute; + const auto &binding = *translated->binding; - gl::Buffer *buffer = attrib.buffer.get(); + gl::Buffer *buffer = binding.getBuffer().get(); ASSERT(buffer || attrib.pointer); ASSERT(attrib.enabled); - BufferD3D *storage = buffer ? GetImplAs(buffer) : NULL; - StaticVertexBufferInterface *staticBuffer = - storage ? storage->getStaticVertexBuffer(attrib, D3D_BUFFER_DO_NOT_CREATE) : NULL; - VertexBufferInterface *vertexBuffer = staticBuffer ? staticBuffer : static_cast(mStreamingBuffer); - bool directStorage = vertexBuffer->directStoragePossible(attrib, translated->currentValueType); + BufferD3D *storage = buffer ? GetImplAs(buffer) : nullptr; // Instanced vertices do not apply the 'start' offset - GLint firstVertexIndex = (attrib.divisor > 0 ? 0 : start); - - translated->vertexBuffer = vertexBuffer->getVertexBuffer(); - - if (directStorage) - { - translated->storage = storage; - translated->serial = storage->getSerial(); - translated->stride = static_cast(ComputeVertexAttributeStride(attrib)); - translated->offset = static_cast(attrib.offset + translated->stride * firstVertexIndex); - - return gl::Error(GL_NO_ERROR); - } + GLint firstVertexIndex = (binding.getDivisor() > 0 ? 0 : start); // Compute source data pointer const uint8_t *sourceData = nullptr; if (buffer) { - gl::Error error = storage->getData(&sourceData); - if (error.isError()) - { - return error; - } - sourceData += static_cast(attrib.offset); + ANGLE_TRY(storage->getData(context, &sourceData)); + sourceData += static_cast(ComputeVertexAttributeOffset(attrib, binding)); } else { + // Attributes using client memory ignore the VERTEX_ATTRIB_BINDING state. + // https://www.opengl.org/registry/specs/ARB/vertex_attrib_binding.txt sourceData = static_cast(attrib.pointer); } unsigned int streamOffset = 0; - unsigned int outputElementSize = 0; - 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, static_cast(storage->getSize())); - int startIndex = static_cast(attrib.offset) / - static_cast(ComputeVertexAttributeStride(attrib)); - - error = staticBuffer->storeVertexAttributes(attrib, - translated->currentValueType, - -startIndex, - totalCount, - 0, - &streamOffset, - sourceData); - if (error.isError()) - { - return error; - } - } + translated->storage = nullptr; + ANGLE_TRY_RESULT(mFactory->getVertexSpaceRequired(attrib, binding, 1, 0), translated->stride); - unsigned int firstElementOffset = - (static_cast(attrib.offset) / - static_cast(ComputeVertexAttributeStride(attrib))) * - outputElementSize; - ASSERT(attrib.divisor == 0 || firstVertexIndex == 0); - unsigned int startOffset = firstVertexIndex * outputElementSize; - if (streamOffset + firstElementOffset + startOffset < streamOffset) - { - return gl::Error(GL_OUT_OF_MEMORY); - } + size_t totalCount = gl::ComputeVertexBindingElementCount( + binding.getDivisor(), static_cast(count), static_cast(instances)); - streamOffset += firstElementOffset + startOffset; - } - else - { - size_t totalCount = ComputeVertexAttributeElementCount(attrib, count, instances); - gl::Error error = mStreamingBuffer->getVertexBuffer()->getSpaceRequired(attrib, 1, 0, &outputElementSize); - if (error.isError()) - { - return error; - } + ANGLE_TRY(mStreamingBuffer->storeDynamicAttribute( + attrib, binding, translated->currentValueType, firstVertexIndex, + static_cast(totalCount), instances, &streamOffset, sourceData)); - error = mStreamingBuffer->storeVertexAttributes( - attrib, translated->currentValueType, firstVertexIndex, - static_cast(totalCount), instances, &streamOffset, sourceData); - if (error.isError()) - { - return error; - } - } + VertexBuffer *vertexBuffer = mStreamingBuffer->getVertexBuffer(); - translated->storage = nullptr; + translated->vertexBuffer.set(vertexBuffer); translated->serial = vertexBuffer->getSerial(); - translated->stride = outputElementSize; - translated->offset = streamOffset; + translated->baseOffset = streamOffset; + translated->usesFirstVertexOffset = false; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } gl::Error VertexDataManager::storeCurrentValue(const gl::VertexAttribCurrentValueData ¤tValue, TranslatedAttribute *translated, - CurrentValueState *cachedState) + size_t attribIndex) { + CurrentValueState *cachedState = &mCurrentValueCache[attribIndex]; + auto &buffer = cachedState->buffer; + + if (!buffer) + { + buffer.reset(new StreamingVertexBufferInterface(mFactory, CONSTANT_VERTEX_BUFFER_SIZE)); + } + if (cachedState->data != currentValue) { - const gl::VertexAttribute &attrib = *translated->attribute; + ASSERT(translated->attribute && translated->binding); + const auto &attrib = *translated->attribute; + const auto &binding = *translated->binding; - gl::Error error = cachedState->buffer->reserveVertexSpace(attrib, 1, 0); - if (error.isError()) - { - return error; - } + ANGLE_TRY(buffer->reserveVertexSpace(attrib, binding, 1, 0)); const uint8_t *sourceData = reinterpret_cast(currentValue.FloatValues); unsigned int streamOffset; - error = cachedState->buffer->storeVertexAttributes(attrib, currentValue.Type, 0, 1, 0, &streamOffset, sourceData); - if (error.isError()) - { - return error; - } + ANGLE_TRY(buffer->storeDynamicAttribute(attrib, binding, currentValue.Type, 0, 1, 0, + &streamOffset, sourceData)); + + buffer->getVertexBuffer()->hintUnmapResource(); cachedState->data = currentValue; cachedState->offset = streamOffset; } - translated->storage = NULL; - translated->vertexBuffer = cachedState->buffer->getVertexBuffer(); - translated->serial = cachedState->buffer->getSerial(); + translated->vertexBuffer.set(buffer->getVertexBuffer()); + + translated->storage = nullptr; + translated->serial = buffer->getSerial(); translated->divisor = 0; + translated->stride = 0; + translated->baseOffset = static_cast(cachedState->offset); + translated->usesFirstVertexOffset = false; - translated->stride = 0; - translated->offset = static_cast(cachedState->offset); + return gl::NoError(); +} - return gl::Error(GL_NO_ERROR); +// VertexBufferBinding implementation +VertexBufferBinding::VertexBufferBinding() : mBoundVertexBuffer(nullptr) +{ } +VertexBufferBinding::VertexBufferBinding(const VertexBufferBinding &other) + : mBoundVertexBuffer(other.mBoundVertexBuffer) +{ + if (mBoundVertexBuffer) + { + mBoundVertexBuffer->addRef(); + } +} + +VertexBufferBinding::~VertexBufferBinding() +{ + if (mBoundVertexBuffer) + { + mBoundVertexBuffer->release(); + } } + +VertexBufferBinding &VertexBufferBinding::operator=(const VertexBufferBinding &other) +{ + mBoundVertexBuffer = other.mBoundVertexBuffer; + if (mBoundVertexBuffer) + { + mBoundVertexBuffer->addRef(); + } + return *this; +} + +void VertexBufferBinding::set(VertexBuffer *vertexBuffer) +{ + if (mBoundVertexBuffer == vertexBuffer) + return; + + if (mBoundVertexBuffer) + { + mBoundVertexBuffer->release(); + } + if (vertexBuffer) + { + vertexBuffer->addRef(); + } + + mBoundVertexBuffer = vertexBuffer; +} + +VertexBuffer *VertexBufferBinding::get() const +{ + return mBoundVertexBuffer; +} + +} // namespace rx diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/VertexDataManager.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/VertexDataManager.h index fb349c4cc2..694366deb7 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/VertexDataManager.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/VertexDataManager.h @@ -10,14 +10,16 @@ #ifndef LIBANGLE_RENDERER_D3D_VERTEXDATAMANAGER_H_ #define LIBANGLE_RENDERER_D3D_VERTEXDATAMANAGER_H_ +#include "common/angleutils.h" +#include "libANGLE/angletypes.h" #include "libANGLE/Constants.h" #include "libANGLE/VertexAttribute.h" -#include "common/angleutils.h" namespace gl { class State; struct VertexAttribute; +class VertexBinding; struct VertexAttribCurrentValueData; } @@ -28,81 +30,123 @@ class BufferFactoryD3D; class StreamingVertexBufferInterface; class VertexBuffer; +class VertexBufferBinding final +{ + public: + VertexBufferBinding(); + VertexBufferBinding(const VertexBufferBinding &other); + ~VertexBufferBinding(); + + void set(VertexBuffer *vertexBuffer); + VertexBuffer *get() const; + VertexBufferBinding &operator=(const VertexBufferBinding &other); + + private: + VertexBuffer *mBoundVertexBuffer; +}; + struct TranslatedAttribute { - TranslatedAttribute() - : active(false), - attribute(NULL), - currentValueType(GL_NONE), - offset(0), - stride(0), - vertexBuffer(NULL), - storage(NULL), - serial(0), - divisor(0) - {} + TranslatedAttribute(); + TranslatedAttribute(const TranslatedAttribute &other); + + // Computes the correct offset from baseOffset, usesFirstVertexOffset, stride and startVertex. + // Can throw an error on integer overflow. + gl::ErrorOrResult computeOffset(GLint startVertex) const; bool active; const gl::VertexAttribute *attribute; + const gl::VertexBinding *binding; GLenum currentValueType; - unsigned int offset; + unsigned int baseOffset; + bool usesFirstVertexOffset; unsigned int stride; // 0 means not to advance the read pointer at all - VertexBuffer *vertexBuffer; + VertexBufferBinding vertexBuffer; BufferD3D *storage; unsigned int serial; unsigned int divisor; }; +enum class VertexStorageType +{ + UNKNOWN, + STATIC, // Translate the vertex data once and re-use it. + DYNAMIC, // Translate the data every frame into a ring buffer. + DIRECT, // Bind a D3D buffer directly without any translation. + CURRENT_VALUE, // Use a single value for the attribute. +}; + +// Given a vertex attribute, return the type of storage it will use. +VertexStorageType ClassifyAttributeStorage(const gl::VertexAttribute &attrib, + const gl::VertexBinding &binding); + class VertexDataManager : angle::NonCopyable { public: VertexDataManager(BufferFactoryD3D *factory); virtual ~VertexDataManager(); - gl::Error prepareVertexData(const gl::State &state, + gl::Error initialize(); + void deinitialize(); + + gl::Error prepareVertexData(const gl::Context *context, GLint start, GLsizei count, std::vector *translatedAttribs, GLsizei instances); + static void StoreDirectAttrib(TranslatedAttribute *directAttrib); + + static gl::Error StoreStaticAttrib(const gl::Context *context, TranslatedAttribute *translated); + + gl::Error storeDynamicAttribs(const gl::Context *context, + std::vector *translatedAttribs, + const gl::AttributesMask &dynamicAttribsMask, + GLint start, + GLsizei count, + GLsizei instances); + + // Promote static usage of dynamic buffers. + static void PromoteDynamicAttribs(const gl::Context *context, + const std::vector &translatedAttribs, + const gl::AttributesMask &dynamicAttribsMask, + GLsizei count); + + gl::Error storeCurrentValue(const gl::VertexAttribCurrentValueData ¤tValue, + TranslatedAttribute *translated, + size_t attribIndex); + private: struct CurrentValueState { CurrentValueState(); ~CurrentValueState(); - StreamingVertexBufferInterface *buffer; + std::unique_ptr buffer; gl::VertexAttribCurrentValueData data; size_t offset; }; gl::Error reserveSpaceForAttrib(const TranslatedAttribute &translatedAttrib, GLsizei count, + GLint start, GLsizei instances) const; - gl::Error storeAttribute(TranslatedAttribute *translated, - GLint start, - GLsizei count, - GLsizei instances); - - gl::Error storeCurrentValue(const gl::VertexAttribCurrentValueData ¤tValue, - TranslatedAttribute *translated, - CurrentValueState *cachedState); - - void hintUnmapAllResources(const std::vector &vertexAttributes); + gl::Error storeDynamicAttrib(const gl::Context *context, + TranslatedAttribute *translated, + GLint start, + GLsizei count, + GLsizei instances); BufferFactoryD3D *const mFactory; - StreamingVertexBufferInterface *mStreamingBuffer; + std::unique_ptr mStreamingBuffer; std::vector mCurrentValueCache; - - // Cache variables - std::vector mActiveEnabledAttributes; - std::vector mActiveDisabledAttributes; + gl::AttributesMask mDynamicAttribsMaskCache; }; -} +} // namespace rx #endif // LIBANGLE_RENDERER_D3D_VERTEXDATAMANAGER_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/WorkaroundsD3D.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/WorkaroundsD3D.h deleted file mode 100644 index 58f65f6496..0000000000 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/WorkaroundsD3D.h +++ /dev/null @@ -1,66 +0,0 @@ -// -// 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. -// - -// WorkaroundsD3D.h: Workarounds for D3D driver bugs and other issues. - -#ifndef LIBANGLE_RENDERER_D3D_WORKAROUNDSD3D_H_ -#define LIBANGLE_RENDERER_D3D_WORKAROUNDSD3D_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 -{ - D3DCompilerWorkarounds() - : skipOptimization(false), useMaxOptimization(false), enableIEEEStrictness(false) - { - } - - bool skipOptimization; - bool useMaxOptimization; - - // IEEE strictness needs to be enabled for NANs to work. - bool enableIEEEStrictness; -}; - -struct WorkaroundsD3D -{ - WorkaroundsD3D() - : 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_D3D_WORKAROUNDSD3D_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/copyimage.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/copyimage.cpp deleted file mode 100644 index b1798454ca..0000000000 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/copyimage.cpp +++ /dev/null @@ -1,22 +0,0 @@ -// -// 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 deleted file mode 100644 index 189654ca39..0000000000 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/copyimage.h +++ /dev/null @@ -1,35 +0,0 @@ -// -// 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 deleted file mode 100644 index 0498cf7750..0000000000 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/copyimage.inl +++ /dev/null @@ -1,32 +0,0 @@ -// -// 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 index e951e13408..f032e888f1 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Blit11.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Blit11.cpp @@ -10,112 +10,404 @@ #include +#include "common/utilities.h" #include "libANGLE/formatutils.h" +#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/formatutils11.h" +#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h" +#include "libANGLE/renderer/d3d/d3d11/texture_format_table.h" #include "third_party/trace_event/trace_event.h" +namespace rx +{ + +namespace +{ + +// Include inline shaders in the anonymous namespace to make sure no symbols are exported #include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthrough2d11vs.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthrougha2d11ps.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/passthroughr2d11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughr2di11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughr2dui11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrg2d11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrg2di11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrg2dui11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrgb2d11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrgb2di11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrgb2dui11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrgba2d11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrgba2di11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrgba2dui11ps.h" + +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/multiplyalpha_ftof_pm_luma_ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/multiplyalpha_ftof_pm_lumaalpha_ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/multiplyalpha_ftof_pm_rgb_ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/multiplyalpha_ftof_pm_rgba_ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/multiplyalpha_ftof_um_luma_ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/multiplyalpha_ftof_um_lumaalpha_ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/multiplyalpha_ftof_um_rgb_ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/multiplyalpha_ftof_um_rgba_ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/multiplyalpha_ftou_pm_rgb_ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/multiplyalpha_ftou_pm_rgba_ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/multiplyalpha_ftou_pt_rgb_ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/multiplyalpha_ftou_pt_rgba_ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/multiplyalpha_ftou_um_rgb_ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/multiplyalpha_ftou_um_rgba_ps.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/passthrough3d11vs.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/passthroughr3d11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughr3di11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughr3dui11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrg3d11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrg3di11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrg3dui11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrgb3d11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrgb3di11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrgb3dui11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrgba3d11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrgba3di11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrgba3dui11ps.h" + +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/resolvedepth11_ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/resolvedepthstencil11_ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/resolvedepthstencil11_vs.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/resolvestencil11_ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/swizzlef2darrayps.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/swizzlei2dps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/swizzlei3dps.h" #include "libANGLE/renderer/d3d/d3d11/shaders/compiled/swizzleui2darrayps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/swizzleui2dps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/swizzleui3dps.h" -namespace rx +void StretchedBlitNearest_RowByRow(const gl::Box &sourceArea, + const gl::Box &destArea, + const gl::Rectangle &clippedDestArea, + const gl::Extents &sourceSize, + unsigned int sourceRowPitch, + unsigned int destRowPitch, + size_t pixelSize, + const uint8_t *sourceData, + uint8_t *destData) { + int srcHeightSubOne = (sourceArea.height - 1); + size_t copySize = pixelSize * destArea.width; + size_t srcOffset = sourceArea.x * pixelSize; + size_t destOffset = destArea.x * pixelSize; -namespace + 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 = static_cast( + gl::clamp(sourceArea.y + floor(yPerc * srcHeightSubOne + 0.5f), 0, srcHeightSubOne)); + unsigned int writeRow = y; + + const uint8_t *sourceRow = sourceData + readRow * sourceRowPitch + srcOffset; + uint8_t *destRow = destData + writeRow * destRowPitch + destOffset; + memcpy(destRow, sourceRow, copySize); + } +} + +void StretchedBlitNearest_PixelByPixel(const gl::Box &sourceArea, + const gl::Box &destArea, + const gl::Rectangle &clippedDestArea, + const gl::Extents &sourceSize, + unsigned int sourceRowPitch, + unsigned int destRowPitch, + ptrdiff_t readOffset, + ptrdiff_t writeOffset, + size_t copySize, + size_t srcPixelStride, + size_t destPixelStride, + const uint8_t *sourceData, + uint8_t *destData) { + auto xMax = clippedDestArea.x + clippedDestArea.width; + auto yMax = clippedDestArea.y + clippedDestArea.height; -DXGI_FORMAT GetTextureFormat(ID3D11Resource *resource) + for (int writeRow = clippedDestArea.y; writeRow < yMax; writeRow++) + { + // Interpolate using the original source rectangle to determine which row to sample from + // while clamping to the edges + float yPerc = static_cast(writeRow - destArea.y) / (destArea.height - 1); + float yRounded = floor(yPerc * (sourceArea.height - 1) + 0.5f); + unsigned int readRow = + static_cast(gl::clamp(sourceArea.y + yRounded, 0, sourceSize.height - 1)); + + for (int writeColumn = clippedDestArea.x; writeColumn < xMax; writeColumn++) + { + // Interpolate the original source rectangle to determine which column to sample + // from while clamping to the edges + float xPerc = static_cast(writeColumn - destArea.x) / (destArea.width - 1); + float xRounded = floor(xPerc * (sourceArea.width - 1) + 0.5f); + unsigned int readColumn = static_cast( + gl::clamp(sourceArea.x + xRounded, 0, sourceSize.height - 1)); + + const uint8_t *sourcePixel = + sourceData + readRow * sourceRowPitch + readColumn * srcPixelStride + readOffset; + + uint8_t *destPixel = + destData + writeRow * destRowPitch + writeColumn * destPixelStride + writeOffset; + + memcpy(destPixel, sourcePixel, copySize); + } + } +} + +void StretchedBlitNearest(const gl::Box &sourceArea, + const gl::Box &destArea, + const gl::Rectangle &clipRect, + const gl::Extents &sourceSize, + unsigned int sourceRowPitch, + unsigned int destRowPitch, + ptrdiff_t readOffset, + ptrdiff_t writeOffset, + size_t copySize, + size_t srcPixelStride, + size_t destPixelStride, + const uint8_t *sourceData, + uint8_t *destData) { - ID3D11Texture2D *texture = d3d11::DynamicCastComObject(resource); - if (!texture) + gl::Rectangle clippedDestArea(destArea.x, destArea.y, destArea.width, destArea.height); + gl::ClipRectangle(clippedDestArea, clipRect, &clippedDestArea); + + // Determine if entire rows can be copied at once instead of each individual pixel. There + // must be no out of bounds lookups, whole rows copies, and no scale. + if (sourceArea.width == clippedDestArea.width && sourceArea.x >= 0 && + sourceArea.x + sourceArea.width <= sourceSize.width && copySize == srcPixelStride && + copySize == destPixelStride) + { + StretchedBlitNearest_RowByRow(sourceArea, destArea, clippedDestArea, sourceSize, + sourceRowPitch, destRowPitch, srcPixelStride, sourceData, + destData); + } + else { - return DXGI_FORMAT_UNKNOWN; + StretchedBlitNearest_PixelByPixel(sourceArea, destArea, clippedDestArea, sourceSize, + sourceRowPitch, destRowPitch, readOffset, writeOffset, + copySize, srcPixelStride, destPixelStride, sourceData, + destData); } +} - D3D11_TEXTURE2D_DESC desc; - texture->GetDesc(&desc); +using DepthStencilLoader = void(const float *, uint8_t *); - SafeRelease(texture); +void LoadDepth16(const float *source, uint8_t *dest) +{ + uint32_t convertedDepth = gl::floatToNormalized<16, uint32_t>(source[0]); + memcpy(dest, &convertedDepth, 2u); +} - return desc.Format; +void LoadDepth24(const float *source, uint8_t *dest) +{ + uint32_t convertedDepth = gl::floatToNormalized<24, uint32_t>(source[0]); + memcpy(dest, &convertedDepth, 3u); } -ID3D11Resource *CreateStagingTexture(ID3D11Device *device, ID3D11DeviceContext *context, - ID3D11Resource *source, unsigned int subresource, - const gl::Extents &size, unsigned int cpuAccessFlags) +void LoadStencilHelper(const float *source, uint8_t *dest) { - 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 = nullptr; - HRESULT result = device->CreateTexture2D(&stagingDesc, nullptr, &stagingTexture); - if (FAILED(result)) + uint32_t convertedStencil = gl::getShiftedData<8, 0>(static_cast(source[1])); + memcpy(dest, &convertedStencil, 1u); +} + +void LoadStencil8(const float *source, uint8_t *dest) +{ + // STENCIL_INDEX8 is implemented with D24S8, with the depth bits unused. Writes zero for safety. + float zero = 0.0f; + LoadDepth24(&zero, &dest[0]); + LoadStencilHelper(source, &dest[3]); +} + +void LoadDepth24Stencil8(const float *source, uint8_t *dest) +{ + LoadDepth24(source, &dest[0]); + LoadStencilHelper(source, &dest[3]); +} + +void LoadDepth32F(const float *source, uint8_t *dest) +{ + memcpy(dest, source, sizeof(float)); +} + +void LoadDepth32FStencil8(const float *source, uint8_t *dest) +{ + LoadDepth32F(source, &dest[0]); + LoadStencilHelper(source, &dest[4]); +} + +template +void CopyDepthStencil(const gl::Box &sourceArea, + const gl::Box &destArea, + const gl::Rectangle &clippedDestArea, + const gl::Extents &sourceSize, + unsigned int sourceRowPitch, + unsigned int destRowPitch, + ptrdiff_t readOffset, + ptrdiff_t writeOffset, + size_t copySize, + size_t srcPixelStride, + size_t destPixelStride, + const uint8_t *sourceData, + uint8_t *destData) +{ + // No stretching or subregions are supported, only full blits. + ASSERT(sourceArea == destArea); + ASSERT(sourceSize.width == sourceArea.width && sourceSize.height == sourceArea.height && + sourceSize.depth == 1); + ASSERT(clippedDestArea.width == sourceSize.width && + clippedDestArea.height == sourceSize.height); + ASSERT(readOffset == 0 && writeOffset == 0); + ASSERT(destArea.x == 0 && destArea.y == 0); + + for (int row = 0; row < destArea.height; ++row) + { + for (int column = 0; column < destArea.width; ++column) + { + ptrdiff_t offset = row * sourceRowPitch + column * srcPixelStride; + const float *sourcePixel = reinterpret_cast(sourceData + offset); + + uint8_t *destPixel = destData + row * destRowPitch + column * destPixelStride; + + loader(sourcePixel, destPixel); + } + } +} + +void Depth32FStencil8ToDepth32F(const float *source, float *dest) +{ + *dest = *source; +} + +void Depth24Stencil8ToDepth32F(const uint32_t *source, float *dest) +{ + uint32_t normDepth = source[0] & 0x00FFFFFF; + float floatDepth = gl::normalizedToFloat<24>(normDepth); + *dest = floatDepth; +} + +void BlitD24S8ToD32F(const gl::Box &sourceArea, + const gl::Box &destArea, + const gl::Rectangle &clippedDestArea, + const gl::Extents &sourceSize, + unsigned int sourceRowPitch, + unsigned int destRowPitch, + ptrdiff_t readOffset, + ptrdiff_t writeOffset, + size_t copySize, + size_t srcPixelStride, + size_t destPixelStride, + const uint8_t *sourceData, + uint8_t *destData) +{ + // No stretching or subregions are supported, only full blits. + ASSERT(sourceArea == destArea); + ASSERT(sourceSize.width == sourceArea.width && sourceSize.height == sourceArea.height && + sourceSize.depth == 1); + ASSERT(clippedDestArea.width == sourceSize.width && + clippedDestArea.height == sourceSize.height); + ASSERT(readOffset == 0 && writeOffset == 0); + ASSERT(destArea.x == 0 && destArea.y == 0); + + for (int row = 0; row < destArea.height; ++row) { - ERR("Failed to create staging texture for depth stencil blit. HRESULT: 0x%X.", result); - return nullptr; + for (int column = 0; column < destArea.width; ++column) + { + ptrdiff_t offset = row * sourceRowPitch + column * srcPixelStride; + const uint32_t *sourcePixel = reinterpret_cast(sourceData + offset); + + float *destPixel = + reinterpret_cast(destData + row * destRowPitch + column * destPixelStride); + + Depth24Stencil8ToDepth32F(sourcePixel, destPixel); + } } +} - context->CopySubresourceRegion(stagingTexture, 0, 0, 0, 0, source, subresource, nullptr); +void BlitD32FS8ToD32F(const gl::Box &sourceArea, + const gl::Box &destArea, + const gl::Rectangle &clippedDestArea, + const gl::Extents &sourceSize, + unsigned int sourceRowPitch, + unsigned int destRowPitch, + ptrdiff_t readOffset, + ptrdiff_t writeOffset, + size_t copySize, + size_t srcPixelStride, + size_t destPixelStride, + const uint8_t *sourceData, + uint8_t *destData) +{ + // No stretching or subregions are supported, only full blits. + ASSERT(sourceArea == destArea); + ASSERT(sourceSize.width == sourceArea.width && sourceSize.height == sourceArea.height && + sourceSize.depth == 1); + ASSERT(clippedDestArea.width == sourceSize.width && + clippedDestArea.height == sourceSize.height); + ASSERT(readOffset == 0 && writeOffset == 0); + ASSERT(destArea.x == 0 && destArea.y == 0); + + for (int row = 0; row < destArea.height; ++row) + { + for (int column = 0; column < destArea.width; ++column) + { + ptrdiff_t offset = row * sourceRowPitch + column * srcPixelStride; + const float *sourcePixel = reinterpret_cast(sourceData + offset); + float *destPixel = + reinterpret_cast(destData + row * destRowPitch + column * destPixelStride); - return stagingTexture; + Depth32FStencil8ToDepth32F(sourcePixel, destPixel); + } + } +} + +Blit11::BlitConvertFunction *GetCopyDepthStencilFunction(GLenum internalFormat) +{ + switch (internalFormat) + { + case GL_DEPTH_COMPONENT16: + return &CopyDepthStencil; + case GL_DEPTH_COMPONENT24: + return &CopyDepthStencil; + case GL_DEPTH_COMPONENT32F: + return &CopyDepthStencil; + case GL_STENCIL_INDEX8: + return &CopyDepthStencil; + case GL_DEPTH24_STENCIL8: + return &CopyDepthStencil; + case GL_DEPTH32F_STENCIL8: + return &CopyDepthStencil; + default: + UNREACHABLE(); + return nullptr; + } } -inline 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) +inline 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; @@ -128,37 +420,49 @@ inline void GenerateVertexCoords(const gl::Box &sourceArea, const gl::Extents &s *v2 = (sourceArea.y + sourceArea.height) / float(sourceSize.height); } -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, +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); + GenerateVertexCoords(sourceArea, sourceSize, destArea, destSize, &x1, &y1, &x2, &y2, &u1, &v1, + &u2, &v2); - d3d11::PositionTexCoordVertex *vertices = static_cast(outVertices); + 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); + *outStride = sizeof(d3d11::PositionTexCoordVertex); *outVertexCount = 4; - *outTopology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP; + *outTopology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP; } -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, +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); + GenerateVertexCoords(sourceArea, sourceSize, destArea, destSize, &x1, &y1, &x2, &y2, &u1, &v1, + &u2, &v2); - d3d11::PositionLayerTexCoord3DVertex *vertices = static_cast(outVertices); + d3d11::PositionLayerTexCoord3DVertex *vertices = + static_cast(outVertices); for (int i = 0; i < destSize.depth; i++) { @@ -173,24 +477,38 @@ void Write3DVertices(const gl::Box &sourceArea, const gl::Extents &sourceSize, d3d11::SetPositionLayerTexCoord3DVertex(&vertices[i * 6 + 5], x2, y1, i, u2, v2, readDepth); } - *outStride = sizeof(d3d11::PositionLayerTexCoord3DVertex); + *outStride = sizeof(d3d11::PositionLayerTexCoord3DVertex); *outVertexCount = destSize.depth * 6; - *outTopology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST; + *outTopology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST; } -inline unsigned int GetSwizzleIndex(GLenum swizzle) +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; + 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; @@ -213,30 +531,50 @@ D3D11_BLEND_DESC GetAlphaMaskBlendStateDesc() return desc; } -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 }, +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}, }; -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 }, +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}, }; -} // namespace +DXGI_FORMAT GetStencilSRVFormat(const d3d11::Format &formatSet) +{ + switch (formatSet.texFormat) + { + case DXGI_FORMAT_R32G8X24_TYPELESS: + return DXGI_FORMAT_X32_TYPELESS_G8X24_UINT; + case DXGI_FORMAT_R24G8_TYPELESS: + return DXGI_FORMAT_X24_TYPELESS_G8_UINT; + default: + UNREACHABLE(); + return DXGI_FORMAT_UNKNOWN; + } +} + +} // namespace + +Blit11::Shader::Shader() = default; + +Blit11::Shader::Shader(Shader &&other) = default; + +Blit11::Shader::~Shader() = default; + +Blit11::Shader &Blit11::Shader::operator=(Blit11::Shader &&other) = default; Blit11::Blit11(Renderer11 *renderer) : mRenderer(renderer), mResourcesInitialized(false), - mVertexBuffer(nullptr), - mPointSampler(nullptr), - mLinearSampler(nullptr), - mScissorEnabledRasterizerState(nullptr), - mScissorDisabledRasterizerState(nullptr), - mDepthStencilState(nullptr), + mVertexBuffer(), + mPointSampler(), + mLinearSampler(), + mScissorEnabledRasterizerState(), + mScissorDisabledRasterizerState(), + mDepthStencilState(), mQuad2DIL(quad2DLayout, ArraySize(quad2DLayout), g_VS_Passthrough2D, @@ -254,516 +592,552 @@ Blit11::Blit11(Renderer11 *renderer) mQuad3DVS(g_VS_Passthrough3D, ArraySize(g_VS_Passthrough3D), "Blit11 3D vertex shader"), mQuad3DGS(g_GS_Passthrough3D, ArraySize(g_GS_Passthrough3D), "Blit11 3D geometry shader"), mAlphaMaskBlendState(GetAlphaMaskBlendStateDesc(), "Blit11 Alpha Mask Blend"), - mSwizzleCB(nullptr) + mSwizzleCB(), + mResolveDepthStencilVS(g_VS_ResolveDepthStencil, + ArraySize(g_VS_ResolveDepthStencil), + "Blit11::mResolveDepthStencilVS"), + mResolveDepthPS(g_PS_ResolveDepth, ArraySize(g_PS_ResolveDepth), "Blit11::mResolveDepthPS"), + mResolveDepthStencilPS(g_PS_ResolveDepthStencil, + ArraySize(g_PS_ResolveDepthStencil), + "Blit11::mResolveDepthStencilPS"), + mResolveStencilPS(g_PS_ResolveStencil, + ArraySize(g_PS_ResolveStencil), + "Blit11::mResolveStencilPS"), + mStencilSRV(), + mResolvedDepthStencilRTView() { } Blit11::~Blit11() { - freeResources(); - - mQuad2DIL.release(); - mQuad2DVS.release(); - mDepthPS.release(); - - mQuad3DIL.release(); - mQuad3DVS.release(); - mQuad3DGS.release(); - - clearShaderMap(); } gl::Error Blit11::initResources() { if (mResourcesInitialized) { - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } TRACE_EVENT0("gpu.angle", "Blit11::initResources"); - HRESULT result; - ID3D11Device *device = mRenderer->getDevice(); - D3D11_BUFFER_DESC vbDesc; vbDesc.ByteWidth = static_cast(std::max(sizeof(d3d11::PositionLayerTexCoord3DVertex), sizeof(d3d11::PositionTexCoordVertex)) * - 6 * mRenderer->getRendererCaps().max3DTextureSize); - vbDesc.Usage = D3D11_USAGE_DYNAMIC; - vbDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; - vbDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; - vbDesc.MiscFlags = 0; + 6 * mRenderer->getNativeCaps().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, nullptr, &mVertexBuffer); - ASSERT(SUCCEEDED(result)); - if (FAILED(result)) - { - freeResources(); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create blit vertex buffer, HRESULT: 0x%X", - result); - } - d3d11::SetDebugName(mVertexBuffer, "Blit11 vertex buffer"); + ANGLE_TRY(mRenderer->allocateResource(vbDesc, &mVertexBuffer)); + mVertexBuffer.setDebugName("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.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; + pointSamplerDesc.MinLOD = 0.0f; + pointSamplerDesc.MaxLOD = FLT_MAX; - result = device->CreateSamplerState(&pointSamplerDesc, &mPointSampler); - ASSERT(SUCCEEDED(result)); - if (FAILED(result)) - { - freeResources(); - return gl::Error(GL_OUT_OF_MEMORY, - "Failed to create blit point sampler state, HRESULT: 0x%X", result); - } - d3d11::SetDebugName(mPointSampler, "Blit11 point sampler"); + ANGLE_TRY(mRenderer->allocateResource(pointSamplerDesc, &mPointSampler)); + mPointSampler.setDebugName("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.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; + linearSamplerDesc.MinLOD = 0.0f; + linearSamplerDesc.MaxLOD = FLT_MAX; - result = device->CreateSamplerState(&linearSamplerDesc, &mLinearSampler); - ASSERT(SUCCEEDED(result)); - if (FAILED(result)) - { - freeResources(); - return gl::Error(GL_OUT_OF_MEMORY, - "Failed to create blit linear sampler state, HRESULT: 0x%X", result); - } - d3d11::SetDebugName(mLinearSampler, "Blit11 linear sampler"); + ANGLE_TRY(mRenderer->allocateResource(linearSamplerDesc, &mLinearSampler)); + mLinearSampler.setDebugName("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.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.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)); - if (FAILED(result)) - { - freeResources(); - return gl::Error(GL_OUT_OF_MEMORY, - "Failed to create blit scissoring rasterizer state, HRESULT: 0x%X", - result); - } - d3d11::SetDebugName(mScissorEnabledRasterizerState, "Blit11 scissoring rasterizer state"); + ANGLE_TRY(mRenderer->allocateResource(rasterDesc, &mScissorEnabledRasterizerState)); + mScissorEnabledRasterizerState.setDebugName("Blit11 scissoring rasterizer state"); rasterDesc.ScissorEnable = FALSE; - result = device->CreateRasterizerState(&rasterDesc, &mScissorDisabledRasterizerState); - ASSERT(SUCCEEDED(result)); - if (FAILED(result)) - { - freeResources(); - return gl::Error(GL_OUT_OF_MEMORY, - "Failed to create blit no scissoring rasterizer state, HRESULT: 0x%X", - result); - } - d3d11::SetDebugName(mScissorDisabledRasterizerState, "Blit11 no scissoring rasterizer state"); + ANGLE_TRY(mRenderer->allocateResource(rasterDesc, &mScissorDisabledRasterizerState)); + mScissorDisabledRasterizerState.setDebugName("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.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)); - if (FAILED(result)) - { - freeResources(); - return gl::Error(GL_OUT_OF_MEMORY, - "Failed to create blit depth stencil state, HRESULT: 0x%X", result); - } - d3d11::SetDebugName(mDepthStencilState, "Blit11 depth stencil state"); + 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; + + ANGLE_TRY(mRenderer->allocateResource(depthStencilDesc, &mDepthStencilState)); + mDepthStencilState.setDebugName("Blit11 depth stencil state"); 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.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, nullptr, &mSwizzleCB); - ASSERT(SUCCEEDED(result)); - if (FAILED(result)) - { - freeResources(); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create blit swizzle buffer, HRESULT: 0x%X", - result); - } - d3d11::SetDebugName(mSwizzleCB, "Blit11 swizzle constant buffer"); + ANGLE_TRY(mRenderer->allocateResource(swizzleBufferDesc, &mSwizzleCB)); + mSwizzleCB.setDebugName("Blit11 swizzle constant buffer"); mResourcesInitialized = true; - return gl::Error(GL_NO_ERROR); -} - -void Blit11::freeResources() -{ - SafeRelease(mVertexBuffer); - SafeRelease(mPointSampler); - SafeRelease(mLinearSampler); - SafeRelease(mScissorEnabledRasterizerState); - SafeRelease(mScissorDisabledRasterizerState); - SafeRelease(mDepthStencilState); - SafeRelease(mSwizzleCB); - - mResourcesInitialized = false; + return gl::NoError(); } // static -Blit11::BlitShaderType Blit11::GetBlitShaderType(GLenum destinationFormat, bool isSigned, ShaderDimension dimension) +Blit11::BlitShaderType Blit11::GetBlitShaderType(GLenum destinationFormat, + GLenum sourceFormat, + bool isSigned, + bool unpackPremultiplyAlpha, + bool unpackUnmultiplyAlpha, + ShaderDimension dimension) { if (dimension == SHADER_3D) { + ASSERT(!unpackPremultiplyAlpha && !unpackUnmultiplyAlpha); + if (isSigned) { switch (destinationFormat) { - case GL_RGBA_INTEGER: return BLITSHADER_3D_RGBAI; - case GL_RGB_INTEGER: return BLITSHADER_3D_RGBI; - case GL_RG_INTEGER: return BLITSHADER_3D_RGI; - case GL_RED_INTEGER: return BLITSHADER_3D_RI; - default: - UNREACHABLE(); - return BLITSHADER_INVALID; + case GL_RGBA_INTEGER: + return BLITSHADER_3D_RGBAI; + case GL_RGB_INTEGER: + return BLITSHADER_3D_RGBI; + case GL_RG_INTEGER: + return BLITSHADER_3D_RGI; + case GL_RED_INTEGER: + return BLITSHADER_3D_RI; + default: + UNREACHABLE(); + return BLITSHADER_INVALID; } } else { switch (destinationFormat) { - case GL_RGBA: return BLITSHADER_3D_RGBAF; - case GL_RGBA_INTEGER: return BLITSHADER_3D_RGBAUI; - case GL_BGRA_EXT: return BLITSHADER_3D_BGRAF; - case GL_RGB: return BLITSHADER_3D_RGBF; - case GL_RGB_INTEGER: return BLITSHADER_3D_RGBUI; - case GL_RG: return BLITSHADER_3D_RGF; - case GL_RG_INTEGER: return BLITSHADER_3D_RGUI; - case GL_RED: return BLITSHADER_3D_RF; - case GL_RED_INTEGER: return BLITSHADER_3D_RUI; - case GL_ALPHA: return BLITSHADER_3D_ALPHA; - case GL_LUMINANCE: return BLITSHADER_3D_LUMA; - case GL_LUMINANCE_ALPHA: return BLITSHADER_3D_LUMAALPHA; - default: - UNREACHABLE(); - return BLITSHADER_INVALID; + case GL_RGBA: + return BLITSHADER_3D_RGBAF; + case GL_RGBA_INTEGER: + return BLITSHADER_3D_RGBAUI; + case GL_BGRA_EXT: + return BLITSHADER_3D_BGRAF; + case GL_RGB: + return BLITSHADER_3D_RGBF; + case GL_RGB_INTEGER: + return BLITSHADER_3D_RGBUI; + case GL_RG: + return BLITSHADER_3D_RGF; + case GL_RG_INTEGER: + return BLITSHADER_3D_RGUI; + case GL_RED: + return BLITSHADER_3D_RF; + case GL_RED_INTEGER: + return BLITSHADER_3D_RUI; + case GL_ALPHA: + return BLITSHADER_3D_ALPHA; + case GL_LUMINANCE: + return BLITSHADER_3D_LUMA; + case GL_LUMINANCE_ALPHA: + return BLITSHADER_3D_LUMAALPHA; + default: + UNREACHABLE(); + return BLITSHADER_INVALID; } } } else if (isSigned) { + ASSERT(!unpackPremultiplyAlpha && !unpackUnmultiplyAlpha); + switch (destinationFormat) { - case GL_RGBA_INTEGER: return BLITSHADER_2D_RGBAI; - case GL_RGB_INTEGER: return BLITSHADER_2D_RGBI; - case GL_RG_INTEGER: return BLITSHADER_2D_RGI; - case GL_RED_INTEGER: return BLITSHADER_2D_RI; - default: - UNREACHABLE(); - return BLITSHADER_INVALID; + case GL_RGBA_INTEGER: + return BLITSHADER_2D_RGBAI; + case GL_RGB_INTEGER: + return BLITSHADER_2D_RGBI; + case GL_RG_INTEGER: + return BLITSHADER_2D_RGI; + case GL_RED_INTEGER: + return BLITSHADER_2D_RI; + default: + UNREACHABLE(); + return BLITSHADER_INVALID; } } else { - switch (destinationFormat) + bool floatToIntBlit = + !gl::IsIntegerFormat(sourceFormat) && gl::IsIntegerFormat(destinationFormat); + if (unpackPremultiplyAlpha != unpackUnmultiplyAlpha || floatToIntBlit) { - case GL_RGBA: return BLITSHADER_2D_RGBAF; - case GL_RGBA_INTEGER: return BLITSHADER_2D_RGBAUI; - case GL_BGRA_EXT: return BLITSHADER_2D_BGRAF; - case GL_RGB: return BLITSHADER_2D_RGBF; - case GL_RGB_INTEGER: return BLITSHADER_2D_RGBUI; - case GL_RG: return BLITSHADER_2D_RGF; - case GL_RG_INTEGER: return BLITSHADER_2D_RGUI; - case GL_RED: return BLITSHADER_2D_RF; - case GL_RED_INTEGER: return BLITSHADER_2D_RUI; - case GL_ALPHA: return BLITSHADER_2D_ALPHA; - case GL_LUMINANCE: return BLITSHADER_2D_LUMA; - case GL_LUMINANCE_ALPHA: return BLITSHADER_2D_LUMAALPHA; - default: - UNREACHABLE(); - return BLITSHADER_INVALID; + switch (destinationFormat) + { + case GL_RGBA: + case GL_BGRA_EXT: + ASSERT(!floatToIntBlit); + return unpackPremultiplyAlpha ? BLITSHADER_2D_RGBAF_PREMULTIPLY + : BLITSHADER_2D_RGBAF_UNMULTIPLY; + + case GL_RGB: + case GL_RG: + case GL_RED: + ASSERT(!floatToIntBlit); + return unpackPremultiplyAlpha ? BLITSHADER_2D_RGBF_PREMULTIPLY + : BLITSHADER_2D_RGBF_UNMULTIPLY; + + case GL_RGBA_INTEGER: + if (unpackPremultiplyAlpha == unpackUnmultiplyAlpha) + { + return BLITSHADER_2D_RGBAF_TOUI; + } + else + { + return unpackPremultiplyAlpha ? BLITSHADER_2D_RGBAF_TOUI_PREMULTIPLY + : BLITSHADER_2D_RGBAF_TOUI_UNMULTIPLY; + } + + case GL_RGB_INTEGER: + case GL_RG_INTEGER: + case GL_RED_INTEGER: + if (unpackPremultiplyAlpha == unpackUnmultiplyAlpha) + { + return BLITSHADER_2D_RGBF_TOUI; + } + else + { + return unpackPremultiplyAlpha ? BLITSHADER_2D_RGBF_TOUI_PREMULTIPLY + : BLITSHADER_2D_RGBF_TOUI_UNMULTIPLY; + } + case GL_LUMINANCE: + ASSERT(!floatToIntBlit); + return unpackPremultiplyAlpha ? BLITSHADER_2D_LUMAF_PREMULTIPLY + : BLITSHADER_2D_LUMAF_UNMULTIPLY; + case GL_LUMINANCE_ALPHA: + ASSERT(!floatToIntBlit); + return unpackPremultiplyAlpha ? BLITSHADER_2D_LUMAALPHAF_PREMULTIPLY + : BLITSHADER_2D_LUMAALPHAF_UNMULTIPLY; + case GL_ALPHA: + ASSERT(!floatToIntBlit); + return BLITSHADER_2D_ALPHA; + default: + UNREACHABLE(); + return BLITSHADER_INVALID; + } + } + else + { + switch (destinationFormat) + { + case GL_RGBA: + return BLITSHADER_2D_RGBAF; + case GL_RGBA_INTEGER: + return BLITSHADER_2D_RGBAUI; + case GL_BGRA_EXT: + return BLITSHADER_2D_BGRAF; + case GL_RGB: + return BLITSHADER_2D_RGBF; + case GL_RGB_INTEGER: + return BLITSHADER_2D_RGBUI; + case GL_RG: + return BLITSHADER_2D_RGF; + case GL_RG_INTEGER: + return BLITSHADER_2D_RGUI; + case GL_RED: + return BLITSHADER_2D_RF; + case GL_RED_INTEGER: + return BLITSHADER_2D_RUI; + case GL_ALPHA: + return BLITSHADER_2D_ALPHA; + case GL_LUMINANCE: + return BLITSHADER_2D_LUMA; + case GL_LUMINANCE_ALPHA: + return BLITSHADER_2D_LUMAALPHA; + default: + UNREACHABLE(); + return BLITSHADER_INVALID; + } } } } // static -Blit11::SwizzleShaderType Blit11::GetSwizzleShaderType(GLenum type, D3D11_SRV_DIMENSION dimensionality) +Blit11::SwizzleShaderType Blit11::GetSwizzleShaderType(GLenum type, + D3D11_SRV_DIMENSION dimensionality) { switch (dimensionality) { - case D3D11_SRV_DIMENSION_TEXTURE2D: - switch (type) - { - case GL_FLOAT: return SWIZZLESHADER_2D_FLOAT; - case GL_UNSIGNED_INT: return SWIZZLESHADER_2D_UINT; - case GL_INT: return SWIZZLESHADER_2D_INT; - default: - UNREACHABLE(); - return SWIZZLESHADER_INVALID; - } - case D3D11_SRV_DIMENSION_TEXTURECUBE: - switch (type) - { - case GL_FLOAT: return SWIZZLESHADER_CUBE_FLOAT; - case GL_UNSIGNED_INT: return SWIZZLESHADER_CUBE_UINT; - case GL_INT: return SWIZZLESHADER_CUBE_INT; - default: - UNREACHABLE(); - return SWIZZLESHADER_INVALID; - } - case D3D11_SRV_DIMENSION_TEXTURE3D: - switch (type) - { - case GL_FLOAT: return SWIZZLESHADER_3D_FLOAT; - case GL_UNSIGNED_INT: return SWIZZLESHADER_3D_UINT; - case GL_INT: return SWIZZLESHADER_3D_INT; - default: - UNREACHABLE(); - return SWIZZLESHADER_INVALID; - } - case D3D11_SRV_DIMENSION_TEXTURE2DARRAY: - switch (type) - { - case GL_FLOAT: return SWIZZLESHADER_ARRAY_FLOAT; - case GL_UNSIGNED_INT: return SWIZZLESHADER_ARRAY_UINT; - case GL_INT: return SWIZZLESHADER_ARRAY_INT; - default: + case D3D11_SRV_DIMENSION_TEXTURE2D: + switch (type) + { + case GL_FLOAT: + return SWIZZLESHADER_2D_FLOAT; + case GL_UNSIGNED_INT: + return SWIZZLESHADER_2D_UINT; + case GL_INT: + return SWIZZLESHADER_2D_INT; + default: + UNREACHABLE(); + return SWIZZLESHADER_INVALID; + } + case D3D11_SRV_DIMENSION_TEXTURECUBE: + switch (type) + { + case GL_FLOAT: + return SWIZZLESHADER_CUBE_FLOAT; + case GL_UNSIGNED_INT: + return SWIZZLESHADER_CUBE_UINT; + case GL_INT: + return SWIZZLESHADER_CUBE_INT; + default: + UNREACHABLE(); + return SWIZZLESHADER_INVALID; + } + case D3D11_SRV_DIMENSION_TEXTURE3D: + switch (type) + { + case GL_FLOAT: + return SWIZZLESHADER_3D_FLOAT; + case GL_UNSIGNED_INT: + return SWIZZLESHADER_3D_UINT; + case GL_INT: + return SWIZZLESHADER_3D_INT; + default: + UNREACHABLE(); + return SWIZZLESHADER_INVALID; + } + case D3D11_SRV_DIMENSION_TEXTURE2DARRAY: + switch (type) + { + case GL_FLOAT: + return SWIZZLESHADER_ARRAY_FLOAT; + case GL_UNSIGNED_INT: + return SWIZZLESHADER_ARRAY_UINT; + case GL_INT: + return SWIZZLESHADER_ARRAY_INT; + default: + UNREACHABLE(); + return SWIZZLESHADER_INVALID; + } + default: UNREACHABLE(); return SWIZZLESHADER_INVALID; - } - default: - UNREACHABLE(); - return SWIZZLESHADER_INVALID; } } -Blit11::ShaderSupport Blit11::getShaderSupport(const Shader &shader) +gl::Error Blit11::getShaderSupport(const Shader &shader, Blit11::ShaderSupport *supportOut) { - ID3D11Device *device = mRenderer->getDevice(); - ShaderSupport support; - if (shader.dimension == SHADER_2D) { - support.inputLayout = mQuad2DIL.resolve(device); - support.vertexShader = mQuad2DVS.resolve(device); - support.geometryShader = nullptr; - support.vertexWriteFunction = Write2DVertices; + ANGLE_TRY(mQuad2DIL.resolve(mRenderer)); + ANGLE_TRY(mQuad2DVS.resolve(mRenderer)); + supportOut->inputLayout = &mQuad2DIL.getObj(); + supportOut->vertexShader = &mQuad2DVS.getObj(); + supportOut->geometryShader = nullptr; + supportOut->vertexWriteFunction = Write2DVertices; } else { ASSERT(shader.dimension == SHADER_3D); - support.inputLayout = mQuad3DIL.resolve(device); - support.vertexShader = mQuad3DVS.resolve(device); - support.geometryShader = mQuad3DGS.resolve(device); - support.vertexWriteFunction = Write3DVertices; + ANGLE_TRY(mQuad3DIL.resolve(mRenderer)); + ANGLE_TRY(mQuad3DVS.resolve(mRenderer)); + ANGLE_TRY(mQuad3DGS.resolve(mRenderer)); + supportOut->inputLayout = &mQuad2DIL.getObj(); + supportOut->vertexShader = &mQuad3DVS.getObj(); + supportOut->geometryShader = &mQuad3DGS.getObj(); + supportOut->vertexWriteFunction = Write3DVertices; } - return support; + return gl::NoError(); } -gl::Error Blit11::swizzleTexture(ID3D11ShaderResourceView *source, - ID3D11RenderTargetView *dest, +gl::Error Blit11::swizzleTexture(const gl::Context *context, + const d3d11::SharedSRV &source, + const d3d11::RenderTargetView &dest, const gl::Extents &size, - GLenum swizzleRed, - GLenum swizzleGreen, - GLenum swizzleBlue, - GLenum swizzleAlpha) + const gl::SwizzleState &swizzleTarget) { - gl::Error error = initResources(); - if (error.isError()) - { - return error; - } + ANGLE_TRY(initResources()); HRESULT result; ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); D3D11_SHADER_RESOURCE_VIEW_DESC sourceSRVDesc; - source->GetDesc(&sourceSRVDesc); + source.get()->GetDesc(&sourceSRVDesc); - const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(sourceSRVDesc.Format); - const gl::InternalFormat &sourceFormatInfo = gl::GetInternalFormatInfo(dxgiFormatInfo.internalFormat); + GLenum componentType = d3d11::GetComponentType(sourceSRVDesc.Format); + if (componentType == GL_NONE) + { + // We're swizzling the depth component of a depth-stencil texture. + switch (sourceSRVDesc.Format) + { + case DXGI_FORMAT_R24_UNORM_X8_TYPELESS: + componentType = GL_UNSIGNED_NORMALIZED; + break; + case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS: + componentType = GL_FLOAT; + break; + default: + UNREACHABLE(); + break; + } + } GLenum shaderType = GL_NONE; - switch (sourceFormatInfo.componentType) + switch (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; + 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; } const Shader *shader = nullptr; - error = getSwizzleShader(shaderType, sourceSRVDesc.ViewDimension, &shader); - if (error.isError()) - { - return error; - } + ANGLE_TRY(getSwizzleShader(shaderType, sourceSRVDesc.ViewDimension, &shader)); // Set vertices D3D11_MAPPED_SUBRESOURCE mappedResource; - result = deviceContext->Map(mVertexBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); + result = + deviceContext->Map(mVertexBuffer.get(), 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); + return gl::OutOfMemory() << "Failed to map internal vertex buffer for swizzle, " + << gl::FmtHR(result); } - const ShaderSupport &support = getShaderSupport(*shader); + ShaderSupport support; + ANGLE_TRY(getShaderSupport(*shader, &support)); - UINT stride = 0; - UINT startIdx = 0; + UINT stride = 0; UINT drawCount = 0; D3D11_PRIMITIVE_TOPOLOGY topology; gl::Box area(0, 0, 0, size.width, size.height, size.depth); - support.vertexWriteFunction(area, size, area, size, mappedResource.pData, &stride, &drawCount, &topology); + support.vertexWriteFunction(area, size, area, size, mappedResource.pData, &stride, &drawCount, + &topology); - deviceContext->Unmap(mVertexBuffer, 0); + deviceContext->Unmap(mVertexBuffer.get(), 0); // Set constant buffer - result = deviceContext->Map(mSwizzleCB, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); + result = deviceContext->Map(mSwizzleCB.get(), 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); + return gl::OutOfMemory() << "Failed to map internal constant buffer for swizzle, " + << gl::FmtHR(result); } - unsigned int *swizzleIndices = reinterpret_cast(mappedResource.pData); - swizzleIndices[0] = GetSwizzleIndex(swizzleRed); - swizzleIndices[1] = GetSwizzleIndex(swizzleGreen); - swizzleIndices[2] = GetSwizzleIndex(swizzleBlue); - swizzleIndices[3] = GetSwizzleIndex(swizzleAlpha); + unsigned int *swizzleIndices = reinterpret_cast(mappedResource.pData); + swizzleIndices[0] = GetSwizzleIndex(swizzleTarget.swizzleRed); + swizzleIndices[1] = GetSwizzleIndex(swizzleTarget.swizzleGreen); + swizzleIndices[2] = GetSwizzleIndex(swizzleTarget.swizzleBlue); + swizzleIndices[3] = GetSwizzleIndex(swizzleTarget.swizzleAlpha); - deviceContext->Unmap(mSwizzleCB, 0); + deviceContext->Unmap(mSwizzleCB.get(), 0); + + StateManager11 *stateManager = mRenderer->getStateManager(); // Apply vertex buffer - deviceContext->IASetVertexBuffers(0, 1, &mVertexBuffer, &stride, &startIdx); + stateManager->setSingleVertexBuffer(&mVertexBuffer, stride, 0); // Apply constant buffer - deviceContext->PSSetConstantBuffers(0, 1, &mSwizzleCB); + stateManager->setPixelConstantBuffer(0, &mSwizzleCB); // Apply state - deviceContext->OMSetBlendState(nullptr, nullptr, 0xFFFFFFF); - deviceContext->OMSetDepthStencilState(nullptr, 0xFFFFFFFF); - deviceContext->RSSetState(mScissorDisabledRasterizerState); + stateManager->setSimpleBlendState(nullptr); + stateManager->setDepthStencilState(nullptr, 0xFFFFFFFF); + stateManager->setRasterizerState(&mScissorDisabledRasterizerState); // Apply shaders - deviceContext->IASetInputLayout(support.inputLayout); - deviceContext->IASetPrimitiveTopology(topology); - deviceContext->VSSetShader(support.vertexShader, nullptr, 0); - - deviceContext->PSSetShader(shader->pixelShader, nullptr, 0); - deviceContext->GSSetShader(support.geometryShader, nullptr, 0); + stateManager->setInputLayout(support.inputLayout); + stateManager->setPrimitiveTopology(topology); - // Unset the currently bound shader resource to avoid conflicts - auto stateManager = mRenderer->getStateManager(); - stateManager->setShaderResource(gl::SAMPLER_PIXEL, 0, nullptr); + stateManager->setDrawShaders(support.vertexShader, support.geometryShader, + &shader->pixelShader); // Apply render target - mRenderer->setOneTimeRenderTarget(dest); + stateManager->setRenderTarget(dest.get(), nullptr); // Set the viewport - D3D11_VIEWPORT viewport; - viewport.TopLeftX = 0; - viewport.TopLeftY = 0; - viewport.Width = static_cast(size.width); - viewport.Height = static_cast(size.height); - viewport.MinDepth = 0.0f; - viewport.MaxDepth = 1.0f; - deviceContext->RSSetViewports(1, &viewport); - - // Apply textures - stateManager->setShaderResource(gl::SAMPLER_PIXEL, 0, source); + stateManager->setSimpleViewport(size); - // Apply samplers - deviceContext->PSSetSamplers(0, 1, &mPointSampler); + // Apply textures and sampler + stateManager->setSimplePixelTextureAndSampler(source, mPointSampler); // Draw the quad deviceContext->Draw(drawCount, 0); - // Unbind textures and render targets and vertex buffer - stateManager->setShaderResource(gl::SAMPLER_PIXEL, 0, nullptr); - - mRenderer->unapplyRenderTargets(); - - UINT zero = 0; - ID3D11Buffer *const nullBuffer = nullptr; - deviceContext->IASetVertexBuffers(0, 1, &nullBuffer, &zero, &zero); - - mRenderer->markAllStateDirty(); - - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error Blit11::copyTexture(ID3D11ShaderResourceView *source, +gl::Error Blit11::copyTexture(const gl::Context *context, + const d3d11::SharedSRV &source, const gl::Box &sourceArea, const gl::Extents &sourceSize, - ID3D11RenderTargetView *dest, + GLenum sourceFormat, + const d3d11::RenderTargetView &dest, const gl::Box &destArea, const gl::Extents &destSize, const gl::Rectangle *scissor, GLenum destFormat, GLenum filter, - bool maskOffAlpha) + bool maskOffAlpha, + bool unpackPremultiplyAlpha, + bool unpackUnmultiplyAlpha) { - gl::Error error = initResources(); - if (error.isError()) - { - return error; - } + ANGLE_TRY(initResources()); HRESULT result; ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); @@ -771,635 +1145,1009 @@ gl::Error Blit11::copyTexture(ID3D11ShaderResourceView *source, // 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); + source.get()->GetDesc(&sourceSRVDesc); + + GLenum componentType = d3d11::GetComponentType(sourceSRVDesc.Format); - const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(sourceSRVDesc.Format); - const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(dxgiFormatInfo.internalFormat); + ASSERT(componentType != GL_NONE); + ASSERT(componentType != GL_SIGNED_NORMALIZED); + bool isSigned = (componentType == GL_INT); - bool isSigned = (internalFormatInfo.componentType == GL_INT); - ShaderDimension dimension = (sourceSRVDesc.ViewDimension == D3D11_SRV_DIMENSION_TEXTURE3D) ? SHADER_3D : SHADER_2D; + ShaderDimension dimension = + (sourceSRVDesc.ViewDimension == D3D11_SRV_DIMENSION_TEXTURE3D) ? SHADER_3D : SHADER_2D; const Shader *shader = nullptr; - error = getBlitShader(destFormat, isSigned, dimension, &shader); - if (error.isError()) - { - return error; - } + ANGLE_TRY(getBlitShader(destFormat, sourceFormat, isSigned, unpackPremultiplyAlpha, + unpackUnmultiplyAlpha, dimension, &shader)); - const ShaderSupport &support = getShaderSupport(*shader); + ShaderSupport support; + ANGLE_TRY(getShaderSupport(*shader, &support)); // Set vertices D3D11_MAPPED_SUBRESOURCE mappedResource; - result = deviceContext->Map(mVertexBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); + result = + deviceContext->Map(mVertexBuffer.get(), 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); + return gl::OutOfMemory() << "Failed to map internal vertex buffer for texture copy, " + << gl::FmtHR(result); } - UINT stride = 0; - UINT startIdx = 0; + UINT stride = 0; UINT drawCount = 0; D3D11_PRIMITIVE_TOPOLOGY topology; support.vertexWriteFunction(sourceArea, sourceSize, destArea, destSize, mappedResource.pData, &stride, &drawCount, &topology); - deviceContext->Unmap(mVertexBuffer, 0); + deviceContext->Unmap(mVertexBuffer.get(), 0); + + StateManager11 *stateManager = mRenderer->getStateManager(); // Apply vertex buffer - deviceContext->IASetVertexBuffers(0, 1, &mVertexBuffer, &stride, &startIdx); + stateManager->setSingleVertexBuffer(&mVertexBuffer, stride, 0); // Apply state if (maskOffAlpha) { - ID3D11BlendState *blendState = mAlphaMaskBlendState.resolve(mRenderer->getDevice()); - ASSERT(blendState); - deviceContext->OMSetBlendState(blendState, nullptr, 0xFFFFFFF); + ANGLE_TRY(mAlphaMaskBlendState.resolve(mRenderer)); + stateManager->setSimpleBlendState(&mAlphaMaskBlendState.getObj()); } else { - deviceContext->OMSetBlendState(nullptr, nullptr, 0xFFFFFFF); + stateManager->setSimpleBlendState(nullptr); } - deviceContext->OMSetDepthStencilState(nullptr, 0xFFFFFFFF); + stateManager->setDepthStencilState(nullptr, 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); + stateManager->setSimpleScissorRect(*scissor); + stateManager->setRasterizerState(&mScissorEnabledRasterizerState); } else { - deviceContext->RSSetState(mScissorDisabledRasterizerState); + stateManager->setRasterizerState(&mScissorDisabledRasterizerState); } // Apply shaders - deviceContext->IASetInputLayout(support.inputLayout); - deviceContext->IASetPrimitiveTopology(topology); - deviceContext->VSSetShader(support.vertexShader, nullptr, 0); - - deviceContext->PSSetShader(shader->pixelShader, nullptr, 0); - deviceContext->GSSetShader(support.geometryShader, nullptr, 0); + stateManager->setInputLayout(support.inputLayout); + stateManager->setPrimitiveTopology(topology); - // Unset the currently bound shader resource to avoid conflicts - auto stateManager = mRenderer->getStateManager(); - stateManager->setShaderResource(gl::SAMPLER_PIXEL, 0, nullptr); + stateManager->setDrawShaders(support.vertexShader, support.geometryShader, + &shader->pixelShader); // Apply render target - mRenderer->setOneTimeRenderTarget(dest); + stateManager->setRenderTarget(dest.get(), nullptr); // Set the viewport - D3D11_VIEWPORT viewport; - viewport.TopLeftX = 0; - viewport.TopLeftY = 0; - viewport.Width = static_cast(destSize.width); - viewport.Height = static_cast(destSize.height); - viewport.MinDepth = 0.0f; - viewport.MaxDepth = 1.0f; - deviceContext->RSSetViewports(1, &viewport); - - // Apply textures - stateManager->setShaderResource(gl::SAMPLER_PIXEL, 0, source); - - // Apply samplers - ID3D11SamplerState *sampler = nullptr; + stateManager->setSimpleViewport(destSize); + + // Apply texture and sampler 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."); + case GL_NEAREST: + stateManager->setSimplePixelTextureAndSampler(source, mPointSampler); + break; + case GL_LINEAR: + stateManager->setSimplePixelTextureAndSampler(source, mLinearSampler); + break; + + default: + UNREACHABLE(); + return gl::InternalError() << "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 - stateManager->setShaderResource(gl::SAMPLER_PIXEL, 0, nullptr); - - mRenderer->unapplyRenderTargets(); - - UINT zero = 0; - ID3D11Buffer *const nullBuffer = nullptr; - deviceContext->IASetVertexBuffers(0, 1, &nullBuffer, &zero, &zero); - - mRenderer->markAllStateDirty(); - - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -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, +gl::Error Blit11::copyStencil(const gl::Context *context, + const TextureHelper11 &source, + unsigned int sourceSubresource, + const gl::Box &sourceArea, + const gl::Extents &sourceSize, + const TextureHelper11 &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); + return copyDepthStencilImpl(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, +gl::Error Blit11::copyDepth(const gl::Context *context, + const d3d11::SharedSRV &source, + const gl::Box &sourceArea, + const gl::Extents &sourceSize, + const d3d11::DepthStencilView &dest, + const gl::Box &destArea, + const gl::Extents &destSize, const gl::Rectangle *scissor) { - gl::Error error = initResources(); - if (error.isError()) - { - return error; - } + ANGLE_TRY(initResources()); HRESULT result; ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); // Set vertices D3D11_MAPPED_SUBRESOURCE mappedResource; - result = deviceContext->Map(mVertexBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); + result = + deviceContext->Map(mVertexBuffer.get(), 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); + return gl::OutOfMemory() << "Failed to map internal vertex buffer for texture copy, " + << gl::FmtHR(result); } - UINT stride = 0; - UINT startIdx = 0; + UINT stride = 0; UINT drawCount = 0; D3D11_PRIMITIVE_TOPOLOGY topology; - Write2DVertices(sourceArea, sourceSize, destArea, destSize, mappedResource.pData, - &stride, &drawCount, &topology); + Write2DVertices(sourceArea, sourceSize, destArea, destSize, mappedResource.pData, &stride, + &drawCount, &topology); - deviceContext->Unmap(mVertexBuffer, 0); + deviceContext->Unmap(mVertexBuffer.get(), 0); + + StateManager11 *stateManager = mRenderer->getStateManager(); // Apply vertex buffer - deviceContext->IASetVertexBuffers(0, 1, &mVertexBuffer, &stride, &startIdx); + stateManager->setSingleVertexBuffer(&mVertexBuffer, stride, 0); // Apply state - deviceContext->OMSetBlendState(nullptr, nullptr, 0xFFFFFFF); - deviceContext->OMSetDepthStencilState(mDepthStencilState, 0xFFFFFFFF); + stateManager->setSimpleBlendState(nullptr); + stateManager->setDepthStencilState(&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); + stateManager->setSimpleScissorRect(*scissor); + stateManager->setRasterizerState(&mScissorEnabledRasterizerState); } else { - deviceContext->RSSetState(mScissorDisabledRasterizerState); + stateManager->setRasterizerState(&mScissorDisabledRasterizerState); } - ID3D11Device *device = mRenderer->getDevice(); - ID3D11VertexShader *quad2DVS = mQuad2DVS.resolve(device); - if (quad2DVS == nullptr) - { - return gl::Error(GL_INVALID_OPERATION, "Error compiling internal 2D blit vertex shader"); - } + ANGLE_TRY(mQuad2DIL.resolve(mRenderer)); + ANGLE_TRY(mQuad2DVS.resolve(mRenderer)); + ANGLE_TRY(mDepthPS.resolve(mRenderer)); // Apply shaders - deviceContext->IASetInputLayout(mQuad2DIL.resolve(device)); - deviceContext->IASetPrimitiveTopology(topology); - deviceContext->VSSetShader(quad2DVS, nullptr, 0); + stateManager->setInputLayout(&mQuad2DIL.getObj()); + stateManager->setPrimitiveTopology(topology); - deviceContext->PSSetShader(mDepthPS.resolve(device), nullptr, 0); - deviceContext->GSSetShader(nullptr, nullptr, 0); - - // Unset the currently bound shader resource to avoid conflicts - auto stateManager = mRenderer->getStateManager(); - stateManager->setShaderResource(gl::SAMPLER_PIXEL, 0, nullptr); + stateManager->setDrawShaders(&mQuad2DVS.getObj(), nullptr, &mDepthPS.getObj()); // Apply render target - deviceContext->OMSetRenderTargets(0, nullptr, dest); + stateManager->setRenderTarget(nullptr, dest.get()); // Set the viewport - D3D11_VIEWPORT viewport; - viewport.TopLeftX = 0; - viewport.TopLeftY = 0; - viewport.Width = static_cast(destSize.width); - viewport.Height = static_cast(destSize.height); - viewport.MinDepth = 0.0f; - viewport.MaxDepth = 1.0f; - deviceContext->RSSetViewports(1, &viewport); - - // Apply textures - stateManager->setShaderResource(gl::SAMPLER_PIXEL, 0, source); + stateManager->setSimpleViewport(destSize); - // Apply samplers - deviceContext->PSSetSamplers(0, 1, &mPointSampler); + // Apply texture and sampler + stateManager->setSimplePixelTextureAndSampler(source, mPointSampler); // Draw the quad deviceContext->Draw(drawCount, 0); - // Unbind textures and render targets and vertex buffer - stateManager->setShaderResource(gl::SAMPLER_PIXEL, 0, nullptr); - - mRenderer->unapplyRenderTargets(); - - UINT zero = 0; - ID3D11Buffer *const nullBuffer = nullptr; - deviceContext->IASetVertexBuffers(0, 1, &nullBuffer, &zero, &zero); - - mRenderer->markAllStateDirty(); - - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -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, +gl::Error Blit11::copyDepthStencil(const TextureHelper11 &source, + unsigned int sourceSubresource, + const gl::Box &sourceArea, + const gl::Extents &sourceSize, + const TextureHelper11 &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); + return copyDepthStencilImpl(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) +gl::Error Blit11::copyDepthStencilImpl(const TextureHelper11 &source, + unsigned int sourceSubresource, + const gl::Box &sourceArea, + const gl::Extents &sourceSize, + const TextureHelper11 &dest, + unsigned int destSubresource, + const gl::Box &destArea, + const gl::Extents &destSize, + const gl::Rectangle *scissor, + bool stencilOnly) { - gl::Error error = initResources(); - if (error.isError()) - { - return error; - } + auto srcDXGIFormat = source.getFormat(); + const auto &srcSizeInfo = d3d11::GetDXGIFormatSizeInfo(srcDXGIFormat); + unsigned int srcPixelSize = srcSizeInfo.pixelBytes; + unsigned int copyOffset = 0; + unsigned int copySize = srcPixelSize; + auto destDXGIFormat = dest.getFormat(); + const auto &destSizeInfo = d3d11::GetDXGIFormatSizeInfo(destDXGIFormat); + unsigned int destPixelSize = destSizeInfo.pixelBytes; - ID3D11Device *device = mRenderer->getDevice(); - ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); + ASSERT(srcDXGIFormat == destDXGIFormat || destDXGIFormat == DXGI_FORMAT_R32_TYPELESS); - 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 (stencilOnly) + { + const auto &srcFormat = source.getFormatSet().format(); + + // Stencil channel should be right after the depth channel. Some views to depth/stencil + // resources have red channel for depth, in which case the depth channel bit width is in + // redBits. + ASSERT((srcFormat.redBits != 0) != (srcFormat.depthBits != 0)); + GLuint depthBits = srcFormat.redBits + srcFormat.depthBits; + // Known formats have either 24 or 32 bits of depth. + ASSERT(depthBits == 24 || depthBits == 32); + copyOffset = depthBits / 8; + + // Stencil is assumed to be 8-bit - currently this is true for all possible formats. + copySize = 1; + } - if (!sourceStaging || !destStaging) + if (srcDXGIFormat != destDXGIFormat) { - SafeRelease(sourceStaging); - SafeRelease(destStaging); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal staging textures for depth stencil blit."); + if (srcDXGIFormat == DXGI_FORMAT_R24G8_TYPELESS) + { + ASSERT(sourceArea == destArea && sourceSize == destSize && scissor == nullptr); + return copyAndConvert(source, sourceSubresource, sourceArea, sourceSize, dest, + destSubresource, destArea, destSize, scissor, copyOffset, + copyOffset, copySize, srcPixelSize, destPixelSize, + BlitD24S8ToD32F); + } + ASSERT(srcDXGIFormat == DXGI_FORMAT_R32G8X24_TYPELESS); + return copyAndConvert(source, sourceSubresource, sourceArea, sourceSize, dest, + destSubresource, destArea, destSize, scissor, copyOffset, copyOffset, + copySize, srcPixelSize, destPixelSize, BlitD32FS8ToD32F); } - DXGI_FORMAT format = GetTextureFormat(source); - ASSERT(format == GetTextureFormat(dest)); + return copyAndConvert(source, sourceSubresource, sourceArea, sourceSize, dest, destSubresource, + destArea, destSize, scissor, copyOffset, copyOffset, copySize, + srcPixelSize, destPixelSize, StretchedBlitNearest); +} - 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; +gl::Error Blit11::copyAndConvertImpl(const TextureHelper11 &source, + unsigned int sourceSubresource, + const gl::Box &sourceArea, + const gl::Extents &sourceSize, + const TextureHelper11 &destStaging, + const gl::Box &destArea, + const gl::Extents &destSize, + const gl::Rectangle *scissor, + size_t readOffset, + size_t writeOffset, + size_t copySize, + size_t srcPixelStride, + size_t destPixelStride, + BlitConvertFunction *convertFunction) +{ + ANGLE_TRY(initResources()); - // 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); - } + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); + + TextureHelper11 sourceStaging; + ANGLE_TRY_RESULT(mRenderer->createStagingTexture(ResourceType::Texture2D, source.getFormatSet(), + sourceSize, StagingAccess::READ), + sourceStaging); + + deviceContext->CopySubresourceRegion(sourceStaging.get(), 0, 0, 0, 0, source.get(), + sourceSubresource, nullptr); D3D11_MAPPED_SUBRESOURCE sourceMapping; - HRESULT result = deviceContext->Map(sourceStaging, 0, D3D11_MAP_READ, 0, &sourceMapping); + HRESULT result = deviceContext->Map(sourceStaging.get(), 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); + return gl::OutOfMemory() + << "Failed to map internal source staging texture for depth stencil blit, " + << gl::FmtHR(result); } D3D11_MAPPED_SUBRESOURCE destMapping; - result = deviceContext->Map(destStaging, 0, D3D11_MAP_WRITE, 0, &destMapping); + result = deviceContext->Map(destStaging.get(), 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); + deviceContext->Unmap(sourceStaging.get(), 0); + return gl::OutOfMemory() + << "Failed to map internal destination staging texture for depth stencil blit, " + << gl::FmtHR(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); + gl::Rectangle clipRect = gl::Rectangle(0, 0, destSize.width, destSize.height); // Clip dest area to the scissor if (scissor) { - gl::ClipRectangle(clippedDestArea, *scissor, &clippedDestArea); + gl::ClipRectangle(clipRect, *scissor, &clipRect); } - // 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; + convertFunction(sourceArea, destArea, clipRect, sourceSize, sourceMapping.RowPitch, + destMapping.RowPitch, readOffset, writeOffset, copySize, srcPixelStride, + destPixelStride, static_cast(sourceMapping.pData), + static_cast(destMapping.pData)); - for (int y = clippedDestArea.y; y < clippedDestArea.y + clippedDestArea.height; y++) - { - float yPerc = static_cast(y - destArea.y) / (destArea.height - 1); + deviceContext->Unmap(sourceStaging.get(), 0); + deviceContext->Unmap(destStaging.get(), 0); - // Interpolate using the original source rectangle to determine which row to sample from while clamping to the edges - unsigned int readRow = static_cast(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; + return gl::NoError(); +} - void *destRow = reinterpret_cast(destMapping.pData) + - writeRow * destMapping.RowPitch + - destArea.x * pixelSize; +gl::Error Blit11::copyAndConvert(const TextureHelper11 &source, + unsigned int sourceSubresource, + const gl::Box &sourceArea, + const gl::Extents &sourceSize, + const TextureHelper11 &dest, + unsigned int destSubresource, + const gl::Box &destArea, + const gl::Extents &destSize, + const gl::Rectangle *scissor, + size_t readOffset, + size_t writeOffset, + size_t copySize, + size_t srcPixelStride, + size_t destPixelStride, + BlitConvertFunction *convertFunction) +{ + ANGLE_TRY(initResources()); - 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); + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); - // Interpolate the original source rectangle to determine which column to sample from while clamping to the edges - unsigned int readColumn = static_cast(gl::clamp(sourceArea.x + floor(xPerc * (sourceArea.width - 1) + 0.5f), 0, sourceSize.width - 1)); - unsigned int writeColumn = x; + // 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 + TextureHelper11 destStaging; + ANGLE_TRY_RESULT(mRenderer->createStagingTexture(ResourceType::Texture2D, dest.getFormatSet(), + destSize, StagingAccess::READ_WRITE), + destStaging); - void *sourcePixel = reinterpret_cast(sourceMapping.pData) + - readRow * sourceMapping.RowPitch + - readColumn * pixelSize + - copyOffset; + deviceContext->CopySubresourceRegion(destStaging.get(), 0, 0, 0, 0, dest.get(), destSubresource, + nullptr); - void *destPixel = reinterpret_cast(destMapping.pData) + - writeRow * destMapping.RowPitch + - writeColumn * pixelSize + - copyOffset; + ANGLE_TRY(copyAndConvertImpl(source, sourceSubresource, sourceArea, sourceSize, destStaging, + destArea, destSize, scissor, readOffset, writeOffset, copySize, + srcPixelStride, destPixelStride, convertFunction)); - memcpy(destPixel, sourcePixel, copySize); - } - } + // Work around timeouts/TDRs in older NVIDIA drivers. + if (mRenderer->getWorkarounds().depthStencilBlitExtraCopy) + { + D3D11_MAPPED_SUBRESOURCE mapped; + deviceContext->Map(destStaging.get(), 0, D3D11_MAP_READ, 0, &mapped); + deviceContext->UpdateSubresource(dest.get(), destSubresource, nullptr, mapped.pData, + mapped.RowPitch, mapped.DepthPitch); + deviceContext->Unmap(destStaging.get(), 0); + } + else + { + deviceContext->CopySubresourceRegion(dest.get(), destSubresource, 0, 0, 0, + destStaging.get(), 0, nullptr); } - // HACK: Use ID3D11DevicContext::UpdateSubresource which causes an extra copy compared to ID3D11DevicContext::CopySubresourceRegion - // according to MSDN. - deviceContext->UpdateSubresource(dest, destSubresource, nullptr, 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, nullptr); - - SafeRelease(sourceStaging); - SafeRelease(destStaging); - - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -void Blit11::addBlitShaderToMap(BlitShaderType blitShaderType, ShaderDimension dimension, ID3D11PixelShader *ps) +gl::Error Blit11::addBlitShaderToMap(BlitShaderType blitShaderType, + ShaderDimension dimension, + const ShaderData &shaderData, + const char *name) { ASSERT(mBlitShaderMap.find(blitShaderType) == mBlitShaderMap.end()); - ASSERT(ps); + + d3d11::PixelShader ps; + ANGLE_TRY(mRenderer->allocateResource(shaderData, &ps)); + ps.setDebugName(name); Shader shader; - shader.dimension = dimension; - shader.pixelShader = ps; + shader.dimension = dimension; + shader.pixelShader = std::move(ps); - mBlitShaderMap[blitShaderType] = shader; + mBlitShaderMap[blitShaderType] = std::move(shader); + return gl::NoError(); } -void Blit11::addSwizzleShaderToMap(SwizzleShaderType swizzleShaderType, ShaderDimension dimension, ID3D11PixelShader *ps) +gl::Error Blit11::addSwizzleShaderToMap(SwizzleShaderType swizzleShaderType, + ShaderDimension dimension, + const ShaderData &shaderData, + const char *name) { ASSERT(mSwizzleShaderMap.find(swizzleShaderType) == mSwizzleShaderMap.end()); - ASSERT(ps); + + d3d11::PixelShader ps; + ANGLE_TRY(mRenderer->allocateResource(shaderData, &ps)); + ps.setDebugName(name); Shader shader; - shader.dimension = dimension; - shader.pixelShader = ps; + shader.dimension = dimension; + shader.pixelShader = std::move(ps); - mSwizzleShaderMap[swizzleShaderType] = shader; + mSwizzleShaderMap[swizzleShaderType] = std::move(shader); + return gl::NoError(); } void Blit11::clearShaderMap() { - for (auto &blitShader : mBlitShaderMap) - { - SafeRelease(blitShader.second.pixelShader); - } mBlitShaderMap.clear(); - - for (auto &swizzleShader : mSwizzleShaderMap) - { - SafeRelease(swizzleShader.second.pixelShader); - } mSwizzleShaderMap.clear(); } -gl::Error Blit11::getBlitShader(GLenum destFormat, bool isSigned, ShaderDimension dimension, const Shader **shader) +gl::Error Blit11::getBlitShader(GLenum destFormat, + GLenum sourceFormat, + bool isSigned, + bool unpackPremultiplyAlpha, + bool unpackUnmultiplyAlpha, + ShaderDimension dimension, + const Shader **shader) { - BlitShaderType blitShaderType = GetBlitShaderType(destFormat, isSigned, dimension); + BlitShaderType blitShaderType = + GetBlitShaderType(destFormat, sourceFormat, isSigned, unpackPremultiplyAlpha, + unpackUnmultiplyAlpha, dimension); if (blitShaderType == BLITSHADER_INVALID) { - return gl::Error(GL_INVALID_OPERATION, "Internal blit shader type mismatch"); + return gl::InternalError() << "Internal blit shader type mismatch"; } auto blitShaderIt = mBlitShaderMap.find(blitShaderType); if (blitShaderIt != mBlitShaderMap.end()) { *shader = &blitShaderIt->second; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } ASSERT(dimension == SHADER_2D || mRenderer->isES3Capable()); - ID3D11Device *device = mRenderer->getDevice(); - switch (blitShaderType) { - case BLITSHADER_2D_RGBAF: - addBlitShaderToMap(blitShaderType, SHADER_2D, d3d11::CompilePS(device, g_PS_PassthroughRGBA2D, "Blit11 2D RGBA pixel shader")); - break; - case BLITSHADER_2D_BGRAF: - addBlitShaderToMap(blitShaderType, SHADER_2D, d3d11::CompilePS(device, g_PS_PassthroughRGBA2D, "Blit11 2D BGRA pixel shader")); - break; - case BLITSHADER_2D_RGBF: - addBlitShaderToMap(blitShaderType, SHADER_2D, d3d11::CompilePS(device, g_PS_PassthroughRGB2D, "Blit11 2D RGB pixel shader")); - break; - case BLITSHADER_2D_RGF: - addBlitShaderToMap(blitShaderType, SHADER_2D, d3d11::CompilePS(device, g_PS_PassthroughRG2D, "Blit11 2D RG pixel shader")); - break; - case BLITSHADER_2D_RF: - addBlitShaderToMap(blitShaderType, SHADER_2D, d3d11::CompilePS(device, g_PS_PassthroughR2D, "Blit11 2D R pixel shader")); - break; - case BLITSHADER_2D_ALPHA: - addBlitShaderToMap(blitShaderType, SHADER_2D, d3d11::CompilePS(device, g_PS_PassthroughRGBA2D, "Blit11 2D alpha pixel shader")); - break; - case BLITSHADER_2D_LUMA: - addBlitShaderToMap(blitShaderType, SHADER_2D, d3d11::CompilePS(device, g_PS_PassthroughLum2D, "Blit11 2D lum pixel shader")); - break; - case BLITSHADER_2D_LUMAALPHA: - addBlitShaderToMap(blitShaderType, SHADER_2D, d3d11::CompilePS(device, g_PS_PassthroughLumAlpha2D, "Blit11 2D luminance alpha pixel shader")); - break; - case BLITSHADER_2D_RGBAUI: - addBlitShaderToMap(blitShaderType, SHADER_2D, d3d11::CompilePS(device, g_PS_PassthroughRGBA2DUI, "Blit11 2D RGBA UI pixel shader")); - break; - case BLITSHADER_2D_RGBAI: - addBlitShaderToMap(blitShaderType, SHADER_2D, d3d11::CompilePS(device, g_PS_PassthroughRGBA2DI, "Blit11 2D RGBA I pixel shader")); - break; - case BLITSHADER_2D_RGBUI: - addBlitShaderToMap(blitShaderType, SHADER_2D, d3d11::CompilePS(device, g_PS_PassthroughRGB2DUI, "Blit11 2D RGB UI pixel shader")); - break; - case BLITSHADER_2D_RGBI: - addBlitShaderToMap(blitShaderType, SHADER_2D, d3d11::CompilePS(device, g_PS_PassthroughRGB2DI, "Blit11 2D RGB I pixel shader")); - break; - case BLITSHADER_2D_RGUI: - addBlitShaderToMap(blitShaderType, SHADER_2D, d3d11::CompilePS(device, g_PS_PassthroughRG2DUI, "Blit11 2D RG UI pixel shader")); - break; - case BLITSHADER_2D_RGI: - addBlitShaderToMap(blitShaderType, SHADER_2D, d3d11::CompilePS(device, g_PS_PassthroughRG2DI, "Blit11 2D RG I pixel shader")); - break; - case BLITSHADER_2D_RUI: - addBlitShaderToMap(blitShaderType, SHADER_2D, d3d11::CompilePS(device, g_PS_PassthroughR2DUI, "Blit11 2D R UI pixel shader")); - break; - case BLITSHADER_2D_RI: - addBlitShaderToMap(blitShaderType, SHADER_2D, d3d11::CompilePS(device, g_PS_PassthroughR2DI, "Blit11 2D R I pixel shader")); - break; - case BLITSHADER_3D_RGBAF: - addBlitShaderToMap(blitShaderType, SHADER_3D, d3d11::CompilePS(device, g_PS_PassthroughRGBA3D, "Blit11 3D RGBA pixel shader")); - break; - case BLITSHADER_3D_RGBAUI: - addBlitShaderToMap(blitShaderType, SHADER_3D, d3d11::CompilePS(device, g_PS_PassthroughRGBA3DUI, "Blit11 3D UI RGBA pixel shader")); - break; - case BLITSHADER_3D_RGBAI: - addBlitShaderToMap(blitShaderType, SHADER_3D, d3d11::CompilePS(device, g_PS_PassthroughRGBA3DI, "Blit11 3D I RGBA pixel shader")); - break; - case BLITSHADER_3D_BGRAF: - addBlitShaderToMap(blitShaderType, SHADER_3D, d3d11::CompilePS(device, g_PS_PassthroughRGBA3D, "Blit11 3D BGRA pixel shader")); - break; - case BLITSHADER_3D_RGBF: - addBlitShaderToMap(blitShaderType, SHADER_3D, d3d11::CompilePS(device, g_PS_PassthroughRGB3D, "Blit11 3D RGB pixel shader")); - break; - case BLITSHADER_3D_RGBUI: - addBlitShaderToMap(blitShaderType, SHADER_3D, d3d11::CompilePS(device, g_PS_PassthroughRGB3DUI, "Blit11 3D RGB UI pixel shader")); - break; - case BLITSHADER_3D_RGBI: - addBlitShaderToMap(blitShaderType, SHADER_3D, d3d11::CompilePS(device, g_PS_PassthroughRGB3DI, "Blit11 3D RGB I pixel shader")); - break; - case BLITSHADER_3D_RGF: - addBlitShaderToMap(blitShaderType, SHADER_3D, d3d11::CompilePS(device, g_PS_PassthroughRG3D, "Blit11 3D RG pixel shader")); - break; - case BLITSHADER_3D_RGUI: - addBlitShaderToMap(blitShaderType, SHADER_3D, d3d11::CompilePS(device, g_PS_PassthroughRG3DUI, "Blit11 3D RG UI pixel shader")); - break; - case BLITSHADER_3D_RGI: - addBlitShaderToMap(blitShaderType, SHADER_3D, d3d11::CompilePS(device, g_PS_PassthroughRG3DI, "Blit11 3D RG I pixel shader")); - break; - case BLITSHADER_3D_RF: - addBlitShaderToMap(blitShaderType, SHADER_3D, d3d11::CompilePS(device, g_PS_PassthroughR3D, "Blit11 3D R pixel shader")); - break; - case BLITSHADER_3D_RUI: - addBlitShaderToMap(blitShaderType, SHADER_3D, d3d11::CompilePS(device, g_PS_PassthroughR3DUI, "Blit11 3D R UI pixel shader")); - break; - case BLITSHADER_3D_RI: - addBlitShaderToMap(blitShaderType, SHADER_3D, d3d11::CompilePS(device, g_PS_PassthroughR3DI, "Blit11 3D R I pixel shader")); - break; - case BLITSHADER_3D_ALPHA: - addBlitShaderToMap(blitShaderType, SHADER_3D, d3d11::CompilePS(device, g_PS_PassthroughRGBA3D, "Blit11 3D alpha pixel shader")); - break; - case BLITSHADER_3D_LUMA: - addBlitShaderToMap(blitShaderType, SHADER_3D, d3d11::CompilePS(device, g_PS_PassthroughLum3D, "Blit11 3D luminance pixel shader")); - break; - case BLITSHADER_3D_LUMAALPHA: - addBlitShaderToMap(blitShaderType, SHADER_3D, d3d11::CompilePS(device, g_PS_PassthroughLumAlpha3D, "Blit11 3D luminance alpha pixel shader")); - break; - default: - UNREACHABLE(); - return gl::Error(GL_INVALID_OPERATION, "Internal error"); + case BLITSHADER_2D_RGBAF: + ANGLE_TRY(addBlitShaderToMap(blitShaderType, SHADER_2D, + ShaderData(g_PS_PassthroughRGBA2D), + "Blit11 2D RGBA pixel shader")); + break; + case BLITSHADER_2D_BGRAF: + ANGLE_TRY(addBlitShaderToMap(blitShaderType, SHADER_2D, + ShaderData(g_PS_PassthroughRGBA2D), + "Blit11 2D BGRA pixel shader")); + break; + case BLITSHADER_2D_RGBF: + ANGLE_TRY(addBlitShaderToMap(blitShaderType, SHADER_2D, + ShaderData(g_PS_PassthroughRGB2D), + "Blit11 2D RGB pixel shader")); + break; + case BLITSHADER_2D_RGF: + ANGLE_TRY(addBlitShaderToMap(blitShaderType, SHADER_2D, + ShaderData(g_PS_PassthroughRG2D), + "Blit11 2D RG pixel shader")); + break; + case BLITSHADER_2D_RF: + ANGLE_TRY(addBlitShaderToMap(blitShaderType, SHADER_2D, ShaderData(g_PS_PassthroughR2D), + "Blit11 2D R pixel shader")); + break; + case BLITSHADER_2D_ALPHA: + ANGLE_TRY(addBlitShaderToMap(blitShaderType, SHADER_2D, ShaderData(g_PS_PassthroughA2D), + "Blit11 2D alpha pixel shader")); + break; + case BLITSHADER_2D_LUMA: + ANGLE_TRY(addBlitShaderToMap(blitShaderType, SHADER_2D, + ShaderData(g_PS_PassthroughLum2D), + "Blit11 2D lum pixel shader")); + break; + case BLITSHADER_2D_LUMAALPHA: + ANGLE_TRY(addBlitShaderToMap(blitShaderType, SHADER_2D, + ShaderData(g_PS_PassthroughLumAlpha2D), + "Blit11 2D luminance alpha pixel shader")); + break; + case BLITSHADER_2D_RGBAUI: + ANGLE_TRY(addBlitShaderToMap(blitShaderType, SHADER_2D, + ShaderData(g_PS_PassthroughRGBA2DUI), + "Blit11 2D RGBA UI pixel shader")); + break; + case BLITSHADER_2D_RGBAI: + ANGLE_TRY(addBlitShaderToMap(blitShaderType, SHADER_2D, + ShaderData(g_PS_PassthroughRGBA2DI), + "Blit11 2D RGBA I pixel shader")); + break; + case BLITSHADER_2D_RGBUI: + ANGLE_TRY(addBlitShaderToMap(blitShaderType, SHADER_2D, + ShaderData(g_PS_PassthroughRGB2DUI), + "Blit11 2D RGB UI pixel shader")); + break; + case BLITSHADER_2D_RGBI: + ANGLE_TRY(addBlitShaderToMap(blitShaderType, SHADER_2D, + ShaderData(g_PS_PassthroughRGB2DI), + "Blit11 2D RGB I pixel shader")); + break; + case BLITSHADER_2D_RGUI: + ANGLE_TRY(addBlitShaderToMap(blitShaderType, SHADER_2D, + ShaderData(g_PS_PassthroughRG2DUI), + "Blit11 2D RG UI pixel shader")); + break; + case BLITSHADER_2D_RGI: + ANGLE_TRY(addBlitShaderToMap(blitShaderType, SHADER_2D, + ShaderData(g_PS_PassthroughRG2DI), + "Blit11 2D RG I pixel shader")); + break; + case BLITSHADER_2D_RUI: + ANGLE_TRY(addBlitShaderToMap(blitShaderType, SHADER_2D, + ShaderData(g_PS_PassthroughR2DUI), + "Blit11 2D R UI pixel shader")); + break; + case BLITSHADER_2D_RI: + ANGLE_TRY(addBlitShaderToMap(blitShaderType, SHADER_2D, + ShaderData(g_PS_PassthroughR2DI), + "Blit11 2D R I pixel shader")); + break; + case BLITSHADER_3D_RGBAF: + ANGLE_TRY(addBlitShaderToMap(blitShaderType, SHADER_3D, + ShaderData(g_PS_PassthroughRGBA3D), + "Blit11 3D RGBA pixel shader")); + break; + case BLITSHADER_3D_RGBAUI: + ANGLE_TRY(addBlitShaderToMap(blitShaderType, SHADER_3D, + ShaderData(g_PS_PassthroughRGBA3DUI), + "Blit11 3D UI RGBA pixel shader")); + break; + case BLITSHADER_3D_RGBAI: + ANGLE_TRY(addBlitShaderToMap(blitShaderType, SHADER_3D, + ShaderData(g_PS_PassthroughRGBA3DI), + "Blit11 3D I RGBA pixel shader")); + break; + case BLITSHADER_3D_BGRAF: + ANGLE_TRY(addBlitShaderToMap(blitShaderType, SHADER_3D, + ShaderData(g_PS_PassthroughRGBA3D), + "Blit11 3D BGRA pixel shader")); + break; + case BLITSHADER_3D_RGBF: + ANGLE_TRY(addBlitShaderToMap(blitShaderType, SHADER_3D, + ShaderData(g_PS_PassthroughRGB3D), + "Blit11 3D RGB pixel shader")); + break; + case BLITSHADER_3D_RGBUI: + ANGLE_TRY(addBlitShaderToMap(blitShaderType, SHADER_3D, + ShaderData(g_PS_PassthroughRGB3DUI), + "Blit11 3D RGB UI pixel shader")); + break; + case BLITSHADER_3D_RGBI: + ANGLE_TRY(addBlitShaderToMap(blitShaderType, SHADER_3D, + ShaderData(g_PS_PassthroughRGB3DI), + "Blit11 3D RGB I pixel shader")); + break; + case BLITSHADER_3D_RGF: + ANGLE_TRY(addBlitShaderToMap(blitShaderType, SHADER_3D, + ShaderData(g_PS_PassthroughRG3D), + "Blit11 3D RG pixel shader")); + break; + case BLITSHADER_3D_RGUI: + ANGLE_TRY(addBlitShaderToMap(blitShaderType, SHADER_3D, + ShaderData(g_PS_PassthroughRG3DUI), + "Blit11 3D RG UI pixel shader")); + break; + case BLITSHADER_3D_RGI: + ANGLE_TRY(addBlitShaderToMap(blitShaderType, SHADER_3D, + ShaderData(g_PS_PassthroughRG3DI), + "Blit11 3D RG I pixel shader")); + break; + case BLITSHADER_3D_RF: + ANGLE_TRY(addBlitShaderToMap(blitShaderType, SHADER_3D, ShaderData(g_PS_PassthroughR3D), + "Blit11 3D R pixel shader")); + break; + case BLITSHADER_3D_RUI: + ANGLE_TRY(addBlitShaderToMap(blitShaderType, SHADER_3D, + ShaderData(g_PS_PassthroughR3DUI), + "Blit11 3D R UI pixel shader")); + break; + case BLITSHADER_3D_RI: + ANGLE_TRY(addBlitShaderToMap(blitShaderType, SHADER_3D, + ShaderData(g_PS_PassthroughR3DI), + "Blit11 3D R I pixel shader")); + break; + case BLITSHADER_3D_ALPHA: + ANGLE_TRY(addBlitShaderToMap(blitShaderType, SHADER_3D, + ShaderData(g_PS_PassthroughRGBA3D), + "Blit11 3D alpha pixel shader")); + break; + case BLITSHADER_3D_LUMA: + ANGLE_TRY(addBlitShaderToMap(blitShaderType, SHADER_3D, + ShaderData(g_PS_PassthroughLum3D), + "Blit11 3D luminance pixel shader")); + break; + case BLITSHADER_3D_LUMAALPHA: + ANGLE_TRY(addBlitShaderToMap(blitShaderType, SHADER_3D, + ShaderData(g_PS_PassthroughLumAlpha3D), + "Blit11 3D luminance alpha pixel shader")); + break; + + case BLITSHADER_2D_RGBAF_PREMULTIPLY: + ANGLE_TRY(addBlitShaderToMap(blitShaderType, SHADER_2D, ShaderData(g_PS_FtoF_PM_RGBA), + "Blit11 2D RGBA premultiply pixel shader")); + break; + + case BLITSHADER_2D_RGBAF_UNMULTIPLY: + ANGLE_TRY(addBlitShaderToMap(blitShaderType, SHADER_2D, ShaderData(g_PS_FtoF_UM_RGBA), + "Blit11 2D RGBA unmultiply pixel shader")); + break; + + case BLITSHADER_2D_RGBF_PREMULTIPLY: + ANGLE_TRY(addBlitShaderToMap(blitShaderType, SHADER_2D, ShaderData(g_PS_FtoF_PM_RGB), + "Blit11 2D RGB premultiply pixel shader")); + break; + + case BLITSHADER_2D_RGBF_UNMULTIPLY: + ANGLE_TRY(addBlitShaderToMap(blitShaderType, SHADER_2D, ShaderData(g_PS_FtoF_UM_RGB), + "Blit11 2D RGB unmultiply pixel shader")); + break; + + case BLITSHADER_2D_RGBAF_TOUI: + ANGLE_TRY(addBlitShaderToMap(blitShaderType, SHADER_2D, ShaderData(g_PS_FtoU_PT_RGBA), + "Blit11 2D RGBA to uint pixel shader")); + break; + + case BLITSHADER_2D_RGBAF_TOUI_PREMULTIPLY: + ANGLE_TRY(addBlitShaderToMap(blitShaderType, SHADER_2D, ShaderData(g_PS_FtoU_PM_RGBA), + "Blit11 2D RGBA to uint premultiply pixel shader")); + break; + + case BLITSHADER_2D_RGBAF_TOUI_UNMULTIPLY: + ANGLE_TRY(addBlitShaderToMap(blitShaderType, SHADER_2D, ShaderData(g_PS_FtoU_UM_RGBA), + "Blit11 2D RGBA to uint unmultiply pixel shader")); + break; + + case BLITSHADER_2D_RGBF_TOUI: + ANGLE_TRY(addBlitShaderToMap(blitShaderType, SHADER_2D, ShaderData(g_PS_FtoU_PT_RGB), + "Blit11 2D RGB to uint pixel shader")); + break; + + case BLITSHADER_2D_RGBF_TOUI_PREMULTIPLY: + ANGLE_TRY(addBlitShaderToMap(blitShaderType, SHADER_2D, ShaderData(g_PS_FtoU_PM_RGB), + "Blit11 2D RGB to uint premultiply pixel shader")); + break; + + case BLITSHADER_2D_RGBF_TOUI_UNMULTIPLY: + ANGLE_TRY(addBlitShaderToMap(blitShaderType, SHADER_2D, ShaderData(g_PS_FtoU_UM_RGB), + "Blit11 2D RGB to uint unmultiply pixel shader")); + break; + case BLITSHADER_2D_LUMAF_PREMULTIPLY: + ANGLE_TRY(addBlitShaderToMap(blitShaderType, SHADER_2D, ShaderData(g_PS_FtoF_PM_LUMA), + "Blit11 2D LUMA premultiply pixel shader")); + break; + case BLITSHADER_2D_LUMAF_UNMULTIPLY: + ANGLE_TRY(addBlitShaderToMap(blitShaderType, SHADER_2D, ShaderData(g_PS_FtoF_UM_LUMA), + "Blit11 2D LUMA unmultiply pixel shader")); + break; + case BLITSHADER_2D_LUMAALPHAF_PREMULTIPLY: + ANGLE_TRY(addBlitShaderToMap(blitShaderType, SHADER_2D, + ShaderData(g_PS_FtoF_PM_LUMAALPHA), + "Blit11 2D LUMAALPHA premultiply pixel shader")); + break; + case BLITSHADER_2D_LUMAALPHAF_UNMULTIPLY: + ANGLE_TRY(addBlitShaderToMap(blitShaderType, SHADER_2D, + ShaderData(g_PS_FtoF_UM_LUMAALPHA), + "Blit11 2D LUMAALPHA unmultiply pixel shader")); + break; + + default: + UNREACHABLE(); + return gl::InternalError() << "Internal error"; } blitShaderIt = mBlitShaderMap.find(blitShaderType); ASSERT(blitShaderIt != mBlitShaderMap.end()); *shader = &blitShaderIt->second; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error Blit11::getSwizzleShader(GLenum type, D3D11_SRV_DIMENSION viewDimension, const Shader **shader) +gl::Error Blit11::getSwizzleShader(GLenum type, + D3D11_SRV_DIMENSION viewDimension, + const Shader **shader) { SwizzleShaderType swizzleShaderType = GetSwizzleShaderType(type, viewDimension); if (swizzleShaderType == SWIZZLESHADER_INVALID) { - return gl::Error(GL_INVALID_OPERATION, "Swizzle shader type not found"); + return gl::InternalError() << "Swizzle shader type not found"; } auto swizzleShaderIt = mSwizzleShaderMap.find(swizzleShaderType); if (swizzleShaderIt != mSwizzleShaderMap.end()) { *shader = &swizzleShaderIt->second; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } // Swizzling shaders (OpenGL ES 3+) ASSERT(mRenderer->isES3Capable()); - ID3D11Device *device = mRenderer->getDevice(); - switch (swizzleShaderType) { - case SWIZZLESHADER_2D_FLOAT: - addSwizzleShaderToMap(swizzleShaderType, SHADER_2D, d3d11::CompilePS(device, g_PS_SwizzleF2D, "Blit11 2D F swizzle pixel shader")); - break; - case SWIZZLESHADER_2D_UINT: - addSwizzleShaderToMap(swizzleShaderType, SHADER_2D, d3d11::CompilePS(device, g_PS_SwizzleUI2D, "Blit11 2D UI swizzle pixel shader")); - break; - case SWIZZLESHADER_2D_INT: - addSwizzleShaderToMap(swizzleShaderType, SHADER_2D, d3d11::CompilePS(device, g_PS_SwizzleI2D, "Blit11 2D I swizzle pixel shader")); - break; - case SWIZZLESHADER_CUBE_FLOAT: - addSwizzleShaderToMap(swizzleShaderType, SHADER_3D, d3d11::CompilePS(device, g_PS_SwizzleF2DArray, "Blit11 2D Cube F swizzle pixel shader")); - break; - case SWIZZLESHADER_CUBE_UINT: - addSwizzleShaderToMap(swizzleShaderType, SHADER_3D, d3d11::CompilePS(device, g_PS_SwizzleUI2DArray, "Blit11 2D Cube UI swizzle pixel shader")); - break; - case SWIZZLESHADER_CUBE_INT: - addSwizzleShaderToMap(swizzleShaderType, SHADER_3D, d3d11::CompilePS(device, g_PS_SwizzleI2DArray, "Blit11 2D Cube I swizzle pixel shader")); - break; - case SWIZZLESHADER_3D_FLOAT: - addSwizzleShaderToMap(swizzleShaderType, SHADER_3D, d3d11::CompilePS(device, g_PS_SwizzleF3D, "Blit11 3D F swizzle pixel shader")); - break; - case SWIZZLESHADER_3D_UINT: - addSwizzleShaderToMap(swizzleShaderType, SHADER_3D, d3d11::CompilePS(device, g_PS_SwizzleUI3D, "Blit11 3D UI swizzle pixel shader")); - break; - case SWIZZLESHADER_3D_INT: - addSwizzleShaderToMap(swizzleShaderType, SHADER_3D, d3d11::CompilePS(device, g_PS_SwizzleI3D, "Blit11 3D I swizzle pixel shader")); - break; - case SWIZZLESHADER_ARRAY_FLOAT: - addSwizzleShaderToMap(swizzleShaderType, SHADER_3D, d3d11::CompilePS(device, g_PS_SwizzleF2DArray, "Blit11 2D Array F swizzle pixel shader")); - break; - case SWIZZLESHADER_ARRAY_UINT: - addSwizzleShaderToMap(swizzleShaderType, SHADER_3D, d3d11::CompilePS(device, g_PS_SwizzleUI2DArray, "Blit11 2D Array UI swizzle pixel shader")); - break; - case SWIZZLESHADER_ARRAY_INT: - addSwizzleShaderToMap(swizzleShaderType, SHADER_3D, d3d11::CompilePS(device, g_PS_SwizzleI2DArray, "Blit11 2D Array I swizzle pixel shader")); - break; - default: - UNREACHABLE(); - return gl::Error(GL_INVALID_OPERATION, "Internal error"); + case SWIZZLESHADER_2D_FLOAT: + ANGLE_TRY(addSwizzleShaderToMap(swizzleShaderType, SHADER_2D, + ShaderData(g_PS_SwizzleF2D), + "Blit11 2D F swizzle pixel shader")); + break; + case SWIZZLESHADER_2D_UINT: + ANGLE_TRY(addSwizzleShaderToMap(swizzleShaderType, SHADER_2D, + ShaderData(g_PS_SwizzleUI2D), + "Blit11 2D UI swizzle pixel shader")); + break; + case SWIZZLESHADER_2D_INT: + ANGLE_TRY(addSwizzleShaderToMap(swizzleShaderType, SHADER_2D, + ShaderData(g_PS_SwizzleI2D), + "Blit11 2D I swizzle pixel shader")); + break; + case SWIZZLESHADER_CUBE_FLOAT: + ANGLE_TRY(addSwizzleShaderToMap(swizzleShaderType, SHADER_3D, + ShaderData(g_PS_SwizzleF2DArray), + "Blit11 2D Cube F swizzle pixel shader")); + break; + case SWIZZLESHADER_CUBE_UINT: + ANGLE_TRY(addSwizzleShaderToMap(swizzleShaderType, SHADER_3D, + ShaderData(g_PS_SwizzleUI2DArray), + "Blit11 2D Cube UI swizzle pixel shader")); + break; + case SWIZZLESHADER_CUBE_INT: + ANGLE_TRY(addSwizzleShaderToMap(swizzleShaderType, SHADER_3D, + ShaderData(g_PS_SwizzleI2DArray), + "Blit11 2D Cube I swizzle pixel shader")); + break; + case SWIZZLESHADER_3D_FLOAT: + ANGLE_TRY(addSwizzleShaderToMap(swizzleShaderType, SHADER_3D, + ShaderData(g_PS_SwizzleF3D), + "Blit11 3D F swizzle pixel shader")); + break; + case SWIZZLESHADER_3D_UINT: + ANGLE_TRY(addSwizzleShaderToMap(swizzleShaderType, SHADER_3D, + ShaderData(g_PS_SwizzleUI3D), + "Blit11 3D UI swizzle pixel shader")); + break; + case SWIZZLESHADER_3D_INT: + ANGLE_TRY(addSwizzleShaderToMap(swizzleShaderType, SHADER_3D, + ShaderData(g_PS_SwizzleI3D), + "Blit11 3D I swizzle pixel shader")); + break; + case SWIZZLESHADER_ARRAY_FLOAT: + ANGLE_TRY(addSwizzleShaderToMap(swizzleShaderType, SHADER_3D, + ShaderData(g_PS_SwizzleF2DArray), + "Blit11 2D Array F swizzle pixel shader")); + break; + case SWIZZLESHADER_ARRAY_UINT: + ANGLE_TRY(addSwizzleShaderToMap(swizzleShaderType, SHADER_3D, + ShaderData(g_PS_SwizzleUI2DArray), + "Blit11 2D Array UI swizzle pixel shader")); + break; + case SWIZZLESHADER_ARRAY_INT: + ANGLE_TRY(addSwizzleShaderToMap(swizzleShaderType, SHADER_3D, + ShaderData(g_PS_SwizzleI2DArray), + "Blit11 2D Array I swizzle pixel shader")); + break; + default: + UNREACHABLE(); + return gl::InternalError() << "Internal error"; } swizzleShaderIt = mSwizzleShaderMap.find(swizzleShaderType); ASSERT(swizzleShaderIt != mSwizzleShaderMap.end()); *shader = &swizzleShaderIt->second; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } +gl::ErrorOrResult Blit11::resolveDepth(const gl::Context *context, + RenderTarget11 *depth) +{ + ANGLE_TRY(initResources()); + + // Multisampled depth stencil SRVs are not available in feature level 10.0 + ASSERT(mRenderer->getRenderer11DeviceCaps().featureLevel > D3D_FEATURE_LEVEL_10_0); + + const auto &extents = depth->getExtents(); + auto *deviceContext = mRenderer->getDeviceContext(); + auto *stateManager = mRenderer->getStateManager(); + + ANGLE_TRY(initResolveDepthOnly(depth->getFormatSet(), extents)); + + ANGLE_TRY(mResolveDepthStencilVS.resolve(mRenderer)); + ANGLE_TRY(mResolveDepthPS.resolve(mRenderer)); + + // Apply the necessary state changes to the D3D11 immediate device context. + stateManager->setInputLayout(nullptr); + stateManager->setPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + stateManager->setDrawShaders(&mResolveDepthStencilVS.getObj(), nullptr, + &mResolveDepthPS.getObj()); + stateManager->setRasterizerState(nullptr); + stateManager->setDepthStencilState(&mDepthStencilState, 0xFFFFFFFF); + stateManager->setRenderTargets(nullptr, 0, mResolvedDepthDSView.get()); + stateManager->setSimpleBlendState(nullptr); + stateManager->setSimpleViewport(extents); + + // Set the viewport + stateManager->setShaderResourceShared(gl::SAMPLER_PIXEL, 0, &depth->getShaderResourceView()); + + // Trigger the blit on the GPU. + deviceContext->Draw(6, 0); + + return mResolvedDepth; } + +gl::Error Blit11::initResolveDepthOnly(const d3d11::Format &format, const gl::Extents &extents) +{ + if (mResolvedDepth.valid() && extents == mResolvedDepth.getExtents() && + format.texFormat == mResolvedDepth.getFormat()) + { + return gl::NoError(); + } + + D3D11_TEXTURE2D_DESC textureDesc; + textureDesc.Width = extents.width; + textureDesc.Height = extents.height; + textureDesc.MipLevels = 1; + textureDesc.ArraySize = 1; + textureDesc.Format = format.texFormat; + textureDesc.SampleDesc.Count = 1; + textureDesc.SampleDesc.Quality = 0; + textureDesc.Usage = D3D11_USAGE_DEFAULT; + textureDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL | D3D11_BIND_SHADER_RESOURCE; + textureDesc.CPUAccessFlags = 0; + textureDesc.MiscFlags = 0; + + ANGLE_TRY(mRenderer->allocateTexture(textureDesc, format, &mResolvedDepth)); + mResolvedDepth.setDebugName("Blit11::mResolvedDepth"); + + D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc; + dsvDesc.Flags = 0; + dsvDesc.Format = format.dsvFormat; + dsvDesc.Texture2D.MipSlice = 0; + dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D; + + ANGLE_TRY(mRenderer->allocateResource(dsvDesc, mResolvedDepth.get(), &mResolvedDepthDSView)); + mResolvedDepthDSView.setDebugName("Blit11::mResolvedDepthDSView"); + + // Possibly D3D11 bug or undefined behaviour: Clear the DSV so that our first render + // works as expected. Otherwise the results of the first use seem to be incorrect. + ID3D11DeviceContext *context = mRenderer->getDeviceContext(); + context->ClearDepthStencilView(mResolvedDepthDSView.get(), D3D11_CLEAR_DEPTH, 1.0f, 0); + + return gl::NoError(); +} + +gl::Error Blit11::initResolveDepthStencil(const gl::Extents &extents) +{ + // Check if we need to recreate depth stencil view + if (mResolvedDepthStencil.valid() && extents == mResolvedDepthStencil.getExtents()) + { + ASSERT(mResolvedDepthStencil.getFormat() == DXGI_FORMAT_R32G32_FLOAT); + return gl::NoError(); + } + + if (mResolvedDepthStencil.valid()) + { + releaseResolveDepthStencilResources(); + } + + const auto &formatSet = d3d11::Format::Get(GL_RG32F, mRenderer->getRenderer11DeviceCaps()); + + D3D11_TEXTURE2D_DESC textureDesc; + textureDesc.Width = extents.width; + textureDesc.Height = extents.height; + textureDesc.MipLevels = 1; + textureDesc.ArraySize = 1; + textureDesc.Format = formatSet.texFormat; + textureDesc.SampleDesc.Count = 1; + textureDesc.SampleDesc.Quality = 0; + textureDesc.Usage = D3D11_USAGE_DEFAULT; + textureDesc.BindFlags = D3D11_BIND_RENDER_TARGET; + textureDesc.CPUAccessFlags = 0; + textureDesc.MiscFlags = 0; + + ANGLE_TRY(mRenderer->allocateTexture(textureDesc, formatSet, &mResolvedDepthStencil)); + mResolvedDepthStencil.setDebugName("Blit11::mResolvedDepthStencil"); + + ANGLE_TRY(mRenderer->allocateResourceNoDesc(mResolvedDepthStencil.get(), + &mResolvedDepthStencilRTView)); + mResolvedDepthStencilRTView.setDebugName("Blit11::mResolvedDepthStencilRTView"); + + return gl::NoError(); +} + +gl::ErrorOrResult Blit11::resolveStencil(const gl::Context *context, + RenderTarget11 *depthStencil, + bool alsoDepth) +{ + ANGLE_TRY(initResources()); + + // Multisampled depth stencil SRVs are not available in feature level 10.0 + ASSERT(mRenderer->getRenderer11DeviceCaps().featureLevel > D3D_FEATURE_LEVEL_10_0); + + const auto &extents = depthStencil->getExtents(); + + ANGLE_TRY(initResolveDepthStencil(extents)); + + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); + auto *stateManager = mRenderer->getStateManager(); + ID3D11Resource *stencilResource = depthStencil->getTexture().get(); + + // Check if we need to re-create the stencil SRV. + if (mStencilSRV.valid()) + { + ID3D11Resource *priorResource = nullptr; + mStencilSRV.get()->GetResource(&priorResource); + + if (stencilResource != priorResource) + { + mStencilSRV.reset(); + } + + SafeRelease(priorResource); + } + + if (!mStencilSRV.valid()) + { + D3D11_SHADER_RESOURCE_VIEW_DESC srViewDesc; + srViewDesc.Format = GetStencilSRVFormat(depthStencil->getFormatSet()); + srViewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DMS; + + ANGLE_TRY(mRenderer->allocateResource(srViewDesc, stencilResource, &mStencilSRV)); + mStencilSRV.setDebugName("Blit11::mStencilSRV"); + } + + // Notify the Renderer that all state should be invalidated. + ANGLE_TRY(mResolveDepthStencilVS.resolve(mRenderer)); + + // Resolving the depth buffer works by sampling the depth in the shader using a SRV, then + // writing to the resolved depth buffer using SV_Depth. We can't use this method for stencil + // because SV_StencilRef isn't supported until HLSL 5.1/D3D11.3. + const d3d11::PixelShader *pixelShader = nullptr; + if (alsoDepth) + { + ANGLE_TRY(mResolveDepthStencilPS.resolve(mRenderer)); + pixelShader = &mResolveDepthStencilPS.getObj(); + } + else + { + ANGLE_TRY(mResolveStencilPS.resolve(mRenderer)); + pixelShader = &mResolveStencilPS.getObj(); + } + + // Apply the necessary state changes to the D3D11 immediate device context. + stateManager->setInputLayout(nullptr); + stateManager->setPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + stateManager->setDrawShaders(&mResolveDepthStencilVS.getObj(), nullptr, pixelShader); + stateManager->setRasterizerState(nullptr); + stateManager->setDepthStencilState(nullptr, 0xFFFFFFFF); + stateManager->setRenderTarget(mResolvedDepthStencilRTView.get(), nullptr); + stateManager->setSimpleBlendState(nullptr); + + // Set the viewport + stateManager->setSimpleViewport(extents); + stateManager->setShaderResourceShared(gl::SAMPLER_PIXEL, 0, + &depthStencil->getShaderResourceView()); + stateManager->setShaderResource(gl::SAMPLER_PIXEL, 1, &mStencilSRV); + + // Trigger the blit on the GPU. + deviceContext->Draw(6, 0); + + gl::Box copyBox(0, 0, 0, extents.width, extents.height, 1); + + TextureHelper11 dest; + ANGLE_TRY_RESULT( + mRenderer->createStagingTexture(ResourceType::Texture2D, depthStencil->getFormatSet(), + extents, StagingAccess::READ_WRITE), + dest); + + const auto ©Function = GetCopyDepthStencilFunction(depthStencil->getInternalFormat()); + const auto &dsFormatSet = depthStencil->getFormatSet(); + const auto &dsDxgiInfo = d3d11::GetDXGIFormatSizeInfo(dsFormatSet.texFormat); + + ANGLE_TRY(copyAndConvertImpl(mResolvedDepthStencil, 0, copyBox, extents, dest, copyBox, extents, + nullptr, 0, 0, 0, 8u, dsDxgiInfo.pixelBytes, copyFunction)); + + // Return the resolved depth texture, which the caller must Release. + return dest; +} + +void Blit11::releaseResolveDepthStencilResources() +{ + mStencilSRV.reset(); + mResolvedDepthStencilRTView.reset(); +} + +} // namespace rx diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Blit11.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Blit11.h index 906616131e..14078f9db8 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Blit11.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Blit11.h @@ -10,8 +10,9 @@ #define LIBANGLE_RENDERER_D3D_D3D11_BLIT11_H_ #include "common/angleutils.h" -#include "libANGLE/angletypes.h" #include "libANGLE/Error.h" +#include "libANGLE/angletypes.h" +#include "libANGLE/renderer/d3d/d3d11/ResourceManager11.h" #include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h" #include @@ -26,36 +27,84 @@ class Blit11 : angle::NonCopyable 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 swizzleTexture(const gl::Context *context, + const d3d11::SharedSRV &source, + const d3d11::RenderTargetView &dest, + const gl::Extents &size, + const gl::SwizzleState &swizzleTarget); - gl::Error copyTexture(ID3D11ShaderResourceView *source, + gl::Error copyTexture(const gl::Context *context, + const d3d11::SharedSRV &source, const gl::Box &sourceArea, const gl::Extents &sourceSize, - ID3D11RenderTargetView *dest, + GLenum sourceFormat, + const d3d11::RenderTargetView &dest, const gl::Box &destArea, const gl::Extents &destSize, const gl::Rectangle *scissor, GLenum destFormat, GLenum filter, - bool maskOffAlpha); + bool maskOffAlpha, + bool unpackPremultiplyAlpha, + bool unpackUnmultiplyAlpha); - 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, + gl::Error copyStencil(const gl::Context *context, + const TextureHelper11 &source, + unsigned int sourceSubresource, + const gl::Box &sourceArea, + const gl::Extents &sourceSize, + const TextureHelper11 &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, + gl::Error copyDepth(const gl::Context *context, + const d3d11::SharedSRV &source, + const gl::Box &sourceArea, + const gl::Extents &sourceSize, + const d3d11::DepthStencilView &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, + gl::Error copyDepthStencil(const TextureHelper11 &source, + unsigned int sourceSubresource, + const gl::Box &sourceArea, + const gl::Extents &sourceSize, + const TextureHelper11 &dest, + unsigned int destSubresource, + const gl::Box &destArea, + const gl::Extents &destSize, const gl::Rectangle *scissor); + gl::ErrorOrResult resolveDepth(const gl::Context *context, + RenderTarget11 *depth); + + gl::ErrorOrResult resolveStencil(const gl::Context *context, + RenderTarget11 *depthStencil, + bool alsoDepth); + + using BlitConvertFunction = void(const gl::Box &sourceArea, + const gl::Box &destArea, + const gl::Rectangle &clipRect, + const gl::Extents &sourceSize, + unsigned int sourceRowPitch, + unsigned int destRowPitch, + ptrdiff_t readOffset, + ptrdiff_t writeOffset, + size_t copySize, + size_t srcPixelStride, + size_t destPixelStride, + const uint8_t *sourceData, + uint8_t *destData); + private: enum BlitShaderType { BLITSHADER_INVALID, + + // Passthrough shaders BLITSHADER_2D_RGBAF, BLITSHADER_2D_BGRAF, BLITSHADER_2D_RGBF, @@ -88,6 +137,27 @@ class Blit11 : angle::NonCopyable BLITSHADER_3D_ALPHA, BLITSHADER_3D_LUMA, BLITSHADER_3D_LUMAALPHA, + + // Multiply alpha shaders + BLITSHADER_2D_RGBAF_PREMULTIPLY, + BLITSHADER_2D_RGBAF_UNMULTIPLY, + + BLITSHADER_2D_RGBF_PREMULTIPLY, + BLITSHADER_2D_RGBF_UNMULTIPLY, + + BLITSHADER_2D_RGBAF_TOUI, + BLITSHADER_2D_RGBAF_TOUI_PREMULTIPLY, + BLITSHADER_2D_RGBAF_TOUI_UNMULTIPLY, + + BLITSHADER_2D_RGBF_TOUI, + BLITSHADER_2D_RGBF_TOUI_PREMULTIPLY, + BLITSHADER_2D_RGBF_TOUI_UNMULTIPLY, + + BLITSHADER_2D_LUMAF_PREMULTIPLY, + BLITSHADER_2D_LUMAF_UNMULTIPLY, + + BLITSHADER_2D_LUMAALPHAF_PREMULTIPLY, + BLITSHADER_2D_LUMAALPHAF_UNMULTIPLY }; enum SwizzleShaderType @@ -107,9 +177,13 @@ class Blit11 : angle::NonCopyable SWIZZLESHADER_ARRAY_INT, }; - 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, + 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); enum ShaderDimension @@ -120,38 +194,102 @@ class Blit11 : angle::NonCopyable struct Shader { + Shader(); + Shader(Shader &&other); + ~Shader(); + Shader &operator=(Shader &&other); + ShaderDimension dimension; - ID3D11PixelShader *pixelShader; + d3d11::PixelShader pixelShader; }; struct ShaderSupport { - ID3D11InputLayout *inputLayout; - ID3D11VertexShader *vertexShader; - ID3D11GeometryShader *geometryShader; + const d3d11::InputLayout *inputLayout; + const d3d11::VertexShader *vertexShader; + const d3d11::GeometryShader *geometryShader; WriteVertexFunction vertexWriteFunction; }; gl::Error initResources(); - void freeResources(); - ShaderSupport getShaderSupport(const Shader &shader); + gl::Error getShaderSupport(const Shader &shader, ShaderSupport *supportOut); - static BlitShaderType GetBlitShaderType(GLenum destinationFormat, bool isSigned, ShaderDimension dimension); + static BlitShaderType GetBlitShaderType(GLenum destinationFormat, + GLenum sourceFormat, + bool isSigned, + bool unpackPremultiplyAlpha, + bool unpackUnmultiplyAlpha, + ShaderDimension dimension); static SwizzleShaderType GetSwizzleShaderType(GLenum type, D3D11_SRV_DIMENSION dimensionality); - 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); - - void addBlitShaderToMap(BlitShaderType blitShaderType, ShaderDimension dimension, ID3D11PixelShader *ps); - - gl::Error getBlitShader(GLenum destFormat, bool isSigned, ShaderDimension dimension, const Shader **shaderOut); - gl::Error getSwizzleShader(GLenum type, D3D11_SRV_DIMENSION viewDimension, const Shader **shaderOut); - - void addSwizzleShaderToMap(SwizzleShaderType swizzleShaderType, ShaderDimension dimension, ID3D11PixelShader *ps); + gl::Error copyDepthStencilImpl(const TextureHelper11 &source, + unsigned int sourceSubresource, + const gl::Box &sourceArea, + const gl::Extents &sourceSize, + const TextureHelper11 &dest, + unsigned int destSubresource, + const gl::Box &destArea, + const gl::Extents &destSize, + const gl::Rectangle *scissor, + bool stencilOnly); + + gl::Error copyAndConvertImpl(const TextureHelper11 &source, + unsigned int sourceSubresource, + const gl::Box &sourceArea, + const gl::Extents &sourceSize, + const TextureHelper11 &destStaging, + const gl::Box &destArea, + const gl::Extents &destSize, + const gl::Rectangle *scissor, + size_t readOffset, + size_t writeOffset, + size_t copySize, + size_t srcPixelStride, + size_t destPixelStride, + BlitConvertFunction *convertFunction); + + gl::Error copyAndConvert(const TextureHelper11 &source, + unsigned int sourceSubresource, + const gl::Box &sourceArea, + const gl::Extents &sourceSize, + const TextureHelper11 &dest, + unsigned int destSubresource, + const gl::Box &destArea, + const gl::Extents &destSize, + const gl::Rectangle *scissor, + size_t readOffset, + size_t writeOffset, + size_t copySize, + size_t srcPixelStride, + size_t destPixelStride, + BlitConvertFunction *convertFunction); + + gl::Error addBlitShaderToMap(BlitShaderType blitShaderType, + ShaderDimension dimension, + const ShaderData &shaderData, + const char *name); + + gl::Error getBlitShader(GLenum destFormat, + GLenum sourceFormat, + bool isSigned, + bool unpackPremultiplyAlpha, + bool unpackUnmultiplyAlpha, + ShaderDimension dimension, + const Shader **shaderOut); + gl::Error getSwizzleShader(GLenum type, + D3D11_SRV_DIMENSION viewDimension, + const Shader **shaderOut); + + gl::Error addSwizzleShaderToMap(SwizzleShaderType swizzleShaderType, + ShaderDimension dimension, + const ShaderData &shaderData, + const char *name); void clearShaderMap(); + void releaseResolveDepthStencilResources(); + gl::Error initResolveDepthOnly(const d3d11::Format &format, const gl::Extents &extents); + gl::Error initResolveDepthStencil(const gl::Extents &extents); Renderer11 *mRenderer; @@ -159,12 +297,12 @@ class Blit11 : angle::NonCopyable std::map mSwizzleShaderMap; bool mResourcesInitialized; - ID3D11Buffer *mVertexBuffer; - ID3D11SamplerState *mPointSampler; - ID3D11SamplerState *mLinearSampler; - ID3D11RasterizerState *mScissorEnabledRasterizerState; - ID3D11RasterizerState *mScissorDisabledRasterizerState; - ID3D11DepthStencilState *mDepthStencilState; + d3d11::Buffer mVertexBuffer; + d3d11::SamplerState mPointSampler; + d3d11::SamplerState mLinearSampler; + d3d11::RasterizerState mScissorEnabledRasterizerState; + d3d11::RasterizerState mScissorDisabledRasterizerState; + d3d11::DepthStencilState mDepthStencilState; d3d11::LazyInputLayout mQuad2DIL; d3d11::LazyShader mQuad2DVS; @@ -176,9 +314,19 @@ class Blit11 : angle::NonCopyable d3d11::LazyBlendState mAlphaMaskBlendState; - ID3D11Buffer *mSwizzleCB; + d3d11::Buffer mSwizzleCB; + + d3d11::LazyShader mResolveDepthStencilVS; + d3d11::LazyShader mResolveDepthPS; + d3d11::LazyShader mResolveDepthStencilPS; + d3d11::LazyShader mResolveStencilPS; + d3d11::ShaderResourceView mStencilSRV; + TextureHelper11 mResolvedDepthStencil; + d3d11::RenderTargetView mResolvedDepthStencilRTView; + TextureHelper11 mResolvedDepth; + d3d11::DepthStencilView mResolvedDepthDSView; }; -} +} // namespace rx -#endif // LIBANGLE_RENDERER_D3D_D3D11_BLIT11_H_ +#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 index 0d5dc08b03..2317c9abdb 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Buffer11.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Buffer11.cpp @@ -13,10 +13,14 @@ #include "common/MemoryBuffer.h" #include "libANGLE/renderer/d3d/IndexDataManager.h" #include "libANGLE/renderer/d3d/VertexDataManager.h" -#include "libANGLE/renderer/d3d/d3d11/Renderer11.h" #include "libANGLE/renderer/d3d/d3d11/RenderTarget11.h" -#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h" +#include "libANGLE/renderer/d3d/d3d11/Renderer11.h" #include "libANGLE/renderer/d3d/d3d11/formatutils11.h" +#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h" +#include "libANGLE/renderer/renderer_utils.h" + +namespace rx +{ namespace { @@ -27,41 +31,41 @@ GLuint ReadIndexValueFromIndices(const uint8_t *data, size_t index) return reinterpret_cast(data)[index]; } typedef GLuint (*ReadIndexValueFunction)(const uint8_t *data, size_t index); -} - -#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(nullptr), offset(0) +enum class CopyResult { -} + RECREATED, + NOT_RECREATED, +}; -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) +void CalculateConstantBufferParams(GLintptr offset, + GLsizeiptr size, + UINT *outFirstConstant, + UINT *outNumConstants) { + // The offset must be aligned to 256 bytes (should have been enforced by glBindBufferRange). + ASSERT(offset % 256 == 0); + + // firstConstant and numConstants are expressed in constants of 16-bytes. Furthermore they must + // be a multiple of 16 constants. + *outFirstConstant = static_cast(offset / 16); + + // The GL size is not required to be aligned to a 256 bytes boundary. + // Round the size up to a 256 bytes boundary then express the results in constants of 16-bytes. + *outNumConstants = static_cast(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 } +} // anonymous namespace + namespace gl_d3d11 { -D3D11_MAP GetD3DMapTypeFromBits(GLbitfield access) +D3D11_MAP GetD3DMapTypeFromBits(BufferUsage usage, GLbitfield access) { bool readBit = ((access & GL_MAP_READ_BIT) != 0); bool writeBit = ((access & GL_MAP_WRITE_BIT) != 0); @@ -77,7 +81,8 @@ D3D11_MAP GetD3DMapTypeFromBits(GLbitfield access) } else if (writeBit && !readBit) { - return D3D11_MAP_WRITE; + // Special case for uniform storage - we only allow full buffer updates. + return usage == BUFFER_USAGE_UNIFORM ? D3D11_MAP_WRITE_DISCARD : D3D11_MAP_WRITE; } else if (writeBit && readBit) { @@ -89,7 +94,7 @@ D3D11_MAP GetD3DMapTypeFromBits(GLbitfield access) return D3D11_MAP_READ; } } -} +} // namespace gl_d3d11 // Each instance of Buffer11::BufferStorage is specialized for a class of D3D binding points // - vertex/transform feedback buffers @@ -106,16 +111,22 @@ class Buffer11::BufferStorage : angle::NonCopyable size_t getSize() const { return mBufferSize; } void setDataRevision(DataRevision rev) { mRevision = rev; } - virtual bool isMappable() const = 0; + virtual bool isCPUAccessible(GLbitfield access) const = 0; + + virtual bool isGPUAccessible() 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 gl::ErrorOrResult copyFromStorage(const gl::Context *context, + BufferStorage *source, + size_t sourceOffset, + size_t size, + size_t destOffset) = 0; + virtual gl::Error resize(const gl::Context *context, size_t size, bool preserveData) = 0; - virtual uint8_t *map(size_t offset, size_t length, GLbitfield access) = 0; - virtual void unmap() = 0; + virtual gl::Error map(size_t offset, + size_t length, + GLbitfield access, + uint8_t **mapPointerOut) = 0; + virtual void unmap() = 0; gl::Error setData(const uint8_t *data, size_t offset, size_t size); @@ -133,28 +144,41 @@ class Buffer11::BufferStorage : angle::NonCopyable class Buffer11::NativeStorage : public Buffer11::BufferStorage { public: - NativeStorage(Renderer11 *renderer, BufferUsage usage); + NativeStorage(Renderer11 *renderer, + BufferUsage usage, + const OnBufferDataDirtyChannel *onStorageChanged); ~NativeStorage() override; - bool isMappable() const override { return mUsage == BUFFER_USAGE_STAGING; } + bool isCPUAccessible(GLbitfield access) const override; + + bool isGPUAccessible() const override { return true; } - 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; + const d3d11::Buffer &getBuffer() const { return mBuffer; } + gl::ErrorOrResult copyFromStorage(const gl::Context *context, + BufferStorage *source, + size_t sourceOffset, + size_t size, + size_t destOffset) override; + gl::Error resize(const gl::Context *context, size_t size, bool preserveData) override; - uint8_t *map(size_t offset, size_t length, GLbitfield access) override; + gl::Error map(size_t offset, + size_t length, + GLbitfield access, + uint8_t **mapPointerOut) override; void unmap() override; + gl::ErrorOrResult getSRVForFormat(DXGI_FORMAT srvFormat); + private: - static void fillBufferDesc(D3D11_BUFFER_DESC *bufferDesc, + static void FillBufferDesc(D3D11_BUFFER_DESC *bufferDesc, Renderer11 *renderer, BufferUsage usage, unsigned int bufferSize); + void clearSRVs(); - ID3D11Buffer *mNativeStorage; + d3d11::Buffer mBuffer; + const OnBufferDataDirtyChannel *mOnStorageChanged; + std::map mBufferResourceViews; }; // A emulated indexed buffer storage represents an underlying D3D11 buffer for data @@ -166,28 +190,32 @@ class Buffer11::EmulatedIndexedStorage : public Buffer11::BufferStorage EmulatedIndexedStorage(Renderer11 *renderer); ~EmulatedIndexedStorage() override; - bool isMappable() const override { return true; } + bool isCPUAccessible(GLbitfield access) const override { return true; } + + bool isGPUAccessible() const override { return false; } - ID3D11Buffer *getNativeStorage(); + gl::ErrorOrResult getBuffer(SourceIndexData *indexInfo, + const TranslatedAttribute &attribute, + GLint startVertex); - bool copyFromStorage(BufferStorage *source, - size_t sourceOffset, - size_t size, - size_t destOffset) override; + gl::ErrorOrResult copyFromStorage(const gl::Context *context, + BufferStorage *source, + size_t sourceOffset, + size_t size, + size_t destOffset) override; - gl::Error resize(size_t size, bool preserveData) override; + gl::Error resize(const gl::Context *context, size_t size, bool preserveData) override; - uint8_t *map(size_t offset, size_t length, GLbitfield access) override; + gl::Error map(size_t offset, + size_t length, + GLbitfield access, + uint8_t **mapPointerOut) override; void unmap() override; - bool update(SourceIndexData *indexInfo, const TranslatedAttribute *attribute); private: - ID3D11Buffer *mNativeStorage; // contains expanded data for use by D3D - MemoryBuffer mMemoryBuffer; // original data (not expanded) - MemoryBuffer mIndicesMemoryBuffer; // indices data - SourceIndexData mIndexInfo; // indices information - size_t mAttributeStride; // per element stride in bytes - size_t mAttributeOffset; // starting offset + d3d11::Buffer mBuffer; // contains expanded data for use by D3D + angle::MemoryBuffer mMemoryBuffer; // original data (not expanded) + angle::MemoryBuffer mIndicesMemoryBuffer; // indices data }; // Pack storage represents internal storage for pack buffers. We implement pack buffers @@ -198,24 +226,32 @@ class Buffer11::PackStorage : public Buffer11::BufferStorage 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; + bool isCPUAccessible(GLbitfield access) const override { return true; } - uint8_t *map(size_t offset, size_t length, GLbitfield access) override; + bool isGPUAccessible() const override { return false; } + + gl::ErrorOrResult copyFromStorage(const gl::Context *context, + BufferStorage *source, + size_t sourceOffset, + size_t size, + size_t destOffset) override; + gl::Error resize(const gl::Context *context, size_t size, bool preserveData) override; + + gl::Error map(size_t offset, + size_t length, + GLbitfield access, + uint8_t **mapPointerOut) override; void unmap() override; - gl::Error packPixels(const gl::FramebufferAttachment &readAttachment, + gl::Error packPixels(const gl::Context *context, + const gl::FramebufferAttachment &readAttachment, const PackPixelsParams ¶ms); private: gl::Error flushQueuedPackCommand(); TextureHelper11 mStagingTexture; - MemoryBuffer mMemoryBuffer; + angle::MemoryBuffer mMemoryBuffer; std::unique_ptr mQueuedPackCommand; PackPixelsParams mPackParams; bool mDataModified; @@ -230,37 +266,46 @@ class Buffer11::SystemMemoryStorage : public Buffer11::BufferStorage 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; + bool isCPUAccessible(GLbitfield access) const override { return true; } + + bool isGPUAccessible() const override { return false; } - uint8_t *map(size_t offset, size_t length, GLbitfield access) override; + gl::ErrorOrResult copyFromStorage(const gl::Context *context, + BufferStorage *source, + size_t sourceOffset, + size_t size, + size_t destOffset) override; + gl::Error resize(const gl::Context *context, size_t size, bool preserveData) override; + + gl::Error map(size_t offset, + size_t length, + GLbitfield access, + uint8_t **mapPointerOut) override; void unmap() override; - MemoryBuffer *getSystemCopy() { return &mSystemCopy; } + angle::MemoryBuffer *getSystemCopy() { return &mSystemCopy; } protected: - MemoryBuffer mSystemCopy; + angle::MemoryBuffer mSystemCopy; }; -Buffer11::Buffer11(Renderer11 *renderer) - : BufferD3D(renderer), +Buffer11::Buffer11(const gl::BufferState &state, Renderer11 *renderer) + : BufferD3D(state, renderer), mRenderer(renderer), mSize(0), mMappedStorage(nullptr), - mBufferStorages(BUFFER_USAGE_COUNT, nullptr), + mBufferStorages({}), + mLatestBufferStorage(nullptr), + mDeallocThresholds({}), + mIdleness({}), mConstantBufferStorageAdditionalSize(0), - mMaxConstantBufferLruCount(0), - mReadUsageCount(0) + mMaxConstantBufferLruCount(0) { } Buffer11::~Buffer11() { - for (auto &storage : mBufferStorages) + for (BufferStorage *&storage : mBufferStorages) { SafeDelete(storage); } @@ -273,79 +318,74 @@ Buffer11::~Buffer11() mRenderer->onBufferDelete(this); } -gl::Error Buffer11::setData(const void *data, size_t size, GLenum usage) +gl::Error Buffer11::setData(const gl::Context *context, + gl::BufferBinding target, + const void *data, + size_t size, + gl::BufferUsage usage) { - gl::Error error = setSubData(data, size, 0); - if (error.isError()) - { - return error; - } - - updateD3DBufferUsage(usage); - return error; + updateD3DBufferUsage(context, usage); + ANGLE_TRY(setSubData(context, target, data, size, 0)); + return gl::NoError(); } -gl::Error Buffer11::getData(const uint8_t **outData) +gl::Error Buffer11::getData(const gl::Context *context, const uint8_t **outData) { SystemMemoryStorage *systemMemoryStorage = nullptr; - gl::Error error = getSystemMemoryStorage(&systemMemoryStorage); - - if (error.isError()) - { - *outData = nullptr; - return error; - } - - mReadUsageCount = 0; + ANGLE_TRY_RESULT(getSystemMemoryStorage(context), systemMemoryStorage); ASSERT(systemMemoryStorage->getSize() >= mSize); *outData = systemMemoryStorage->getSystemCopy()->data(); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error Buffer11::getSystemMemoryStorage(SystemMemoryStorage **storageOut) +gl::ErrorOrResult Buffer11::getSystemMemoryStorage( + const gl::Context *context) { - 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); + BufferStorage *storage = nullptr; + ANGLE_TRY_RESULT(getBufferStorage(context, BUFFER_USAGE_SYSTEM_MEMORY), storage); + return GetAs(storage); } -gl::Error Buffer11::setSubData(const void *data, size_t size, size_t offset) +gl::Error Buffer11::setSubData(const gl::Context *context, + gl::BufferBinding target, + 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. - + // Try using a constant storage for constant buffers BufferStorage *writeBuffer = nullptr; - if (supportsDirectBinding()) + if (target == gl::BufferBinding::Uniform) { - writeBuffer = getStagingStorage(); - - if (!writeBuffer) + // If we are a very large uniform buffer, keep system memory storage around so that we + // aren't forced to read back from a constant buffer. We also check the workaround for + // Intel - this requires us to use system memory so we don't end up having to copy from + // a constant buffer to a staging buffer. + // TODO(jmadill): Use Context caps. + if (offset == 0 && size >= mSize && + size <= static_cast(mRenderer->getNativeCaps().maxUniformBlockSize) && + !mRenderer->getWorkarounds().useSystemMemoryForConstantBuffers) + { + ANGLE_TRY_RESULT(getBufferStorage(context, BUFFER_USAGE_UNIFORM), writeBuffer); + } + else { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate internal buffer."); + ANGLE_TRY_RESULT(getSystemMemoryStorage(context), writeBuffer); } } + else if (supportsDirectBinding()) + { + ANGLE_TRY_RESULT(getStagingStorage(context), writeBuffer); + } else { - SystemMemoryStorage *systemMemoryStorage = nullptr; - gl::Error error = getSystemMemoryStorage(&systemMemoryStorage); - if (error.isError()) - { - return error; - } - - writeBuffer = systemMemoryStorage; + ANGLE_TRY_RESULT(getSystemMemoryStorage(context), writeBuffer); } ASSERT(writeBuffer); @@ -355,24 +395,25 @@ gl::Error Buffer11::setSubData(const void *data, size_t size, size_t offset) if (writeBuffer->getSize() < requiredSize) { bool preserveData = (offset > 0); - gl::Error error = writeBuffer->resize(requiredSize, preserveData); - if (error.isError()) - { - return error; - } + ANGLE_TRY(writeBuffer->resize(context, requiredSize, preserveData)); } - writeBuffer->setData(static_cast(data), offset, size); - writeBuffer->setDataRevision(writeBuffer->getDataRevision() + 1); + ANGLE_TRY(writeBuffer->setData(static_cast(data), offset, size)); + onStorageUpdate(writeBuffer); + + // Notify any vertex arrays that we have dirty data. + // TODO(jmadill): Use a more fine grained notification for data updates. + mDirectBroadcastChannel.signal(context); } mSize = std::max(mSize, requiredSize); - invalidateStaticData(D3D_BUFFER_INVALIDATE_WHOLE_CACHE); + invalidateStaticData(context); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error Buffer11::copySubData(BufferImpl *source, +gl::Error Buffer11::copySubData(const gl::Context *context, + BufferImpl *source, GLintptr sourceOffset, GLintptr destOffset, GLsizeiptr size) @@ -380,28 +421,32 @@ gl::Error Buffer11::copySubData(BufferImpl *source, Buffer11 *sourceBuffer = GetAs(source); ASSERT(sourceBuffer != nullptr); - BufferStorage *copyDest = getLatestBufferStorage(); + BufferStorage *copyDest = nullptr; + ANGLE_TRY_RESULT(getLatestBufferStorage(context), copyDest); + if (!copyDest) { - copyDest = getStagingStorage(); + ANGLE_TRY_RESULT(getStagingStorage(context), copyDest); } - BufferStorage *copySource = sourceBuffer->getLatestBufferStorage(); + BufferStorage *copySource = nullptr; + ANGLE_TRY_RESULT(sourceBuffer->getLatestBufferStorage(context), copySource); - if (!copySource || !copyDest) + if (!copySource) { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate internal staging buffer."); + ANGLE_TRY_RESULT(sourceBuffer->getStagingStorage(context), copySource); } - // 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()) + ASSERT(copySource && copyDest); + + // A staging buffer is needed if there is no cpu-cpu or gpu-gpu copy path avaiable. + if (!copyDest->isGPUAccessible() && !copySource->isCPUAccessible(GL_MAP_READ_BIT)) { - copySource = sourceBuffer->getStagingStorage(); + ANGLE_TRY_RESULT(sourceBuffer->getStagingStorage(context), copySource); } - else if (copySource->getUsage() == BUFFER_USAGE_PIXEL_PACK && !copyDest->isMappable()) + else if (!copySource->isGPUAccessible() && !copyDest->isCPUAccessible(GL_MAP_WRITE_BIT)) { - copyDest = getStagingStorage(); + ANGLE_TRY_RESULT(getStagingStorage(context), copyDest); } // D3D11 does not allow overlapped copies until 11.1, and only if the @@ -411,36 +456,48 @@ gl::Error Buffer11::copySubData(BufferImpl *source, { if (copySource->getUsage() == BUFFER_USAGE_STAGING) { - copySource = getBufferStorage(BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK); + ANGLE_TRY_RESULT(getBufferStorage(context, BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK), + copySource); } else { - copySource = getStagingStorage(); + ANGLE_TRY_RESULT(getStagingStorage(context), copySource); } } - copyDest->copyFromStorage(copySource, sourceOffset, size, destOffset); - copyDest->setDataRevision(copyDest->getDataRevision() + 1); + CopyResult copyResult = CopyResult::NOT_RECREATED; + ANGLE_TRY_RESULT(copyDest->copyFromStorage(context, copySource, sourceOffset, size, destOffset), + copyResult); + onStorageUpdate(copyDest); mSize = std::max(mSize, destOffset + size); - invalidateStaticData(D3D_BUFFER_INVALIDATE_WHOLE_CACHE); + invalidateStaticData(context); + + // Also notify that direct buffers are dirty. + mDirectBroadcastChannel.signal(context); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error Buffer11::map(GLenum access, GLvoid **mapPtr) +gl::Error Buffer11::map(const gl::Context *context, GLenum access, void **mapPtr) { // GL_OES_mapbuffer uses an enum instead of a bitfield for it's access, convert to a bitfield // and call mapRange. ASSERT(access == GL_WRITE_ONLY_OES); - return mapRange(0, mSize, GL_MAP_WRITE_BIT, mapPtr); + return mapRange(context, 0, mSize, GL_MAP_WRITE_BIT, mapPtr); } -gl::Error Buffer11::mapRange(size_t offset, size_t length, GLbitfield access, GLvoid **mapPtr) +gl::Error Buffer11::mapRange(const gl::Context *context, + size_t offset, + size_t length, + GLbitfield access, + void **mapPtr) { ASSERT(!mMappedStorage); - BufferStorage *latestStorage = getLatestBufferStorage(); + BufferStorage *latestStorage = nullptr; + ANGLE_TRY_RESULT(getLatestBufferStorage(context), latestStorage); + if (latestStorage && (latestStorage->getUsage() == BUFFER_USAGE_PIXEL_PACK || latestStorage->getUsage() == BUFFER_USAGE_STAGING)) { @@ -449,34 +506,32 @@ gl::Error Buffer11::mapRange(size_t offset, size_t length, GLbitfield access, GL } else { - // Fall back to using the staging buffer if the latest storage does - // not exist or is not CPU-accessible. - mMappedStorage = getStagingStorage(); + // Fall back to using the staging buffer if the latest storage does not exist or is not + // CPU-accessible. + ANGLE_TRY_RESULT(getStagingStorage(context), mMappedStorage); } if (!mMappedStorage) { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate mappable internal buffer."); + return gl::OutOfMemory() << "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); - invalidateStaticData(D3D_BUFFER_INVALIDATE_WHOLE_CACHE); + onStorageUpdate(mMappedStorage); + invalidateStaticData(context); } - uint8_t *mappedBuffer = mMappedStorage->map(offset, length, access); - if (!mappedBuffer) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to map internal buffer."); - } + uint8_t *mappedBuffer = nullptr; + ANGLE_TRY(mMappedStorage->map(offset, length, access, &mappedBuffer)); + ASSERT(mappedBuffer); - *mapPtr = static_cast(mappedBuffer); - return gl::Error(GL_NO_ERROR); + *mapPtr = static_cast(mappedBuffer); + return gl::NoError(); } -gl::Error Buffer11::unmap(GLboolean *result) +gl::Error Buffer11::unmap(const gl::Context *context, GLboolean *result) { ASSERT(mMappedStorage); mMappedStorage->unmap(); @@ -485,168 +540,171 @@ gl::Error Buffer11::unmap(GLboolean *result) // TODO: detect if we had corruption. if so, return false. *result = GL_TRUE; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -void Buffer11::markTransformFeedbackUsage() +gl::Error Buffer11::markTransformFeedbackUsage(const gl::Context *context) { - BufferStorage *transformFeedbackStorage = - getBufferStorage(BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK); + BufferStorage *transformFeedbackStorage = nullptr; + ANGLE_TRY_RESULT(getBufferStorage(context, BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK), + transformFeedbackStorage); if (transformFeedbackStorage) { - transformFeedbackStorage->setDataRevision(transformFeedbackStorage->getDataRevision() + 1); + onStorageUpdate(transformFeedbackStorage); } - invalidateStaticData(D3D_BUFFER_INVALIDATE_WHOLE_CACHE); + invalidateStaticData(context); + return gl::NoError(); } -void Buffer11::markBufferUsage() +void Buffer11::updateDeallocThreshold(BufferUsage usage) { - mReadUsageCount++; + // The following strategy was tuned on the Oort online benchmark (http://oortonline.gl/) + // as well as a custom microbenchmark (IndexConversionPerfTest.Run/index_range_d3d11) + + // First readback: 8 unmodified uses before we free buffer memory. + // After that, double the threshold each time until we reach the max. + if (mDeallocThresholds[usage] == 0) + { + mDeallocThresholds[usage] = 8; + } + else if (mDeallocThresholds[usage] < std::numeric_limits::max() / 2u) + { + mDeallocThresholds[usage] *= 2u; + } + else + { + mDeallocThresholds[usage] = std::numeric_limits::max(); + } +} - // Free the system memory storage if we decide it isn't being used very often. - const unsigned int usageLimit = 5; +// Free the storage if we decide it isn't being used very often. +gl::Error Buffer11::checkForDeallocation(const gl::Context *context, BufferUsage usage) +{ + mIdleness[usage]++; - BufferStorage *&sysMemUsage = mBufferStorages[BUFFER_USAGE_SYSTEM_MEMORY]; - if (mReadUsageCount > usageLimit && sysMemUsage != nullptr) + BufferStorage *&storage = mBufferStorages[usage]; + if (storage != nullptr && mIdleness[usage] > mDeallocThresholds[usage]) { - if (getLatestBufferStorage() != sysMemUsage) + BufferStorage *latestStorage = nullptr; + ANGLE_TRY_RESULT(getLatestBufferStorage(context), latestStorage); + if (latestStorage != storage) { - SafeDelete(sysMemUsage); + SafeDelete(storage); } } + + return gl::NoError(); } -ID3D11Buffer *Buffer11::getBuffer(BufferUsage usage) +// Keep system memory when we are using it for the canonical version of data. +bool Buffer11::canDeallocateSystemMemory() const { - markBufferUsage(); - - BufferStorage *bufferStorage = getBufferStorage(usage); - - if (!bufferStorage) + // Must keep system memory on Intel. + if (mRenderer->getWorkarounds().useSystemMemoryForConstantBuffers) { - // Storage out-of-memory - return nullptr; + return false; } - return GetAs(bufferStorage)->getNativeStorage(); + return (!mBufferStorages[BUFFER_USAGE_UNIFORM] || + mSize <= mRenderer->getNativeCaps().maxUniformBlockSize); } -ID3D11Buffer *Buffer11::getEmulatedIndexedBuffer(SourceIndexData *indexInfo, - const TranslatedAttribute *attribute) +void Buffer11::markBufferUsage(BufferUsage usage) { - markBufferUsage(); - - assert(indexInfo != nullptr); - assert(attribute != nullptr); + mIdleness[usage] = 0; +} - BufferStorage *bufferStorage = getBufferStorage(BUFFER_USAGE_EMULATED_INDEXED_VERTEX); - if (!bufferStorage) +gl::Error Buffer11::garbageCollection(const gl::Context *context, BufferUsage currentUsage) +{ + if (currentUsage != BUFFER_USAGE_SYSTEM_MEMORY && canDeallocateSystemMemory()) { - // Storage out-of-memory - return nullptr; + ANGLE_TRY(checkForDeallocation(context, BUFFER_USAGE_SYSTEM_MEMORY)); } - EmulatedIndexedStorage *emulatedStorage = GetAs(bufferStorage); - if (!emulatedStorage->update(indexInfo, attribute)) + if (currentUsage != BUFFER_USAGE_STAGING) { - // Storage out-of-memory - return nullptr; + ANGLE_TRY(checkForDeallocation(context, BUFFER_USAGE_STAGING)); } - return emulatedStorage->getNativeStorage(); + return gl::NoError(); } -ID3D11Buffer *Buffer11::getConstantBufferRange(GLintptr offset, GLsizeiptr size) +gl::ErrorOrResult Buffer11::getBuffer(const gl::Context *context, BufferUsage usage) { - markBufferUsage(); + BufferStorage *storage = nullptr; + ANGLE_TRY_RESULT(getBufferStorage(context, usage), storage); + return GetAs(storage)->getBuffer().get(); +} - BufferStorage *bufferStorage; +gl::ErrorOrResult Buffer11::getEmulatedIndexedBuffer( + const gl::Context *context, + SourceIndexData *indexInfo, + const TranslatedAttribute &attribute, + GLint startVertex) +{ + ASSERT(indexInfo); - if (offset == 0) - { - bufferStorage = getBufferStorage(BUFFER_USAGE_UNIFORM); - } - else - { - bufferStorage = getConstantBufferRangeStorage(offset, size); - } + BufferStorage *untypedStorage = nullptr; + ANGLE_TRY_RESULT(getBufferStorage(context, BUFFER_USAGE_EMULATED_INDEXED_VERTEX), + untypedStorage); - if (!bufferStorage) - { - // Storage out-of-memory - return nullptr; - } + EmulatedIndexedStorage *emulatedStorage = GetAs(untypedStorage); + + const d3d11::Buffer *nativeStorage = nullptr; + ANGLE_TRY_RESULT(emulatedStorage->getBuffer(indexInfo, attribute, startVertex), nativeStorage); - return GetAs(bufferStorage)->getNativeStorage(); + return nativeStorage->get(); } -ID3D11ShaderResourceView *Buffer11::getSRV(DXGI_FORMAT srvFormat) +gl::Error Buffer11::getConstantBufferRange(const gl::Context *context, + GLintptr offset, + GLsizeiptr size, + const d3d11::Buffer **bufferOut, + UINT *firstConstantOut, + UINT *numConstantsOut) { - BufferStorage *storage = getBufferStorage(BUFFER_USAGE_PIXEL_UNPACK); + BufferStorage *bufferStorage = nullptr; - if (!storage) + if (offset == 0 || mRenderer->getRenderer11DeviceCaps().supportsConstantBufferOffsets) { - // Storage out-of-memory - return nullptr; + ANGLE_TRY_RESULT(getBufferStorage(context, BUFFER_USAGE_UNIFORM), bufferStorage); + CalculateConstantBufferParams(offset, size, firstConstantOut, numConstantsOut); } - - ID3D11Buffer *buffer = GetAs(storage)->getNativeStorage(); - - auto bufferSRVIt = mBufferResourceViews.find(srvFormat); - - if (bufferSRVIt != mBufferResourceViews.end()) + else { - 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); - } + ANGLE_TRY_RESULT(getConstantBufferRangeStorage(context, offset, size), bufferStorage); + *firstConstantOut = 0; + *numConstantsOut = 0; } - ID3D11Device *device = mRenderer->getDevice(); - ID3D11ShaderResourceView *bufferSRV = nullptr; - - const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(srvFormat); + *bufferOut = &GetAs(bufferStorage)->getBuffer(); - D3D11_SHADER_RESOURCE_VIEW_DESC bufferSRVDesc; - bufferSRVDesc.Buffer.ElementOffset = 0; - bufferSRVDesc.Buffer.ElementWidth = - static_cast(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 gl::NoError(); +} - return bufferSRV; +gl::ErrorOrResult Buffer11::getSRV(const gl::Context *context, + DXGI_FORMAT srvFormat) +{ + BufferStorage *storage = nullptr; + ANGLE_TRY_RESULT(getBufferStorage(context, BUFFER_USAGE_PIXEL_UNPACK), storage); + NativeStorage *nativeStorage = GetAs(storage); + return nativeStorage->getSRVForFormat(srvFormat); } -gl::Error Buffer11::packPixels(const gl::FramebufferAttachment &readAttachment, +gl::Error Buffer11::packPixels(const gl::Context *context, + const gl::FramebufferAttachment &readAttachment, const PackPixelsParams ¶ms) { - PackStorage *packStorage = getPackStorage(); - BufferStorage *latestStorage = getLatestBufferStorage(); + PackStorage *packStorage = nullptr; + ANGLE_TRY_RESULT(getPackStorage(context), packStorage); - if (packStorage) - { - gl::Error error = packStorage->packPixels(readAttachment, params); - if (error.isError()) - { - return error; - } - packStorage->setDataRevision(latestStorage ? latestStorage->getDataRevision() + 1 : 1); - } + ASSERT(packStorage); + ANGLE_TRY(packStorage->packPixels(context, readAttachment, params)); + onStorageUpdate(packStorage); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } size_t Buffer11::getTotalCPUBufferMemoryBytes() const @@ -662,48 +720,56 @@ size_t Buffer11::getTotalCPUBufferMemoryBytes() const return allocationSize; } -Buffer11::BufferStorage *Buffer11::getBufferStorage(BufferUsage usage) +gl::ErrorOrResult Buffer11::getBufferStorage(const gl::Context *context, + BufferUsage usage) { ASSERT(0 <= usage && usage < BUFFER_USAGE_COUNT); BufferStorage *&newStorage = mBufferStorages[usage]; if (!newStorage) { - if (usage == BUFFER_USAGE_PIXEL_PACK) - { - newStorage = new PackStorage(mRenderer); - } - else if (usage == BUFFER_USAGE_SYSTEM_MEMORY) - { - newStorage = new SystemMemoryStorage(mRenderer); - } - else if (usage == BUFFER_USAGE_EMULATED_INDEXED_VERTEX) - { - newStorage = new EmulatedIndexedStorage(mRenderer); - } - else - { - // buffer is not allocated, create it - newStorage = new NativeStorage(mRenderer, usage); - } + newStorage = allocateStorage(usage); } + markBufferUsage(usage); + // resize buffer if (newStorage->getSize() < mSize) { - if (newStorage->resize(mSize, true).isError()) - { - // Out of memory error - return nullptr; - } + ANGLE_TRY(newStorage->resize(context, mSize, true)); } - updateBufferStorage(newStorage, 0, mSize); + ASSERT(newStorage); + + ANGLE_TRY(updateBufferStorage(context, newStorage, 0, mSize)); + ANGLE_TRY(garbageCollection(context, usage)); return newStorage; } -Buffer11::BufferStorage *Buffer11::getConstantBufferRangeStorage(GLintptr offset, GLsizeiptr size) +Buffer11::BufferStorage *Buffer11::allocateStorage(BufferUsage usage) +{ + updateDeallocThreshold(usage); + switch (usage) + { + case BUFFER_USAGE_PIXEL_PACK: + return new PackStorage(mRenderer); + case BUFFER_USAGE_SYSTEM_MEMORY: + return new SystemMemoryStorage(mRenderer); + case BUFFER_USAGE_EMULATED_INDEXED_VERTEX: + return new EmulatedIndexedStorage(mRenderer); + case BUFFER_USAGE_INDEX: + case BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK: + return new NativeStorage(mRenderer, usage, &mDirectBroadcastChannel); + default: + return new NativeStorage(mRenderer, usage, nullptr); + } +} + +gl::ErrorOrResult Buffer11::getConstantBufferRangeStorage( + const gl::Context *context, + GLintptr offset, + GLsizeiptr size) { BufferStorage *newStorage; @@ -714,7 +780,7 @@ Buffer11::BufferStorage *Buffer11::getConstantBufferRangeStorage(GLintptr offset if (!cacheEntry->storage) { - cacheEntry->storage = new NativeStorage(mRenderer, BUFFER_USAGE_UNIFORM); + cacheEntry->storage = allocateStorage(BUFFER_USAGE_UNIFORM); cacheEntry->lruCount = ++mMaxConstantBufferLruCount; } @@ -722,6 +788,8 @@ Buffer11::BufferStorage *Buffer11::getConstantBufferRangeStorage(GLintptr offset newStorage = cacheEntry->storage; } + markBufferUsage(BUFFER_USAGE_UNIFORM); + if (newStorage->getSize() < static_cast(size)) { size_t maximumAllowedAdditionalSize = 2 * getSize(); @@ -733,8 +801,7 @@ Buffer11::BufferStorage *Buffer11::getConstantBufferRangeStorage(GLintptr offset auto iter = std::min_element(std::begin(mConstantBufferRangeStoragesCache), std::end(mConstantBufferRangeStoragesCache), [](const ConstantBufferCache::value_type &a, - const ConstantBufferCache::value_type &b) - { + const ConstantBufferCache::value_type &b) { return a.second.lruCount < b.second.lruCount; }); @@ -746,12 +813,7 @@ Buffer11::BufferStorage *Buffer11::getConstantBufferRangeStorage(GLintptr offset mConstantBufferRangeStoragesCache.erase(iter); } - if (newStorage->resize(size, false).isError()) - { - // Out of memory error - return nullptr; - } - + ANGLE_TRY(newStorage->resize(context, size, false)); mConstantBufferStorageAdditionalSize += sizeDelta; // We don't copy the old data when resizing the constant buffer because the data may be @@ -760,103 +822,148 @@ Buffer11::BufferStorage *Buffer11::getConstantBufferRangeStorage(GLintptr offset newStorage->setDataRevision(0); } - updateBufferStorage(newStorage, offset, size); - + ANGLE_TRY(updateBufferStorage(context, newStorage, offset, size)); + ANGLE_TRY(garbageCollection(context, BUFFER_USAGE_UNIFORM)); return newStorage; } -void Buffer11::updateBufferStorage(BufferStorage *storage, size_t sourceOffset, size_t storageSize) +gl::Error Buffer11::updateBufferStorage(const gl::Context *context, + BufferStorage *storage, + size_t sourceOffset, + size_t storageSize) { - BufferStorage *latestBuffer = getLatestBufferStorage(); - if (latestBuffer && latestBuffer->getDataRevision() > storage->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 && - storage->getUsage() != BUFFER_USAGE_STAGING && - (!latestBuffer->isMappable() || !storage->isMappable())) - { - NativeStorage *stagingBuffer = getStagingStorage(); + BufferStorage *latestBuffer = nullptr; + ANGLE_TRY_RESULT(getLatestBufferStorage(context), latestBuffer); - stagingBuffer->copyFromStorage(latestBuffer, 0, latestBuffer->getSize(), 0); - stagingBuffer->setDataRevision(latestBuffer->getDataRevision()); - - latestBuffer = stagingBuffer; - } + ASSERT(storage); - // if copyFromStorage returns true, the D3D buffer has been recreated - // and we should update our serial - if (storage->copyFromStorage(latestBuffer, sourceOffset, storageSize, 0)) - { - updateSerial(); - } - storage->setDataRevision(latestBuffer->getDataRevision()); + if (!latestBuffer) + { + onStorageUpdate(storage); + return gl::NoError(); } -} -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 = nullptr; - DataRevision latestRevision = 0; - for (auto &storage : mBufferStorages) + if (latestBuffer->getDataRevision() <= storage->getDataRevision()) { - if (storage && (!latestStorage || storage->getDataRevision() > latestRevision)) - { - latestStorage = storage; - latestRevision = storage->getDataRevision(); - } + return gl::NoError(); } - // resize buffer - if (latestStorage && latestStorage->getSize() < mSize) + // 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 && + storage->getUsage() != BUFFER_USAGE_STAGING && + (!latestBuffer->isCPUAccessible(GL_MAP_READ_BIT) || + !storage->isCPUAccessible(GL_MAP_WRITE_BIT))) { - if (latestStorage->resize(mSize, true).isError()) - { - // Out of memory error - return nullptr; - } + NativeStorage *stagingBuffer = nullptr; + ANGLE_TRY_RESULT(getStagingStorage(context), stagingBuffer); + + CopyResult copyResult = CopyResult::NOT_RECREATED; + ANGLE_TRY_RESULT( + stagingBuffer->copyFromStorage(context, latestBuffer, 0, latestBuffer->getSize(), 0), + copyResult); + onCopyStorage(stagingBuffer, latestBuffer); + + latestBuffer = stagingBuffer; } - return latestStorage; + CopyResult copyResult = CopyResult::NOT_RECREATED; + ANGLE_TRY_RESULT(storage->copyFromStorage(context, latestBuffer, sourceOffset, storageSize, 0), + copyResult); + // If the D3D buffer has been recreated, we should update our serial. + if (copyResult == CopyResult::RECREATED) + { + updateSerial(); + } + onCopyStorage(storage, latestBuffer); + return gl::NoError(); } -Buffer11::NativeStorage *Buffer11::getStagingStorage() +gl::ErrorOrResult Buffer11::getLatestBufferStorage( + const gl::Context *context) const { - BufferStorage *stagingStorage = getBufferStorage(BUFFER_USAGE_STAGING); - - if (!stagingStorage) + // resize buffer + if (mLatestBufferStorage && mLatestBufferStorage->getSize() < mSize) { - // Out-of-memory - return nullptr; + ANGLE_TRY(mLatestBufferStorage->resize(context, mSize, true)); } - return GetAs(stagingStorage); + return mLatestBufferStorage; } -Buffer11::PackStorage *Buffer11::getPackStorage() +gl::ErrorOrResult Buffer11::getStagingStorage(const gl::Context *context) { - BufferStorage *packStorage = getBufferStorage(BUFFER_USAGE_PIXEL_PACK); - - if (!packStorage) - { - // Out-of-memory - return nullptr; - } + BufferStorage *stagingStorage = nullptr; + ANGLE_TRY_RESULT(getBufferStorage(context, BUFFER_USAGE_STAGING), stagingStorage); + return GetAs(stagingStorage); +} +gl::ErrorOrResult Buffer11::getPackStorage(const gl::Context *context) +{ + BufferStorage *packStorage = nullptr; + ANGLE_TRY_RESULT(getBufferStorage(context, BUFFER_USAGE_PIXEL_PACK), packStorage); return GetAs(packStorage); } +size_t Buffer11::getSize() const +{ + return mSize; +} + 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); + return (mUsage == D3DBufferUsage::STATIC); +} + +void Buffer11::initializeStaticData(const gl::Context *context) +{ + BufferD3D::initializeStaticData(context); + + // Notify when static data changes. + mStaticBroadcastChannel.signal(context); } +void Buffer11::invalidateStaticData(const gl::Context *context) +{ + BufferD3D::invalidateStaticData(context); + + // Notify when static data changes. + mStaticBroadcastChannel.signal(context); +} + +OnBufferDataDirtyChannel *Buffer11::getStaticBroadcastChannel() +{ + return &mStaticBroadcastChannel; +} + +OnBufferDataDirtyChannel *Buffer11::getDirectBroadcastChannel() +{ + return &mDirectBroadcastChannel; +} + +void Buffer11::onCopyStorage(BufferStorage *dest, BufferStorage *source) +{ + ASSERT(source && mLatestBufferStorage); + dest->setDataRevision(source->getDataRevision()); + + // Only update the latest buffer storage if our usage index is lower. See comment in header. + if (dest->getUsage() < mLatestBufferStorage->getUsage()) + { + mLatestBufferStorage = dest; + } +} + +void Buffer11::onStorageUpdate(BufferStorage *updatedStorage) +{ + updatedStorage->setDataRevision(updatedStorage->getDataRevision() + 1); + mLatestBufferStorage = updatedStorage; +} + +// Buffer11::BufferStorage implementation + Buffer11::BufferStorage::BufferStorage(Renderer11 *renderer, BufferUsage usage) : mRenderer(renderer), mRevision(0), mUsage(usage), mBufferSize(0) { @@ -864,113 +971,118 @@ Buffer11::BufferStorage::BufferStorage(Renderer11 *renderer, BufferUsage usage) gl::Error Buffer11::BufferStorage::setData(const uint8_t *data, size_t offset, size_t size) { - ASSERT(isMappable()); + ASSERT(isCPUAccessible(GL_MAP_WRITE_BIT)); - uint8_t *writePointer = map(offset, size, GL_MAP_WRITE_BIT); - if (!writePointer) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to map internal buffer."); - } + // Uniform storage can have a different internal size than the buffer size. Ensure we don't + // overflow. + size_t mapSize = std::min(size, mBufferSize - offset); + + uint8_t *writePointer = nullptr; + ANGLE_TRY(map(offset, mapSize, GL_MAP_WRITE_BIT, &writePointer)); - memcpy(writePointer, data, size); + memcpy(writePointer, data, mapSize); unmap(); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -Buffer11::NativeStorage::NativeStorage(Renderer11 *renderer, BufferUsage usage) - : BufferStorage(renderer, usage), mNativeStorage(nullptr) +// Buffer11::NativeStorage implementation + +Buffer11::NativeStorage::NativeStorage(Renderer11 *renderer, + BufferUsage usage, + const OnBufferDataDirtyChannel *onStorageChanged) + : BufferStorage(renderer, usage), mBuffer(), mOnStorageChanged(onStorageChanged) { } Buffer11::NativeStorage::~NativeStorage() { - SafeRelease(mNativeStorage); + clearSRVs(); } -// Returns true if it recreates the direct buffer -bool Buffer11::NativeStorage::copyFromStorage(BufferStorage *source, - size_t sourceOffset, - size_t size, - size_t destOffset) +bool Buffer11::NativeStorage::isCPUAccessible(GLbitfield access) const { - ID3D11DeviceContext *context = mRenderer->getDeviceContext(); + if ((access & GL_MAP_READ_BIT) != 0) + { + // Read is more exclusive than write mappability. + return (mUsage == BUFFER_USAGE_STAGING); + } + ASSERT((access & GL_MAP_WRITE_BIT) != 0); + return (mUsage == BUFFER_USAGE_STAGING || mUsage == BUFFER_USAGE_UNIFORM); +} +// Returns true if it recreates the direct buffer +gl::ErrorOrResult Buffer11::NativeStorage::copyFromStorage(const gl::Context *context, + BufferStorage *source, + size_t sourceOffset, + size_t size, + size_t destOffset) +{ size_t requiredSize = destOffset + size; - bool createBuffer = !mNativeStorage || mBufferSize < requiredSize; + bool createBuffer = !mBuffer.valid() || mBufferSize < requiredSize; // (Re)initialize D3D buffer if needed + bool preserveData = (destOffset > 0); if (createBuffer) { - bool preserveData = (destOffset > 0); - resize(requiredSize, preserveData); + ANGLE_TRY(resize(context, requiredSize, preserveData)); + } + + size_t clampedSize = size; + if (mUsage == BUFFER_USAGE_UNIFORM) + { + clampedSize = std::min(clampedSize, mBufferSize - destOffset); } 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); - ASSERT(SUCCEEDED(hr)); - if (FAILED(hr)) - { - source->unmap(); - return false; - } + ASSERT(source->isCPUAccessible(GL_MAP_READ_BIT) && isCPUAccessible(GL_MAP_WRITE_BIT)); - uint8_t *destPointer = static_cast(mappedResource.pData) + destOffset; + // Uniform buffers must be mapped with write/discard. + ASSERT(!(preserveData && mUsage == BUFFER_USAGE_UNIFORM)); - // Offset bounds are validated at the API layer - ASSERT(sourceOffset + size <= destOffset + mBufferSize); - memcpy(destPointer, sourcePointer, size); + uint8_t *sourcePointer = nullptr; + ANGLE_TRY(source->map(sourceOffset, clampedSize, GL_MAP_READ_BIT, &sourcePointer)); - context->Unmap(mNativeStorage, 0); + auto err = setData(sourcePointer, destOffset, clampedSize); source->unmap(); + ANGLE_TRY(err); } else { D3D11_BOX srcBox; srcBox.left = static_cast(sourceOffset); - srcBox.right = static_cast(sourceOffset + size); + srcBox.right = static_cast(sourceOffset + clampedSize); srcBox.top = 0; srcBox.bottom = 1; srcBox.front = 0; srcBox.back = 1; - ID3D11Buffer *sourceBuffer = GetAs(source)->getNativeStorage(); + const d3d11::Buffer *sourceBuffer = &GetAs(source)->getBuffer(); - context->CopySubresourceRegion(mNativeStorage, 0, static_cast(destOffset), 0, - 0, sourceBuffer, 0, &srcBox); + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); + deviceContext->CopySubresourceRegion(mBuffer.get(), 0, + static_cast(destOffset), 0, 0, + sourceBuffer->get(), 0, &srcBox); } - return createBuffer; + return createBuffer ? CopyResult::RECREATED : CopyResult::NOT_RECREATED; } -gl::Error Buffer11::NativeStorage::resize(size_t size, bool preserveData) +gl::Error Buffer11::NativeStorage::resize(const gl::Context *context, + size_t size, + bool preserveData) { - ID3D11Device *device = mRenderer->getDevice(); - ID3D11DeviceContext *context = mRenderer->getDeviceContext(); - D3D11_BUFFER_DESC bufferDesc; - fillBufferDesc(&bufferDesc, mRenderer, mUsage, static_cast(size)); - - ID3D11Buffer *newBuffer; - HRESULT result = device->CreateBuffer(&bufferDesc, nullptr, &newBuffer); - - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal buffer, result: 0x%X.", - result); - } + FillBufferDesc(&bufferDesc, mRenderer, mUsage, static_cast(size)); - d3d11::SetDebugName(newBuffer, "Buffer11::NativeStorage"); + d3d11::Buffer newBuffer; + ANGLE_TRY(mRenderer->allocateResource(bufferDesc, &newBuffer)); + newBuffer.setDebugName("Buffer11::NativeStorage"); - if (mNativeStorage && preserveData) + if (mBuffer.valid() && preserveData) { // We don't call resize if the buffer is big enough already. ASSERT(mBufferSize <= size); @@ -983,19 +1095,30 @@ gl::Error Buffer11::NativeStorage::resize(size_t size, bool preserveData) srcBox.front = 0; srcBox.back = 1; - context->CopySubresourceRegion(newBuffer, 0, 0, 0, 0, mNativeStorage, 0, &srcBox); + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); + deviceContext->CopySubresourceRegion(newBuffer.get(), 0, 0, 0, 0, mBuffer.get(), 0, + &srcBox); } // No longer need the old buffer - SafeRelease(mNativeStorage); - mNativeStorage = newBuffer; + mBuffer = std::move(newBuffer); mBufferSize = bufferDesc.ByteWidth; - return gl::Error(GL_NO_ERROR); + // Free the SRVs. + clearSRVs(); + + // Notify that the storage has changed. + if (mOnStorageChanged) + { + mOnStorageChanged->signal(context); + } + + return gl::NoError(); } -void Buffer11::NativeStorage::fillBufferDesc(D3D11_BUFFER_DESC *bufferDesc, +// static +void Buffer11::NativeStorage::FillBufferDesc(D3D11_BUFFER_DESC *bufferDesc, Renderer11 *renderer, BufferUsage usage, unsigned int bufferSize) @@ -1030,6 +1153,13 @@ void Buffer11::NativeStorage::fillBufferDesc(D3D11_BUFFER_DESC *bufferDesc, bufferDesc->CPUAccessFlags = 0; break; + case BUFFER_USAGE_INDIRECT: + bufferDesc->MiscFlags = D3D11_RESOURCE_MISC_DRAWINDIRECT_ARGS; + bufferDesc->Usage = D3D11_USAGE_DEFAULT; + bufferDesc->BindFlags = 0; + bufferDesc->CPUAccessFlags = 0; + break; + case BUFFER_USAGE_PIXEL_UNPACK: bufferDesc->Usage = D3D11_USAGE_DEFAULT; bufferDesc->BindFlags = D3D11_BIND_SHADER_RESOURCE; @@ -1044,9 +1174,12 @@ void Buffer11::NativeStorage::fillBufferDesc(D3D11_BUFFER_DESC *bufferDesc, // 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); + + // Note: it seems that D3D11 allows larger buffers on some platforms, but not all. + // (Windows 10 seems to allow larger constant buffers, but not Windows 7) bufferDesc->ByteWidth = std::min(bufferDesc->ByteWidth, - static_cast(renderer->getRendererCaps().maxUniformBlockSize)); + static_cast(renderer->getNativeCaps().maxUniformBlockSize)); break; default: @@ -1054,67 +1187,146 @@ void Buffer11::NativeStorage::fillBufferDesc(D3D11_BUFFER_DESC *bufferDesc, } } -uint8_t *Buffer11::NativeStorage::map(size_t offset, size_t length, GLbitfield access) +gl::Error Buffer11::NativeStorage::map(size_t offset, + size_t length, + GLbitfield access, + uint8_t **mapPointerOut) { - ASSERT(mUsage == BUFFER_USAGE_STAGING); + ASSERT(isCPUAccessible(access)); 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); + D3D11_MAP d3dMapType = gl_d3d11::GetD3DMapTypeFromBits(mUsage, 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); + HRESULT result = context->Map(mBuffer.get(), 0, d3dMapType, d3dMapFlag, &mappedResource); ASSERT(SUCCEEDED(result)); if (FAILED(result)) { - return nullptr; + return gl::OutOfMemory() << "Failed to map native storage in Buffer11::NativeStorage::map"; } - return static_cast(mappedResource.pData) + offset; + ASSERT(mappedResource.pData); + *mapPointerOut = static_cast(mappedResource.pData) + offset; + return gl::NoError(); } void Buffer11::NativeStorage::unmap() { - ASSERT(mUsage == BUFFER_USAGE_STAGING); + ASSERT(isCPUAccessible(GL_MAP_WRITE_BIT) || isCPUAccessible(GL_MAP_READ_BIT)); ID3D11DeviceContext *context = mRenderer->getDeviceContext(); - context->Unmap(mNativeStorage, 0); + context->Unmap(mBuffer.get(), 0); +} + +gl::ErrorOrResult Buffer11::NativeStorage::getSRVForFormat( + DXGI_FORMAT srvFormat) +{ + auto bufferSRVIt = mBufferResourceViews.find(srvFormat); + + if (bufferSRVIt != mBufferResourceViews.end()) + { + return &bufferSRVIt->second; + } + + const d3d11::DXGIFormatSize &dxgiFormatInfo = d3d11::GetDXGIFormatSizeInfo(srvFormat); + + D3D11_SHADER_RESOURCE_VIEW_DESC bufferSRVDesc; + bufferSRVDesc.Buffer.ElementOffset = 0; + bufferSRVDesc.Buffer.ElementWidth = static_cast(mBufferSize) / dxgiFormatInfo.pixelBytes; + bufferSRVDesc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER; + bufferSRVDesc.Format = srvFormat; + + ANGLE_TRY(mRenderer->allocateResource(bufferSRVDesc, mBuffer.get(), + &mBufferResourceViews[srvFormat])); + + return &mBufferResourceViews[srvFormat]; +} + +void Buffer11::NativeStorage::clearSRVs() +{ + mBufferResourceViews.clear(); } +// Buffer11::EmulatedIndexStorage implementation + Buffer11::EmulatedIndexedStorage::EmulatedIndexedStorage(Renderer11 *renderer) - : BufferStorage(renderer, BUFFER_USAGE_EMULATED_INDEXED_VERTEX), mNativeStorage(nullptr) + : BufferStorage(renderer, BUFFER_USAGE_EMULATED_INDEXED_VERTEX), mBuffer() { } Buffer11::EmulatedIndexedStorage::~EmulatedIndexedStorage() { - SafeRelease(mNativeStorage); } -ID3D11Buffer *Buffer11::EmulatedIndexedStorage::getNativeStorage() +gl::ErrorOrResult Buffer11::EmulatedIndexedStorage::getBuffer( + SourceIndexData *indexInfo, + const TranslatedAttribute &attribute, + GLint startVertex) { - if (!mNativeStorage) + // If a change in the indices applied from the last draw call is detected, then the emulated + // indexed buffer needs to be invalidated. After invalidation, the change detected flag should + // be cleared to avoid unnecessary recreation of the buffer. + if (!mBuffer.valid() || indexInfo->srcIndicesChanged) + { + mBuffer.reset(); + + // Copy the source index data. This ensures that the lifetime of the indices pointer + // stays with this storage until the next time we invalidate. + size_t indicesDataSize = 0; + switch (indexInfo->srcIndexType) + { + case GL_UNSIGNED_INT: + indicesDataSize = sizeof(GLuint) * indexInfo->srcCount; + break; + case GL_UNSIGNED_SHORT: + indicesDataSize = sizeof(GLushort) * indexInfo->srcCount; + break; + case GL_UNSIGNED_BYTE: + indicesDataSize = sizeof(GLubyte) * indexInfo->srcCount; + break; + default: + indicesDataSize = sizeof(GLushort) * indexInfo->srcCount; + break; + } + + if (!mIndicesMemoryBuffer.resize(indicesDataSize)) + { + return gl::OutOfMemory() << "Error resizing index memory buffer in " + "Buffer11::EmulatedIndexedStorage::getBuffer"; + } + + memcpy(mIndicesMemoryBuffer.data(), indexInfo->srcIndices, indicesDataSize); + + indexInfo->srcIndicesChanged = false; + } + + if (!mBuffer.valid()) { + unsigned int offset = 0; + ANGLE_TRY_RESULT(attribute.computeOffset(startVertex), offset); + // Expand the memory storage upon request and cache the results. unsigned int expandedDataSize = - static_cast((mIndexInfo.srcCount * mAttributeStride) + mAttributeOffset); - MemoryBuffer expandedData; + static_cast((indexInfo->srcCount * attribute.stride) + offset); + angle::MemoryBuffer expandedData; if (!expandedData.resize(expandedDataSize)) { - return nullptr; + return gl::OutOfMemory() + << "Error resizing buffer in Buffer11::EmulatedIndexedStorage::getBuffer"; } // Clear the contents of the allocated buffer ZeroMemory(expandedData.data(), expandedDataSize); uint8_t *curr = expandedData.data(); - const uint8_t *ptr = static_cast(mIndexInfo.srcIndices); + const uint8_t *ptr = static_cast(indexInfo->srcIndices); // Ensure that we start in the correct place for the emulated data copy operation to // maintain offset behaviors. - curr += mAttributeOffset; + curr += offset; ReadIndexValueFunction readIndexValue = ReadIndexValueFromIndices; - switch (mIndexInfo.srcIndexType) + switch (indexInfo->srcIndexType) { case GL_UNSIGNED_INT: readIndexValue = ReadIndexValueFromIndices; @@ -1128,17 +1340,15 @@ ID3D11Buffer *Buffer11::EmulatedIndexedStorage::getNativeStorage() } // Iterate over the cached index data and copy entries indicated into the emulated buffer. - for (GLuint i = 0; i < mIndexInfo.srcCount; i++) + for (GLuint i = 0; i < indexInfo->srcCount; i++) { GLuint idx = readIndexValue(ptr, i); - memcpy(curr, mMemoryBuffer.data() + (mAttributeStride * idx), mAttributeStride); - curr += mAttributeStride; + memcpy(curr, mMemoryBuffer.data() + (attribute.stride * idx), attribute.stride); + curr += attribute.stride; } // Finally, initialize the emulated indexed native storage object with the newly copied data // and free the temporary buffers used. - ID3D11Device *device = mRenderer->getDevice(); - D3D11_BUFFER_DESC bufferDesc; bufferDesc.ByteWidth = expandedDataSize; bufferDesc.MiscFlags = 0; @@ -1149,99 +1359,53 @@ ID3D11Buffer *Buffer11::EmulatedIndexedStorage::getNativeStorage() D3D11_SUBRESOURCE_DATA subResourceData = {expandedData.data(), 0, 0}; - HRESULT result = device->CreateBuffer(&bufferDesc, &subResourceData, &mNativeStorage); - if (FAILED(result)) - { - ERR("Could not create emulated index data buffer: %08lX", result); - return nullptr; - } - d3d11::SetDebugName(mNativeStorage, "Buffer11::EmulatedIndexedStorage"); + ANGLE_TRY(mRenderer->allocateResource(bufferDesc, &subResourceData, &mBuffer)); + mBuffer.setDebugName("Buffer11::EmulatedIndexedStorage"); } - return mNativeStorage; -} - -bool Buffer11::EmulatedIndexedStorage::update(SourceIndexData *indexInfo, - const TranslatedAttribute *attribute) -{ - // If a change in the indices applied from the last draw call is detected, then the emulated - // indexed buffer needs to be invalidated. After invalidation, the change detected flag should - // be cleared to avoid unnecessary recreation of the buffer. - if (mNativeStorage == nullptr || indexInfo->srcIndicesChanged) - { - SafeRelease(mNativeStorage); - - // Copy attribute offset and stride information - mAttributeStride = attribute->stride; - mAttributeOffset = attribute->offset; - - // Copy the source index data. This ensures that the lifetime of the indices pointer - // stays with this storage until the next time we invalidate. - size_t indicesDataSize = 0; - switch (indexInfo->srcIndexType) - { - case GL_UNSIGNED_INT: - indicesDataSize = sizeof(GLuint) * indexInfo->srcCount; - break; - case GL_UNSIGNED_SHORT: - indicesDataSize = sizeof(GLushort) * indexInfo->srcCount; - break; - case GL_UNSIGNED_BYTE: - indicesDataSize = sizeof(GLubyte) * indexInfo->srcCount; - break; - default: - indicesDataSize = sizeof(GLushort) * indexInfo->srcCount; - break; - } - - if (!mIndicesMemoryBuffer.resize(indicesDataSize)) - { - return false; - } - - memcpy(mIndicesMemoryBuffer.data(), indexInfo->srcIndices, indicesDataSize); - - // Copy the source index data description and update the srcIndices pointer to point - // to our cached index data. - mIndexInfo = *indexInfo; - mIndexInfo.srcIndices = mIndicesMemoryBuffer.data(); - - indexInfo->srcIndicesChanged = false; - } - return true; + return &mBuffer; } -bool Buffer11::EmulatedIndexedStorage::copyFromStorage(BufferStorage *source, - size_t sourceOffset, - size_t size, - size_t destOffset) +gl::ErrorOrResult Buffer11::EmulatedIndexedStorage::copyFromStorage( + const gl::Context *context, + 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(source->isCPUAccessible(GL_MAP_READ_BIT)); + uint8_t *sourceData = nullptr; + ANGLE_TRY(source->map(sourceOffset, size, GL_MAP_READ_BIT, &sourceData)); ASSERT(destOffset + size <= mMemoryBuffer.size()); memcpy(mMemoryBuffer.data() + destOffset, sourceData, size); source->unmap(); - return true; + return CopyResult::RECREATED; } -gl::Error Buffer11::EmulatedIndexedStorage::resize(size_t size, bool preserveData) +gl::Error Buffer11::EmulatedIndexedStorage::resize(const gl::Context *context, + size_t size, + bool preserveData) { if (mMemoryBuffer.size() < size) { if (!mMemoryBuffer.resize(size)) { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to resize EmulatedIndexedStorage"); + return gl::OutOfMemory() << "Failed to resize EmulatedIndexedStorage"; } mBufferSize = size; } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -uint8_t *Buffer11::EmulatedIndexedStorage::map(size_t offset, size_t length, GLbitfield access) +gl::Error Buffer11::EmulatedIndexedStorage::map(size_t offset, + size_t length, + GLbitfield access, + uint8_t **mapPointerOut) { ASSERT(!mMemoryBuffer.empty() && offset + length <= mMemoryBuffer.size()); - return mMemoryBuffer.data() + offset; + *mapPointerOut = mMemoryBuffer.data() + offset; + return gl::NoError(); } void Buffer11::EmulatedIndexedStorage::unmap() @@ -1249,6 +1413,8 @@ void Buffer11::EmulatedIndexedStorage::unmap() // No-op } +// Buffer11::PackStorage implementation + Buffer11::PackStorage::PackStorage(Renderer11 *renderer) : BufferStorage(renderer, BUFFER_USAGE_PIXEL_PACK), mStagingTexture(), mDataModified(false) { @@ -1258,32 +1424,42 @@ Buffer11::PackStorage::~PackStorage() { } -bool Buffer11::PackStorage::copyFromStorage(BufferStorage *source, - size_t sourceOffset, - size_t size, - size_t destOffset) +gl::ErrorOrResult Buffer11::PackStorage::copyFromStorage(const gl::Context *context, + 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; + ANGLE_TRY(flushQueuedPackCommand()); + + // For all use cases of pack buffers, we must copy through a readable buffer. + ASSERT(source->isCPUAccessible(GL_MAP_READ_BIT)); + uint8_t *sourceData = nullptr; + ANGLE_TRY(source->map(sourceOffset, size, GL_MAP_READ_BIT, &sourceData)); + ASSERT(destOffset + size <= mMemoryBuffer.size()); + memcpy(mMemoryBuffer.data() + destOffset, sourceData, size); + source->unmap(); + return CopyResult::NOT_RECREATED; } -gl::Error Buffer11::PackStorage::resize(size_t size, bool preserveData) +gl::Error Buffer11::PackStorage::resize(const gl::Context *context, 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."); + return gl::OutOfMemory() << "Failed to resize internal buffer storage."; } mBufferSize = size; } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -uint8_t *Buffer11::PackStorage::map(size_t offset, size_t length, GLbitfield access) +gl::Error Buffer11::PackStorage::map(size_t offset, + size_t length, + GLbitfield access, + uint8_t **mapPointerOut) { ASSERT(offset + length <= getSize()); // TODO: fast path @@ -1291,15 +1467,12 @@ uint8_t *Buffer11::PackStorage::map(size_t offset, size_t length, GLbitfield acc // 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 nullptr; - } + ANGLE_TRY(flushQueuedPackCommand()); mDataModified = (mDataModified || (access & GL_MAP_WRITE_BIT) != 0); - return mMemoryBuffer.data() + offset; + *mapPointerOut = mMemoryBuffer.data() + offset; + return gl::NoError(); } void Buffer11::PackStorage::unmap() @@ -1307,42 +1480,29 @@ void Buffer11::PackStorage::unmap() // No-op } -gl::Error Buffer11::PackStorage::packPixels(const gl::FramebufferAttachment &readAttachment, +gl::Error Buffer11::PackStorage::packPixels(const gl::Context *context, + const gl::FramebufferAttachment &readAttachment, const PackPixelsParams ¶ms) { - gl::Error error = flushQueuedPackCommand(); - if (error.isError()) - { - return error; - } + ANGLE_TRY(flushQueuedPackCommand()); RenderTarget11 *renderTarget = nullptr; - error = readAttachment.getRenderTarget(&renderTarget); - if (error.isError()) - { - return error; - } - - ID3D11Resource *renderTargetResource = renderTarget->getTexture(); - ASSERT(renderTargetResource); + ANGLE_TRY(readAttachment.getRenderTarget(context, &renderTarget)); + const TextureHelper11 &srcTexture = renderTarget->getTexture(); + ASSERT(srcTexture.valid()); unsigned int srcSubresource = renderTarget->getSubresourceIndex(); - TextureHelper11 srcTexture = TextureHelper11::MakeAndReference(renderTargetResource); mQueuedPackCommand.reset(new PackPixelsParams(params)); gl::Extents srcTextureSize(params.area.width, params.area.height, 1); - if (!mStagingTexture.getResource() || mStagingTexture.getFormat() != srcTexture.getFormat() || + if (!mStagingTexture.get() || mStagingTexture.getFormat() != srcTexture.getFormat() || mStagingTexture.getExtents() != srcTextureSize) { - auto textureOrError = - CreateStagingTexture(srcTexture.getTextureType(), srcTexture.getFormat(), - srcTextureSize, mRenderer->getDevice()); - if (textureOrError.isError()) - { - return textureOrError.getError(); - } - mStagingTexture = std::move(textureOrError.getResult()); + ANGLE_TRY_RESULT( + mRenderer->createStagingTexture(srcTexture.getTextureType(), srcTexture.getFormatSet(), + srcTextureSize, StagingAccess::READ), + mStagingTexture); } // ReadPixels from multisampled FBOs isn't supported in current GL @@ -1357,17 +1517,17 @@ gl::Error Buffer11::PackStorage::packPixels(const gl::FramebufferAttachment &rea // Select the correct layer from a 3D attachment srcBox.front = 0; - if (mStagingTexture.getTextureType() == GL_TEXTURE_3D) + if (mStagingTexture.is3D()) { srcBox.front = static_cast(readAttachment.layer()); } srcBox.back = srcBox.front + 1; // Asynchronous copy - immediateContext->CopySubresourceRegion(mStagingTexture.getResource(), 0, 0, 0, 0, - srcTexture.getResource(), srcSubresource, &srcBox); + immediateContext->CopySubresourceRegion(mStagingTexture.get(), 0, 0, 0, 0, srcTexture.get(), + srcSubresource, &srcBox); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } gl::Error Buffer11::PackStorage::flushQueuedPackCommand() @@ -1376,58 +1536,65 @@ gl::Error Buffer11::PackStorage::flushQueuedPackCommand() if (mQueuedPackCommand) { - gl::Error error = - mRenderer->packPixels(mStagingTexture, *mQueuedPackCommand, mMemoryBuffer.data()); + ANGLE_TRY( + mRenderer->packPixels(mStagingTexture, *mQueuedPackCommand, mMemoryBuffer.data())); mQueuedPackCommand.reset(nullptr); - if (error.isError()) - { - return error; - } } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } +// Buffer11::SystemMemoryStorage implementation + 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) +gl::ErrorOrResult Buffer11::SystemMemoryStorage::copyFromStorage( + const gl::Context *context, + 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(source->isCPUAccessible(GL_MAP_READ_BIT)); + uint8_t *sourceData = nullptr; + ANGLE_TRY(source->map(sourceOffset, size, GL_MAP_READ_BIT, &sourceData)); ASSERT(destOffset + size <= mSystemCopy.size()); memcpy(mSystemCopy.data() + destOffset, sourceData, size); source->unmap(); - return true; + return CopyResult::RECREATED; } -gl::Error Buffer11::SystemMemoryStorage::resize(size_t size, bool preserveData) +gl::Error Buffer11::SystemMemoryStorage::resize(const gl::Context *context, + size_t size, + bool preserveData) { if (mSystemCopy.size() < size) { if (!mSystemCopy.resize(size)) { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to resize SystemMemoryStorage"); + return gl::OutOfMemory() << "Failed to resize SystemMemoryStorage"; } mBufferSize = size; } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -uint8_t *Buffer11::SystemMemoryStorage::map(size_t offset, size_t length, GLbitfield access) +gl::Error Buffer11::SystemMemoryStorage::map(size_t offset, + size_t length, + GLbitfield access, + uint8_t **mapPointerOut) { ASSERT(!mSystemCopy.empty() && offset + length <= mSystemCopy.size()); - return mSystemCopy.data() + offset; + *mapPointerOut = mSystemCopy.data() + offset; + return gl::NoError(); } void Buffer11::SystemMemoryStorage::unmap() { // No-op } -} +} // namespace rx diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Buffer11.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Buffer11.h index a748db57ae..ddbeeb90d2 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Buffer11.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Buffer11.h @@ -9,10 +9,12 @@ #ifndef LIBANGLE_RENDERER_D3D_D3D11_BUFFER11_H_ #define LIBANGLE_RENDERER_D3D_D3D11_BUFFER11_H_ +#include #include #include "libANGLE/angletypes.h" #include "libANGLE/renderer/d3d/BufferD3D.h" +#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h" namespace gl { @@ -21,69 +23,92 @@ class FramebufferAttachment; namespace rx { +struct PackPixelsParams; class Renderer11; struct SourceIndexData; struct TranslatedAttribute; +// The order of this enum governs priority of 'getLatestBufferStorage'. enum BufferUsage { + BUFFER_USAGE_SYSTEM_MEMORY, BUFFER_USAGE_STAGING, BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK, BUFFER_USAGE_INDEX, + // TODO: possibly share this buffer type with shader storage buffers. + BUFFER_USAGE_INDIRECT, BUFFER_USAGE_PIXEL_UNPACK, BUFFER_USAGE_PIXEL_PACK, BUFFER_USAGE_UNIFORM, - BUFFER_USAGE_SYSTEM_MEMORY, BUFFER_USAGE_EMULATED_INDEXED_VERTEX, BUFFER_USAGE_COUNT, }; -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(); - - ID3D11Buffer *getBuffer(BufferUsage usage); - ID3D11Buffer *getEmulatedIndexedBuffer(SourceIndexData *indexInfo, const TranslatedAttribute *attribute); - ID3D11Buffer *getConstantBufferRange(GLintptr offset, GLsizeiptr size); - ID3D11ShaderResourceView *getSRV(DXGI_FORMAT srvFormat); - bool isMapped() const { return mMappedStorage != NULL; } - gl::Error packPixels(const gl::FramebufferAttachment &readAttachment, + Buffer11(const gl::BufferState &state, Renderer11 *renderer); + ~Buffer11() override; + + gl::ErrorOrResult getBuffer(const gl::Context *context, BufferUsage usage); + gl::ErrorOrResult getEmulatedIndexedBuffer(const gl::Context *context, + SourceIndexData *indexInfo, + const TranslatedAttribute &attribute, + GLint startVertex); + gl::Error getConstantBufferRange(const gl::Context *context, + GLintptr offset, + GLsizeiptr size, + const d3d11::Buffer **bufferOut, + UINT *firstConstantOut, + UINT *numConstantsOut); + gl::ErrorOrResult getSRV(const gl::Context *context, + DXGI_FORMAT srvFormat); + bool isMapped() const { return mMappedStorage != nullptr; } + gl::Error packPixels(const gl::Context *context, + const gl::FramebufferAttachment &readAttachment, const PackPixelsParams ¶ms); size_t getTotalCPUBufferMemoryBytes() const; // BufferD3D implementation - virtual size_t getSize() const { return mSize; } - virtual bool supportsDirectBinding() const; - gl::Error getData(const uint8_t **outData) override; + size_t getSize() const override; + bool supportsDirectBinding() const override; + gl::Error getData(const gl::Context *context, const uint8_t **outData) override; + void initializeStaticData(const gl::Context *context) override; + void invalidateStaticData(const gl::Context *context) override; // BufferImpl implementation - virtual gl::Error setData(const void* data, size_t size, GLenum usage); - 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(GLenum access, GLvoid **mapPtr); - virtual gl::Error mapRange(size_t offset, size_t length, GLbitfield access, GLvoid **mapPtr); - virtual gl::Error unmap(GLboolean *result); - virtual void markTransformFeedbackUsage(); + gl::Error setData(const gl::Context *context, + gl::BufferBinding target, + const void *data, + size_t size, + gl::BufferUsage usage) override; + gl::Error setSubData(const gl::Context *context, + gl::BufferBinding target, + const void *data, + size_t size, + size_t offset) override; + gl::Error copySubData(const gl::Context *context, + BufferImpl *source, + GLintptr sourceOffset, + GLintptr destOffset, + GLsizeiptr size) override; + gl::Error map(const gl::Context *context, GLenum access, void **mapPtr) override; + gl::Error mapRange(const gl::Context *context, + size_t offset, + size_t length, + GLbitfield access, + void **mapPtr) override; + gl::Error unmap(const gl::Context *context, GLboolean *result) override; + gl::Error markTransformFeedbackUsage(const gl::Context *context) override; + + // We use two set of dirty events. Static buffers are marked dirty whenever + // data changes, because they must be re-translated. Direct buffers only need to be + // updated when the underlying ID3D11Buffer pointer changes - hopefully far less often. + OnBufferDataDirtyChannel *getStaticBroadcastChannel(); + OnBufferDataDirtyChannel *getDirectBroadcastChannel(); private: class BufferStorage; @@ -92,21 +117,61 @@ class Buffer11 : public BufferD3D class PackStorage; class SystemMemoryStorage; - Renderer11 *mRenderer; - size_t mSize; - - BufferStorage *mMappedStorage; - - std::vector mBufferStorages; - struct ConstantBufferCacheEntry { - ConstantBufferCacheEntry() : storage(nullptr), lruCount(0) { } + ConstantBufferCacheEntry() : storage(nullptr), lruCount(0) {} BufferStorage *storage; unsigned int lruCount; }; + void markBufferUsage(BufferUsage usage); + gl::Error garbageCollection(const gl::Context *context, BufferUsage currentUsage); + gl::ErrorOrResult getStagingStorage(const gl::Context *context); + gl::ErrorOrResult getPackStorage(const gl::Context *context); + gl::ErrorOrResult getSystemMemoryStorage(const gl::Context *context); + + gl::Error updateBufferStorage(const gl::Context *context, + BufferStorage *storage, + size_t sourceOffset, + size_t storageSize); + gl::ErrorOrResult getBufferStorage(const gl::Context *context, + BufferUsage usage); + gl::ErrorOrResult getLatestBufferStorage(const gl::Context *context) const; + + gl::ErrorOrResult getConstantBufferRangeStorage(const gl::Context *context, + GLintptr offset, + GLsizeiptr size); + + BufferStorage *allocateStorage(BufferUsage usage); + void updateDeallocThreshold(BufferUsage usage); + + // Free the storage if we decide it isn't being used very often. + gl::Error checkForDeallocation(const gl::Context *context, BufferUsage usage); + + // For some cases of uniform buffer storage, we can't deallocate system memory storage. + bool canDeallocateSystemMemory() const; + + // Updates data revisions and latest storage. + void onCopyStorage(BufferStorage *dest, BufferStorage *source); + void onStorageUpdate(BufferStorage *updatedStorage); + + Renderer11 *mRenderer; + size_t mSize; + + BufferStorage *mMappedStorage; + + // Buffer storages are sorted by usage. It's important that the latest buffer storage picks + // the lowest usage in the case where two storages are tied on data revision - this ensures + // we never do anything dangerous like map a uniform buffer over a staging or system memory + // copy. + std::array mBufferStorages; + BufferStorage *mLatestBufferStorage; + + // These two arrays are used to track when to free unused storage. + std::array mDeallocThresholds; + std::array mIdleness; + // Cache of D3D11 constant buffer for specific ranges of buffer data. // This is used to emulate UBO ranges on 11.0 devices. // Constant buffers are indexed by there start offset. @@ -115,25 +180,10 @@ class Buffer11 : public BufferD3D size_t mConstantBufferStorageAdditionalSize; unsigned int mMaxConstantBufferLruCount; - typedef std::pair BufferSRVPair; - std::map mBufferResourceViews; - - unsigned int mReadUsageCount; - - void markBufferUsage(); - NativeStorage *getStagingStorage(); - PackStorage *getPackStorage(); - gl::Error getSystemMemoryStorage(SystemMemoryStorage **storageOut); - - void updateBufferStorage(BufferStorage *storage, size_t sourceOffset, size_t storageSize); - BufferStorage *getBufferStorage(BufferUsage usage); - BufferStorage *getLatestBufferStorage() const; - - BufferStorage *getConstantBufferRangeStorage(GLintptr offset, GLsizeiptr size); - - void invalidateEmulatedIndexedBuffer(); + OnBufferDataDirtyChannel mStaticBroadcastChannel; + OnBufferDataDirtyChannel mDirectBroadcastChannel; }; -} +} // namespace rx -#endif // LIBANGLE_RENDERER_D3D_D3D11_BUFFER11_H_ +#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 index cd95c65d1c..f9dda0aeb4 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Clear11.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Clear11.cpp @@ -1,4 +1,4 @@ -// + // 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. @@ -20,624 +20,814 @@ #include "third_party/trace_event/trace_event.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/clear11_fl9vs.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clear11multiviewgs.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clear11multiviewvs.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clear11vs.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/cleardepth11ps.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" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearfloat11ps1.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearfloat11ps2.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearfloat11ps3.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearfloat11ps4.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearfloat11ps5.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearfloat11ps6.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearfloat11ps7.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearfloat11ps8.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearsint11ps1.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearsint11ps2.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearsint11ps3.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearsint11ps4.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearsint11ps5.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearsint11ps6.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearsint11ps7.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearsint11ps8.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearuint11ps1.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearuint11ps2.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearuint11ps3.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearuint11ps4.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearuint11ps5.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearuint11ps6.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearuint11ps7.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearuint11ps8.h" namespace rx { +namespace +{ +constexpr uint32_t g_ConstantBufferSize = sizeof(RtvDsvClearInfo); +constexpr uint32_t g_VertexSize = sizeof(d3d11::PositionVertex); + +// Updates color, depth and alpha components of cached CB if necessary. +// Returns true if any constants are updated, false otherwise. template -static void ApplyVertices(const gl::Extents &framebufferSize, const gl::Rectangle *scissor, const gl::Color &color, float depth, void *buffer) +bool UpdateDataCache(RtvDsvClearInfo *dataCache, + const gl::Color &color, + const float *zValue, + const uint32_t numRtvs, + const uint8_t writeMask) { - d3d11::PositionDepthColorVertex *vertices = reinterpret_cast*>(buffer); + bool cacheDirty = false; + + if (numRtvs > 0) + { + const bool writeRGB = (writeMask & ~D3D11_COLOR_WRITE_ENABLE_ALPHA) != 0; + if (writeRGB && memcmp(&dataCache->r, &color.red, sizeof(T) * 3) != 0) + { + dataCache->r = color.red; + dataCache->g = color.green; + dataCache->b = color.blue; + cacheDirty = true; + } - float depthClear = gl::clamp01(depth); - float left = -1.0f; - float right = 1.0f; - float top = -1.0f; - float bottom = 1.0f; + const bool writeAlpha = (writeMask & D3D11_COLOR_WRITE_ENABLE_ALPHA) != 0; + if (writeAlpha && (dataCache->a != color.alpha)) + { + dataCache->a = color.alpha; + cacheDirty = true; + } + } - // Clip the quad coordinates to the scissor if needed - if (scissor != nullptr) + if (zValue) { - 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); + const float clampedZValue = gl::clamp01(*zValue); + + if (clampedZValue != dataCache->z) + { + dataCache->z = clampedZValue; + cacheDirty = true; + } } - 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); + return cacheDirty; } -Clear11::ClearShader::ClearShader(DXGI_FORMAT colorType, - const char *inputLayoutName, - const BYTE *vsByteCode, - size_t vsSize, - const char *vsDebugName, - const BYTE *psByteCode, - size_t psSize, - const char *psDebugName) - : inputLayout(nullptr), - vertexShader(vsByteCode, vsSize, vsDebugName), - pixelShader(psByteCode, psSize, psDebugName) +bool AllOffsetsAreNonNegative(const std::vector &viewportOffsets) { - D3D11_INPUT_ELEMENT_DESC quadLayout[] = + for (size_t i = 0u; i < viewportOffsets.size(); ++i) { - { "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 }, - }; - - inputLayout = new d3d11::LazyInputLayout(quadLayout, 2, vsByteCode, vsSize, inputLayoutName); + const auto &offset = viewportOffsets[i]; + if (offset.x < 0 || offset.y < 0) + { + return false; + } + } + return true; } - -Clear11::ClearShader::~ClearShader() +} // anonymous namespace + +#define CLEARPS(Index) \ + d3d11::LazyShader(g_PS_Clear##Index, ArraySize(g_PS_Clear##Index), \ + "Clear11 PS " ANGLE_STRINGIFY(Index)) + +Clear11::ShaderManager::ShaderManager() + : mIl9(), + mVs9(g_VS_Clear_FL9, ArraySize(g_VS_Clear_FL9), "Clear11 VS FL9"), + mPsFloat9(g_PS_ClearFloat_FL9, ArraySize(g_PS_ClearFloat_FL9), "Clear11 PS FloatFL9"), + mVs(g_VS_Clear, ArraySize(g_VS_Clear), "Clear11 VS"), + mVsMultiview(g_VS_Multiview_Clear, ArraySize(g_VS_Multiview_Clear), "Clear11 VS Multiview"), + mGsMultiview(g_GS_Multiview_Clear, ArraySize(g_GS_Multiview_Clear), "Clear11 GS Multiview"), + mPsDepth(g_PS_ClearDepth, ArraySize(g_PS_ClearDepth), "Clear11 PS Depth"), + mPsFloat{{CLEARPS(Float1), CLEARPS(Float2), CLEARPS(Float3), CLEARPS(Float4), CLEARPS(Float5), + CLEARPS(Float6), CLEARPS(Float7), CLEARPS(Float8)}}, + mPsUInt{{CLEARPS(Uint1), CLEARPS(Uint2), CLEARPS(Uint3), CLEARPS(Uint4), CLEARPS(Uint5), + CLEARPS(Uint6), CLEARPS(Uint7), CLEARPS(Uint8)}}, + mPsSInt{{CLEARPS(Sint1), CLEARPS(Sint2), CLEARPS(Sint3), CLEARPS(Sint4), CLEARPS(Sint5), + CLEARPS(Sint6), CLEARPS(Sint7), CLEARPS(Sint8)}} { - SafeDelete(inputLayout); - vertexShader.release(); - pixelShader.release(); } -Clear11::Clear11(Renderer11 *renderer) - : mRenderer(renderer), - mClearBlendStates(StructLessThan), - mFloatClearShader(nullptr), - mUintClearShader(nullptr), - mIntClearShader(nullptr), - mClearDepthStencilStates(StructLessThan), - mVertexBuffer(nullptr), - mRasterizerState(nullptr) +#undef CLEARPS + +Clear11::ShaderManager::~ShaderManager() { - TRACE_EVENT0("gpu.angle", "Clear11::Clear11"); +} - HRESULT result; - ID3D11Device *device = renderer->getDevice(); +gl::Error Clear11::ShaderManager::getShadersAndLayout(Renderer11 *renderer, + const INT clearType, + const uint32_t numRTs, + const bool hasLayeredLayout, + const d3d11::InputLayout **il, + const d3d11::VertexShader **vs, + const d3d11::GeometryShader **gs, + const d3d11::PixelShader **ps) +{ + if (renderer->getRenderer11DeviceCaps().featureLevel <= D3D_FEATURE_LEVEL_9_3) + { + ASSERT(clearType == GL_FLOAT); - 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; + ANGLE_TRY(mVs9.resolve(renderer)); + ANGLE_TRY(mPsFloat9.resolve(renderer)); - result = device->CreateBuffer(&vbDesc, nullptr, &mVertexBuffer); - ASSERT(SUCCEEDED(result)); - d3d11::SetDebugName(mVertexBuffer, "Clear11 masked clear vertex buffer"); + if (!mIl9.valid()) + { + const D3D11_INPUT_ELEMENT_DESC ilDesc[] = { + {"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0}}; - 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; + InputElementArray ilDescArray(ilDesc); + ShaderData vertexShader(g_VS_Clear_FL9); - result = device->CreateRasterizerState(&rsDesc, &mRasterizerState); - ASSERT(SUCCEEDED(result)); - d3d11::SetDebugName(mRasterizerState, "Clear11 masked clear rasterizer state"); + ANGLE_TRY(renderer->allocateResource(ilDescArray, &vertexShader, &mIl9)); + } - if (mRenderer->getRenderer11DeviceCaps().featureLevel <= D3D_FEATURE_LEVEL_9_3) + *vs = &mVs9.getObj(); + *gs = nullptr; + *il = &mIl9; + *ps = &mPsFloat9.getObj(); + return gl::NoError(); + } + if (!hasLayeredLayout) { - mFloatClearShader = new ClearShader(DXGI_FORMAT_R32G32B32A32_FLOAT, - "Clear11 Float IL", - g_VS_ClearFloat, - ArraySize(g_VS_ClearFloat), - "Clear11 Float VS", - g_PS_ClearFloat_FL9, - ArraySize(g_PS_ClearFloat_FL9), - "Clear11 Float PS"); + ANGLE_TRY(mVs.resolve(renderer)); + *vs = &mVs.getObj(); + *gs = nullptr; } else { - mFloatClearShader = new ClearShader(DXGI_FORMAT_R32G32B32A32_FLOAT, - "Clear11 Float IL", - g_VS_ClearFloat, - ArraySize(g_VS_ClearFloat), - "Clear11 Float VS", - g_PS_ClearFloat, - ArraySize(g_PS_ClearFloat), - "Clear11 Float PS"); + // For layered framebuffers we have to use the multi-view versions of the VS and GS. + ANGLE_TRY(mVsMultiview.resolve(renderer)); + ANGLE_TRY(mGsMultiview.resolve(renderer)); + *vs = &mVsMultiview.getObj(); + *gs = &mGsMultiview.getObj(); + } + + *il = nullptr; + + if (numRTs == 0) + { + ANGLE_TRY(mPsDepth.resolve(renderer)); + *ps = &mPsDepth.getObj(); + return gl::NoError(); } - if (renderer->isES3Capable()) + switch (clearType) { - mUintClearShader = new ClearShader(DXGI_FORMAT_R32G32B32A32_UINT, - "Clear11 UINT IL", - g_VS_ClearUint, - ArraySize(g_VS_ClearUint), - "Clear11 UINT VS", - g_PS_ClearUint, - ArraySize(g_PS_ClearUint), - "Clear11 UINT PS"); - mIntClearShader = new ClearShader(DXGI_FORMAT_R32G32B32A32_UINT, - "Clear11 SINT IL", - g_VS_ClearSint, - ArraySize(g_VS_ClearSint), - "Clear11 SINT VS", - g_PS_ClearSint, - ArraySize(g_PS_ClearSint), - "Clear11 SINT PS"); + case GL_FLOAT: + ANGLE_TRY(mPsFloat[numRTs - 1].resolve(renderer)); + *ps = &mPsFloat[numRTs - 1].getObj(); + break; + case GL_UNSIGNED_INT: + ANGLE_TRY(mPsUInt[numRTs - 1].resolve(renderer)); + *ps = &mPsUInt[numRTs - 1].getObj(); + break; + case GL_INT: + ANGLE_TRY(mPsSInt[numRTs - 1].resolve(renderer)); + *ps = &mPsSInt[numRTs - 1].getObj(); + break; + default: + UNREACHABLE(); + break; } + + return gl::NoError(); +} + +Clear11::Clear11(Renderer11 *renderer) + : mRenderer(renderer), + mResourcesInitialized(false), + mScissorEnabledRasterizerState(), + mScissorDisabledRasterizerState(), + mShaderManager(), + mConstantBuffer(), + mVertexBuffer(), + mShaderData({}) +{ } Clear11::~Clear11() { - for (ClearBlendStateMap::iterator i = mClearBlendStates.begin(); i != mClearBlendStates.end(); i++) +} + +gl::Error Clear11::ensureResourcesInitialized() +{ + if (mResourcesInitialized) { - SafeRelease(i->second); + return gl::NoError(); } - mClearBlendStates.clear(); - SafeDelete(mFloatClearShader); - SafeDelete(mUintClearShader); - SafeDelete(mIntClearShader); + TRACE_EVENT0("gpu.angle", "Clear11::ensureResourcesInitialized"); + + static_assert((sizeof(RtvDsvClearInfo) == sizeof(RtvDsvClearInfo)), + "Size of rx::RtvDsvClearInfo is not equal to rx::RtvDsvClearInfo"); + + static_assert( + (sizeof(RtvDsvClearInfo) == sizeof(RtvDsvClearInfo)), + "Size of rx::RtvDsvClearInfo is not equal to rx::RtvDsvClearInfo"); - for (ClearDepthStencilStateMap::iterator i = mClearDepthStencilStates.begin(); i != mClearDepthStencilStates.end(); i++) + static_assert((sizeof(RtvDsvClearInfo) % 16 == 0), + "The size of RtvDsvClearInfo should be a multiple of 16bytes."); + + // Create Rasterizer States + 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; + + ANGLE_TRY(mRenderer->allocateResource(rsDesc, &mScissorDisabledRasterizerState)); + mScissorDisabledRasterizerState.setDebugName("Clear11 Rasterizer State with scissor disabled"); + + rsDesc.ScissorEnable = TRUE; + ANGLE_TRY(mRenderer->allocateResource(rsDesc, &mScissorEnabledRasterizerState)); + mScissorEnabledRasterizerState.setDebugName("Clear11 Rasterizer State with scissor enabled"); + + // Initialize Depthstencil state with defaults + mDepthStencilStateKey.depthTest = false; + mDepthStencilStateKey.depthMask = false; + mDepthStencilStateKey.depthFunc = GL_ALWAYS; + mDepthStencilStateKey.stencilWritemask = static_cast(-1); + mDepthStencilStateKey.stencilBackWritemask = static_cast(-1); + mDepthStencilStateKey.stencilBackMask = 0; + mDepthStencilStateKey.stencilTest = false; + mDepthStencilStateKey.stencilMask = 0; + mDepthStencilStateKey.stencilFail = GL_REPLACE; + mDepthStencilStateKey.stencilPassDepthFail = GL_REPLACE; + mDepthStencilStateKey.stencilPassDepthPass = GL_REPLACE; + mDepthStencilStateKey.stencilFunc = GL_ALWAYS; + mDepthStencilStateKey.stencilBackFail = GL_REPLACE; + mDepthStencilStateKey.stencilBackPassDepthFail = GL_REPLACE; + mDepthStencilStateKey.stencilBackPassDepthPass = GL_REPLACE; + mDepthStencilStateKey.stencilBackFunc = GL_ALWAYS; + + // Initialize BlendStateKey with defaults + mBlendStateKey.blendState.blend = false; + mBlendStateKey.blendState.sourceBlendRGB = GL_ONE; + mBlendStateKey.blendState.sourceBlendAlpha = GL_ONE; + mBlendStateKey.blendState.destBlendRGB = GL_ZERO; + mBlendStateKey.blendState.destBlendAlpha = GL_ZERO; + mBlendStateKey.blendState.blendEquationRGB = GL_FUNC_ADD; + mBlendStateKey.blendState.blendEquationAlpha = GL_FUNC_ADD; + mBlendStateKey.blendState.sampleAlphaToCoverage = false; + mBlendStateKey.blendState.dither = true; + + mResourcesInitialized = true; + return gl::NoError(); +} + +bool Clear11::useVertexBuffer() const +{ + return (mRenderer->getRenderer11DeviceCaps().featureLevel <= D3D_FEATURE_LEVEL_9_3); +} + +gl::Error Clear11::ensureConstantBufferCreated() +{ + if (mConstantBuffer.valid()) { - SafeRelease(i->second); + return gl::NoError(); } - mClearDepthStencilStates.clear(); - SafeRelease(mVertexBuffer); - SafeRelease(mRasterizerState); + // Create constant buffer for color & depth data + + D3D11_BUFFER_DESC bufferDesc; + bufferDesc.ByteWidth = g_ConstantBufferSize; + bufferDesc.Usage = D3D11_USAGE_DYNAMIC; + bufferDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; + bufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + bufferDesc.MiscFlags = 0; + bufferDesc.StructureByteStride = 0; + + D3D11_SUBRESOURCE_DATA initialData; + initialData.pSysMem = &mShaderData; + initialData.SysMemPitch = g_ConstantBufferSize; + initialData.SysMemSlicePitch = g_ConstantBufferSize; + + ANGLE_TRY(mRenderer->allocateResource(bufferDesc, &initialData, &mConstantBuffer)); + mConstantBuffer.setDebugName("Clear11 Constant Buffer"); + return gl::NoError(); } -gl::Error Clear11::clearFramebuffer(const ClearParameters &clearParams, const gl::Framebuffer::Data &fboData) +gl::Error Clear11::ensureVertexBufferCreated() { - const auto &colorAttachments = fboData.getColorAttachments(); - const auto &drawBufferStates = fboData.getDrawBufferStates(); - const auto *depthAttachment = fboData.getDepthAttachment(); - const auto *stencilAttachment = fboData.getStencilAttachment(); + ASSERT(useVertexBuffer()); + + if (mVertexBuffer.valid()) + { + return gl::NoError(); + } + + // Create vertex buffer with vertices for a quad covering the entire surface + + static_assert((sizeof(d3d11::PositionVertex) % 16) == 0, + "d3d11::PositionVertex should be a multiple of 16 bytes"); + const d3d11::PositionVertex vbData[6] = {{-1.0f, 1.0f, 0.0f, 1.0f}, {1.0f, -1.0f, 0.0f, 1.0f}, + {-1.0f, -1.0f, 0.0f, 1.0f}, {-1.0f, 1.0f, 0.0f, 1.0f}, + {1.0f, 1.0f, 0.0f, 1.0f}, {1.0f, -1.0f, 0.0f, 1.0f}}; + + const UINT vbSize = sizeof(vbData); + + D3D11_BUFFER_DESC bufferDesc; + bufferDesc.ByteWidth = vbSize; + bufferDesc.Usage = D3D11_USAGE_IMMUTABLE; + bufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; + bufferDesc.CPUAccessFlags = 0; + bufferDesc.MiscFlags = 0; + bufferDesc.StructureByteStride = 0; + + D3D11_SUBRESOURCE_DATA initialData; + initialData.pSysMem = vbData; + initialData.SysMemPitch = vbSize; + initialData.SysMemSlicePitch = initialData.SysMemPitch; + + ANGLE_TRY(mRenderer->allocateResource(bufferDesc, &initialData, &mVertexBuffer)); + mVertexBuffer.setDebugName("Clear11 Vertex Buffer"); + return gl::NoError(); +} - ASSERT(colorAttachments.size() == drawBufferStates.size()); +gl::Error Clear11::clearFramebuffer(const gl::Context *context, + const ClearParameters &clearParams, + const gl::FramebufferState &fboData) +{ + ANGLE_TRY(ensureResourcesInitialized()); // 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) + // 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. + // 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. + // Otherwise perform a shader based clear. // - // Also determine if the depth stencil can be cleared with ID3D11DeviceContext::ClearDepthStencilView - // by checking if the stencil write mask covers the entire stencil. + // Also determine if the DSV can be cleared withID3D11DeviceContext::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. + // To clear the remaining buffers, a shader based clear is performed: + // - The appropriate ShaderManagers (VS & PS) for the clearType is set + // - A CB containing the clear color and Z values is bound + // - An IL and VB are bound (for FL93 and below) + // - ScissorRect/Raststate/Viewport set as required + // - Blendstate set containing appropriate colorMasks + // - DepthStencilState set with appropriate parameters for a z or stencil clear if required + // - Color and/or Z buffers to be cleared are bound + // - Primitive covering entire clear area is drawn gl::Extents framebufferSize; - const gl::FramebufferAttachment *colorAttachment = fboData.getFirstColorAttachment(); - if (colorAttachment != nullptr) - { - framebufferSize = colorAttachment->getSize(); - } - else if (depthAttachment != nullptr) - { - framebufferSize = depthAttachment->getSize(); - } - else if (stencilAttachment != nullptr) + const auto *depthStencilAttachment = fboData.getDepthOrStencilAttachment(); + if (depthStencilAttachment != nullptr) { - framebufferSize = stencilAttachment->getSize(); + framebufferSize = depthStencilAttachment->getSize(); } else { - UNREACHABLE(); - return gl::Error(GL_INVALID_OPERATION); + const gl::FramebufferAttachment *colorAttachment = fboData.getFirstColorAttachment(); + + if (!colorAttachment) + { + UNREACHABLE(); + return gl::InternalError(); + } + + framebufferSize = colorAttachment->getSize(); } - 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)) + const bool isSideBySideFBO = + (fboData.getMultiviewLayout() == GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE); + bool needScissoredClear = false; + std::vector scissorRects; + if (clearParams.scissorEnabled) { - // Scissor is enabled and the scissor rectangle is outside the renderbuffer - return gl::Error(GL_NO_ERROR); - } + const std::vector *viewportOffsets = fboData.getViewportOffsets(); + ASSERT(viewportOffsets != nullptr); + ASSERT(AllOffsetsAreNonNegative(*fboData.getViewportOffsets())); - 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); + if (clearParams.scissor.x >= framebufferSize.width || + clearParams.scissor.y >= framebufferSize.height || clearParams.scissor.width == 0 || + clearParams.scissor.height == 0) + { + // The check assumes that the viewport offsets are not negative as according to the + // ANGLE_multiview spec. + // Scissor rect is outside the renderbuffer or is an empty rect. + return gl::NoError(); + } - std::vector maskedClearRenderTargets; - RenderTarget11* maskedClearDepthStencil = nullptr; + if (isSideBySideFBO) + { + // We always have to do a scissor clear for side-by-side framebuffers. + needScissoredClear = true; + } + else + { + // Because the viewport offsets can generate scissor rectangles within the framebuffer's + // bounds, we can do this check only for non-side-by-side framebuffers. + if (clearParams.scissor.x + clearParams.scissor.width <= 0 || + clearParams.scissor.y + clearParams.scissor.height <= 0) + { + // Scissor rect is outside the renderbuffer. + return gl::NoError(); + } + needScissoredClear = + clearParams.scissor.x > 0 || clearParams.scissor.y > 0 || + clearParams.scissor.x + clearParams.scissor.width < framebufferSize.width || + clearParams.scissor.y + clearParams.scissor.height < framebufferSize.height; + } - ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); -#if defined(ANGLE_ENABLE_D3D11_1) + if (needScissoredClear) + { + // Apply viewport offsets to compute the final scissor rectangles. This is valid also + // for non-side-by-side framebuffers, because the default viewport offset is {0,0}. + const size_t numViews = viewportOffsets->size(); + scissorRects.reserve(numViews); + for (size_t i = 0u; i < numViews; ++i) + { + const gl::Offset &offset = (*viewportOffsets)[i]; + D3D11_RECT rect; + int x = clearParams.scissor.x + offset.x; + int y = clearParams.scissor.y + offset.y; + rect.left = x; + rect.right = x + clearParams.scissor.width; + rect.top = y; + rect.bottom = y + clearParams.scissor.height; + scissorRects.emplace_back(rect); + } + } + } + + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); ID3D11DeviceContext1 *deviceContext1 = mRenderer->getDeviceContext1IfSupported(); -#endif - ID3D11Device *device = mRenderer->getDevice(); - for (size_t colorAttachmentIndex = 0; colorAttachmentIndex < colorAttachments.size(); - colorAttachmentIndex++) + std::array rtvs; + std::array rtvMasks = {}; + + uint32_t numRtvs = 0; + const uint8_t colorMask = + gl_d3d11::ConvertColorMask(clearParams.colorMaskRed, clearParams.colorMaskGreen, + clearParams.colorMaskBlue, clearParams.colorMaskAlpha); + + const auto &colorAttachments = fboData.getColorAttachments(); + for (auto colorAttachmentIndex : fboData.getEnabledDrawBuffers()) { const gl::FramebufferAttachment &attachment = colorAttachments[colorAttachmentIndex]; - if (clearParams.clearColor[colorAttachmentIndex] && attachment.isAttached() && - drawBufferStates[colorAttachmentIndex] != GL_NONE) + if (!clearParams.clearColor[colorAttachmentIndex]) { - RenderTarget11 *renderTarget = nullptr; - gl::Error error = attachment.getRenderTarget(&renderTarget); - if (error.isError()) - { - return error; - } + continue; + } - const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(attachment.getInternalFormat()); + RenderTarget11 *renderTarget = nullptr; + ANGLE_TRY(attachment.getRenderTarget(context, &renderTarget)); - 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).", - colorAttachmentIndex, attachment.getInternalFormat()); - } + const gl::InternalFormat &formatInfo = *attachment.getFormat().info; - 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 ((!(mRenderer->getRenderer11DeviceCaps().supportsClearView) && 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[colorAttachmentIndex]; - 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 + if (clearParams.colorType == 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 " + << colorAttachmentIndex << " has internal format " << attachment.getFormat() + << ")."; + } - ID3D11RenderTargetView *framebufferRTV = renderTarget->getRenderTargetView(); - if (!framebufferRTV) - { - return gl::Error(GL_OUT_OF_MEMORY, "Internal render target view pointer unexpectedly null."); - } + 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; + } - const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(renderTarget->getDXGIFormat()); + const auto &framebufferRTV = renderTarget->getRenderTargetView(); + ASSERT(framebufferRTV.valid()); - // Check if the actual format has a channel that the internal format does not and set them to the - // default values - 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 ((!(mRenderer->getRenderer11DeviceCaps().supportsClearView) && needScissoredClear) || + clearParams.colorType != GL_FLOAT || + (formatInfo.redBits > 0 && !clearParams.colorMaskRed) || + (formatInfo.greenBits > 0 && !clearParams.colorMaskGreen) || + (formatInfo.blueBits > 0 && !clearParams.colorMaskBlue) || + (formatInfo.alphaBits > 0 && !clearParams.colorMaskAlpha)) + { + rtvs[numRtvs] = framebufferRTV.get(); + rtvMasks[numRtvs] = gl_d3d11::GetColorMask(formatInfo) & colorMask; + numRtvs++; + } + else + { + // ID3D11DeviceContext::ClearRenderTargetView or ID3D11DeviceContext1::ClearView is + // possible + + const auto &nativeFormat = renderTarget->getFormatSet().format(); + + // Check if the actual format has a channel that the internal format does not and + // set them to the default values + float clearValues[4] = { + ((formatInfo.redBits == 0 && nativeFormat.redBits > 0) ? 0.0f + : clearParams.colorF.red), + ((formatInfo.greenBits == 0 && nativeFormat.greenBits > 0) + ? 0.0f + : clearParams.colorF.green), + ((formatInfo.blueBits == 0 && nativeFormat.blueBits > 0) ? 0.0f + : clearParams.colorF.blue), + ((formatInfo.alphaBits == 0 && nativeFormat.alphaBits > 0) + ? 1.0f + : clearParams.colorF.alpha), + }; + + if (formatInfo.alphaBits == 1) + { + // Some drivers do not correctly handle calling Clear() on a format with 1-bit + // alpha. They can incorrectly round all non-zero values up to 1.0f. Note that + // WARP does not do this. We should handle the rounding for them instead. + clearValues[3] = (clearParams.colorF.alpha >= 0.5f) ? 1.0f : 0.0f; + } - if (dxgiFormatInfo.alphaBits == 1) + if (needScissoredClear) + { + // We shouldn't reach here if deviceContext1 is unavailable. + ASSERT(deviceContext1); + // There must be at least one scissor rectangle. + ASSERT(!scissorRects.empty()); + deviceContext1->ClearView(framebufferRTV.get(), clearValues, scissorRects.data(), + static_cast(scissorRects.size())); + if (mRenderer->getWorkarounds().callClearTwice) { - // Some drivers do not correctly handle calling Clear() on a format with 1-bit alpha. - // They can incorrectly round all non-zero values up to 1.0f. Note that WARP does not do this. - // We should handle the rounding for them instead. - clearValues[3] = (clearParams.colorFClearValue.alpha >= 0.5f) ? 1.0f : 0.0f; + deviceContext1->ClearView(framebufferRTV.get(), clearValues, + scissorRects.data(), + static_cast(scissorRects.size())); } - -#if defined(ANGLE_ENABLE_D3D11_1) - if (needScissoredClear) - { - // 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); - } - else -#endif + } + else + { + deviceContext->ClearRenderTargetView(framebufferRTV.get(), clearValues); + if (mRenderer->getWorkarounds().callClearTwice) { - deviceContext->ClearRenderTargetView(framebufferRTV, clearValues); + deviceContext->ClearRenderTargetView(framebufferRTV.get(), clearValues); } } } } + ID3D11DepthStencilView *dsv = nullptr; + if (clearParams.clearDepth || clearParams.clearStencil) { - const gl::FramebufferAttachment *attachment = (depthAttachment != nullptr) ? depthAttachment : stencilAttachment; - ASSERT(attachment != nullptr); + RenderTarget11 *depthStencilRenderTarget = nullptr; - RenderTarget11 *renderTarget = nullptr; - gl::Error error = attachment->getRenderTarget(&renderTarget); - if (error.isError()) - { - return error; - } + ASSERT(depthStencilAttachment != nullptr); + ANGLE_TRY(depthStencilAttachment->getRenderTarget(context, &depthStencilRenderTarget)); - const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(renderTarget->getDXGIFormat()); + dsv = depthStencilRenderTarget->getDepthStencilView().get(); + ASSERT(dsv != nullptr); - unsigned int stencilUnmasked = (stencilAttachment != nullptr) ? (1 << dxgiFormatInfo.stencilBits) - 1 : 0; - bool needMaskedStencilClear = clearParams.clearStencil && (clearParams.stencilWriteMask & stencilUnmasked) != stencilUnmasked; + const auto &nativeFormat = depthStencilRenderTarget->getFormatSet().format(); + const auto *stencilAttachment = fboData.getStencilAttachment(); - if (needScissoredClear || needMaskedStencilClear) - { - maskedClearDepthStencil = renderTarget; - } - else + uint32_t stencilUnmasked = + (stencilAttachment != nullptr) ? (1 << nativeFormat.stencilBits) - 1 : 0; + bool needMaskedStencilClear = + clearParams.clearStencil && + (clearParams.stencilWriteMask & stencilUnmasked) != stencilUnmasked; + + if (!needScissoredClear && !needMaskedStencilClear) { - ID3D11DepthStencilView *framebufferDSV = renderTarget->getDepthStencilView(); - if (!framebufferDSV) - { - return gl::Error(GL_OUT_OF_MEMORY, "Internal depth stencil view pointer unexpectedly null."); - } + const UINT clearFlags = (clearParams.clearDepth ? D3D11_CLEAR_DEPTH : 0) | + (clearParams.clearStencil ? D3D11_CLEAR_STENCIL : 0); + const FLOAT depthClear = gl::clamp01(clearParams.depthValue); + const UINT8 stencilClear = clearParams.stencilValue & 0xFF; - 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(dsv, clearFlags, depthClear, stencilClear); - deviceContext->ClearDepthStencilView(framebufferDSV, clearFlags, depthClear, stencilClear); + dsv = nullptr; } } - if (maskedClearRenderTargets.size() > 0 || maskedClearDepthStencil) + if (numRtvs == 0 && dsv == nullptr) { - // 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."); - } + return gl::NoError(); + } - rtvs[i] = rtv; - } - ID3D11DepthStencilView *dsv = maskedClearDepthStencil ? maskedClearDepthStencil->getDepthStencilView() : nullptr; + // Clear the remaining render targets and depth stencil in one pass by rendering a quad: + // + // IA/VS: Vertices containing position and color members are passed through to the next stage. + // The vertex position has XY coordinates equal to clip extents and a Z component equal to the + // Z clear value. The vertex color contains the clear color. + // + // Rasterizer: Viewport scales the VS output over the entire surface and depending on whether + // or not scissoring is enabled the appropriate scissor rect and rasterizerState with or without + // the scissor test enabled is set as well. + // + // DepthStencilTest: DepthTesting, DepthWrites, StencilMask and StencilWrites will be enabled or + // disabled or set depending on what the input depthStencil clear parameters are. Since the PS + // is not writing out depth or rejecting pixels, this should happen prior to the PS stage. + // + // PS: Will write out the color values passed through from the previous stage to all outputs. + // + // OM: BlendState will perform the required color masking and output to RTV(s). + + // + // ====================================================================================== + // + // 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. - ID3D11BlendState *blendState = getBlendState(maskedClearRenderTargets); - const FLOAT blendFactors[4] = { 1.0f, 1.0f, 1.0f, 1.0f }; - const UINT sampleMask = 0xFFFFFFFF; + ASSERT(numRtvs <= mRenderer->getNativeCaps().maxDrawBuffers); - ID3D11DepthStencilState *dsState = getDepthStencilState(clearParams); - const UINT stencilClear = clearParams.stencilClearValue & 0xFF; + // Setup BlendStateKey parameters + mBlendStateKey.blendState.colorMaskRed = clearParams.colorMaskRed; + mBlendStateKey.blendState.colorMaskGreen = clearParams.colorMaskGreen; + mBlendStateKey.blendState.colorMaskBlue = clearParams.colorMaskBlue; + mBlendStateKey.blendState.colorMaskAlpha = clearParams.colorMaskAlpha; + mBlendStateKey.rtvMax = numRtvs; + memcpy(mBlendStateKey.rtvMasks, &rtvMasks[0], sizeof(mBlendStateKey.rtvMasks)); - // Set the vertices - UINT vertexStride = 0; - const UINT startIdx = 0; - ClearShader *shader = nullptr; - 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); - } + // Get BlendState + const d3d11::BlendState *blendState = nullptr; + ANGLE_TRY(mRenderer->getBlendState(mBlendStateKey, &blendState)); - const gl::Rectangle *scissorPtr = clearParams.scissorEnabled ? &clearParams.scissor : nullptr; - switch (clearParams.colorClearType) - { - case GL_FLOAT: - ApplyVertices(framebufferSize, scissorPtr, clearParams.colorFClearValue, clearParams.depthClearValue, mappedResource.pData); - vertexStride = sizeof(d3d11::PositionDepthColorVertex); - shader = mFloatClearShader; - break; + const d3d11::DepthStencilState *dsState = nullptr; + const float *zValue = nullptr; - case GL_UNSIGNED_INT: - ApplyVertices(framebufferSize, scissorPtr, clearParams.colorUIClearValue, clearParams.depthClearValue, mappedResource.pData); - vertexStride = sizeof(d3d11::PositionDepthColorVertex); - shader = mUintClearShader; - break; + if (dsv) + { + // Setup DepthStencilStateKey + mDepthStencilStateKey.depthTest = clearParams.clearDepth; + mDepthStencilStateKey.depthMask = clearParams.clearDepth; + mDepthStencilStateKey.stencilWritemask = clearParams.stencilWriteMask; + mDepthStencilStateKey.stencilTest = clearParams.clearStencil; + + // Get DepthStencilState + ANGLE_TRY(mRenderer->getDepthStencilState(mDepthStencilStateKey, &dsState)); + zValue = clearParams.clearDepth ? &clearParams.depthValue : nullptr; + } - case GL_INT: - ApplyVertices(framebufferSize, scissorPtr, clearParams.colorIClearValue, clearParams.depthClearValue, mappedResource.pData); - vertexStride = sizeof(d3d11::PositionDepthColorVertex); - shader = mIntClearShader; - break; + bool dirtyCb = false; - default: + // Compare the input color/z values against the CB cache and update it if necessary + switch (clearParams.colorType) + { + case GL_FLOAT: + dirtyCb = UpdateDataCache(reinterpret_cast *>(&mShaderData), + clearParams.colorF, zValue, numRtvs, colorMask); + break; + case GL_UNSIGNED_INT: + dirtyCb = UpdateDataCache(reinterpret_cast *>(&mShaderData), + clearParams.colorUI, zValue, numRtvs, colorMask); + break; + case GL_INT: + dirtyCb = UpdateDataCache(reinterpret_cast *>(&mShaderData), + clearParams.colorI, zValue, numRtvs, colorMask); + 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 = static_cast(framebufferSize.width); - viewport.Height = static_cast(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->resolve(device)); - deviceContext->VSSetShader(shader->vertexShader.resolve(device), nullptr, 0); - deviceContext->PSSetShader(shader->pixelShader.resolve(device), nullptr, 0); - deviceContext->GSSetShader(nullptr, nullptr, 0); - - // Apply vertex buffer - deviceContext->IASetVertexBuffers(0, 1, &mVertexBuffer, &vertexStride, &startIdx); - deviceContext->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); - - // Apply render targets - deviceContext->OMSetRenderTargets(static_cast(rtvs.size()), - (rtvs.empty() ? nullptr : &rtvs[0]), dsv); - - // Draw the clear quad - deviceContext->Draw(4, 0); - - // Clean up - mRenderer->markAllStateDirty(); } - return gl::Error(GL_NO_ERROR); -} + ANGLE_TRY(ensureConstantBufferCreated()); -ID3D11BlendState *Clear11::getBlendState(const std::vector& rts) -{ - ClearBlendInfo blendKey = {}; - for (unsigned int i = 0; i < D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; i++) + if (dirtyCb) { - 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 + // Update the constant buffer with the updated cache contents + // TODO(Shahmeer): Consider using UpdateSubresource1 D3D11_COPY_DISCARD where possible. + D3D11_MAPPED_SUBRESOURCE mappedResource; + HRESULT result = deviceContext->Map(mConstantBuffer.get(), 0, D3D11_MAP_WRITE_DISCARD, 0, + &mappedResource); + if (FAILED(result)) { - blendKey.maskChannels[i][0] = false; - blendKey.maskChannels[i][1] = false; - blendKey.maskChannels[i][2] = false; - blendKey.maskChannels[i][3] = false; + return gl::OutOfMemory() << "Clear11: Failed to map CB, " << gl::FmtHR(result); } - } - ClearBlendStateMap::const_iterator i = mClearBlendStates.find(blendKey); - if (i != mClearBlendStates.end()) - { - return i->second; + memcpy(mappedResource.pData, &mShaderData, g_ConstantBufferSize); + deviceContext->Unmap(mConstantBuffer.get(), 0); } - 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]); - } + auto *stateManager = mRenderer->getStateManager(); - ID3D11Device *device = mRenderer->getDevice(); - ID3D11BlendState* blendState = nullptr; - HRESULT result = device->CreateBlendState(&blendDesc, &blendState); - if (FAILED(result) || !blendState) - { - ERR("Unable to create a ID3D11BlendState, HRESULT: 0x%X.", result); - return nullptr; - } + // Set the viewport to be the same size as the framebuffer. + stateManager->setSimpleViewport(framebufferSize); - mClearBlendStates[blendKey] = blendState; + // Apply state + stateManager->setSimpleBlendState(blendState); - return blendState; - } -} + const UINT stencilValue = clearParams.stencilValue & 0xFF; + stateManager->setDepthStencilState(dsState, stencilValue); -ID3D11DepthStencilState *Clear11::getDepthStencilState(const ClearParameters &clearParams) -{ - ClearDepthStencilInfo dsKey = { 0 }; - dsKey.clearDepth = clearParams.clearDepth; - dsKey.clearStencil = clearParams.clearStencil; - dsKey.stencilWriteMask = clearParams.stencilWriteMask & 0xFF; + if (needScissoredClear) + { + stateManager->setRasterizerState(&mScissorEnabledRasterizerState); + } + else + { + stateManager->setRasterizerState(&mScissorDisabledRasterizerState); + } - ClearDepthStencilStateMap::const_iterator i = mClearDepthStencilStates.find(dsKey); - if (i != mClearDepthStencilStates.end()) + // Get Shaders + const d3d11::VertexShader *vs = nullptr; + const d3d11::GeometryShader *gs = nullptr; + const d3d11::InputLayout *il = nullptr; + const d3d11::PixelShader *ps = nullptr; + const bool hasLayeredLayout = + (fboData.getMultiviewLayout() == GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE); + ANGLE_TRY(mShaderManager.getShadersAndLayout(mRenderer, clearParams.colorType, numRtvs, + hasLayeredLayout, &il, &vs, &gs, &ps)); + + // Apply Shaders + stateManager->setDrawShaders(vs, gs, ps); + stateManager->setPixelConstantBuffer(0, &mConstantBuffer); + + // Bind IL & VB if needed + stateManager->setIndexBuffer(nullptr, DXGI_FORMAT_UNKNOWN, 0); + stateManager->setInputLayout(il); + + if (useVertexBuffer()) { - return i->second; + ANGLE_TRY(ensureVertexBufferCreated()); + stateManager->setSingleVertexBuffer(&mVertexBuffer, g_VertexSize, 0); } 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 = nullptr; - HRESULT result = device->CreateDepthStencilState(&dsDesc, &dsState); - if (FAILED(result) || !dsState) - { - ERR("Unable to create a ID3D11DepthStencilState, HRESULT: 0x%X.", result); - return nullptr; - } + stateManager->setSingleVertexBuffer(nullptr, 0, 0); + } - mClearDepthStencilStates[dsKey] = dsState; + stateManager->setPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST); - return dsState; + // Apply render targets + stateManager->setRenderTargets(&rtvs[0], numRtvs, dsv); + + // If scissors are necessary to be applied, then the number of clears is the number of scissor + // rects. If no scissors are necessary, then a single full-size clear is enough. + size_t necessaryNumClears = needScissoredClear ? scissorRects.size() : 1u; + for (size_t i = 0u; i < necessaryNumClears; ++i) + { + if (needScissoredClear) + { + ASSERT(i < scissorRects.size()); + stateManager->setScissorRectD3D(scissorRects[i]); + } + // Draw the fullscreen quad. + if (!hasLayeredLayout || isSideBySideFBO) + { + deviceContext->Draw(6, 0); + } + else + { + ASSERT(hasLayeredLayout); + deviceContext->DrawInstanced(6, static_cast(fboData.getNumViews()), 0, 0); + } } -} + return gl::NoError(); } + +} // namespace rx diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Clear11.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Clear11.h index 3ff73c85d1..a09812c42b 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Clear11.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Clear11.h @@ -23,6 +23,14 @@ class Renderer11; class RenderTarget11; struct ClearParameters; +template +struct RtvDsvClearInfo +{ + T r, g, b, a; + float z; + float c1padding[3]; +}; + class Clear11 : angle::NonCopyable { public: @@ -30,68 +38,63 @@ class Clear11 : angle::NonCopyable ~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); + gl::Error clearFramebuffer(const gl::Context *context, + const ClearParameters &clearParams, + const gl::FramebufferState &fboData); private: - struct MaskedRenderTarget - { - bool colorMask[4]; - RenderTarget11 *renderTarget; - }; - - ID3D11BlendState *getBlendState(const std::vector &rts); - ID3D11DepthStencilState *getDepthStencilState(const ClearParameters &clearParams); - - struct ClearShader final : public angle::NonCopyable + class ShaderManager final : angle::NonCopyable { - ClearShader(DXGI_FORMAT colorType, - const char *inputLayoutName, - const BYTE *vsByteCode, - size_t vsSize, - const char *vsDebugName, - const BYTE *psByteCode, - size_t psSize, - const char *psDebugName); - ~ClearShader(); - - d3d11::LazyInputLayout *inputLayout; - d3d11::LazyShader vertexShader; - d3d11::LazyShader pixelShader; + public: + ShaderManager(); + ~ShaderManager(); + gl::Error getShadersAndLayout(Renderer11 *renderer, + const INT clearType, + const uint32_t numRTs, + const bool hasLayeredLayout, + const d3d11::InputLayout **il, + const d3d11::VertexShader **vs, + const d3d11::GeometryShader **gs, + const d3d11::PixelShader **ps); + + private: + constexpr static size_t kNumShaders = D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; + + d3d11::InputLayout mIl9; + d3d11::LazyShader mVs9; + d3d11::LazyShader mPsFloat9; + d3d11::LazyShader mVs; + d3d11::LazyShader mVsMultiview; + d3d11::LazyShader mGsMultiview; + d3d11::LazyShader mPsDepth; + std::array, kNumShaders> mPsFloat; + std::array, kNumShaders> mPsUInt; + std::array, kNumShaders> mPsSInt; }; - template - static ClearShader CreateClearShader(ID3D11Device *device, DXGI_FORMAT colorType, const BYTE(&vsByteCode)[vsSize], const BYTE(&psByteCode)[psSize]); - - struct ClearBlendInfo - { - bool maskChannels[D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT][4]; - }; - typedef bool(*ClearBlendInfoComparisonFunction)(const ClearBlendInfo&, const ClearBlendInfo &); - typedef std::map ClearBlendStateMap; - - struct ClearDepthStencilInfo - { - bool clearDepth; - bool clearStencil; - UINT8 stencilWriteMask; - }; - typedef bool(*ClearDepthStencilInfoComparisonFunction)(const ClearDepthStencilInfo&, const ClearDepthStencilInfo &); - typedef std::map ClearDepthStencilStateMap; + bool useVertexBuffer() const; + gl::Error ensureConstantBufferCreated(); + gl::Error ensureVertexBufferCreated(); + gl::Error ensureResourcesInitialized(); Renderer11 *mRenderer; + bool mResourcesInitialized; - ClearBlendStateMap mClearBlendStates; - - ClearShader *mFloatClearShader; - ClearShader *mUintClearShader; - ClearShader *mIntClearShader; + // States + d3d11::RasterizerState mScissorEnabledRasterizerState; + d3d11::RasterizerState mScissorDisabledRasterizerState; + gl::DepthStencilState mDepthStencilStateKey; + d3d11::BlendStateKey mBlendStateKey; - ClearDepthStencilStateMap mClearDepthStencilStates; + // Shaders and shader resources + ShaderManager mShaderManager; + d3d11::Buffer mConstantBuffer; + d3d11::Buffer mVertexBuffer; - ID3D11Buffer *mVertexBuffer; - ID3D11RasterizerState *mRasterizerState; + // Buffer data and draw parameters + RtvDsvClearInfo mShaderData; }; -} +} // namespace rx #endif // LIBANGLE_RENDERER_D3D_D3D11_CLEAR11_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Context11.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Context11.cpp new file mode 100644 index 0000000000..b79dd3603a --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Context11.cpp @@ -0,0 +1,405 @@ +// +// Copyright 2016 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. +// +// Context11: +// D3D11-specific functionality associated with a GL Context. +// + +#include "libANGLE/renderer/d3d/d3d11/Context11.h" + +#include "common/string_utils.h" +#include "libANGLE/Context.h" +#include "libANGLE/MemoryProgramCache.h" +#include "libANGLE/renderer/d3d/CompilerD3D.h" +#include "libANGLE/renderer/d3d/ProgramD3D.h" +#include "libANGLE/renderer/d3d/RenderbufferD3D.h" +#include "libANGLE/renderer/d3d/SamplerD3D.h" +#include "libANGLE/renderer/d3d/ShaderD3D.h" +#include "libANGLE/renderer/d3d/TextureD3D.h" +#include "libANGLE/renderer/d3d/d3d11/Buffer11.h" +#include "libANGLE/renderer/d3d/d3d11/Fence11.h" +#include "libANGLE/renderer/d3d/d3d11/Framebuffer11.h" +#include "libANGLE/renderer/d3d/d3d11/ProgramPipeline11.h" +#include "libANGLE/renderer/d3d/d3d11/Renderer11.h" +#include "libANGLE/renderer/d3d/d3d11/StateManager11.h" +#include "libANGLE/renderer/d3d/d3d11/TransformFeedback11.h" +#include "libANGLE/renderer/d3d/d3d11/VertexArray11.h" + +namespace rx +{ + +Context11::Context11(const gl::ContextState &state, Renderer11 *renderer) + : ContextImpl(state), mRenderer(renderer) +{ +} + +Context11::~Context11() +{ +} + +gl::Error Context11::initialize() +{ + return gl::NoError(); +} + +CompilerImpl *Context11::createCompiler() +{ + if (mRenderer->getRenderer11DeviceCaps().featureLevel <= D3D_FEATURE_LEVEL_9_3) + { + return new CompilerD3D(SH_HLSL_4_0_FL9_3_OUTPUT); + } + else + { + return new CompilerD3D(SH_HLSL_4_1_OUTPUT); + } +} + +ShaderImpl *Context11::createShader(const gl::ShaderState &data) +{ + return new ShaderD3D(data, mRenderer->getWorkarounds(), mRenderer->getNativeExtensions()); +} + +ProgramImpl *Context11::createProgram(const gl::ProgramState &data) +{ + return new ProgramD3D(data, mRenderer); +} + +FramebufferImpl *Context11::createFramebuffer(const gl::FramebufferState &data) +{ + return new Framebuffer11(data, mRenderer); +} + +TextureImpl *Context11::createTexture(const gl::TextureState &state) +{ + switch (state.getTarget()) + { + case GL_TEXTURE_2D: + return new TextureD3D_2D(state, mRenderer); + case GL_TEXTURE_CUBE_MAP: + return new TextureD3D_Cube(state, mRenderer); + case GL_TEXTURE_3D: + return new TextureD3D_3D(state, mRenderer); + case GL_TEXTURE_2D_ARRAY: + return new TextureD3D_2DArray(state, mRenderer); + case GL_TEXTURE_EXTERNAL_OES: + return new TextureD3D_External(state, mRenderer); + case GL_TEXTURE_2D_MULTISAMPLE: + return new TextureD3D_2DMultisample(state, mRenderer); + break; + default: + UNREACHABLE(); + } + + return nullptr; +} + +RenderbufferImpl *Context11::createRenderbuffer() +{ + return new RenderbufferD3D(mRenderer); +} + +BufferImpl *Context11::createBuffer(const gl::BufferState &state) +{ + Buffer11 *buffer = new Buffer11(state, mRenderer); + mRenderer->onBufferCreate(buffer); + return buffer; +} + +VertexArrayImpl *Context11::createVertexArray(const gl::VertexArrayState &data) +{ + return new VertexArray11(data); +} + +QueryImpl *Context11::createQuery(GLenum type) +{ + return new Query11(mRenderer, type); +} + +FenceNVImpl *Context11::createFenceNV() +{ + return new FenceNV11(mRenderer); +} + +SyncImpl *Context11::createSync() +{ + return new Sync11(mRenderer); +} + +TransformFeedbackImpl *Context11::createTransformFeedback(const gl::TransformFeedbackState &state) +{ + return new TransformFeedback11(state, mRenderer); +} + +SamplerImpl *Context11::createSampler(const gl::SamplerState &state) +{ + return new SamplerD3D(state); +} + +ProgramPipelineImpl *Context11::createProgramPipeline(const gl::ProgramPipelineState &data) +{ + return new ProgramPipeline11(data); +} + +std::vector Context11::createPaths(GLsizei) +{ + return std::vector(); +} + +gl::Error Context11::flush(const gl::Context *context) +{ + return mRenderer->flush(); +} + +gl::Error Context11::finish(const gl::Context *context) +{ + return mRenderer->finish(); +} + +gl::Error Context11::drawArrays(const gl::Context *context, GLenum mode, GLint first, GLsizei count) +{ + ANGLE_TRY(prepareForDrawCall(context, mode)); + return mRenderer->drawArrays(context, mode, first, count, 0); +} + +gl::Error Context11::drawArraysInstanced(const gl::Context *context, + GLenum mode, + GLint first, + GLsizei count, + GLsizei instanceCount) +{ + ANGLE_TRY(prepareForDrawCall(context, mode)); + return mRenderer->drawArrays(context, mode, first, count, instanceCount); +} + +gl::Error Context11::drawElements(const gl::Context *context, + GLenum mode, + GLsizei count, + GLenum type, + const void *indices) +{ + ANGLE_TRY(prepareForDrawCall(context, mode)); + return mRenderer->drawElements(context, mode, count, type, indices, 0); +} + +gl::Error Context11::drawElementsInstanced(const gl::Context *context, + GLenum mode, + GLsizei count, + GLenum type, + const void *indices, + GLsizei instances) +{ + ANGLE_TRY(prepareForDrawCall(context, mode)); + return mRenderer->drawElements(context, mode, count, type, indices, instances); +} + +gl::Error Context11::drawRangeElements(const gl::Context *context, + GLenum mode, + GLuint start, + GLuint end, + GLsizei count, + GLenum type, + const void *indices) +{ + ANGLE_TRY(prepareForDrawCall(context, mode)); + return mRenderer->drawElements(context, mode, count, type, indices, 0); +} + +gl::Error Context11::drawArraysIndirect(const gl::Context *context, + GLenum mode, + const void *indirect) +{ + ANGLE_TRY(prepareForDrawCall(context, mode)); + return mRenderer->drawArraysIndirect(context, mode, indirect); +} + +gl::Error Context11::drawElementsIndirect(const gl::Context *context, + GLenum mode, + GLenum type, + const void *indirect) +{ + ANGLE_TRY(prepareForDrawCall(context, mode)); + return mRenderer->drawElementsIndirect(context, mode, type, indirect); +} + +GLenum Context11::getResetStatus() +{ + return mRenderer->getResetStatus(); +} + +std::string Context11::getVendorString() const +{ + return mRenderer->getVendorString(); +} + +std::string Context11::getRendererDescription() const +{ + return mRenderer->getRendererDescription(); +} + +void Context11::insertEventMarker(GLsizei length, const char *marker) +{ + auto optionalString = angle::WidenString(static_cast(length), marker); + if (optionalString.valid()) + { + mRenderer->getAnnotator()->setMarker(optionalString.value().data()); + } +} + +void Context11::pushGroupMarker(GLsizei length, const char *marker) +{ + auto optionalString = angle::WidenString(static_cast(length), marker); + if (optionalString.valid()) + { + mRenderer->getAnnotator()->beginEvent(optionalString.value().data()); + } +} + +void Context11::popGroupMarker() +{ + mRenderer->getAnnotator()->endEvent(); +} + +void Context11::pushDebugGroup(GLenum source, GLuint id, GLsizei length, const char *message) +{ + // Fall through to the EXT_debug_marker functions + pushGroupMarker(length, message); +} + +void Context11::popDebugGroup() +{ + // Fall through to the EXT_debug_marker functions + popGroupMarker(); +} + +void Context11::syncState(const gl::Context *context, const gl::State::DirtyBits &dirtyBits) +{ + mRenderer->getStateManager()->syncState(context, dirtyBits); +} + +GLint Context11::getGPUDisjoint() +{ + return mRenderer->getGPUDisjoint(); +} + +GLint64 Context11::getTimestamp() +{ + return mRenderer->getTimestamp(); +} + +void Context11::onMakeCurrent(const gl::Context *context) +{ + ANGLE_SWALLOW_ERR(mRenderer->getStateManager()->onMakeCurrent(context)); +} + +const gl::Caps &Context11::getNativeCaps() const +{ + return mRenderer->getNativeCaps(); +} + +const gl::TextureCapsMap &Context11::getNativeTextureCaps() const +{ + return mRenderer->getNativeTextureCaps(); +} + +const gl::Extensions &Context11::getNativeExtensions() const +{ + return mRenderer->getNativeExtensions(); +} + +const gl::Limitations &Context11::getNativeLimitations() const +{ + return mRenderer->getNativeLimitations(); +} + +gl::Error Context11::dispatchCompute(const gl::Context *context, + GLuint numGroupsX, + GLuint numGroupsY, + GLuint numGroupsZ) +{ + return mRenderer->dispatchCompute(context, numGroupsX, numGroupsY, numGroupsZ); +} + +gl::Error Context11::triggerDrawCallProgramRecompilation(const gl::Context *context, + GLenum drawMode) +{ + const auto &glState = context->getGLState(); + const auto *va11 = GetImplAs(glState.getVertexArray()); + const auto *drawFBO = glState.getDrawFramebuffer(); + gl::Program *program = glState.getProgram(); + ProgramD3D *programD3D = GetImplAs(program); + + programD3D->updateCachedInputLayout(va11->getCurrentStateSerial(), glState); + programD3D->updateCachedOutputLayout(context, drawFBO); + + bool recompileVS = !programD3D->hasVertexExecutableForCachedInputLayout(); + bool recompileGS = !programD3D->hasGeometryExecutableForPrimitiveType(drawMode); + bool recompilePS = !programD3D->hasPixelExecutableForCachedOutputLayout(); + + if (!recompileVS && !recompileGS && !recompilePS) + { + return gl::NoError(); + } + + // Load the compiler if necessary and recompile the programs. + ANGLE_TRY(mRenderer->ensureHLSLCompilerInitialized()); + + gl::InfoLog infoLog; + + if (recompileVS) + { + ShaderExecutableD3D *vertexExe = nullptr; + ANGLE_TRY(programD3D->getVertexExecutableForCachedInputLayout(&vertexExe, &infoLog)); + if (!programD3D->hasVertexExecutableForCachedInputLayout()) + { + ASSERT(infoLog.getLength() > 0); + ERR() << "Dynamic recompilation error log: " << infoLog.str(); + return gl::InternalError() + << "Error compiling dynamic vertex executable:" << infoLog.str(); + } + } + + if (recompileGS) + { + ShaderExecutableD3D *geometryExe = nullptr; + ANGLE_TRY(programD3D->getGeometryExecutableForPrimitiveType(context, drawMode, &geometryExe, + &infoLog)); + if (!programD3D->hasGeometryExecutableForPrimitiveType(drawMode)) + { + ASSERT(infoLog.getLength() > 0); + ERR() << "Dynamic recompilation error log: " << infoLog.str(); + return gl::InternalError() + << "Error compiling dynamic geometry executable:" << infoLog.str(); + } + } + + if (recompilePS) + { + ShaderExecutableD3D *pixelExe = nullptr; + ANGLE_TRY(programD3D->getPixelExecutableForCachedOutputLayout(&pixelExe, &infoLog)); + if (!programD3D->hasPixelExecutableForCachedOutputLayout()) + { + ASSERT(infoLog.getLength() > 0); + ERR() << "Dynamic recompilation error log: " << infoLog.str(); + return gl::InternalError() + << "Error compiling dynamic pixel executable:" << infoLog.str(); + } + } + + // Refresh the program cache entry. + if (mMemoryProgramCache) + { + mMemoryProgramCache->updateProgram(context, program); + } + + return gl::NoError(); +} + +gl::Error Context11::prepareForDrawCall(const gl::Context *context, GLenum drawMode) +{ + ANGLE_TRY(mRenderer->getStateManager()->updateState(context, drawMode)); + return gl::NoError(); +} + +} // namespace rx diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Context11.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Context11.h new file mode 100644 index 0000000000..dd99111b19 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Context11.h @@ -0,0 +1,155 @@ +// +// Copyright 2016 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. +// +// Context11: +// D3D11-specific functionality associated with a GL Context. +// + +#ifndef LIBANGLE_RENDERER_D3D_D3D11_CONTEXT11_H_ +#define LIBANGLE_RENDERER_D3D_D3D11_CONTEXT11_H_ + +#include "libANGLE/renderer/ContextImpl.h" + +namespace rx +{ +class Renderer11; + +class Context11 : public ContextImpl +{ + public: + Context11(const gl::ContextState &state, Renderer11 *renderer); + ~Context11() override; + + gl::Error initialize() override; + + // Shader creation + CompilerImpl *createCompiler() override; + ShaderImpl *createShader(const gl::ShaderState &data) override; + ProgramImpl *createProgram(const gl::ProgramState &data) override; + + // Framebuffer creation + FramebufferImpl *createFramebuffer(const gl::FramebufferState &data) override; + + // Texture creation + TextureImpl *createTexture(const gl::TextureState &state) override; + + // Renderbuffer creation + RenderbufferImpl *createRenderbuffer() override; + + // Buffer creation + BufferImpl *createBuffer(const gl::BufferState &state) override; + + // Vertex Array creation + VertexArrayImpl *createVertexArray(const gl::VertexArrayState &data) override; + + // Query and Fence creation + QueryImpl *createQuery(GLenum type) override; + FenceNVImpl *createFenceNV() override; + SyncImpl *createSync() override; + + // Transform Feedback creation + TransformFeedbackImpl *createTransformFeedback( + const gl::TransformFeedbackState &state) override; + + // Sampler object creation + SamplerImpl *createSampler(const gl::SamplerState &state) override; + + // Program Pipeline object creation + ProgramPipelineImpl *createProgramPipeline(const gl::ProgramPipelineState &data) override; + + // Path object creation. + std::vector createPaths(GLsizei) override; + + // Flush and finish. + gl::Error flush(const gl::Context *context) override; + gl::Error finish(const gl::Context *context) override; + + // Drawing methods. + gl::Error drawArrays(const gl::Context *context, + GLenum mode, + GLint first, + GLsizei count) override; + gl::Error drawArraysInstanced(const gl::Context *context, + GLenum mode, + GLint first, + GLsizei count, + GLsizei instanceCount) override; + + gl::Error drawElements(const gl::Context *context, + GLenum mode, + GLsizei count, + GLenum type, + const void *indices) override; + gl::Error drawElementsInstanced(const gl::Context *context, + GLenum mode, + GLsizei count, + GLenum type, + const void *indices, + GLsizei instances) override; + gl::Error drawRangeElements(const gl::Context *context, + GLenum mode, + GLuint start, + GLuint end, + GLsizei count, + GLenum type, + const void *indices) override; + gl::Error drawArraysIndirect(const gl::Context *context, + GLenum mode, + const void *indirect) override; + gl::Error drawElementsIndirect(const gl::Context *context, + GLenum mode, + GLenum type, + const void *indirect) override; + + // Device loss + GLenum getResetStatus() override; + + // Vendor and description strings. + std::string getVendorString() const override; + std::string getRendererDescription() const override; + + // EXT_debug_marker + void insertEventMarker(GLsizei length, const char *marker) override; + void pushGroupMarker(GLsizei length, const char *marker) override; + void popGroupMarker() override; + + // KHR_debug + void pushDebugGroup(GLenum source, GLuint id, GLsizei length, const char *message) override; + void popDebugGroup() override; + + // State sync with dirty bits. + void syncState(const gl::Context *context, const gl::State::DirtyBits &dirtyBits) override; + + // Disjoint timer queries + GLint getGPUDisjoint() override; + GLint64 getTimestamp() override; + + // Context switching + void onMakeCurrent(const gl::Context *context) override; + + // Caps queries + const gl::Caps &getNativeCaps() const override; + const gl::TextureCapsMap &getNativeTextureCaps() const override; + const gl::Extensions &getNativeExtensions() const override; + const gl::Limitations &getNativeLimitations() const override; + + Renderer11 *getRenderer() const { return mRenderer; } + + gl::Error dispatchCompute(const gl::Context *context, + GLuint numGroupsX, + GLuint numGroupsY, + GLuint numGroupsZ) override; + + gl::Error triggerDrawCallProgramRecompilation(const gl::Context *context, GLenum drawMode); + + private: + gl::Error prepareForDrawCall(const gl::Context *context, GLenum drawMode); + + Renderer11 *mRenderer; +}; + +} // namespace rx + +#endif // LIBANGLE_RENDERER_D3D_D3D11_CONTEXT11_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 index 1c35ab45cc..1e70363e11 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/DebugAnnotator11.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/DebugAnnotator11.cpp @@ -27,9 +27,7 @@ DebugAnnotator11::~DebugAnnotator11() { if (mInitialized) { -#if defined(ANGLE_ENABLE_D3D11_1) SafeRelease(mUserDefinedAnnotation); -#endif #if !defined(ANGLE_ENABLE_WINDOWS_STORE) FreeLibrary(mD3d11Module); @@ -43,9 +41,7 @@ void DebugAnnotator11::beginEvent(const wchar_t *eventName) if (mUserDefinedAnnotation != nullptr) { -#if defined(ANGLE_ENABLE_D3D11_1) mUserDefinedAnnotation->BeginEvent(eventName); -#endif } } @@ -55,9 +51,7 @@ void DebugAnnotator11::endEvent() if (mUserDefinedAnnotation != nullptr) { -#if defined(ANGLE_ENABLE_D3D11_1) mUserDefinedAnnotation->EndEvent(); -#endif } } @@ -67,16 +61,14 @@ void DebugAnnotator11::setMarker(const wchar_t *markerName) if (mUserDefinedAnnotation != nullptr) { -#if defined(ANGLE_ENABLE_D3D11_1) mUserDefinedAnnotation->SetMarker(markerName); -#endif } } bool DebugAnnotator11::getStatus() { #if defined(ANGLE_ENABLE_WINDOWS_STORE) -#if (NTDDI_VERSION == NTDDI_WIN10) + static_assert(NTDDI_VERSION >= NTDDI_WIN10, "GetStatus only works on Win10 and above"); initializeDevice(); if (mUserDefinedAnnotation != nullptr) @@ -85,38 +77,6 @@ bool DebugAnnotator11::getStatus() } return true; // Default if initializeDevice() failed -#elif defined(_DEBUG) && (WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP) - static bool underCapture = true; - - // ID3DUserDefinedAnnotation::GetStatus doesn't work with the Graphics Diagnostics tools in - // Windows 8.1/Visual Studio 2013. We can use IDXGraphicsAnalysis, though. - // 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. - - // Cache the result to reduce the number of calls to DXGIGetDebugInterface1 - static bool triedIDXGraphicsAnalysis = false; - - if (!triedIDXGraphicsAnalysis) - { - IDXGraphicsAnalysis *graphicsAnalysis = nullptr; - - HRESULT result = DXGIGetDebugInterface1(0, IID_PPV_ARGS(&graphicsAnalysis)); - if (SUCCEEDED(result)) - { - underCapture = (graphicsAnalysis != nullptr); - } - - SafeRelease(graphicsAnalysis); - triedIDXGraphicsAnalysis = true; - } - - return underCapture; -#else - // We can't detect GetStatus() on release WinRT 8.1 builds, so always return true. - return true; -#endif // (NTDDI_VERSION == NTDDI_WIN10) or _DEBUG #else // We can't detect GetStatus() on desktop ANGLE builds so always return true. return true; @@ -141,14 +101,13 @@ void DebugAnnotator11::initializeDevice() 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); + hr = D3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_NULL, nullptr, 0, nullptr, 0, + D3D11_SDK_VERSION, &device, nullptr, &context); ASSERT(SUCCEEDED(hr)); if (SUCCEEDED(hr)) { -#if defined(ANGLE_ENABLE_D3D11_1) mUserDefinedAnnotation = d3d11::DynamicCastComObject(context); ASSERT(mUserDefinedAnnotation != nullptr); -#endif 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 index d1a0f7fd2e..62662c49ae 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/DebugAnnotator11.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/DebugAnnotator11.h @@ -9,14 +9,12 @@ #ifndef LIBANGLE_RENDERER_D3D_D3D11_DEBUGANNOTATOR11_H_ #define LIBANGLE_RENDERER_D3D_D3D11_DEBUGANNOTATOR11_H_ -#include "common/debug.h" - -struct ID3DUserDefinedAnnotation; +#include "libANGLE/LoggingAnnotator.h" namespace rx { -class DebugAnnotator11 : public gl::DebugAnnotator +class DebugAnnotator11 : public angle::LoggingAnnotator { public: DebugAnnotator11(); diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Fence11.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Fence11.cpp index 53fac65f2a..082f28d794 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Fence11.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Fence11.cpp @@ -4,7 +4,8 @@ // found in the LICENSE file. // -// Fence11.cpp: Defines the rx::FenceNV11 and rx::FenceSync11 classes which implement rx::FenceNVImpl and rx::FenceSyncImpl. +// Fence11.cpp: Defines the rx::FenceNV11 and rx::Sync11 classes which implement +// rx::FenceNVImpl and rx::SyncImpl. #include "libANGLE/renderer/d3d/d3d11/Fence11.h" #include "libANGLE/renderer/d3d/d3d11/Renderer11.h" @@ -14,28 +15,30 @@ namespace rx { +static const int kDeviceLostCheckPeriod = 64; + // // Template helpers for set and test operations. // -template +template gl::Error FenceSetHelper(FenceClass *fence) { if (!fence->mQuery) { D3D11_QUERY_DESC queryDesc; - queryDesc.Query = D3D11_QUERY_EVENT; + 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); + return gl::OutOfMemory() << "Failed to create event query, " << gl::FmtHR(result); } } fence->mRenderer->getDeviceContext()->End(fence->mQuery); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } template @@ -44,30 +47,24 @@ gl::Error FenceTestHelper(FenceClass *fence, bool flushCommandBuffer, GLboolean ASSERT(fence->mQuery); UINT getDataFlags = (flushCommandBuffer ? 0 : D3D11_ASYNC_GETDATA_DONOTFLUSH); - HRESULT result = fence->mRenderer->getDeviceContext()->GetData(fence->mQuery, NULL, 0, getDataFlags); + HRESULT result = + fence->mRenderer->getDeviceContext()->GetData(fence->mQuery, nullptr, 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."); + return gl::OutOfMemory() << "Failed to get query data, " << gl::FmtHR(result); } ASSERT(result == S_OK || result == S_FALSE); *outFinished = ((result == S_OK) ? GL_TRUE : GL_FALSE); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } // // FenceNV11 // -FenceNV11::FenceNV11(Renderer11 *renderer) - : FenceNVImpl(), - mRenderer(renderer), - mQuery(NULL) +FenceNV11::FenceNV11(Renderer11 *renderer) : FenceNVImpl(), mRenderer(renderer), mQuery(nullptr) { } @@ -89,22 +86,26 @@ gl::Error FenceNV11::test(GLboolean *outFinished) gl::Error FenceNV11::finish() { GLboolean finished = GL_FALSE; + + int loopCount = 0; while (finished != GL_TRUE) { - gl::Error error = FenceTestHelper(this, true, &finished); - if (error.isError()) + loopCount++; + ANGLE_TRY(FenceTestHelper(this, true, &finished)); + + if (loopCount % kDeviceLostCheckPeriod == 0 && mRenderer->testDeviceLost()) { - return error; + return gl::OutOfMemory() << "Device was lost while querying result of an event query."; } ScheduleYield(); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } // -// FenceSync11 +// Sync11 // // Important note on accurate timers in Windows: @@ -118,38 +119,34 @@ gl::Error FenceNV11::finish() // 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) +Sync11::Sync11(Renderer11 *renderer) : SyncImpl(), mRenderer(renderer), mQuery(nullptr) { LARGE_INTEGER counterFreqency = {}; - BOOL success = QueryPerformanceFrequency(&counterFreqency); - UNUSED_ASSERTION_VARIABLE(success); + BOOL success = QueryPerformanceFrequency(&counterFreqency); ASSERT(success); mCounterFrequency = counterFreqency.QuadPart; } -FenceSync11::~FenceSync11() +Sync11::~Sync11() { SafeRelease(mQuery); } -gl::Error FenceSync11::set(GLenum condition, GLbitfield flags) +gl::Error Sync11::set(GLenum condition, GLbitfield flags) { ASSERT(condition == GL_SYNC_GPU_COMMANDS_COMPLETE && flags == 0); return FenceSetHelper(this); } -gl::Error FenceSync11::clientWait(GLbitfield flags, GLuint64 timeout, GLenum *outResult) +gl::Error Sync11::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); + gl::Error error = FenceTestHelper(this, flushCommandBuffer, &result); if (error.isError()) { *outResult = GL_WAIT_FAILED; @@ -159,28 +156,34 @@ gl::Error FenceSync11::clientWait(GLbitfield flags, GLuint64 timeout, GLenum *ou if (result == GL_TRUE) { *outResult = GL_ALREADY_SIGNALED; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } if (timeout == 0) { *outResult = GL_TIMEOUT_EXPIRED; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } LARGE_INTEGER currentCounter = {}; - BOOL success = QueryPerformanceCounter(¤tCounter); - UNUSED_ASSERTION_VARIABLE(success); + BOOL success = QueryPerformanceCounter(¤tCounter); ASSERT(success); - LONGLONG timeoutInSeconds = static_cast(timeout) * static_cast(1000000ll); - LONGLONG endCounter = currentCounter.QuadPart + mCounterFrequency * timeoutInSeconds; + LONGLONG timeoutInSeconds = static_cast(timeout / 1000000000ull); + LONGLONG endCounter = currentCounter.QuadPart + mCounterFrequency * timeoutInSeconds; + // Extremely unlikely, but if mCounterFrequency is large enough, endCounter can wrap + if (endCounter < currentCounter.QuadPart) + { + endCounter = MAXLONGLONG; + } + + int loopCount = 0; while (currentCounter.QuadPart < endCounter && !result) { + loopCount++; ScheduleYield(); success = QueryPerformanceCounter(¤tCounter); - UNUSED_ASSERTION_VARIABLE(success); ASSERT(success); error = FenceTestHelper(this, flushCommandBuffer, &result); @@ -189,6 +192,12 @@ gl::Error FenceSync11::clientWait(GLbitfield flags, GLuint64 timeout, GLenum *ou *outResult = GL_WAIT_FAILED; return error; } + + if ((loopCount % kDeviceLostCheckPeriod) == 0 && mRenderer->testDeviceLost()) + { + *outResult = GL_WAIT_FAILED; + return gl::OutOfMemory() << "Device was lost while querying result of an event query."; + } } if (currentCounter.QuadPart >= endCounter) @@ -200,32 +209,32 @@ gl::Error FenceSync11::clientWait(GLbitfield flags, GLuint64 timeout, GLenum *ou *outResult = GL_CONDITION_SATISFIED; } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error FenceSync11::serverWait(GLbitfield flags, GLuint64 timeout) +gl::Error Sync11::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); + // 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::NoError(); } -gl::Error FenceSync11::getStatus(GLint *outResult) +gl::Error Sync11::getStatus(GLint *outResult) { GLboolean result = GL_FALSE; - gl::Error error = FenceTestHelper(this, false, &result); + 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. + // 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); + return gl::NoError(); } -} // namespace rx +} // 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 index 595978885b..4168df5365 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Fence11.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Fence11.h @@ -4,13 +4,14 @@ // found in the LICENSE file. // -// Fence11.h: Defines the rx::FenceNV11 and rx::FenceSync11 classes which implement rx::FenceNVImpl and rx::FenceSyncImpl. +// Fence11.h: Defines the rx::FenceNV11 and rx::Sync11 classes which implement rx::FenceNVImpl +// and rx::SyncImpl. #ifndef LIBANGLE_RENDERER_D3D_D3D11_FENCE11_H_ #define LIBANGLE_RENDERER_D3D_D3D11_FENCE11_H_ #include "libANGLE/renderer/FenceNVImpl.h" -#include "libANGLE/renderer/FenceSyncImpl.h" +#include "libANGLE/renderer/SyncImpl.h" namespace rx { @@ -34,11 +35,11 @@ class FenceNV11 : public FenceNVImpl ID3D11Query *mQuery; }; -class FenceSync11 : public FenceSyncImpl +class Sync11 : public SyncImpl { public: - explicit FenceSync11(Renderer11 *renderer); - ~FenceSync11() override; + explicit Sync11(Renderer11 *renderer); + ~Sync11() override; gl::Error set(GLenum condition, GLbitfield flags) override; gl::Error clientWait(GLbitfield flags, GLuint64 timeout, GLenum *outResult) override; diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Framebuffer11.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Framebuffer11.cpp index 186a035902..02326d7b50 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Framebuffer11.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Framebuffer11.cpp @@ -8,94 +8,119 @@ #include "libANGLE/renderer/d3d/d3d11/Framebuffer11.h" +#include "common/bitset_utils.h" #include "common/debug.h" +#include "libANGLE/Context.h" +#include "libANGLE/Framebuffer.h" +#include "libANGLE/FramebufferAttachment.h" +#include "libANGLE/Texture.h" +#include "libANGLE/renderer/d3d/TextureD3D.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/Renderer11.h" +#include "libANGLE/renderer/d3d/d3d11/TextureStorage11.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" +#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h" + +using namespace angle; namespace rx { -Framebuffer11::Framebuffer11(const gl::Framebuffer::Data &data, Renderer11 *renderer) - : FramebufferD3D(data, renderer), mRenderer(renderer) +namespace { - ASSERT(mRenderer != nullptr); -} - -Framebuffer11::~Framebuffer11() +gl::Error MarkAttachmentsDirty(const gl::Context *context, + const gl::FramebufferAttachment *attachment) { -} - -static gl::Error InvalidateAttachmentSwizzles(const gl::FramebufferAttachment *attachment) -{ - if (attachment && attachment->type() == GL_TEXTURE) + if (attachment->type() == GL_TEXTURE) { gl::Texture *texture = attachment->getTexture(); TextureD3D *textureD3D = GetImplAs(texture); TextureStorage *texStorage = nullptr; - gl::Error error = textureD3D->getNativeTexture(&texStorage); - if (error.isError()) - { - return error; - } + ANGLE_TRY(textureD3D->getNativeTexture(context, &texStorage)); if (texStorage) { TextureStorage11 *texStorage11 = GetAs(texStorage); ASSERT(texStorage11); - texStorage11->invalidateSwizzleCacheLevel(attachment->mipLevel()); + texStorage11->markLevelDirty(attachment->mipLevel()); } } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error Framebuffer11::invalidateSwizzles() const +void UpdateCachedRenderTarget(const gl::Context *context, + const gl::FramebufferAttachment *attachment, + RenderTarget11 *&cachedRenderTarget, + OnRenderTargetDirtyBinding *channelBinding) { - for (const auto &colorAttachment : mData.getColorAttachments()) + RenderTarget11 *newRenderTarget = nullptr; + if (attachment) { - if (colorAttachment.isAttached()) + // TODO(jmadill): Don't swallow this error. + gl::Error error = attachment->getRenderTarget(context, &newRenderTarget); + if (error.isError()) { - gl::Error error = InvalidateAttachmentSwizzles(&colorAttachment); - if (error.isError()) - { - return error; - } + ERR() << "Internal rendertarget error: " << error; } } + if (newRenderTarget != cachedRenderTarget) + { + OnRenderTargetDirtyChannel *channel = + (newRenderTarget ? newRenderTarget->getBroadcastChannel() : nullptr); + channelBinding->bind(channel); + cachedRenderTarget = newRenderTarget; + } +} +} // anonymous namespace + +Framebuffer11::Framebuffer11(const gl::FramebufferState &data, Renderer11 *renderer) + : FramebufferD3D(data, renderer), + mRenderer(renderer), + mCachedDepthStencilRenderTarget(nullptr), + mDepthStencilRenderTargetDirty(this, gl::IMPLEMENTATION_MAX_FRAMEBUFFER_ATTACHMENTS) +{ + ASSERT(mRenderer != nullptr); + mCachedColorRenderTargets.fill(nullptr); + for (size_t colorIndex = 0; colorIndex < data.getColorAttachments().size(); ++colorIndex) + { + mColorRenderTargetsDirty.emplace_back(this, colorIndex); + } +} - gl::Error error = InvalidateAttachmentSwizzles(mData.getDepthAttachment()); - if (error.isError()) +Framebuffer11::~Framebuffer11() +{ +} + +gl::Error Framebuffer11::markAttachmentsDirty(const gl::Context *context) const +{ + const auto &colorAttachments = mState.getColorAttachments(); + for (size_t drawBuffer : mState.getEnabledDrawBuffers()) { - return error; + const gl::FramebufferAttachment &colorAttachment = colorAttachments[drawBuffer]; + ASSERT(colorAttachment.isAttached()); + ANGLE_TRY(MarkAttachmentsDirty(context, &colorAttachment)); } - error = InvalidateAttachmentSwizzles(mData.getStencilAttachment()); - if (error.isError()) + const gl::FramebufferAttachment *dsAttachment = mState.getDepthOrStencilAttachment(); + if (dsAttachment) { - return error; + ANGLE_TRY(MarkAttachmentsDirty(context, dsAttachment)); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error Framebuffer11::clear(const gl::Data &data, const ClearParameters &clearParams) +gl::Error Framebuffer11::clearImpl(const gl::Context *context, const ClearParameters &clearParams) { Clear11 *clearer = mRenderer->getClearer(); - gl::Error error(GL_NO_ERROR); - const gl::FramebufferAttachment *colorAttachment = mData.getFirstColorAttachment(); + const gl::FramebufferAttachment *colorAttachment = mState.getFirstColorAttachment(); if (clearParams.scissorEnabled == true && colorAttachment != nullptr && UsePresentPathFast(mRenderer, colorAttachment)) { @@ -107,46 +132,43 @@ gl::Error Framebuffer11::clear(const gl::Data &data, const ClearParameters &clea presentPathFastClearParams.scissor.y = framebufferSize.height - presentPathFastClearParams.scissor.y - presentPathFastClearParams.scissor.height; - error = clearer->clearFramebuffer(presentPathFastClearParams, mData); + ANGLE_TRY(clearer->clearFramebuffer(context, presentPathFastClearParams, mState)); } else { - error = clearer->clearFramebuffer(clearParams, mData); + ANGLE_TRY(clearer->clearFramebuffer(context, clearParams, mState)); } - if (error.isError()) - { - return error; - } - - error = invalidateSwizzles(); - if (error.isError()) - { - return error; - } + ANGLE_TRY(markAttachmentsDirty(context)); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error Framebuffer11::invalidate(size_t count, const GLenum *attachments) +gl::Error Framebuffer11::invalidate(const gl::Context *context, + size_t count, + const GLenum *attachments) { - return invalidateBase(count, attachments, false); + return invalidateBase(context, count, attachments, false); } -gl::Error Framebuffer11::discard(size_t count, const GLenum *attachments) +gl::Error Framebuffer11::discard(const gl::Context *context, + size_t count, + const GLenum *attachments) { - return invalidateBase(count, attachments, true); + return invalidateBase(context, count, attachments, true); } -gl::Error Framebuffer11::invalidateBase(size_t count, const GLenum *attachments, bool useEXTBehavior) const +gl::Error Framebuffer11::invalidateBase(const gl::Context *context, + size_t count, + const GLenum *attachments, + bool useEXTBehavior) const { -#if defined(ANGLE_ENABLE_D3D11_1) ID3D11DeviceContext1 *deviceContext1 = mRenderer->getDeviceContext1IfSupported(); if (!deviceContext1) { // DiscardView() is only supported on ID3D11DeviceContext1 - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } bool foundDepth = false; @@ -175,37 +197,14 @@ gl::Error Framebuffer11::invalidateBase(size_t count, const GLenum *attachments, ASSERT((attachments[i] >= GL_COLOR_ATTACHMENT0 && attachments[i] <= GL_COLOR_ATTACHMENT15) || (attachments[i] == GL_COLOR)); - RenderTarget11 *renderTarget = nullptr; - ID3D11View *colorView = nullptr; - gl::Error error(GL_NO_ERROR); - size_t colorAttachmentID = 0; - - if (attachments[i] == GL_COLOR) - { - colorAttachmentID = 0; - } - else + size_t colorIndex = + (attachments[i] == GL_COLOR ? 0u : (attachments[i] - GL_COLOR_ATTACHMENT0)); + const gl::FramebufferAttachment *colorAttachment = + mState.getColorAttachment(colorIndex); + if (colorAttachment) { - colorAttachmentID = attachments[i] - GL_COLOR_ATTACHMENT0; + ANGLE_TRY(invalidateAttachment(context, colorAttachment)); } - - if (mData.getColorAttachment(static_cast(colorAttachmentID))) - { - error = mData.getColorAttachment(static_cast(colorAttachmentID)) - ->getRenderTarget(&renderTarget); - if (error.isError()) - { - return error; - } - - colorView = renderTarget->getRenderTargetView(); - - if (colorView != nullptr) - { - deviceContext1->DiscardView(colorView); - } - } - break; } } @@ -222,7 +221,7 @@ gl::Error Framebuffer11::invalidateBase(size_t count, const GLenum *attachments, discardDepth = foundDepth; // Don't bother discarding the stencil buffer if the depth buffer will already do it - discardStencil = foundStencil && (!discardDepth || mData.getDepthAttachment() == nullptr); + discardStencil = foundStencil && (!discardDepth || mState.getDepthAttachment() == nullptr); } else { @@ -230,94 +229,86 @@ gl::Error Framebuffer11::invalidateBase(size_t count, const GLenum *attachments, // attachments list does not include DEPTH_STENCIL_ATTACHMENT or both DEPTH_ATTACHMENT and // STENCIL_ATTACHMENT, then only the specified portion of every pixel in the subregion of pixels // of the DEPTH_STENCIL buffer may be invalidated, and the other portion must be preserved. - discardDepth = (foundDepth && foundStencil) || (foundDepth && (mData.getStencilAttachment() == nullptr)); - discardStencil = (foundStencil && (mData.getDepthAttachment() == nullptr)); + discardDepth = (foundDepth && foundStencil) || + (foundDepth && (mState.getStencilAttachment() == nullptr)); + discardStencil = (foundStencil && (mState.getDepthAttachment() == nullptr)); } - if (discardDepth && mData.getDepthAttachment()) + if (discardDepth && mState.getDepthAttachment()) { - RenderTarget11 *renderTarget = nullptr; - ID3D11View *depthView = nullptr; - gl::Error error(GL_NO_ERROR); - - error = mData.getDepthAttachment()->getRenderTarget(&renderTarget); - if (error.isError()) - { - return error; - } - - depthView = renderTarget->getDepthStencilView(); - - if (depthView != nullptr) - { - deviceContext1->DiscardView(depthView); - } + ANGLE_TRY(invalidateAttachment(context, mState.getDepthAttachment())); } - if (discardStencil && mData.getStencilAttachment()) + if (discardStencil && mState.getStencilAttachment()) { - RenderTarget11 *renderTarget = nullptr; - ID3D11View *stencilView = nullptr; - gl::Error error(GL_NO_ERROR); - - error = mData.getStencilAttachment()->getRenderTarget(&renderTarget); - if (error.isError()) - { - return error; - } - - stencilView = renderTarget->getDepthStencilView(); - - if (stencilView != nullptr) - { - deviceContext1->DiscardView(stencilView); - } + ANGLE_TRY(invalidateAttachment(context, mState.getStencilAttachment())); } -#endif // ANGLE_ENABLE_D3D11_1 - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error Framebuffer11::invalidateSub(size_t, const GLenum *, const gl::Rectangle &) +gl::Error Framebuffer11::invalidateSub(const gl::Context *context, + size_t, + const GLenum *, + const gl::Rectangle &) { // A no-op implementation conforms to the spec, so don't call UNIMPLEMENTED() - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error Framebuffer11::readPixelsImpl(const gl::Rectangle &area, +gl::Error Framebuffer11::invalidateAttachment(const gl::Context *context, + const gl::FramebufferAttachment *attachment) const +{ + ID3D11DeviceContext1 *deviceContext1 = mRenderer->getDeviceContext1IfSupported(); + ASSERT(deviceContext1); + ASSERT(attachment && attachment->isAttached()); + + RenderTarget11 *renderTarget = nullptr; + ANGLE_TRY(attachment->getRenderTarget(context, &renderTarget)); + const auto &rtv = renderTarget->getRenderTargetView(); + + if (rtv.valid()) + { + deviceContext1->DiscardView(rtv.get()); + } + + return gl::NoError(); +} + +gl::Error Framebuffer11::readPixelsImpl(const gl::Context *context, + const gl::Rectangle &area, GLenum format, GLenum type, size_t outputPitch, const gl::PixelPackState &pack, - uint8_t *pixels) const + uint8_t *pixels) { - const gl::FramebufferAttachment *readAttachment = mData.getReadAttachment(); + const gl::FramebufferAttachment *readAttachment = mState.getReadAttachment(); ASSERT(readAttachment); - gl::Buffer *packBuffer = pack.pixelBuffer.get(); + gl::Buffer *packBuffer = context->getGLState().getTargetBuffer(gl::BufferBinding::PixelPack); if (packBuffer != nullptr) { - if (pack.rowLength != 0 || pack.skipRows != 0 || pack.skipPixels != 0) - { - UNIMPLEMENTED(); - return gl::Error(GL_INVALID_OPERATION, - "Unimplemented pixel store parameters in readPixelsImpl"); - } - Buffer11 *packBufferStorage = GetImplAs(packBuffer); PackPixelsParams packParams(area, format, type, static_cast(outputPitch), pack, - reinterpret_cast(pixels)); + packBuffer, reinterpret_cast(pixels)); - return packBufferStorage->packPixels(*readAttachment, packParams); + return packBufferStorage->packPixels(context, *readAttachment, packParams); } - return mRenderer->readFromAttachment(*readAttachment, area, format, type, + return mRenderer->readFromAttachment(context, *readAttachment, area, format, type, static_cast(outputPitch), pack, pixels); } -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) +gl::Error Framebuffer11::blitImpl(const gl::Context *context, + 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) { @@ -325,15 +316,11 @@ gl::Error Framebuffer11::blit(const gl::Rectangle &sourceArea, const gl::Rectang ASSERT(readBuffer); RenderTargetD3D *readRenderTarget = nullptr; - gl::Error error = readBuffer->getRenderTarget(&readRenderTarget); - if (error.isError()) - { - return error; - } + ANGLE_TRY(readBuffer->getRenderTarget(context, &readRenderTarget)); ASSERT(readRenderTarget); - const auto &colorAttachments = mData.getColorAttachments(); - const auto &drawBufferStates = mData.getDrawBufferStates(); + const auto &colorAttachments = mState.getColorAttachments(); + const auto &drawBufferStates = mState.getDrawBufferStates(); for (size_t colorAttachment = 0; colorAttachment < colorAttachments.size(); colorAttachment++) { @@ -343,11 +330,7 @@ gl::Error Framebuffer11::blit(const gl::Rectangle &sourceArea, const gl::Rectang drawBufferStates[colorAttachment] != GL_NONE) { RenderTargetD3D *drawRenderTarget = nullptr; - error = drawBuffer.getRenderTarget(&drawRenderTarget); - if (error.isError()) - { - return error; - } + ANGLE_TRY(drawBuffer.getRenderTarget(context, &drawRenderTarget)); ASSERT(drawRenderTarget); const bool invertColorSource = UsePresentPathFast(mRenderer, readBuffer); @@ -368,13 +351,9 @@ gl::Error Framebuffer11::blit(const gl::Rectangle &sourceArea, const gl::Rectang actualDestArea.height = -destArea.height; } - error = mRenderer->blitRenderbufferRect(actualSourceArea, actualDestArea, - readRenderTarget, drawRenderTarget, filter, - scissor, blitRenderTarget, false, false); - if (error.isError()) - { - return error; - } + ANGLE_TRY(mRenderer->blitRenderbufferRect( + context, actualSourceArea, actualDestArea, readRenderTarget, drawRenderTarget, + filter, scissor, blitRenderTarget, false, false)); } } } @@ -385,46 +364,144 @@ gl::Error Framebuffer11::blit(const gl::Rectangle &sourceArea, const gl::Rectang ASSERT(readBuffer); RenderTargetD3D *readRenderTarget = nullptr; - gl::Error error = readBuffer->getRenderTarget(&readRenderTarget); - if (error.isError()) - { - return error; - } + ANGLE_TRY(readBuffer->getRenderTarget(context, &readRenderTarget)); ASSERT(readRenderTarget); - const gl::FramebufferAttachment *drawBuffer = mData.getDepthOrStencilAttachment(); + const gl::FramebufferAttachment *drawBuffer = mState.getDepthOrStencilAttachment(); ASSERT(drawBuffer); RenderTargetD3D *drawRenderTarget = nullptr; - error = drawBuffer->getRenderTarget(&drawRenderTarget); - if (error.isError()) - { - return error; - } + ANGLE_TRY(drawBuffer->getRenderTarget(context, &drawRenderTarget)); ASSERT(drawRenderTarget); - error = mRenderer->blitRenderbufferRect(sourceArea, destArea, readRenderTarget, drawRenderTarget, filter, scissor, - false, blitDepth, blitStencil); - if (error.isError()) + ANGLE_TRY(mRenderer->blitRenderbufferRect(context, sourceArea, destArea, readRenderTarget, + drawRenderTarget, filter, scissor, false, + blitDepth, blitStencil)); + } + + ANGLE_TRY(markAttachmentsDirty(context)); + return gl::NoError(); +} + +GLenum Framebuffer11::getRenderTargetImplementationFormat(RenderTargetD3D *renderTarget) const +{ + RenderTarget11 *renderTarget11 = GetAs(renderTarget); + return renderTarget11->getFormatSet().format().fboImplementationInternalFormat; +} + +void Framebuffer11::updateColorRenderTarget(const gl::Context *context, size_t colorIndex) +{ + UpdateCachedRenderTarget(context, mState.getColorAttachment(colorIndex), + mCachedColorRenderTargets[colorIndex], + &mColorRenderTargetsDirty[colorIndex]); +} + +void Framebuffer11::updateDepthStencilRenderTarget(const gl::Context *context) +{ + UpdateCachedRenderTarget(context, mState.getDepthOrStencilAttachment(), + mCachedDepthStencilRenderTarget, &mDepthStencilRenderTargetDirty); +} + +void Framebuffer11::syncState(const gl::Context *context, + const gl::Framebuffer::DirtyBits &dirtyBits) +{ + const auto &mergedDirtyBits = dirtyBits | mInternalDirtyBits; + mInternalDirtyBits.reset(); + + for (auto dirtyBit : mergedDirtyBits) + { + switch (dirtyBit) { - return error; + case gl::Framebuffer::DIRTY_BIT_DEPTH_ATTACHMENT: + case gl::Framebuffer::DIRTY_BIT_STENCIL_ATTACHMENT: + updateDepthStencilRenderTarget(context); + break; + case gl::Framebuffer::DIRTY_BIT_DRAW_BUFFERS: + case gl::Framebuffer::DIRTY_BIT_READ_BUFFER: + break; + case gl::Framebuffer::DIRTY_BIT_DEFAULT_WIDTH: + case gl::Framebuffer::DIRTY_BIT_DEFAULT_HEIGHT: + case gl::Framebuffer::DIRTY_BIT_DEFAULT_SAMPLES: + case gl::Framebuffer::DIRTY_BIT_DEFAULT_FIXED_SAMPLE_LOCATIONS: + break; + default: + { + ASSERT(gl::Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_0 == 0 && + dirtyBit < gl::Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_MAX); + size_t colorIndex = + static_cast(dirtyBit - gl::Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_0); + updateColorRenderTarget(context, colorIndex); + break; + } } } - gl::Error error = invalidateSwizzles(); - if (error.isError()) + // We should not have dirtied any additional state during our sync. + ASSERT(!mInternalDirtyBits.any()); + + FramebufferD3D::syncState(context, dirtyBits); + + // Call this last to allow the state manager to take advantage of the cached render targets. + mRenderer->getStateManager()->invalidateRenderTarget(); + + // Call this to syncViewport for framebuffer default parameters. + if (mState.getDefaultWidth() != 0 || mState.getDefaultHeight() != 0) + { + mRenderer->getStateManager()->invalidateViewport(context); + } +} + +void Framebuffer11::signal(size_t channelID, const gl::Context *context) +{ + if (channelID == gl::IMPLEMENTATION_MAX_FRAMEBUFFER_ATTACHMENTS) + { + // Stencil is redundant in this case. + mInternalDirtyBits.set(gl::Framebuffer::DIRTY_BIT_DEPTH_ATTACHMENT); + mCachedDepthStencilRenderTarget = nullptr; + } + else { - return error; + mInternalDirtyBits.set(gl::Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_0 + channelID); + mCachedColorRenderTargets[channelID] = nullptr; } - return gl::Error(GL_NO_ERROR); + // Notify the context we need to re-validate the RenderTarget. + // TODO(jmadill): Check that we're the active draw framebuffer. + mRenderer->getStateManager()->invalidateRenderTarget(); } -GLenum Framebuffer11::getRenderTargetImplementationFormat(RenderTargetD3D *renderTarget) const +gl::Error Framebuffer11::getSamplePosition(size_t index, GLfloat *xy) const { - RenderTarget11 *renderTarget11 = GetAs(renderTarget); - const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(renderTarget11->getDXGIFormat()); - return dxgiFormatInfo.internalFormat; + const gl::FramebufferAttachment *attachment = mState.getFirstNonNullAttachment(); + ASSERT(attachment); + GLsizei sampleCount = attachment->getSamples(); + + d3d11_gl::GetSamplePosition(sampleCount, index, xy); + return gl::NoError(); +} + +bool Framebuffer11::hasAnyInternalDirtyBit() const +{ + return mInternalDirtyBits.any(); +} + +void Framebuffer11::syncInternalState(const gl::Context *context) +{ + syncState(context, gl::Framebuffer::DirtyBits()); } +RenderTarget11 *Framebuffer11::getFirstRenderTarget() const +{ + ASSERT(mInternalDirtyBits.none()); + for (auto *renderTarget : mCachedColorRenderTargets) + { + if (renderTarget) + { + return renderTarget; + } + } + + return mCachedDepthStencilRenderTarget; } + +} // namespace rx diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Framebuffer11.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Framebuffer11.h index c8a33ec7e5..afdda299b9 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Framebuffer11.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Framebuffer11.h @@ -10,43 +10,93 @@ #define LIBANGLE_RENDERER_D3D_D3D11_FRAMBUFFER11_H_ #include "libANGLE/renderer/d3d/FramebufferD3D.h" +#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h" +#include "libANGLE/signal_utils.h" namespace rx { class Renderer11; -class Framebuffer11 : public FramebufferD3D +class Framebuffer11 : public FramebufferD3D, public OnRenderTargetDirtyReceiver { public: - Framebuffer11(const gl::Framebuffer::Data &data, Renderer11 *renderer); - virtual ~Framebuffer11(); + Framebuffer11(const gl::FramebufferState &data, Renderer11 *renderer); + ~Framebuffer11() override; - gl::Error discard(size_t count, const GLenum *attachments) 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 discard(const gl::Context *context, size_t count, const GLenum *attachments) override; + gl::Error invalidate(const gl::Context *context, + size_t count, + const GLenum *attachments) override; + gl::Error invalidateSub(const gl::Context *context, + size_t count, + const GLenum *attachments, + const gl::Rectangle &area) override; // Invalidate the cached swizzles of all bound texture attachments. - gl::Error invalidateSwizzles() const; + gl::Error markAttachmentsDirty(const gl::Context *context) const; + + void syncState(const gl::Context *context, + const gl::Framebuffer::DirtyBits &dirtyBits) override; + + const RenderTargetArray &getCachedColorRenderTargets() const + { + return mCachedColorRenderTargets; + } + const RenderTarget11 *getCachedDepthStencilRenderTarget() const + { + return mCachedDepthStencilRenderTarget; + } + + RenderTarget11 *getFirstRenderTarget() const; + + bool hasAnyInternalDirtyBit() const; + void syncInternalState(const gl::Context *context); + + void signal(size_t channelID, const gl::Context *context) override; + + gl::Error getSamplePosition(size_t index, GLfloat *xy) const override; private: - gl::Error clear(const gl::Data &data, const ClearParameters &clearParams) override; + gl::Error clearImpl(const gl::Context *context, const ClearParameters &clearParams) override; - gl::Error readPixelsImpl(const gl::Rectangle &area, + gl::Error readPixelsImpl(const gl::Context *context, + const gl::Rectangle &area, GLenum format, GLenum type, size_t outputPitch, const gl::PixelPackState &pack, - uint8_t *pixels) const override; + uint8_t *pixels) 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; + gl::Error blitImpl(const gl::Context *context, + 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; - gl::Error invalidateBase(size_t count, const GLenum *attachments, bool useEXTBehavior) const; + gl::Error invalidateBase(const gl::Context *context, + size_t count, + const GLenum *attachments, + bool useEXTBehavior) const; + gl::Error invalidateAttachment(const gl::Context *context, + const gl::FramebufferAttachment *attachment) const; GLenum getRenderTargetImplementationFormat(RenderTargetD3D *renderTarget) const override; + void updateColorRenderTarget(const gl::Context *context, size_t colorIndex); + void updateDepthStencilRenderTarget(const gl::Context *context); + Renderer11 *const mRenderer; + RenderTargetArray mCachedColorRenderTargets; + RenderTarget11 *mCachedDepthStencilRenderTarget; + + std::vector mColorRenderTargetsDirty; + OnRenderTargetDirtyBinding mDepthStencilRenderTargetDirty; + + gl::Framebuffer::DirtyBits mInternalDirtyBits; }; } diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Image11.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Image11.cpp index c52092d81e..bd921f1935 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Image11.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Image11.cpp @@ -26,10 +26,10 @@ namespace rx Image11::Image11(Renderer11 *renderer) : mRenderer(renderer), mDXGIFormat(DXGI_FORMAT_UNKNOWN), - mStagingTexture(NULL), + mStagingTexture(), mStagingSubresource(0), mRecoverFromStorage(false), - mAssociatedStorage(NULL), + mAssociatedStorage(nullptr), mAssociatedImageIndex(gl::ImageIndex::MakeInvalid()), mRecoveredFromStorageCount(0) { @@ -41,55 +41,106 @@ Image11::~Image11() releaseStagingTexture(); } -gl::Error Image11::generateMipmap(Image11 *dest, Image11 *src) +// static +gl::Error Image11::GenerateMipmap(const gl::Context *context, + Image11 *dest, + Image11 *src, + const Renderer11DeviceCaps &rendererCaps) { 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); + ANGLE_TRY(dest->map(context, D3D11_MAP_WRITE, &destMapped)); + + D3D11_MAPPED_SUBRESOURCE srcMapped; + gl::Error error = src->map(context, 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); + + auto mipGenerationFunction = + d3d11::Format::Get(src->getInternalFormat(), rendererCaps).format().mipGenerationFunction; + 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::NoError(); +} + +// static +gl::Error Image11::CopyImage(const gl::Context *context, + Image11 *dest, + Image11 *source, + const gl::Rectangle &sourceRect, + const gl::Offset &destOffset, + bool unpackFlipY, + bool unpackPremultiplyAlpha, + bool unpackUnmultiplyAlpha, + const Renderer11DeviceCaps &rendererCaps) +{ + D3D11_MAPPED_SUBRESOURCE destMapped; + ANGLE_TRY(dest->map(context, D3D11_MAP_WRITE, &destMapped)); + D3D11_MAPPED_SUBRESOURCE srcMapped; - error = src->map(D3D11_MAP_READ, &srcMapped); + gl::Error error = source->map(context, 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); + const auto &sourceFormat = + d3d11::Format::Get(source->getInternalFormat(), rendererCaps).format(); + GLuint sourcePixelBytes = + gl::GetSizedInternalFormatInfo(sourceFormat.fboImplementationInternalFormat).pixelBytes; + + GLenum destUnsizedFormat = gl::GetUnsizedFormat(dest->getInternalFormat()); + const auto &destFormat = d3d11::Format::Get(dest->getInternalFormat(), rendererCaps).format(); + const auto &destFormatInfo = + gl::GetSizedInternalFormatInfo(destFormat.fboImplementationInternalFormat); + GLuint destPixelBytes = destFormatInfo.pixelBytes; - dxgiFormatInfo.mipGenerationFunction(src->getWidth(), src->getHeight(), src->getDepth(), - sourceData, srcMapped.RowPitch, srcMapped.DepthPitch, - destData, destMapped.RowPitch, destMapped.DepthPitch); + const uint8_t *sourceData = reinterpret_cast(srcMapped.pData) + + sourceRect.x * sourcePixelBytes + sourceRect.y * srcMapped.RowPitch; + uint8_t *destData = reinterpret_cast(destMapped.pData) + + destOffset.x * destPixelBytes + destOffset.y * destMapped.RowPitch; + + CopyImageCHROMIUM(sourceData, srcMapped.RowPitch, sourcePixelBytes, + sourceFormat.colorReadFunction, destData, destMapped.RowPitch, destPixelBytes, + destFormat.colorWriteFunction, destUnsizedFormat, + destFormatInfo.componentType, sourceRect.width, sourceRect.height, + unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha); dest->unmap(); - src->unmap(); + source->unmap(); dest->markDirty(); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } 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) + // 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) AND robust resource initialization is not enabled then isDirty should + // still return false. + if (mDirty && !mStagingTexture.valid() && !mRecoverFromStorage) { const Renderer11DeviceCaps &deviceCaps = mRenderer->getRenderer11DeviceCaps(); - const d3d11::TextureFormat formatInfo = d3d11::GetTextureFormatInfo(mInternalFormat, deviceCaps); + const auto &formatInfo = d3d11::Format::Get(mInternalFormat, deviceCaps); if (formatInfo.dataInitializerFunction == nullptr) { return false; @@ -99,92 +150,69 @@ bool Image11::isDirty() const return mDirty; } -gl::Error Image11::copyToStorage(TextureStorage *storage, const gl::ImageIndex &index, const gl::Box ®ion) +gl::Error Image11::copyToStorage(const gl::Context *context, + TextureStorage *storage, + const gl::ImageIndex &index, + const gl::Box ®ion) { TextureStorage11 *storage11 = GetAs(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. + // 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; - } + // If another image is relying on this Storage for its data, then we must let it recover its + // data before we overwrite it. + ANGLE_TRY(storage11->releaseAssociatedImage(context, index, this)); } - ID3D11Resource *stagingTexture = NULL; + const TextureHelper11 *stagingTexture = nullptr; 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; - } + ANGLE_TRY(getStagingTexture(&stagingTexture, &stagingSubresourceIndex)); + ANGLE_TRY(storage11->updateSubresourceLevel(context, *stagingTexture, stagingSubresourceIndex, + index, region)); // 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; + mRecoverFromStorage = true; + mAssociatedStorage = storage11; mAssociatedImageIndex = index; } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -bool Image11::isAssociatedStorageValid(TextureStorage11* textureStorage) const +void Image11::verifyAssociatedStorageValid(TextureStorage11 *textureStorage) const { - return (mAssociatedStorage == textureStorage); + ASSERT(mAssociatedStorage == textureStorage); } -gl::Error Image11::recoverFromAssociatedStorage() +gl::Error Image11::recoverFromAssociatedStorage(const gl::Context *context) { if (mRecoverFromStorage) { - gl::Error error = createStagingTexture(); - if (error.isError()) - { - return error; - } - - bool textureStorageCorrect = mAssociatedStorage->isAssociatedImageValid(mAssociatedImageIndex, this); + ANGLE_TRY(createStagingTexture()); - // 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); + mAssociatedStorage->verifyAssociatedImageValid(mAssociatedImageIndex, this); - 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; - } + // CopySubResource from the Storage to the Staging texture + gl::Box region(0, 0, 0, mWidth, mHeight, mDepth); + ANGLE_TRY(mAssociatedStorage->copySubresourceLevel( + context, mStagingTexture, mStagingSubresource, mAssociatedImageIndex, region)); + mRecoveredFromStorageCount += 1; // Reset all the recovery parameters, even if the texture storage association is broken. disassociateStorage(); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } void Image11::disassociateStorage() @@ -194,17 +222,18 @@ void Image11::disassociateStorage() // Make the texturestorage release the Image11 too mAssociatedStorage->disassociateImage(mAssociatedImageIndex, this); - mRecoverFromStorage = false; - mAssociatedStorage = NULL; + mRecoverFromStorage = false; + mAssociatedStorage = nullptr; mAssociatedImageIndex = gl::ImageIndex::MakeInvalid(); } } -bool Image11::redefine(GLenum target, GLenum internalformat, const gl::Extents &size, bool forceRelease) +bool Image11::redefine(GLenum target, + GLenum internalformat, + const gl::Extents &size, + bool forceRelease) { - if (mWidth != size.width || - mHeight != size.height || - mInternalFormat != internalformat || + if (mWidth != size.width || mHeight != size.height || mInternalFormat != internalformat || forceRelease) { // End the association with the TextureStorage, since that data will be out of date. @@ -212,19 +241,20 @@ bool Image11::redefine(GLenum target, GLenum internalformat, const gl::Extents & disassociateStorage(); mRecoveredFromStorageCount = 0; - mWidth = size.width; - mHeight = size.height; - mDepth = size.depth; + mWidth = size.width; + mHeight = size.height; + mDepth = size.depth; mInternalFormat = internalformat; - mTarget = target; + mTarget = target; // compute the d3d format that will be used - const d3d11::TextureFormat &formatInfo = d3d11::GetTextureFormatInfo(internalformat, mRenderer->getRenderer11DeviceCaps()); + const d3d11::Format &formatInfo = + d3d11::Format::Get(internalformat, mRenderer->getRenderer11DeviceCaps()); mDXGIFormat = formatInfo.texFormat; mRenderable = (formatInfo.rtvFormat != DXGI_FORMAT_UNKNOWN); releaseStagingTexture(); - mDirty = (formatInfo.dataInitializerFunction != NULL); + mDirty = (formatInfo.dataInitializerFunction != nullptr); return true; } @@ -241,119 +271,125 @@ DXGI_FORMAT Image11::getDXGIFormat() const return mDXGIFormat; } -// Store the pixel rectangle designated by xoffset,yoffset,width,height with pixels stored as format/type at input +// 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) +gl::Error Image11::loadData(const gl::Context *context, + const gl::Box &area, + const gl::PixelUnpackState &unpack, + GLenum type, + const void *input, + bool applySkipImages) { - 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, unpack.imageHeight); - GLsizei inputSkipBytes = formatInfo.computeSkipPixels( - inputRowPitch, inputDepthPitch, unpack.skipImages, unpack.skipRows, unpack.skipPixels); - - const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(mDXGIFormat); - GLuint outputPixelSize = dxgiFormatInfo.pixelBytes; - - const d3d11::TextureFormat &d3dFormatInfo = d3d11::GetTextureFormatInfo(mInternalFormat, mRenderer->getRenderer11DeviceCaps()); - LoadImageFunction loadFunction = d3dFormatInfo.loadFunctions.at(type).loadFunction; + const gl::InternalFormat &formatInfo = gl::GetSizedInternalFormatInfo(mInternalFormat); + GLuint inputRowPitch = 0; + ANGLE_TRY_RESULT( + formatInfo.computeRowPitch(type, area.width, unpack.alignment, unpack.rowLength), + inputRowPitch); + GLuint inputDepthPitch = 0; + ANGLE_TRY_RESULT(formatInfo.computeDepthPitch(area.height, unpack.imageHeight, inputRowPitch), + inputDepthPitch); + GLuint inputSkipBytes = 0; + ANGLE_TRY_RESULT( + formatInfo.computeSkipBytes(inputRowPitch, inputDepthPitch, unpack, applySkipImages), + inputSkipBytes); + + const d3d11::DXGIFormatSize &dxgiFormatInfo = d3d11::GetDXGIFormatSizeInfo(mDXGIFormat); + GLuint outputPixelSize = dxgiFormatInfo.pixelBytes; + + const d3d11::Format &d3dFormatInfo = + d3d11::Format::Get(mInternalFormat, mRenderer->getRenderer11DeviceCaps()); + LoadImageFunction loadFunction = d3dFormatInfo.getLoadFunctions()(type).loadFunction; D3D11_MAPPED_SUBRESOURCE mappedImage; - gl::Error error = map(D3D11_MAP_WRITE, &mappedImage); - if (error.isError()) - { - return error; - } + ANGLE_TRY(map(context, D3D11_MAP_WRITE, &mappedImage)); - uint8_t *offsetMappedData = (reinterpret_cast(mappedImage.pData) + (area.y * mappedImage.RowPitch + area.x * outputPixelSize + area.z * mappedImage.DepthPitch)); + 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) + inputSkipBytes, inputRowPitch, inputDepthPitch, offsetMappedData, mappedImage.RowPitch, mappedImage.DepthPitch); unmap(); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error Image11::loadCompressedData(const gl::Box &area, const void *input) +gl::Error Image11::loadCompressedData(const gl::Context *context, + 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, 0); + const gl::InternalFormat &formatInfo = gl::GetSizedInternalFormatInfo(mInternalFormat); + GLsizei inputRowPitch = 0; + ANGLE_TRY_RESULT(formatInfo.computeRowPitch(GL_UNSIGNED_BYTE, area.width, 1, 0), inputRowPitch); + GLsizei inputDepthPitch = 0; + ANGLE_TRY_RESULT(formatInfo.computeDepthPitch(area.height, 0, inputRowPitch), inputDepthPitch); - const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(mDXGIFormat); - GLuint outputPixelSize = dxgiFormatInfo.pixelBytes; - GLuint outputBlockWidth = dxgiFormatInfo.blockWidth; - GLuint outputBlockHeight = dxgiFormatInfo.blockHeight; + const d3d11::DXGIFormatSize &dxgiFormatInfo = d3d11::GetDXGIFormatSizeInfo(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, mRenderer->getRenderer11DeviceCaps()); - LoadImageFunction loadFunction = d3dFormatInfo.loadFunctions.at(GL_UNSIGNED_BYTE).loadFunction; + const d3d11::Format &d3dFormatInfo = + d3d11::Format::Get(mInternalFormat, mRenderer->getRenderer11DeviceCaps()); + LoadImageFunction loadFunction = + d3dFormatInfo.getLoadFunctions()(GL_UNSIGNED_BYTE).loadFunction; D3D11_MAPPED_SUBRESOURCE mappedImage; - gl::Error error = map(D3D11_MAP_WRITE, &mappedImage); - if (error.isError()) - { - return error; - } + ANGLE_TRY(map(context, D3D11_MAP_WRITE, &mappedImage)); - uint8_t* offsetMappedData = reinterpret_cast(mappedImage.pData) + ((area.y / outputBlockHeight) * mappedImage.RowPitch + - (area.x / outputBlockWidth) * outputPixelSize + - area.z * mappedImage.DepthPitch); + 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); + loadFunction(area.width, area.height, area.depth, reinterpret_cast(input), + inputRowPitch, inputDepthPitch, offsetMappedData, mappedImage.RowPitch, + mappedImage.DepthPitch); unmap(); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error Image11::copyFromTexStorage(const gl::ImageIndex &imageIndex, TextureStorage *source) +gl::Error Image11::copyFromTexStorage(const gl::Context *context, + const gl::ImageIndex &imageIndex, + TextureStorage *source) { TextureStorage11 *storage11 = GetAs(source); - ID3D11Resource *resource = nullptr; - gl::Error error = storage11->getResource(&resource); - if (error.isError()) - { - return error; - } + const TextureHelper11 *textureHelper = nullptr; + ANGLE_TRY(storage11->getResource(context, &textureHelper)); - UINT subresourceIndex = storage11->getSubresourceIndex(imageIndex); - TextureHelper11 textureHelper = TextureHelper11::MakeAndReference(resource); + UINT subresourceIndex = storage11->getSubresourceIndex(imageIndex); gl::Box sourceBox(0, 0, 0, mWidth, mHeight, mDepth); - return copyWithoutConversion(gl::Offset(), sourceBox, textureHelper, subresourceIndex); + return copyWithoutConversion(gl::Offset(), sourceBox, *textureHelper, subresourceIndex); } -gl::Error Image11::copyFromFramebuffer(const gl::Offset &destOffset, +gl::Error Image11::copyFromFramebuffer(const gl::Context *context, + const gl::Offset &destOffset, const gl::Rectangle &sourceArea, const gl::Framebuffer *sourceFBO) { const gl::FramebufferAttachment *srcAttachment = sourceFBO->getReadColorbuffer(); ASSERT(srcAttachment); - const auto &d3d11Format = d3d11::GetTextureFormatInfo(srcAttachment->getInternalFormat(), - mRenderer->getRenderer11DeviceCaps()); + GLenum sourceInternalFormat = srcAttachment->getFormat().info->sizedInternalFormat; + const auto &d3d11Format = + d3d11::Format::Get(sourceInternalFormat, mRenderer->getRenderer11DeviceCaps()); - if (d3d11Format.texFormat == mDXGIFormat) + if (d3d11Format.texFormat == mDXGIFormat && sourceInternalFormat == mInternalFormat) { - RenderTargetD3D *renderTarget = nullptr; - gl::Error error = srcAttachment->getRenderTarget(&renderTarget); - if (error.isError()) - { - return error; - } - - RenderTarget11 *rt11 = GetAs(renderTarget); - ASSERT(rt11->getTexture()); + RenderTarget11 *rt11 = nullptr; + ANGLE_TRY(srcAttachment->getRenderTarget(context, &rt11)); + ASSERT(rt11->getTexture().get()); - TextureHelper11 textureHelper = TextureHelper11::MakeAndReference(rt11->getTexture()); + TextureHelper11 textureHelper = rt11->getTexture(); unsigned int sourceSubResource = rt11->getSubresourceIndex(); gl::Box sourceBox(sourceArea.x, sourceArea.y, 0, sourceArea.width, sourceArea.height, 1); @@ -363,25 +399,47 @@ gl::Error Image11::copyFromFramebuffer(const gl::Offset &destOffset, // 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; - } + ANGLE_TRY(map(context, D3D11_MAP_WRITE, &mappedImage)); // determine the offset coordinate into the destination buffer - const auto &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(mDXGIFormat); + const auto &dxgiFormatInfo = d3d11::GetDXGIFormatSizeInfo(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); + const gl::InternalFormat &destFormatInfo = gl::GetSizedInternalFormatInfo(mInternalFormat); + const auto &destD3D11Format = + d3d11::Format::Get(mInternalFormat, mRenderer->getRenderer11DeviceCaps()); + + auto loadFunction = destD3D11Format.getLoadFunctions()(destFormatInfo.type); + gl::Error error = gl::NoError(); + if (loadFunction.requiresConversion) + { + size_t bufferSize = destFormatInfo.pixelBytes * sourceArea.width * sourceArea.height; + angle::MemoryBuffer *memoryBuffer = nullptr; + error = mRenderer->getScratchMemoryBuffer(bufferSize, &memoryBuffer); + + if (!error.isError()) + { + GLuint memoryBufferRowPitch = destFormatInfo.pixelBytes * sourceArea.width; - error = mRenderer->readFromAttachment(*srcAttachment, sourceArea, formatInfo.format, - formatInfo.type, mappedImage.RowPitch, - gl::PixelPackState(), dataOffset); + error = mRenderer->readFromAttachment( + context, *srcAttachment, sourceArea, destFormatInfo.format, destFormatInfo.type, + memoryBufferRowPitch, gl::PixelPackState(), memoryBuffer->data()); + + loadFunction.loadFunction(sourceArea.width, sourceArea.height, 1, memoryBuffer->data(), + memoryBufferRowPitch, 0, dataOffset, mappedImage.RowPitch, + mappedImage.DepthPitch); + } + } + else + { + error = mRenderer->readFromAttachment( + context, *srcAttachment, sourceArea, destFormatInfo.format, destFormatInfo.type, + mappedImage.RowPitch, gl::PixelPackState(), dataOffset); + } unmap(); mDirty = true; @@ -395,26 +453,23 @@ gl::Error Image11::copyWithoutConversion(const gl::Offset &destOffset, UINT sourceSubResource) { // No conversion needed-- use copyback fastpath - ID3D11Resource *stagingTexture = nullptr; + const TextureHelper11 *stagingTexture = nullptr; unsigned int stagingSubresourceIndex = 0; - gl::Error error = getStagingTexture(&stagingTexture, &stagingSubresourceIndex); - if (error.isError()) - { - return error; - } + ANGLE_TRY(getStagingTexture(&stagingTexture, &stagingSubresourceIndex)); - ID3D11Device *device = mRenderer->getDevice(); ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); - UINT subresourceAfterResolve = sourceSubResource; - - ID3D11Resource *srcTex = nullptr; const gl::Extents &extents = textureHelper.getExtents(); - bool needResolve = - (textureHelper.getTextureType() == GL_TEXTURE_2D && textureHelper.getSampleCount() > 1); + 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; - if (needResolve) + if (textureHelper.is2D() && textureHelper.getSampleCount() > 1) { D3D11_TEXTURE2D_DESC resolveDesc; resolveDesc.Width = extents.width; @@ -429,80 +484,57 @@ gl::Error Image11::copyWithoutConversion(const gl::Offset &destOffset, 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; + d3d11::Texture2D resolveTex; + ANGLE_TRY(mRenderer->allocateResource(resolveDesc, &resolveTex)); - deviceContext->ResolveSubresource(srcTex, 0, textureHelper.getTexture2D(), + deviceContext->ResolveSubresource(resolveTex.get(), 0, textureHelper.get(), sourceSubResource, textureHelper.getFormat()); - subresourceAfterResolve = 0; + + deviceContext->CopySubresourceRegion(stagingTexture->get(), stagingSubresourceIndex, + destOffset.x, destOffset.y, destOffset.z, + resolveTex.get(), 0, &srcBox); } else { - srcTex = textureHelper.getResource(); - } - - 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); + deviceContext->CopySubresourceRegion(stagingTexture->get(), stagingSubresourceIndex, + destOffset.x, destOffset.y, destOffset.z, + textureHelper.get(), sourceSubResource, &srcBox); } mDirty = true; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error Image11::getStagingTexture(ID3D11Resource **outStagingTexture, unsigned int *outSubresourceIndex) +gl::Error Image11::getStagingTexture(const TextureHelper11 **outStagingTexture, + unsigned int *outSubresourceIndex) { - gl::Error error = createStagingTexture(); - if (error.isError()) - { - return error; - } + ANGLE_TRY(createStagingTexture()); - *outStagingTexture = mStagingTexture; + *outStagingTexture = &mStagingTexture; *outSubresourceIndex = mStagingSubresource; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } void Image11::releaseStagingTexture() { - SafeRelease(mStagingTexture); + mStagingTexture.reset(); } gl::Error Image11::createStagingTexture() { - if (mStagingTexture) + if (mStagingTexture.valid()) { - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } ASSERT(mWidth > 0 && mHeight > 0 && mDepth > 0); const DXGI_FORMAT dxgiFormat = getDXGIFormat(); + const auto &formatInfo = + d3d11::Format::Get(mInternalFormat, mRenderer->getRenderer11DeviceCaps()); - ID3D11Device *device = mRenderer->getDevice(); - HRESULT result; - - int lodOffset = 1; - GLsizei width = mWidth; + int lodOffset = 1; + GLsizei width = mWidth; GLsizei height = mHeight; // adjust size if needed for compressed textures @@ -510,80 +542,69 @@ gl::Error Image11::createStagingTexture() 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.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; + desc.MiscFlags = 0; - if (d3d11::GetTextureFormatInfo(mInternalFormat, mRenderer->getRenderer11DeviceCaps()).dataInitializerFunction != NULL) + if (formatInfo.dataInitializerFunction != nullptr) { std::vector initialData; std::vector> textureData; - d3d11::GenerateInitialTextureData(mInternalFormat, mRenderer->getRenderer11DeviceCaps(), width, height, mDepth, - lodOffset + 1, &initialData, &textureData); + d3d11::GenerateInitialTextureData(mInternalFormat, mRenderer->getRenderer11DeviceCaps(), + width, height, mDepth, lodOffset + 1, &initialData, + &textureData); - result = device->CreateTexture3D(&desc, initialData.data(), &newTexture); + ANGLE_TRY( + mRenderer->allocateTexture(desc, formatInfo, initialData.data(), &mStagingTexture)); } else { - result = device->CreateTexture3D(&desc, NULL, &newTexture); + ANGLE_TRY(mRenderer->allocateTexture(desc, formatInfo, &mStagingTexture)); } - 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; + mStagingTexture.setDebugName("Image11::StagingTexture3D"); mStagingSubresource = D3D11CalcSubresource(lodOffset, 0, lodOffset + 1); } - else if (mTarget == GL_TEXTURE_2D || mTarget == GL_TEXTURE_2D_ARRAY || mTarget == GL_TEXTURE_CUBE_MAP) + 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.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; + 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, mRenderer->getRenderer11DeviceCaps()).dataInitializerFunction != NULL) + if (formatInfo.dataInitializerFunction != nullptr) { std::vector initialData; std::vector> textureData; - d3d11::GenerateInitialTextureData(mInternalFormat, mRenderer->getRenderer11DeviceCaps(), width, height, 1, - lodOffset + 1, &initialData, &textureData); + d3d11::GenerateInitialTextureData(mInternalFormat, mRenderer->getRenderer11DeviceCaps(), + width, height, 1, lodOffset + 1, &initialData, + &textureData); - result = device->CreateTexture2D(&desc, initialData.data(), &newTexture); + ANGLE_TRY( + mRenderer->allocateTexture(desc, formatInfo, initialData.data(), &mStagingTexture)); } else { - result = device->CreateTexture2D(&desc, NULL, &newTexture); + ANGLE_TRY(mRenderer->allocateTexture(desc, formatInfo, &mStagingTexture)); } - 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; + mStagingTexture.setDebugName("Image11::StagingTexture2D"); mStagingSubresource = D3D11CalcSubresource(lodOffset, 0, lodOffset + 1); } else @@ -592,30 +613,22 @@ gl::Error Image11::createStagingTexture() } mDirty = false; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error Image11::map(D3D11_MAP mapType, D3D11_MAPPED_SUBRESOURCE *map) +gl::Error Image11::map(const gl::Context *context, 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; - } + ANGLE_TRY(recoverFromAssociatedStorage(context)); - ID3D11Resource *stagingTexture = NULL; - unsigned int subresourceIndex = 0; - error = getStagingTexture(&stagingTexture, &subresourceIndex); - if (error.isError()) - { - return error; - } + const TextureHelper11 *stagingTexture = nullptr; + unsigned int subresourceIndex = 0; + ANGLE_TRY(getStagingTexture(&stagingTexture, &subresourceIndex)); ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); - ASSERT(mStagingTexture); - HRESULT result = deviceContext->Map(stagingTexture, subresourceIndex, mapType, 0, map); + ASSERT(stagingTexture && stagingTexture->valid()); + HRESULT result = deviceContext->Map(stagingTexture->get(), subresourceIndex, mapType, 0, map); if (FAILED(result)) { @@ -624,20 +637,20 @@ gl::Error Image11::map(D3D11_MAP mapType, D3D11_MAPPED_SUBRESOURCE *map) { mRenderer->notifyDeviceLost(); } - return gl::Error(GL_OUT_OF_MEMORY, "Failed to map staging texture, result: 0x%X.", result); + return gl::OutOfMemory() << "Failed to map staging texture, " << gl::FmtHR(result); } mDirty = true; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } void Image11::unmap() { - if (mStagingTexture) + if (mStagingTexture.valid()) { ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); - deviceContext->Unmap(mStagingTexture, mStagingSubresource); + deviceContext->Unmap(mStagingTexture.get(), 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 index a5fcec84f8..584d231b37 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Image11.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Image11.h @@ -10,10 +10,10 @@ #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" +#include "libANGLE/ImageIndex.h" +#include "libANGLE/renderer/d3d/ImageD3D.h" +#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h" namespace gl { @@ -25,37 +25,63 @@ namespace rx class Renderer11; class TextureHelper11; class TextureStorage11; +struct Renderer11DeviceCaps; class Image11 : public ImageD3D { public: Image11(Renderer11 *renderer); - virtual ~Image11(); - - 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); + ~Image11() override; + + static gl::Error GenerateMipmap(const gl::Context *context, + Image11 *dest, + Image11 *src, + const Renderer11DeviceCaps &rendererCaps); + static gl::Error CopyImage(const gl::Context *context, + Image11 *dest, + Image11 *source, + const gl::Rectangle &sourceRect, + const gl::Offset &destOffset, + bool unpackFlipY, + bool unpackPremultiplyAlpha, + bool unpackUnmultiplyAlpha, + const Renderer11DeviceCaps &rendererCaps); + + bool isDirty() const override; + + gl::Error copyToStorage(const gl::Context *context, + TextureStorage *storage, + const gl::ImageIndex &index, + const gl::Box ®ion) override; 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); - - gl::Error copyFromTexStorage(const gl::ImageIndex &imageIndex, TextureStorage *source) override; - gl::Error copyFromFramebuffer(const gl::Offset &destOffset, + gl::Error loadData(const gl::Context *context, + const gl::Box &area, + const gl::PixelUnpackState &unpack, + GLenum type, + const void *input, + bool applySkipImages) override; + gl::Error loadCompressedData(const gl::Context *context, + const gl::Box &area, + const void *input) override; + + gl::Error copyFromTexStorage(const gl::Context *context, + const gl::ImageIndex &imageIndex, + TextureStorage *source) override; + gl::Error copyFromFramebuffer(const gl::Context *context, + const gl::Offset &destOffset, const gl::Rectangle &sourceArea, const gl::Framebuffer *source) override; - gl::Error recoverFromAssociatedStorage(); - bool isAssociatedStorageValid(TextureStorage11* textureStorage) const; + gl::Error recoverFromAssociatedStorage(const gl::Context *context); + void verifyAssociatedStorageValid(TextureStorage11 *textureStorage) const; void disassociateStorage(); protected: - gl::Error map(D3D11_MAP mapType, D3D11_MAPPED_SUBRESOURCE *map); + gl::Error map(const gl::Context *context, D3D11_MAP mapType, D3D11_MAPPED_SUBRESOURCE *map); void unmap(); private: @@ -64,14 +90,15 @@ class Image11 : public ImageD3D const TextureHelper11 &textureHelper, UINT sourceSubResource); - gl::Error getStagingTexture(ID3D11Resource **outStagingTexture, unsigned int *outSubresourceIndex); + gl::Error getStagingTexture(const TextureHelper11 **outStagingTexture, + unsigned int *outSubresourceIndex); gl::Error createStagingTexture(); void releaseStagingTexture(); Renderer11 *mRenderer; DXGI_FORMAT mDXGIFormat; - ID3D11Resource *mStagingTexture; + TextureHelper11 mStagingTexture; unsigned int mStagingSubresource; bool mRecoverFromStorage; diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/IndexBuffer11.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/IndexBuffer11.cpp index a5e78a245d..a79fb71f71 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/IndexBuffer11.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/IndexBuffer11.cpp @@ -14,28 +14,23 @@ namespace rx { -IndexBuffer11::IndexBuffer11(Renderer11 *const renderer) : mRenderer(renderer) +IndexBuffer11::IndexBuffer11(Renderer11 *const renderer) + : mRenderer(renderer), mBuffer(), mBufferSize(0), mIndexType(GL_NONE), mDynamicUsage(false) { - mBuffer = NULL; - mBufferSize = 0; - mDynamicUsage = false; } IndexBuffer11::~IndexBuffer11() { - SafeRelease(mBuffer); } gl::Error IndexBuffer11::initialize(unsigned int bufferSize, GLenum indexType, bool dynamic) { - SafeRelease(mBuffer); + mBuffer.reset(); updateSerial(); if (bufferSize > 0) { - ID3D11Device* dxDevice = mRenderer->getDevice(); - D3D11_BUFFER_DESC bufferDesc; bufferDesc.ByteWidth = bufferSize; bufferDesc.Usage = D3D11_USAGE_DYNAMIC; @@ -44,19 +39,15 @@ gl::Error IndexBuffer11::initialize(unsigned int bufferSize, GLenum indexType, b 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); - } + ANGLE_TRY(mRenderer->allocateResource(bufferDesc, &mBuffer)); if (dynamic) { - d3d11::SetDebugName(mBuffer, "IndexBuffer11 (dynamic)"); + mBuffer.setDebugName("IndexBuffer11 (dynamic)"); } else { - d3d11::SetDebugName(mBuffer, "IndexBuffer11 (static)"); + mBuffer.setDebugName("IndexBuffer11 (static)"); } } @@ -64,45 +55,46 @@ gl::Error IndexBuffer11::initialize(unsigned int bufferSize, GLenum indexType, b mIndexType = indexType; mDynamicUsage = dynamic; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } gl::Error IndexBuffer11::mapBuffer(unsigned int offset, unsigned int size, void** outMappedMemory) { - if (!mBuffer) + if (!mBuffer.valid()) { - return gl::Error(GL_OUT_OF_MEMORY, "Internal index buffer is not initialized."); + return gl::OutOfMemory() << "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."); + return gl::OutOfMemory() << "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); + HRESULT result = + dxContext->Map(mBuffer.get(), 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); + return gl::OutOfMemory() << "Failed to map internal index buffer, " << gl::FmtHR(result); } *outMappedMemory = reinterpret_cast(mappedResource.pData) + offset; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } gl::Error IndexBuffer11::unmapBuffer() { - if (!mBuffer) + if (!mBuffer.valid()) { - return gl::Error(GL_OUT_OF_MEMORY, "Internal index buffer is not initialized."); + return gl::OutOfMemory() << "Internal index buffer is not initialized."; } ID3D11DeviceContext *dxContext = mRenderer->getDeviceContext(); - dxContext->Unmap(mBuffer, 0); - return gl::Error(GL_NO_ERROR); + dxContext->Unmap(mBuffer.get(), 0); + return gl::NoError(); } GLenum IndexBuffer11::getIndexType() const @@ -123,29 +115,29 @@ gl::Error IndexBuffer11::setSize(unsigned int bufferSize, GLenum indexType) } else { - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } } gl::Error IndexBuffer11::discard() { - if (!mBuffer) + if (!mBuffer.valid()) { - return gl::Error(GL_OUT_OF_MEMORY, "Internal index buffer is not initialized."); + return gl::OutOfMemory() << "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); + HRESULT result = dxContext->Map(mBuffer.get(), 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); + return gl::OutOfMemory() << "Failed to map internal index buffer, " << gl::FmtHR(result); } - dxContext->Unmap(mBuffer, 0); + dxContext->Unmap(mBuffer.get(), 0); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } DXGI_FORMAT IndexBuffer11::getIndexFormat() const @@ -159,9 +151,9 @@ DXGI_FORMAT IndexBuffer11::getIndexFormat() const } } -ID3D11Buffer *IndexBuffer11::getBuffer() const +const d3d11::Buffer &IndexBuffer11::getBuffer() const { return mBuffer; } -} +} // namespace rx diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/IndexBuffer11.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/IndexBuffer11.h index e730377e00..7b5d744c02 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/IndexBuffer11.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/IndexBuffer11.h @@ -10,6 +10,7 @@ #define LIBANGLE_RENDERER_D3D_D3D11_INDEXBUFFER11_H_ #include "libANGLE/renderer/d3d/IndexBuffer.h" +#include "libANGLE/renderer/d3d/d3d11/ResourceManager11.h" namespace rx { @@ -19,31 +20,31 @@ class IndexBuffer11 : public IndexBuffer { public: explicit IndexBuffer11(Renderer11 *const renderer); - virtual ~IndexBuffer11(); + ~IndexBuffer11() override; - virtual gl::Error initialize(unsigned int bufferSize, GLenum indexType, bool dynamic); + gl::Error initialize(unsigned int bufferSize, GLenum indexType, bool dynamic) override; - virtual gl::Error mapBuffer(unsigned int offset, unsigned int size, void** outMappedMemory); - virtual gl::Error unmapBuffer(); + gl::Error mapBuffer(unsigned int offset, unsigned int size, void **outMappedMemory) override; + gl::Error unmapBuffer() override; - virtual GLenum getIndexType() const; - virtual unsigned int getBufferSize() const; - virtual gl::Error setSize(unsigned int bufferSize, GLenum indexType); + GLenum getIndexType() const override; + unsigned int getBufferSize() const override; + gl::Error setSize(unsigned int bufferSize, GLenum indexType) override; - virtual gl::Error discard(); + gl::Error discard() override; DXGI_FORMAT getIndexFormat() const; - ID3D11Buffer *getBuffer() const; + const d3d11::Buffer &getBuffer() const; private: Renderer11 *const mRenderer; - ID3D11Buffer *mBuffer; + d3d11::Buffer mBuffer; unsigned int mBufferSize; GLenum mIndexType; bool mDynamicUsage; }; -} +} // namespace rx #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 index 3a6d797ea6..a238f97b08 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/InputLayoutCache.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/InputLayoutCache.cpp @@ -9,17 +9,22 @@ #include "libANGLE/renderer/d3d/d3d11/InputLayoutCache.h" +#include "common/bitset_utils.h" #include "common/utilities.h" +#include "libANGLE/Context.h" #include "libANGLE/Program.h" +#include "libANGLE/VertexArray.h" #include "libANGLE/VertexAttribute.h" #include "libANGLE/renderer/d3d/IndexDataManager.h" #include "libANGLE/renderer/d3d/ProgramD3D.h" #include "libANGLE/renderer/d3d/VertexDataManager.h" #include "libANGLE/renderer/d3d/d3d11/Buffer11.h" +#include "libANGLE/renderer/d3d/d3d11/Context11.h" +#include "libANGLE/renderer/d3d/d3d11/Renderer11.h" #include "libANGLE/renderer/d3d/d3d11/ShaderExecutable11.h" +#include "libANGLE/renderer/d3d/d3d11/VertexArray11.h" #include "libANGLE/renderer/d3d/d3d11/VertexBuffer11.h" #include "libANGLE/renderer/d3d/d3d11/formatutils11.h" -#include "third_party/murmurhash/MurmurHash3.h" namespace rx { @@ -32,24 +37,7 @@ size_t GetReservedBufferCount(bool usesPointSpriteEmulation) return usesPointSpriteEmulation ? 1 : 0; } -gl::InputLayout GetInputLayout(const SortedAttribArray &translatedAttributes, size_t attributeCount) -{ - gl::InputLayout inputLayout(attributeCount, gl::VERTEX_FORMAT_INVALID); - - for (size_t attributeIndex = 0; attributeIndex < attributeCount; ++attributeIndex) - { - const TranslatedAttribute *translatedAttribute = translatedAttributes[attributeIndex]; - - if (translatedAttribute->active) - { - inputLayout[attributeIndex] = gl::GetVertexFormatType( - *translatedAttribute->attribute, translatedAttribute->currentValueType); - } - } - return inputLayout; -} - -GLenum GetGLSLAttributeType(const std::vector &shaderAttributes, int index) +GLenum GetGLSLAttributeType(const std::vector &shaderAttributes, size_t index) { // Count matrices differently for (const sh::Attribute &attrib : shaderAttributes) @@ -61,8 +49,9 @@ GLenum GetGLSLAttributeType(const std::vector &shaderAttributes, GLenum transposedType = gl::TransposeMatrixType(attrib.type); int rows = gl::VariableRowCount(transposedType); + int intIndex = static_cast(index); - if (index >= attrib.location && index < attrib.location + rows) + if (intIndex >= attrib.location && intIndex < attrib.location + rows) { return transposedType; } @@ -72,8 +61,6 @@ GLenum GetGLSLAttributeType(const std::vector &shaderAttributes, return GL_NONE; } -const unsigned int kDefaultCacheSize = 1024; - struct PackedAttribute { uint8_t attribType; @@ -82,26 +69,18 @@ struct PackedAttribute uint8_t divisor; }; -Optional FindFirstNonInstanced(const SortedAttribArray &sortedAttributes, size_t maxIndex) -{ - for (size_t index = 0; index < maxIndex; ++index) - { - if (sortedAttributes[index]->divisor == 0) - { - return Optional(index); - } - } +} // anonymous namespace - return Optional::Invalid(); +PackedAttributeLayout::PackedAttributeLayout() : numAttributes(0), flags(0), attributeData({}) +{ } -} // anonymous namespace +PackedAttributeLayout::PackedAttributeLayout(const PackedAttributeLayout &other) = default; -void InputLayoutCache::PackedAttributeLayout::addAttributeData( - GLenum glType, - UINT semanticIndex, - gl::VertexFormatType vertexFormatType, - unsigned int divisor) +void PackedAttributeLayout::addAttributeData(GLenum glType, + UINT semanticIndex, + gl::VertexFormatType vertexFormatType, + unsigned int divisor) { gl::AttributeType attribType = gl::GetAttributeType(glType); @@ -121,139 +100,58 @@ void InputLayoutCache::PackedAttributeLayout::addAttributeData( attributeData[numAttributes++] = gl::bitCast(packedAttrib); } -bool InputLayoutCache::PackedAttributeLayout::operator<(const PackedAttributeLayout &other) const +bool PackedAttributeLayout::operator==(const PackedAttributeLayout &other) const { - if (numAttributes != other.numAttributes) - { - return numAttributes < other.numAttributes; - } - - if (flags != other.flags) - { - return flags < other.flags; - } - - return memcmp(attributeData, other.attributeData, sizeof(uint32_t) * numAttributes) < 0; + return (numAttributes == other.numAttributes) && (flags == other.flags) && + (attributeData == other.attributeData); } -InputLayoutCache::InputLayoutCache() : mUnsortedAttributesCount(0), mCacheSize(kDefaultCacheSize) +InputLayoutCache::InputLayoutCache() + : mLayoutCache(kDefaultCacheSize * 2), mPointSpriteVertexBuffer(), mPointSpriteIndexBuffer() { - 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 (auto &layout : mLayoutMap) - { - SafeRelease(layout.second); - } - mLayoutMap.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); - } - mUnsortedAttributesCount = 0; + mLayoutCache.Clear(); + mPointSpriteVertexBuffer.reset(); + mPointSpriteIndexBuffer.reset(); } gl::Error InputLayoutCache::applyVertexBuffers( - const std::vector &unsortedAttributes, + const gl::Context *context, + const std::vector ¤tAttributes, GLenum mode, - gl::Program *program, - TranslatedIndexData *indexInfo, - GLsizei numIndicesPerInstance) + GLint start, + bool isIndexedRendering) { - ASSERT(mDevice && mDeviceContext); - + Renderer11 *renderer = GetImplAs(context)->getRenderer(); + const gl::State &state = context->getGLState(); + auto *stateManager = renderer->getStateManager(); + gl::Program *program = state.getProgram(); ProgramD3D *programD3D = GetImplAs(program); bool programUsesInstancedPointSprites = programD3D->usesPointSize() && programD3D->usesInstancedPointSpriteEmulation(); bool instancedPointSpritesActive = programUsesInstancedPointSprites && (mode == GL_POINTS); - SortedIndexArray sortedSemanticIndices; - mSortedAttributes.fill(nullptr); - mUnsortedAttributesCount = unsortedAttributes.size(); - - programD3D->sortAttributesByLayout(unsortedAttributes, sortedSemanticIndices.data(), - mSortedAttributes.data()); - - // If we are using FL 9_3, make sure the first attribute is not instanced - if (mFeatureLevel <= D3D_FEATURE_LEVEL_9_3 && !unsortedAttributes.empty()) - { - if (mSortedAttributes[0]->divisor > 0) - { - Optional firstNonInstancedIndex = - FindFirstNonInstanced(mSortedAttributes, unsortedAttributes.size()); - if (firstNonInstancedIndex.valid()) - { - size_t index = firstNonInstancedIndex.value(); - std::swap(mSortedAttributes[0], mSortedAttributes[index]); - std::swap(sortedSemanticIndices[0], sortedSemanticIndices[index]); - } - } - } - - gl::Error error = updateInputLayout(program, mode, mSortedAttributes, sortedSemanticIndices, - unsortedAttributes.size(), numIndicesPerInstance); - if (error.isError()) - { - return error; - } - - bool dirtyBuffers = false; - size_t minDiff = gl::MAX_VERTEX_ATTRIBS; - size_t maxDiff = 0; - // Note that if we use instance emulation, we reserve the first buffer slot. size_t reservedBuffers = GetReservedBufferCount(programUsesInstancedPointSprites); for (size_t attribIndex = 0; attribIndex < (gl::MAX_VERTEX_ATTRIBS - reservedBuffers); ++attribIndex) { - ID3D11Buffer *buffer = NULL; - UINT vertexStride = 0; - UINT vertexOffset = 0; + ID3D11Buffer *buffer = nullptr; + UINT vertexStride = 0; + UINT vertexOffset = 0; - const auto &attrib = *mSortedAttributes[attribIndex]; - - if (attribIndex < unsortedAttributes.size() && attrib.active) + if (attribIndex < currentAttributes.size()) { - VertexBuffer11 *vertexBuffer = GetAs(attrib.vertexBuffer); - Buffer11 *bufferStorage = attrib.storage ? GetAs(attrib.storage) : nullptr; + const auto &attrib = *currentAttributes[attribIndex]; + Buffer11 *bufferStorage = attrib.storage ? GetAs(attrib.storage) : nullptr; // If indexed pointsprite emulation is active, then we need to take a less efficent code path. // Emulated indexed pointsprite rendering requires that the vertex buffers match exactly to @@ -261,18 +159,18 @@ gl::Error InputLayoutCache::applyVertexBuffers( // on the number of points indicated by the index list or how many duplicates are found on the index list. if (bufferStorage == nullptr) { - buffer = vertexBuffer->getBuffer(); + ASSERT(attrib.vertexBuffer.get()); + buffer = GetAs(attrib.vertexBuffer.get())->getBuffer().get(); } - else if (instancedPointSpritesActive && (indexInfo != nullptr)) + else if (instancedPointSpritesActive && isIndexedRendering) { + VertexArray11 *vao11 = GetImplAs(state.getVertexArray()); + ASSERT(vao11->isCachedIndexInfoValid()); + TranslatedIndexData *indexInfo = vao11->getCachedIndexInfo(); if (indexInfo->srcIndexData.srcBuffer != nullptr) { const uint8_t *bufferData = nullptr; - error = indexInfo->srcIndexData.srcBuffer->getData(&bufferData); - if (error.isError()) - { - return error; - } + ANGLE_TRY(indexInfo->srcIndexData.srcBuffer->getData(context, &bufferData)); ASSERT(bufferData != nullptr); ptrdiff_t offset = @@ -281,31 +179,24 @@ gl::Error InputLayoutCache::applyVertexBuffers( indexInfo->srcIndexData.srcIndices = bufferData + offset; } - buffer = bufferStorage->getEmulatedIndexedBuffer(&indexInfo->srcIndexData, &attrib); + ANGLE_TRY_RESULT(bufferStorage->getEmulatedIndexedBuffer( + context, &indexInfo->srcIndexData, attrib, start), + buffer); } else { - buffer = bufferStorage->getBuffer(BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK); + ANGLE_TRY_RESULT( + bufferStorage->getBuffer(context, BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK), + buffer); } vertexStride = attrib.stride; - vertexOffset = attrib.offset; + ANGLE_TRY_RESULT(attrib.computeOffset(start), vertexOffset); } size_t bufferIndex = reservedBuffers + attribIndex; - if (buffer != mCurrentBuffers[bufferIndex] || - vertexStride != mCurrentVertexStrides[bufferIndex] || - vertexOffset != mCurrentVertexOffsets[bufferIndex]) - { - dirtyBuffers = true; - minDiff = std::min(minDiff, bufferIndex); - maxDiff = std::max(maxDiff, bufferIndex); - - mCurrentBuffers[bufferIndex] = buffer; - mCurrentVertexStrides[bufferIndex] = vertexStride; - mCurrentVertexOffsets[bufferIndex] = vertexOffset; - } + stateManager->queueVertexBufferChange(bufferIndex, buffer, vertexStride, vertexOffset); } // Instanced PointSprite emulation requires two additional ID3D11Buffers. A vertex buffer needs @@ -317,10 +208,9 @@ gl::Error InputLayoutCache::applyVertexBuffers( // handle missing vertex data and will TDR the system. if (programUsesInstancedPointSprites) { - HRESULT result = S_OK; const UINT pointSpriteVertexStride = sizeof(float) * 5; - if (!mPointSpriteVertexBuffer) + if (!mPointSpriteVertexBuffer.valid()) { static const float pointSpriteVertices[] = { @@ -342,25 +232,16 @@ gl::Error InputLayoutCache::applyVertexBuffers( 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); - } + ANGLE_TRY(renderer->allocateResource(vertexBufferDesc, &vertexBufferData, + &mPointSpriteVertexBuffer)); } - mCurrentBuffers[0] = mPointSpriteVertexBuffer; // Set the stride to 0 if GL_POINTS mode is not being used to instruct the driver to avoid // indexing into the vertex buffer. - mCurrentVertexStrides[0] = instancedPointSpritesActive ? pointSpriteVertexStride : 0; - mCurrentVertexOffsets[0] = 0; - - // Update maxDiff to include the additional point sprite vertex buffer - // to ensure that IASetVertexBuffers uses the correct buffer count. - minDiff = 0; - maxDiff = std::max(maxDiff, static_cast(0)); + UINT stride = instancedPointSpritesActive ? pointSpriteVertexStride : 0; + stateManager->queueVertexBufferChange(0, mPointSpriteVertexBuffer.get(), stride, 0); - if (!mPointSpriteIndexBuffer) + if (!mPointSpriteIndexBuffer.valid()) { // Create an index buffer and set it for pointsprite rendering static const unsigned short pointSpriteIndices[] = @@ -377,12 +258,8 @@ gl::Error InputLayoutCache::applyVertexBuffers( 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); - } + ANGLE_TRY(renderer->allocateResource(indexBufferDesc, &indexBufferData, + &mPointSpriteIndexBuffer)); } if (instancedPointSpritesActive) @@ -391,51 +268,51 @@ gl::Error InputLayoutCache::applyVertexBuffers( // 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); + stateManager->setIndexBuffer(mPointSpriteIndexBuffer.get(), DXGI_FORMAT_R16_UINT, 0); } } - if (dirtyBuffers) - { - ASSERT(minDiff <= maxDiff && maxDiff < gl::MAX_VERTEX_ATTRIBS); - mDeviceContext->IASetVertexBuffers( - static_cast(minDiff), static_cast(maxDiff - minDiff + 1), - mCurrentBuffers + minDiff, mCurrentVertexStrides + minDiff, - mCurrentVertexOffsets + minDiff); - } - - return gl::Error(GL_NO_ERROR); + stateManager->applyVertexBufferChanges(); + return gl::NoError(); } -gl::Error InputLayoutCache::updateVertexOffsetsForPointSpritesEmulation(GLsizei emulatedInstanceId) +gl::Error InputLayoutCache::updateVertexOffsetsForPointSpritesEmulation( + Renderer11 *renderer, + const std::vector ¤tAttributes, + GLint startVertex, + GLsizei emulatedInstanceId) { + auto *stateManager = renderer->getStateManager(); + size_t reservedBuffers = GetReservedBufferCount(true); - for (size_t attribIndex = 0; attribIndex < mUnsortedAttributesCount; ++attribIndex) + for (size_t attribIndex = 0; attribIndex < currentAttributes.size(); ++attribIndex) { - const auto &attrib = *mSortedAttributes[attribIndex]; + const auto &attrib = *currentAttributes[attribIndex]; size_t bufferIndex = reservedBuffers + attribIndex; - if (attrib.active && attrib.divisor > 0) + if (attrib.divisor > 0) { - mCurrentVertexOffsets[bufferIndex] = - attrib.offset + (attrib.stride * (emulatedInstanceId / attrib.divisor)); + unsigned int offset = 0; + ANGLE_TRY_RESULT(attrib.computeOffset(startVertex), offset); + offset += (attrib.stride * (emulatedInstanceId / attrib.divisor)); + stateManager->queueVertexOffsetChange(bufferIndex, offset); } } - mDeviceContext->IASetVertexBuffers(0, gl::MAX_VERTEX_ATTRIBS, mCurrentBuffers, - mCurrentVertexStrides, mCurrentVertexOffsets); - - return gl::Error(GL_NO_ERROR); + stateManager->applyVertexBufferChanges(); + return gl::NoError(); } -gl::Error InputLayoutCache::updateInputLayout(gl::Program *program, - GLenum mode, - const SortedAttribArray &sortedAttributes, - const SortedIndexArray &sortedSemanticIndices, - size_t attribCount, - GLsizei numIndicesPerInstance) +gl::Error InputLayoutCache::updateInputLayout( + Renderer11 *renderer, + const gl::State &state, + const std::vector ¤tAttributes, + GLenum mode, + const AttribIndexArray &sortedSemanticIndices, + const DrawCallVertexParams &vertexParams) { - const std::vector &shaderAttributes = program->getAttributes(); + gl::Program *program = state.getProgram(); + const auto &shaderAttributes = program->getAttributes(); PackedAttributeLayout layout; ProgramD3D *programD3D = GetImplAs(program); @@ -453,90 +330,70 @@ gl::Error InputLayoutCache::updateInputLayout(gl::Program *program, layout.flags |= PackedAttributeLayout::FLAG_INSTANCED_SPRITES_ACTIVE; } - if (numIndicesPerInstance > 0) + if (vertexParams.instances() > 0) { layout.flags |= PackedAttributeLayout::FLAG_INSTANCED_RENDERING_ACTIVE; } - const auto &semanticToLocation = programD3D->getAttributesByLayout(); + const auto &attribs = state.getVertexArray()->getVertexAttributes(); + const auto &bindings = state.getVertexArray()->getVertexBindings(); + const auto &locationToSemantic = programD3D->getAttribLocationToD3DSemantics(); + int divisorMultiplier = program->usesMultiview() ? program->getNumViews() : 1; - for (size_t attribIndex = 0; attribIndex < attribCount; ++attribIndex) + for (size_t attribIndex : program->getActiveAttribLocationsMask()) { - const auto &attrib = *sortedAttributes[attribIndex]; - int sortedIndex = sortedSemanticIndices[attribIndex]; - - if (!attrib.active) - continue; - - gl::VertexFormatType vertexFormatType = - gl::GetVertexFormatType(*attrib.attribute, attrib.currentValueType); - // Record the type of the associated vertex shader vector in our key // This will prevent mismatched vertex shaders from using the same input layout - GLenum glslElementType = - GetGLSLAttributeType(shaderAttributes, semanticToLocation[sortedIndex]); + GLenum glslElementType = GetGLSLAttributeType(shaderAttributes, attribIndex); - layout.addAttributeData(glslElementType, sortedIndex, vertexFormatType, attrib.divisor); + const auto &attrib = attribs[attribIndex]; + const auto &binding = bindings[attrib.bindingIndex]; + int d3dSemantic = locationToSemantic[attribIndex]; + + const auto ¤tValue = + state.getVertexAttribCurrentValue(static_cast(attribIndex)); + gl::VertexFormatType vertexFormatType = gl::GetVertexFormatType(attrib, currentValue.Type); + + layout.addAttributeData(glslElementType, d3dSemantic, vertexFormatType, + binding.getDivisor() * divisorMultiplier); } - ID3D11InputLayout *inputLayout = nullptr; + const d3d11::InputLayout *inputLayout = nullptr; if (layout.numAttributes > 0 || layout.flags != 0) { - auto layoutMapIt = mLayoutMap.find(layout); - if (layoutMapIt != mLayoutMap.end()) + auto it = mLayoutCache.Get(layout); + if (it != mLayoutCache.end()) { - inputLayout = layoutMapIt->second; + inputLayout = &it->second; } else { - gl::Error error = - createInputLayout(sortedAttributes, sortedSemanticIndices, attribCount, mode, - program, numIndicesPerInstance, &inputLayout); - if (error.isError()) - { - return error; - } - if (mLayoutMap.size() >= mCacheSize) - { - TRACE("Overflowed the limit of %u input layouts, purging half the cache.", - mCacheSize); + angle::TrimCache(mLayoutCache.max_size() / 2, kGCLimit, "input layout", &mLayoutCache); - // Randomly release every second element - auto it = mLayoutMap.begin(); - while (it != mLayoutMap.end()) - { - it++; - if (it != mLayoutMap.end()) - { - // c++11 erase allows us to easily delete the current iterator. - SafeRelease(it->second); - it = mLayoutMap.erase(it); - } - } - } + d3d11::InputLayout newInputLayout; + ANGLE_TRY(createInputLayout(renderer, sortedSemanticIndices, currentAttributes, mode, + program, vertexParams, &newInputLayout)); - mLayoutMap[layout] = inputLayout; + auto insertIt = mLayoutCache.Put(layout, std::move(newInputLayout)); + inputLayout = &insertIt->second; } } - if (inputLayout != mCurrentIL) - { - mDeviceContext->IASetInputLayout(inputLayout); - mCurrentIL = inputLayout; - } - - return gl::Error(GL_NO_ERROR); + renderer->getStateManager()->setInputLayout(inputLayout); + return gl::NoError(); } -gl::Error InputLayoutCache::createInputLayout(const SortedAttribArray &sortedAttributes, - const SortedIndexArray &sortedSemanticIndices, - size_t attribCount, - GLenum mode, - gl::Program *program, - GLsizei numIndicesPerInstance, - ID3D11InputLayout **inputLayoutOut) +gl::Error InputLayoutCache::createInputLayout( + Renderer11 *renderer, + const AttribIndexArray &sortedSemanticIndices, + const std::vector ¤tAttributes, + GLenum mode, + gl::Program *program, + const DrawCallVertexParams &vertexParams, + d3d11::InputLayout *inputLayoutOut) { ProgramD3D *programD3D = GetImplAs(program); + auto featureLevel = renderer->getRenderer11DeviceCaps().featureLevel; bool programUsesInstancedPointSprites = programD3D->usesPointSize() && programD3D->usesInstancedPointSpriteEmulation(); @@ -544,20 +401,17 @@ gl::Error InputLayoutCache::createInputLayout(const SortedAttribArray &sortedAtt unsigned int inputElementCount = 0; std::array inputElements; - for (size_t attribIndex = 0; attribIndex < attribCount; ++attribIndex) + for (size_t attribIndex = 0; attribIndex < currentAttributes.size(); ++attribIndex) { - const auto &attrib = *sortedAttributes[attribIndex]; + const auto &attrib = *currentAttributes[attribIndex]; const int sortedIndex = sortedSemanticIndices[attribIndex]; - if (!attrib.active) - continue; - D3D11_INPUT_CLASSIFICATION inputClass = attrib.divisor > 0 ? D3D11_INPUT_PER_INSTANCE_DATA : D3D11_INPUT_PER_VERTEX_DATA; const auto &vertexFormatType = gl::GetVertexFormatType(*attrib.attribute, attrib.currentValueType); - const auto &vertexFormatInfo = d3d11::GetVertexFormatInfo(vertexFormatType, mFeatureLevel); + const auto &vertexFormatInfo = d3d11::GetVertexFormatInfo(vertexFormatType, featureLevel); auto *inputElement = &inputElements[inputElementCount]; @@ -584,23 +438,28 @@ gl::Error InputLayoutCache::createInputLayout(const SortedAttribArray &sortedAtt // 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. + + GLsizei numIndicesPerInstance = 0; + if (vertexParams.instances() > 0) + { + // This may trigger an evaluation of the index range. + numIndicesPerInstance = vertexParams.vertexCount(); + } + for (size_t elementIndex = 0; elementIndex < inputElementCount; ++elementIndex) { - if (sortedAttributes[elementIndex]->active) + // If rendering points and instanced pointsprite emulation is being used, the + // inputClass is required to be configured as per instance data + if (mode == GL_POINTS) { - // If rendering points and instanced pointsprite emulation is being used, the - // inputClass is required to be configured as per instance data - if (mode == GL_POINTS) + inputElements[elementIndex].InputSlotClass = D3D11_INPUT_PER_INSTANCE_DATA; + inputElements[elementIndex].InstanceDataStepRate = 1; + if (numIndicesPerInstance > 0 && currentAttributes[elementIndex]->divisor > 0) { - inputElements[elementIndex].InputSlotClass = D3D11_INPUT_PER_INSTANCE_DATA; - inputElements[elementIndex].InstanceDataStepRate = 1; - if (numIndicesPerInstance > 0 && sortedAttributes[elementIndex]->divisor > 0) - { - inputElements[elementIndex].InstanceDataStepRate = numIndicesPerInstance; - } + inputElements[elementIndex].InstanceDataStepRate = numIndicesPerInstance; } - inputElements[elementIndex].InputSlot++; } + inputElements[elementIndex].InputSlot++; } inputElements[inputElementCount].SemanticName = "SPRITEPOSITION"; @@ -622,28 +481,23 @@ gl::Error InputLayoutCache::createInputLayout(const SortedAttribArray &sortedAtt inputElementCount++; } - const gl::InputLayout &shaderInputLayout = GetInputLayout(sortedAttributes, attribCount); - ShaderExecutableD3D *shader = nullptr; - gl::Error error = - programD3D->getVertexExecutableForInputLayout(shaderInputLayout, &shader, nullptr); - if (error.isError()) - { - return error; - } + ANGLE_TRY(programD3D->getVertexExecutableForCachedInputLayout(&shader, nullptr)); ShaderExecutableD3D *shader11 = GetAs(shader); - HRESULT result = - mDevice->CreateInputLayout(inputElements.data(), inputElementCount, shader11->getFunction(), - shader11->getLength(), inputLayoutOut); - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, - "Failed to create internal input layout, HRESULT: 0x%08x", result); - } + InputElementArray inputElementArray(inputElements.data(), inputElementCount); + ShaderData vertexShaderData(shader11->getFunction(), shader11->getLength()); - return gl::Error(GL_NO_ERROR); + ANGLE_TRY(renderer->allocateResource(inputElementArray, &vertexShaderData, inputLayoutOut)); + return gl::NoError(); +} + +void InputLayoutCache::setCacheSize(size_t newCacheSize) +{ + // Forces a reset of the cache. + LayoutCache newCache(newCacheSize); + mLayoutCache.Swap(newCache); } } // namespace rx diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/InputLayoutCache.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/InputLayoutCache.h index e208ae3c64..8d7c7dd0f0 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/InputLayoutCache.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/InputLayoutCache.h @@ -20,12 +20,55 @@ #include "common/angleutils.h" #include "libANGLE/Constants.h" #include "libANGLE/Error.h" +#include "libANGLE/SizedMRUCache.h" #include "libANGLE/formatutils.h" +#include "libANGLE/renderer/d3d/RendererD3D.h" +#include "libANGLE/renderer/d3d/d3d11/ResourceManager11.h" + +namespace rx +{ +class DrawCallVertexParams; +struct PackedAttributeLayout +{ + PackedAttributeLayout(); + PackedAttributeLayout(const PackedAttributeLayout &other); + + void addAttributeData(GLenum glType, + UINT semanticIndex, + gl::VertexFormatType vertexFormatType, + unsigned int divisor); + + bool operator==(const PackedAttributeLayout &other) const; + + enum Flags + { + FLAG_USES_INSTANCED_SPRITES = 0x1, + FLAG_INSTANCED_SPRITES_ACTIVE = 0x2, + FLAG_INSTANCED_RENDERING_ACTIVE = 0x4, + }; + + uint32_t numAttributes; + uint32_t flags; + std::array attributeData; +}; +} // namespace rx + +namespace std +{ +template <> +struct hash +{ + size_t operator()(const rx::PackedAttributeLayout &value) const + { + return angle::ComputeGenericHash(value); + } +}; +} // namespace std namespace gl { class Program; -} +} // namespace gl namespace rx { @@ -33,91 +76,58 @@ struct TranslatedAttribute; struct TranslatedIndexData; struct SourceIndexData; class ProgramD3D; - -using SortedAttribArray = std::array; -using SortedIndexArray = std::array; +class Renderer11; class InputLayoutCache : angle::NonCopyable { public: InputLayoutCache(); - virtual ~InputLayoutCache(); + ~InputLayoutCache(); - void initialize(ID3D11Device *device, ID3D11DeviceContext *context); void clear(); - void markDirty(); - gl::Error applyVertexBuffers(const std::vector &attributes, + gl::Error applyVertexBuffers(const gl::Context *context, + const std::vector ¤tAttributes, GLenum mode, - gl::Program *program, - TranslatedIndexData *indexInfo, - GLsizei numIndicesPerInstance); + GLint start, + bool isIndexedRendering); - gl::Error updateVertexOffsetsForPointSpritesEmulation(GLsizei emulatedInstanceId); + gl::Error updateVertexOffsetsForPointSpritesEmulation( + Renderer11 *renderer, + const std::vector ¤tAttributes, + GLint startVertex, + GLsizei emulatedInstanceId); // Useful for testing - void setCacheSize(unsigned int cacheSize) { mCacheSize = cacheSize; } - - private: - struct PackedAttributeLayout - { - PackedAttributeLayout() - : numAttributes(0), - flags(0) - { - } - - void addAttributeData(GLenum glType, - UINT semanticIndex, - gl::VertexFormatType vertexFormatType, - unsigned int divisor); - - bool operator<(const PackedAttributeLayout &other) const; - - enum Flags - { - FLAG_USES_INSTANCED_SPRITES = 0x1, - FLAG_INSTANCED_SPRITES_ACTIVE = 0x2, - FLAG_INSTANCED_RENDERING_ACTIVE = 0x4, - }; - - size_t numAttributes; - unsigned int flags; - uint32_t attributeData[gl::MAX_VERTEX_ATTRIBS]; - }; + void setCacheSize(size_t newCacheSize); - gl::Error updateInputLayout(gl::Program *program, + gl::Error updateInputLayout(Renderer11 *renderer, + const gl::State &state, + const std::vector ¤tAttributes, GLenum mode, - const SortedAttribArray &sortedAttributes, - const SortedIndexArray &sortedSemanticIndices, - size_t attribCount, - GLsizei numIndicesPerInstance); - gl::Error createInputLayout(const SortedAttribArray &sortedAttributes, - const SortedIndexArray &sortedSemanticIndices, - size_t attribCount, + const AttribIndexArray &sortedSemanticIndices, + const DrawCallVertexParams &vertexParams); + + private: + gl::Error createInputLayout(Renderer11 *renderer, + const AttribIndexArray &sortedSemanticIndices, + const std::vector ¤tAttributes, GLenum mode, gl::Program *program, - GLsizei numIndicesPerInstance, - ID3D11InputLayout **inputLayoutOut); - - std::map mLayoutMap; + const DrawCallVertexParams &vertexParams, + d3d11::InputLayout *inputLayoutOut); - ID3D11InputLayout *mCurrentIL; - ID3D11Buffer *mCurrentBuffers[gl::MAX_VERTEX_ATTRIBS]; - UINT mCurrentVertexStrides[gl::MAX_VERTEX_ATTRIBS]; - UINT mCurrentVertexOffsets[gl::MAX_VERTEX_ATTRIBS]; - SortedAttribArray mSortedAttributes; - size_t mUnsortedAttributesCount; + // Starting cache size. + static constexpr size_t kDefaultCacheSize = 1024; - ID3D11Buffer *mPointSpriteVertexBuffer; - ID3D11Buffer *mPointSpriteIndexBuffer; + // The cache tries to clean up this many states at once. + static constexpr size_t kGCLimit = 128; - unsigned int mCacheSize; - unsigned long long mCounter; + using LayoutCache = angle::base::HashingMRUCache; + LayoutCache mLayoutCache; - ID3D11Device *mDevice; - ID3D11DeviceContext *mDeviceContext; - D3D_FEATURE_LEVEL mFeatureLevel; + d3d11::Buffer mPointSpriteVertexBuffer; + d3d11::Buffer mPointSpriteIndexBuffer; }; } // namespace rx diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/NativeWindow.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/NativeWindow.h deleted file mode 100644 index 612b06bb10..0000000000 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/NativeWindow.h +++ /dev/null @@ -1,97 +0,0 @@ -// -// 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 -#include "libANGLE/Config.h" - -// 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; - -#elif defined(ANGLE_ENABLE_D3D11) -typedef IDXGISwapChain DXGISwapChain; -typedef IDXGIFactory DXGIFactory; -#endif - -typedef interface IDCompositionDevice IDCompositionDevice; -typedef interface IDCompositionTarget IDCompositionTarget; -typedef interface IDCompositionVisual IDCompositionVisual; - -namespace rx -{ - -class NativeWindow -{ - public: - enum RotationFlags { RotateNone = 0, RotateLeft = 1, RotateRight = 2 }; - explicit NativeWindow(EGLNativeWindowType window, - const egl::Config *config, - bool directComposition); - - ~NativeWindow(); - 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); - -#if defined(ANGLE_ENABLE_D3D11) - HRESULT createSwapChain(ID3D11Device* device, DXGIFactory* factory, - DXGI_FORMAT format, UINT width, UINT height, - DXGISwapChain** swapChain); -#endif - - inline EGLNativeWindowType getNativeWindow() const { return mWindow; } - - void commitChange(); - - private: - EGLNativeWindowType mWindow; - - bool mDirectComposition; - IDCompositionDevice *mDevice; - IDCompositionTarget *mCompositionTarget; - IDCompositionVisual *mVisual; - const egl::Config *mConfig; -#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/NativeWindow11.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/NativeWindow11.h new file mode 100644 index 0000000000..ab234d4450 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/NativeWindow11.h @@ -0,0 +1,38 @@ +// +// Copyright (c) 2016 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. +// + +// NativeWindow11.h: Defines NativeWindow11, a class for managing and performing operations on an +// EGLNativeWindowType for the D3D11 renderer. + +#ifndef LIBANGLE_RENDERER_D3D_D3D11_NATIVEWINDOW11_H_ +#define LIBANGLE_RENDERER_D3D_D3D11_NATIVEWINDOW11_H_ + +#include "common/debug.h" +#include "common/platform.h" + +#include "libANGLE/Config.h" +#include "libANGLE/renderer/d3d/NativeWindowD3D.h" + +namespace rx +{ + +class NativeWindow11 : public NativeWindowD3D +{ + public: + NativeWindow11(EGLNativeWindowType window) : NativeWindowD3D(window) {} + + virtual HRESULT createSwapChain(ID3D11Device *device, + IDXGIFactory *factory, + DXGI_FORMAT format, + UINT width, + UINT height, + UINT samples, + IDXGISwapChain **swapChain) = 0; + virtual void commitChange() = 0; +}; +} // namespace rx + +#endif // LIBANGLE_RENDERER_D3D_D3D11_NATIVEWINDOW11_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 index dfc521f14f..7d7ecb0976 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/PixelTransfer11.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/PixelTransfer11.cpp @@ -36,40 +36,25 @@ namespace rx PixelTransfer11::PixelTransfer11(Renderer11 *renderer) : mRenderer(renderer), mResourcesLoaded(false), - mBufferToTextureVS(NULL), - mBufferToTextureGS(NULL), - mParamsConstantBuffer(NULL), - mCopyRasterizerState(NULL), - mCopyDepthStencilState(NULL) + mBufferToTextureVS(), + mBufferToTextureGS(), + mParamsConstantBuffer(), + mCopyRasterizerState(), + mCopyDepthStencilState() { } 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); + return gl::NoError(); } - HRESULT result = S_OK; - ID3D11Device *device = mRenderer->getDevice(); - D3D11_RASTERIZER_DESC rasterDesc; rasterDesc.FillMode = D3D11_FILL_SOLID; rasterDesc.CullMode = D3D11_CULL_NONE; @@ -82,12 +67,7 @@ gl::Error PixelTransfer11::loadResources() 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); - } + ANGLE_TRY(mRenderer->allocateResource(rasterDesc, &mCopyRasterizerState)); D3D11_DEPTH_STENCIL_DESC depthStencilDesc; depthStencilDesc.DepthEnable = true; @@ -105,12 +85,7 @@ gl::Error PixelTransfer11::loadResources() 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); - } + ANGLE_TRY(mRenderer->allocateResource(depthStencilDesc, &mCopyDepthStencilState)); D3D11_BUFFER_DESC constantBufferDesc = { 0 }; constantBufferDesc.ByteWidth = roundUp(sizeof(CopyShaderParams), 32u); @@ -120,38 +95,23 @@ gl::Error PixelTransfer11::loadResources() 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"); + ANGLE_TRY(mRenderer->allocateResource(constantBufferDesc, &mParamsConstantBuffer)); + mParamsConstantBuffer.setDebugName("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."); - } + ANGLE_TRY(mRenderer->allocateResource(ShaderData(g_VS_BufferToTexture), &mBufferToTextureVS)); + mBufferToTextureVS.setDebugName("BufferToTexture VS"); - 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."); - } + ANGLE_TRY(mRenderer->allocateResource(ShaderData(g_GS_BufferToTexture), &mBufferToTextureGS)); + mBufferToTextureGS.setDebugName("BufferToTexture GS"); - gl::Error error = buildShaderMap(); - if (error.isError()) - { - return error; - } + ANGLE_TRY(buildShaderMap()); StructZero(&mParamsData); mResourcesLoaded = true; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } void PixelTransfer11::setBufferToTextureCopyParams(const gl::Box &destArea, const gl::Extents &destSize, GLenum internalFormat, @@ -162,7 +122,7 @@ void PixelTransfer11::setBufferToTextureCopyParams(const gl::Box &destArea, cons 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 bytesPerPixel = gl::GetSizedInternalFormatInfo(internalFormat).pixelBytes; unsigned int alignmentBytes = static_cast(unpack.alignment); unsigned int alignmentPixels = (alignmentBytes <= bytesPerPixel ? 1 : alignmentBytes / bytesPerPixel); @@ -177,14 +137,15 @@ void PixelTransfer11::setBufferToTextureCopyParams(const gl::Box &destArea, cons 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 PixelTransfer11::copyBufferToTexture(const gl::Context *context, + 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; - } + ANGLE_TRY(loadResources()); gl::Extents destSize = destRenderTarget->getExtents(); @@ -192,114 +153,106 @@ gl::Error PixelTransfer11::copyBufferToTexture(const gl::PixelUnpackState &unpac 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(); + const gl::Buffer &sourceBuffer = + *context->getGLState().getTargetBuffer(gl::BufferBinding::PixelUnpack); ASSERT(mRenderer->supportsFastCopyBufferToTexture(destinationFormat)); - ID3D11PixelShader *pixelShader = findBufferToTexturePS(destinationFormat); + const d3d11::PixelShader *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); + GLenum unsizedFormat = gl::GetUnsizedFormat(destinationFormat); + const gl::InternalFormat &sourceglFormatInfo = + gl::GetInternalFormatInfo(unsizedFormat, sourcePixelsType); - const d3d11::TextureFormat &sourceFormatInfo = d3d11::GetTextureFormatInfo(sourceFormat, mRenderer->getRenderer11DeviceCaps()); + const d3d11::Format &sourceFormatInfo = d3d11::Format::Get( + sourceglFormatInfo.sizedInternalFormat, mRenderer->getRenderer11DeviceCaps()); DXGI_FORMAT srvFormat = sourceFormatInfo.srvFormat; ASSERT(srvFormat != DXGI_FORMAT_UNKNOWN); Buffer11 *bufferStorage11 = GetAs(sourceBuffer.getImplementation()); - ID3D11ShaderResourceView *bufferSRV = bufferStorage11->getSRV(srvFormat); - ASSERT(bufferSRV != NULL); + const d3d11::ShaderResourceView *bufferSRV = nullptr; + ANGLE_TRY_RESULT(bufferStorage11->getSRV(context, srvFormat), bufferSRV); + ASSERT(bufferSRV != nullptr); - ID3D11RenderTargetView *textureRTV = GetAs(destRenderTarget)->getRenderTargetView(); - ASSERT(textureRTV != NULL); + const d3d11::RenderTargetView &textureRTV = + GetAs(destRenderTarget)->getRenderTargetView(); + ASSERT(textureRTV.valid()); CopyShaderParams shaderParams; - setBufferToTextureCopyParams(destArea, destSize, sourceFormat, unpack, offset, &shaderParams); + setBufferToTextureCopyParams(destArea, destSize, sourceglFormatInfo.sizedInternalFormat, 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); - auto stateManager = mRenderer->getStateManager(); + const auto *geometryShader = ((destSize.depth > 1) ? &mBufferToTextureGS : nullptr); + StateManager11 *stateManager = mRenderer->getStateManager(); - deviceContext->VSSetShader(mBufferToTextureVS, NULL, 0); - deviceContext->GSSetShader(geometryShader, NULL, 0); - deviceContext->PSSetShader(pixelShader, NULL, 0); + stateManager->setDrawShaders(&mBufferToTextureVS, geometryShader, pixelShader); stateManager->setShaderResource(gl::SAMPLER_PIXEL, 0, bufferSRV); - deviceContext->IASetInputLayout(NULL); - deviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_POINTLIST); + stateManager->setInputLayout(nullptr); + stateManager->setPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_POINTLIST); - deviceContext->IASetVertexBuffers(0, 1, &nullBuffer, &zero, &zero); - deviceContext->OMSetBlendState(NULL, NULL, 0xFFFFFFF); - deviceContext->OMSetDepthStencilState(mCopyDepthStencilState, 0xFFFFFFFF); - deviceContext->RSSetState(mCopyRasterizerState); + stateManager->setSingleVertexBuffer(nullptr, 0, 0); + stateManager->setSimpleBlendState(nullptr); + stateManager->setDepthStencilState(&mCopyDepthStencilState, 0xFFFFFFFF); + stateManager->setRasterizerState(&mCopyRasterizerState); - mRenderer->setOneTimeRenderTarget(textureRTV); + stateManager->setRenderTarget(textureRTV.get(), nullptr); if (!StructEquals(mParamsData, shaderParams)) { - d3d11::SetBufferData(deviceContext, mParamsConstantBuffer, shaderParams); + d3d11::SetBufferData(deviceContext, mParamsConstantBuffer.get(), shaderParams); mParamsData = shaderParams; } - deviceContext->VSSetConstantBuffers(0, 1, &mParamsConstantBuffer); + stateManager->setVertexConstantBuffer(0, &mParamsConstantBuffer); // Set the viewport - D3D11_VIEWPORT viewport; - viewport.TopLeftX = 0; - viewport.TopLeftY = 0; - viewport.Width = static_cast(destSize.width); - viewport.Height = static_cast(destSize.height); - viewport.MinDepth = 0.0f; - viewport.MaxDepth = 1.0f; - deviceContext->RSSetViewports(1, &viewport); + stateManager->setSimpleViewport(destSize); UINT numPixels = (destArea.width * destArea.height * destArea.depth); deviceContext->Draw(numPixels, 0); - // Unbind textures and render targets and vertex buffer - stateManager->setShaderResource(gl::SAMPLER_PIXEL, 0, NULL); - deviceContext->VSSetConstantBuffers(0, 1, &nullBuffer); - - mRenderer->markAllStateDirty(); - - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } 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); + d3d11::PixelShader bufferToTextureFloat; + d3d11::PixelShader bufferToTextureInt; + d3d11::PixelShader bufferToTextureUint; + + ANGLE_TRY( + mRenderer->allocateResource(ShaderData(g_PS_BufferToTexture_4F), &bufferToTextureFloat)); + ANGLE_TRY( + mRenderer->allocateResource(ShaderData(g_PS_BufferToTexture_4I), &bufferToTextureInt)); + ANGLE_TRY( + mRenderer->allocateResource(ShaderData(g_PS_BufferToTexture_4UI), &bufferToTextureUint)); + + bufferToTextureFloat.setDebugName("BufferToTexture RGBA ps"); + bufferToTextureInt.setDebugName("BufferToTexture RGBA-I ps"); + bufferToTextureUint.setDebugName("BufferToTexture RGBA-UI ps"); + + mBufferToTexturePSMap[GL_FLOAT] = std::move(bufferToTextureFloat); + mBufferToTexturePSMap[GL_INT] = std::move(bufferToTextureInt); + mBufferToTexturePSMap[GL_UNSIGNED_INT] = std::move(bufferToTextureUint); + + return gl::NoError(); } -ID3D11PixelShader *PixelTransfer11::findBufferToTexturePS(GLenum internalFormat) const +const d3d11::PixelShader *PixelTransfer11::findBufferToTexturePS(GLenum internalFormat) const { - GLenum componentType = gl::GetInternalFormatInfo(internalFormat).componentType; + GLenum componentType = gl::GetSizedInternalFormatInfo(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); + return (shaderMapIt == mBufferToTexturePSMap.end() ? nullptr : &shaderMapIt->second); } -} +} // namespace rx diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/PixelTransfer11.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/PixelTransfer11.h index 1672121ec7..a93544247e 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/PixelTransfer11.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/PixelTransfer11.h @@ -11,14 +11,14 @@ #ifndef LIBANGLE_RENDERER_D3D_D3D11_PIXELTRANSFER11_H_ #define LIBANGLE_RENDERER_D3D_D3D11_PIXELTRANSFER11_H_ -#include "libANGLE/Error.h" - -#include "common/platform.h" - #include #include +#include "common/platform.h" +#include "libANGLE/Error.h" +#include "libANGLE/renderer/d3d/d3d11/ResourceManager11.h" + namespace gl { @@ -45,8 +45,13 @@ class PixelTransfer11 // 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); + gl::Error copyBufferToTexture(const gl::Context *context, + const gl::PixelUnpackState &unpack, + unsigned int offset, + RenderTargetD3D *destRenderTarget, + GLenum destinationFormat, + GLenum sourcePixelsType, + const gl::Box &destArea); private: @@ -68,22 +73,21 @@ class PixelTransfer11 gl::Error loadResources(); gl::Error buildShaderMap(); - ID3D11PixelShader *findBufferToTexturePS(GLenum internalFormat) const; + const d3d11::PixelShader *findBufferToTexturePS(GLenum internalFormat) const; Renderer11 *mRenderer; bool mResourcesLoaded; - std::map mBufferToTexturePSMap; - ID3D11VertexShader *mBufferToTextureVS; - ID3D11GeometryShader *mBufferToTextureGS; - ID3D11Buffer *mParamsConstantBuffer; + std::map mBufferToTexturePSMap; + d3d11::VertexShader mBufferToTextureVS; + d3d11::GeometryShader mBufferToTextureGS; + d3d11::Buffer mParamsConstantBuffer; CopyShaderParams mParamsData; - ID3D11RasterizerState *mCopyRasterizerState; - ID3D11DepthStencilState *mCopyDepthStencilState; - + d3d11::RasterizerState mCopyRasterizerState; + d3d11::DepthStencilState mCopyDepthStencilState; }; -} +} // namespace rx #endif // LIBANGLE_RENDERER_D3D_D3D11_PIXELTRANSFER11_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/ProgramPipeline11.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/ProgramPipeline11.cpp new file mode 100644 index 0000000000..c9554431e5 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/ProgramPipeline11.cpp @@ -0,0 +1,24 @@ +// +// Copyright 2017 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. +// +// ProgramPipelineNULL.cpp: +// Implements the class methods for ProgramPipeline11. +// + +#include "libANGLE/renderer/d3d/d3d11/ProgramPipeline11.h" + +namespace rx +{ + +ProgramPipeline11::ProgramPipeline11(const gl::ProgramPipelineState &state) + : ProgramPipelineImpl(state) +{ +} + +ProgramPipeline11::~ProgramPipeline11() +{ +} + +} // namespace rx diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/ProgramPipeline11.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/ProgramPipeline11.h new file mode 100644 index 0000000000..cf838eec05 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/ProgramPipeline11.h @@ -0,0 +1,27 @@ +// +// Copyright 2017 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. +// +// ProgramPipeline11.h: +// Defines the class interface for ProgramPipeline11, implementing ProgramPipelineImpl. +// + +#ifndef LIBANGLE_RENDERER_D3D_D3D11_PROGRAMPIPELINE11_H_ +#define LIBANGLE_RENDERER_D3D_D3D11_PROGRAMPIPELINE11_H_ + +#include "libANGLE/renderer/ProgramPipelineImpl.h" + +namespace rx +{ + +class ProgramPipeline11 : public ProgramPipelineImpl +{ + public: + ProgramPipeline11(const gl::ProgramPipelineState &state); + ~ProgramPipeline11() override; +}; + +} // namespace rx + +#endif // LIBANGLE_RENDERER_D3D_D3D11_PROGRAMPIPELINE11_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 index 0a79b26df0..66b9476e7f 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Query11.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Query11.cpp @@ -7,146 +7,96 @@ // 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 // ANGLE_MINGW32_COMPAT - -#ifndef ANGLE_D3D11_QDTD_AVAILABLE -typedef struct D3D11_QUERY_DATA_TIMESTAMP_DISJOINT { - UINT64 Frequency; - BOOL Disjoint; -} D3D11_QUERY_DATA_TIMESTAMP_DISJOINT; -#endif // MINGW32 +#include "common/utilities.h" +#include "libANGLE/renderer/d3d/d3d11/Renderer11.h" +#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h" -namespace rx +namespace { -Query11::Query11(Renderer11 *renderer, GLenum type) - : QueryImpl(type), - mResult(0), - mQueryFinished(false), - mRenderer(renderer), - mQuery(nullptr), - mTimestampBeginQuery(nullptr), - mTimestampEndQuery(nullptr) +GLuint64 MergeQueryResults(GLenum type, GLuint64 currentResult, GLuint64 newResult) { -} + switch (type) + { + case GL_ANY_SAMPLES_PASSED: + case GL_ANY_SAMPLES_PASSED_CONSERVATIVE: + return (currentResult == GL_TRUE || newResult == GL_TRUE) ? GL_TRUE : GL_FALSE; -Query11::~Query11() -{ - SafeRelease(mQuery); - SafeRelease(mTimestampBeginQuery); - SafeRelease(mTimestampEndQuery); -} + case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN: + return currentResult + newResult; -gl::Error Query11::begin() -{ - if (mQuery == nullptr) - { - D3D11_QUERY_DESC queryDesc; - queryDesc.Query = gl_d3d11::ConvertQueryType(getType()); - queryDesc.MiscFlags = 0; + case GL_TIME_ELAPSED_EXT: + return currentResult + newResult; - ID3D11Device *device = mRenderer->getDevice(); + case GL_TIMESTAMP_EXT: + return newResult; - HRESULT result = device->CreateQuery(&queryDesc, &mQuery); - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Internal query creation failed, result: 0x%X.", result); - } + case GL_COMMANDS_COMPLETED_CHROMIUM: + return newResult; - // If we are doing time elapsed we also need a query to actually query the timestamp - if (getType() == GL_TIME_ELAPSED_EXT) - { - D3D11_QUERY_DESC desc; - desc.Query = D3D11_QUERY_TIMESTAMP; - desc.MiscFlags = 0; - result = device->CreateQuery(&desc, &mTimestampBeginQuery); - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Internal query creation failed, result: 0x%X.", - result); - } - result = device->CreateQuery(&desc, &mTimestampEndQuery); - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Internal query creation failed, result: 0x%X.", - result); - } - } + default: + UNREACHABLE(); + return 0; } +} - ID3D11DeviceContext *context = mRenderer->getDeviceContext(); +} // anonymous namespace - context->Begin(mQuery); +namespace rx +{ - // If we are doing time elapsed query the begin timestamp - if (getType() == GL_TIME_ELAPSED_EXT) - { - context->End(mTimestampBeginQuery); - } - return gl::Error(GL_NO_ERROR); +Query11::QueryState::QueryState() : query(), beginTimestamp(), endTimestamp(), finished(false) +{ } -gl::Error Query11::end() +Query11::QueryState::~QueryState() { - ASSERT(mQuery); - - ID3D11DeviceContext *context = mRenderer->getDeviceContext(); +} - // If we are doing time elapsed query the end timestamp - if (getType() == GL_TIME_ELAPSED_EXT) - { - context->End(mTimestampEndQuery); - } +Query11::Query11(Renderer11 *renderer, GLenum type) + : QueryImpl(type), mResult(0), mResultSum(0), mRenderer(renderer) +{ + mActiveQuery = std::unique_ptr(new QueryState()); +} - context->End(mQuery); +Query11::~Query11() +{ + mRenderer->getStateManager()->onDeleteQueryObject(this); +} - mQueryFinished = false; - mResult = GL_FALSE; +gl::Error Query11::begin() +{ + mResultSum = 0; + mRenderer->getStateManager()->onBeginQuery(this); + return resume(); +} - return gl::Error(GL_NO_ERROR); +gl::Error Query11::end() +{ + return pause(); } gl::Error Query11::queryCounter() { // This doesn't do anything for D3D11 as we don't support timestamps ASSERT(getType() == GL_TIMESTAMP_EXT); - mQueryFinished = true; - mResult = 0; - return gl::Error(GL_NO_ERROR); + mResultSum = 0; + mPendingQueries.push_back(std::unique_ptr(new QueryState())); + return gl::NoError(); } template gl::Error Query11::getResultBase(T *params) { - while (!mQueryFinished) - { - gl::Error error = testQuery(); - if (error.isError()) - { - return error; - } - - if (!mQueryFinished) - { - ScheduleYield(); - } - } + ASSERT(!mActiveQuery->query.valid()); + ANGLE_TRY(flush(true)); + ASSERT(mPendingQueries.empty()); + *params = static_cast(mResultSum); - ASSERT(mQueryFinished); - *params = static_cast(mResult); - - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } gl::Error Query11::getResult(GLint *params) @@ -171,105 +121,197 @@ gl::Error Query11::getResult(GLuint64 *params) gl::Error Query11::isResultAvailable(bool *available) { - gl::Error error = testQuery(); - if (error.isError()) + ANGLE_TRY(flush(false)); + + *available = mPendingQueries.empty(); + return gl::NoError(); +} + +gl::Error Query11::pause() +{ + if (mActiveQuery->query.valid()) { - return error; + ID3D11DeviceContext *context = mRenderer->getDeviceContext(); + GLenum queryType = getType(); + + // If we are doing time elapsed query the end timestamp + if (queryType == GL_TIME_ELAPSED_EXT) + { + context->End(mActiveQuery->endTimestamp.get()); + } + + context->End(mActiveQuery->query.get()); + + mPendingQueries.push_back(std::move(mActiveQuery)); + mActiveQuery = std::unique_ptr(new QueryState()); } - *available = mQueryFinished; + return flush(false); +} + +gl::Error Query11::resume() +{ + if (!mActiveQuery->query.valid()) + { + ANGLE_TRY(flush(false)); + + GLenum queryType = getType(); + D3D11_QUERY d3dQueryType = gl_d3d11::ConvertQueryType(queryType); - return gl::Error(GL_NO_ERROR); + D3D11_QUERY_DESC queryDesc; + queryDesc.Query = d3dQueryType; + queryDesc.MiscFlags = 0; + + ANGLE_TRY(mRenderer->allocateResource(queryDesc, &mActiveQuery->query)); + + // If we are doing time elapsed we also need a query to actually query the timestamp + if (queryType == GL_TIME_ELAPSED_EXT) + { + D3D11_QUERY_DESC desc; + desc.Query = D3D11_QUERY_TIMESTAMP; + desc.MiscFlags = 0; + + ANGLE_TRY(mRenderer->allocateResource(desc, &mActiveQuery->beginTimestamp)); + ANGLE_TRY(mRenderer->allocateResource(desc, &mActiveQuery->endTimestamp)); + } + + ID3D11DeviceContext *context = mRenderer->getDeviceContext(); + + if (d3dQueryType != D3D11_QUERY_EVENT) + { + context->Begin(mActiveQuery->query.get()); + } + + // If we are doing time elapsed, query the begin timestamp + if (queryType == GL_TIME_ELAPSED_EXT) + { + context->End(mActiveQuery->beginTimestamp.get()); + } + } + + return gl::NoError(); } -gl::Error Query11::testQuery() +gl::Error Query11::flush(bool force) { - if (!mQueryFinished) + while (!mPendingQueries.empty()) { - ASSERT(mQuery); + QueryState *query = mPendingQueries.front().get(); + do + { + ANGLE_TRY(testQuery(query)); + if (!query->finished && !force) + { + return gl::NoError(); + } + } while (!query->finished); + + mResultSum = MergeQueryResults(getType(), mResultSum, mResult); + mPendingQueries.pop_front(); + } + + return gl::NoError(); +} + +gl::Error Query11::testQuery(QueryState *queryState) +{ + if (!queryState->finished) + { ID3D11DeviceContext *context = mRenderer->getDeviceContext(); switch (getType()) { - case GL_ANY_SAMPLES_PASSED_EXT: - case GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT: + case GL_ANY_SAMPLES_PASSED_EXT: + case GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT: { + ASSERT(queryState->query.valid()); UINT64 numPixels = 0; - HRESULT result = context->GetData(mQuery, &numPixels, sizeof(numPixels), 0); + HRESULT result = + context->GetData(queryState->query.get(), &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); + return gl::OutOfMemory() + << "Failed to get the data of an internal query, " << gl::FmtHR(result); } if (result == S_OK) { - mQueryFinished = true; - mResult = (numPixels > 0) ? GL_TRUE : GL_FALSE; + queryState->finished = true; + mResult = (numPixels > 0) ? GL_TRUE : GL_FALSE; } } break; - case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN: + case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN: { - D3D11_QUERY_DATA_SO_STATISTICS soStats = { 0 }; - HRESULT result = context->GetData(mQuery, &soStats, sizeof(soStats), 0); + ASSERT(queryState->query.valid()); + D3D11_QUERY_DATA_SO_STATISTICS soStats = {0}; + HRESULT result = + context->GetData(queryState->query.get(), &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); + return gl::OutOfMemory() + << "Failed to get the data of an internal query, " << gl::FmtHR(result); } if (result == S_OK) { - mQueryFinished = true; - mResult = static_cast(soStats.NumPrimitivesWritten); + queryState->finished = true; + mResult = static_cast(soStats.NumPrimitivesWritten); } } break; case GL_TIME_ELAPSED_EXT: { + ASSERT(queryState->query.valid()); + ASSERT(queryState->beginTimestamp.valid()); + ASSERT(queryState->endTimestamp.valid()); D3D11_QUERY_DATA_TIMESTAMP_DISJOINT timeStats = {0}; - HRESULT result = context->GetData(mQuery, &timeStats, sizeof(timeStats), 0); + HRESULT result = + context->GetData(queryState->query.get(), &timeStats, sizeof(timeStats), 0); if (FAILED(result)) { - return gl::Error(GL_OUT_OF_MEMORY, - "Failed to get the data of an internal query, result: 0x%X.", - result); + return gl::OutOfMemory() + << "Failed to get the data of an internal query, " << gl::FmtHR(result); } if (result == S_OK) { UINT64 beginTime = 0; - HRESULT beginRes = - context->GetData(mTimestampBeginQuery, &beginTime, sizeof(UINT64), 0); + HRESULT beginRes = context->GetData(queryState->beginTimestamp.get(), + &beginTime, sizeof(UINT64), 0); if (FAILED(beginRes)) { - return gl::Error( - GL_OUT_OF_MEMORY, - "Failed to get the data of an internal query, result: 0x%X.", beginRes); + return gl::OutOfMemory() << "Failed to get the data of an internal query, " + << gl::FmtHR(beginRes); } UINT64 endTime = 0; - HRESULT endRes = - context->GetData(mTimestampEndQuery, &endTime, sizeof(UINT64), 0); + HRESULT endRes = context->GetData(queryState->endTimestamp.get(), &endTime, + sizeof(UINT64), 0); if (FAILED(endRes)) { - return gl::Error( - GL_OUT_OF_MEMORY, - "Failed to get the data of an internal query, result: 0x%X.", endRes); + return gl::OutOfMemory() << "Failed to get the data of an internal query, " + << gl::FmtHR(endRes); } if (beginRes == S_OK && endRes == S_OK) { - mQueryFinished = true; + queryState->finished = true; if (timeStats.Disjoint) { mRenderer->setGPUDisjoint(); } static_assert(sizeof(UINT64) == sizeof(unsigned long long), "D3D UINT64 isn't 64 bits"); - if (rx::IsUnsignedMultiplicationSafe(endTime - beginTime, 1000000000ull)) + + angle::CheckedNumeric checkedTime(endTime); + checkedTime -= beginTime; + checkedTime *= 1000000000ull; + checkedTime /= timeStats.Frequency; + if (checkedTime.IsValid()) { - mResult = ((endTime - beginTime) * 1000000000ull) / timeStats.Frequency; + mResult = checkedTime.ValueOrDie(); } else { @@ -288,23 +330,46 @@ gl::Error Query11::testQuery() // D3D11 doesn't support GL timestamp queries as D3D timestamps are not guaranteed // to have any sort of continuity outside of a disjoint timestamp query block, which // GL depends on - mResult = 0; + ASSERT(!queryState->query.valid()); + mResult = 0; + queryState->finished = true; } break; - default: - UNREACHABLE(); + case GL_COMMANDS_COMPLETED_CHROMIUM: + { + ASSERT(queryState->query.valid()); + BOOL completed = 0; + HRESULT result = + context->GetData(queryState->query.get(), &completed, sizeof(completed), 0); + if (FAILED(result)) + { + return gl::OutOfMemory() + << "Failed to get the data of an internal query, " << gl::FmtHR(result); + } + + if (result == S_OK) + { + queryState->finished = true; + ASSERT(completed == TRUE); + mResult = (completed == TRUE) ? GL_TRUE : GL_FALSE; + } + } break; + + default: + UNREACHABLE(); + break; } - if (!mQueryFinished && mRenderer->testDeviceLost()) + if (!queryState->finished && mRenderer->testDeviceLost()) { mRenderer->notifyDeviceLost(); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to test get query result, device is lost."); + return gl::OutOfMemory() << "Failed to test get query result, device is lost."; } } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -} +} // namespace rx diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Query11.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Query11.h index 29a6e6f85d..a88a8892aa 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Query11.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Query11.h @@ -9,7 +9,10 @@ #ifndef LIBANGLE_RENDERER_D3D_D3D11_QUERY11_H_ #define LIBANGLE_RENDERER_D3D_D3D11_QUERY11_H_ +#include + #include "libANGLE/renderer/QueryImpl.h" +#include "libANGLE/renderer/d3d/d3d11/ResourceManager11.h" namespace rx { @@ -19,31 +22,45 @@ class Query11 : public QueryImpl { public: Query11(Renderer11 *renderer, GLenum type); - virtual ~Query11(); + ~Query11() override; + + gl::Error begin() override; + gl::Error end() override; + gl::Error queryCounter() override; + gl::Error getResult(GLint *params) override; + gl::Error getResult(GLuint *params) override; + gl::Error getResult(GLint64 *params) override; + gl::Error getResult(GLuint64 *params) override; + gl::Error isResultAvailable(bool *available) override; - virtual gl::Error begin(); - virtual gl::Error end(); - virtual gl::Error queryCounter(); - virtual gl::Error getResult(GLint *params); - virtual gl::Error getResult(GLuint *params); - virtual gl::Error getResult(GLint64 *params); - virtual gl::Error getResult(GLuint64 *params); - virtual gl::Error isResultAvailable(bool *available); + gl::Error pause(); + gl::Error resume(); private: - gl::Error testQuery(); + struct QueryState final : private angle::NonCopyable + { + QueryState(); + ~QueryState(); + + d3d11::Query query; + d3d11::Query beginTimestamp; + d3d11::Query endTimestamp; + bool finished; + }; + + gl::Error flush(bool force); + gl::Error testQuery(QueryState *queryState); template gl::Error getResultBase(T *params); GLuint64 mResult; - - bool mQueryFinished; + GLuint64 mResultSum; Renderer11 *mRenderer; - ID3D11Query *mQuery; - ID3D11Query *mTimestampBeginQuery; - ID3D11Query *mTimestampEndQuery; + + std::unique_ptr mActiveQuery; + std::deque> mPendingQueries; }; } diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/RenderStateCache.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/RenderStateCache.cpp index 2ee25cfb6c..5b85196c2e 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/RenderStateCache.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/RenderStateCache.cpp @@ -17,338 +17,180 @@ #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 { using namespace gl_d3d11; -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), - mCounter(0), - mBlendStateCache(kMaxBlendStates, hashBlendState, compareBlendStates), - mRasterizerStateCache(kMaxRasterizerStates, hashRasterizerState, compareRasterizerStates), - mDepthStencilStateCache(kMaxDepthStencilStates, hashDepthStencilState, compareDepthStencilStates), - mSamplerStateCache(kMaxSamplerStates, hashSamplerState, compareSamplerStates), - mDevice(NULL) +RenderStateCache::RenderStateCache() + : mBlendStateCache(kMaxStates), + mRasterizerStateCache(kMaxStates), + mDepthStencilStateCache(kMaxStates), + mSamplerStateCache(kMaxStates) { } RenderStateCache::~RenderStateCache() { - clear(); -} - -void RenderStateCache::initialize(ID3D11Device *device) -{ - clear(); - mDevice = device; } void RenderStateCache::clear() { - ClearStateMap(mBlendStateCache); - ClearStateMap(mRasterizerStateCache); - ClearStateMap(mDepthStencilStateCache); - ClearStateMap(mSamplerStateCache); + mBlendStateCache.Clear(); + mRasterizerStateCache.Clear(); + mDepthStencilStateCache.Clear(); + mSamplerStateCache.Clear(); } -std::size_t RenderStateCache::hashBlendState(const BlendStateKey &blendState) +// static +d3d11::BlendStateKey RenderStateCache::GetBlendStateKey(const gl::Context *context, + const gl::Framebuffer *framebuffer, + const gl::BlendState &blendState) { - static const unsigned int seed = 0xABCDEF98; - - std::size_t hash = 0; - MurmurHash3_x86_32(&blendState, sizeof(gl::BlendState), seed, &hash); - return hash; -} + d3d11::BlendStateKey key; + FramebufferD3D *framebufferD3D = GetImplAs(framebuffer); + const gl::AttachmentList &colorbuffers = framebufferD3D->getColorAttachmentsForRender(context); + const UINT8 blendStateMask = + gl_d3d11::ConvertColorMask(blendState.colorMaskRed, blendState.colorMaskGreen, + blendState.colorMaskBlue, blendState.colorMaskAlpha); -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(); - - BlendStateKey key = {}; key.blendState = blendState; - for (size_t colorAttachment = 0; colorAttachment < colorbuffers.size(); ++colorAttachment) - { - const gl::FramebufferAttachment *attachment = colorbuffers[colorAttachment]; - auto rtChannels = key.rtChannels[colorAttachment]; + for (size_t i = 0; i < colorbuffers.size(); i++) + { + const gl::FramebufferAttachment *attachment = colorbuffers[i]; 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; + key.rtvMax = static_cast(i) + 1; + key.rtvMasks[i] = + (gl_d3d11::GetColorMask(*attachment->getFormat().info)) & blendStateMask; } } - BlendStateMap::iterator keyIter = mBlendStateCache.find(key); + return key; +} + +gl::Error RenderStateCache::getBlendState(Renderer11 *renderer, + const d3d11::BlendStateKey &key, + const d3d11::BlendState **outBlendState) +{ + auto keyIter = mBlendStateCache.Get(key); if (keyIter != mBlendStateCache.end()) { - BlendStateCounterPair &state = keyIter->second; - state.second = mCounter++; - *outBlendState = state.first; - return gl::Error(GL_NO_ERROR); + *outBlendState = &keyIter->second; + return gl::NoError(); } - 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; + TrimCache(kMaxStates, kGCLimit, "blend state", &mBlendStateCache); - 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); - } + // Create a new blend state and insert it into the cache + D3D11_BLEND_DESC blendDesc; + D3D11_RENDER_TARGET_BLEND_DESC &rtDesc0 = blendDesc.RenderTarget[0]; + const gl::BlendState &blendState = key.blendState; - 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); - } + blendDesc.AlphaToCoverageEnable = blendState.sampleAlphaToCoverage; + blendDesc.IndependentBlendEnable = key.rtvMax > 1 ? TRUE : FALSE; - mBlendStateCache.insert(std::make_pair(key, std::make_pair(dx11BlendState, mCounter++))); + rtDesc0 = {}; - *outBlendState = dx11BlendState; - return gl::Error(GL_NO_ERROR); + if (blendState.blend) + { + rtDesc0.BlendEnable = true; + rtDesc0.SrcBlend = gl_d3d11::ConvertBlendFunc(blendState.sourceBlendRGB, false); + rtDesc0.DestBlend = gl_d3d11::ConvertBlendFunc(blendState.destBlendRGB, false); + rtDesc0.BlendOp = gl_d3d11::ConvertBlendOp(blendState.blendEquationRGB); + rtDesc0.SrcBlendAlpha = gl_d3d11::ConvertBlendFunc(blendState.sourceBlendAlpha, true); + rtDesc0.DestBlendAlpha = gl_d3d11::ConvertBlendFunc(blendState.destBlendAlpha, true); + rtDesc0.BlendOpAlpha = gl_d3d11::ConvertBlendOp(blendState.blendEquationAlpha); } -} -std::size_t RenderStateCache::hashRasterizerState(const RasterizerStateKey &rasterState) -{ - static const unsigned int seed = 0xABCDEF98; + rtDesc0.RenderTargetWriteMask = key.rtvMasks[0]; - std::size_t hash = 0; - MurmurHash3_x86_32(&rasterState, sizeof(RasterizerStateKey), seed, &hash); - return hash; -} + for (unsigned int i = 1; i < D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; i++) + { + blendDesc.RenderTarget[i] = rtDesc0; + blendDesc.RenderTarget[i].RenderTargetWriteMask = key.rtvMasks[i]; + } -bool RenderStateCache::compareRasterizerStates(const RasterizerStateKey &a, const RasterizerStateKey &b) -{ - return memcmp(&a, &b, sizeof(RasterizerStateKey)) == 0; + d3d11::BlendState d3dBlendState; + ANGLE_TRY(renderer->allocateResource(blendDesc, &d3dBlendState)); + const auto &iter = mBlendStateCache.Put(key, std::move(d3dBlendState)); + + *outBlendState = &iter->second; + + return gl::NoError(); } -gl::Error RenderStateCache::getRasterizerState(const gl::RasterizerState &rasterState, bool scissorEnabled, +gl::Error RenderStateCache::getRasterizerState(Renderer11 *renderer, + 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 = {}; + d3d11::RasterizerStateKey key; key.rasterizerState = rasterState; - key.scissorEnabled = scissorEnabled; + key.scissorEnabled = scissorEnabled ? 1 : 0; - RasterizerStateMap::iterator keyIter = mRasterizerStateCache.find(key); + auto keyIter = mRasterizerStateCache.Get(key); if (keyIter != mRasterizerStateCache.end()) { - RasterizerStateCounterPair &state = keyIter->second; - state.second = mCounter++; - *outRasterizerState = state.first; - return gl::Error(GL_NO_ERROR); + *outRasterizerState = keyIter->second.get(); + return gl::NoError(); } - 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); + TrimCache(kMaxStates, kGCLimit, "rasterizer state", &mRasterizerStateCache); - // Disable culling if drawing points - if (rasterState.pointDrawMode) - { - cullMode = D3D11_CULL_NONE; - } + D3D11_CULL_MODE cullMode = + gl_d3d11::ConvertCullMode(rasterState.cullFace, rasterState.cullMode); - 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 &originalState, - bool disableDepth, - bool disableStencil, - ID3D11DepthStencilState **outDSState) -{ - if (!mDevice) + // Disable culling if drawing points + if (rasterState.pointDrawMode) { - return gl::Error(GL_OUT_OF_MEMORY, "Internal error, RenderStateCache is not initialized."); + cullMode = D3D11_CULL_NONE; } - gl::DepthStencilState glState = originalState; - if (disableDepth) + 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) { - glState.depthTest = false; - glState.depthMask = false; + rasterDesc.SlopeScaledDepthBias = rasterState.polygonOffsetFactor; + rasterDesc.DepthBias = (INT)rasterState.polygonOffsetUnits; } - - if (disableStencil) + else { - glState.stencilWritemask = 0; - glState.stencilBackWritemask = 0; - glState.stencilTest = false; + rasterDesc.SlopeScaledDepthBias = 0.0f; + rasterDesc.DepthBias = 0; } - auto keyIter = mDepthStencilStateCache.find(glState); + d3d11::RasterizerState dx11RasterizerState; + ANGLE_TRY(renderer->allocateResource(rasterDesc, &dx11RasterizerState)); + *outRasterizerState = dx11RasterizerState.get(); + mRasterizerStateCache.Put(key, std::move(dx11RasterizerState)); + + return gl::NoError(); +} + +gl::Error RenderStateCache::getDepthStencilState(Renderer11 *renderer, + const gl::DepthStencilState &glState, + const d3d11::DepthStencilState **outDSState) +{ + auto keyIter = mDepthStencilStateCache.Get(glState); if (keyIter != mDepthStencilStateCache.end()) { - DepthStencilStateCounterPair &state = keyIter->second; - state.second = mCounter++; - *outDSState = state.first; - return gl::Error(GL_NO_ERROR); + *outDSState = &keyIter->second; + return gl::NoError(); } - if (mDepthStencilStateCache.size() >= kMaxDepthStencilStates) - { - TRACE( - "Overflowed the limit of %u depth stencil states, removing the least recently used " - "to make room.", - kMaxDepthStencilStates); - - auto leastRecentlyUsed = mDepthStencilStateCache.begin(); - for (auto i = mDepthStencilStateCache.begin(); i != mDepthStencilStateCache.end(); i++) - { - if (i->second.second < leastRecentlyUsed->second.second) - { - leastRecentlyUsed = i; - } - } - SafeRelease(leastRecentlyUsed->second.first); - mDepthStencilStateCache.erase(leastRecentlyUsed); - } + TrimCache(kMaxStates, kGCLimit, "depth stencil state", &mDepthStencilStateCache); D3D11_DEPTH_STENCIL_DESC dsDesc = {0}; dsDesc.DepthEnable = glState.depthTest ? TRUE : FALSE; @@ -366,107 +208,66 @@ gl::Error RenderStateCache::getDepthStencilState(const gl::DepthStencilState &or dsDesc.BackFace.StencilPassOp = ConvertStencilOp(glState.stencilBackPassDepthPass); dsDesc.BackFace.StencilFunc = ConvertComparison(glState.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); - } + d3d11::DepthStencilState dx11DepthStencilState; + ANGLE_TRY(renderer->allocateResource(dsDesc, &dx11DepthStencilState)); + const auto &iter = mDepthStencilStateCache.Put(glState, std::move(dx11DepthStencilState)); - mDepthStencilStateCache.insert( - std::make_pair(glState, std::make_pair(dx11DepthStencilState, mCounter++))); + *outDSState = &iter->second; - *outDSState = dx11DepthStencilState; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -std::size_t RenderStateCache::hashSamplerState(const gl::SamplerState &samplerState) +gl::Error RenderStateCache::getSamplerState(Renderer11 *renderer, + const gl::SamplerState &samplerState, + ID3D11SamplerState **outSamplerState) { - 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) + auto keyIter = mSamplerStateCache.Get(samplerState); + if (keyIter != mSamplerStateCache.end()) { - return gl::Error(GL_OUT_OF_MEMORY, "Internal error, RenderStateCache is not initialized."); + *outSamplerState = keyIter->second.get(); + return gl::NoError(); } - SamplerStateMap::iterator keyIter = mSamplerStateCache.find(samplerState); - if (keyIter != mSamplerStateCache.end()) + TrimCache(kMaxStates, kGCLimit, "sampler state", &mSamplerStateCache); + + const auto &featureLevel = renderer->getRenderer11DeviceCaps().featureLevel; + + 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 = + gl_d3d11::ConvertMaxAnisotropy(samplerState.maxAnisotropy, featureLevel); + 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 (featureLevel <= D3D_FEATURE_LEVEL_9_3) { - SamplerStateCounterPair &state = keyIter->second; - state.second = mCounter++; - *outSamplerState = state.first; - return gl::Error(GL_NO_ERROR); + // 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; } - 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 = static_cast(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->getRenderer11DeviceCaps().featureLevel <= 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; - } + d3d11::SamplerState dx11SamplerState; + ANGLE_TRY(renderer->allocateResource(samplerDesc, &dx11SamplerState)); + *outSamplerState = dx11SamplerState.get(); + mSamplerStateCache.Put(samplerState, std::move(dx11SamplerState)); - 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); - } + return gl::NoError(); } -} +} // namespace rx diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/RenderStateCache.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/RenderStateCache.h index 82cb13903c..7501e83fc4 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/RenderStateCache.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/RenderStateCache.h @@ -10,9 +10,11 @@ #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 "libANGLE/Error.h" +#include "libANGLE/SizedMRUCache.h" +#include "libANGLE/angletypes.h" +#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h" #include @@ -21,6 +23,42 @@ namespace gl class Framebuffer; } +namespace std +{ +template <> +struct hash +{ + size_t operator()(const rx::d3d11::BlendStateKey &key) const + { + return angle::ComputeGenericHash(key); + } +}; + +template <> +struct hash +{ + size_t operator()(const rx::d3d11::RasterizerStateKey &key) const + { + return angle::ComputeGenericHash(key); + } +}; + +template <> +struct hash +{ + size_t operator()(const gl::DepthStencilState &key) const + { + return angle::ComputeGenericHash(key); + } +}; + +template <> +struct hash +{ + size_t operator()(const gl::SamplerState &key) const { return angle::ComputeGenericHash(key); } +}; +} // namespace std + namespace rx { class Renderer11; @@ -28,87 +66,58 @@ class Renderer11; class RenderStateCache : angle::NonCopyable { public: - RenderStateCache(Renderer11 *renderer); + RenderStateCache(); 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, - bool disableDepth, - bool disableStencil, - ID3D11DepthStencilState **outDSState); - gl::Error getSamplerState(const gl::SamplerState &samplerState, ID3D11SamplerState **outSamplerState); + static d3d11::BlendStateKey GetBlendStateKey(const gl::Context *context, + const gl::Framebuffer *framebuffer, + const gl::BlendState &blendState); + gl::Error getBlendState(Renderer11 *renderer, + const d3d11::BlendStateKey &key, + const d3d11::BlendState **outBlendState); + gl::Error getRasterizerState(Renderer11 *renderer, + const gl::RasterizerState &rasterState, + bool scissorEnabled, + ID3D11RasterizerState **outRasterizerState); + gl::Error getDepthStencilState(Renderer11 *renderer, + const gl::DepthStencilState &dsState, + const d3d11::DepthStencilState **outDSState); + gl::Error getSamplerState(Renderer11 *renderer, + const gl::SamplerState &samplerState, + ID3D11SamplerState **outSamplerState); private: - Renderer11 *mRenderer; - unsigned long long mCounter; + // 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 + // TODO(ShahmeerEsmail): Revisit the cache sizes to make sure they are appropriate for most + // scenarios. + static constexpr unsigned int kMaxStates = 4096; + + // The cache tries to clean up this many states at once. + static constexpr unsigned int kGCLimit = 128; // 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; + using BlendStateMap = angle::base::HashingMRUCache; 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; + using RasterizerStateMap = + angle::base::HashingMRUCache; 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; + using DepthStencilStateMap = + angle::base::HashingMRUCache; 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; + using SamplerStateMap = angle::base::HashingMRUCache; SamplerStateMap mSamplerStateCache; - - ID3D11Device *mDevice; }; -} +} // namespace rx #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 index cdfcacc287..594a382a72 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/RenderTarget11.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/RenderTarget11.cpp @@ -18,7 +18,9 @@ namespace rx { -static bool getTextureProperties(ID3D11Resource *resource, unsigned int *mipLevels, unsigned int *samples) +namespace +{ +bool GetTextureProperties(ID3D11Resource *resource, unsigned int *mipLevels, unsigned int *samples) { ID3D11Texture1D *texture1D = d3d11::DynamicCastComObject(resource); if (texture1D) @@ -62,7 +64,7 @@ static bool getTextureProperties(ID3D11Resource *resource, unsigned int *mipLeve return false; } -static unsigned int getRTVSubresourceIndex(ID3D11Resource *resource, ID3D11RenderTargetView *view) +unsigned int GetRTVSubresourceIndex(ID3D11Resource *resource, ID3D11RenderTargetView *view) { D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; view->GetDesc(&rtvDesc); @@ -72,58 +74,58 @@ static unsigned int getRTVSubresourceIndex(ID3D11Resource *resource, ID3D11Rende 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; + 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); + GetTextureProperties(resource, &mipLevels, &samples); return D3D11CalcSubresource(mipSlice, arraySlice, mipLevels); } -static unsigned int getDSVSubresourceIndex(ID3D11Resource *resource, ID3D11DepthStencilView *view) +unsigned int GetDSVSubresourceIndex(ID3D11Resource *resource, ID3D11DepthStencilView *view) { D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc; view->GetDesc(&dsvDesc); @@ -133,157 +135,170 @@ static unsigned int getDSVSubresourceIndex(ID3D11Resource *resource, ID3D11Depth 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; + 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); + GetTextureProperties(resource, &mipLevels, &samples); return D3D11CalcSubresource(mipSlice, arraySlice, mipLevels); } -TextureRenderTarget11::TextureRenderTarget11(ID3D11RenderTargetView *rtv, ID3D11Resource *resource, ID3D11ShaderResourceView *srv, - GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLsizei samples) - : mWidth(width), +GLenum GetSurfaceRTFormat(bool depth, SwapChain11 *swapChain) +{ + return (depth ? swapChain->getDepthBufferInternalFormat() + : swapChain->getRenderTargetInternalFormat()); +} + +const d3d11::Format &GetSurfaceFormatSet(bool depth, SwapChain11 *swapChain, Renderer11 *renderer) +{ + return d3d11::Format::Get(GetSurfaceRTFormat(depth, swapChain), + renderer->getRenderer11DeviceCaps()); +} + +} // anonymous namespace + +RenderTarget11::RenderTarget11(const d3d11::Format &formatSet) : mFormatSet(formatSet) +{ +} + +RenderTarget11::~RenderTarget11() +{ + ASSERT(mBroadcastChannel.empty()); +} + +void RenderTarget11::signalDirty(const gl::Context *context) +{ + mBroadcastChannel.signal(context); + + // Clear the list. We can't do this in the receiver because it would mutate during iteration. + mBroadcastChannel.reset(); +} + +TextureRenderTarget11::TextureRenderTarget11(d3d11::RenderTargetView &&rtv, + const TextureHelper11 &resource, + const d3d11::SharedSRV &srv, + const d3d11::SharedSRV &blitSRV, + GLenum internalFormat, + const d3d11::Format &formatSet, + GLsizei width, + GLsizei height, + GLsizei depth, + GLsizei samples) + : RenderTarget11(formatSet), + mWidth(width), mHeight(height), mDepth(depth), mInternalFormat(internalFormat), - mDXGIFormat(DXGI_FORMAT_UNKNOWN), mSamples(samples), mSubresourceIndex(0), mTexture(resource), - mRenderTarget(rtv), - mDepthStencil(NULL), - mShaderResource(srv) + mRenderTarget(std::move(rtv)), + mDepthStencil(), + mShaderResource(srv.makeCopy()), + mBlitShaderResource(blitSRV.makeCopy()) { - if (mTexture) - { - mTexture->AddRef(); - } - - if (mRenderTarget) - { - mRenderTarget->AddRef(); - } - - if (mShaderResource) - { - mShaderResource->AddRef(); - } - - if (mRenderTarget && mTexture) + if (mRenderTarget.valid() && mTexture.valid()) { - mSubresourceIndex = getRTVSubresourceIndex(mTexture, mRenderTarget); - - D3D11_RENDER_TARGET_VIEW_DESC desc; - mRenderTarget->GetDesc(&desc); - mDXGIFormat = desc.Format; + mSubresourceIndex = GetRTVSubresourceIndex(mTexture.get(), mRenderTarget.get()); } + ASSERT(mFormatSet.formatID != angle::Format::ID::NONE || mWidth == 0 || mHeight == 0); } -TextureRenderTarget11::TextureRenderTarget11(ID3D11DepthStencilView *dsv, ID3D11Resource *resource, ID3D11ShaderResourceView *srv, - GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLsizei samples) - : mWidth(width), +TextureRenderTarget11::TextureRenderTarget11(d3d11::DepthStencilView &&dsv, + const TextureHelper11 &resource, + const d3d11::SharedSRV &srv, + GLenum internalFormat, + const d3d11::Format &formatSet, + GLsizei width, + GLsizei height, + GLsizei depth, + GLsizei samples) + : RenderTarget11(formatSet), + mWidth(width), mHeight(height), mDepth(depth), mInternalFormat(internalFormat), - mDXGIFormat(DXGI_FORMAT_UNKNOWN), mSamples(samples), mSubresourceIndex(0), mTexture(resource), - mRenderTarget(NULL), - mDepthStencil(dsv), - mShaderResource(srv) + mRenderTarget(), + mDepthStencil(std::move(dsv)), + mShaderResource(srv.makeCopy()), + mBlitShaderResource() { - if (mTexture) + if (mDepthStencil.valid() && mTexture.valid()) { - 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; + mSubresourceIndex = GetDSVSubresourceIndex(mTexture.get(), mDepthStencil.get()); } + ASSERT(mFormatSet.formatID != angle::Format::ID::NONE || mWidth == 0 || mHeight == 0); } TextureRenderTarget11::~TextureRenderTarget11() { - SafeRelease(mTexture); - SafeRelease(mRenderTarget); - SafeRelease(mDepthStencil); - SafeRelease(mShaderResource); } -ID3D11Resource *TextureRenderTarget11::getTexture() const +const TextureHelper11 &TextureRenderTarget11::getTexture() const { return mTexture; } -ID3D11RenderTargetView *TextureRenderTarget11::getRenderTargetView() const +const d3d11::RenderTargetView &TextureRenderTarget11::getRenderTargetView() const { return mRenderTarget; } -ID3D11DepthStencilView *TextureRenderTarget11::getDepthStencilView() const +const d3d11::DepthStencilView &TextureRenderTarget11::getDepthStencilView() const { return mDepthStencil; } -ID3D11ShaderResourceView *TextureRenderTarget11::getShaderResourceView() const +const d3d11::SharedSRV &TextureRenderTarget11::getShaderResourceView() const { return mShaderResource; } +const d3d11::SharedSRV &TextureRenderTarget11::getBlitShaderResourceView() const +{ + return mBlitShaderResource; +} + GLsizei TextureRenderTarget11::getWidth() const { return mWidth; @@ -314,14 +329,11 @@ 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), +SurfaceRenderTarget11::SurfaceRenderTarget11(SwapChain11 *swapChain, + Renderer11 *renderer, + bool depth) + : RenderTarget11(GetSurfaceFormatSet(depth, swapChain, renderer)), + mSwapChain(swapChain), mDepth(depth) { ASSERT(mSwapChain); @@ -348,43 +360,46 @@ GLsizei SurfaceRenderTarget11::getDepth() const GLenum SurfaceRenderTarget11::getInternalFormat() const { - return (mDepth ? mSwapChain->GetDepthBufferInternalFormat() : mSwapChain->GetRenderTargetInternalFormat()); + return GetSurfaceRTFormat(mDepth, mSwapChain); } GLsizei SurfaceRenderTarget11::getSamples() const { - // Our EGL surfaces do not support multisampling. - return 0; + return mSwapChain->getSamples(); } -ID3D11Resource *SurfaceRenderTarget11::getTexture() const +const TextureHelper11 &SurfaceRenderTarget11::getTexture() const { return (mDepth ? mSwapChain->getDepthStencilTexture() : mSwapChain->getOffscreenTexture()); } -ID3D11RenderTargetView *SurfaceRenderTarget11::getRenderTargetView() const +const d3d11::RenderTargetView &SurfaceRenderTarget11::getRenderTargetView() const { - return (mDepth ? NULL : mSwapChain->getRenderTarget()); + ASSERT(!mDepth); + return mSwapChain->getRenderTarget(); } -ID3D11DepthStencilView *SurfaceRenderTarget11::getDepthStencilView() const +const d3d11::DepthStencilView &SurfaceRenderTarget11::getDepthStencilView() const { - return (mDepth ? mSwapChain->getDepthStencil() : NULL); + ASSERT(mDepth); + return mSwapChain->getDepthStencil(); } -ID3D11ShaderResourceView *SurfaceRenderTarget11::getShaderResourceView() const +const d3d11::SharedSRV &SurfaceRenderTarget11::getShaderResourceView() const { - return (mDepth ? mSwapChain->getDepthStencilShaderResource() : mSwapChain->getRenderTargetShaderResource()); + return (mDepth ? mSwapChain->getDepthStencilShaderResource() + : mSwapChain->getRenderTargetShaderResource()); } -unsigned int SurfaceRenderTarget11::getSubresourceIndex() const +const d3d11::SharedSRV &SurfaceRenderTarget11::getBlitShaderResourceView() const { - return 0; + // The SurfaceRenderTargetView format should always be such that the normal SRV works for blits. + return getShaderResourceView(); } -DXGI_FORMAT SurfaceRenderTarget11::getDXGIFormat() const +unsigned int SurfaceRenderTarget11::getSubresourceIndex() const { - return d3d11::GetTextureFormatInfo(getInternalFormat(), mRenderer->getRenderer11DeviceCaps()).texFormat; + return 0; } -} +} // namespace rx diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/RenderTarget11.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/RenderTarget11.h index d47b237c09..db49cac9f5 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/RenderTarget11.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/RenderTarget11.h @@ -11,6 +11,9 @@ #define LIBANGLE_RENDERER_D3D_D3D11_RENDERTARGET11_H_ #include "libANGLE/renderer/d3d/RenderTargetD3D.h" +#include "libANGLE/renderer/d3d/d3d11/ResourceManager11.h" +#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h" +#include "libANGLE/renderer/d3d/d3d11/texture_format_table.h" namespace rx { @@ -20,28 +23,51 @@ class Renderer11; class RenderTarget11 : public RenderTargetD3D { public: - RenderTarget11() { } - virtual ~RenderTarget11() { } + RenderTarget11(const d3d11::Format &formatSet); + ~RenderTarget11() override; - virtual ID3D11Resource *getTexture() const = 0; - virtual ID3D11RenderTargetView *getRenderTargetView() const = 0; - virtual ID3D11DepthStencilView *getDepthStencilView() const = 0; - virtual ID3D11ShaderResourceView *getShaderResourceView() const = 0; + virtual const TextureHelper11 &getTexture() const = 0; + virtual const d3d11::RenderTargetView &getRenderTargetView() const = 0; + virtual const d3d11::DepthStencilView &getDepthStencilView() const = 0; + virtual const d3d11::SharedSRV &getShaderResourceView() const = 0; + virtual const d3d11::SharedSRV &getBlitShaderResourceView() const = 0; virtual unsigned int getSubresourceIndex() const = 0; - virtual DXGI_FORMAT getDXGIFormat() const = 0; + void signalDirty(const gl::Context *context) override; + OnRenderTargetDirtyChannel *getBroadcastChannel() { return &mBroadcastChannel; } + + const d3d11::Format &getFormatSet() const { return mFormatSet; } + + protected: + OnRenderTargetDirtyChannel mBroadcastChannel; + const d3d11::Format &mFormatSet; }; 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(); + TextureRenderTarget11(d3d11::RenderTargetView &&rtv, + const TextureHelper11 &resource, + const d3d11::SharedSRV &srv, + const d3d11::SharedSRV &blitSRV, + GLenum internalFormat, + const d3d11::Format &formatSet, + GLsizei width, + GLsizei height, + GLsizei depth, + GLsizei samples); + TextureRenderTarget11(d3d11::DepthStencilView &&dsv, + const TextureHelper11 &resource, + const d3d11::SharedSRV &srv, + GLenum internalFormat, + const d3d11::Format &formatSet, + GLsizei width, + GLsizei height, + GLsizei depth, + GLsizei samples); + ~TextureRenderTarget11() override; GLsizei getWidth() const override; GLsizei getHeight() const override; @@ -49,35 +75,37 @@ class TextureRenderTarget11 : public RenderTarget11 GLenum getInternalFormat() const override; GLsizei getSamples() const override; - ID3D11Resource *getTexture() const override; - ID3D11RenderTargetView *getRenderTargetView() const override; - ID3D11DepthStencilView *getDepthStencilView() const override; - ID3D11ShaderResourceView *getShaderResourceView() const override; + const TextureHelper11 &getTexture() const override; + const d3d11::RenderTargetView &getRenderTargetView() const override; + const d3d11::DepthStencilView &getDepthStencilView() const override; + const d3d11::SharedSRV &getShaderResourceView() const override; + const d3d11::SharedSRV &getBlitShaderResourceView() 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; + TextureHelper11 mTexture; + d3d11::RenderTargetView mRenderTarget; + d3d11::DepthStencilView mDepthStencil; + d3d11::SharedSRV mShaderResource; + + // Shader resource view to use with internal blit shaders. Not set for depth/stencil render + // targets. + d3d11::SharedSRV mBlitShaderResource; }; class SurfaceRenderTarget11 : public RenderTarget11 { public: SurfaceRenderTarget11(SwapChain11 *swapChain, Renderer11 *renderer, bool depth); - virtual ~SurfaceRenderTarget11(); + ~SurfaceRenderTarget11() override; GLsizei getWidth() const override; GLsizei getHeight() const override; @@ -85,21 +113,19 @@ class SurfaceRenderTarget11 : public RenderTarget11 GLenum getInternalFormat() const override; GLsizei getSamples() const override; - ID3D11Resource *getTexture() const override; - ID3D11RenderTargetView *getRenderTargetView() const override; - ID3D11DepthStencilView *getDepthStencilView() const override; - ID3D11ShaderResourceView *getShaderResourceView() const override; + const TextureHelper11 &getTexture() const override; + const d3d11::RenderTargetView &getRenderTargetView() const override; + const d3d11::DepthStencilView &getDepthStencilView() const override; + const d3d11::SharedSRV &getShaderResourceView() const override; + const d3d11::SharedSRV &getBlitShaderResourceView() const override; unsigned int getSubresourceIndex() const override; - DXGI_FORMAT getDXGIFormat() const override; - private: SwapChain11 *mSwapChain; - Renderer11 *mRenderer; bool mDepth; }; -} +} // namespace rx #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 index 5118bdbe9c..b0ef9abddc 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp @@ -9,56 +9,64 @@ #include "libANGLE/renderer/d3d/d3d11/Renderer11.h" #include +#include #include -#if !defined(ANGLE_MINGW32_COMPAT) && WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP -#include -#endif #include "common/tls.h" #include "common/utilities.h" #include "libANGLE/Buffer.h" +#include "libANGLE/Context.h" #include "libANGLE/Display.h" -#include "libANGLE/formatutils.h" #include "libANGLE/Framebuffer.h" #include "libANGLE/FramebufferAttachment.h" -#include "libANGLE/histogram_macros.h" #include "libANGLE/Program.h" +#include "libANGLE/State.h" +#include "libANGLE/Surface.h" +#include "libANGLE/formatutils.h" +#include "libANGLE/histogram_macros.h" #include "libANGLE/renderer/d3d/CompilerD3D.h" +#include "libANGLE/renderer/d3d/DeviceD3D.h" +#include "libANGLE/renderer/d3d/DisplayD3D.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/VertexDataManager.h" #include "libANGLE/renderer/d3d/d3d11/Blit11.h" #include "libANGLE/renderer/d3d/d3d11/Buffer11.h" #include "libANGLE/renderer/d3d/d3d11/Clear11.h" -#include "libANGLE/renderer/d3d/d3d11/dxgi_support_table.h" +#include "libANGLE/renderer/d3d/d3d11/Context11.h" #include "libANGLE/renderer/d3d/d3d11/Fence11.h" -#include "libANGLE/renderer/d3d/d3d11/formatutils11.h" #include "libANGLE/renderer/d3d/d3d11/Framebuffer11.h" #include "libANGLE/renderer/d3d/d3d11/Image11.h" #include "libANGLE/renderer/d3d/d3d11/IndexBuffer11.h" #include "libANGLE/renderer/d3d/d3d11/PixelTransfer11.h" #include "libANGLE/renderer/d3d/d3d11/Query11.h" -#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h" #include "libANGLE/renderer/d3d/d3d11/RenderTarget11.h" #include "libANGLE/renderer/d3d/d3d11/ShaderExecutable11.h" +#include "libANGLE/renderer/d3d/d3d11/StreamProducerNV12.h" #include "libANGLE/renderer/d3d/d3d11/SwapChain11.h" -#include "libANGLE/renderer/d3d/d3d11/texture_format_table.h" #include "libANGLE/renderer/d3d/d3d11/TextureStorage11.h" +#include "libANGLE/renderer/d3d/d3d11/TransformFeedback11.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/CompilerD3D.h" -#include "libANGLE/renderer/d3d/DeviceD3D.h" -#include "libANGLE/renderer/d3d/FramebufferD3D.h" -#include "libANGLE/renderer/d3d/IndexDataManager.h" -#include "libANGLE/renderer/d3d/ProgramD3D.h" -#include "libANGLE/renderer/d3d/RenderbufferD3D.h" -#include "libANGLE/renderer/d3d/ShaderD3D.h" -#include "libANGLE/renderer/d3d/SurfaceD3D.h" -#include "libANGLE/renderer/d3d/TextureD3D.h" -#include "libANGLE/renderer/d3d/TransformFeedbackD3D.h" -#include "libANGLE/renderer/d3d/VertexDataManager.h" -#include "libANGLE/State.h" -#include "libANGLE/Surface.h" +#include "libANGLE/renderer/d3d/d3d11/dxgi_support_table.h" +#include "libANGLE/renderer/d3d/d3d11/formatutils11.h" +#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h" +#include "libANGLE/renderer/d3d/d3d11/texture_format_table.h" +#include "libANGLE/renderer/renderer_utils.h" #include "third_party/trace_event/trace_event.h" +#ifdef ANGLE_ENABLE_WINDOWS_STORE +#include "libANGLE/renderer/d3d/d3d11/winrt/NativeWindow11WinRT.h" +#else +#include "libANGLE/renderer/d3d/d3d11/win32/NativeWindow11Win32.h" +#endif + // Include the D3D9 debug annotator header for use by the desktop D3D11 renderer // because the D3D11 interface method ID3DUserDefinedAnnotation::GetStatus // doesn't work with the Graphics Diagnostics tools in Visual Studio 2013. @@ -72,12 +80,6 @@ #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 - namespace rx { @@ -89,25 +91,6 @@ enum MAX_TEXTURE_IMAGE_UNITS_VTF_SM4 = 16 }; -#if defined(ANGLE_ENABLE_D3D11_1) -void CalculateConstantBufferParams(GLintptr offset, GLsizeiptr size, UINT *outFirstConstant, UINT *outNumConstants) -{ - // The offset must be aligned to 256 bytes (should have been enforced by glBindBufferRange). - ASSERT(offset % 256 == 0); - - // firstConstant and numConstants are expressed in constants of 16-bytes. Furthermore they must be a multiple of 16 constants. - *outFirstConstant = static_cast(offset / 16); - - // The GL size is not required to be aligned to a 256 bytes boundary. - // Round the size up to a 256 bytes boundary then express the results in constants of 16-bytes. - *outNumConstants = static_cast(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 -} -#endif - enum ANGLEFeatureLevel { ANGLE_FEATURE_LEVEL_INVALID, @@ -123,14 +106,18 @@ ANGLEFeatureLevel GetANGLEFeatureLevel(D3D_FEATURE_LEVEL d3dFeatureLevel) { switch (d3dFeatureLevel) { - case D3D_FEATURE_LEVEL_9_3: return ANGLE_FEATURE_LEVEL_9_3; - case D3D_FEATURE_LEVEL_10_0: return ANGLE_FEATURE_LEVEL_10_0; - case D3D_FEATURE_LEVEL_10_1: return ANGLE_FEATURE_LEVEL_10_1; - case D3D_FEATURE_LEVEL_11_0: return ANGLE_FEATURE_LEVEL_11_0; - // Note: we don't ever request a 11_1 device, because this gives - // an E_INVALIDARG error on systems that don't have the platform update. - case D3D_FEATURE_LEVEL_11_1: return ANGLE_FEATURE_LEVEL_11_1; - default: return ANGLE_FEATURE_LEVEL_INVALID; + case D3D_FEATURE_LEVEL_9_3: + return ANGLE_FEATURE_LEVEL_9_3; + case D3D_FEATURE_LEVEL_10_0: + return ANGLE_FEATURE_LEVEL_10_0; + case D3D_FEATURE_LEVEL_10_1: + return ANGLE_FEATURE_LEVEL_10_1; + case D3D_FEATURE_LEVEL_11_0: + return ANGLE_FEATURE_LEVEL_11_0; + case D3D_FEATURE_LEVEL_11_1: + return ANGLE_FEATURE_LEVEL_11_1; + default: + return ANGLE_FEATURE_LEVEL_INVALID; } } @@ -144,7 +131,7 @@ void SetLineLoopIndices(GLuint *dest, size_t count) } template -void CopyLineLoopIndices(const GLvoid *indices, GLuint *dest, size_t count) +void CopyLineLoopIndices(const void *indices, GLuint *dest, size_t count) { const T *srcPtr = static_cast(indices); for (size_t i = 0; i < count; ++i) @@ -165,7 +152,7 @@ void SetTriangleFanIndices(GLuint *destPtr, size_t numTris) } template -void CopyLineLoopIndicesWithRestart(const GLvoid *indices, +void CopyLineLoopIndicesWithRestart(const void *indices, size_t count, GLenum indexType, std::vector *bufferOut) @@ -206,7 +193,7 @@ void CopyLineLoopIndicesWithRestart(const GLvoid *indices, } } -void GetLineLoopIndices(const GLvoid *indices, +void GetLineLoopIndices(const void *indices, GLenum indexType, GLuint count, bool usePrimitiveRestartFixedIndex, @@ -257,7 +244,7 @@ void GetLineLoopIndices(const GLvoid *indices, } template -void CopyTriangleFanIndices(const GLvoid *indices, GLuint *destPtr, size_t numTris) +void CopyTriangleFanIndices(const void *indices, GLuint *destPtr, size_t numTris) { const T *srcPtr = static_cast(indices); @@ -270,7 +257,7 @@ void CopyTriangleFanIndices(const GLvoid *indices, GLuint *destPtr, size_t numTr } template -void CopyTriangleFanIndicesWithRestart(const GLvoid *indices, +void CopyTriangleFanIndicesWithRestart(const void *indices, GLuint indexCount, GLenum indexType, std::vector *bufferOut) @@ -314,7 +301,7 @@ void CopyTriangleFanIndicesWithRestart(const GLvoid *indices, } } -void GetTriFanIndices(const GLvoid *indices, +void GetTriFanIndices(const void *indices, GLenum indexType, GLuint count, bool usePrimitiveRestartFixedIndex, @@ -365,60 +352,135 @@ void GetTriFanIndices(const GLvoid *indices, } } +bool DrawCallNeedsTranslation(const gl::Context *context, GLenum mode) +{ + const auto &glState = context->getGLState(); + const gl::VertexArray *vertexArray = glState.getVertexArray(); + VertexArray11 *vertexArray11 = GetImplAs(vertexArray); + // Direct drawing doesn't support dynamic attribute storage since it needs the first and count + // to translate when applyVertexBuffer. GL_LINE_LOOP and GL_TRIANGLE_FAN are not supported + // either since we need to simulate them in D3D. + if (vertexArray11->hasActiveDynamicAttrib(context) || mode == GL_LINE_LOOP || + mode == GL_TRIANGLE_FAN) + { + return true; + } + + ProgramD3D *programD3D = GetImplAs(glState.getProgram()); + if (InstancedPointSpritesActive(programD3D, mode)) + { + return true; + } + + return false; +} + +bool IsArrayRTV(ID3D11RenderTargetView *rtv) +{ + D3D11_RENDER_TARGET_VIEW_DESC desc; + rtv->GetDesc(&desc); + if (desc.ViewDimension == D3D11_RTV_DIMENSION_TEXTURE1DARRAY && + desc.Texture1DArray.ArraySize > 1) + return true; + if (desc.ViewDimension == D3D11_RTV_DIMENSION_TEXTURE2DARRAY && + desc.Texture2DArray.ArraySize > 1) + return true; + if (desc.ViewDimension == D3D11_RTV_DIMENSION_TEXTURE2DMSARRAY && + desc.Texture2DMSArray.ArraySize > 1) + return true; + return false; +} + +int GetAdjustedInstanceCount(const gl::Program *program, int instanceCount) +{ + if (!program->usesMultiview()) + { + return instanceCount; + } + if (instanceCount == 0) + { + return program->getNumViews(); + } + return program->getNumViews() * instanceCount; +} + +const uint32_t ScratchMemoryBufferLifetime = 1000; + +void PopulateFormatDeviceCaps(ID3D11Device *device, + DXGI_FORMAT format, + UINT *outSupport, + UINT *outMaxSamples) +{ + if (FAILED(device->CheckFormatSupport(format, outSupport))) + { + *outSupport = 0; + } + + *outMaxSamples = 0; + for (UINT sampleCount = 2; sampleCount <= D3D11_MAX_MULTISAMPLE_SAMPLE_COUNT; sampleCount *= 2) + { + UINT qualityCount = 0; + if (FAILED(device->CheckMultisampleQualityLevels(format, sampleCount, &qualityCount)) || + qualityCount == 0) + { + break; + } + + *outMaxSamples = sampleCount; + } +} + +bool CullsEverything(const gl::State &glState) +{ + return (glState.getRasterizerState().cullFace && + glState.getRasterizerState().cullMode == gl::CullFaceMode::FrontAndBack); +} + } // anonymous namespace +Renderer11DeviceCaps::Renderer11DeviceCaps() = default; + Renderer11::Renderer11(egl::Display *display) : RendererD3D(display), - mStateCache(this), + mCreateDebugDevice(false), + mStateCache(), mStateManager(this), - mLastHistogramUpdateTime(ANGLEPlatformCurrent()->monotonicallyIncreasingTime()) -#if !defined(ANGLE_MINGW32_COMPAT) - ,mDebug(nullptr) -#endif + mLastHistogramUpdateTime( + ANGLEPlatformCurrent()->monotonicallyIncreasingTime(ANGLEPlatformCurrent())), + mDebug(nullptr), + mScratchMemoryBuffer(ScratchMemoryBufferLifetime), + mAnnotator(nullptr) { - mVertexDataManager = NULL; - mIndexDataManager = NULL; - - mLineLoopIB = NULL; - mTriangleFanIB = NULL; - mAppliedIBChanged = false; + mLineLoopIB = nullptr; + mTriangleFanIB = nullptr; - mBlit = NULL; - mPixelTransfer = NULL; + mBlit = nullptr; + mPixelTransfer = nullptr; - mClear = NULL; + mClear = nullptr; - mTrim = NULL; + mTrim = nullptr; - mSyncQuery = NULL; - - mRenderer11DeviceCaps.supportsClearView = false; + mRenderer11DeviceCaps.supportsClearView = false; mRenderer11DeviceCaps.supportsConstantBufferOffsets = false; - mRenderer11DeviceCaps.supportsDXGI1_2 = false; - mRenderer11DeviceCaps.B5G6R5support = 0; - mRenderer11DeviceCaps.B4G4R4A4support = 0; - mRenderer11DeviceCaps.B5G5R5A1support = 0; - - mD3d11Module = NULL; - mDxgiModule = NULL; - mDCompModule = NULL; + mRenderer11DeviceCaps.supportsVpRtIndexWriteFromVertexShader = false; + mRenderer11DeviceCaps.supportsDXGI1_2 = false; + mRenderer11DeviceCaps.B5G6R5support = 0; + mRenderer11DeviceCaps.B4G4R4A4support = 0; + mRenderer11DeviceCaps.B5G5R5A1support = 0; + + mD3d11Module = nullptr; + mDxgiModule = nullptr; + mDCompModule = nullptr; mCreatedWithDeviceEXT = false; mEGLDevice = nullptr; - mDevice = NULL; - mDeviceContext = NULL; - mDeviceContext1 = NULL; - mDxgiAdapter = NULL; - mDxgiFactory = NULL; - - mDriverConstantBufferVS = NULL; - mDriverConstantBufferPS = NULL; - - mAppliedVertexShader = NULL; - mAppliedGeometryShader = NULL; - mAppliedPixelShader = NULL; - - mAppliedNumXFBBindings = static_cast(-1); + mDevice = nullptr; + mDeviceContext = nullptr; + mDeviceContext1 = nullptr; + mDeviceContext3 = nullptr; + mDxgiAdapter = nullptr; + mDxgiFactory = nullptr; ZeroMemory(&mAdapterDescription, sizeof(mAdapterDescription)); @@ -426,13 +488,21 @@ Renderer11::Renderer11(egl::Display *display) { 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); + EGLint requestedMajorVersion = static_cast( + attributes.get(EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE, EGL_DONT_CARE)); + EGLint requestedMinorVersion = static_cast( + 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 >= 1) + { + // This could potentially lead to failed context creation if done on a system + // without the platform update which installs DXGI 1.2. Currently, for Chrome users + // D3D11 contexts are only created if the platform update is available, so this + // should not cause any issues. + mAvailableFeatureLevels.push_back(D3D_FEATURE_LEVEL_11_1); + } if (requestedMinorVersion == EGL_DONT_CARE || requestedMinorVersion >= 0) { mAvailableFeatureLevels.push_back(D3D_FEATURE_LEVEL_11_0); @@ -451,11 +521,7 @@ Renderer11::Renderer11(egl::Display *display) } } -#if defined(ANGLE_ENABLE_WINDOWS_STORE) - if (requestedMajorVersion == EGL_DONT_CARE || requestedMajorVersion >= 9) -#else if (requestedMajorVersion == 9 && requestedMinorVersion == 3) -#endif { if (requestedMinorVersion == EGL_DONT_CARE || requestedMinorVersion >= 3) { @@ -473,8 +539,8 @@ Renderer11::Renderer11(egl::Display *display) #endif } - EGLint requestedDeviceType = attributes.get(EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE, - EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE); + EGLint requestedDeviceType = static_cast(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: @@ -497,9 +563,11 @@ Renderer11::Renderer11(egl::Display *display) UNREACHABLE(); } - const EGLenum presentPath = attributes.get(EGL_EXPERIMENTAL_PRESENT_PATH_ANGLE, - EGL_EXPERIMENTAL_PRESENT_PATH_COPY_ANGLE); + const EGLenum presentPath = static_cast(attributes.get( + EGL_EXPERIMENTAL_PRESENT_PATH_ANGLE, EGL_EXPERIMENTAL_PRESENT_PATH_COPY_ANGLE)); mPresentPathFastEnabled = (presentPath == EGL_EXPERIMENTAL_PRESENT_PATH_FAST_ANGLE); + + mCreateDebugDevice = ShouldUseDebugLayers(attributes); } else if (display->getPlatform() == EGL_PLATFORM_DEVICE_EXT) { @@ -509,11 +577,22 @@ Renderer11::Renderer11(egl::Display *display) // Also set EGL_PLATFORM_ANGLE_ANGLE variables, in case they're used elsewhere in ANGLE // mAvailableFeatureLevels defaults to empty - mRequestedDriverType = D3D_DRIVER_TYPE_UNKNOWN; + mRequestedDriverType = D3D_DRIVER_TYPE_UNKNOWN; mPresentPathFastEnabled = false; } - initializeDebugAnnotator(); +// The D3D11 renderer must choose the D3D9 debug annotator because the D3D11 interface +// method ID3DUserDefinedAnnotation::GetStatus on desktop builds doesn't work with the Graphics +// Diagnostics tools in Visual Studio 2013. +// The D3D9 annotator works properly for both D3D11 and D3D9. +// Incorrect status reporting can cause ANGLE to log unnecessary debug events. +#ifdef ANGLE_ENABLE_D3D9 + mAnnotator = new DebugAnnotator9(); +#else + mAnnotator = new DebugAnnotator11(); +#endif + ASSERT(mAnnotator); + gl::InitializeDebugAnnotations(mAnnotator); } Renderer11::~Renderer11() @@ -529,20 +608,17 @@ egl::Error Renderer11::initialize() { HRESULT result = S_OK; - egl::Error error = initializeD3DDevice(); - if (error.isError()) - { - return error; - } + ANGLE_TRY(initializeD3DDevice()); #if !defined(ANGLE_ENABLE_WINDOWS_STORE) #if !ANGLE_SKIP_DXGI_1_2_CHECK { TRACE_EVENT0("gpu.angle", "Renderer11::initialize (DXGICheck)"); - // In order to create a swap chain for an HWND owned by another process, DXGI 1.2 is required. + // 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()); + HWND hwnd = WindowFromDC(mDisplay->getNativeDisplayId()); if (hwnd) { DWORD currentProcessId = GetCurrentProcessId(); @@ -557,13 +633,12 @@ egl::Error Renderer11::initialize() if (requireDXGI1_2) { - IDXGIDevice2 *dxgiDevice2 = NULL; - result = mDevice->QueryInterface(__uuidof(IDXGIDevice2), (void**)&dxgiDevice2); + IDXGIDevice2 *dxgiDevice2 = nullptr; + 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."); + return egl::EglNotInitialized(D3D11_INIT_INCOMPATIBLE_DXGI) + << "DXGI 1.2 required to present to HWNDs owned by another process."; } SafeRelease(dxgiDevice2); } @@ -573,90 +648,83 @@ egl::Error Renderer11::initialize() { TRACE_EVENT0("gpu.angle", "Renderer11::initialize (ComQueries)"); - // Cast the DeviceContext to a DeviceContext1. + // Cast the DeviceContext to a DeviceContext1 and DeviceContext3. // 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) + // Don't error in this case- just don't use mDeviceContext1 or mDeviceContext3. mDeviceContext1 = d3d11::DynamicCastComObject(mDeviceContext); -#endif + mDeviceContext3 = d3d11::DynamicCastComObject(mDeviceContext); - IDXGIDevice *dxgiDevice = NULL; - result = mDevice->QueryInterface(__uuidof(IDXGIDevice), (void**)&dxgiDevice); + IDXGIDevice *dxgiDevice = nullptr; + 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."); + return egl::EglNotInitialized(D3D11_INIT_OTHER_ERROR) << "Could not query DXGI device."; } - result = dxgiDevice->GetParent(__uuidof(IDXGIAdapter), (void**)&mDxgiAdapter); + 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"); + return egl::EglNotInitialized(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 (mRenderer11DeviceCaps.featureLevel <= D3D_FEATURE_LEVEL_9_3 && dxgiAdapter2 != NULL) + // On D3D_FEATURE_LEVEL_9_*, IDXGIAdapter::GetDesc returns "Software Adapter" for the + // description string. + // If DXGI1.2 is available then IDXGIAdapter2::GetDesc2 can be used to get the actual + // hardware values. + if (mRenderer11DeviceCaps.featureLevel <= D3D_FEATURE_LEVEL_9_3 && dxgiAdapter2 != nullptr) { DXGI_ADAPTER_DESC2 adapterDesc2 = {}; - result = dxgiAdapter2->GetDesc2(&adapterDesc2); + result = dxgiAdapter2->GetDesc2(&adapterDesc2); if (SUCCEEDED(result)) { - // Copy the contents of the DXGI_ADAPTER_DESC2 into mAdapterDescription (a DXGI_ADAPTER_DESC). - memcpy(mAdapterDescription.Description, adapterDesc2.Description, sizeof(mAdapterDescription.Description)); - mAdapterDescription.VendorId = adapterDesc2.VendorId; - mAdapterDescription.DeviceId = adapterDesc2.DeviceId; - mAdapterDescription.SubSysId = adapterDesc2.SubSysId; - mAdapterDescription.Revision = adapterDesc2.Revision; - mAdapterDescription.DedicatedVideoMemory = adapterDesc2.DedicatedVideoMemory; + // 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; + mAdapterDescription.SharedSystemMemory = adapterDesc2.SharedSystemMemory; + mAdapterDescription.AdapterLuid = adapterDesc2.AdapterLuid; } } else -#endif { result = mDxgiAdapter->GetDesc(&mAdapterDescription); } -#if defined(ANGLE_ENABLE_D3D11_1) SafeRelease(dxgiAdapter2); -#endif if (FAILED(result)) { - return egl::Error(EGL_NOT_INITIALIZED, - D3D11_INIT_OTHER_ERROR, - "Could not read DXGI adaptor description."); + return egl::EglNotInitialized(D3D11_INIT_OTHER_ERROR) + << "Could not read DXGI adaptor description."; } memset(mDescription, 0, sizeof(mDescription)); wcstombs(mDescription, mAdapterDescription.Description, sizeof(mDescription) - 1); - result = mDxgiAdapter->GetParent(__uuidof(IDXGIFactory), (void**)&mDxgiFactory); + 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."); + return egl::EglNotInitialized(D3D11_INIT_OTHER_ERROR) + << "Could not create DXGI factory."; } } -#if !defined(ANGLE_MINGW32_COMPAT) // Disable some spurious D3D11 debug warnings to prevent them from flooding the output log -#if defined(ANGLE_SUPPRESS_D3D11_HAZARD_WARNINGS) && defined(_DEBUG) + if (mCreateDebugDevice) { TRACE_EVENT0("gpu.angle", "Renderer11::initialize (HideWarnings)"); ID3D11InfoQueue *infoQueue; @@ -664,29 +732,33 @@ egl::Error Renderer11::initialize() if (SUCCEEDED(result)) { - D3D11_MESSAGE_ID hideMessages[] = - { - D3D11_MESSAGE_ID_DEVICE_DRAW_RENDERTARGETVIEW_NOT_SET - }; + D3D11_MESSAGE_ID hideMessages[] = { + D3D11_MESSAGE_ID_DEVICE_DRAW_RENDERTARGETVIEW_NOT_SET}; D3D11_INFO_QUEUE_FILTER filter = {}; filter.DenyList.NumIDs = static_cast(ArraySize(hideMessages)); - filter.DenyList.pIDList = hideMessages; + filter.DenyList.pIDList = hideMessages; infoQueue->AddStorageFilterEntries(&filter); SafeRelease(infoQueue); } } -#endif #if !defined(NDEBUG) mDebug = d3d11::DynamicCastComObject(mDevice); #endif -#endif // !ANGLE_MINGW32_COMPAT - initializeDevice(); + ANGLE_TRY(initializeDevice()); + + return egl::NoError(); +} - return egl::Error(EGL_SUCCESS); +HRESULT Renderer11::callD3D11CreateDevice(PFN_D3D11_CREATE_DEVICE createDevice, bool debug) +{ + return createDevice( + nullptr, mRequestedDriverType, nullptr, debug ? D3D11_CREATE_DEVICE_DEBUG : 0, + mAvailableFeatureLevels.data(), static_cast(mAvailableFeatureLevels.size()), + D3D11_SDK_VERSION, &mDevice, &(mRenderer11DeviceCaps.featureLevel), &mDeviceContext); } egl::Error Renderer11::initializeD3DDevice() @@ -706,8 +778,8 @@ egl::Error Renderer11::initializeD3DDevice() if (mD3d11Module == nullptr || mDxgiModule == nullptr) { - return egl::Error(EGL_NOT_INITIALIZED, D3D11_INIT_MISSING_DEP, - "Could not load D3D11 or DXGI library."); + return egl::EglNotInitialized(D3D11_INIT_MISSING_DEP) + << "Could not load D3D11 or DXGI library."; } // create the D3D11 device @@ -717,68 +789,76 @@ egl::Error Renderer11::initializeD3DDevice() if (D3D11CreateDevice == nullptr) { - return egl::Error(EGL_NOT_INITIALIZED, D3D11_INIT_MISSING_DEP, - "Could not retrieve D3D11CreateDevice address."); + return egl::EglNotInitialized(D3D11_INIT_MISSING_DEP) + << "Could not retrieve D3D11CreateDevice address."; } } #endif -#ifdef _DEBUG + if (mCreateDebugDevice) { TRACE_EVENT0("gpu.angle", "D3D11CreateDevice (Debug)"); - result = D3D11CreateDevice(nullptr, mRequestedDriverType, nullptr, - D3D11_CREATE_DEVICE_DEBUG, mAvailableFeatureLevels.data(), - static_cast(mAvailableFeatureLevels.size()), - D3D11_SDK_VERSION, &mDevice, - &(mRenderer11DeviceCaps.featureLevel), &mDeviceContext); - } + result = callD3D11CreateDevice(D3D11CreateDevice, true); - if (!mDevice || FAILED(result)) - { - ERR("Failed creating Debug D3D11 device - falling back to release runtime.\n"); + if (result == E_INVALIDARG && mAvailableFeatureLevels.size() > 1u && + mAvailableFeatureLevels[0] == D3D_FEATURE_LEVEL_11_1) + { + // On older Windows platforms, D3D11.1 is not supported which returns E_INVALIDARG. + // Try again without passing D3D_FEATURE_LEVEL_11_1 in case we have other feature + // levels to fall back on. + mAvailableFeatureLevels.erase(mAvailableFeatureLevels.begin()); + result = callD3D11CreateDevice(D3D11CreateDevice, true); + } + + if (!mDevice || FAILED(result)) + { + WARN() << "Failed creating Debug D3D11 device - falling back to release runtime."; + } } if (!mDevice || FAILED(result)) -#endif { SCOPED_ANGLE_HISTOGRAM_TIMER("GPU.ANGLE.D3D11CreateDeviceMS"); TRACE_EVENT0("gpu.angle", "D3D11CreateDevice"); - result = D3D11CreateDevice( - nullptr, mRequestedDriverType, nullptr, 0, mAvailableFeatureLevels.data(), - static_cast(mAvailableFeatureLevels.size()), D3D11_SDK_VERSION, - &mDevice, &(mRenderer11DeviceCaps.featureLevel), &mDeviceContext); + result = callD3D11CreateDevice(D3D11CreateDevice, false); + + if (result == E_INVALIDARG && mAvailableFeatureLevels.size() > 1u && + mAvailableFeatureLevels[0] == D3D_FEATURE_LEVEL_11_1) + { + // On older Windows platforms, D3D11.1 is not supported which returns E_INVALIDARG. + // Try again without passing D3D_FEATURE_LEVEL_11_1 in case we have other feature + // levels to fall back on. + mAvailableFeatureLevels.erase(mAvailableFeatureLevels.begin()); + result = callD3D11CreateDevice(D3D11CreateDevice, false); + } // Cleanup done by destructor if (!mDevice || FAILED(result)) { ANGLE_HISTOGRAM_SPARSE_SLOWLY("GPU.ANGLE.D3D11CreateDeviceError", static_cast(result)); - return egl::Error(EGL_NOT_INITIALIZED, D3D11_INIT_CREATEDEVICE_ERROR, - "Could not create D3D11 device."); + return egl::EglNotInitialized(D3D11_INIT_CREATEDEVICE_ERROR) + << "Could not create D3D11 device."; } } } else { // We should use the inputted D3D11 device instead - void *device = nullptr; - egl::Error error = mEGLDevice->getDevice(&device); - if (error.isError()) - { - return error; - } + void *device = nullptr; + ANGLE_TRY(mEGLDevice->getDevice(&device)); ID3D11Device *d3dDevice = reinterpret_cast(device); if (FAILED(d3dDevice->GetDeviceRemovedReason())) { - return egl::Error(EGL_NOT_INITIALIZED, "Inputted D3D11 device has been lost."); + return egl::EglNotInitialized() << "Inputted D3D11 device has been lost."; } if (d3dDevice->GetFeatureLevel() < D3D_FEATURE_LEVEL_9_3) { - return egl::Error(EGL_NOT_INITIALIZED, - "Inputted D3D11 device must be Feature Level 9_3 or greater."); + return egl::EglNotInitialized() + << "Inputted D3D11 device must be Feature Level 9_3 or greater."; } // The Renderer11 adds a ref to the inputted D3D11 device, like D3D11CreateDevice does. @@ -788,27 +868,24 @@ egl::Error Renderer11::initializeD3DDevice() mRenderer11DeviceCaps.featureLevel = mDevice->GetFeatureLevel(); } + mResourceManager11.setAllocationsInitialized(mCreateDebugDevice); + d3d11::SetDebugName(mDeviceContext, "DeviceContext"); - return egl::Error(EGL_SUCCESS); + return egl::NoError(); } // 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() +egl::Error Renderer11::initializeDevice() { SCOPED_ANGLE_HISTOGRAM_TIMER("GPU.ANGLE.Renderer11InitializeDeviceMS"); TRACE_EVENT0("gpu.angle", "Renderer11::initializeDevice"); populateRenderer11DeviceCaps(); - mStateCache.initialize(mDevice); - mInputLayoutCache.initialize(mDevice, mDeviceContext); - - ASSERT(!mVertexDataManager && !mIndexDataManager); - mVertexDataManager = new VertexDataManager(this); - mIndexDataManager = new IndexDataManager(this, getRendererClass()); + mStateCache.clear(); ASSERT(!mBlit); mBlit = new Blit11(this); @@ -820,7 +897,8 @@ void Renderer11::initializeDevice() // 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); + EGLint enableAutoTrim = static_cast( + attributes.get(EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE, EGL_FALSE)); if (enableAutoTrim == EGL_TRUE) { @@ -831,19 +909,12 @@ void Renderer11::initializeDevice() ASSERT(!mPixelTransfer); mPixelTransfer = new PixelTransfer11(this); - const gl::Caps &rendererCaps = getRendererCaps(); - - mStateManager.initialize(rendererCaps); - - mForceSetVertexSamplerStates.resize(rendererCaps.maxVertexTextureImageUnits); - mCurVertexSamplerStates.resize(rendererCaps.maxVertexTextureImageUnits); - - mForceSetPixelSamplerStates.resize(rendererCaps.maxTextureImageUnits); - mCurPixelSamplerStates.resize(rendererCaps.maxTextureImageUnits); + const gl::Caps &rendererCaps = getNativeCaps(); - mStateManager.initialize(rendererCaps); - - markAllStateDirty(); + if (mStateManager.initialize(rendererCaps, getNativeExtensions()).isError()) + { + return egl::EglBadAlloc() << "Error initializing state manager."; + } // Gather stats on DXGI and D3D feature level ANGLE_HISTOGRAM_BOOLEAN("GPU.ANGLE.SupportsDXGI1_2", mRenderer11DeviceCaps.supportsDXGI1_2); @@ -859,57 +930,117 @@ void Renderer11::initializeDevice() angleFeatureLevel = ANGLE_FEATURE_LEVEL_11_1; } - ANGLE_HISTOGRAM_ENUMERATION("GPU.ANGLE.D3D11FeatureLevel", - angleFeatureLevel, + ANGLE_HISTOGRAM_ENUMERATION("GPU.ANGLE.D3D11FeatureLevel", angleFeatureLevel, NUM_ANGLE_FEATURE_LEVELS); - // TODO(jmadill): use context caps, and place in common D3D location - mTranslatedAttribCache.resize(getRendererCaps().maxVertexAttributes); + return egl::NoError(); } void Renderer11::populateRenderer11DeviceCaps() { HRESULT hr = S_OK; -#if defined(ANGLE_ENABLE_D3D11_1) + LARGE_INTEGER version; + hr = mDxgiAdapter->CheckInterfaceSupport(__uuidof(IDXGIDevice), &version); + if (FAILED(hr)) + { + mRenderer11DeviceCaps.driverVersion.reset(); + ERR() << "Error querying driver version from DXGI Adapter."; + } + else + { + mRenderer11DeviceCaps.driverVersion = version; + } + if (mDeviceContext1) { D3D11_FEATURE_DATA_D3D11_OPTIONS d3d11Options; - HRESULT result = mDevice->CheckFeatureSupport(D3D11_FEATURE_D3D11_OPTIONS, &d3d11Options, sizeof(D3D11_FEATURE_DATA_D3D11_OPTIONS)); + HRESULT result = mDevice->CheckFeatureSupport(D3D11_FEATURE_D3D11_OPTIONS, &d3d11Options, + sizeof(D3D11_FEATURE_DATA_D3D11_OPTIONS)); if (SUCCEEDED(result)) { mRenderer11DeviceCaps.supportsClearView = (d3d11Options.ClearView != FALSE); - mRenderer11DeviceCaps.supportsConstantBufferOffsets = (d3d11Options.ConstantBufferOffsetting != FALSE); + mRenderer11DeviceCaps.supportsConstantBufferOffsets = + (d3d11Options.ConstantBufferOffsetting != FALSE); } } -#endif - hr = mDevice->CheckFormatSupport(DXGI_FORMAT_B5G6R5_UNORM, &(mRenderer11DeviceCaps.B5G6R5support)); - if (FAILED(hr)) + if (mDeviceContext3) { - mRenderer11DeviceCaps.B5G6R5support = 0; + D3D11_FEATURE_DATA_D3D11_OPTIONS3 d3d11Options3; + HRESULT result = mDevice->CheckFeatureSupport(D3D11_FEATURE_D3D11_OPTIONS3, &d3d11Options3, + sizeof(D3D11_FEATURE_DATA_D3D11_OPTIONS3)); + if (SUCCEEDED(result)) + { + mRenderer11DeviceCaps.supportsVpRtIndexWriteFromVertexShader = + (d3d11Options3.VPAndRTArrayIndexFromAnyShaderFeedingRasterizer == TRUE); + } } - hr = mDevice->CheckFormatSupport(DXGI_FORMAT_B4G4R4A4_UNORM, &(mRenderer11DeviceCaps.B4G4R4A4support)); - if (FAILED(hr)) + mRenderer11DeviceCaps.supportsMultisampledDepthStencilSRVs = + mRenderer11DeviceCaps.featureLevel > D3D_FEATURE_LEVEL_10_0; + + if (getWorkarounds().disableB5G6R5Support) { - mRenderer11DeviceCaps.B4G4R4A4support = 0; + mRenderer11DeviceCaps.B5G6R5support = 0; + mRenderer11DeviceCaps.B5G6R5maxSamples = 0; } - - hr = mDevice->CheckFormatSupport(DXGI_FORMAT_B5G5R5A1_UNORM, &(mRenderer11DeviceCaps.B5G5R5A1support)); - if (FAILED(hr)) + else { - mRenderer11DeviceCaps.B5G5R5A1support = 0; + PopulateFormatDeviceCaps(mDevice, DXGI_FORMAT_B5G6R5_UNORM, + &mRenderer11DeviceCaps.B5G6R5support, + &mRenderer11DeviceCaps.B5G6R5maxSamples); } -#if defined(ANGLE_ENABLE_D3D11_1) + PopulateFormatDeviceCaps(mDevice, DXGI_FORMAT_B4G4R4A4_UNORM, + &mRenderer11DeviceCaps.B4G4R4A4support, + &mRenderer11DeviceCaps.B4G4R4A4maxSamples); + PopulateFormatDeviceCaps(mDevice, DXGI_FORMAT_B5G5R5A1_UNORM, + &mRenderer11DeviceCaps.B5G5R5A1support, + &mRenderer11DeviceCaps.B5G5R5A1maxSamples); + IDXGIAdapter2 *dxgiAdapter2 = d3d11::DynamicCastComObject(mDxgiAdapter); mRenderer11DeviceCaps.supportsDXGI1_2 = (dxgiAdapter2 != nullptr); SafeRelease(dxgiAdapter2); +} + +gl::SupportedSampleSet Renderer11::generateSampleSetForEGLConfig( + const gl::TextureCaps &colorBufferFormatCaps, + const gl::TextureCaps &depthStencilBufferFormatCaps) const +{ + gl::SupportedSampleSet sampleCounts; + +#if 0 // Disabling support for multisampling with Qt5 as it's causing a crash in the D3D11 shaders. + + // Generate a new set from the set intersection of sample counts between the color and depth + // format caps. + std::set_intersection(colorBufferFormatCaps.sampleCounts.begin(), + colorBufferFormatCaps.sampleCounts.end(), + depthStencilBufferFormatCaps.sampleCounts.begin(), + depthStencilBufferFormatCaps.sampleCounts.end(), + std::inserter(sampleCounts, sampleCounts.begin())); + + // Format of GL_NONE results in no supported sample counts. + // Add back the color sample counts to the supported sample set. + if (depthStencilBufferFormatCaps.sampleCounts.empty()) + { + sampleCounts = colorBufferFormatCaps.sampleCounts; + } + else if (colorBufferFormatCaps.sampleCounts.empty()) + { + // Likewise, add back the depth sample counts to the supported sample set. + sampleCounts = depthStencilBufferFormatCaps.sampleCounts; + } + #endif + + // Always support 0 samples + sampleCounts.insert(0); + + return sampleCounts; } -egl::ConfigSet Renderer11::generateConfigs() const +egl::ConfigSet Renderer11::generateConfigs() { std::vector colorBufferFormats; @@ -920,6 +1051,14 @@ egl::ConfigSet Renderer11::generateConfigs() const // 24-bit supported formats colorBufferFormats.push_back(GL_RGB8_OES); + if (mRenderer11DeviceCaps.featureLevel >= D3D_FEATURE_LEVEL_10_0) + { + // Additional high bit depth formats added in D3D 10.0 + // https://msdn.microsoft.com/en-us/library/windows/desktop/bb173064.aspx + colorBufferFormats.push_back(GL_RGBA16F); + colorBufferFormats.push_back(GL_RGB10_A2); + } + if (!mPresentPathFastEnabled) { // 16-bit supported formats @@ -930,15 +1069,13 @@ egl::ConfigSet Renderer11::generateConfigs() const colorBufferFormats.push_back(GL_RGB565); } - static const GLenum depthStencilBufferFormats[] = - { - GL_NONE, - GL_DEPTH24_STENCIL8_OES, - GL_DEPTH_COMPONENT16, + static const GLenum depthStencilBufferFormats[] = { + GL_NONE, GL_DEPTH24_STENCIL8_OES, GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT16, + GL_STENCIL_INDEX8, }; - const gl::Caps &rendererCaps = getRendererCaps(); - const gl::TextureCapsMap &rendererTextureCaps = getRendererTextureCaps(); + const gl::Caps &rendererCaps = getNativeCaps(); + const gl::TextureCapsMap &rendererTextureCaps = getNativeTextureCaps(); const EGLint optimalSurfaceOrientation = mPresentPathFastEnabled ? 0 : EGL_SURFACE_ORIENTATION_INVERT_Y_ANGLE; @@ -946,7 +1083,8 @@ egl::ConfigSet Renderer11::generateConfigs() const egl::ConfigSet configs; for (GLenum colorBufferInternalFormat : colorBufferFormats) { - const gl::TextureCaps &colorBufferFormatCaps = rendererTextureCaps.get(colorBufferInternalFormat); + const gl::TextureCaps &colorBufferFormatCaps = + rendererTextureCaps.get(colorBufferInternalFormat); if (!colorBufferFormatCaps.renderable) { continue; @@ -963,64 +1101,87 @@ egl::ConfigSet Renderer11::generateConfigs() const } const gl::InternalFormat &colorBufferFormatInfo = - gl::GetInternalFormatInfo(colorBufferInternalFormat); + gl::GetSizedInternalFormatInfo(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 = (mRenderer11DeviceCaps.featureLevel >= D3D_FEATURE_LEVEL_10_0) - ? (EGL_OPENGL_ES2_BIT | EGL_OPENGL_ES3_BIT_KHR) - : 0; - config.configCaveat = config.conformant == EGL_NONE ? EGL_NON_CONFORMANT_CONFIG : EGL_NONE; - - // PresentPathFast may not be conformant - if (mPresentPathFastEnabled) + gl::GetSizedInternalFormatInfo(depthStencilBufferInternalFormat); + const gl::Version &maxVersion = getMaxSupportedESVersion(); + + const gl::SupportedSampleSet sampleCounts = + generateSampleSetForEGLConfig(colorBufferFormatCaps, depthStencilBufferFormatCaps); + + for (GLuint sampleCount : sampleCounts) { + 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) && (sampleCount <= 1)); + config.bindToTextureRGBA = (((colorBufferFormatInfo.format == GL_RGBA) || + (colorBufferFormatInfo.format == GL_BGRA_EXT)) && + (sampleCount <= 1)); + config.colorBufferType = EGL_RGB_BUFFER; + config.configCaveat = EGL_NONE; + config.configID = static_cast(configs.size() + 1); + + // PresentPathFast may not be conformant config.conformant = 0; - } + if (!mPresentPathFastEnabled) + { + // Can only support a conformant ES2 with feature level greater than 10.0. + if (mRenderer11DeviceCaps.featureLevel >= D3D_FEATURE_LEVEL_10_0) + { + config.conformant |= EGL_OPENGL_ES2_BIT; + } + + // We can only support conformant ES3 on FL 10.1+ + if (maxVersion.major >= 3) + { + config.conformant |= EGL_OPENGL_ES3_BIT_KHR; + } + } + + 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.1 + config.renderableType = EGL_OPENGL_ES2_BIT; + if (maxVersion.major >= 3) + { + config.renderableType |= EGL_OPENGL_ES3_BIT_KHR; + } - config.depthSize = depthStencilBufferFormatInfo.depthBits; - config.level = 0; - config.matchNativePixmap = EGL_NONE; - config.maxPBufferWidth = rendererCaps.max2DTextureSize; - config.maxPBufferHeight = rendererCaps.max2DTextureSize; - config.maxPBufferPixels = rendererCaps.max2DTextureSize * rendererCaps.max2DTextureSize; - config.maxSwapInterval = 4; - config.minSwapInterval = 0; - config.nativeRenderable = EGL_FALSE; - config.nativeVisualID = 0; - config.nativeVisualType = EGL_NONE; - // Can't support ES3 at all without feature level 10.0 - config.renderableType = - EGL_OPENGL_ES2_BIT | ((mRenderer11DeviceCaps.featureLevel >= D3D_FEATURE_LEVEL_10_0) - ? EGL_OPENGL_ES3_BIT_KHR - : 0); - config.sampleBuffers = 0; // FIXME: enumerate multi-sampling - config.samples = 0; - config.stencilSize = depthStencilBufferFormatInfo.stencilBits; - config.surfaceType = EGL_PBUFFER_BIT | EGL_WINDOW_BIT | EGL_SWAP_BEHAVIOR_PRESERVED_BIT; - config.transparentType = EGL_NONE; - config.transparentRedValue = 0; - config.transparentGreenValue = 0; - config.transparentBlueValue = 0; - config.optimalOrientation = optimalSurfaceOrientation; - - configs.add(config); + config.sampleBuffers = (sampleCount == 0) ? 0 : 1; + config.samples = sampleCount; + config.stencilSize = depthStencilBufferFormatInfo.stencilBits; + config.surfaceType = + EGL_PBUFFER_BIT | EGL_WINDOW_BIT | EGL_SWAP_BEHAVIOR_PRESERVED_BIT; + config.transparentType = EGL_NONE; + config.transparentRedValue = 0; + config.transparentGreenValue = 0; + config.transparentBlueValue = 0; + config.optimalOrientation = optimalSurfaceOrientation; + config.colorComponentType = gl_egl::GLComponentTypeToEGLColorComponentType( + colorBufferFormatInfo.componentType); + + configs.add(config); + } } } @@ -1037,8 +1198,9 @@ void Renderer11::generateDisplayExtensions(egl::DisplayExtensions *outExtensions outExtensions->d3dShareHandleClientBuffer = true; outExtensions->surfaceD3DTexture2DShareHandle = true; } + outExtensions->d3dTextureClientBuffer = true; - outExtensions->keyedMutex = true; + outExtensions->keyedMutex = true; outExtensions->querySurfacePointer = true; outExtensions->windowFixedSize = true; @@ -1048,624 +1210,350 @@ void Renderer11::generateDisplayExtensions(egl::DisplayExtensions *outExtensions // D3D11 does not support present with dirty rectangles until DXGI 1.2. outExtensions->postSubBuffer = mRenderer11DeviceCaps.supportsDXGI1_2; - outExtensions->createContext = true; - outExtensions->deviceQuery = true; - outExtensions->createContextNoError = true; - outExtensions->image = true; outExtensions->imageBase = true; outExtensions->glTexture2DImage = true; outExtensions->glTextureCubemapImage = true; outExtensions->glRenderbufferImage = true; + outExtensions->stream = true; + outExtensions->streamConsumerGLTexture = true; + outExtensions->streamConsumerGLTextureYUV = true; + // Not all D3D11 devices support NV12 textures + if (getNV12TextureSupport()) + { + outExtensions->streamProducerD3DTextureNV12 = true; + } + outExtensions->flexibleSurfaceCompatibility = true; outExtensions->directComposition = !!mDCompModule; + + // Contexts are virtualized so textures can be shared globally + outExtensions->displayTextureShareGroup = true; + + // getSyncValues requires direct composition. + outExtensions->getSyncValues = outExtensions->directComposition; + + // D3D11 can be used without a swap chain + outExtensions->surfacelessContext = true; + + // All D3D feature levels support robust resource init + outExtensions->robustResourceInitialization = true; } gl::Error Renderer11::flush() { mDeviceContext->Flush(); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } gl::Error Renderer11::finish() { - HRESULT result; - - if (!mSyncQuery) + if (!mSyncQuery.valid()) { D3D11_QUERY_DESC queryDesc; - queryDesc.Query = D3D11_QUERY_EVENT; + 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); - } + ANGLE_TRY(allocateResource(queryDesc, &mSyncQuery)); } - mDeviceContext->End(mSyncQuery); - mDeviceContext->Flush(); + mDeviceContext->End(mSyncQuery.get()); + HRESULT result = S_OK; + unsigned int attempt = 0; do { - result = mDeviceContext->GetData(mSyncQuery, NULL, 0, D3D11_ASYNC_GETDATA_DONOTFLUSH); + unsigned int flushFrequency = 100; + UINT flags = (attempt % flushFrequency == 0) ? 0 : D3D11_ASYNC_GETDATA_DONOTFLUSH; + attempt++; + + result = mDeviceContext->GetData(mSyncQuery.get(), nullptr, 0, flags); if (FAILED(result)) { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to get event query data, result: 0x%X.", result); + return gl::OutOfMemory() << "Failed to get event query data, " << gl::FmtHR(result); } - // Keep polling, but allow other threads to do something useful first - ScheduleYield(); + if (result == S_FALSE) + { + // 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."); + return gl::OutOfMemory() << "Device was lost while waiting for sync."; } - } - while (result == S_FALSE); + } while (result == S_FALSE); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -SwapChainD3D *Renderer11::createSwapChain(NativeWindow nativeWindow, - HANDLE shareHandle, - GLenum backBufferFormat, - GLenum depthBufferFormat, - EGLint orientation) +bool Renderer11::isValidNativeWindow(EGLNativeWindowType window) const +{ +#ifdef ANGLE_ENABLE_WINDOWS_STORE + return NativeWindow11WinRT::IsValidNativeWindow(window); +#else + return NativeWindow11Win32::IsValidNativeWindow(window); +#endif +} + +NativeWindowD3D *Renderer11::createNativeWindow(EGLNativeWindowType window, + const egl::Config *config, + const egl::AttributeMap &attribs) const { - return new SwapChain11(this, nativeWindow, shareHandle, backBufferFormat, depthBufferFormat, - orientation); +#ifdef ANGLE_ENABLE_WINDOWS_STORE + UNUSED_VARIABLE(attribs); + return new NativeWindow11WinRT(window, config->alphaSize > 0); +#else + return new NativeWindow11Win32( + window, config->alphaSize > 0, + attribs.get(EGL_DIRECT_COMPOSITION_ANGLE, EGL_FALSE) == EGL_TRUE); +#endif } -CompilerImpl *Renderer11::createCompiler() +egl::Error Renderer11::getD3DTextureInfo(const egl::Config *configuration, + IUnknown *d3dTexture, + EGLint *width, + EGLint *height, + GLenum *fboFormat) const { - if (mRenderer11DeviceCaps.featureLevel <= D3D_FEATURE_LEVEL_9_3) + ID3D11Texture2D *texture = d3d11::DynamicCastComObject(d3dTexture); + if (texture == nullptr) { - return new CompilerD3D(SH_HLSL_4_0_FL9_3_OUTPUT); + return egl::EglBadParameter() << "client buffer is not a ID3D11Texture2D"; } - else + + ID3D11Device *textureDevice = nullptr; + texture->GetDevice(&textureDevice); + if (textureDevice != mDevice) { - return new CompilerD3D(SH_HLSL_4_1_OUTPUT); + SafeRelease(texture); + return egl::EglBadParameter() << "Texture's device does not match."; } -} + SafeRelease(textureDevice); -void *Renderer11::getD3DDevice() -{ - return reinterpret_cast(mDevice); -} + D3D11_TEXTURE2D_DESC desc = {0}; + texture->GetDesc(&desc); + SafeRelease(texture); -gl::Error Renderer11::generateSwizzle(gl::Texture *texture) -{ - if (texture) + if (width) { - TextureD3D *textureD3D = GetImplAs(texture); - ASSERT(textureD3D); - - TextureStorage *texStorage = nullptr; - gl::Error error = textureD3D->getNativeTexture(&texStorage); - if (error.isError()) + *width = static_cast(desc.Width); + } + if (height) + { + *height = static_cast(desc.Height); + } + if (static_cast(desc.SampleDesc.Count) != configuration->samples) + { + // Both the texture and EGL config sample count may not be the same when multi-sampling + // is disabled. The EGL sample count can be 0 but a D3D texture is always 1. Therefore, + // we must only check for a invalid match when the EGL config is non-zero or the texture is + // not one. + if (configuration->samples != 0 || desc.SampleDesc.Count != 1) { - return error; + return egl::EglBadParameter() << "Texture's sample count does not match."; } + } + // From table egl.restrictions in EGL_ANGLE_d3d_texture_client_buffer. + switch (desc.Format) + { + case DXGI_FORMAT_R8G8B8A8_UNORM: + case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: + case DXGI_FORMAT_B8G8R8A8_UNORM: + case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: + case DXGI_FORMAT_R16G16B16A16_FLOAT: + case DXGI_FORMAT_R32G32B32A32_FLOAT: + break; - if (texStorage) - { - TextureStorage11 *storage11 = GetAs(texStorage); - const gl::TextureState &textureState = texture->getTextureState(); - error = - storage11->generateSwizzles(textureState.swizzleRed, textureState.swizzleGreen, - textureState.swizzleBlue, textureState.swizzleAlpha); - if (error.isError()) - { - return error; - } - } + default: + return egl::EglBadParameter() + << "Unknown client buffer texture format: " << desc.Format; + } + + if (fboFormat) + { + const angle::Format &angleFormat = d3d11_angle::GetFormat(desc.Format); + *fboFormat = angleFormat.fboImplementationInternalFormat; } - return gl::Error(GL_NO_ERROR); + return egl::NoError(); } -gl::Error Renderer11::setSamplerState(gl::SamplerType type, - int index, - gl::Texture *texture, - const gl::SamplerState &samplerState) +egl::Error Renderer11::validateShareHandle(const egl::Config *config, + HANDLE shareHandle, + const egl::AttributeMap &attribs) const { - // Make sure to add the level offset for our tiny compressed texture workaround - TextureD3D *textureD3D = GetImplAs(texture); + if (shareHandle == nullptr) + { + return egl::EglBadParameter() << "NULL share handle."; + } - TextureStorage *storage = nullptr; - gl::Error error = textureD3D->getNativeTexture(&storage); - if (error.isError()) + ID3D11Resource *tempResource11 = nullptr; + HRESULT result = mDevice->OpenSharedResource(shareHandle, __uuidof(ID3D11Resource), + (void **)&tempResource11); + if (FAILED(result)) { - return error; + return egl::EglBadParameter() << "Failed to open share handle, " << gl::FmtHR(result); } - // Storage should exist, texture should be complete - ASSERT(storage); + ID3D11Texture2D *texture2D = d3d11::DynamicCastComObject(tempResource11); + SafeRelease(tempResource11); - if (type == gl::SAMPLER_PIXEL) + if (texture2D == nullptr) { - ASSERT(static_cast(index) < getRendererCaps().maxTextureImageUnits); + return egl::EglBadParameter() + << "Failed to query ID3D11Texture2D object from share handle."; + } - if (mForceSetPixelSamplerStates[index] || - memcmp(&samplerState, &mCurPixelSamplerStates[index], sizeof(gl::SamplerState)) != 0) - { - ID3D11SamplerState *dxSamplerState = NULL; - error = mStateCache.getSamplerState(samplerState, &dxSamplerState); - if (error.isError()) - { - return error; - } + D3D11_TEXTURE2D_DESC desc = {0}; + texture2D->GetDesc(&desc); + SafeRelease(texture2D); - ASSERT(dxSamplerState != NULL); - mDeviceContext->PSSetSamplers(index, 1, &dxSamplerState); + EGLint width = attribs.getAsInt(EGL_WIDTH, 0); + EGLint height = attribs.getAsInt(EGL_HEIGHT, 0); + ASSERT(width != 0 && height != 0); - mCurPixelSamplerStates[index] = samplerState; - } + const d3d11::Format &backbufferFormatInfo = + d3d11::Format::Get(config->renderTargetFormat, getRenderer11DeviceCaps()); - mForceSetPixelSamplerStates[index] = false; - } - else if (type == gl::SAMPLER_VERTEX) + if (desc.Width != static_cast(width) || desc.Height != static_cast(height) || + desc.Format != backbufferFormatInfo.texFormat || desc.MipLevels != 1 || desc.ArraySize != 1) { - ASSERT(static_cast(index) < getRendererCaps().maxVertexTextureImageUnits); - - if (mForceSetVertexSamplerStates[index] || - memcmp(&samplerState, &mCurVertexSamplerStates[index], sizeof(gl::SamplerState)) != 0) - { - ID3D11SamplerState *dxSamplerState = NULL; - error = mStateCache.getSamplerState(samplerState, &dxSamplerState); - if (error.isError()) - { - return error; - } - - ASSERT(dxSamplerState != NULL); - mDeviceContext->VSSetSamplers(index, 1, &dxSamplerState); - - mCurVertexSamplerStates[index] = samplerState; - } - - mForceSetVertexSamplerStates[index] = false; + return egl::EglBadParameter() << "Invalid texture parameters in share handle texture."; } - else UNREACHABLE(); - return gl::Error(GL_NO_ERROR); + return egl::NoError(); } -gl::Error Renderer11::setTexture(gl::SamplerType type, int index, gl::Texture *texture) +SwapChainD3D *Renderer11::createSwapChain(NativeWindowD3D *nativeWindow, + HANDLE shareHandle, + IUnknown *d3dTexture, + GLenum backBufferFormat, + GLenum depthBufferFormat, + EGLint orientation, + EGLint samples) { - 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 = GetAs(texStorage); - - // Make sure to add the level offset for our tiny compressed texture workaround - gl::TextureState textureState = texture->getTextureState(); - textureState.baseLevel += storage11->getTopLevel(); - - error = storage11->getSRV(textureState, &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)); - - mStateManager.setShaderResource(type, index, textureSRV); - - return gl::Error(GL_NO_ERROR); + return new SwapChain11(this, GetAs(nativeWindow), shareHandle, d3dTexture, + backBufferFormat, depthBufferFormat, orientation, samples); } -gl::Error Renderer11::setUniformBuffers(const gl::Data &data, - const std::vector &vertexUniformBuffers, - const std::vector &fragmentUniformBuffers) +void *Renderer11::getD3DDevice() { - for (size_t uniformBufferIndex = 0; uniformBufferIndex < vertexUniformBuffers.size(); uniformBufferIndex++) - { - GLint binding = vertexUniformBuffers[uniformBufferIndex]; - - if (binding == -1) - { - continue; - } - - const OffsetBindingPointer &uniformBuffer = - data.state->getIndexedUniformBuffer(binding); - GLintptr uniformBufferOffset = uniformBuffer.getOffset(); - GLsizeiptr uniformBufferSize = uniformBuffer.getSize(); - - if (uniformBuffer.get() != nullptr) - { - Buffer11 *bufferStorage = GetImplAs(uniformBuffer.get()); - ID3D11Buffer *constantBuffer; - - if (mRenderer11DeviceCaps.supportsConstantBufferOffsets) - { - constantBuffer = bufferStorage->getBuffer(BUFFER_USAGE_UNIFORM); - } - else - { - constantBuffer = bufferStorage->getConstantBufferRange(uniformBufferOffset, uniformBufferSize); - } - - if (!constantBuffer) - { - return gl::Error(GL_OUT_OF_MEMORY); - } + return reinterpret_cast(mDevice); +} - if (mCurrentConstantBufferVS[uniformBufferIndex] != bufferStorage->getSerial() || - mCurrentConstantBufferVSOffset[uniformBufferIndex] != uniformBufferOffset || - mCurrentConstantBufferVSSize[uniformBufferIndex] != uniformBufferSize) - { -#if defined(ANGLE_ENABLE_D3D11_1) - if (mRenderer11DeviceCaps.supportsConstantBufferOffsets && uniformBufferSize != 0) - { - UINT firstConstant = 0, numConstants = 0; - CalculateConstantBufferParams(uniformBufferOffset, uniformBufferSize, &firstConstant, &numConstants); - mDeviceContext1->VSSetConstantBuffers1( - getReservedVertexUniformBuffers() + - static_cast(uniformBufferIndex), - 1, &constantBuffer, &firstConstant, &numConstants); - } - else -#endif - { - mDeviceContext->VSSetConstantBuffers( - getReservedVertexUniformBuffers() + - static_cast(uniformBufferIndex), - 1, &constantBuffer); - } +bool Renderer11::applyPrimitiveType(const gl::State &glState, GLenum mode, GLsizei count) +{ + D3D11_PRIMITIVE_TOPOLOGY primitiveTopology = D3D_PRIMITIVE_TOPOLOGY_UNDEFINED; - mCurrentConstantBufferVS[uniformBufferIndex] = bufferStorage->getSerial(); - mCurrentConstantBufferVSOffset[uniformBufferIndex] = uniformBufferOffset; - mCurrentConstantBufferVSSize[uniformBufferIndex] = uniformBufferSize; - } - } - } + GLsizei minCount = 0; - for (size_t uniformBufferIndex = 0; uniformBufferIndex < fragmentUniformBuffers.size(); uniformBufferIndex++) + switch (mode) { - GLint binding = fragmentUniformBuffers[uniformBufferIndex]; - - if (binding == -1) + case GL_POINTS: { - continue; - } + bool usesPointSize = GetImplAs(glState.getProgram())->usesPointSize(); - const OffsetBindingPointer &uniformBuffer = - data.state->getIndexedUniformBuffer(binding); - GLintptr uniformBufferOffset = uniformBuffer.getOffset(); - GLsizeiptr uniformBufferSize = uniformBuffer.getSize(); - - if (uniformBuffer.get() != nullptr) - { - Buffer11 *bufferStorage = GetImplAs(uniformBuffer.get()); - ID3D11Buffer *constantBuffer; - - if (mRenderer11DeviceCaps.supportsConstantBufferOffsets) + // 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 (!usesPointSize && !glState.isTransformFeedbackActiveUnpaused()) { - constantBuffer = bufferStorage->getBuffer(BUFFER_USAGE_UNIFORM); - } - else - { - constantBuffer = bufferStorage->getConstantBufferRange(uniformBufferOffset, uniformBufferSize); + // Notify developers of risking undefined behavior. + WARN() << "Point rendering without writing to gl_PointSize."; + return false; } - if (!constantBuffer) + // If instanced pointsprites are enabled and the shader uses gl_PointSize, the topology + // must be D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST. + if (usesPointSize && getWorkarounds().useInstancedPointSpriteEmulation) { - return gl::Error(GL_OUT_OF_MEMORY); + primitiveTopology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST; } - - if (mCurrentConstantBufferPS[uniformBufferIndex] != bufferStorage->getSerial() || - mCurrentConstantBufferPSOffset[uniformBufferIndex] != uniformBufferOffset || - mCurrentConstantBufferPSSize[uniformBufferIndex] != uniformBufferSize) + else { -#if defined(ANGLE_ENABLE_D3D11_1) - if (mRenderer11DeviceCaps.supportsConstantBufferOffsets && uniformBufferSize != 0) - { - UINT firstConstant = 0, numConstants = 0; - CalculateConstantBufferParams(uniformBufferOffset, uniformBufferSize, &firstConstant, &numConstants); - mDeviceContext1->PSSetConstantBuffers1( - getReservedFragmentUniformBuffers() + - static_cast(uniformBufferIndex), - 1, &constantBuffer, &firstConstant, &numConstants); - } - else -#endif - { - mDeviceContext->PSSetConstantBuffers( - getReservedFragmentUniformBuffers() + - static_cast(uniformBufferIndex), - 1, &constantBuffer); - } - - mCurrentConstantBufferPS[uniformBufferIndex] = bufferStorage->getSerial(); - mCurrentConstantBufferPSOffset[uniformBufferIndex] = uniformBufferOffset; - mCurrentConstantBufferPSSize[uniformBufferIndex] = uniformBufferSize; + 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 = CullsEverything(glState) ? std::numeric_limits::max() : 3; + break; + case GL_TRIANGLE_STRIP: + primitiveTopology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP; + minCount = CullsEverything(glState) ? std::numeric_limits::max() : 3; + break; + // emulate fans via rewriting index buffer + case GL_TRIANGLE_FAN: + primitiveTopology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST; + minCount = CullsEverything(glState) ? std::numeric_limits::max() : 3; + break; + default: + UNREACHABLE(); + return false; } - return gl::Error(GL_NO_ERROR); -} - -gl::Error Renderer11::updateState(const gl::Data &data, GLenum drawMode) -{ - // Applies the render target surface, depth stencil surface, viewport rectangle and - // scissor rectangle to the renderer - const gl::Framebuffer *framebufferObject = data.state->getDrawFramebuffer(); - ASSERT(framebufferObject && framebufferObject->checkStatus(data) == GL_FRAMEBUFFER_COMPLETE); - gl::Error error = applyRenderTarget(framebufferObject); - if (error.isError()) - { - return error; - } - - // Set the present path state - const bool presentPathFastActive = - UsePresentPathFast(this, framebufferObject->getFirstColorbuffer()); - mStateManager.updatePresentPath(presentPathFastActive, - framebufferObject->getFirstColorbuffer()); - - // Setting viewport state - mStateManager.setViewport(data.caps, data.state->getViewport(), data.state->getNearPlane(), - data.state->getFarPlane()); - - // Setting scissor state - mStateManager.setScissorRectangle(data.state->getScissor(), data.state->isScissorTestEnabled()); - - // Applying rasterizer state to D3D11 device - int samples = framebufferObject->getSamples(data); - gl::RasterizerState rasterizer = data.state->getRasterizerState(); - rasterizer.pointDrawMode = (drawMode == GL_POINTS); - rasterizer.multiSample = (samples != 0); - - error = mStateManager.setRasterizerState(rasterizer); - if (error.isError()) - { - return error; - } - - // Setting blend state - unsigned int mask = GetBlendSampleMask(data, samples); - error = mStateManager.setBlendState(framebufferObject, data.state->getBlendState(), - data.state->getBlendColor(), mask); - if (error.isError()) - { - return error; - } - - // Setting depth stencil state - error = mStateManager.setDepthStencilState(*data.state); - return error; -} - -void Renderer11::syncState(const gl::State &state, const gl::State::DirtyBits &bitmask) -{ - mStateManager.syncState(state, bitmask); -} - -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; - } + mStateManager.setPrimitiveTopology(primitiveTopology); return count >= minCount; } -gl::Error Renderer11::applyRenderTarget(const gl::Framebuffer *framebuffer) +gl::Error Renderer11::drawArrays(const gl::Context *context, + GLenum mode, + GLint startVertex, + GLsizei count, + GLsizei instances) { - return mStateManager.syncFramebuffer(framebuffer); -} + const auto &glState = context->getGLState(); -gl::Error Renderer11::applyVertexBuffer(const gl::State &state, - GLenum mode, - GLint first, - GLsizei count, - GLsizei instances, - TranslatedIndexData *indexInfo) -{ - gl::Error error = mVertexDataManager->prepareVertexData(state, first, count, &mTranslatedAttribCache, instances); - if (error.isError()) + if (!applyPrimitiveType(glState, mode, count)) { - return error; + return gl::NoError(); } - // If index information is passed, mark it with the current changed status. - if (indexInfo) - { - indexInfo->srcIndexData.srcIndicesChanged = mAppliedIBChanged; - } + DrawCallVertexParams vertexParams(startVertex, count, instances); + ANGLE_TRY(mStateManager.applyVertexBuffer(context, mode, vertexParams, false)); - GLsizei numIndicesPerInstance = 0; - if (instances > 0) + if (glState.isTransformFeedbackActiveUnpaused()) { - numIndicesPerInstance = count; + ANGLE_TRY(markTransformFeedbackUsage(context)); } - return mInputLayoutCache.applyVertexBuffers(mTranslatedAttribCache, mode, state.getProgram(), - indexInfo, numIndicesPerInstance); -} -gl::Error Renderer11::applyIndexBuffer(const gl::Data &data, - const GLvoid *indices, - GLsizei count, - GLenum mode, - GLenum type, - TranslatedIndexData *indexInfo) -{ - gl::VertexArray *vao = data.state->getVertexArray(); - gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get(); - gl::Error error = - mIndexDataManager->prepareIndexData(type, count, elementArrayBuffer, indices, indexInfo, - data.state->isPrimitiveRestartEnabled()); - if (error.isError()) - { - return error; - } + gl::Program *program = glState.getProgram(); + ASSERT(program != nullptr); + GLsizei adjustedInstanceCount = GetAdjustedInstanceCount(program, instances); + ProgramD3D *programD3D = GetImplAs(program); - ID3D11Buffer *buffer = NULL; - DXGI_FORMAT bufferFormat = (indexInfo->indexType == GL_UNSIGNED_INT) ? DXGI_FORMAT_R32_UINT : DXGI_FORMAT_R16_UINT; - - if (indexInfo->storage) - { - Buffer11 *storage = GetAs(indexInfo->storage); - buffer = storage->getBuffer(BUFFER_USAGE_INDEX); - } - else - { - IndexBuffer11* indexBuffer = GetAs(indexInfo->indexBuffer); - buffer = indexBuffer->getBuffer(); - } - - mAppliedIBChanged = false; - if (buffer != mAppliedIB || bufferFormat != mAppliedIBFormat || indexInfo->startOffset != mAppliedIBOffset) - { - mDeviceContext->IASetIndexBuffer(buffer, bufferFormat, indexInfo->startOffset); - - mAppliedIB = buffer; - mAppliedIBFormat = bufferFormat; - mAppliedIBOffset = indexInfo->startOffset; - mAppliedIBChanged = true; - } - - return gl::Error(GL_NO_ERROR); -} - -void Renderer11::applyTransformFeedbackBuffers(const gl::State &state) -{ - size_t numXFBBindings = 0; - bool requiresUpdate = false; - - if (state.isTransformFeedbackActiveUnpaused()) - { - const gl::TransformFeedback *transformFeedback = state.getCurrentTransformFeedback(); - numXFBBindings = transformFeedback->getIndexedBufferCount(); - ASSERT(numXFBBindings <= gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS); - - for (size_t i = 0; i < numXFBBindings; i++) - { - const OffsetBindingPointer &binding = transformFeedback->getIndexedBuffer(i); - - ID3D11Buffer *d3dBuffer = NULL; - if (binding.get() != nullptr) - { - Buffer11 *storage = GetImplAs(binding.get()); - d3dBuffer = storage->getBuffer(BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK); - } - - // TODO: mAppliedTFBuffers and friends should also be kept in a vector. - if (d3dBuffer != mAppliedTFBuffers[i] || binding.getOffset() != mAppliedTFOffsets[i]) - { - requiresUpdate = true; - } - } - } - - if (requiresUpdate || numXFBBindings != mAppliedNumXFBBindings) - { - const gl::TransformFeedback *transformFeedback = state.getCurrentTransformFeedback(); - for (size_t i = 0; i < numXFBBindings; ++i) - { - const OffsetBindingPointer &binding = transformFeedback->getIndexedBuffer(i); - if (binding.get() != nullptr) - { - Buffer11 *storage = GetImplAs(binding.get()); - ID3D11Buffer *d3dBuffer = storage->getBuffer(BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK); - - mCurrentD3DOffsets[i] = (mAppliedTFBuffers[i] != d3dBuffer || mAppliedTFOffsets[i] != binding.getOffset()) ? - static_cast(binding.getOffset()) : -1; - mAppliedTFBuffers[i] = d3dBuffer; - } - else - { - mAppliedTFBuffers[i] = NULL; - mCurrentD3DOffsets[i] = 0; - } - mAppliedTFOffsets[i] = binding.getOffset(); - } - - mAppliedNumXFBBindings = numXFBBindings; - - mDeviceContext->SOSetTargets(static_cast(numXFBBindings), mAppliedTFBuffers, - mCurrentD3DOffsets); - } -} - -gl::Error Renderer11::drawArraysImpl(const gl::Data &data, - GLenum mode, - GLsizei count, - GLsizei instances) -{ - ProgramD3D *programD3D = GetImplAs(data.state->getProgram()); - - if (programD3D->usesGeometryShader(mode) && data.state->isTransformFeedbackActiveUnpaused()) + if (programD3D->usesGeometryShader(mode) && glState.isTransformFeedbackActiveUnpaused()) { // Since we use a geometry if-and-only-if we rewrite vertex streams, transform feedback // won't get the correct output. To work around this, draw with *only* the stream out // first (no pixel shader) to feed the stream out buffers and then draw again with the // geometry shader + pixel shader to rasterize the primitives. - mDeviceContext->PSSetShader(nullptr, nullptr, 0); + mStateManager.setPixelShader(nullptr); - if (instances > 0) + if (adjustedInstanceCount > 0) { - mDeviceContext->DrawInstanced(count, instances, 0, 0); + mDeviceContext->DrawInstanced(count, adjustedInstanceCount, 0, 0); } else { @@ -1673,709 +1561,481 @@ gl::Error Renderer11::drawArraysImpl(const gl::Data &data, } rx::ShaderExecutableD3D *pixelExe = nullptr; - gl::Error error = programD3D->getPixelExecutableForFramebuffer(data.state->getDrawFramebuffer(), &pixelExe); - if (error.isError()) - { - return error; - } + ANGLE_TRY(programD3D->getPixelExecutableForCachedOutputLayout(&pixelExe, nullptr)); // Skip the draw call if rasterizer discard is enabled (or no fragment shader). - if (!pixelExe || data.state->getRasterizerState().rasterizerDiscard) + if (!pixelExe || glState.getRasterizerState().rasterizerDiscard) { - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } - ID3D11PixelShader *pixelShader = GetAs(pixelExe)->getPixelShader(); - ASSERT(reinterpret_cast(pixelShader) == mAppliedPixelShader); - mDeviceContext->PSSetShader(pixelShader, NULL, 0); + mStateManager.setPixelShader(&GetAs(pixelExe)->getPixelShader()); // Retrieve the geometry shader. rx::ShaderExecutableD3D *geometryExe = nullptr; - error = - programD3D->getGeometryExecutableForPrimitiveType(data, mode, &geometryExe, nullptr); - if (error.isError()) - { - return error; - } + ANGLE_TRY(programD3D->getGeometryExecutableForPrimitiveType(context, mode, &geometryExe, + nullptr)); - ID3D11GeometryShader *geometryShader = - (geometryExe ? GetAs(geometryExe)->getGeometryShader() : NULL); - mAppliedGeometryShader = reinterpret_cast(geometryShader); - ASSERT(geometryShader); - mDeviceContext->GSSetShader(geometryShader, NULL, 0); + mStateManager.setGeometryShader( + &GetAs(geometryExe)->getGeometryShader()); - if (instances > 0) + if (adjustedInstanceCount > 0) { - mDeviceContext->DrawInstanced(count, instances, 0, 0); + mDeviceContext->DrawInstanced(count, adjustedInstanceCount, 0, 0); } else { mDeviceContext->Draw(count, 0); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } if (mode == GL_LINE_LOOP) { - return drawLineLoop(data, count, GL_NONE, nullptr, nullptr, instances); + return drawLineLoop(context, count, GL_NONE, nullptr, 0, adjustedInstanceCount); } if (mode == GL_TRIANGLE_FAN) { - return drawTriangleFan(data, count, GL_NONE, nullptr, 0, instances); + return drawTriangleFan(context, count, GL_NONE, nullptr, 0, adjustedInstanceCount); } bool useInstancedPointSpriteEmulation = programD3D->usesPointSize() && getWorkarounds().useInstancedPointSpriteEmulation; - if (instances > 0) + if (mode != GL_POINTS || !useInstancedPointSpriteEmulation) { - if (mode == GL_POINTS && useInstancedPointSpriteEmulation) + if (adjustedInstanceCount == 0) { - // If pointsprite emulation is used with glDrawArraysInstanced then we need to take a - // less efficent code path. - // Instanced rendering of emulated pointsprites requires a loop to draw each batch of - // points. An offset into the instanced data buffer is calculated and applied on each - // iteration to ensure all instances are rendered correctly. - - // Each instance being rendered requires the inputlayout cache to reapply buffers and - // offsets. - for (GLsizei i = 0; i < instances; i++) - { - gl::Error error = mInputLayoutCache.updateVertexOffsetsForPointSpritesEmulation(i); - if (error.isError()) - { - return error; - } - - mDeviceContext->DrawIndexedInstanced(6, count, 0, 0, 0); - } + mDeviceContext->Draw(count, 0); } else { - mDeviceContext->DrawInstanced(count, instances, 0, 0); + mDeviceContext->DrawInstanced(count, adjustedInstanceCount, 0, 0); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } + // This code should not be reachable by multi-view programs. + ASSERT(program->usesMultiview() == false); + // If the shader is writing to gl_PointSize, then pointsprites are being rendered. // Emulating instanced point sprites for FL9_3 requires the topology to be // D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST and DrawIndexedInstanced is called instead. - if (mode == GL_POINTS && useInstancedPointSpriteEmulation) + if (adjustedInstanceCount == 0) { mDeviceContext->DrawIndexedInstanced(6, count, 0, 0, 0); + return gl::NoError(); } - else - { - mDeviceContext->Draw(count, 0); - } - return gl::Error(GL_NO_ERROR); -} -gl::Error Renderer11::drawElementsImpl(const gl::Data &data, - const TranslatedIndexData &indexInfo, - GLenum mode, - GLsizei count, - GLenum type, - const GLvoid *indices, - GLsizei instances) -{ - int minIndex = static_cast(indexInfo.indexRange.start); - - if (mode == GL_LINE_LOOP) - { - return drawLineLoop(data, count, type, indices, &indexInfo, instances); - } - - if (mode == GL_TRIANGLE_FAN) - { - return drawTriangleFan(data, count, type, indices, minIndex, instances); - } - - const ProgramD3D *programD3D = GetImplAs(data.state->getProgram()); - if (instances > 0) + // If pointsprite emulation is used with glDrawArraysInstanced then we need to take a less + // efficent code path. Instanced rendering of emulated pointsprites requires a loop to draw each + // batch of points. An offset into the instanced data buffer is calculated and applied on each + // iteration to ensure all instances are rendered correctly. Each instance being rendered + // requires the inputlayout cache to reapply buffers and offsets. + for (GLsizei i = 0; i < instances; i++) { - if (mode == GL_POINTS && programD3D->usesInstancedPointSpriteEmulation()) - { - // If pointsprite emulation is used with glDrawElementsInstanced then we need to take a - // less efficent code path. - // Instanced rendering of emulated pointsprites requires a loop to draw each batch of - // points. An offset into the instanced data buffer is calculated and applied on each - // iteration to ensure all instances are rendered correctly. - GLsizei elementsToRender = static_cast(indexInfo.indexRange.vertexCount()); - - // Each instance being rendered requires the inputlayout cache to reapply buffers and - // offsets. - for (GLsizei i = 0; i < instances; i++) - { - gl::Error error = mInputLayoutCache.updateVertexOffsetsForPointSpritesEmulation(i); - if (error.isError()) - { - return error; - } - - mDeviceContext->DrawIndexedInstanced(6, elementsToRender, 0, 0, 0); - } - } - else - { - mDeviceContext->DrawIndexedInstanced(count, instances, 0, -minIndex, 0); - } - return gl::Error(GL_NO_ERROR); - } - - // If the shader is writing to gl_PointSize, then pointsprites are being rendered. - // Emulating instanced point sprites for FL9_3 requires the topology to be - // D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST and DrawIndexedInstanced is called instead. - if (mode == GL_POINTS && programD3D->usesInstancedPointSpriteEmulation()) - { - // The count parameter passed to drawElements represents the total number of instances - // to be rendered. Each instance is referenced by the bound index buffer from the - // the caller. - // - // Indexed pointsprite emulation replicates data for duplicate entries found - // in the index buffer. - // This is not an efficent rendering mechanism and is only used on downlevel renderers - // that do not support geometry shaders. + ANGLE_TRY(mStateManager.updateVertexOffsetsForPointSpritesEmulation(startVertex, i)); mDeviceContext->DrawIndexedInstanced(6, count, 0, 0, 0); } - else - { - mDeviceContext->DrawIndexed(count, 0, -minIndex); - } - return gl::Error(GL_NO_ERROR); + + // This required by updateVertexOffsets... above but is outside of the loop for speed. + mStateManager.invalidateVertexBuffer(); + return gl::NoError(); } -gl::Error Renderer11::drawLineLoop(const gl::Data &data, +gl::Error Renderer11::drawElements(const gl::Context *context, + GLenum mode, GLsizei count, GLenum type, - const GLvoid *indexPointer, - const TranslatedIndexData *indexInfo, - int instances) + const void *indices, + GLsizei instances) { - gl::VertexArray *vao = data.state->getVertexArray(); - gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get(); + const auto &glState = context->getGLState(); - const GLvoid *indices = indexPointer; - - // Get the raw indices for an indexed draw - if (type != GL_NONE && elementArrayBuffer) + if (!applyPrimitiveType(glState, mode, count)) { - 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; + return gl::NoError(); } - 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; - } - } + // Transform feedback is not allowed for DrawElements, this error should have been caught at the + // API validation layer. + ASSERT(!glState.isTransformFeedbackActiveUnpaused()); - // Checked by Renderer11::applyPrimitiveType - ASSERT(count >= 0); + const auto &lazyIndexRange = context->getParams(); - 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."); - } + bool usePrimitiveRestartWorkaround = + UsePrimitiveRestartWorkaround(glState.isPrimitiveRestartEnabled(), type); + DrawCallVertexParams vertexParams(!usePrimitiveRestartWorkaround, lazyIndexRange, 0, instances); - GetLineLoopIndices(indices, type, static_cast(count), - data.state->isPrimitiveRestartEnabled(), &mScratchIndexDataBuffer); + ANGLE_TRY(mStateManager.applyIndexBuffer(context, indices, count, type, lazyIndexRange, + usePrimitiveRestartWorkaround)); + ANGLE_TRY(mStateManager.applyVertexBuffer(context, mode, vertexParams, true)); - unsigned int spaceNeeded = - static_cast(sizeof(GLuint) * mScratchIndexDataBuffer.size()); - gl::Error error = mLineLoopIB->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_INT); - if (error.isError()) - { - return error; - } + int startVertex = static_cast(vertexParams.firstVertex()); + int baseVertex = -startVertex; - void* mappedMemory = NULL; - unsigned int offset; - error = mLineLoopIB->mapBuffer(spaceNeeded, &mappedMemory, &offset); - if (error.isError()) - { - return error; - } + const gl::Program *program = glState.getProgram(); + GLsizei adjustedInstanceCount = GetAdjustedInstanceCount(program, instances); - // Copy over the converted index data. - memcpy(mappedMemory, &mScratchIndexDataBuffer[0], - sizeof(GLuint) * mScratchIndexDataBuffer.size()); - - error = mLineLoopIB->unmapBuffer(); - if (error.isError()) - { - return error; - } - - IndexBuffer11 *indexBuffer = GetAs(mLineLoopIB->getIndexBuffer()); - ID3D11Buffer *d3dIndexBuffer = indexBuffer->getBuffer(); - DXGI_FORMAT indexFormat = indexBuffer->getIndexFormat(); - - if (mAppliedIB != d3dIndexBuffer || mAppliedIBFormat != indexFormat || - mAppliedIBOffset != offset) + if (mode == GL_LINE_LOOP) { - mDeviceContext->IASetIndexBuffer(d3dIndexBuffer, indexFormat, offset); - mAppliedIB = d3dIndexBuffer; - mAppliedIBFormat = indexFormat; - mAppliedIBOffset = offset; + return drawLineLoop(context, count, type, indices, baseVertex, adjustedInstanceCount); } - INT baseVertexLocation = (indexInfo ? -static_cast(indexInfo->indexRange.start) : 0); - UINT indexCount = static_cast(mScratchIndexDataBuffer.size()); - - if (instances > 0) - { - mDeviceContext->DrawIndexedInstanced(indexCount, instances, 0, baseVertexLocation, 0); - } - else + if (mode == GL_TRIANGLE_FAN) { - mDeviceContext->DrawIndexed(indexCount, 0, baseVertexLocation); + return drawTriangleFan(context, count, type, indices, baseVertex, adjustedInstanceCount); } - return gl::Error(GL_NO_ERROR); -} + const ProgramD3D *programD3D = GetImplAs(glState.getProgram()); -gl::Error Renderer11::drawTriangleFan(const gl::Data &data, - GLsizei count, - GLenum type, - const GLvoid *indices, - int minIndex, - int instances) -{ - gl::VertexArray *vao = data.state->getVertexArray(); - gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get(); - - const GLvoid *indexPointer = indices; - - // Get the raw indices for an indexed draw - if (type != GL_NONE && elementArrayBuffer) + if (mode != GL_POINTS || !programD3D->usesInstancedPointSpriteEmulation()) { - BufferD3D *storage = GetImplAs(elementArrayBuffer); - intptr_t offset = reinterpret_cast(indices); - - const uint8_t *bufferData = NULL; - gl::Error error = storage->getData(&bufferData); - if (error.isError()) + if (adjustedInstanceCount == 0) { - return error; + mDeviceContext->DrawIndexed(count, 0, baseVertex); } - - indexPointer = bufferData + offset; - } - - if (!mTriangleFanIB) - { - mTriangleFanIB = new StreamingIndexBufferInterface(this); - gl::Error error = mTriangleFanIB->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_INT); - if (error.isError()) + else { - SafeDelete(mTriangleFanIB); - return error; + mDeviceContext->DrawIndexedInstanced(count, adjustedInstanceCount, 0, baseVertex, 0); } + return gl::NoError(); } - // Checked by Renderer11::applyPrimitiveType - ASSERT(count >= 3); - - const GLuint numTris = count - 2; + // This code should not be reachable by multi-view programs. + ASSERT(program->usesMultiview() == false); - if (numTris > (std::numeric_limits::max() / (sizeof(unsigned int) * 3))) + // If the shader is writing to gl_PointSize, then pointsprites are being rendered. + // Emulating instanced point sprites for FL9_3 requires the topology to be + // D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST and DrawIndexedInstanced is called instead. + // + // The count parameter passed to drawElements represents the total number of instances to be + // rendered. Each instance is referenced by the bound index buffer from the the caller. + // + // Indexed pointsprite emulation replicates data for duplicate entries found in the index + // buffer. This is not an efficent rendering mechanism and is only used on downlevel renderers + // that do not support geometry shaders. + if (instances == 0) { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create a scratch index buffer for GL_TRIANGLE_FAN, too many indices required."); + mDeviceContext->DrawIndexedInstanced(6, count, 0, 0, 0); + return gl::NoError(); } - GetTriFanIndices(indexPointer, type, count, data.state->isPrimitiveRestartEnabled(), - &mScratchIndexDataBuffer); + // If pointsprite emulation is used with glDrawElementsInstanced then we need to take a less + // efficent code path. Instanced rendering of emulated pointsprites requires a loop to draw each + // batch of points. An offset into the instanced data buffer is calculated and applied on each + // iteration to ensure all instances are rendered correctly. + GLsizei elementsToRender = vertexParams.vertexCount(); - const unsigned int spaceNeeded = - static_cast(mScratchIndexDataBuffer.size() * sizeof(unsigned int)); - gl::Error error = mTriangleFanIB->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_INT); - if (error.isError()) + // Each instance being rendered requires the inputlayout cache to reapply buffers and offsets. + for (GLsizei i = 0; i < instances; i++) { - return error; - } - - void *mappedMemory = nullptr; - unsigned int offset; - error = mTriangleFanIB->mapBuffer(spaceNeeded, &mappedMemory, &offset); - if (error.isError()) - { - return error; + ANGLE_TRY(mStateManager.updateVertexOffsetsForPointSpritesEmulation(startVertex, i)); + mDeviceContext->DrawIndexedInstanced(6, elementsToRender, 0, 0, 0); } + mStateManager.invalidateVertexBuffer(); + return gl::NoError(); +} - memcpy(mappedMemory, &mScratchIndexDataBuffer[0], spaceNeeded); +gl::Error Renderer11::drawArraysIndirect(const gl::Context *context, + GLenum mode, + const void *indirect) +{ + const auto &glState = context->getGLState(); + ASSERT(!glState.isTransformFeedbackActiveUnpaused()); - error = mTriangleFanIB->unmapBuffer(); - if (error.isError()) + if (!applyPrimitiveType(glState, mode, std::numeric_limits::max() - 1)) { - return error; + return gl::NoError(); } - IndexBuffer11 *indexBuffer = GetAs(mTriangleFanIB->getIndexBuffer()); - ID3D11Buffer *d3dIndexBuffer = indexBuffer->getBuffer(); - DXGI_FORMAT indexFormat = indexBuffer->getIndexFormat(); + gl::Buffer *drawIndirectBuffer = glState.getTargetBuffer(gl::BufferBinding::DrawIndirect); + ASSERT(drawIndirectBuffer); + Buffer11 *storage = GetImplAs(drawIndirectBuffer); + uintptr_t offset = reinterpret_cast(indirect); - if (mAppliedIB != d3dIndexBuffer || mAppliedIBFormat != indexFormat || - mAppliedIBOffset != offset) + if (!DrawCallNeedsTranslation(context, mode)) { - mDeviceContext->IASetIndexBuffer(d3dIndexBuffer, indexFormat, offset); - mAppliedIB = d3dIndexBuffer; - mAppliedIBFormat = indexFormat; - mAppliedIBOffset = offset; + DrawCallVertexParams vertexParams(0, 0, 0); + ANGLE_TRY(mStateManager.applyVertexBuffer(context, mode, vertexParams, false)); + ID3D11Buffer *buffer = nullptr; + ANGLE_TRY_RESULT(storage->getBuffer(context, BUFFER_USAGE_INDIRECT), buffer); + mDeviceContext->DrawInstancedIndirect(buffer, static_cast(offset)); + return gl::NoError(); } - UINT indexCount = static_cast(mScratchIndexDataBuffer.size()); + const uint8_t *bufferData = nullptr; + ANGLE_TRY(storage->getData(context, &bufferData)); + ASSERT(bufferData); + const gl::DrawArraysIndirectCommand *args = + reinterpret_cast(bufferData + offset); + GLuint count = args->count; + GLuint instances = args->instanceCount; + GLuint first = args->first; - if (instances > 0) + DrawCallVertexParams vertexParams(first, count, instances); + ANGLE_TRY(mStateManager.applyVertexBuffer(context, mode, vertexParams, false)); + + if (mode == GL_LINE_LOOP) { - mDeviceContext->DrawIndexedInstanced(indexCount, instances, 0, -minIndex, 0); + return drawLineLoop(context, count, GL_NONE, nullptr, 0, instances); } - else + if (mode == GL_TRIANGLE_FAN) { - mDeviceContext->DrawIndexed(indexCount, 0, -minIndex); + return drawTriangleFan(context, count, GL_NONE, nullptr, 0, instances); } - return gl::Error(GL_NO_ERROR); + mDeviceContext->DrawInstanced(count, instances, 0, 0); + return gl::NoError(); } -gl::Error Renderer11::applyShadersImpl(const gl::Data &data, GLenum drawMode) +gl::Error Renderer11::drawElementsIndirect(const gl::Context *context, + GLenum mode, + GLenum type, + const void *indirect) { - ProgramD3D *programD3D = GetImplAs(data.state->getProgram()); - const auto &inputLayout = programD3D->getCachedInputLayout(); + const auto &glState = context->getGLState(); + ASSERT(!glState.isTransformFeedbackActiveUnpaused()); - ShaderExecutableD3D *vertexExe = NULL; - gl::Error error = programD3D->getVertexExecutableForInputLayout(inputLayout, &vertexExe, nullptr); - if (error.isError()) + if (!applyPrimitiveType(glState, mode, std::numeric_limits::max() - 1)) { - return error; + return gl::NoError(); } - const gl::Framebuffer *drawFramebuffer = data.state->getDrawFramebuffer(); - ShaderExecutableD3D *pixelExe = NULL; - error = programD3D->getPixelExecutableForFramebuffer(drawFramebuffer, &pixelExe); - if (error.isError()) - { - return error; - } + gl::Buffer *drawIndirectBuffer = glState.getTargetBuffer(gl::BufferBinding::DrawIndirect); + ASSERT(drawIndirectBuffer); + Buffer11 *storage = GetImplAs(drawIndirectBuffer); + uintptr_t offset = reinterpret_cast(indirect); - ShaderExecutableD3D *geometryExe = nullptr; - error = - programD3D->getGeometryExecutableForPrimitiveType(data, drawMode, &geometryExe, nullptr); - if (error.isError()) + // TODO(jmadill): Remove the if statement and compute indirect parameters lazily. + bool usePrimitiveRestartWorkaround = + UsePrimitiveRestartWorkaround(glState.isPrimitiveRestartEnabled(), type); + + if (!DrawCallNeedsTranslation(context, mode) && !IsStreamingIndexData(context, type)) { - return error; + ANGLE_TRY(mStateManager.applyIndexBuffer(context, nullptr, 0, type, gl::HasIndexRange(), + usePrimitiveRestartWorkaround)); + DrawCallVertexParams vertexParams(0, 0, 0); + ANGLE_TRY(mStateManager.applyVertexBuffer(context, mode, vertexParams, true)); + ID3D11Buffer *buffer = nullptr; + ANGLE_TRY_RESULT(storage->getBuffer(context, BUFFER_USAGE_INDIRECT), buffer); + mDeviceContext->DrawIndexedInstancedIndirect(buffer, static_cast(offset)); + return gl::NoError(); } - ID3D11VertexShader *vertexShader = (vertexExe ? GetAs(vertexExe)->getVertexShader() : NULL); + const uint8_t *bufferData = nullptr; + ANGLE_TRY(storage->getData(context, &bufferData)); + ASSERT(bufferData); - ID3D11PixelShader *pixelShader = NULL; - // Skip pixel shader if we're doing rasterizer discard. - bool rasterizerDiscard = data.state->getRasterizerState().rasterizerDiscard; - if (!rasterizerDiscard) - { - pixelShader = (pixelExe ? GetAs(pixelExe)->getPixelShader() : NULL); - } + const gl::DrawElementsIndirectCommand *cmd = + reinterpret_cast(bufferData + offset); + GLsizei count = cmd->count; + GLuint instances = cmd->primCount; + GLuint firstIndex = cmd->firstIndex; + GLint baseVertex = cmd->baseVertex; - ID3D11GeometryShader *geometryShader = NULL; - bool transformFeedbackActive = data.state->isTransformFeedbackActiveUnpaused(); - if (transformFeedbackActive) - { - geometryShader = (vertexExe ? GetAs(vertexExe)->getStreamOutShader() : NULL); - } - else - { - geometryShader = (geometryExe ? GetAs(geometryExe)->getGeometryShader() : NULL); - } + // TODO(jmadill): Fix const cast. + const gl::Type &typeInfo = gl::GetTypeInfo(type); + const void *indices = + reinterpret_cast(static_cast(firstIndex * typeInfo.bytes)); + gl::HasIndexRange lazyIndexRange(const_cast(context), count, type, indices); - bool dirtyUniforms = false; + ANGLE_TRY(mStateManager.applyIndexBuffer(context, indices, count, type, lazyIndexRange, + usePrimitiveRestartWorkaround)); - if (reinterpret_cast(vertexShader) != mAppliedVertexShader) - { - mDeviceContext->VSSetShader(vertexShader, NULL, 0); - mAppliedVertexShader = reinterpret_cast(vertexShader); - dirtyUniforms = true; - } + DrawCallVertexParams vertexParams(false, lazyIndexRange, baseVertex, instances); - if (reinterpret_cast(geometryShader) != mAppliedGeometryShader) - { - mDeviceContext->GSSetShader(geometryShader, NULL, 0); - mAppliedGeometryShader = reinterpret_cast(geometryShader); - dirtyUniforms = true; - } + ANGLE_TRY(mStateManager.applyVertexBuffer(context, mode, vertexParams, true)); - if (reinterpret_cast(pixelShader) != mAppliedPixelShader) + int baseVertexLocation = -static_cast(lazyIndexRange.getIndexRange().value().start); + + if (mode == GL_LINE_LOOP) { - mDeviceContext->PSSetShader(pixelShader, NULL, 0); - mAppliedPixelShader = reinterpret_cast(pixelShader); - dirtyUniforms = true; + return drawLineLoop(context, count, type, indices, baseVertexLocation, instances); } - if (dirtyUniforms) + if (mode == GL_TRIANGLE_FAN) { - programD3D->dirtyAllUniforms(); + return drawTriangleFan(context, count, type, indices, baseVertexLocation, instances); } - return gl::Error(GL_NO_ERROR); + mDeviceContext->DrawIndexedInstanced(count, instances, 0, baseVertexLocation, 0); + return gl::NoError(); } -gl::Error Renderer11::applyUniforms(const ProgramD3D &programD3D, - GLenum drawMode, - const std::vector &uniformArray) +gl::Error Renderer11::drawLineLoop(const gl::Context *context, + GLsizei count, + GLenum type, + const void *indexPointer, + int baseVertex, + int instances) { - unsigned int totalRegisterCountVS = 0; - unsigned int totalRegisterCountPS = 0; + const gl::State &glState = context->getGLState(); + gl::VertexArray *vao = glState.getVertexArray(); + gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get(); - bool vertexUniformsDirty = false; - bool pixelUniformsDirty = false; + const void *indices = indexPointer; - for (const D3DUniform *uniform : uniformArray) + // Get the raw indices for an indexed draw + if (type != GL_NONE && elementArrayBuffer) { - 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 UniformStorage11 *vertexUniformStorage = - GetAs(&programD3D.getVertexUniformStorage()); - const UniformStorage11 *fragmentUniformStorage = - GetAs(&programD3D.getFragmentUniformStorage()); - ASSERT(vertexUniformStorage); - ASSERT(fragmentUniformStorage); + BufferD3D *storage = GetImplAs(elementArrayBuffer); + intptr_t offset = reinterpret_cast(indices); - ID3D11Buffer *vertexConstantBuffer = vertexUniformStorage->getConstantBuffer(); - ID3D11Buffer *pixelConstantBuffer = fragmentUniformStorage->getConstantBuffer(); + const uint8_t *bufferData = nullptr; + ANGLE_TRY(storage->getData(context, &bufferData)); - float (*mapVS)[4] = NULL; - float (*mapPS)[4] = NULL; + indices = bufferData + offset; + } - if (totalRegisterCountVS > 0 && vertexUniformsDirty) + if (!mLineLoopIB) { - 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; + mLineLoopIB = new StreamingIndexBufferInterface(this); + gl::Error error = + mLineLoopIB->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_INT); + if (error.isError()) + { + SafeDelete(mLineLoopIB); + return error; + } } - if (totalRegisterCountPS > 0 && pixelUniformsDirty) + // Checked by Renderer11::applyPrimitiveType + ASSERT(count >= 0); + + if (static_cast(count) + 1 > + (std::numeric_limits::max() / sizeof(unsigned int))) { - 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; + return gl::OutOfMemory() << "Failed to create a 32-bit looping index buffer for " + "GL_LINE_LOOP, too many indices required."; } - for (const D3DUniform *uniform : uniformArray) - { - if (uniform->isSampler()) - continue; + GetLineLoopIndices(indices, type, static_cast(count), + glState.isPrimitiveRestartEnabled(), &mScratchIndexDataBuffer); - unsigned int componentCount = (4 - uniform->registerElement); + unsigned int spaceNeeded = + static_cast(sizeof(GLuint) * mScratchIndexDataBuffer.size()); + ANGLE_TRY(mLineLoopIB->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_INT)); - // we assume that uniforms from structs are arranged in struct order in our uniforms list. - // otherwise we would overwrite previously written regions of memory. + void *mappedMemory = nullptr; + unsigned int offset; + ANGLE_TRY(mLineLoopIB->mapBuffer(spaceNeeded, &mappedMemory, &offset)); - if (uniform->isReferencedByVertexShader() && mapVS) - { - memcpy(&mapVS[uniform->vsRegisterIndex][uniform->registerElement], uniform->data, - uniform->registerCount * sizeof(float) * componentCount); - } + // Copy over the converted index data. + memcpy(mappedMemory, &mScratchIndexDataBuffer[0], + sizeof(GLuint) * mScratchIndexDataBuffer.size()); - if (uniform->isReferencedByFragmentShader() && mapPS) - { - memcpy(&mapPS[uniform->psRegisterIndex][uniform->registerElement], uniform->data, - uniform->registerCount * sizeof(float) * componentCount); - } - } + ANGLE_TRY(mLineLoopIB->unmapBuffer()); - if (mapVS) - { - mDeviceContext->Unmap(vertexConstantBuffer, 0); - } + IndexBuffer11 *indexBuffer = GetAs(mLineLoopIB->getIndexBuffer()); + const d3d11::Buffer &d3dIndexBuffer = indexBuffer->getBuffer(); + DXGI_FORMAT indexFormat = indexBuffer->getIndexFormat(); - if (mapPS) - { - mDeviceContext->Unmap(pixelConstantBuffer, 0); - } + mStateManager.setIndexBuffer(d3dIndexBuffer.get(), indexFormat, offset); - if (mCurrentVertexConstantBuffer != vertexConstantBuffer) - { - mDeviceContext->VSSetConstantBuffers(0, 1, &vertexConstantBuffer); - mCurrentVertexConstantBuffer = vertexConstantBuffer; - } + UINT indexCount = static_cast(mScratchIndexDataBuffer.size()); - if (mCurrentPixelConstantBuffer != pixelConstantBuffer) + if (instances > 0) { - mDeviceContext->PSSetConstantBuffers(0, 1, &pixelConstantBuffer); - mCurrentPixelConstantBuffer = pixelConstantBuffer; + mDeviceContext->DrawIndexedInstanced(indexCount, instances, 0, baseVertex, 0); } - - // Driver uniforms - if (!mDriverConstantBufferVS) + else { - D3D11_BUFFER_DESC constantBufferDescription = {0}; - constantBufferDescription.ByteWidth = sizeof(dx_VertexConstants11); - 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); - ASSERT(SUCCEEDED(result)); - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create vertex shader constant buffer, result: 0x%X.", result); - } - mDeviceContext->VSSetConstantBuffers(1, 1, &mDriverConstantBufferVS); + mDeviceContext->DrawIndexed(indexCount, 0, baseVertex); } - if (!mDriverConstantBufferPS) - { - D3D11_BUFFER_DESC constantBufferDescription = {0}; - constantBufferDescription.ByteWidth = sizeof(dx_PixelConstants11); - constantBufferDescription.Usage = D3D11_USAGE_DEFAULT; - constantBufferDescription.BindFlags = D3D11_BIND_CONSTANT_BUFFER; - constantBufferDescription.CPUAccessFlags = 0; - constantBufferDescription.MiscFlags = 0; - constantBufferDescription.StructureByteStride = 0; + return gl::NoError(); +} - HRESULT result = mDevice->CreateBuffer(&constantBufferDescription, NULL, &mDriverConstantBufferPS); - ASSERT(SUCCEEDED(result)); - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create pixel shader constant buffer, result: 0x%X.", result); - } - mDeviceContext->PSSetConstantBuffers(1, 1, &mDriverConstantBufferPS); - } +gl::Error Renderer11::drawTriangleFan(const gl::Context *context, + GLsizei count, + GLenum type, + const void *indices, + int baseVertex, + int instances) +{ + const gl::State &glState = context->getGLState(); + gl::VertexArray *vao = glState.getVertexArray(); + gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get(); - const dx_VertexConstants11 &vertexConstants = mStateManager.getVertexConstants(); - if (memcmp(&vertexConstants, &mAppliedVertexConstants, sizeof(dx_VertexConstants11)) != 0) - { - ASSERT(mDriverConstantBufferVS != nullptr); - if (mDriverConstantBufferVS) - { - mDeviceContext->UpdateSubresource(mDriverConstantBufferVS, 0, NULL, &vertexConstants, - 16, 0); - memcpy(&mAppliedVertexConstants, &vertexConstants, sizeof(dx_VertexConstants11)); - } - } + const void *indexPointer = indices; - const dx_PixelConstants11 &pixelConstants = mStateManager.getPixelConstants(); - if (memcmp(&pixelConstants, &mAppliedPixelConstants, sizeof(dx_PixelConstants11)) != 0) + // Get the raw indices for an indexed draw + if (type != GL_NONE && elementArrayBuffer) { - ASSERT(mDriverConstantBufferPS != nullptr); - if (mDriverConstantBufferPS) - { - mDeviceContext->UpdateSubresource(mDriverConstantBufferPS, 0, NULL, &pixelConstants, 16, - 0); - memcpy(&mAppliedPixelConstants, &pixelConstants, sizeof(dx_PixelConstants11)); - } + BufferD3D *storage = GetImplAs(elementArrayBuffer); + intptr_t offset = reinterpret_cast(indices); + + const uint8_t *bufferData = nullptr; + ANGLE_TRY(storage->getData(context, &bufferData)); + + indexPointer = bufferData + offset; } - // GSSetConstantBuffers triggers device removal on 9_3, so we should only call it if necessary - if (programD3D.usesGeometryShader(drawMode)) + if (!mTriangleFanIB) { - // needed for the point sprite geometry shader - if (mCurrentGeometryConstantBuffer != mDriverConstantBufferPS) + mTriangleFanIB = new StreamingIndexBufferInterface(this); + gl::Error error = + mTriangleFanIB->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_INT); + if (error.isError()) { - ASSERT(mDriverConstantBufferPS != nullptr); - if (mDriverConstantBufferPS) - { - mDeviceContext->GSSetConstantBuffers(0, 1, &mDriverConstantBufferPS); - mCurrentGeometryConstantBuffer = mDriverConstantBufferPS; - } + SafeDelete(mTriangleFanIB); + return error; } } - return gl::Error(GL_NO_ERROR); -} + // Checked by Renderer11::applyPrimitiveType + ASSERT(count >= 3); -void Renderer11::markAllStateDirty() -{ - TRACE_EVENT0("gpu.angle", "Renderer11::markAllStateDirty"); + const GLuint numTris = count - 2; - for (size_t vsamplerId = 0; vsamplerId < mForceSetVertexSamplerStates.size(); ++vsamplerId) + if (numTris > (std::numeric_limits::max() / (sizeof(unsigned int) * 3))) { - mForceSetVertexSamplerStates[vsamplerId] = true; + return gl::OutOfMemory() << "Failed to create a scratch index buffer for GL_TRIANGLE_FAN, " + "too many indices required."; } - for (size_t fsamplerId = 0; fsamplerId < mForceSetPixelSamplerStates.size(); ++fsamplerId) - { - mForceSetPixelSamplerStates[fsamplerId] = true; - } + GetTriFanIndices(indexPointer, type, count, glState.isPrimitiveRestartEnabled(), + &mScratchIndexDataBuffer); - mStateManager.invalidateEverything(); + const unsigned int spaceNeeded = + static_cast(mScratchIndexDataBuffer.size() * sizeof(unsigned int)); + ANGLE_TRY(mTriangleFanIB->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_INT)); - mAppliedIB = NULL; - mAppliedIBFormat = DXGI_FORMAT_UNKNOWN; - mAppliedIBOffset = 0; + void *mappedMemory = nullptr; + unsigned int offset; + ANGLE_TRY(mTriangleFanIB->mapBuffer(spaceNeeded, &mappedMemory, &offset)); - mAppliedVertexShader = angle::DirtyPointer; - mAppliedGeometryShader = angle::DirtyPointer; - mAppliedPixelShader = angle::DirtyPointer; + memcpy(mappedMemory, &mScratchIndexDataBuffer[0], spaceNeeded); - mAppliedNumXFBBindings = static_cast(-1); + ANGLE_TRY(mTriangleFanIB->unmapBuffer()); - for (size_t i = 0; i < gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS; i++) - { - mAppliedTFBuffers[i] = NULL; - mAppliedTFOffsets[i] = 0; - } + IndexBuffer11 *indexBuffer = GetAs(mTriangleFanIB->getIndexBuffer()); + const d3d11::Buffer &d3dIndexBuffer = indexBuffer->getBuffer(); + DXGI_FORMAT indexFormat = indexBuffer->getIndexFormat(); - memset(&mAppliedVertexConstants, 0, sizeof(dx_VertexConstants11)); - memset(&mAppliedPixelConstants, 0, sizeof(dx_PixelConstants11)); + mStateManager.setIndexBuffer(d3dIndexBuffer.get(), indexFormat, offset); - mInputLayoutCache.markDirty(); + UINT indexCount = static_cast(mScratchIndexDataBuffer.size()); - for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS; i++) + if (instances > 0) { - mCurrentConstantBufferVS[i] = static_cast(-1); - mCurrentConstantBufferVSOffset[i] = 0; - mCurrentConstantBufferVSSize[i] = 0; - mCurrentConstantBufferPS[i] = static_cast(-1); - mCurrentConstantBufferPSOffset[i] = 0; - mCurrentConstantBufferPSSize[i] = 0; + mDeviceContext->DrawIndexedInstanced(indexCount, instances, 0, baseVertex, 0); + } + else + { + mDeviceContext->DrawIndexed(indexCount, 0, baseVertex); } - mCurrentVertexConstantBuffer = NULL; - mCurrentPixelConstantBuffer = NULL; - mCurrentGeometryConstantBuffer = NULL; - - mCurrentPrimitiveTopology = D3D_PRIMITIVE_TOPOLOGY_UNDEFINED; + return gl::NoError(); } void Renderer11::releaseDeviceResources() { + mStateManager.deinitialize(); mStateCache.clear(); - mInputLayoutCache.clear(); - SafeDelete(mVertexDataManager); - SafeDelete(mIndexDataManager); SafeDelete(mLineLoopIB); SafeDelete(mTriangleFanIB); SafeDelete(mBlit); @@ -2383,9 +2043,9 @@ void Renderer11::releaseDeviceResources() SafeDelete(mTrim); SafeDelete(mPixelTransfer); - SafeRelease(mDriverConstantBufferVS); - SafeRelease(mDriverConstantBufferPS); - SafeRelease(mSyncQuery); + mSyncQuery.reset(); + + mCachedResolveTexture.reset(); } // set notify to true to broadcast a message to all contexts of the device loss @@ -2393,24 +2053,18 @@ bool Renderer11::testDeviceLost() { bool isLost = false; + if (!mDevice) + { + return true; + } + // GetRemovedReason is used to test if the device is removed HRESULT result = mDevice->GetDeviceRemovedReason(); - isLost = d3d11::isDeviceLostError(result); + 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; + ERR() << "The D3D11 device was removed, " << gl::FmtHR(result); } return isLost; @@ -2419,27 +2073,24 @@ bool Renderer11::testDeviceLost() 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"); + PFN_D3D11_CREATE_DEVICE D3D11CreateDevice = + (PFN_D3D11_CREATE_DEVICE)GetProcAddress(mD3d11Module, "D3D11CreateDevice"); - if (D3D11CreateDevice == NULL) + if (D3D11CreateDevice == nullptr) { return false; } - ID3D11Device* dummyDevice; + ID3D11Device *dummyDevice; D3D_FEATURE_LEVEL dummyFeatureLevel; - ID3D11DeviceContext* dummyContext; + ID3D11DeviceContext *dummyContext; + UINT flags = (mCreateDebugDevice ? D3D11_CREATE_DEVICE_DEBUG : 0); ASSERT(mRequestedDriverType != D3D_DRIVER_TYPE_UNKNOWN); HRESULT result = D3D11CreateDevice( - NULL, mRequestedDriverType, NULL, - #if defined(_DEBUG) - D3D11_CREATE_DEVICE_DEBUG, - #else - 0, - #endif - mAvailableFeatureLevels.data(), static_cast(mAvailableFeatureLevels.size()), - D3D11_SDK_VERSION, &dummyDevice, &dummyFeatureLevel, &dummyContext); + nullptr, mRequestedDriverType, nullptr, flags, mAvailableFeatureLevels.data(), + static_cast(mAvailableFeatureLevels.size()), D3D11_SDK_VERSION, &dummyDevice, + &dummyFeatureLevel, &dummyContext); if (!mDevice || FAILED(result)) { @@ -2456,6 +2107,14 @@ void Renderer11::release() { RendererD3D::cleanup(); + mScratchMemoryBuffer.clear(); + + if (mAnnotator != nullptr) + { + gl::UninitializeDebugAnnotations(); + SafeDelete(mAnnotator); + } + releaseDeviceResources(); if (!mCreatedWithDeviceEXT) @@ -2468,9 +2127,8 @@ void Renderer11::release() SafeRelease(mDxgiFactory); SafeRelease(mDxgiAdapter); -#if defined(ANGLE_ENABLE_D3D11_1) + SafeRelease(mDeviceContext3); SafeRelease(mDeviceContext1); -#endif if (mDeviceContext) { @@ -2480,26 +2138,24 @@ void Renderer11::release() } SafeRelease(mDevice); -#if !defined(ANGLE_MINGW32_COMPAT) SafeRelease(mDebug); -#endif if (mD3d11Module) { FreeLibrary(mD3d11Module); - mD3d11Module = NULL; + mD3d11Module = nullptr; } if (mDxgiModule) { FreeLibrary(mDxgiModule); - mDxgiModule = NULL; + mDxgiModule = nullptr; } if (mDCompModule) { FreeLibrary(mDCompModule); - mDCompModule = NULL; + mDCompModule = nullptr; } mCompiler.release(); @@ -2515,12 +2171,10 @@ bool Renderer11::resetDevice() if (result.isError()) { - ERR("Could not reinitialize D3D11 device: %08X", result.getCode()); + ERR() << "Could not reinitialize D3D11 device: " << result; return false; } - mDeviceLost = false; - return true; } @@ -2531,8 +2185,10 @@ std::string Renderer11::getRendererDescription() const rendererString << mDescription; rendererString << " Direct3D11"; - rendererString << " vs_" << getMajorShaderModel() << "_" << getMinorShaderModel() << getShaderModelSuffix(); - rendererString << " ps_" << getMajorShaderModel() << "_" << getMinorShaderModel() << getShaderModelSuffix(); + rendererString << " vs_" << getMajorShaderModel() << "_" << getMinorShaderModel() + << getShaderModelSuffix(); + rendererString << " ps_" << getMajorShaderModel() << "_" << getMinorShaderModel() + << getShaderModelSuffix(); return rendererString.str(); } @@ -2540,12 +2196,12 @@ std::string Renderer11::getRendererDescription() const DeviceIdentifier Renderer11::getAdapterIdentifier() const { // Don't use the AdapterLuid here, since that doesn't persist across reboot. - DeviceIdentifier deviceIdentifier = { 0 }; - deviceIdentifier.VendorId = mAdapterDescription.VendorId; - deviceIdentifier.DeviceId = mAdapterDescription.DeviceId; - deviceIdentifier.SubSysId = mAdapterDescription.SubSysId; - deviceIdentifier.Revision = mAdapterDescription.Revision; - deviceIdentifier.FeatureLevel = static_cast(mRenderer11DeviceCaps.featureLevel); + DeviceIdentifier deviceIdentifier = {0}; + deviceIdentifier.VendorId = mAdapterDescription.VendorId; + deviceIdentifier.DeviceId = mAdapterDescription.DeviceId; + deviceIdentifier.SubSysId = mAdapterDescription.SubSysId; + deviceIdentifier.Revision = mAdapterDescription.Revision; + deviceIdentifier.FeatureLevel = static_cast(mRenderer11DeviceCaps.featureLevel); return deviceIdentifier; } @@ -2605,7 +2261,7 @@ 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. - if (!getRendererExtensions().textureFormatBGRA8888) + if (!getNativeExtensions().textureFormatBGRA8888) { mSupportsShareHandles = false; return false; @@ -2620,7 +2276,8 @@ bool Renderer11::getShareHandleSupport() const // Qt: we don't care about the 9_3 limitation #if 0 - // Also disable share handles on Feature Level 9_3, since it doesn't support share handles on RGBA8 textures/swapchains. + // Also disable share handles on Feature Level 9_3, since it doesn't support share handles on + // RGBA8 textures/swapchains. if (mRenderer11DeviceCaps.featureLevel <= D3D_FEATURE_LEVEL_9_3) { mSupportsShareHandles = false; @@ -2668,15 +2325,34 @@ bool Renderer11::getShareHandleSupport() const return true; } +bool Renderer11::getNV12TextureSupport() const +{ + HRESULT result; + UINT formatSupport; + result = mDevice->CheckFormatSupport(DXGI_FORMAT_NV12, &formatSupport); + if (result == E_FAIL) + { + return false; + } + return (formatSupport & D3D11_FORMAT_SUPPORT_TEXTURE2D) != 0; +} + int Renderer11::getMajorShaderModel() const { switch (mRenderer11DeviceCaps.featureLevel) { - case D3D_FEATURE_LEVEL_11_0: return D3D11_SHADER_MAJOR_VERSION; // 5 - case D3D_FEATURE_LEVEL_10_1: return D3D10_1_SHADER_MAJOR_VERSION; // 4 - 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; + case D3D_FEATURE_LEVEL_11_1: + 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; } } @@ -2684,11 +2360,18 @@ int Renderer11::getMinorShaderModel() const { switch (mRenderer11DeviceCaps.featureLevel) { - case D3D_FEATURE_LEVEL_11_0: return D3D11_SHADER_MINOR_VERSION; // 0 - case D3D_FEATURE_LEVEL_10_1: return D3D10_1_SHADER_MINOR_VERSION; // 1 - 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; + case D3D_FEATURE_LEVEL_11_1: + 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; } } @@ -2696,15 +2379,22 @@ std::string Renderer11::getShaderModelSuffix() const { switch (mRenderer11DeviceCaps.featureLevel) { - 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 ""; + case D3D_FEATURE_LEVEL_11_1: + 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 ""; } } -const WorkaroundsD3D &RendererD3D::getWorkarounds() const +const angle::WorkaroundsD3D &RendererD3D::getWorkarounds() const { if (!mWorkaroundsInitialized) { @@ -2715,42 +2405,31 @@ const WorkaroundsD3D &RendererD3D::getWorkarounds() const return mWorkarounds; } -gl::Error Renderer11::copyImage2D(const gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, - const gl::Offset &destOffset, TextureStorage *storage, GLint level) +gl::Error Renderer11::copyImageInternal(const gl::Context *context, + const gl::Framebuffer *framebuffer, + const gl::Rectangle &sourceRect, + GLenum destFormat, + const gl::Offset &destOffset, + RenderTargetD3D *destRenderTarget) { - const gl::FramebufferAttachment *colorbuffer = framebuffer->getReadColorbuffer(); - ASSERT(colorbuffer); + const gl::FramebufferAttachment *colorAttachment = framebuffer->getReadColorbuffer(); + ASSERT(colorAttachment); - RenderTarget11 *sourceRenderTarget = NULL; - gl::Error error = colorbuffer->getRenderTarget(&sourceRenderTarget); - if (error.isError()) - { - return error; - } + RenderTarget11 *sourceRenderTarget = nullptr; + ANGLE_TRY(colorAttachment->getRenderTarget(context, &sourceRenderTarget)); ASSERT(sourceRenderTarget); - ID3D11ShaderResourceView *source = sourceRenderTarget->getShaderResourceView(); - ASSERT(source); - - TextureStorage11_2D *storage11 = GetAs(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); + const d3d11::SharedSRV &source = sourceRenderTarget->getBlitShaderResourceView(); + ASSERT(source.valid()); - ID3D11RenderTargetView *dest = GetAs(destRenderTarget)->getRenderTargetView(); - ASSERT(dest); + const d3d11::RenderTargetView &dest = + GetAs(destRenderTarget)->getRenderTargetView(); + ASSERT(dest.valid()); gl::Box sourceArea(sourceRect.x, sourceRect.y, 0, sourceRect.width, sourceRect.height, 1); gl::Extents sourceSize(sourceRenderTarget->getWidth(), sourceRenderTarget->getHeight(), 1); - const bool invertSource = UsePresentPathFast(this, colorbuffer); + const bool invertSource = UsePresentPathFast(this, colorAttachment); if (invertSource) { sourceArea.y = sourceSize.height - sourceRect.y; @@ -2760,226 +2439,267 @@ gl::Error Renderer11::copyImage2D(const gl::Framebuffer *framebuffer, const gl:: 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, false); - if (error.isError()) - { - return error; - } - - storage11->invalidateSwizzleCacheLevel(level); + // Use nearest filtering because source and destination are the same size for the direct copy. + // Convert to the unsized format before calling copyTexture. + GLenum sourceFormat = colorAttachment->getFormat().info->format; + ANGLE_TRY(mBlit->copyTexture(context, source, sourceArea, sourceSize, sourceFormat, dest, + destArea, destSize, nullptr, gl::GetUnsizedFormat(destFormat), + GL_NEAREST, false, false, false)); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -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::Error Renderer11::copyImage2D(const gl::Context *context, + const gl::Framebuffer *framebuffer, + const gl::Rectangle &sourceRect, + GLenum destFormat, + const gl::Offset &destOffset, + TextureStorage *storage, + GLint level) { - const gl::FramebufferAttachment *colorbuffer = framebuffer->getReadColorbuffer(); - ASSERT(colorbuffer); + TextureStorage11_2D *storage11 = GetAs(storage); + ASSERT(storage11); - RenderTarget11 *sourceRenderTarget = NULL; - gl::Error error = colorbuffer->getRenderTarget(&sourceRenderTarget); - if (error.isError()) - { - return error; - } - ASSERT(sourceRenderTarget); + gl::ImageIndex index = gl::ImageIndex::Make2D(level); + RenderTargetD3D *destRenderTarget = nullptr; + ANGLE_TRY(storage11->getRenderTarget(context, index, &destRenderTarget)); + ASSERT(destRenderTarget); + + ANGLE_TRY(copyImageInternal(context, framebuffer, sourceRect, destFormat, destOffset, + destRenderTarget)); + + storage11->markLevelDirty(level); - ID3D11ShaderResourceView *source = sourceRenderTarget->getShaderResourceView(); - ASSERT(source); + return gl::NoError(); +} +gl::Error Renderer11::copyImageCube(const gl::Context *context, + const gl::Framebuffer *framebuffer, + const gl::Rectangle &sourceRect, + GLenum destFormat, + const gl::Offset &destOffset, + TextureStorage *storage, + GLenum target, + GLint level) +{ TextureStorage11_Cube *storage11 = GetAs(storage); ASSERT(storage11); - gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level); - RenderTargetD3D *destRenderTarget = NULL; - error = storage11->getRenderTarget(index, &destRenderTarget); - if (error.isError()) - { - return error; - } + gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level); + RenderTargetD3D *destRenderTarget = nullptr; + ANGLE_TRY(storage11->getRenderTarget(context, index, &destRenderTarget)); ASSERT(destRenderTarget); - ID3D11RenderTargetView *dest = GetAs(destRenderTarget)->getRenderTargetView(); - ASSERT(dest); + ANGLE_TRY(copyImageInternal(context, framebuffer, sourceRect, destFormat, destOffset, + destRenderTarget)); - gl::Box sourceArea(sourceRect.x, sourceRect.y, 0, sourceRect.width, sourceRect.height, 1); - gl::Extents sourceSize(sourceRenderTarget->getWidth(), sourceRenderTarget->getHeight(), 1); + storage11->markLevelDirty(level); - const bool invertSource = UsePresentPathFast(this, colorbuffer); - if (invertSource) - { - sourceArea.y = sourceSize.height - sourceRect.y; - sourceArea.height = -sourceArea.height; - } + return gl::NoError(); +} - gl::Box destArea(destOffset.x, destOffset.y, 0, sourceRect.width, sourceRect.height, 1); - gl::Extents destSize(destRenderTarget->getWidth(), destRenderTarget->getHeight(), 1); +gl::Error Renderer11::copyImage3D(const gl::Context *context, + const gl::Framebuffer *framebuffer, + const gl::Rectangle &sourceRect, + GLenum destFormat, + const gl::Offset &destOffset, + TextureStorage *storage, + GLint level) +{ + TextureStorage11_3D *storage11 = GetAs(storage); + ASSERT(storage11); - // 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, false); - if (error.isError()) - { - return error; - } + gl::ImageIndex index = gl::ImageIndex::Make3D(level, destOffset.z); + RenderTargetD3D *destRenderTarget = nullptr; + ANGLE_TRY(storage11->getRenderTarget(context, index, &destRenderTarget)); + ASSERT(destRenderTarget); - storage11->invalidateSwizzleCacheLevel(level); + ANGLE_TRY(copyImageInternal(context, framebuffer, sourceRect, destFormat, destOffset, + destRenderTarget)); - return gl::Error(GL_NO_ERROR); + storage11->markLevelDirty(level); + + return gl::NoError(); } -gl::Error Renderer11::copyImage3D(const gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, - const gl::Offset &destOffset, TextureStorage *storage, GLint level) +gl::Error Renderer11::copyImage2DArray(const gl::Context *context, + const gl::Framebuffer *framebuffer, + const gl::Rectangle &sourceRect, + GLenum destFormat, + const gl::Offset &destOffset, + TextureStorage *storage, + GLint level) { - const gl::FramebufferAttachment *colorbuffer = framebuffer->getReadColorbuffer(); - ASSERT(colorbuffer); + TextureStorage11_2DArray *storage11 = GetAs(storage); + ASSERT(storage11); - RenderTarget11 *sourceRenderTarget = NULL; - gl::Error error = colorbuffer->getRenderTarget(&sourceRenderTarget); - if (error.isError()) - { - return error; - } - ASSERT(sourceRenderTarget); + gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, destOffset.z); + RenderTargetD3D *destRenderTarget = nullptr; + ANGLE_TRY(storage11->getRenderTarget(context, index, &destRenderTarget)); + ASSERT(destRenderTarget); - ID3D11ShaderResourceView *source = sourceRenderTarget->getShaderResourceView(); - ASSERT(source); + ANGLE_TRY(copyImageInternal(context, framebuffer, sourceRect, destFormat, destOffset, + destRenderTarget)); + storage11->markLevelDirty(level); - TextureStorage11_3D *storage11 = GetAs(storage); - ASSERT(storage11); + return gl::NoError(); +} - gl::ImageIndex index = gl::ImageIndex::Make3D(level, destOffset.z); - RenderTargetD3D *destRenderTarget = NULL; - error = storage11->getRenderTarget(index, &destRenderTarget); - if (error.isError()) - { - return error; - } - ASSERT(destRenderTarget); +gl::Error Renderer11::copyTexture(const gl::Context *context, + const gl::Texture *source, + GLint sourceLevel, + const gl::Rectangle &sourceRect, + GLenum destFormat, + const gl::Offset &destOffset, + TextureStorage *storage, + GLenum destTarget, + GLint destLevel, + bool unpackFlipY, + bool unpackPremultiplyAlpha, + bool unpackUnmultiplyAlpha) +{ + TextureD3D *sourceD3D = GetImplAs(source); - ID3D11RenderTargetView *dest = GetAs(destRenderTarget)->getRenderTargetView(); - ASSERT(dest); + TextureStorage *sourceStorage = nullptr; + ANGLE_TRY(sourceD3D->getNativeTexture(context, &sourceStorage)); - gl::Box sourceArea(sourceRect.x, sourceRect.y, 0, sourceRect.width, sourceRect.height, 1); - gl::Extents sourceSize(sourceRenderTarget->getWidth(), sourceRenderTarget->getHeight(), 1); + TextureStorage11_2D *sourceStorage11 = GetAs(sourceStorage); + ASSERT(sourceStorage11); - gl::Box destArea(destOffset.x, destOffset.y, 0, sourceRect.width, sourceRect.height, 1); - gl::Extents destSize(destRenderTarget->getWidth(), destRenderTarget->getHeight(), 1); + TextureStorage11 *destStorage11 = GetAs(storage); + ASSERT(destStorage11); - // 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, false); - if (error.isError()) + // Check for fast path where a CopySubresourceRegion can be used. + if (unpackPremultiplyAlpha == unpackUnmultiplyAlpha && !unpackFlipY && + source->getFormat(GL_TEXTURE_2D, sourceLevel).info->format == destFormat && + sourceStorage11->getFormatSet().texFormat == destStorage11->getFormatSet().texFormat) { - return error; - } + const TextureHelper11 *sourceResource = nullptr; + ANGLE_TRY(sourceStorage11->getResource(context, &sourceResource)); - storage11->invalidateSwizzleCacheLevel(level); + gl::ImageIndex sourceIndex = gl::ImageIndex::Make2D(sourceLevel); + UINT sourceSubresource = sourceStorage11->getSubresourceIndex(sourceIndex); - return gl::Error(GL_NO_ERROR); -} + const TextureHelper11 *destResource = nullptr; + ANGLE_TRY(destStorage11->getResource(context, &destResource)); -gl::Error Renderer11::copyImage2DArray(const gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, - const gl::Offset &destOffset, TextureStorage *storage, GLint level) -{ - const gl::FramebufferAttachment *colorbuffer = framebuffer->getReadColorbuffer(); - ASSERT(colorbuffer); + gl::ImageIndex destIndex = gl::ImageIndex::MakeGeneric(destTarget, destLevel); + UINT destSubresource = destStorage11->getSubresourceIndex(destIndex); - RenderTarget11 *sourceRenderTarget = NULL; - gl::Error error = colorbuffer->getRenderTarget(&sourceRenderTarget); - if (error.isError()) - { - return error; - } - ASSERT(sourceRenderTarget); + D3D11_BOX sourceBox{ + static_cast(sourceRect.x), + static_cast(sourceRect.y), + 0u, + static_cast(sourceRect.x + sourceRect.width), + static_cast(sourceRect.y + sourceRect.height), + 1u, + }; - ID3D11ShaderResourceView *source = sourceRenderTarget->getShaderResourceView(); - ASSERT(source); + mDeviceContext->CopySubresourceRegion(destResource->get(), destSubresource, destOffset.x, + destOffset.y, destOffset.z, sourceResource->get(), + sourceSubresource, &sourceBox); + } + else + { + const d3d11::SharedSRV *sourceSRV = nullptr; + ANGLE_TRY(sourceStorage11->getSRVLevels(context, sourceLevel, sourceLevel, &sourceSRV)); - TextureStorage11_2DArray *storage11 = GetAs(storage); - ASSERT(storage11); + gl::ImageIndex destIndex = gl::ImageIndex::MakeGeneric(destTarget, destLevel); + RenderTargetD3D *destRenderTargetD3D = nullptr; + ANGLE_TRY(destStorage11->getRenderTarget(context, destIndex, &destRenderTargetD3D)); - gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, destOffset.z); - RenderTargetD3D *destRenderTarget = NULL; - error = storage11->getRenderTarget(index, &destRenderTarget); - if (error.isError()) - { - return error; - } - ASSERT(destRenderTarget); + RenderTarget11 *destRenderTarget11 = GetAs(destRenderTargetD3D); - ID3D11RenderTargetView *dest = GetAs(destRenderTarget)->getRenderTargetView(); - ASSERT(dest); + const d3d11::RenderTargetView &destRTV = destRenderTarget11->getRenderTargetView(); + ASSERT(destRTV.valid()); - gl::Box sourceArea(sourceRect.x, sourceRect.y, 0, sourceRect.width, sourceRect.height, 1); - gl::Extents sourceSize(sourceRenderTarget->getWidth(), sourceRenderTarget->getHeight(), 1); + gl::Box sourceArea(sourceRect.x, sourceRect.y, 0, sourceRect.width, sourceRect.height, 1); + gl::Extents sourceSize( + static_cast(source->getWidth(source->getTarget(), sourceLevel)), + static_cast(source->getHeight(source->getTarget(), sourceLevel)), 1); + if (unpackFlipY) + { + sourceArea.y += sourceArea.height; + sourceArea.height = -sourceArea.height; + } - gl::Box destArea(destOffset.x, destOffset.y, 0, sourceRect.width, sourceRect.height, 1); - gl::Extents destSize(destRenderTarget->getWidth(), destRenderTarget->getHeight(), 1); + gl::Box destArea(destOffset.x, destOffset.y, 0, sourceRect.width, sourceRect.height, 1); + gl::Extents destSize(destRenderTarget11->getWidth(), destRenderTarget11->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, false); - if (error.isError()) - { - return error; + // Use nearest filtering because source and destination are the same size for the direct + // copy + GLenum sourceFormat = source->getFormat(GL_TEXTURE_2D, sourceLevel).info->format; + ANGLE_TRY(mBlit->copyTexture(context, *sourceSRV, sourceArea, sourceSize, sourceFormat, + destRTV, destArea, destSize, nullptr, destFormat, GL_NEAREST, + false, unpackPremultiplyAlpha, unpackUnmultiplyAlpha)); } - storage11->invalidateSwizzleCacheLevel(level); + destStorage11->markLevelDirty(destLevel); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -void Renderer11::unapplyRenderTargets() +gl::Error Renderer11::copyCompressedTexture(const gl::Context *context, + const gl::Texture *source, + GLint sourceLevel, + TextureStorage *storage, + GLint destLevel) { - setOneTimeRenderTarget(NULL); -} + TextureStorage11_2D *destStorage11 = GetAs(storage); + ASSERT(destStorage11); -// When finished with this rendertarget, markAllStateDirty must be called. -void Renderer11::setOneTimeRenderTarget(ID3D11RenderTargetView *renderTargetView) -{ - ID3D11RenderTargetView *rtvArray[gl::IMPLEMENTATION_MAX_DRAW_BUFFERS] = {NULL}; + const TextureHelper11 *destResource = nullptr; + ANGLE_TRY(destStorage11->getResource(context, &destResource)); - rtvArray[0] = renderTargetView; + gl::ImageIndex destIndex = gl::ImageIndex::Make2D(destLevel); + UINT destSubresource = destStorage11->getSubresourceIndex(destIndex); - mDeviceContext->OMSetRenderTargets(getRendererCaps().maxDrawBuffers, rtvArray, NULL); + TextureD3D *sourceD3D = GetImplAs(source); + ASSERT(sourceD3D); - // Do not preserve the serial for this one-time-use render target - for (size_t rtIndex = 0; rtIndex < ArraySize(mAppliedRTVs); rtIndex++) - { - mAppliedRTVs[rtIndex] = angle::DirtyPointer; - } - mAppliedDSV = angle::DirtyPointer; + TextureStorage *sourceStorage = nullptr; + ANGLE_TRY(sourceD3D->getNativeTexture(context, &sourceStorage)); + + TextureStorage11_2D *sourceStorage11 = GetAs(sourceStorage); + ASSERT(sourceStorage11); + + const TextureHelper11 *sourceResource = nullptr; + ANGLE_TRY(sourceStorage11->getResource(context, &sourceResource)); + + gl::ImageIndex sourceIndex = gl::ImageIndex::Make2D(sourceLevel); + UINT sourceSubresource = sourceStorage11->getSubresourceIndex(sourceIndex); + + mDeviceContext->CopySubresourceRegion(destResource->get(), destSubresource, 0, 0, 0, + sourceResource->get(), sourceSubresource, nullptr); + + return gl::NoError(); } -gl::Error Renderer11::createRenderTarget(int width, int height, GLenum format, GLsizei samples, RenderTargetD3D **outRT) +gl::Error Renderer11::createRenderTarget(int width, + int height, + GLenum format, + GLsizei samples, + RenderTargetD3D **outRT) { - const d3d11::TextureFormat &formatInfo = d3d11::GetTextureFormatInfo(format, mRenderer11DeviceCaps); + const d3d11::Format &formatInfo = d3d11::Format::Get(format, mRenderer11DeviceCaps); - const gl::TextureCaps &textureCaps = getRendererTextureCaps().get(format); - GLuint supportedSamples = textureCaps.getNearestSamples(samples); + const gl::TextureCaps &textureCaps = getNativeTextureCaps().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.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; + 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 @@ -2987,110 +2707,105 @@ gl::Error Renderer11::createRenderTarget(int width, int height, GLenum format, G 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) + bindSRV = (formatInfo.srvFormat != DXGI_FORMAT_UNKNOWN); + + bool isMultisampledDepthStencil = bindDSV && desc.SampleDesc.Count > 1; + if (isMultisampledDepthStencil && + !mRenderer11DeviceCaps.supportsMultisampledDepthStencilSRVs) { - // 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); + bindSRV = false; } - desc.BindFlags = (bindRTV ? D3D11_BIND_RENDER_TARGET : 0) | - (bindDSV ? D3D11_BIND_DEPTH_STENCIL : 0) | + 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); - } + TextureHelper11 texture; + ANGLE_TRY(allocateTexture(desc, formatInfo, &texture)); - ID3D11ShaderResourceView *srv = NULL; + d3d11::SharedSRV srv; + d3d11::SharedSRV blitSRV; 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.Format = formatInfo.srvFormat; + srvDesc.ViewDimension = (supportedSamples == 0) ? D3D11_SRV_DIMENSION_TEXTURE2D + : D3D11_SRV_DIMENSION_TEXTURE2DMS; srvDesc.Texture2D.MostDetailedMip = 0; - srvDesc.Texture2D.MipLevels = 1; + srvDesc.Texture2D.MipLevels = 1; - result = mDevice->CreateShaderResourceView(texture, &srvDesc, &srv); - if (FAILED(result)) + ANGLE_TRY(allocateResource(srvDesc, texture.get(), &srv)); + + if (formatInfo.blitSRVFormat != formatInfo.srvFormat) + { + D3D11_SHADER_RESOURCE_VIEW_DESC blitSRVDesc; + blitSRVDesc.Format = formatInfo.blitSRVFormat; + blitSRVDesc.ViewDimension = (supportedSamples == 0) + ? D3D11_SRV_DIMENSION_TEXTURE2D + : D3D11_SRV_DIMENSION_TEXTURE2DMS; + blitSRVDesc.Texture2D.MostDetailedMip = 0; + blitSRVDesc.Texture2D.MipLevels = 1; + + ANGLE_TRY(allocateResource(blitSRVDesc, texture.get(), &blitSRV)); + } + else { - 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); + blitSRV = srv.makeCopy(); } } 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.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); - } + dsvDesc.Flags = 0; - *outRT = new TextureRenderTarget11(dsv, texture, srv, format, width, height, 1, supportedSamples); + d3d11::DepthStencilView dsv; + ANGLE_TRY(allocateResource(dsvDesc, texture.get(), &dsv)); - SafeRelease(dsv); + *outRT = new TextureRenderTarget11(std::move(dsv), texture, srv, format, formatInfo, + width, height, 1, supportedSamples); } 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.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); - } + d3d11::RenderTargetView rtv; + ANGLE_TRY(allocateResource(rtvDesc, texture.get(), &rtv)); - if (formatInfo.dataInitializerFunction != NULL) + if (formatInfo.dataInitializerFunction != nullptr) { - const float clearValues[4] = { 0.0f, 0.0f, 0.0f, 1.0f }; - mDeviceContext->ClearRenderTargetView(rtv, clearValues); + const float clearValues[4] = {0.0f, 0.0f, 0.0f, 1.0f}; + mDeviceContext->ClearRenderTargetView(rtv.get(), clearValues); } - *outRT = new TextureRenderTarget11(rtv, texture, srv, format, width, height, 1, supportedSamples); - - SafeRelease(rtv); + *outRT = new TextureRenderTarget11(std::move(rtv), texture, srv, blitSRV, format, + formatInfo, width, height, 1, supportedSamples); } else { UNREACHABLE(); } - - SafeRelease(texture); - SafeRelease(srv); } else { - *outRT = new TextureRenderTarget11(reinterpret_cast(NULL), NULL, NULL, format, width, height, 1, supportedSamples); + *outRT = new TextureRenderTarget11(d3d11::RenderTargetView(), TextureHelper11(), + d3d11::SharedSRV(), d3d11::SharedSRV(), format, + d3d11::Format::Get(GL_NONE, mRenderer11DeviceCaps), + width, height, 1, supportedSamples); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } gl::Error Renderer11::createRenderTargetCopy(RenderTargetD3D *source, RenderTargetD3D **outRT) @@ -3098,58 +2813,35 @@ gl::Error Renderer11::createRenderTargetCopy(RenderTargetD3D *source, RenderTarg ASSERT(source != nullptr); RenderTargetD3D *newRT = nullptr; - gl::Error error = createRenderTarget(source->getWidth(), source->getHeight(), - source->getInternalFormat(), source->getSamples(), &newRT); - if (error.isError()) - { - return error; - } + ANGLE_TRY(createRenderTarget(source->getWidth(), source->getHeight(), + source->getInternalFormat(), source->getSamples(), &newRT)); RenderTarget11 *source11 = GetAs(source); RenderTarget11 *dest11 = GetAs(newRT); - mDeviceContext->CopySubresourceRegion(dest11->getTexture(), dest11->getSubresourceIndex(), 0, 0, - 0, source11->getTexture(), + mDeviceContext->CopySubresourceRegion(dest11->getTexture().get(), dest11->getSubresourceIndex(), + 0, 0, 0, source11->getTexture().get(), source11->getSubresourceIndex(), nullptr); *outRT = newRT; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -FramebufferImpl *Renderer11::createFramebuffer(const gl::Framebuffer::Data &data) -{ - return new Framebuffer11(data, this); -} - -ShaderImpl *Renderer11::createShader(const gl::Shader::Data &data) -{ - return new ShaderD3D(data); -} - -ProgramImpl *Renderer11::createProgram(const gl::Program::Data &data) -{ - return new ProgramD3D(data, this); -} - -gl::Error Renderer11::loadExecutable(const void *function, +gl::Error Renderer11::loadExecutable(const uint8_t *function, size_t length, - ShaderType type, + gl::ShaderType type, const std::vector &streamOutVaryings, bool separatedOutputBuffers, ShaderExecutableD3D **outExecutable) { + ShaderData shaderData(function, length); + switch (type) { - case SHADER_VERTEX: + case gl::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); - } + d3d11::VertexShader vertexShader; + d3d11::GeometryShader streamOutShader; + ANGLE_TRY(allocateResource(shaderData, &vertexShader)); if (!streamOutVaryings.empty()) { @@ -3163,88 +2855,80 @@ gl::Error Renderer11::loadExecutable(const void *function, entry.SemanticName = streamOutVarying.semanticName.c_str(); entry.SemanticIndex = streamOutVarying.semanticIndex; entry.StartComponent = 0; - entry.ComponentCount = static_cast(streamOutVarying.componentCount); - entry.OutputSlot = static_cast( + entry.ComponentCount = static_cast(streamOutVarying.componentCount); + entry.OutputSlot = static_cast( (separatedOutputBuffers ? streamOutVarying.outputSlot : 0)); soDeclaration.push_back(entry); } - result = mDevice->CreateGeometryShaderWithStreamOutput( - function, static_cast(length), soDeclaration.data(), - static_cast(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); - } + ANGLE_TRY(allocateResource(shaderData, &soDeclaration, &streamOutShader)); } - *outExecutable = new ShaderExecutable11(function, length, vertexShader, streamOutShader); + *outExecutable = new ShaderExecutable11(function, length, std::move(vertexShader), + std::move(streamOutShader)); } break; - case SHADER_PIXEL: + case gl::SHADER_FRAGMENT: { - 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); + d3d11::PixelShader pixelShader; + ANGLE_TRY(allocateResource(shaderData, &pixelShader)); + *outExecutable = new ShaderExecutable11(function, length, std::move(pixelShader)); } break; - case SHADER_GEOMETRY: + case gl::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); + d3d11::GeometryShader geometryShader; + ANGLE_TRY(allocateResource(shaderData, &geometryShader)); + *outExecutable = new ShaderExecutable11(function, length, std::move(geometryShader)); + } + break; + case gl::SHADER_COMPUTE: + { + d3d11::ComputeShader computeShader; + ANGLE_TRY(allocateResource(shaderData, &computeShader)); + *outExecutable = new ShaderExecutable11(function, length, std::move(computeShader)); } break; - default: - UNREACHABLE(); - return gl::Error(GL_INVALID_OPERATION); + default: + UNREACHABLE(); + return gl::InternalError(); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } gl::Error Renderer11::compileToExecutable(gl::InfoLog &infoLog, const std::string &shaderHLSL, - ShaderType type, + gl::ShaderType type, const std::vector &streamOutVaryings, bool separatedOutputBuffers, - const D3DCompilerWorkarounds &workarounds, + const angle::CompilerWorkaroundsD3D &workarounds, ShaderExecutableD3D **outExectuable) { - const char *profileType = NULL; + std::stringstream profileStream; + 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); + case gl::SHADER_VERTEX: + profileStream << "vs"; + break; + case gl::SHADER_FRAGMENT: + profileStream << "ps"; + break; + case gl::SHADER_GEOMETRY: + profileStream << "gs"; + break; + case gl::SHADER_COMPUTE: + profileStream << "cs"; + break; + default: + UNREACHABLE(); + return gl::InternalError(); } - std::string profile = FormatString("%s_%d_%d%s", profileType, getMajorShaderModel(), getMinorShaderModel(), getShaderModelSuffix().c_str()); + profileStream << "_" << getMajorShaderModel() << "_" << getMinorShaderModel() + << getShaderModelSuffix(); + std::string profile = profileStream.str(); UINT flags = D3DCOMPILE_OPTIMIZATION_LEVEL2; @@ -3260,11 +2944,12 @@ gl::Error Renderer11::compileToExecutable(gl::InfoLog &infoLog, 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. + // 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, "default")); + configs.push_back(CompileConfig(flags | D3DCOMPILE_SKIP_VALIDATION, "skip validation")); configs.push_back(CompileConfig(flags | D3DCOMPILE_SKIP_OPTIMIZATION, "skip optimization")); if (getMajorShaderModel() == 4 && getShaderModelSuffix() != "") @@ -3276,26 +2961,26 @@ gl::Error Renderer11::compileToExecutable(gl::InfoLog &infoLog, CompileConfig(flags | D3DCOMPILE_AVOID_FLOW_CONTROL, "avoid flow control")); } - D3D_SHADER_MACRO loopMacros[] = { {"ANGLE_ENABLE_LOOP_FLATTEN", "1"}, {0, 0} }; + D3D_SHADER_MACRO loopMacros[] = {{"ANGLE_ENABLE_LOOP_FLATTEN", "1"}, {0, 0}}; - ID3DBlob *binary = NULL; + // TODO(jmadill): Use ComPtr? + ID3DBlob *binary = nullptr; std::string debugInfo; - gl::Error error = mCompiler.compileToBinary(infoLog, shaderHLSL, profile, configs, loopMacros, &binary, &debugInfo); - if (error.isError()) - { - return error; - } + ANGLE_TRY(mCompiler.compileToBinary(infoLog, shaderHLSL, profile, configs, loopMacros, &binary, + &debugInfo)); - // 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. + // 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); + *outExectuable = nullptr; + return gl::NoError(); } - error = loadExecutable(binary->GetBufferPointer(), binary->GetBufferSize(), type, - streamOutVaryings, separatedOutputBuffers, outExectuable); + gl::Error error = loadExecutable(reinterpret_cast(binary->GetBufferPointer()), + binary->GetBufferSize(), type, streamOutVaryings, + separatedOutputBuffers, outExectuable); SafeRelease(binary); if (error.isError()) @@ -3308,12 +2993,17 @@ gl::Error Renderer11::compileToExecutable(gl::InfoLog &infoLog, (*outExectuable)->appendDebugInfo(debugInfo); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); +} + +gl::Error Renderer11::ensureHLSLCompilerInitialized() +{ + return mCompiler.ensureInitialized(); } UniformStorageD3D *Renderer11::createUniformStorage(size_t storageSize) { - return new UniformStorage11(this, storageSize); + return new UniformStorage11(storageSize); } VertexBuffer *Renderer11::createVertexBuffer() @@ -3326,45 +3016,20 @@ IndexBuffer *Renderer11::createIndexBuffer() return new IndexBuffer11(this); } -BufferImpl *Renderer11::createBuffer() +StreamProducerImpl *Renderer11::createStreamProducerD3DTextureNV12( + egl::Stream::ConsumerType consumerType, + const egl::AttributeMap &attribs) { - Buffer11 *buffer = new Buffer11(this); - mAliveBuffers.insert(buffer); - return buffer; -} - -VertexArrayImpl *Renderer11::createVertexArray(const gl::VertexArray::Data &data) -{ - return new VertexArray11(data); -} - -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(); + return new StreamProducerNV12(this); } bool Renderer11::supportsFastCopyBufferToTexture(GLenum internalFormat) const { - ASSERT(getRendererExtensions().pixelBufferObject); + ASSERT(getNativeExtensions().pixelBufferObject); - const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(internalFormat); - const d3d11::TextureFormat &d3d11FormatInfo = d3d11::GetTextureFormatInfo(internalFormat, mRenderer11DeviceCaps); - const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(d3d11FormatInfo.texFormat); + const gl::InternalFormat &internalFormatInfo = gl::GetSizedInternalFormatInfo(internalFormat); + const d3d11::Format &d3d11FormatInfo = + d3d11::Format::Get(internalFormat, mRenderer11DeviceCaps); // sRGB formats do not work with D3D11 buffer SRVs if (internalFormatInfo.colorEncoding == GL_SRGB) @@ -3385,7 +3050,19 @@ bool Renderer11::supportsFastCopyBufferToTexture(GLenum internalFormat) const } // We don't support formats which we can't represent without conversion - if (dxgiFormatInfo.internalFormat != internalFormat) + if (d3d11FormatInfo.format().glInternalFormat != internalFormat) + { + return false; + } + + // Buffer SRV creation for this format was not working on Windows 10. + if (d3d11FormatInfo.texFormat == DXGI_FORMAT_B5G5R5A1_UNORM) + { + return false; + } + + // This format is not supported as a buffer SRV. + if (d3d11FormatInfo.texFormat == DXGI_FORMAT_A8_UNORM) { return false; } @@ -3393,11 +3070,17 @@ bool Renderer11::supportsFastCopyBufferToTexture(GLenum internalFormat) const return true; } -gl::Error Renderer11::fastCopyBufferToTexture(const gl::PixelUnpackState &unpack, unsigned int offset, RenderTargetD3D *destRenderTarget, - GLenum destinationFormat, GLenum sourcePixelsType, const gl::Box &destArea) +gl::Error Renderer11::fastCopyBufferToTexture(const gl::Context *context, + 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); + return mPixelTransfer->copyBufferToTexture(context, unpack, offset, destRenderTarget, + destinationFormat, sourcePixelsType, destArea); } ImageD3D *Renderer11::createImage() @@ -3405,31 +3088,44 @@ ImageD3D *Renderer11::createImage() return new Image11(this); } -gl::Error Renderer11::generateMipmap(ImageD3D *dest, ImageD3D *src) +gl::Error Renderer11::generateMipmap(const gl::Context *context, ImageD3D *dest, ImageD3D *src) { Image11 *dest11 = GetAs(dest); - Image11 *src11 = GetAs(src); - return Image11::generateMipmap(dest11, src11); + Image11 *src11 = GetAs(src); + return Image11::GenerateMipmap(context, dest11, src11, mRenderer11DeviceCaps); } -gl::Error Renderer11::generateMipmapsUsingD3D(TextureStorage *storage, - const gl::TextureState &textureState) +gl::Error Renderer11::generateMipmapUsingD3D(const gl::Context *context, + TextureStorage *storage, + const gl::TextureState &textureState) { TextureStorage11 *storage11 = GetAs(storage); ASSERT(storage11->isRenderTarget()); ASSERT(storage11->supportsNativeMipmapFunction()); - ID3D11ShaderResourceView *srv; - gl::Error error = storage11->getSRVLevels(textureState.baseLevel, textureState.maxLevel, &srv); - if (error.isError()) - { - return error; - } + const d3d11::SharedSRV *srv = nullptr; + ANGLE_TRY(storage11->getSRVLevels(context, textureState.getEffectiveBaseLevel(), + textureState.getEffectiveMaxLevel(), &srv)); + + mDeviceContext->GenerateMips(srv->get()); - mDeviceContext->GenerateMips(srv); + return gl::NoError(); +} - return gl::Error(GL_NO_ERROR); +gl::Error Renderer11::copyImage(const gl::Context *context, + ImageD3D *dest, + ImageD3D *source, + const gl::Rectangle &sourceRect, + const gl::Offset &destOffset, + bool unpackFlipY, + bool unpackPremultiplyAlpha, + bool unpackUnmultiplyAlpha) +{ + Image11 *dest11 = GetAs(dest); + Image11 *src11 = GetAs(source); + return Image11::CopyImage(context, dest11, src11, sourceRect, destOffset, unpackFlipY, + unpackPremultiplyAlpha, unpackUnmultiplyAlpha, mRenderer11DeviceCaps); } TextureStorage *Renderer11::createTextureStorage2D(SwapChainD3D *swapChain) @@ -3438,53 +3134,75 @@ TextureStorage *Renderer11::createTextureStorage2D(SwapChainD3D *swapChain) return new TextureStorage11_2D(this, swapChain11); } -TextureStorage *Renderer11::createTextureStorageEGLImage(EGLImageD3D *eglImage) +TextureStorage *Renderer11::createTextureStorageEGLImage(EGLImageD3D *eglImage, + RenderTargetD3D *renderTargetD3D) { - return new TextureStorage11_EGLImage(this, eglImage); + return new TextureStorage11_EGLImage(this, eglImage, GetAs(renderTargetD3D)); } -TextureStorage *Renderer11::createTextureStorage2D(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels, bool hintLevelZeroOnly) +TextureStorage *Renderer11::createTextureStorageExternal( + egl::Stream *stream, + const egl::Stream::GLTextureDescription &desc) { - return new TextureStorage11_2D(this, internalformat, renderTarget, width, height, levels, hintLevelZeroOnly); + return new TextureStorage11_External(this, stream, desc); } -TextureStorage *Renderer11::createTextureStorageCube(GLenum internalformat, bool renderTarget, int size, int levels, bool hintLevelZeroOnly) +TextureStorage *Renderer11::createTextureStorage2D(GLenum internalformat, + bool renderTarget, + GLsizei width, + GLsizei height, + int levels, + bool hintLevelZeroOnly) { - return new TextureStorage11_Cube(this, internalformat, renderTarget, size, levels, hintLevelZeroOnly); + return new TextureStorage11_2D(this, internalformat, renderTarget, width, height, levels, + hintLevelZeroOnly); } -TextureStorage *Renderer11::createTextureStorage3D(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth, int levels) +TextureStorage *Renderer11::createTextureStorageCube(GLenum internalformat, + bool renderTarget, + int size, + int levels, + bool hintLevelZeroOnly) { - return new TextureStorage11_3D(this, internalformat, renderTarget, width, height, depth, levels); + return new TextureStorage11_Cube(this, internalformat, renderTarget, size, levels, + hintLevelZeroOnly); } -TextureStorage *Renderer11::createTextureStorage2DArray(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth, int levels) +TextureStorage *Renderer11::createTextureStorage3D(GLenum internalformat, + bool renderTarget, + GLsizei width, + GLsizei height, + GLsizei depth, + int levels) { - return new TextureStorage11_2DArray(this, internalformat, renderTarget, width, height, depth, levels); + return new TextureStorage11_3D(this, internalformat, renderTarget, width, height, depth, + levels); } -TextureImpl *Renderer11::createTexture(GLenum target) +TextureStorage *Renderer11::createTextureStorage2DArray(GLenum internalformat, + bool renderTarget, + GLsizei width, + GLsizei height, + GLsizei depth, + int levels) { - 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; + return new TextureStorage11_2DArray(this, internalformat, renderTarget, width, height, depth, + levels); } -RenderbufferImpl *Renderer11::createRenderbuffer() +TextureStorage *Renderer11::createTextureStorage2DMultisample(GLenum internalformat, + GLsizei width, + GLsizei height, + int levels, + int samples, + bool fixedSampleLocations) { - RenderbufferD3D *renderbuffer = new RenderbufferD3D(this); - return renderbuffer; + return new TextureStorage11_2DMultisample(this, internalformat, width, height, levels, samples, + fixedSampleLocations); } -gl::Error Renderer11::readFromAttachment(const gl::FramebufferAttachment &srcAttachment, +gl::Error Renderer11::readFromAttachment(const gl::Context *context, + const gl::FramebufferAttachment &srcAttachment, const gl::Rectangle &sourceArea, GLenum format, GLenum type, @@ -3497,17 +3215,11 @@ gl::Error Renderer11::readFromAttachment(const gl::FramebufferAttachment &srcAtt const bool invertTexture = UsePresentPathFast(this, &srcAttachment); - RenderTargetD3D *renderTarget = nullptr; - gl::Error error = srcAttachment.getRenderTarget(&renderTarget); - if (error.isError()) - { - return error; - } - - RenderTarget11 *rt11 = GetAs(renderTarget); - ASSERT(rt11->getTexture()); + RenderTarget11 *rt11 = nullptr; + ANGLE_TRY(srcAttachment.getRenderTarget(context, &rt11)); + ASSERT(rt11->getTexture().valid()); - TextureHelper11 textureHelper = TextureHelper11::MakeAndReference(rt11->getTexture()); + const TextureHelper11 &textureHelper = rt11->getTexture(); unsigned int sourceSubResource = rt11->getSubresourceIndex(); const gl::Extents &texSize = textureHelper.getExtents(); @@ -3535,52 +3247,42 @@ gl::Error Renderer11::readFromAttachment(const gl::FramebufferAttachment &srcAtt if (safeArea.width == 0 || safeArea.height == 0) { // no work to do - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } gl::Extents safeSize(safeArea.width, safeArea.height, 1); - auto errorOrResult = CreateStagingTexture(textureHelper.getTextureType(), - textureHelper.getFormat(), safeSize, mDevice); - if (errorOrResult.isError()) - { - return errorOrResult.getError(); - } + TextureHelper11 stagingHelper; + ANGLE_TRY_RESULT( + createStagingTexture(textureHelper.getTextureType(), textureHelper.getFormatSet(), safeSize, + StagingAccess::READ), + stagingHelper); - TextureHelper11 stagingHelper(errorOrResult.getResult()); TextureHelper11 resolvedTextureHelper; // "srcTexture" usually points to the source texture. // For 2D multisampled textures, it points to the multisampled resolve texture. const TextureHelper11 *srcTexture = &textureHelper; - if (textureHelper.getTextureType() == GL_TEXTURE_2D && textureHelper.getSampleCount() > 1) + if (textureHelper.is2D() && textureHelper.getSampleCount() > 1) { D3D11_TEXTURE2D_DESC resolveDesc; resolveDesc.Width = static_cast(texSize.width); resolveDesc.Height = static_cast(texSize.height); - resolveDesc.MipLevels = 1; - resolveDesc.ArraySize = 1; + resolveDesc.MipLevels = 1; + resolveDesc.ArraySize = 1; resolveDesc.Format = textureHelper.getFormat(); - resolveDesc.SampleDesc.Count = 1; + resolveDesc.SampleDesc.Count = 1; resolveDesc.SampleDesc.Quality = 0; - resolveDesc.Usage = D3D11_USAGE_DEFAULT; - resolveDesc.BindFlags = 0; - resolveDesc.CPUAccessFlags = 0; - resolveDesc.MiscFlags = 0; + resolveDesc.Usage = D3D11_USAGE_DEFAULT; + resolveDesc.BindFlags = 0; + resolveDesc.CPUAccessFlags = 0; + resolveDesc.MiscFlags = 0; - ID3D11Texture2D *resolveTex2D = nullptr; - HRESULT result = mDevice->CreateTexture2D(&resolveDesc, nullptr, &resolveTex2D); - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, - "Renderer11::readTextureData failed to create internal resolve " - "texture for ReadPixels, HRESULT: 0x%X.", - result); - } + ANGLE_TRY( + allocateTexture(resolveDesc, textureHelper.getFormatSet(), &resolvedTextureHelper)); - mDeviceContext->ResolveSubresource(resolveTex2D, 0, textureHelper.getTexture2D(), + mDeviceContext->ResolveSubresource(resolvedTextureHelper.get(), 0, textureHelper.get(), sourceSubResource, textureHelper.getFormat()); - resolvedTextureHelper = TextureHelper11::MakeAndReference(resolveTex2D); sourceSubResource = 0; srcTexture = &resolvedTextureHelper; @@ -3594,132 +3296,66 @@ gl::Error Renderer11::readFromAttachment(const gl::FramebufferAttachment &srcAtt // Select the correct layer from a 3D attachment srcBox.front = 0; - if (textureHelper.getTextureType() == GL_TEXTURE_3D) + if (textureHelper.is3D()) { srcBox.front = static_cast(srcAttachment.layer()); } srcBox.back = srcBox.front + 1; - mDeviceContext->CopySubresourceRegion(stagingHelper.getResource(), 0, 0, 0, 0, - srcTexture->getResource(), sourceSubResource, &srcBox); - - if (invertTexture) - { - gl::PixelPackState invertTexturePack; - - // Create a new PixelPackState with reversed row order. Note that we can't just assign - // 'invertTexturePack' to be 'pack' (or memcpy) since that breaks the ref counting/object - // tracking in the 'pixelBuffer' members, causing leaks. Instead we must use - // pixelBuffer.set() twice, which performs the addRef/release correctly - invertTexturePack.alignment = pack.alignment; - invertTexturePack.pixelBuffer.set(pack.pixelBuffer.get()); - invertTexturePack.reverseRowOrder = !pack.reverseRowOrder; - - PackPixelsParams packParams(safeArea, format, type, outputPitch, invertTexturePack, 0); - error = packPixels(stagingHelper, packParams, pixelsOut); + mDeviceContext->CopySubresourceRegion(stagingHelper.get(), 0, 0, 0, 0, srcTexture->get(), + sourceSubResource, &srcBox); - invertTexturePack.pixelBuffer.set(nullptr); - - return error; - } - else + gl::Buffer *packBuffer = context->getGLState().getTargetBuffer(gl::BufferBinding::PixelPack); + if (!invertTexture) { - PackPixelsParams packParams(safeArea, format, type, outputPitch, pack, 0); + PackPixelsParams packParams(safeArea, format, type, outputPitch, pack, packBuffer, 0); return packPixels(stagingHelper, packParams, pixelsOut); } + + // Create a new PixelPackState with reversed row order. Note that we can't just assign + // 'invertTexturePack' to be 'pack' (or memcpy) since that breaks the ref counting/object + // tracking in the 'pixelBuffer' members, causing leaks. Instead we must use + // pixelBuffer.set() twice, which performs the addRef/release correctly + gl::PixelPackState invertTexturePack; + invertTexturePack.alignment = pack.alignment; + invertTexturePack.reverseRowOrder = !pack.reverseRowOrder; + + PackPixelsParams packParams(safeArea, format, type, outputPitch, invertTexturePack, packBuffer, + 0); + gl::Error error = packPixels(stagingHelper, packParams, pixelsOut); + ANGLE_TRY(error); + return gl::NoError(); } gl::Error Renderer11::packPixels(const TextureHelper11 &textureHelper, const PackPixelsParams ¶ms, uint8_t *pixelsOut) { - ID3D11Resource *readResource = textureHelper.getResource(); + ID3D11Resource *readResource = textureHelper.get(); D3D11_MAPPED_SUBRESOURCE mapping; HRESULT hr = mDeviceContext->Map(readResource, 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(textureHelper.getFormat()); - 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); - } + return gl::OutOfMemory() << "Failed to map internal texture for reading, " << gl::FmtHR(hr); } - else - { - ColorCopyFunction fastCopyFunc = - dxgiFormatInfo.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 = dxgiFormatInfo.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."); + uint8_t *source = static_cast(mapping.pData); + int inputPitch = static_cast(mapping.RowPitch); - 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; + const auto &formatInfo = textureHelper.getFormatSet(); + ASSERT(formatInfo.format().glInternalFormat != GL_NONE); - // readFunc and writeFunc will be using the same type of color, CopyTexImage - // will not allow the copy otherwise. - colorReadFunction(src, temp); - colorWriteFunction(temp, dest); - } - } - } - } + PackPixels(params, formatInfo.format(), inputPitch, source, pixelsOut); mDeviceContext->Unmap(readResource, 0); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error Renderer11::blitRenderbufferRect(const gl::Rectangle &readRectIn, +gl::Error Renderer11::blitRenderbufferRect(const gl::Context *context, + const gl::Rectangle &readRectIn, const gl::Rectangle &drawRectIn, RenderTargetD3D *readRenderTarget, RenderTargetD3D *drawRenderTarget, @@ -3735,63 +3371,64 @@ gl::Error Renderer11::blitRenderbufferRect(const gl::Rectangle &readRectIn, ASSERT(colorBlit != (depthBlit || stencilBlit)); RenderTarget11 *drawRenderTarget11 = GetAs(drawRenderTarget); - if (!drawRenderTarget) + if (!drawRenderTarget11) { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to retrieve the internal draw render target from the draw framebuffer."); + return gl::OutOfMemory() + << "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(); + const TextureHelper11 &drawTexture = drawRenderTarget11->getTexture(); + unsigned int drawSubresource = drawRenderTarget11->getSubresourceIndex(); RenderTarget11 *readRenderTarget11 = GetAs(readRenderTarget); - if (!readRenderTarget) + if (!readRenderTarget11) { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to retrieve the internal read render target from the read framebuffer."); + return gl::OutOfMemory() + << "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) + TextureHelper11 readTexture; + unsigned int readSubresource = 0; + d3d11::SharedSRV readSRV; + + if (readRenderTarget->isMultisampled()) { - ID3D11Resource *unresolvedResource = readRenderTarget11->getTexture(); - ID3D11Texture2D *unresolvedTexture = d3d11::DynamicCastComObject(unresolvedResource); + ANGLE_TRY_RESULT( + resolveMultisampledTexture(context, readRenderTarget11, depthBlit, stencilBlit), + readTexture); - if (unresolvedTexture) + if (!stencilBlit) { - readTexture = resolveMultisampledTexture(unresolvedTexture, readRenderTarget11->getSubresourceIndex()); - readSubresource = 0; + const auto &readFormatSet = readTexture.getFormatSet(); - SafeRelease(unresolvedTexture); + D3D11_SHADER_RESOURCE_VIEW_DESC viewDesc; + viewDesc.Format = readFormatSet.srvFormat; + viewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; + viewDesc.Texture2D.MipLevels = 1; + viewDesc.Texture2D.MostDetailedMip = 0; - 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."); - } + ANGLE_TRY(allocateResource(viewDesc, readTexture.get(), &readSRV)); } } else { - readTexture = readRenderTarget11->getTexture(); - readTexture->AddRef(); + ASSERT(readRenderTarget11); + readTexture = readRenderTarget11->getTexture(); readSubresource = readRenderTarget11->getSubresourceIndex(); - readSRV = readRenderTarget11->getShaderResourceView(); - readSRV->AddRef(); + readSRV = readRenderTarget11->getBlitShaderResourceView().makeCopy(); + if (!readSRV.valid()) + { + ASSERT(depthBlit || stencilBlit); + readSRV = readRenderTarget11->getShaderResourceView().makeCopy(); + } + ASSERT(readSRV.valid()); } - 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."); - } + // Stencil blits don't use shaders. + ASSERT(readSRV.valid() || stencilBlit); - gl::Extents readSize(readRenderTarget->getWidth(), readRenderTarget->getHeight(), 1); - gl::Extents drawSize(drawRenderTarget->getWidth(), drawRenderTarget->getHeight(), 1); + const gl::Extents readSize(readRenderTarget->getWidth(), readRenderTarget->getHeight(), 1); + const gl::Extents drawSize(drawRenderTarget->getWidth(), drawRenderTarget->getHeight(), 1); // From the spec: // "The actual region taken from the read framebuffer is limited to the intersection of the @@ -3801,8 +3438,32 @@ gl::Error Renderer11::blitRenderbufferRect(const gl::Rectangle &readRectIn, // by internally scaling the read and draw rectangles. gl::Rectangle readRect = readRectIn; gl::Rectangle drawRect = drawRectIn; - auto readToDrawX = [&drawRectIn, &readRectIn](int readOffset) + + auto flip = [](int val) { return val >= 0 ? 1 : -1; }; + + if (readRect.x > readSize.width && readRect.width < 0) + { + int delta = readRect.x - readSize.width; + readRect.x -= delta; + readRect.width += delta; + + int drawDelta = delta * flip(drawRect.width); + drawRect.x += drawDelta; + drawRect.width -= drawDelta; + } + + if (readRect.y > readSize.height && readRect.height < 0) { + int delta = readRect.y - readSize.height; + readRect.y -= delta; + readRect.height += delta; + + int drawDelta = delta * flip(drawRect.height); + drawRect.y += drawDelta; + drawRect.height -= drawDelta; + } + + auto readToDrawX = [&drawRectIn, &readRectIn](int readOffset) { double readToDrawScale = static_cast(drawRectIn.width) / static_cast(readRectIn.width); return static_cast(round(static_cast(readOffset) * readToDrawScale)); @@ -3818,8 +3479,7 @@ gl::Error Renderer11::blitRenderbufferRect(const gl::Rectangle &readRectIn, drawRect.width -= drawOffset; } - auto readToDrawY = [&drawRectIn, &readRectIn](int readOffset) - { + auto readToDrawY = [&drawRectIn, &readRectIn](int readOffset) { double readToDrawScale = static_cast(drawRectIn.height) / static_cast(readRectIn.height); return static_cast(round(static_cast(readOffset) * readToDrawScale)); @@ -3853,24 +3513,41 @@ gl::Error Renderer11::blitRenderbufferRect(const gl::Rectangle &readRectIn, drawRect.height += drawOffset; } - bool scissorNeeded = scissor && gl::ClipRectangle(drawRect, *scissor, NULL); + if (readRect.x1() > readSize.width) + { + int delta = readRect.x1() - readSize.width; + readRect.width -= delta; + drawRect.width -= delta * flip(drawRect.width); + } + + if (readRect.y1() > readSize.height) + { + int delta = readRect.y1() - readSize.height; + readRect.height -= delta; + drawRect.height -= delta * flip(drawRect.height); + } + + bool scissorNeeded = scissor && gl::ClipRectangle(drawRect, *scissor, nullptr); - const auto &destFormatInfo = gl::GetInternalFormatInfo(drawRenderTarget->getInternalFormat()); - const auto &srcFormatInfo = gl::GetInternalFormatInfo(readRenderTarget->getInternalFormat()); - const auto &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(drawRenderTarget11->getDXGIFormat()); + const auto &destFormatInfo = + gl::GetSizedInternalFormatInfo(drawRenderTarget->getInternalFormat()); + const auto &srcFormatInfo = + gl::GetSizedInternalFormatInfo(readRenderTarget->getInternalFormat()); + const auto &formatSet = drawRenderTarget11->getFormatSet(); + const auto &nativeFormat = formatSet.format(); // Some blits require masking off emulated texture channels. eg: from RGBA8 to RGB8, we // emulate RGB8 with RGBA8, so we need to mask off the alpha channel when we copy. gl::Color colorMask; - colorMask.red = (srcFormatInfo.redBits > 0) && (destFormatInfo.redBits == 0) && - (dxgiFormatInfo.redBits > 0); + colorMask.red = + (srcFormatInfo.redBits > 0) && (destFormatInfo.redBits == 0) && (nativeFormat.redBits > 0); colorMask.green = (srcFormatInfo.greenBits > 0) && (destFormatInfo.greenBits == 0) && - (dxgiFormatInfo.greenBits > 0); + (nativeFormat.greenBits > 0); colorMask.blue = (srcFormatInfo.blueBits > 0) && (destFormatInfo.blueBits == 0) && - (dxgiFormatInfo.blueBits > 0); + (nativeFormat.blueBits > 0); colorMask.alpha = (srcFormatInfo.alphaBits > 0) && (destFormatInfo.alphaBits == 0) && - (dxgiFormatInfo.alphaBits > 0); + (nativeFormat.alphaBits > 0); // We only currently support masking off the alpha channel. bool colorMaskingNeeded = colorMask.alpha; @@ -3884,18 +3561,19 @@ gl::Error Renderer11::blitRenderbufferRect(const gl::Rectangle &readRectIn, 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 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; - bool partialDSBlit = (dxgiFormatInfo.depthBits > 0 && depthBlit) != (dxgiFormatInfo.stencilBits > 0 && stencilBlit); + bool partialDSBlit = + (nativeFormat.depthBits > 0 && depthBlit) != (nativeFormat.stencilBits > 0 && stencilBlit); - gl::Error result(GL_NO_ERROR); - - if (readRenderTarget11->getDXGIFormat() == drawRenderTarget11->getDXGIFormat() && + if (readRenderTarget11->getFormatSet().formatID == + drawRenderTarget11->getFormatSet().formatID && !stretchRequired && !outOfBounds && !flipRequired && !partialDSBlit && !colorMaskingNeeded && (!(depthBlit || stencilBlit) || wholeBufferCopy)) { @@ -3903,16 +3581,17 @@ gl::Error Renderer11::blitRenderbufferRect(const gl::Rectangle &readRectIn, UINT dstY = drawRect.y; D3D11_BOX readBox; - readBox.left = readRect.x; - readBox.right = readRect.x + readRect.width; - readBox.top = readRect.y; + 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; + readBox.front = 0; + readBox.back = 1; if (scissorNeeded) { - // drawRect is guaranteed to have positive width and height because stretchRequired is false. + // 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) @@ -3937,11 +3616,10 @@ gl::Error Renderer11::blitRenderbufferRect(const gl::Rectangle &readRectIn, // 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; + D3D11_BOX *pSrcBox = wholeBufferCopy ? nullptr : &readBox; - mDeviceContext->CopySubresourceRegion(drawTexture, drawSubresource, dstX, dstY, 0, - readTexture, readSubresource, pSrcBox); - result = gl::Error(GL_NO_ERROR); + mDeviceContext->CopySubresourceRegion(drawTexture.get(), drawSubresource, dstX, dstY, 0, + readTexture.get(), readSubresource, pSrcBox); } else { @@ -3950,47 +3628,56 @@ gl::Error Renderer11::blitRenderbufferRect(const gl::Rectangle &readRectIn, if (depthBlit && stencilBlit) { - result = mBlit->copyDepthStencil(readTexture, readSubresource, readArea, readSize, - drawTexture, drawSubresource, drawArea, drawSize, - scissor); + ANGLE_TRY(mBlit->copyDepthStencil(readTexture, readSubresource, readArea, readSize, + drawTexture, drawSubresource, drawArea, drawSize, + scissor)); } else if (depthBlit) { - result = mBlit->copyDepth(readSRV, readArea, readSize, drawDSV, drawArea, drawSize, - scissor); + const d3d11::DepthStencilView &drawDSV = drawRenderTarget11->getDepthStencilView(); + ASSERT(readSRV.valid()); + ANGLE_TRY(mBlit->copyDepth(context, readSRV, readArea, readSize, drawDSV, drawArea, + drawSize, scissor)); } else if (stencilBlit) { - result = mBlit->copyStencil(readTexture, readSubresource, readArea, readSize, - drawTexture, drawSubresource, drawArea, drawSize, - scissor); + ANGLE_TRY(mBlit->copyStencil(context, readTexture, readSubresource, readArea, readSize, + drawTexture, drawSubresource, drawArea, drawSize, + scissor)); } else { + const d3d11::RenderTargetView &drawRTV = drawRenderTarget11->getRenderTargetView(); + // We don't currently support masking off any other channel than alpha bool maskOffAlpha = colorMaskingNeeded && colorMask.alpha; - result = mBlit->copyTexture(readSRV, readArea, readSize, drawRTV, drawArea, drawSize, - scissor, destFormatInfo.format, filter, maskOffAlpha); + ASSERT(readSRV.valid()); + ANGLE_TRY(mBlit->copyTexture( + context, readSRV, readArea, readSize, srcFormatInfo.format, drawRTV, drawArea, + drawSize, scissor, destFormatInfo.format, filter, maskOffAlpha, false, false)); } } - SafeRelease(readTexture); - SafeRelease(readSRV); - - return result; + return gl::NoError(); } bool Renderer11::isES3Capable() const { - return (d3d11_gl::GetMaximumClientVersion(mRenderer11DeviceCaps.featureLevel) > 2); -}; + return (d3d11_gl::GetMaximumClientVersion(mRenderer11DeviceCaps.featureLevel).major > 2); +} + +RendererClass Renderer11::getRendererClass() const +{ + return RENDERER_D3D11; +} void Renderer11::onSwap() { // Send histogram updates every half hour const double kHistogramUpdateInterval = 30 * 60; - const double currentTime = ANGLEPlatformCurrent()->monotonicallyIncreasingTime(); + auto *platform = ANGLEPlatformCurrent(); + const double currentTime = platform->monotonicallyIncreasingTime(platform); const double timeSinceLastUpdate = currentTime - mLastHistogramUpdateTime; if (timeSinceLastUpdate > kHistogramUpdateInterval) @@ -4005,7 +3692,7 @@ void Renderer11::updateHistograms() // Update the buffer CPU memory histogram { size_t sizeSum = 0; - for (auto &buffer : mAliveBuffers) + for (const Buffer11 *buffer : mAliveBuffers) { sizeSum += buffer->getTotalCPUBufferMemoryBytes(); } @@ -4015,53 +3702,71 @@ void Renderer11::updateHistograms() } } +void Renderer11::onBufferCreate(const Buffer11 *created) +{ + mAliveBuffers.insert(created); +} + void Renderer11::onBufferDelete(const Buffer11 *deleted) { mAliveBuffers.erase(deleted); } -ID3D11Texture2D *Renderer11::resolveMultisampledTexture(ID3D11Texture2D *source, unsigned int subresource) +gl::ErrorOrResult Renderer11::resolveMultisampledTexture( + const gl::Context *context, + RenderTarget11 *renderTarget, + bool depth, + bool stencil) { - D3D11_TEXTURE2D_DESC textureDesc; - source->GetDesc(&textureDesc); + if (depth && !stencil) + { + return mBlit->resolveDepth(context, renderTarget); + } - if (textureDesc.SampleDesc.Count > 1) + if (stencil) { - 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; + return mBlit->resolveStencil(context, renderTarget, depth); + } - 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; - } + const auto &formatSet = renderTarget->getFormatSet(); - mDeviceContext->ResolveSubresource(resolveTexture, 0, source, subresource, textureDesc.Format); - return resolveTexture; - } - else + ASSERT(renderTarget->isMultisampled()); + const d3d11::SharedSRV &sourceSRV = renderTarget->getShaderResourceView(); + D3D11_SHADER_RESOURCE_VIEW_DESC sourceSRVDesc; + sourceSRV.get()->GetDesc(&sourceSRVDesc); + ASSERT(sourceSRVDesc.ViewDimension == D3D_SRV_DIMENSION_TEXTURE2DMS); + + if (!mCachedResolveTexture.valid() || + mCachedResolveTexture.getExtents().width != renderTarget->getWidth() || + mCachedResolveTexture.getExtents().height != renderTarget->getHeight() || + mCachedResolveTexture.getFormat() != formatSet.texFormat) { - source->AddRef(); - return source; + D3D11_TEXTURE2D_DESC resolveDesc; + resolveDesc.Width = renderTarget->getWidth(); + resolveDesc.Height = renderTarget->getHeight(); + resolveDesc.MipLevels = 1; + resolveDesc.ArraySize = 1; + resolveDesc.Format = formatSet.texFormat; + resolveDesc.SampleDesc.Count = 1; + resolveDesc.SampleDesc.Quality = 0; + resolveDesc.Usage = D3D11_USAGE_DEFAULT; + resolveDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE; + resolveDesc.CPUAccessFlags = 0; + resolveDesc.MiscFlags = 0; + + ANGLE_TRY(allocateTexture(resolveDesc, formatSet, &mCachedResolveTexture)); } + + mDeviceContext->ResolveSubresource(mCachedResolveTexture.get(), 0, + renderTarget->getTexture().get(), + renderTarget->getSubresourceIndex(), formatSet.texFormat); + return mCachedResolveTexture; } bool Renderer11::getLUID(LUID *adapterLuid) const { adapterLuid->HighPart = 0; - adapterLuid->LowPart = 0; + adapterLuid->LowPart = 0; if (!mDxgiAdapter) { @@ -4078,45 +3783,70 @@ bool Renderer11::getLUID(LUID *adapterLuid) const return true; } -VertexConversionType Renderer11::getVertexConversionType(gl::VertexFormatType vertexFormatType) const +VertexConversionType Renderer11::getVertexConversionType( + gl::VertexFormatType vertexFormatType) const { - return d3d11::GetVertexFormatInfo(vertexFormatType, mRenderer11DeviceCaps.featureLevel).conversionType; + return d3d11::GetVertexFormatInfo(vertexFormatType, mRenderer11DeviceCaps.featureLevel) + .conversionType; } GLenum Renderer11::getVertexComponentType(gl::VertexFormatType vertexFormatType) const { - return d3d11::GetDXGIFormatInfo(d3d11::GetVertexFormatInfo(vertexFormatType, mRenderer11DeviceCaps.featureLevel).nativeFormat).componentType; + const auto &format = + d3d11::GetVertexFormatInfo(vertexFormatType, mRenderer11DeviceCaps.featureLevel); + return d3d11::GetComponentType(format.nativeFormat); } -void Renderer11::generateCaps(gl::Caps *outCaps, gl::TextureCapsMap *outTextureCaps, - gl::Extensions *outExtensions, gl::Limitations *outLimitations) const +gl::ErrorOrResult Renderer11::getVertexSpaceRequired( + const gl::VertexAttribute &attrib, + const gl::VertexBinding &binding, + GLsizei count, + GLsizei instances) const { - d3d11_gl::GenerateCaps(mDevice, mDeviceContext, mRenderer11DeviceCaps, outCaps, outTextureCaps, - outExtensions, outLimitations); -} + if (!attrib.enabled) + { + return 16u; + } -WorkaroundsD3D Renderer11::generateWorkarounds() const -{ - return d3d11::GenerateWorkarounds(mRenderer11DeviceCaps.featureLevel); + unsigned int elementCount = 0; + const unsigned int divisor = binding.getDivisor(); + if (instances == 0 || divisor == 0) + { + elementCount = count; + } + else + { + // Round up to divisor, if possible + elementCount = UnsignedCeilDivide(static_cast(instances), divisor); + } + + gl::VertexFormatType formatType = gl::GetVertexFormatType(attrib); + const D3D_FEATURE_LEVEL featureLevel = mRenderer11DeviceCaps.featureLevel; + const d3d11::VertexFormat &vertexFormatInfo = + d3d11::GetVertexFormatInfo(formatType, featureLevel); + const d3d11::DXGIFormatSize &dxgiFormatInfo = + d3d11::GetDXGIFormatSizeInfo(vertexFormatInfo.nativeFormat); + unsigned int elementSize = dxgiFormatInfo.pixelBytes; + if (elementSize > std::numeric_limits::max() / elementCount) + { + return gl::OutOfMemory() << "New vertex buffer size would result in an overflow."; + } + + return elementSize * elementCount; } -void Renderer11::createAnnotator() +void Renderer11::generateCaps(gl::Caps *outCaps, + gl::TextureCapsMap *outTextureCaps, + gl::Extensions *outExtensions, + gl::Limitations *outLimitations) const { - // The D3D11 renderer must choose the D3D9 debug annotator because the D3D11 interface - // method ID3DUserDefinedAnnotation::GetStatus on desktop builds doesn't work with the Graphics - // Diagnostics tools in Visual Studio 2013. - // The D3D9 annotator works properly for both D3D11 and D3D9. - // Incorrect status reporting can cause ANGLE to log unnecessary debug events. -#ifdef ANGLE_ENABLE_D3D9 - mAnnotator = new DebugAnnotator9(); -#else - mAnnotator = new DebugAnnotator11(); -#endif + d3d11_gl::GenerateCaps(mDevice, mDeviceContext, mRenderer11DeviceCaps, outCaps, outTextureCaps, + outExtensions, outLimitations); } -gl::Error Renderer11::clearTextures(gl::SamplerType samplerType, size_t rangeStart, size_t rangeEnd) +angle::WorkaroundsD3D Renderer11::generateWorkarounds() const { - return mStateManager.clearTextures(samplerType, rangeStart, rangeEnd); + return d3d11::GenerateWorkarounds(mRenderer11DeviceCaps, mAdapterDescription); } egl::Error Renderer11::getEGLDevice(DeviceImpl **device) @@ -4136,6 +3866,224 @@ egl::Error Renderer11::getEGLDevice(DeviceImpl **device) } *device = static_cast(mEGLDevice); - return egl::Error(EGL_SUCCESS); + return egl::NoError(); +} + +ContextImpl *Renderer11::createContext(const gl::ContextState &state) +{ + return new Context11(state, this); +} + +FramebufferImpl *Renderer11::createDefaultFramebuffer(const gl::FramebufferState &state) +{ + return new Framebuffer11(state, this); +} + +gl::Error Renderer11::getScratchMemoryBuffer(size_t requestedSize, angle::MemoryBuffer **bufferOut) +{ + if (!mScratchMemoryBuffer.get(requestedSize, bufferOut)) + { + return gl::OutOfMemory() << "Failed to allocate internal buffer."; + } + return gl::NoError(); +} + +gl::Version Renderer11::getMaxSupportedESVersion() const +{ + return d3d11_gl::GetMaximumClientVersion(mRenderer11DeviceCaps.featureLevel); +} + +gl::DebugAnnotator *Renderer11::getAnnotator() +{ + return mAnnotator; +} + +gl::Error Renderer11::applyComputeShader(const gl::Context *context) +{ + ANGLE_TRY(ensureHLSLCompilerInitialized()); + + const auto &glState = context->getGLState(); + ProgramD3D *programD3D = GetImplAs(glState.getProgram()); + + ShaderExecutableD3D *computeExe = nullptr; + ANGLE_TRY(programD3D->getComputeExecutable(&computeExe)); + ASSERT(computeExe != nullptr); + + mStateManager.setComputeShader(&GetAs(computeExe)->getComputeShader()); + ANGLE_TRY(mStateManager.applyComputeUniforms(programD3D)); + + return gl::NoError(); +} + +gl::Error Renderer11::dispatchCompute(const gl::Context *context, + GLuint numGroupsX, + GLuint numGroupsY, + GLuint numGroupsZ) +{ + ANGLE_TRY(mStateManager.updateStateForCompute(context, numGroupsX, numGroupsY, numGroupsZ)); + ANGLE_TRY(applyComputeShader(context)); + + mDeviceContext->Dispatch(numGroupsX, numGroupsY, numGroupsZ); + + return gl::NoError(); +} + +gl::ErrorOrResult Renderer11::createStagingTexture( + ResourceType textureType, + const d3d11::Format &formatSet, + const gl::Extents &size, + StagingAccess readAndWriteAccess) +{ + if (textureType == ResourceType::Texture2D) + { + D3D11_TEXTURE2D_DESC stagingDesc; + stagingDesc.Width = size.width; + stagingDesc.Height = size.height; + stagingDesc.MipLevels = 1; + stagingDesc.ArraySize = 1; + stagingDesc.Format = formatSet.texFormat; + 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; + + if (readAndWriteAccess == StagingAccess::READ_WRITE) + { + stagingDesc.CPUAccessFlags |= D3D11_CPU_ACCESS_WRITE; + } + + TextureHelper11 stagingTex; + ANGLE_TRY(allocateTexture(stagingDesc, formatSet, &stagingTex)); + return stagingTex; + } + ASSERT(textureType == ResourceType::Texture3D); + + D3D11_TEXTURE3D_DESC stagingDesc; + stagingDesc.Width = size.width; + stagingDesc.Height = size.height; + stagingDesc.Depth = 1; + stagingDesc.MipLevels = 1; + stagingDesc.Format = formatSet.texFormat; + stagingDesc.Usage = D3D11_USAGE_STAGING; + stagingDesc.BindFlags = 0; + stagingDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; + stagingDesc.MiscFlags = 0; + + TextureHelper11 stagingTex; + ANGLE_TRY(allocateTexture(stagingDesc, formatSet, &stagingTex)); + return stagingTex; +} + +gl::Error Renderer11::allocateTexture(const D3D11_TEXTURE2D_DESC &desc, + const d3d11::Format &format, + const D3D11_SUBRESOURCE_DATA *initData, + TextureHelper11 *textureOut) +{ + d3d11::Texture2D texture; + ANGLE_TRY(mResourceManager11.allocate(this, &desc, initData, &texture)); + textureOut->init(std::move(texture), desc, format); + return gl::NoError(); +} + +gl::Error Renderer11::allocateTexture(const D3D11_TEXTURE3D_DESC &desc, + const d3d11::Format &format, + const D3D11_SUBRESOURCE_DATA *initData, + TextureHelper11 *textureOut) +{ + d3d11::Texture3D texture; + ANGLE_TRY(mResourceManager11.allocate(this, &desc, initData, &texture)); + textureOut->init(std::move(texture), desc, format); + return gl::NoError(); +} + +gl::Error Renderer11::getBlendState(const d3d11::BlendStateKey &key, + const d3d11::BlendState **outBlendState) +{ + return mStateCache.getBlendState(this, key, outBlendState); +} + +gl::Error Renderer11::getRasterizerState(const gl::RasterizerState &rasterState, + bool scissorEnabled, + ID3D11RasterizerState **outRasterizerState) +{ + return mStateCache.getRasterizerState(this, rasterState, scissorEnabled, outRasterizerState); } + +gl::Error Renderer11::getDepthStencilState(const gl::DepthStencilState &dsState, + const d3d11::DepthStencilState **outDSState) +{ + return mStateCache.getDepthStencilState(this, dsState, outDSState); +} + +gl::Error Renderer11::getSamplerState(const gl::SamplerState &samplerState, + ID3D11SamplerState **outSamplerState) +{ + return mStateCache.getSamplerState(this, samplerState, outSamplerState); +} + +gl::Error Renderer11::clearRenderTarget(RenderTargetD3D *renderTarget, + const gl::ColorF &clearColorValue, + const float clearDepthValue, + const unsigned int clearStencilValue) +{ + RenderTarget11 *rt11 = GetAs(renderTarget); + + if (rt11->getDepthStencilView().valid()) + { + const auto &format = rt11->getFormatSet(); + const UINT clearFlags = (format.format().depthBits > 0 ? D3D11_CLEAR_DEPTH : 0) | + (format.format().stencilBits ? D3D11_CLEAR_STENCIL : 0); + mDeviceContext->ClearDepthStencilView(rt11->getDepthStencilView().get(), clearFlags, + clearDepthValue, + static_cast(clearStencilValue)); + return gl::NoError(); + } + + ASSERT(rt11->getRenderTargetView().valid()); + ID3D11RenderTargetView *rtv = rt11->getRenderTargetView().get(); + + // There are complications with some types of RTV and FL 9_3 with ClearRenderTargetView. + // See https://msdn.microsoft.com/en-us/library/windows/desktop/ff476388(v=vs.85).aspx + ASSERT(mRenderer11DeviceCaps.featureLevel > D3D_FEATURE_LEVEL_9_3 || !IsArrayRTV(rtv)); + + const auto &d3d11Format = rt11->getFormatSet(); + const auto &glFormat = gl::GetSizedInternalFormatInfo(renderTarget->getInternalFormat()); + + gl::ColorF safeClearColor = clearColorValue; + + if (d3d11Format.format().alphaBits > 0 && glFormat.alphaBits == 0) + { + safeClearColor.alpha = 1.0f; + } + + mDeviceContext->ClearRenderTargetView(rtv, &safeClearColor.red); + return gl::NoError(); +} + +bool Renderer11::canSelectViewInVertexShader() const +{ + return !getWorkarounds().selectViewInGeometryShader && + getRenderer11DeviceCaps().supportsVpRtIndexWriteFromVertexShader; +} + +gl::Error Renderer11::markTransformFeedbackUsage(const gl::Context *context) +{ + const gl::State &glState = context->getGLState(); + const gl::TransformFeedback *transformFeedback = glState.getCurrentTransformFeedback(); + for (size_t i = 0; i < transformFeedback->getIndexedBufferCount(); i++) + { + const gl::OffsetBindingPointer &binding = + transformFeedback->getIndexedBuffer(i); + if (binding.get() != nullptr) + { + BufferD3D *bufferD3D = GetImplAs(binding.get()); + ANGLE_TRY(bufferD3D->markTransformFeedbackUsage(context)); + } + } + + return gl::NoError(); } + +} // namespace rx diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Renderer11.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Renderer11.h index b4e7761ffc..a8c24e681b 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Renderer11.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Renderer11.h @@ -14,13 +14,14 @@ #include "libANGLE/AttributeMap.h" #include "libANGLE/angletypes.h" #include "libANGLE/renderer/d3d/HLSLCompiler.h" -#include "libANGLE/renderer/d3d/RendererD3D.h" +#include "libANGLE/renderer/d3d/ProgramD3D.h" #include "libANGLE/renderer/d3d/RenderTargetD3D.h" +#include "libANGLE/renderer/d3d/RendererD3D.h" #include "libANGLE/renderer/d3d/d3d11/DebugAnnotator11.h" -#include "libANGLE/renderer/d3d/d3d11/InputLayoutCache.h" -#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h" #include "libANGLE/renderer/d3d/d3d11/RenderStateCache.h" +#include "libANGLE/renderer/d3d/d3d11/ResourceManager11.h" #include "libANGLE/renderer/d3d/d3d11/StateManager11.h" +#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h" namespace gl { @@ -28,36 +29,46 @@ class FramebufferAttachment; struct ImageIndex; } -struct ID3D11DeviceContext1; - namespace rx { - -class VertexDataManager; -class IndexDataManager; -class StreamingIndexBufferInterface; class Blit11; class Buffer11; class Clear11; +class Context11; +class IndexDataManager; +struct PackPixelsParams; class PixelTransfer11; class RenderTarget11; +class StreamingIndexBufferInterface; class Trim11; -struct PackPixelsParams; +class VertexDataManager; struct Renderer11DeviceCaps { + Renderer11DeviceCaps(); + D3D_FEATURE_LEVEL featureLevel; - bool supportsDXGI1_2; // Support for DXGI 1.2 - bool supportsClearView; // Support for ID3D11DeviceContext1::ClearView - bool supportsConstantBufferOffsets; // Support for Constant buffer offset - UINT B5G6R5support; // Bitfield of D3D11_FORMAT_SUPPORT values for DXGI_FORMAT_B5G6R5_UNORM - UINT B4G4R4A4support; // Bitfield of D3D11_FORMAT_SUPPORT values for DXGI_FORMAT_B4G4R4A4_UNORM - UINT B5G5R5A1support; // Bitfield of D3D11_FORMAT_SUPPORT values for DXGI_FORMAT_B5G5R5A1_UNORM + bool supportsDXGI1_2; // Support for DXGI 1.2 + bool supportsClearView; // Support for ID3D11DeviceContext1::ClearView + bool supportsConstantBufferOffsets; // Support for Constant buffer offset + bool supportsVpRtIndexWriteFromVertexShader; // VP/RT can be selected in the Vertex Shader + // stage. + bool supportsMultisampledDepthStencilSRVs; // D3D feature level 10.0 no longer allows creation + // of textures with both the bind SRV and DSV flags + // when multisampled. Textures will need to be + // resolved before reading. crbug.com/656989 + UINT B5G6R5support; // Bitfield of D3D11_FORMAT_SUPPORT values for DXGI_FORMAT_B5G6R5_UNORM + UINT B5G6R5maxSamples; // Maximum number of samples supported by DXGI_FORMAT_B5G6R5_UNORM + UINT B4G4R4A4support; // Bitfield of D3D11_FORMAT_SUPPORT values for DXGI_FORMAT_B4G4R4A4_UNORM + UINT B4G4R4A4maxSamples; // Maximum number of samples supported by DXGI_FORMAT_B4G4R4A4_UNORM + UINT B5G5R5A1support; // Bitfield of D3D11_FORMAT_SUPPORT values for DXGI_FORMAT_B5G5R5A1_UNORM + UINT B5G5R5A1maxSamples; // Maximum number of samples supported by DXGI_FORMAT_B5G5R5A1_UNORM + Optional driverVersion; // Four-part driver version number. }; enum { - MAX_VERTEX_UNIFORM_VECTORS_D3D11 = 1024, + MAX_VERTEX_UNIFORM_VECTORS_D3D11 = 1024, MAX_FRAGMENT_UNIFORM_VECTORS_D3D11 = 1024 }; @@ -103,172 +114,244 @@ class Renderer11 : public RendererD3D { public: explicit Renderer11(egl::Display *display); - virtual ~Renderer11(); + ~Renderer11() override; egl::Error initialize() override; - virtual bool resetDevice(); + bool resetDevice() override; - egl::ConfigSet generateConfigs() const override; + egl::ConfigSet generateConfigs() override; void generateDisplayExtensions(egl::DisplayExtensions *outExtensions) const override; - gl::Error flush() override; - gl::Error finish() override; + ContextImpl *createContext(const gl::ContextState &state) override; + + gl::Error flush(); + gl::Error finish(); - SwapChainD3D *createSwapChain(NativeWindow nativeWindow, + bool isValidNativeWindow(EGLNativeWindowType window) const override; + NativeWindowD3D *createNativeWindow(EGLNativeWindowType window, + const egl::Config *config, + const egl::AttributeMap &attribs) const override; + + SwapChainD3D *createSwapChain(NativeWindowD3D *nativeWindow, HANDLE shareHandle, + IUnknown *d3dTexture, GLenum backBufferFormat, GLenum depthBufferFormat, - EGLint orientation) override; - - CompilerImpl *createCompiler() override; - - 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 std::vector &vertexUniformBuffers, - const std::vector &fragmentUniformBuffers) override; - - gl::Error updateState(const gl::Data &data, GLenum drawMode) override; - - virtual bool applyPrimitiveType(GLenum mode, GLsizei count, bool usesPointSize); - gl::Error applyRenderTarget(const gl::Framebuffer *frameBuffer) override; - gl::Error applyUniforms(const ProgramD3D &programD3D, - GLenum drawMode, - const std::vector &uniformArray) override; - virtual gl::Error applyVertexBuffer(const gl::State &state, - GLenum mode, - GLint first, - GLsizei count, - GLsizei instances, - TranslatedIndexData *indexInfo); - gl::Error applyIndexBuffer(const gl::Data &data, - const GLvoid *indices, - GLsizei count, - GLenum mode, - GLenum type, - TranslatedIndexData *indexInfo) override; - void applyTransformFeedbackBuffers(const gl::State &state) override; + EGLint orientation, + EGLint samples) override; + egl::Error getD3DTextureInfo(const egl::Config *configuration, + IUnknown *d3dTexture, + EGLint *width, + EGLint *height, + GLenum *fboFormat) const override; + egl::Error validateShareHandle(const egl::Config *config, + HANDLE shareHandle, + const egl::AttributeMap &attribs) const override; + + bool applyPrimitiveType(const gl::State &glState, GLenum mode, GLsizei count); // lost device bool testDeviceLost() override; bool testDeviceResettable() override; - std::string getRendererDescription() const override; + std::string getRendererDescription() const; DeviceIdentifier getAdapterIdentifier() const override; - virtual unsigned int getReservedVertexUniformVectors() const; - virtual unsigned int getReservedFragmentUniformVectors() const; - virtual unsigned int getReservedVertexUniformBuffers() const; - virtual unsigned int getReservedFragmentUniformBuffers() const; + unsigned int getReservedVertexUniformVectors() const; + unsigned int getReservedFragmentUniformVectors() const; + unsigned int getReservedVertexUniformBuffers() const; + unsigned int getReservedFragmentUniformBuffers() const; bool getShareHandleSupport() const; - virtual int getMajorShaderModel() const; + bool getNV12TextureSupport() const; + + int getMajorShaderModel() const override; 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); + gl::Error copyImage2D(const gl::Context *context, + const gl::Framebuffer *framebuffer, + const gl::Rectangle &sourceRect, + GLenum destFormat, + const gl::Offset &destOffset, + TextureStorage *storage, + GLint level) override; + gl::Error copyImageCube(const gl::Context *context, + const gl::Framebuffer *framebuffer, + const gl::Rectangle &sourceRect, + GLenum destFormat, + const gl::Offset &destOffset, + TextureStorage *storage, + GLenum target, + GLint level) override; + gl::Error copyImage3D(const gl::Context *context, + const gl::Framebuffer *framebuffer, + const gl::Rectangle &sourceRect, + GLenum destFormat, + const gl::Offset &destOffset, + TextureStorage *storage, + GLint level) override; + gl::Error copyImage2DArray(const gl::Context *context, + const gl::Framebuffer *framebuffer, + const gl::Rectangle &sourceRect, + GLenum destFormat, + const gl::Offset &destOffset, + TextureStorage *storage, + GLint level) override; + + gl::Error copyTexture(const gl::Context *context, + const gl::Texture *source, + GLint sourceLevel, + const gl::Rectangle &sourceRect, + GLenum destFormat, + const gl::Offset &destOffset, + TextureStorage *storage, + GLenum destTarget, + GLint destLevel, + bool unpackFlipY, + bool unpackPremultiplyAlpha, + bool unpackUnmultiplyAlpha) override; + gl::Error copyCompressedTexture(const gl::Context *context, + const gl::Texture *source, + GLint sourceLevel, + TextureStorage *storage, + GLint destLevel) override; // RenderTarget creation - virtual gl::Error createRenderTarget(int width, int height, GLenum format, GLsizei samples, RenderTargetD3D **outRT); + gl::Error createRenderTarget(int width, + int height, + GLenum format, + GLsizei samples, + RenderTargetD3D **outRT) override; gl::Error createRenderTargetCopy(RenderTargetD3D *source, RenderTargetD3D **outRT) override; - // Framebuffer creation - FramebufferImpl *createFramebuffer(const gl::Framebuffer::Data &data) override; - - // Shader creation - ShaderImpl *createShader(const gl::Shader::Data &data) override; - ProgramImpl *createProgram(const gl::Program::Data &data) override; - // Shader operations - gl::Error loadExecutable(const void *function, + gl::Error loadExecutable(const uint8_t *function, size_t length, - ShaderType type, + gl::ShaderType type, const std::vector &streamOutVaryings, bool separatedOutputBuffers, ShaderExecutableD3D **outExecutable) override; gl::Error compileToExecutable(gl::InfoLog &infoLog, const std::string &shaderHLSL, - ShaderType type, + gl::ShaderType type, const std::vector &streamOutVaryings, bool separatedOutputBuffers, - const D3DCompilerWorkarounds &workarounds, + const angle::CompilerWorkaroundsD3D &workarounds, ShaderExecutableD3D **outExectuable) override; + gl::Error ensureHLSLCompilerInitialized() override; + UniformStorageD3D *createUniformStorage(size_t storageSize) override; // Image operations - virtual ImageD3D *createImage(); - gl::Error generateMipmap(ImageD3D *dest, ImageD3D *source) override; - gl::Error generateMipmapsUsingD3D(TextureStorage *storage, - const gl::TextureState &textureState) override; - virtual TextureStorage *createTextureStorage2D(SwapChainD3D *swapChain); - TextureStorage *createTextureStorageEGLImage(EGLImageD3D *eglImage) override; - 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 - VertexArrayImpl *createVertexArray(const gl::VertexArray::Data &data) override; - - // Query and Fence creation - virtual QueryImpl *createQuery(GLenum type); - virtual FenceNVImpl *createFenceNV(); - virtual FenceSyncImpl *createFenceSync(); - - // Transform Feedback creation - virtual TransformFeedbackImpl* createTransformFeedback(); + ImageD3D *createImage() override; + gl::Error generateMipmap(const gl::Context *context, ImageD3D *dest, ImageD3D *source) override; + gl::Error generateMipmapUsingD3D(const gl::Context *context, + TextureStorage *storage, + const gl::TextureState &textureState) override; + gl::Error copyImage(const gl::Context *context, + ImageD3D *dest, + ImageD3D *source, + const gl::Rectangle &sourceRect, + const gl::Offset &destOffset, + bool unpackFlipY, + bool unpackPremultiplyAlpha, + bool unpackUnmultiplyAlpha) override; + TextureStorage *createTextureStorage2D(SwapChainD3D *swapChain) override; + TextureStorage *createTextureStorageEGLImage(EGLImageD3D *eglImage, + RenderTargetD3D *renderTargetD3D) override; + TextureStorage *createTextureStorageExternal( + egl::Stream *stream, + const egl::Stream::GLTextureDescription &desc) override; + TextureStorage *createTextureStorage2D(GLenum internalformat, + bool renderTarget, + GLsizei width, + GLsizei height, + int levels, + bool hintLevelZeroOnly) override; + TextureStorage *createTextureStorageCube(GLenum internalformat, + bool renderTarget, + int size, + int levels, + bool hintLevelZeroOnly) override; + TextureStorage *createTextureStorage3D(GLenum internalformat, + bool renderTarget, + GLsizei width, + GLsizei height, + GLsizei depth, + int levels) override; + TextureStorage *createTextureStorage2DArray(GLenum internalformat, + bool renderTarget, + GLsizei width, + GLsizei height, + GLsizei depth, + int levels) override; + TextureStorage *createTextureStorage2DMultisample(GLenum internalformat, + GLsizei width, + GLsizei height, + int levels, + int samples, + bool fixedSampleLocations) override; + + VertexBuffer *createVertexBuffer() override; + IndexBuffer *createIndexBuffer() override; + + // Stream Creation + StreamProducerImpl *createStreamProducerD3DTextureNV12( + egl::Stream::ConsumerType consumerType, + const egl::AttributeMap &attribs) override; // D3D11-renderer specific methods ID3D11Device *getDevice() { return mDevice; } void *getD3DDevice() override; ID3D11DeviceContext *getDeviceContext() { return mDeviceContext; }; ID3D11DeviceContext1 *getDeviceContext1IfSupported() { return mDeviceContext1; }; - DXGIFactory *getDxgiFactory() { return mDxgiFactory; }; - - RenderStateCache &getStateCache() { return mStateCache; } + IDXGIFactory *getDxgiFactory() { return mDxgiFactory; }; + + gl::Error getBlendState(const d3d11::BlendStateKey &key, + const d3d11::BlendState **outBlendState); + gl::Error getRasterizerState(const gl::RasterizerState &rasterState, + bool scissorEnabled, + ID3D11RasterizerState **outRasterizerState); + gl::Error getDepthStencilState(const gl::DepthStencilState &dsState, + const d3d11::DepthStencilState **outDSState); + gl::Error getSamplerState(const gl::SamplerState &samplerState, + ID3D11SamplerState **outSamplerState); Blit11 *getBlitter() { return mBlit; } Clear11 *getClearer() { return mClear; } + gl::DebugAnnotator *getAnnotator(); // 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); + bool supportsFastCopyBufferToTexture(GLenum internalFormat) const override; + gl::Error fastCopyBufferToTexture(const gl::Context *context, + const gl::PixelUnpackState &unpack, + unsigned int offset, + RenderTargetD3D *destRenderTarget, + GLenum destinationFormat, + GLenum sourcePixelsType, + const gl::Box &destArea) override; - void markAllStateDirty(); - void unapplyRenderTargets(); - void setOneTimeRenderTarget(ID3D11RenderTargetView *renderTargetView); gl::Error packPixels(const TextureHelper11 &textureHelper, const PackPixelsParams ¶ms, uint8_t *pixelsOut); bool getLUID(LUID *adapterLuid) const override; - VertexConversionType getVertexConversionType(gl::VertexFormatType vertexFormatType) const override; + VertexConversionType getVertexConversionType( + gl::VertexFormatType vertexFormatType) const override; GLenum getVertexComponentType(gl::VertexFormatType vertexFormatType) const override; - gl::Error readFromAttachment(const gl::FramebufferAttachment &srcAttachment, + // Warning: you should ensure binding really matches attrib.bindingIndex before using this + // function. + gl::ErrorOrResult getVertexSpaceRequired(const gl::VertexAttribute &attrib, + const gl::VertexBinding &binding, + GLsizei count, + GLsizei instances) const override; + + gl::Error readFromAttachment(const gl::Context *context, + const gl::FramebufferAttachment &srcAttachment, const gl::Rectangle &sourceArea, GLenum format, GLenum type, @@ -276,145 +359,175 @@ class Renderer11 : public RendererD3D const gl::PixelPackState &pack, uint8_t *pixels); - 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); + gl::Error blitRenderbufferRect(const gl::Context *context, + 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; - const Renderer11DeviceCaps &getRenderer11DeviceCaps() { return mRenderer11DeviceCaps; }; + const Renderer11DeviceCaps &getRenderer11DeviceCaps() const { return mRenderer11DeviceCaps; }; - RendererClass getRendererClass() const override { return RENDERER_D3D11; } - InputLayoutCache *getInputLayoutCache() { return &mInputLayoutCache; } + RendererClass getRendererClass() const override; StateManager11 *getStateManager() { return &mStateManager; } void onSwap(); + void onBufferCreate(const Buffer11 *created); void onBufferDelete(const Buffer11 *deleted); egl::Error getEGLDevice(DeviceImpl **device) override; - protected: - void createAnnotator() override; - gl::Error clearTextures(gl::SamplerType samplerType, size_t rangeStart, size_t rangeEnd) override; - gl::Error applyShadersImpl(const gl::Data &data, GLenum drawMode) override; + gl::Error drawArrays(const gl::Context *context, + GLenum mode, + GLint startVertex, + GLsizei count, + GLsizei instances); - void syncState(const gl::State &state, const gl::State::DirtyBits &bitmask) override; + gl::Error drawElements(const gl::Context *context, + GLenum mode, + GLsizei count, + GLenum type, + const void *indices, + GLsizei instances); + + gl::Error drawArraysIndirect(const gl::Context *context, GLenum mode, const void *indirect); + gl::Error drawElementsIndirect(const gl::Context *context, + GLenum mode, + GLenum type, + const void *indirect); + + // Necessary hack for default framebuffers in D3D. + FramebufferImpl *createDefaultFramebuffer(const gl::FramebufferState &state) override; + + gl::Error getScratchMemoryBuffer(size_t requestedSize, angle::MemoryBuffer **bufferOut); + + gl::Version getMaxSupportedESVersion() const override; + + gl::Error dispatchCompute(const gl::Context *context, + GLuint numGroupsX, + GLuint numGroupsY, + GLuint numGroupsZ); + gl::Error applyComputeShader(const gl::Context *context); + + gl::ErrorOrResult createStagingTexture(ResourceType textureType, + const d3d11::Format &formatSet, + const gl::Extents &size, + StagingAccess readAndWriteAccess); + + template + gl::Error allocateResource(const DescT &desc, ResourceT *resourceOut) + { + return mResourceManager11.allocate(this, &desc, nullptr, resourceOut); + } + + template + gl::Error allocateResource(const DescT &desc, InitDataT *initData, ResourceT *resourceOut) + { + return mResourceManager11.allocate(this, &desc, initData, resourceOut); + } + + template + gl::Error allocateResourceNoDesc(InitDataT *initData, ResourceT *resourceOut) + { + return mResourceManager11.allocate(this, nullptr, initData, resourceOut); + } + + template + gl::Error allocateTexture(const DescT &desc, + const d3d11::Format &format, + TextureHelper11 *textureOut) + { + return allocateTexture(desc, format, nullptr, textureOut); + } + + gl::Error allocateTexture(const D3D11_TEXTURE2D_DESC &desc, + const d3d11::Format &format, + const D3D11_SUBRESOURCE_DATA *initData, + TextureHelper11 *textureOut); + + gl::Error allocateTexture(const D3D11_TEXTURE3D_DESC &desc, + const d3d11::Format &format, + const D3D11_SUBRESOURCE_DATA *initData, + TextureHelper11 *textureOut); + + gl::Error clearRenderTarget(RenderTargetD3D *renderTarget, + const gl::ColorF &clearColorValue, + const float clearDepthValue, + const unsigned int clearStencilValue) override; + + bool canSelectViewInVertexShader() const override; private: - gl::Error drawArraysImpl(const gl::Data &data, - GLenum mode, - GLsizei count, - GLsizei instances) override; - gl::Error drawElementsImpl(const gl::Data &data, - const TranslatedIndexData &indexInfo, - GLenum mode, - GLsizei count, - GLenum type, - const GLvoid *indices, - GLsizei instances) override; - - void generateCaps(gl::Caps *outCaps, gl::TextureCapsMap *outTextureCaps, + void generateCaps(gl::Caps *outCaps, + gl::TextureCapsMap *outTextureCaps, gl::Extensions *outExtensions, gl::Limitations *outLimitations) const override; - WorkaroundsD3D generateWorkarounds() const override; + angle::WorkaroundsD3D generateWorkarounds() const override; - gl::Error drawLineLoop(const gl::Data &data, + gl::Error drawLineLoop(const gl::Context *context, GLsizei count, GLenum type, - const GLvoid *indices, - const TranslatedIndexData *indexInfo, + const void *indices, + int baseVertex, int instances); - gl::Error drawTriangleFan(const gl::Data &data, + gl::Error drawTriangleFan(const gl::Context *context, GLsizei count, GLenum type, - const GLvoid *indices, - int minIndex, + const void *indices, + int baseVertex, int instances); - ID3D11Texture2D *resolveMultisampledTexture(ID3D11Texture2D *source, unsigned int subresource); + gl::ErrorOrResult resolveMultisampledTexture(const gl::Context *context, + RenderTarget11 *renderTarget, + bool depth, + bool stencil); void populateRenderer11DeviceCaps(); void updateHistograms(); - HMODULE mD3d11Module; - HMODULE mDxgiModule; - HMODULE mDCompModule; - std::vector mAvailableFeatureLevels; - D3D_DRIVER_TYPE mRequestedDriverType; - bool mCreatedWithDeviceEXT; - DeviceD3D *mEGLDevice; + gl::Error copyImageInternal(const gl::Context *context, + const gl::Framebuffer *framebuffer, + const gl::Rectangle &sourceRect, + GLenum destFormat, + const gl::Offset &destOffset, + RenderTargetD3D *destRenderTarget); - HLSLCompiler mCompiler; + gl::SupportedSampleSet generateSampleSetForEGLConfig( + const gl::TextureCaps &colorBufferFormatCaps, + const gl::TextureCaps &depthStencilBufferFormatCaps) const; + HRESULT callD3D11CreateDevice(PFN_D3D11_CREATE_DEVICE createDevice, bool debug); egl::Error initializeD3DDevice(); - void initializeDevice(); + egl::Error initializeDevice(); void releaseDeviceResources(); void release(); d3d11::ANGLED3D11DeviceType getDeviceType() const; - RenderStateCache mStateCache; + gl::Error markTransformFeedbackUsage(const gl::Context *context); - // current render target states - uintptr_t mAppliedRTVs[gl::IMPLEMENTATION_MAX_DRAW_BUFFERS]; - uintptr_t mAppliedDSV; + HMODULE mD3d11Module; + HMODULE mDxgiModule; + HMODULE mDCompModule; + std::vector mAvailableFeatureLevels; + D3D_DRIVER_TYPE mRequestedDriverType; + bool mCreateDebugDevice; + bool mCreatedWithDeviceEXT; + DeviceD3D *mEGLDevice; - // Currently applied sampler states - std::vector mForceSetVertexSamplerStates; - std::vector mCurVertexSamplerStates; + HLSLCompiler mCompiler; - std::vector mForceSetPixelSamplerStates; - std::vector mCurPixelSamplerStates; + RenderStateCache mStateCache; StateManager11 mStateManager; - // Currently applied primitive topology - D3D11_PRIMITIVE_TOPOLOGY mCurrentPrimitiveTopology; - - // Currently applied index buffer - ID3D11Buffer *mAppliedIB; - DXGI_FORMAT mAppliedIBFormat; - unsigned int mAppliedIBOffset; - bool mAppliedIBChanged; - - // 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_VertexConstants11 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_PixelConstants11 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; @@ -429,10 +542,10 @@ class Renderer11 : public RendererD3D Trim11 *mTrim; // Sync query - ID3D11Query *mSyncQuery; + d3d11::Query mSyncQuery; // Created objects state tracking - std::set mAliveBuffers; + std::set mAliveBuffers; double mLastHistogramUpdateTime; @@ -440,18 +553,24 @@ class Renderer11 : public RendererD3D Renderer11DeviceCaps mRenderer11DeviceCaps; ID3D11DeviceContext *mDeviceContext; ID3D11DeviceContext1 *mDeviceContext1; + ID3D11DeviceContext3 *mDeviceContext3; IDXGIAdapter *mDxgiAdapter; DXGI_ADAPTER_DESC mAdapterDescription; char mDescription[128]; - DXGIFactory *mDxgiFactory; -#if !defined(ANGLE_MINGW32_COMPAT) + IDXGIFactory *mDxgiFactory; ID3D11Debug *mDebug; -#endif std::vector mScratchIndexDataBuffer; + angle::ScratchBuffer mScratchMemoryBuffer; + + gl::DebugAnnotator *mAnnotator; + mutable Optional mSupportsShareHandles; + ResourceManager11 mResourceManager11; + + TextureHelper11 mCachedResolveTexture; }; -} -#endif // LIBANGLE_RENDERER_D3D_D3D11_RENDERER11_H_ +} // namespace rx +#endif // LIBANGLE_RENDERER_D3D_D3D11_RENDERER11_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/ResourceManager11.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/ResourceManager11.cpp new file mode 100644 index 0000000000..c228380a34 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/ResourceManager11.cpp @@ -0,0 +1,533 @@ +// +// Copyright 2017 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. +// +// ResourceManager11: +// Centralized point of allocation for all D3D11 Resources. + +#include "libANGLE/renderer/d3d/d3d11/ResourceManager11.h" + +#include "common/debug.h" +#include "libANGLE/renderer/d3d/d3d11/Renderer11.h" +#include "libANGLE/renderer/d3d/d3d11/formatutils11.h" + +namespace rx +{ + +namespace +{ + +constexpr uint8_t kDebugInitTextureDataValue = 0x48; +constexpr FLOAT kDebugColorInitClearValue[4] = {0.3f, 0.5f, 0.7f, 0.5f}; +constexpr FLOAT kDebugDepthInitValue = 0.2f; +constexpr UINT8 kDebugStencilInitValue = 3; + +uint64_t ComputeMippedMemoryUsage(unsigned int width, + unsigned int height, + unsigned int depth, + uint64_t pixelSize, + unsigned int mipLevels) +{ + uint64_t sizeSum = 0; + + for (unsigned int level = 0; level < mipLevels; ++level) + { + unsigned int mipWidth = std::max(width >> level, 1u); + unsigned int mipHeight = std::max(height >> level, 1u); + unsigned int mipDepth = std::max(depth >> level, 1u); + sizeSum += static_cast(mipWidth * mipHeight * mipDepth) * pixelSize; + } + + return sizeSum; +} + +uint64_t ComputeMemoryUsage(const D3D11_TEXTURE2D_DESC *desc) +{ + ASSERT(desc); + uint64_t pixelBytes = + static_cast(d3d11::GetDXGIFormatSizeInfo(desc->Format).pixelBytes); + return ComputeMippedMemoryUsage(desc->Width, desc->Height, 1, pixelBytes, desc->MipLevels); +} + +uint64_t ComputeMemoryUsage(const D3D11_TEXTURE3D_DESC *desc) +{ + ASSERT(desc); + uint64_t pixelBytes = + static_cast(d3d11::GetDXGIFormatSizeInfo(desc->Format).pixelBytes); + return ComputeMippedMemoryUsage(desc->Width, desc->Height, desc->Depth, pixelBytes, + desc->MipLevels); +} + +uint64_t ComputeMemoryUsage(const D3D11_BUFFER_DESC *desc) +{ + ASSERT(desc); + return static_cast(desc->ByteWidth); +} + +template +uint64_t ComputeMemoryUsage(const T *desc) +{ + return 0; +} + +template +uint64_t ComputeGenericMemoryUsage(ID3D11DeviceChild *genericResource) +{ + auto *typedResource = static_cast *>(genericResource); + GetDescType desc; + typedResource->GetDesc(&desc); + return ComputeMemoryUsage(&desc); +} + +uint64_t ComputeGenericMemoryUsage(ResourceType resourceType, ID3D11DeviceChild *resource) +{ + switch (resourceType) + { + case ResourceType::Texture2D: + return ComputeGenericMemoryUsage(resource); + case ResourceType::Texture3D: + return ComputeGenericMemoryUsage(resource); + case ResourceType::Buffer: + return ComputeGenericMemoryUsage(resource); + + default: + return 0; + } +} + +HRESULT CreateResource(ID3D11Device *device, + const D3D11_BLEND_DESC *desc, + void * /*initData*/, + ID3D11BlendState **blendState) +{ + return device->CreateBlendState(desc, blendState); +} + +HRESULT CreateResource(ID3D11Device *device, + const D3D11_BUFFER_DESC *desc, + const D3D11_SUBRESOURCE_DATA *initData, + ID3D11Buffer **buffer) +{ + return device->CreateBuffer(desc, initData, buffer); +} + +HRESULT CreateResource(ID3D11Device *device, + const ShaderData *desc, + void * /*initData*/, + ID3D11ComputeShader **resourceOut) +{ + return device->CreateComputeShader(desc->get(), desc->size(), nullptr, resourceOut); +} + +HRESULT CreateResource(ID3D11Device *device, + const D3D11_DEPTH_STENCIL_DESC *desc, + void * /*initData*/, + ID3D11DepthStencilState **resourceOut) +{ + return device->CreateDepthStencilState(desc, resourceOut); +} + +HRESULT CreateResource(ID3D11Device *device, + const D3D11_DEPTH_STENCIL_VIEW_DESC *desc, + ID3D11Resource *resource, + ID3D11DepthStencilView **resourceOut) +{ + return device->CreateDepthStencilView(resource, desc, resourceOut); +} + +HRESULT CreateResource(ID3D11Device *device, + const ShaderData *desc, + const std::vector *initData, + ID3D11GeometryShader **resourceOut) +{ + if (initData) + { + return device->CreateGeometryShaderWithStreamOutput( + desc->get(), desc->size(), initData->data(), static_cast(initData->size()), + nullptr, 0, 0, nullptr, resourceOut); + } + else + { + return device->CreateGeometryShader(desc->get(), desc->size(), nullptr, resourceOut); + } +} + +HRESULT CreateResource(ID3D11Device *device, + const InputElementArray *desc, + const ShaderData *initData, + ID3D11InputLayout **resourceOut) +{ + return device->CreateInputLayout(desc->get(), static_cast(desc->size()), initData->get(), + initData->size(), resourceOut); +} + +HRESULT CreateResource(ID3D11Device *device, + const ShaderData *desc, + void * /*initData*/, + ID3D11PixelShader **resourceOut) +{ + return device->CreatePixelShader(desc->get(), desc->size(), nullptr, resourceOut); +} + +HRESULT CreateResource(ID3D11Device *device, + const D3D11_QUERY_DESC *desc, + void * /*initData*/, + ID3D11Query **resourceOut) +{ + return device->CreateQuery(desc, resourceOut); +} + +HRESULT CreateResource(ID3D11Device *device, + const D3D11_RASTERIZER_DESC *desc, + void * /*initData*/, + ID3D11RasterizerState **rasterizerState) +{ + return device->CreateRasterizerState(desc, rasterizerState); +} + +HRESULT CreateResource(ID3D11Device *device, + const D3D11_RENDER_TARGET_VIEW_DESC *desc, + ID3D11Resource *resource, + ID3D11RenderTargetView **renderTargetView) +{ + return device->CreateRenderTargetView(resource, desc, renderTargetView); +} + +HRESULT CreateResource(ID3D11Device *device, + const D3D11_SAMPLER_DESC *desc, + void * /*initData*/, + ID3D11SamplerState **resourceOut) +{ + return device->CreateSamplerState(desc, resourceOut); +} + +HRESULT CreateResource(ID3D11Device *device, + const D3D11_SHADER_RESOURCE_VIEW_DESC *desc, + ID3D11Resource *resource, + ID3D11ShaderResourceView **resourceOut) +{ + return device->CreateShaderResourceView(resource, desc, resourceOut); +} + +HRESULT CreateResource(ID3D11Device *device, + const D3D11_TEXTURE2D_DESC *desc, + const D3D11_SUBRESOURCE_DATA *initData, + ID3D11Texture2D **texture) +{ + return device->CreateTexture2D(desc, initData, texture); +} + +HRESULT CreateResource(ID3D11Device *device, + const D3D11_TEXTURE3D_DESC *desc, + const D3D11_SUBRESOURCE_DATA *initData, + ID3D11Texture3D **texture) +{ + return device->CreateTexture3D(desc, initData, texture); +} + +HRESULT CreateResource(ID3D11Device *device, + const ShaderData *desc, + void * /*initData*/, + ID3D11VertexShader **resourceOut) +{ + return device->CreateVertexShader(desc->get(), desc->size(), nullptr, resourceOut); +} + +DXGI_FORMAT GetTypedDepthStencilFormat(DXGI_FORMAT dxgiFormat) +{ + switch (dxgiFormat) + { + case DXGI_FORMAT_R16_TYPELESS: + return DXGI_FORMAT_D16_UNORM; + case DXGI_FORMAT_R24G8_TYPELESS: + return DXGI_FORMAT_D24_UNORM_S8_UINT; + case DXGI_FORMAT_R32_TYPELESS: + return DXGI_FORMAT_D32_FLOAT; + case DXGI_FORMAT_R32G8X24_TYPELESS: + return DXGI_FORMAT_D32_FLOAT_S8X24_UINT; + default: + return dxgiFormat; + } +} + +template +gl::Error ClearResource(Renderer11 *renderer, const DescT *desc, ResourceT *texture) +{ + // No-op. + return gl::NoError(); +} + +template <> +gl::Error ClearResource(Renderer11 *renderer, + const D3D11_TEXTURE2D_DESC *desc, + ID3D11Texture2D *texture) +{ + ID3D11DeviceContext *context = renderer->getDeviceContext(); + + if ((desc->BindFlags & D3D11_BIND_DEPTH_STENCIL) != 0) + { + D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc; + dsvDesc.Flags = 0; + dsvDesc.Format = GetTypedDepthStencilFormat(desc->Format); + + const auto &format = d3d11_angle::GetFormat(dsvDesc.Format); + UINT clearFlags = (format.depthBits > 0 ? D3D11_CLEAR_DEPTH : 0) | + (format.stencilBits > 0 ? D3D11_CLEAR_STENCIL : 0); + + // Must process each mip level individually. + for (UINT mipLevel = 0; mipLevel < desc->MipLevels; ++mipLevel) + { + if (desc->SampleDesc.Count == 0) + { + dsvDesc.Texture2D.MipSlice = mipLevel; + dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D; + } + else + { + dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DMS; + } + + d3d11::DepthStencilView dsv; + ANGLE_TRY(renderer->allocateResource(dsvDesc, texture, &dsv)); + + context->ClearDepthStencilView(dsv.get(), clearFlags, kDebugDepthInitValue, + kDebugStencilInitValue); + } + } + else + { + ASSERT((desc->BindFlags & D3D11_BIND_RENDER_TARGET) != 0); + d3d11::RenderTargetView rtv; + ANGLE_TRY(renderer->allocateResourceNoDesc(texture, &rtv)); + + context->ClearRenderTargetView(rtv.get(), kDebugColorInitClearValue); + } + + return gl::NoError(); +} + +template <> +gl::Error ClearResource(Renderer11 *renderer, + const D3D11_TEXTURE3D_DESC *desc, + ID3D11Texture3D *texture) +{ + ID3D11DeviceContext *context = renderer->getDeviceContext(); + + ASSERT((desc->BindFlags & D3D11_BIND_DEPTH_STENCIL) == 0); + ASSERT((desc->BindFlags & D3D11_BIND_RENDER_TARGET) != 0); + + d3d11::RenderTargetView rtv; + ANGLE_TRY(renderer->allocateResourceNoDesc(texture, &rtv)); + + context->ClearRenderTargetView(rtv.get(), kDebugColorInitClearValue); + return gl::NoError(); +} + +#define ANGLE_RESOURCE_STRINGIFY_OP(NAME, RESTYPE, D3D11TYPE, DESCTYPE, INITDATATYPE) #RESTYPE, + +constexpr std::array kResourceTypeNames = { + {ANGLE_RESOURCE_TYPE_OP(Stringify, ANGLE_RESOURCE_STRINGIFY_OP)}}; +static_assert(kResourceTypeNames[NumResourceTypes - 1] != nullptr, + "All members must be initialized."); + +} // anonymous namespace + +// ResourceManager11 Implementation. +ResourceManager11::ResourceManager11() + : mInitializeAllocations(false), + mAllocatedResourceCounts({{}}), + mAllocatedResourceDeviceMemory({{}}) +{ +} + +ResourceManager11::~ResourceManager11() +{ + for (size_t count : mAllocatedResourceCounts) + { + ASSERT(count == 0); + } + + for (uint64_t memorySize : mAllocatedResourceDeviceMemory) + { + ASSERT(memorySize == 0); + } +} + +template +gl::Error ResourceManager11::allocate(Renderer11 *renderer, + const GetDescFromD3D11 *desc, + GetInitDataFromD3D11 *initData, + Resource11 *resourceOut) +{ + ID3D11Device *device = renderer->getDevice(); + T *resource = nullptr; + + GetInitDataFromD3D11 *shadowInitData = initData; + if (!shadowInitData && mInitializeAllocations) + { + shadowInitData = createInitDataIfNeeded(desc); + } + + HRESULT hr = CreateResource(device, desc, shadowInitData, &resource); + if (FAILED(hr)) + { + ASSERT(!resource); + if (d3d11::isDeviceLostError(hr)) + { + renderer->notifyDeviceLost(); + } + return gl::OutOfMemory() << "Error allocating " + << std::string(kResourceTypeNames[ResourceTypeIndex()]) << ". " + << gl::FmtHR(hr); + } + + if (!shadowInitData && mInitializeAllocations) + { + ANGLE_TRY(ClearResource(renderer, desc, resource)); + } + + ASSERT(resource); + incrResource(GetResourceTypeFromD3D11(), ComputeMemoryUsage(desc)); + *resourceOut = std::move(Resource11(resource, this)); + return gl::NoError(); +} + +void ResourceManager11::incrResource(ResourceType resourceType, uint64_t memorySize) +{ + size_t typeIndex = ResourceTypeIndex(resourceType); + + mAllocatedResourceCounts[typeIndex]++; + mAllocatedResourceDeviceMemory[typeIndex] += memorySize; + + // This checks for integer overflow. + ASSERT(mAllocatedResourceCounts[typeIndex] > 0); + ASSERT(mAllocatedResourceDeviceMemory[typeIndex] >= memorySize); +} + +void ResourceManager11::decrResource(ResourceType resourceType, uint64_t memorySize) +{ + size_t typeIndex = ResourceTypeIndex(resourceType); + + ASSERT(mAllocatedResourceCounts[typeIndex] > 0); + mAllocatedResourceCounts[typeIndex]--; + ASSERT(mAllocatedResourceDeviceMemory[typeIndex] >= memorySize); + mAllocatedResourceDeviceMemory[typeIndex] -= memorySize; +} + +void ResourceManager11::onReleaseGeneric(ResourceType resourceType, ID3D11DeviceChild *resource) +{ + ASSERT(resource); + decrResource(resourceType, ComputeGenericMemoryUsage(resourceType, resource)); +} + +template <> +const D3D11_SUBRESOURCE_DATA *ResourceManager11::createInitDataIfNeeded( + const D3D11_TEXTURE2D_DESC *desc) +{ + ASSERT(desc); + + if ((desc->BindFlags & (D3D11_BIND_DEPTH_STENCIL | D3D11_BIND_RENDER_TARGET)) != 0) + { + // This will be done using ClearView methods. + return nullptr; + } + + size_t requiredSize = static_cast(ComputeMemoryUsage(desc)); + if (mZeroMemory.size() < requiredSize) + { + mZeroMemory.resize(requiredSize); + mZeroMemory.fill(kDebugInitTextureDataValue); + } + + const auto &formatSizeInfo = d3d11::GetDXGIFormatSizeInfo(desc->Format); + + UINT subresourceCount = desc->MipLevels * desc->ArraySize; + if (mShadowInitData.size() < subresourceCount) + { + mShadowInitData.resize(subresourceCount); + } + + for (UINT mipLevel = 0; mipLevel < desc->MipLevels; ++mipLevel) + { + for (UINT arrayIndex = 0; arrayIndex < desc->ArraySize; ++arrayIndex) + { + UINT subresourceIndex = D3D11CalcSubresource(mipLevel, arrayIndex, desc->MipLevels); + D3D11_SUBRESOURCE_DATA *data = &mShadowInitData[subresourceIndex]; + + UINT levelWidth = std::max(desc->Width >> mipLevel, 1u); + UINT levelHeight = std::max(desc->Height >> mipLevel, 1u); + + data->SysMemPitch = levelWidth * formatSizeInfo.pixelBytes; + data->SysMemSlicePitch = data->SysMemPitch * levelHeight; + data->pSysMem = mZeroMemory.data(); + } + } + + return mShadowInitData.data(); +} + +template <> +const D3D11_SUBRESOURCE_DATA *ResourceManager11::createInitDataIfNeeded( + const D3D11_TEXTURE3D_DESC *desc) +{ + ASSERT(desc); + + if ((desc->BindFlags & D3D11_BIND_RENDER_TARGET) != 0) + { + // This will be done using ClearView methods. + return nullptr; + } + + size_t requiredSize = static_cast(ComputeMemoryUsage(desc)); + if (mZeroMemory.size() < requiredSize) + { + mZeroMemory.resize(requiredSize); + mZeroMemory.fill(kDebugInitTextureDataValue); + } + + const auto &formatSizeInfo = d3d11::GetDXGIFormatSizeInfo(desc->Format); + + UINT subresourceCount = desc->MipLevels; + if (mShadowInitData.size() < subresourceCount) + { + mShadowInitData.resize(subresourceCount); + } + + for (UINT mipLevel = 0; mipLevel < desc->MipLevels; ++mipLevel) + { + UINT subresourceIndex = D3D11CalcSubresource(mipLevel, 0, desc->MipLevels); + D3D11_SUBRESOURCE_DATA *data = &mShadowInitData[subresourceIndex]; + + UINT levelWidth = std::max(desc->Width >> mipLevel, 1u); + UINT levelHeight = std::max(desc->Height >> mipLevel, 1u); + + data->SysMemPitch = levelWidth * formatSizeInfo.pixelBytes; + data->SysMemSlicePitch = data->SysMemPitch * levelHeight; + data->pSysMem = mZeroMemory.data(); + } + + return mShadowInitData.data(); +} + +template +GetInitDataFromD3D11 *ResourceManager11::createInitDataIfNeeded(const GetDescFromD3D11 *desc) +{ + // No-op. + return nullptr; +} + +void ResourceManager11::setAllocationsInitialized(bool initialize) +{ + mInitializeAllocations = initialize; +} + +#define ANGLE_INSTANTIATE_OP(NAME, RESTYPE, D3D11TYPE, DESCTYPE, INITDATATYPE) \ + \ +template \ +gl::Error \ + ResourceManager11::allocate(Renderer11 *, const DESCTYPE *, INITDATATYPE *, \ + Resource11 *); + +ANGLE_RESOURCE_TYPE_OP(Instantitate, ANGLE_INSTANTIATE_OP) +} // namespace rx diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/ResourceManager11.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/ResourceManager11.h new file mode 100644 index 0000000000..0bdde9f8b6 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/ResourceManager11.h @@ -0,0 +1,366 @@ +// +// Copyright 2017 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. +// +// ResourceManager11: +// Centralized point of allocation for all D3D11 Resources. + +#ifndef LIBANGLE_RENDERER_D3D_D3D11_RESOURCEFACTORY11_H_ +#define LIBANGLE_RENDERER_D3D_D3D11_RESOURCEFACTORY11_H_ + +#include +#include + +#include "common/MemoryBuffer.h" +#include "common/angleutils.h" +#include "common/debug.h" +#include "libANGLE/Error.h" +#include "libANGLE/renderer/renderer_utils.h" + +namespace rx +{ +// These two methods are declared here to prevent circular includes. +namespace d3d11 +{ +HRESULT SetDebugName(ID3D11DeviceChild *resource, const char *name); + +template +HRESULT SetDebugName(angle::ComPtr &resource, const char *name) +{ + return SetDebugName(resource.Get(), name); +} +} // namespace d3d11 + +class Renderer11; +class ResourceManager11; +template +class SharedResource11; +class TextureHelper11; + +using InputElementArray = WrappedArray; +using ShaderData = WrappedArray; + +// Format: ResourceType, D3D11 type, DESC type, init data type. +#define ANGLE_RESOURCE_TYPE_OP(NAME, OP) \ + OP(NAME, BlendState, ID3D11BlendState, D3D11_BLEND_DESC, void) \ + OP(NAME, Buffer, ID3D11Buffer, D3D11_BUFFER_DESC, const D3D11_SUBRESOURCE_DATA) \ + OP(NAME, ComputeShader, ID3D11ComputeShader, ShaderData, void) \ + OP(NAME, DepthStencilState, ID3D11DepthStencilState, D3D11_DEPTH_STENCIL_DESC, void) \ + OP(NAME, DepthStencilView, ID3D11DepthStencilView, D3D11_DEPTH_STENCIL_VIEW_DESC, \ + ID3D11Resource) \ + OP(NAME, GeometryShader, ID3D11GeometryShader, ShaderData, \ + const std::vector) \ + OP(NAME, InputLayout, ID3D11InputLayout, InputElementArray, const ShaderData) \ + OP(NAME, PixelShader, ID3D11PixelShader, ShaderData, void) \ + OP(NAME, Query, ID3D11Query, D3D11_QUERY_DESC, void) \ + OP(NAME, RasterizerState, ID3D11RasterizerState, D3D11_RASTERIZER_DESC, void) \ + OP(NAME, RenderTargetView, ID3D11RenderTargetView, D3D11_RENDER_TARGET_VIEW_DESC, \ + ID3D11Resource) \ + OP(NAME, SamplerState, ID3D11SamplerState, D3D11_SAMPLER_DESC, void) \ + OP(NAME, ShaderResourceView, ID3D11ShaderResourceView, D3D11_SHADER_RESOURCE_VIEW_DESC, \ + ID3D11Resource) \ + OP(NAME, Texture2D, ID3D11Texture2D, D3D11_TEXTURE2D_DESC, const D3D11_SUBRESOURCE_DATA) \ + OP(NAME, Texture3D, ID3D11Texture3D, D3D11_TEXTURE3D_DESC, const D3D11_SUBRESOURCE_DATA) \ + OP(NAME, VertexShader, ID3D11VertexShader, ShaderData, void) + +#define ANGLE_RESOURCE_TYPE_LIST(NAME, RESTYPE, D3D11TYPE, DESCTYPE, INITDATATYPE) RESTYPE, + +enum class ResourceType +{ + ANGLE_RESOURCE_TYPE_OP(List, ANGLE_RESOURCE_TYPE_LIST) Last +}; + +#undef ANGLE_RESOURCE_TYPE_LIST + +constexpr size_t ResourceTypeIndex(ResourceType resourceType) +{ + return static_cast(resourceType); +} + +constexpr size_t NumResourceTypes = ResourceTypeIndex(ResourceType::Last); + +#define ANGLE_RESOURCE_TYPE_TO_D3D11(NAME, RESTYPE, D3D11TYPE, DESCTYPE, INITDATATYPE) \ + \ +template<> struct NAME \ + { \ + using Value = D3D11TYPE; \ + }; + +#define ANGLE_RESOURCE_TYPE_TO_DESC(NAME, RESTYPE, D3D11TYPE, DESCTYPE, INITDATATYPE) \ + \ +template<> struct NAME \ + { \ + using Value = DESCTYPE; \ + }; + +#define ANGLE_RESOURCE_TYPE_TO_INIT_DATA(NAME, RESTYPE, D3D11TYPE, DESCTYPE, INITDATATYPE) \ + \ +template<> struct NAME \ + { \ + using Value = INITDATATYPE; \ + }; + +#define ANGLE_RESOURCE_TYPE_TO_TYPE(NAME, OP) \ + template \ + struct NAME; \ + ANGLE_RESOURCE_TYPE_OP(NAME, OP) \ + \ +template struct NAME \ + { \ + }; \ + \ +template using Get##NAME = typename NAME::Value; + +ANGLE_RESOURCE_TYPE_TO_TYPE(D3D11Type, ANGLE_RESOURCE_TYPE_TO_D3D11) +ANGLE_RESOURCE_TYPE_TO_TYPE(DescType, ANGLE_RESOURCE_TYPE_TO_DESC) +ANGLE_RESOURCE_TYPE_TO_TYPE(InitDataType, ANGLE_RESOURCE_TYPE_TO_INIT_DATA) + +#undef ANGLE_RESOURCE_TYPE_TO_D3D11 +#undef ANGLE_RESOURCE_TYPE_TO_DESC +#undef ANGLE_RESOURCE_TYPE_TO_INIT_DATA +#undef ANGLE_RESOURCE_TYPE_TO_TYPE + +#define ANGLE_TYPE_TO_RESOURCE_TYPE(NAME, OP) \ + template \ + struct NAME; \ + ANGLE_RESOURCE_TYPE_OP(NAME, OP) \ + \ +template struct NAME \ + { \ + }; \ + \ +template constexpr ResourceType Get##NAME() \ + { \ + return NAME::Value; \ + } + +#define ANGLE_D3D11_TO_RESOURCE_TYPE(NAME, RESTYPE, D3D11TYPE, DESCTYPE, INITDATATYPE) \ + \ +template<> struct NAME \ + { \ + static constexpr ResourceType Value = ResourceType::RESTYPE; \ + }; + +ANGLE_TYPE_TO_RESOURCE_TYPE(ResourceTypeFromD3D11, ANGLE_D3D11_TO_RESOURCE_TYPE) + +#undef ANGLE_D3D11_TO_RESOURCE_TYPE +#undef ANGLE_TYPE_TO_RESOURCE_TYPE + +template +using GetDescFromD3D11 = GetDescType::Value>; + +template +using GetInitDataFromD3D11 = GetInitDataType::Value>; + +template +constexpr size_t ResourceTypeIndex() +{ + return static_cast(GetResourceTypeFromD3D11()); +} + +template +struct TypedData +{ + TypedData() {} + ~TypedData(); + + T *object = nullptr; + ResourceManager11 *manager = nullptr; +}; + +// Smart pointer type. Wraps the resource and a factory for safe deletion. +template class Pointer, typename DataT> +class Resource11Base : angle::NonCopyable +{ + public: + T *get() const { return mData->object; } + T *const *getPointer() const { return &mData->object; } + + void setDebugName(const char *name) { d3d11::SetDebugName(mData->object, name); } + + void set(T *object) + { + ASSERT(!valid()); + mData->object = object; + } + + bool valid() const { return (mData->object != nullptr); } + + void reset() + { + if (valid()) + mData.reset(new DataT()); + } + + ResourceSerial getSerial() const + { + return ResourceSerial(reinterpret_cast(mData->object)); + } + + protected: + friend class TextureHelper11; + + Resource11Base() : mData(new DataT()) {} + + Resource11Base(Resource11Base &&movedObj) : mData(new DataT()) + { + std::swap(mData, movedObj.mData); + } + + virtual ~Resource11Base() { mData.reset(); } + + Resource11Base &operator=(Resource11Base &&movedObj) + { + std::swap(mData, movedObj.mData); + return *this; + } + + Pointer mData; +}; + +template +using UniquePtr = typename std::unique_ptr>; + +template +class Resource11 : public Resource11Base> +{ + public: + Resource11() {} + Resource11(Resource11 &&other) + : Resource11Base>(std::move(other)) + { + } + Resource11 &operator=(Resource11 &&other) + { + std::swap(this->mData, other.mData); + return *this; + } + + private: + template + friend class SharedResource11; + friend class ResourceManager11; + + Resource11(ResourceT *object, ResourceManager11 *manager) + { + this->mData->object = object; + this->mData->manager = manager; + } +}; + +template +class SharedResource11 : public Resource11Base> +{ + public: + SharedResource11() {} + SharedResource11(SharedResource11 &&movedObj) + : Resource11Base>(std::move(movedObj)) + { + } + + SharedResource11 &operator=(SharedResource11 &&other) + { + std::swap(this->mData, other.mData); + return *this; + } + + SharedResource11 makeCopy() const + { + SharedResource11 copy; + copy.mData = this->mData; + return std::move(copy); + } + + private: + friend class ResourceManager11; + SharedResource11(Resource11 &&obj) : Resource11Base>() + { + std::swap(this->mData->manager, obj.mData->manager); + + // Can't use std::swap because of ID3D11Resource. + auto temp = this->mData->object; + this->mData->object = obj.mData->object; + obj.mData->object = static_cast(temp); + } +}; + +class ResourceManager11 final : angle::NonCopyable +{ + public: + ResourceManager11(); + ~ResourceManager11(); + + template + gl::Error allocate(Renderer11 *renderer, + const GetDescFromD3D11 *desc, + GetInitDataFromD3D11 *initData, + Resource11 *resourceOut); + + template + gl::Error allocate(Renderer11 *renderer, + const GetDescFromD3D11 *desc, + GetInitDataFromD3D11 *initData, + SharedResource11 *sharedRes) + { + Resource11 res; + ANGLE_TRY(allocate(renderer, desc, initData, &res)); + *sharedRes = std::move(res); + return gl::NoError(); + } + + template + void onRelease(T *resource) + { + onReleaseGeneric(GetResourceTypeFromD3D11(), resource); + } + + void onReleaseGeneric(ResourceType resourceType, ID3D11DeviceChild *resource); + + void setAllocationsInitialized(bool initialize); + + private: + void incrResource(ResourceType resourceType, uint64_t memorySize); + void decrResource(ResourceType resourceType, uint64_t memorySize); + + template + GetInitDataFromD3D11 *createInitDataIfNeeded(const GetDescFromD3D11 *desc); + + bool mInitializeAllocations; + + std::array mAllocatedResourceCounts; + std::array mAllocatedResourceDeviceMemory; + angle::MemoryBuffer mZeroMemory; + + std::vector mShadowInitData; +}; + +template +TypedData::~TypedData() +{ + if (object) + { + // We can have a nullptr factory when holding passed-in resources. + if (manager) + { + manager->onRelease(object); + } + object->Release(); + } +} + +#define ANGLE_RESOURCE_TYPE_CLASS(NAME, RESTYPE, D3D11TYPE, DESCTYPE, INITDATATYPE) \ + using RESTYPE = Resource11; + +namespace d3d11 +{ +ANGLE_RESOURCE_TYPE_OP(ClassList, ANGLE_RESOURCE_TYPE_CLASS) + +using SharedSRV = SharedResource11; +} // namespace d3d11 + +#undef ANGLE_RESOURCE_TYPE_CLASS + +} // namespace rx + +#endif // LIBANGLE_RENDERER_D3D_D3D11_RESOURCEFACTORY11_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 index 4da51afe49..73a530add0 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/ShaderExecutable11.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/ShaderExecutable11.cpp @@ -13,86 +13,107 @@ namespace rx { -ShaderExecutable11::ShaderExecutable11(const void *function, size_t length, ID3D11PixelShader *executable) - : ShaderExecutableD3D(function, length) +ShaderExecutable11::ShaderExecutable11(const void *function, + size_t length, + d3d11::PixelShader &&executable) + : ShaderExecutableD3D(function, length), + mPixelExecutable(std::move(executable)), + mVertexExecutable(), + mGeometryExecutable(), + mStreamOutExecutable(), + mComputeExecutable() { - mPixelExecutable = executable; - mVertexExecutable = NULL; - mGeometryExecutable = NULL; - mStreamOutExecutable = NULL; } -ShaderExecutable11::ShaderExecutable11(const void *function, size_t length, ID3D11VertexShader *executable, ID3D11GeometryShader *streamOut) - : ShaderExecutableD3D(function, length) +ShaderExecutable11::ShaderExecutable11(const void *function, + size_t length, + d3d11::VertexShader &&executable, + d3d11::GeometryShader &&streamOut) + : ShaderExecutableD3D(function, length), + mPixelExecutable(), + mVertexExecutable(std::move(executable)), + mGeometryExecutable(), + mStreamOutExecutable(std::move(streamOut)), + mComputeExecutable() { - mVertexExecutable = executable; - mPixelExecutable = NULL; - mGeometryExecutable = NULL; - mStreamOutExecutable = streamOut; } -ShaderExecutable11::ShaderExecutable11(const void *function, size_t length, ID3D11GeometryShader *executable) - : ShaderExecutableD3D(function, length) +ShaderExecutable11::ShaderExecutable11(const void *function, + size_t length, + d3d11::GeometryShader &&executable) + : ShaderExecutableD3D(function, length), + mPixelExecutable(), + mVertexExecutable(), + mGeometryExecutable(std::move(executable)), + mStreamOutExecutable(), + mComputeExecutable() +{ +} + +ShaderExecutable11::ShaderExecutable11(const void *function, + size_t length, + d3d11::ComputeShader &&executable) + : ShaderExecutableD3D(function, length), + mPixelExecutable(), + mVertexExecutable(), + mGeometryExecutable(), + mStreamOutExecutable(), + mComputeExecutable(std::move(executable)) { - mGeometryExecutable = executable; - mVertexExecutable = NULL; - mPixelExecutable = NULL; - mStreamOutExecutable = NULL; } ShaderExecutable11::~ShaderExecutable11() { - SafeRelease(mVertexExecutable); - SafeRelease(mPixelExecutable); - SafeRelease(mGeometryExecutable); - SafeRelease(mStreamOutExecutable); } -ID3D11VertexShader *ShaderExecutable11::getVertexShader() const +const d3d11::VertexShader &ShaderExecutable11::getVertexShader() const { return mVertexExecutable; } -ID3D11PixelShader *ShaderExecutable11::getPixelShader() const +const d3d11::PixelShader &ShaderExecutable11::getPixelShader() const { return mPixelExecutable; } -ID3D11GeometryShader *ShaderExecutable11::getGeometryShader() const +const d3d11::GeometryShader &ShaderExecutable11::getGeometryShader() const { return mGeometryExecutable; } -ID3D11GeometryShader *ShaderExecutable11::getStreamOutShader() const +const d3d11::GeometryShader &ShaderExecutable11::getStreamOutShader() const { return mStreamOutExecutable; } -UniformStorage11::UniformStorage11(Renderer11 *renderer, size_t initialSize) - : UniformStorageD3D(initialSize), - mConstantBuffer(NULL) +const d3d11::ComputeShader &ShaderExecutable11::getComputeShader() const { - ID3D11Device *d3d11Device = renderer->getDevice(); + return mComputeExecutable; +} - if (initialSize > 0) - { - D3D11_BUFFER_DESC constantBufferDescription = {0}; - constantBufferDescription.ByteWidth = static_cast(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(size_t initialSize) + : UniformStorageD3D(initialSize), mConstantBuffer() +{ } UniformStorage11::~UniformStorage11() { - SafeRelease(mConstantBuffer); } +gl::Error UniformStorage11::getConstantBuffer(Renderer11 *renderer, const d3d11::Buffer **bufferOut) +{ + if (size() > 0 && !mConstantBuffer.valid()) + { + D3D11_BUFFER_DESC desc = {0}; + desc.ByteWidth = static_cast(size()); + desc.Usage = D3D11_USAGE_DEFAULT; + desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; + + ANGLE_TRY(renderer->allocateResource(desc, &mConstantBuffer)); + } + + *bufferOut = &mConstantBuffer; + return gl::NoError(); } + +} // namespace rx diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/ShaderExecutable11.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/ShaderExecutable11.h index 379f39fe53..3f417578a3 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/ShaderExecutable11.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/ShaderExecutable11.h @@ -11,6 +11,7 @@ #define LIBANGLE_RENDERER_D3D_D3D11_SHADEREXECUTABLE11_H_ #include "libANGLE/renderer/d3d/ShaderExecutableD3D.h" +#include "libANGLE/renderer/d3d/d3d11/ResourceManager11.h" namespace rx { @@ -20,36 +21,42 @@ 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(); - - ID3D11PixelShader *getPixelShader() const; - ID3D11VertexShader *getVertexShader() const; - ID3D11GeometryShader *getGeometryShader() const; - ID3D11GeometryShader *getStreamOutShader() const; + ShaderExecutable11(const void *function, size_t length, d3d11::PixelShader &&executable); + ShaderExecutable11(const void *function, + size_t length, + d3d11::VertexShader &&executable, + d3d11::GeometryShader &&streamOut); + ShaderExecutable11(const void *function, size_t length, d3d11::GeometryShader &&executable); + ShaderExecutable11(const void *function, size_t length, d3d11::ComputeShader &&executable); + + ~ShaderExecutable11() override; + + const d3d11::PixelShader &getPixelShader() const; + const d3d11::VertexShader &getVertexShader() const; + const d3d11::GeometryShader &getGeometryShader() const; + const d3d11::GeometryShader &getStreamOutShader() const; + const d3d11::ComputeShader &getComputeShader() const; private: - ID3D11PixelShader *mPixelExecutable; - ID3D11VertexShader *mVertexExecutable; - ID3D11GeometryShader *mGeometryExecutable; - ID3D11GeometryShader *mStreamOutExecutable; + d3d11::PixelShader mPixelExecutable; + d3d11::VertexShader mVertexExecutable; + d3d11::GeometryShader mGeometryExecutable; + d3d11::GeometryShader mStreamOutExecutable; + d3d11::ComputeShader mComputeExecutable; }; class UniformStorage11 : public UniformStorageD3D { public: - UniformStorage11(Renderer11 *renderer, size_t initialSize); - virtual ~UniformStorage11(); + UniformStorage11(size_t initialSize); + ~UniformStorage11() override; - ID3D11Buffer *getConstantBuffer() const { return mConstantBuffer; } + gl::Error getConstantBuffer(Renderer11 *renderer, const d3d11::Buffer **bufferOut); private: - ID3D11Buffer *mConstantBuffer; + d3d11::Buffer mConstantBuffer; }; -} +} // namespace rx #endif // LIBANGLE_RENDERER_D3D_D3D11_SHADEREXECUTABLE11_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/StateManager11.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/StateManager11.cpp index aa34fd4de8..e9902d3f14 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/StateManager11.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/StateManager11.cpp @@ -8,11 +8,22 @@ #include "libANGLE/renderer/d3d/d3d11/StateManager11.h" -#include "common/BitSetIterator.h" +#include "common/bitset_utils.h" #include "common/utilities.h" +#include "libANGLE/Context.h" +#include "libANGLE/Query.h" +#include "libANGLE/VertexArray.h" +#include "libANGLE/renderer/d3d/TextureD3D.h" +#include "libANGLE/renderer/d3d/d3d11/Buffer11.h" +#include "libANGLE/renderer/d3d/d3d11/Context11.h" #include "libANGLE/renderer/d3d/d3d11/Framebuffer11.h" -#include "libANGLE/renderer/d3d/d3d11/Renderer11.h" +#include "libANGLE/renderer/d3d/d3d11/IndexBuffer11.h" #include "libANGLE/renderer/d3d/d3d11/RenderTarget11.h" +#include "libANGLE/renderer/d3d/d3d11/Renderer11.h" +#include "libANGLE/renderer/d3d/d3d11/ShaderExecutable11.h" +#include "libANGLE/renderer/d3d/d3d11/TextureStorage11.h" +#include "libANGLE/renderer/d3d/d3d11/TransformFeedback11.h" +#include "libANGLE/renderer/d3d/d3d11/VertexArray11.h" namespace rx { @@ -22,15 +33,16 @@ namespace bool ImageIndexConflictsWithSRV(const gl::ImageIndex &index, D3D11_SHADER_RESOURCE_VIEW_DESC desc) { unsigned mipLevel = index.mipIndex; - unsigned layerIndex = index.layerIndex; + GLint 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; + bool allLevels = (desc.Texture2D.MipLevels == std::numeric_limits::max()); + unsigned int maxSrvMip = desc.Texture2D.MipLevels + desc.Texture2D.MostDetailedMip; + maxSrvMip = allLevels ? INT_MAX : maxSrvMip; unsigned mipMin = index.mipIndex; unsigned mipMax = (layerIndex == -1) ? INT_MAX : layerIndex; @@ -42,22 +54,25 @@ bool ImageIndexConflictsWithSRV(const gl::ImageIndex &index, D3D11_SHADER_RESOUR case D3D11_SRV_DIMENSION_TEXTURE2DARRAY: { - unsigned maxSrvMip = + bool allLevels = (desc.Texture2DArray.MipLevels == std::numeric_limits::max()); + unsigned int maxSrvMip = desc.Texture2DArray.MipLevels + desc.Texture2DArray.MostDetailedMip; - maxSrvMip = (desc.Texture2DArray.MipLevels == -1) ? INT_MAX : maxSrvMip; + maxSrvMip = allLevels ? 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; + desc.Texture2DArray.FirstArraySlice <= static_cast(layerIndex) && + static_cast(layerIndex) < maxSlice; } case D3D11_SRV_DIMENSION_TEXTURECUBE: { - unsigned maxSrvMip = desc.TextureCube.MipLevels + desc.TextureCube.MostDetailedMip; - maxSrvMip = (desc.TextureCube.MipLevels == -1) ? INT_MAX : maxSrvMip; + bool allLevels = (desc.TextureCube.MipLevels == std::numeric_limits::max()); + unsigned int maxSrvMip = desc.TextureCube.MipLevels + desc.TextureCube.MostDetailedMip; + maxSrvMip = allLevels ? INT_MAX : maxSrvMip; return gl::IsCubeMapTextureTarget(type) && desc.TextureCube.MostDetailedMip <= mipLevel && mipLevel < maxSrvMip; @@ -65,8 +80,9 @@ bool ImageIndexConflictsWithSRV(const gl::ImageIndex &index, D3D11_SHADER_RESOUR case D3D11_SRV_DIMENSION_TEXTURE3D: { - unsigned maxSrvMip = desc.Texture3D.MipLevels + desc.Texture3D.MostDetailedMip; - maxSrvMip = (desc.Texture3D.MipLevels == -1) ? INT_MAX : maxSrvMip; + bool allLevels = (desc.Texture3D.MipLevels == std::numeric_limits::max()); + unsigned int maxSrvMip = desc.Texture3D.MipLevels + desc.Texture3D.MostDetailedMip; + maxSrvMip = allLevels ? INT_MAX : maxSrvMip; return type == GL_TEXTURE_3D && desc.Texture3D.MostDetailedMip <= mipLevel && mipLevel < maxSrvMip; @@ -82,15 +98,97 @@ bool ImageIndexConflictsWithSRV(const gl::ImageIndex &index, D3D11_SHADER_RESOUR // Does *not* increment the resource ref count!! ID3D11Resource *GetViewResource(ID3D11View *view) { - ID3D11Resource *resource = NULL; + ID3D11Resource *resource = nullptr; ASSERT(view); view->GetResource(&resource); resource->Release(); return resource; } +int GetWrapBits(GLenum wrap) +{ + switch (wrap) + { + case GL_CLAMP_TO_EDGE: + return 0x1; + case GL_REPEAT: + return 0x2; + case GL_MIRRORED_REPEAT: + return 0x3; + default: + UNREACHABLE(); + return 0; + } +} + +Optional FindFirstNonInstanced( + const std::vector ¤tAttributes) +{ + for (size_t index = 0; index < currentAttributes.size(); ++index) + { + if (currentAttributes[index]->divisor == 0) + { + return Optional(index); + } + } + + return Optional::Invalid(); +} + +void SortAttributesByLayout(const gl::Program *program, + const std::vector &vertexArrayAttribs, + const std::vector ¤tValueAttribs, + AttribIndexArray *sortedD3DSemanticsOut, + std::vector *sortedAttributesOut) +{ + sortedAttributesOut->clear(); + + const auto &locationToSemantic = + GetImplAs(program)->getAttribLocationToD3DSemantics(); + + for (auto locationIndex : program->getActiveAttribLocationsMask()) + { + int d3dSemantic = locationToSemantic[locationIndex]; + if (sortedAttributesOut->size() <= static_cast(d3dSemantic)) + { + sortedAttributesOut->resize(d3dSemantic + 1); + } + + (*sortedD3DSemanticsOut)[d3dSemantic] = d3dSemantic; + + const auto *arrayAttrib = &vertexArrayAttribs[locationIndex]; + if (arrayAttrib->attribute && arrayAttrib->attribute->enabled) + { + (*sortedAttributesOut)[d3dSemantic] = arrayAttrib; + } + else + { + ASSERT(currentValueAttribs[locationIndex].attribute); + (*sortedAttributesOut)[d3dSemantic] = ¤tValueAttribs[locationIndex]; + } + } +} + +void UpdateUniformBuffer(ID3D11DeviceContext *deviceContext, + UniformStorage11 *storage, + const d3d11::Buffer *buffer) +{ + deviceContext->UpdateSubresource(buffer->get(), 0, nullptr, storage->getDataPointer(0, 0), 0, + 0); +} + } // anonymous namespace +// StateManager11::SRVCache Implementation. + +StateManager11::SRVCache::SRVCache() : mHighestUsedSRV(0) +{ +} + +StateManager11::SRVCache::~SRVCache() +{ +} + void StateManager11::SRVCache::update(size_t resourceIndex, ID3D11ShaderResourceView *srv) { ASSERT(resourceIndex < mCurrentSRVs.size()); @@ -128,27 +226,348 @@ void StateManager11::SRVCache::clear() mHighestUsedSRV = 0; } +// ShaderConstants11 implementation + +ShaderConstants11::ShaderConstants11() + : mVertexDirty(true), + mPixelDirty(true), + mComputeDirty(true), + mSamplerMetadataVSDirty(true), + mSamplerMetadataPSDirty(true), + mSamplerMetadataCSDirty(true) +{ +} + +ShaderConstants11::~ShaderConstants11() +{ +} + +void ShaderConstants11::init(const gl::Caps &caps) +{ + mSamplerMetadataVS.resize(caps.maxVertexTextureImageUnits); + mSamplerMetadataPS.resize(caps.maxTextureImageUnits); + mSamplerMetadataCS.resize(caps.maxComputeTextureImageUnits); +} + +size_t ShaderConstants11::getRequiredBufferSize(gl::SamplerType samplerType) const +{ + switch (samplerType) + { + case gl::SAMPLER_VERTEX: + return sizeof(Vertex) + mSamplerMetadataVS.size() * sizeof(SamplerMetadata); + case gl::SAMPLER_PIXEL: + return sizeof(Pixel) + mSamplerMetadataPS.size() * sizeof(SamplerMetadata); + case gl::SAMPLER_COMPUTE: + return sizeof(Compute) + mSamplerMetadataCS.size() * sizeof(SamplerMetadata); + default: + UNREACHABLE(); + return 0; + } +} + +void ShaderConstants11::markDirty() +{ + mVertexDirty = true; + mPixelDirty = true; + mComputeDirty = true; + mSamplerMetadataVSDirty = true; + mSamplerMetadataPSDirty = true; + mSamplerMetadataCSDirty = true; +} + +bool ShaderConstants11::updateSamplerMetadata(SamplerMetadata *data, const gl::Texture &texture) +{ + bool dirty = false; + unsigned int baseLevel = texture.getTextureState().getEffectiveBaseLevel(); + GLenum sizedFormat = + texture.getFormat(texture.getTarget(), baseLevel).info->sizedInternalFormat; + if (data->baseLevel != static_cast(baseLevel)) + { + data->baseLevel = static_cast(baseLevel); + dirty = true; + } + + // Some metadata is needed only for integer textures. We avoid updating the constant buffer + // unnecessarily by changing the data only in case the texture is an integer texture and + // the values have changed. + bool needIntegerTextureMetadata = false; + // internalFormatBits == 0 means a 32-bit texture in the case of integer textures. + int internalFormatBits = 0; + switch (sizedFormat) + { + case GL_RGBA32I: + case GL_RGBA32UI: + case GL_RGB32I: + case GL_RGB32UI: + case GL_RG32I: + case GL_RG32UI: + case GL_R32I: + case GL_R32UI: + needIntegerTextureMetadata = true; + break; + case GL_RGBA16I: + case GL_RGBA16UI: + case GL_RGB16I: + case GL_RGB16UI: + case GL_RG16I: + case GL_RG16UI: + case GL_R16I: + case GL_R16UI: + needIntegerTextureMetadata = true; + internalFormatBits = 16; + break; + case GL_RGBA8I: + case GL_RGBA8UI: + case GL_RGB8I: + case GL_RGB8UI: + case GL_RG8I: + case GL_RG8UI: + case GL_R8I: + case GL_R8UI: + needIntegerTextureMetadata = true; + internalFormatBits = 8; + break; + case GL_RGB10_A2UI: + needIntegerTextureMetadata = true; + internalFormatBits = 10; + break; + default: + break; + } + if (needIntegerTextureMetadata) + { + if (data->internalFormatBits != internalFormatBits) + { + data->internalFormatBits = internalFormatBits; + dirty = true; + } + // Pack the wrap values into one integer so we can fit all the metadata in one 4-integer + // vector. + GLenum wrapS = texture.getWrapS(); + GLenum wrapT = texture.getWrapT(); + GLenum wrapR = texture.getWrapR(); + int wrapModes = GetWrapBits(wrapS) | (GetWrapBits(wrapT) << 2) | (GetWrapBits(wrapR) << 4); + if (data->wrapModes != wrapModes) + { + data->wrapModes = wrapModes; + dirty = true; + } + } + + return dirty; +} + +void ShaderConstants11::setComputeWorkGroups(GLuint numGroupsX, + GLuint numGroupsY, + GLuint numGroupsZ) +{ + mCompute.numWorkGroups[0] = numGroupsX; + mCompute.numWorkGroups[1] = numGroupsY; + mCompute.numWorkGroups[2] = numGroupsZ; + mComputeDirty = true; +} + +void ShaderConstants11::setMultiviewWriteToViewportIndex(GLfloat index) +{ + mVertex.multiviewWriteToViewportIndex = index; + mVertexDirty = true; + mPixel.multiviewWriteToViewportIndex = index; + mPixelDirty = true; +} + +void ShaderConstants11::onViewportChange(const gl::Rectangle &glViewport, + const D3D11_VIEWPORT &dxViewport, + bool is9_3, + bool presentPathFast) +{ + mVertexDirty = true; + mPixelDirty = true; + + // On Feature Level 9_*, we must emulate large and/or negative viewports in the shaders + // using viewAdjust (like the D3D9 renderer). + if (is9_3) + { + mVertex.viewAdjust[0] = static_cast((glViewport.width - dxViewport.Width) + + 2 * (glViewport.x - dxViewport.TopLeftX)) / + dxViewport.Width; + mVertex.viewAdjust[1] = static_cast((glViewport.height - dxViewport.Height) + + 2 * (glViewport.y - dxViewport.TopLeftY)) / + dxViewport.Height; + mVertex.viewAdjust[2] = static_cast(glViewport.width) / dxViewport.Width; + mVertex.viewAdjust[3] = static_cast(glViewport.height) / dxViewport.Height; + } + + mPixel.viewCoords[0] = glViewport.width * 0.5f; + mPixel.viewCoords[1] = glViewport.height * 0.5f; + mPixel.viewCoords[2] = glViewport.x + (glViewport.width * 0.5f); + mPixel.viewCoords[3] = glViewport.y + (glViewport.height * 0.5f); + + // Instanced pointsprite emulation requires ViewCoords to be defined in the + // the vertex shader. + mVertex.viewCoords[0] = mPixel.viewCoords[0]; + mVertex.viewCoords[1] = mPixel.viewCoords[1]; + mVertex.viewCoords[2] = mPixel.viewCoords[2]; + mVertex.viewCoords[3] = mPixel.viewCoords[3]; + + const float zNear = dxViewport.MinDepth; + const float zFar = dxViewport.MaxDepth; + + mPixel.depthFront[0] = (zFar - zNear) * 0.5f; + mPixel.depthFront[1] = (zNear + zFar) * 0.5f; + + mVertex.depthRange[0] = zNear; + mVertex.depthRange[1] = zFar; + mVertex.depthRange[2] = zFar - zNear; + + mPixel.depthRange[0] = zNear; + mPixel.depthRange[1] = zFar; + mPixel.depthRange[2] = zFar - zNear; + + mPixel.viewScale[0] = 1.0f; + mPixel.viewScale[1] = presentPathFast ? 1.0f : -1.0f; + // Updates to the multiviewWriteToViewportIndex member are to be handled whenever the draw + // framebuffer's layout is changed. + + mVertex.viewScale[0] = mPixel.viewScale[0]; + mVertex.viewScale[1] = mPixel.viewScale[1]; +} + +void ShaderConstants11::onSamplerChange(gl::SamplerType samplerType, + unsigned int samplerIndex, + const gl::Texture &texture) +{ + switch (samplerType) + { + case gl::SAMPLER_VERTEX: + if (updateSamplerMetadata(&mSamplerMetadataVS[samplerIndex], texture)) + { + mSamplerMetadataVSDirty = true; + } + break; + case gl::SAMPLER_PIXEL: + if (updateSamplerMetadata(&mSamplerMetadataPS[samplerIndex], texture)) + { + mSamplerMetadataPSDirty = true; + } + break; + case gl::SAMPLER_COMPUTE: + if (updateSamplerMetadata(&mSamplerMetadataCS[samplerIndex], texture)) + { + mSamplerMetadataCSDirty = true; + } + break; + default: + UNREACHABLE(); + break; + } +} + +gl::Error ShaderConstants11::updateBuffer(ID3D11DeviceContext *deviceContext, + gl::SamplerType samplerType, + const ProgramD3D &programD3D, + const d3d11::Buffer &driverConstantBuffer) +{ + bool dirty = false; + size_t dataSize = 0; + const uint8_t *data = nullptr; + const uint8_t *samplerData = nullptr; + + switch (samplerType) + { + case gl::SAMPLER_VERTEX: + dirty = mVertexDirty || mSamplerMetadataVSDirty; + dataSize = sizeof(Vertex); + data = reinterpret_cast(&mVertex); + samplerData = reinterpret_cast(mSamplerMetadataVS.data()); + mVertexDirty = false; + mSamplerMetadataVSDirty = false; + break; + case gl::SAMPLER_PIXEL: + dirty = mPixelDirty || mSamplerMetadataPSDirty; + dataSize = sizeof(Pixel); + data = reinterpret_cast(&mPixel); + samplerData = reinterpret_cast(mSamplerMetadataPS.data()); + mPixelDirty = false; + mSamplerMetadataPSDirty = false; + break; + case gl::SAMPLER_COMPUTE: + dirty = mComputeDirty || mSamplerMetadataCSDirty; + dataSize = sizeof(Compute); + data = reinterpret_cast(&mCompute); + samplerData = reinterpret_cast(mSamplerMetadataCS.data()); + mComputeDirty = false; + mSamplerMetadataCSDirty = false; + break; + default: + UNREACHABLE(); + break; + } + + ASSERT(driverConstantBuffer.valid()); + + if (!dirty) + { + return gl::NoError(); + } + + // Previous buffer contents are discarded, so we need to refresh the whole buffer. + D3D11_MAPPED_SUBRESOURCE mapping = {0}; + HRESULT result = + deviceContext->Map(driverConstantBuffer.get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &mapping); + + if (FAILED(result)) + { + return gl::OutOfMemory() << "Internal error mapping constant buffer: " << gl::FmtHR(result); + } + + size_t samplerDataBytes = sizeof(SamplerMetadata) * programD3D.getUsedSamplerRange(samplerType); + + memcpy(mapping.pData, data, dataSize); + memcpy(reinterpret_cast(mapping.pData) + dataSize, samplerData, samplerDataBytes); + + deviceContext->Unmap(driverConstantBuffer.get(), 0); + + return gl::NoError(); +} + +static const GLenum QueryTypes[] = {GL_ANY_SAMPLES_PASSED, GL_ANY_SAMPLES_PASSED_CONSERVATIVE, + GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, GL_TIME_ELAPSED_EXT, + GL_COMMANDS_COMPLETED_CHROMIUM}; + StateManager11::StateManager11(Renderer11 *renderer) : mRenderer(renderer), - mBlendStateIsDirty(false), + mInternalDirtyBits(), mCurBlendColor(0, 0, 0, 0), mCurSampleMask(0), - mDepthStencilStateIsDirty(false), mCurStencilRef(0), mCurStencilBackRef(0), mCurStencilSize(0), - mRasterizerStateIsDirty(false), - mScissorStateIsDirty(false), mCurScissorEnabled(false), mCurScissorRect(), - mViewportStateIsDirty(false), mCurViewport(), mCurNear(0.0f), mCurFar(0.0f), mViewportBounds(), + mRenderTargetIsDirty(true), mCurPresentPathFastEnabled(false), mCurPresentPathFastColorBufferHeight(0), - mAppliedDSV(angle::DirtyPointer) + mDirtyCurrentValueAttribs(), + mCurrentValueAttribs(), + mCurrentInputLayout(), + mInputLayoutIsDirty(false), + mVertexAttribsNeedTranslation(false), + mDirtyVertexBufferRange(gl::MAX_VERTEX_ATTRIBS, 0), + mCurrentPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_UNDEFINED), + mDirtySwizzles(false), + mAppliedIB(nullptr), + mAppliedIBFormat(DXGI_FORMAT_UNKNOWN), + mAppliedIBOffset(0), + mIndexBufferIsDirty(false), + mVertexDataManager(renderer), + mIndexDataManager(renderer), + mIsMultiviewEnabled(false), + mEmptySerial(mRenderer->generateSerial()), + mIsTransformFeedbackCurrentlyActiveUnpaused(false) { mCurBlendState.blend = false; mCurBlendState.sourceBlendRGB = GL_ONE; @@ -182,64 +601,127 @@ StateManager11::StateManager11(Renderer11 *renderer) mCurRasterState.rasterizerDiscard = false; mCurRasterState.cullFace = false; - mCurRasterState.cullMode = GL_BACK; + mCurRasterState.cullMode = gl::CullFaceMode::Back; mCurRasterState.frontFace = GL_CCW; mCurRasterState.polygonOffsetFill = false; mCurRasterState.polygonOffsetFactor = 0.0f; mCurRasterState.polygonOffsetUnits = 0.0f; mCurRasterState.pointDrawMode = false; mCurRasterState.multiSample = false; + + // Start with all internal dirty bits set. + mInternalDirtyBits.set(); + + // Initially all current value attributes must be updated on first use. + mDirtyCurrentValueAttribs.set(); + + mCurrentVertexBuffers.fill(nullptr); + mCurrentVertexStrides.fill(std::numeric_limits::max()); + mCurrentVertexOffsets.fill(std::numeric_limits::max()); } StateManager11::~StateManager11() { } -void StateManager11::updateStencilSizeIfChanged(bool depthStencilInitialized, - unsigned int stencilSize) +template +void StateManager11::setShaderResourceInternal(gl::SamplerType shaderType, + UINT resourceSlot, + const SRVType *srv) { - if (!depthStencilInitialized || stencilSize != mCurStencilSize) + auto ¤tSRVs = (shaderType == gl::SAMPLER_VERTEX ? mCurVertexSRVs : mCurPixelSRVs); + + ASSERT(static_cast(resourceSlot) < currentSRVs.size()); + const SRVRecord &record = currentSRVs[resourceSlot]; + + if (record.srv != reinterpret_cast(srv)) { - mCurStencilSize = stencilSize; - mDepthStencilStateIsDirty = true; + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); + ID3D11ShaderResourceView *srvPtr = srv ? srv->get() : nullptr; + if (shaderType == gl::SAMPLER_VERTEX) + { + deviceContext->VSSetShaderResources(resourceSlot, 1, &srvPtr); + } + else + { + deviceContext->PSSetShaderResources(resourceSlot, 1, &srvPtr); + } + + currentSRVs.update(resourceSlot, srvPtr); } } -void StateManager11::setViewportBounds(const int width, const int height) +void StateManager11::updateStencilSizeIfChanged(bool depthStencilInitialized, + unsigned int stencilSize) { - if (mRenderer->getRenderer11DeviceCaps().featureLevel <= D3D_FEATURE_LEVEL_9_3 && - (mViewportBounds.width != width || mViewportBounds.height != height)) + if (!depthStencilInitialized || stencilSize != mCurStencilSize) { - mViewportBounds = gl::Extents(width, height, 1); - mViewportStateIsDirty = true; + mCurStencilSize = stencilSize; + mInternalDirtyBits.set(DIRTY_BIT_DEPTH_STENCIL_STATE); } } -void StateManager11::updatePresentPath(bool presentPathFastActive, - const gl::FramebufferAttachment *framebufferAttachment) +void StateManager11::checkPresentPath(const gl::Context *context) { - const int colorBufferHeight = - framebufferAttachment ? framebufferAttachment->getSize().height : 0; + if (!mRenderer->presentPathFastEnabled()) + return; + + const auto *framebuffer = context->getGLState().getDrawFramebuffer(); + const auto *firstColorAttachment = framebuffer->getFirstColorbuffer(); + const bool presentPathFastActive = UsePresentPathFast(mRenderer, firstColorAttachment); + + const int colorBufferHeight = firstColorAttachment ? firstColorAttachment->getSize().height : 0; if ((mCurPresentPathFastEnabled != presentPathFastActive) || (presentPathFastActive && (colorBufferHeight != mCurPresentPathFastColorBufferHeight))) { mCurPresentPathFastEnabled = presentPathFastActive; mCurPresentPathFastColorBufferHeight = colorBufferHeight; - mViewportStateIsDirty = true; // Viewport may need to be vertically inverted - mScissorStateIsDirty = true; // Scissor rect may need to be vertically inverted - mRasterizerStateIsDirty = true; // Cull Mode may need to be inverted + + // Scissor rect may need to be vertically inverted + mInternalDirtyBits.set(DIRTY_BIT_SCISSOR_STATE); + + // Cull Mode may need to be inverted + mInternalDirtyBits.set(DIRTY_BIT_RASTERIZER_STATE); + + // Viewport may need to be vertically inverted + invalidateViewport(context); } } -void StateManager11::syncState(const gl::State &state, const gl::State::DirtyBits &dirtyBits) +gl::Error StateManager11::updateStateForCompute(const gl::Context *context, + GLuint numGroupsX, + GLuint numGroupsY, + GLuint numGroupsZ) +{ + mShaderConstants.setComputeWorkGroups(numGroupsX, numGroupsY, numGroupsZ); + + // TODO(jmadill): Use dirty bits. + const auto &glState = context->getGLState(); + auto *programD3D = GetImplAs(glState.getProgram()); + programD3D->updateSamplerMapping(); + + // TODO(jmadill): Use dirty bits. + ANGLE_TRY(generateSwizzlesForShader(context, gl::SAMPLER_COMPUTE)); + + // TODO(jmadill): More complete implementation. + ANGLE_TRY(syncTextures(context)); + + // TODO(Xinghua): applyUniformBuffers for compute shader. + + return gl::NoError(); +} + +void StateManager11::syncState(const gl::Context *context, const gl::State::DirtyBits &dirtyBits) { if (!dirtyBits.any()) { return; } - for (unsigned int dirtyBit : angle::IterateBitSet(dirtyBits)) + const auto &state = context->getGLState(); + + for (auto dirtyBit : dirtyBits) { switch (dirtyBit) { @@ -249,7 +731,7 @@ void StateManager11::syncState(const gl::State &state, const gl::State::DirtyBit if (blendState.blendEquationRGB != mCurBlendState.blendEquationRGB || blendState.blendEquationAlpha != mCurBlendState.blendEquationAlpha) { - mBlendStateIsDirty = true; + mInternalDirtyBits.set(DIRTY_BIT_BLEND_STATE); } break; } @@ -261,27 +743,27 @@ void StateManager11::syncState(const gl::State &state, const gl::State::DirtyBit blendState.sourceBlendAlpha != mCurBlendState.sourceBlendAlpha || blendState.destBlendAlpha != mCurBlendState.destBlendAlpha) { - mBlendStateIsDirty = true; + mInternalDirtyBits.set(DIRTY_BIT_BLEND_STATE); } break; } case gl::State::DIRTY_BIT_BLEND_ENABLED: if (state.getBlendState().blend != mCurBlendState.blend) { - mBlendStateIsDirty = true; + mInternalDirtyBits.set(DIRTY_BIT_BLEND_STATE); } break; case gl::State::DIRTY_BIT_SAMPLE_ALPHA_TO_COVERAGE_ENABLED: if (state.getBlendState().sampleAlphaToCoverage != mCurBlendState.sampleAlphaToCoverage) { - mBlendStateIsDirty = true; + mInternalDirtyBits.set(DIRTY_BIT_BLEND_STATE); } break; case gl::State::DIRTY_BIT_DITHER_ENABLED: if (state.getBlendState().dither != mCurBlendState.dither) { - mBlendStateIsDirty = true; + mInternalDirtyBits.set(DIRTY_BIT_BLEND_STATE); } break; case gl::State::DIRTY_BIT_COLOR_MASK: @@ -292,38 +774,38 @@ void StateManager11::syncState(const gl::State &state, const gl::State::DirtyBit blendState.colorMaskBlue != mCurBlendState.colorMaskBlue || blendState.colorMaskAlpha != mCurBlendState.colorMaskAlpha) { - mBlendStateIsDirty = true; + mInternalDirtyBits.set(DIRTY_BIT_BLEND_STATE); } break; } case gl::State::DIRTY_BIT_BLEND_COLOR: if (state.getBlendColor() != mCurBlendColor) { - mBlendStateIsDirty = true; + mInternalDirtyBits.set(DIRTY_BIT_BLEND_STATE); } break; case gl::State::DIRTY_BIT_DEPTH_MASK: if (state.getDepthStencilState().depthMask != mCurDepthStencilState.depthMask) { - mDepthStencilStateIsDirty = true; + mInternalDirtyBits.set(DIRTY_BIT_DEPTH_STENCIL_STATE); } break; case gl::State::DIRTY_BIT_DEPTH_TEST_ENABLED: if (state.getDepthStencilState().depthTest != mCurDepthStencilState.depthTest) { - mDepthStencilStateIsDirty = true; + mInternalDirtyBits.set(DIRTY_BIT_DEPTH_STENCIL_STATE); } break; case gl::State::DIRTY_BIT_DEPTH_FUNC: if (state.getDepthStencilState().depthFunc != mCurDepthStencilState.depthFunc) { - mDepthStencilStateIsDirty = true; + mInternalDirtyBits.set(DIRTY_BIT_DEPTH_STENCIL_STATE); } break; case gl::State::DIRTY_BIT_STENCIL_TEST_ENABLED: if (state.getDepthStencilState().stencilTest != mCurDepthStencilState.stencilTest) { - mDepthStencilStateIsDirty = true; + mInternalDirtyBits.set(DIRTY_BIT_DEPTH_STENCIL_STATE); } break; case gl::State::DIRTY_BIT_STENCIL_FUNCS_FRONT: @@ -333,7 +815,7 @@ void StateManager11::syncState(const gl::State &state, const gl::State::DirtyBit depthStencil.stencilMask != mCurDepthStencilState.stencilMask || state.getStencilRef() != mCurStencilRef) { - mDepthStencilStateIsDirty = true; + mInternalDirtyBits.set(DIRTY_BIT_DEPTH_STENCIL_STATE); } break; } @@ -344,7 +826,7 @@ void StateManager11::syncState(const gl::State &state, const gl::State::DirtyBit depthStencil.stencilBackMask != mCurDepthStencilState.stencilBackMask || state.getStencilBackRef() != mCurStencilBackRef) { - mDepthStencilStateIsDirty = true; + mInternalDirtyBits.set(DIRTY_BIT_DEPTH_STENCIL_STATE); } break; } @@ -352,14 +834,14 @@ void StateManager11::syncState(const gl::State &state, const gl::State::DirtyBit if (state.getDepthStencilState().stencilWritemask != mCurDepthStencilState.stencilWritemask) { - mDepthStencilStateIsDirty = true; + mInternalDirtyBits.set(DIRTY_BIT_DEPTH_STENCIL_STATE); } break; case gl::State::DIRTY_BIT_STENCIL_WRITEMASK_BACK: if (state.getDepthStencilState().stencilBackWritemask != mCurDepthStencilState.stencilBackWritemask) { - mDepthStencilStateIsDirty = true; + mInternalDirtyBits.set(DIRTY_BIT_DEPTH_STENCIL_STATE); } break; case gl::State::DIRTY_BIT_STENCIL_OPS_FRONT: @@ -370,7 +852,7 @@ void StateManager11::syncState(const gl::State &state, const gl::State::DirtyBit mCurDepthStencilState.stencilPassDepthFail || depthStencil.stencilPassDepthPass != mCurDepthStencilState.stencilPassDepthPass) { - mDepthStencilStateIsDirty = true; + mInternalDirtyBits.set(DIRTY_BIT_DEPTH_STENCIL_STATE); } break; } @@ -383,33 +865,33 @@ void StateManager11::syncState(const gl::State &state, const gl::State::DirtyBit depthStencil.stencilBackPassDepthPass != mCurDepthStencilState.stencilBackPassDepthPass) { - mDepthStencilStateIsDirty = true; + mInternalDirtyBits.set(DIRTY_BIT_DEPTH_STENCIL_STATE); } break; } case gl::State::DIRTY_BIT_CULL_FACE_ENABLED: if (state.getRasterizerState().cullFace != mCurRasterState.cullFace) { - mRasterizerStateIsDirty = true; + mInternalDirtyBits.set(DIRTY_BIT_RASTERIZER_STATE); } break; case gl::State::DIRTY_BIT_CULL_FACE: if (state.getRasterizerState().cullMode != mCurRasterState.cullMode) { - mRasterizerStateIsDirty = true; + mInternalDirtyBits.set(DIRTY_BIT_RASTERIZER_STATE); } break; case gl::State::DIRTY_BIT_FRONT_FACE: if (state.getRasterizerState().frontFace != mCurRasterState.frontFace) { - mRasterizerStateIsDirty = true; + mInternalDirtyBits.set(DIRTY_BIT_RASTERIZER_STATE); } break; case gl::State::DIRTY_BIT_POLYGON_OFFSET_FILL_ENABLED: if (state.getRasterizerState().polygonOffsetFill != mCurRasterState.polygonOffsetFill) { - mRasterizerStateIsDirty = true; + mInternalDirtyBits.set(DIRTY_BIT_RASTERIZER_STATE); } break; case gl::State::DIRTY_BIT_POLYGON_OFFSET: @@ -418,7 +900,7 @@ void StateManager11::syncState(const gl::State &state, const gl::State::DirtyBit if (rasterState.polygonOffsetFactor != mCurRasterState.polygonOffsetFactor || rasterState.polygonOffsetUnits != mCurRasterState.polygonOffsetUnits) { - mRasterizerStateIsDirty = true; + mInternalDirtyBits.set(DIRTY_BIT_RASTERIZER_STATE); } break; } @@ -426,58 +908,150 @@ void StateManager11::syncState(const gl::State &state, const gl::State::DirtyBit if (state.getRasterizerState().rasterizerDiscard != mCurRasterState.rasterizerDiscard) { - mRasterizerStateIsDirty = true; + mInternalDirtyBits.set(DIRTY_BIT_RASTERIZER_STATE); + + // Enabling/disabling rasterizer discard affects the pixel shader. + invalidateShaders(); } break; case gl::State::DIRTY_BIT_SCISSOR: if (state.getScissor() != mCurScissorRect) { - mScissorStateIsDirty = true; + mInternalDirtyBits.set(DIRTY_BIT_SCISSOR_STATE); } break; case gl::State::DIRTY_BIT_SCISSOR_TEST_ENABLED: if (state.isScissorTestEnabled() != mCurScissorEnabled) { - mScissorStateIsDirty = true; + mInternalDirtyBits.set(DIRTY_BIT_SCISSOR_STATE); // Rasterizer state update needs mCurScissorsEnabled and updates when it changes - mRasterizerStateIsDirty = true; + mInternalDirtyBits.set(DIRTY_BIT_RASTERIZER_STATE); } break; case gl::State::DIRTY_BIT_DEPTH_RANGE: if (state.getNearPlane() != mCurNear || state.getFarPlane() != mCurFar) { - mViewportStateIsDirty = true; + invalidateViewport(context); } break; case gl::State::DIRTY_BIT_VIEWPORT: if (state.getViewport() != mCurViewport) { - mViewportStateIsDirty = true; + invalidateViewport(context); + } + break; + case gl::State::DIRTY_BIT_DRAW_FRAMEBUFFER_BINDING: + invalidateRenderTarget(); + if (mIsMultiviewEnabled) + { + handleMultiviewDrawFramebufferChange(context); + } + break; + case gl::State::DIRTY_BIT_VERTEX_ARRAY_BINDING: + invalidateVertexBuffer(); + // Force invalidate the current value attributes, since the VertexArray11 keeps an + // internal cache of TranslatedAttributes, and they CurrentValue attributes are + // owned by the StateManager11/Context. + mDirtyCurrentValueAttribs.set(); + // Invalidate the cached index buffer. + mIndexBufferIsDirty = true; + break; + case gl::State::DIRTY_BIT_TEXTURE_BINDINGS: + invalidateTexturesAndSamplers(); + break; + case gl::State::DIRTY_BIT_SAMPLER_BINDINGS: + invalidateTexturesAndSamplers(); + break; + case gl::State::DIRTY_BIT_PROGRAM_EXECUTABLE: + { + mInternalDirtyBits.set(DIRTY_BIT_SHADERS); + invalidateVertexBuffer(); + invalidateRenderTarget(); + invalidateTexturesAndSamplers(); + invalidateProgramUniforms(); + invalidateProgramUniformBuffers(); + gl::VertexArray *vao = state.getVertexArray(); + if (mIsMultiviewEnabled && vao != nullptr) + { + // If ANGLE_multiview is enabled, the attribute divisor has to be updated for + // each binding. + VertexArray11 *vao11 = GetImplAs(vao); + const gl::Program *program = state.getProgram(); + int numViews = 1; + if (program != nullptr && program->usesMultiview()) + { + numViews = program->getNumViews(); + } + vao11->markAllAttributeDivisorsForAdjustment(numViews); } break; + } + case gl::State::DIRTY_BIT_CURRENT_VALUES: + { + for (auto attribIndex : state.getAndResetDirtyCurrentValues()) + { + invalidateCurrentValueAttrib(attribIndex); + } + } default: break; } } + + // TODO(jmadill): Input layout and vertex buffer state. } -gl::Error StateManager11::setBlendState(const gl::Framebuffer *framebuffer, - const gl::BlendState &blendState, - const gl::ColorF &blendColor, - unsigned int sampleMask) +void StateManager11::handleMultiviewDrawFramebufferChange(const gl::Context *context) { - if (!mBlendStateIsDirty && sampleMask == mCurSampleMask) + const auto &glState = context->getGLState(); + const gl::Framebuffer *drawFramebuffer = glState.getDrawFramebuffer(); + ASSERT(drawFramebuffer != nullptr); + + // Update viewport offsets. + const std::vector *attachmentViewportOffsets = + drawFramebuffer->getViewportOffsets(); + const std::vector &viewportOffsets = + attachmentViewportOffsets != nullptr + ? *attachmentViewportOffsets + : gl::FramebufferAttachment::GetDefaultViewportOffsetVector(); + if (mViewportOffsets != viewportOffsets) { - return gl::Error(GL_NO_ERROR); - } + mViewportOffsets = viewportOffsets; - ID3D11BlendState *dxBlendState = nullptr; - gl::Error error = - mRenderer->getStateCache().getBlendState(framebuffer, blendState, &dxBlendState); - if (error.isError()) + // Because new viewport offsets are to be applied, we have to mark the internal viewport and + // scissor state as dirty. + invalidateViewport(context); + mInternalDirtyBits.set(DIRTY_BIT_SCISSOR_STATE); + } + switch (drawFramebuffer->getMultiviewLayout()) { - return error; + case GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE: + mShaderConstants.setMultiviewWriteToViewportIndex(1.0f); + break; + case GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE: + // Because the base view index is applied as an offset to the 2D texture array when the + // RTV is created, we just have to pass a boolean to select which code path is to be + // used. + mShaderConstants.setMultiviewWriteToViewportIndex(0.0f); + break; + default: + // There is no need to update the value in the constant buffer if the active framebuffer + // object does not have a multiview layout. + break; } +} + +gl::Error StateManager11::syncBlendState(const gl::Context *context, + const gl::Framebuffer *framebuffer, + const gl::BlendState &blendState, + const gl::ColorF &blendColor, + unsigned int sampleMask) +{ + const d3d11::BlendState *dxBlendState = nullptr; + const d3d11::BlendStateKey &key = + RenderStateCache::GetBlendStateKey(context, framebuffer, blendState); + + ANGLE_TRY(mRenderer->getBlendState(key, &dxBlendState)); ASSERT(dxBlendState != nullptr); @@ -500,62 +1074,53 @@ gl::Error StateManager11::setBlendState(const gl::Framebuffer *framebuffer, blendColors[3] = blendColor.alpha; } - mRenderer->getDeviceContext()->OMSetBlendState(dxBlendState, blendColors, sampleMask); + mRenderer->getDeviceContext()->OMSetBlendState(dxBlendState->get(), blendColors, sampleMask); mCurBlendState = blendState; mCurBlendColor = blendColor; mCurSampleMask = sampleMask; - mBlendStateIsDirty = false; - - return error; + return gl::NoError(); } -gl::Error StateManager11::setDepthStencilState(const gl::State &glState) +gl::Error StateManager11::syncDepthStencilState(const gl::State &glState) { - const auto &fbo = *glState.getDrawFramebuffer(); - - // Disable the depth test/depth write if we are using a stencil-only attachment. - // This is because ANGLE emulates stencil-only with D24S8 on D3D11 - we should neither read - // nor write to the unused depth part of this emulated texture. - bool disableDepth = (!fbo.hasDepth() && fbo.hasStencil()); - - // Similarly we disable the stencil portion of the DS attachment if the app only binds depth. - bool disableStencil = (fbo.hasDepth() && !fbo.hasStencil()); + mCurDepthStencilState = glState.getDepthStencilState(); + mCurStencilRef = glState.getStencilRef(); + mCurStencilBackRef = glState.getStencilBackRef(); - // CurDisableDepth/Stencil are reset automatically after we call forceSetDepthStencilState. - if (!mDepthStencilStateIsDirty && mCurDisableDepth.valid() && - disableDepth == mCurDisableDepth.value() && mCurDisableStencil.valid() && - disableStencil == mCurDisableStencil.value()) + // get the maximum size of the stencil ref + unsigned int maxStencil = 0; + if (mCurDepthStencilState.stencilTest && mCurStencilSize > 0) { - return gl::Error(GL_NO_ERROR); + maxStencil = (1 << mCurStencilSize) - 1; } + ASSERT((mCurDepthStencilState.stencilWritemask & maxStencil) == + (mCurDepthStencilState.stencilBackWritemask & maxStencil)); + ASSERT(mCurStencilRef == mCurStencilBackRef); + ASSERT((mCurDepthStencilState.stencilMask & maxStencil) == + (mCurDepthStencilState.stencilBackMask & maxStencil)); - const auto &depthStencilState = glState.getDepthStencilState(); - int stencilRef = glState.getStencilRef(); - int stencilBackRef = glState.getStencilBackRef(); + gl::DepthStencilState modifiedGLState = glState.getDepthStencilState(); - // get the maximum size of the stencil ref - unsigned int maxStencil = 0; - if (depthStencilState.stencilTest && mCurStencilSize > 0) + ASSERT(mCurDisableDepth.valid() && mCurDisableStencil.valid()); + + if (mCurDisableDepth.value()) { - maxStencil = (1 << mCurStencilSize) - 1; + modifiedGLState.depthTest = false; + modifiedGLState.depthMask = false; } - ASSERT((depthStencilState.stencilWritemask & maxStencil) == - (depthStencilState.stencilBackWritemask & maxStencil)); - ASSERT(stencilRef == stencilBackRef); - ASSERT((depthStencilState.stencilMask & maxStencil) == - (depthStencilState.stencilBackMask & maxStencil)); - ID3D11DepthStencilState *dxDepthStencilState = NULL; - gl::Error error = mRenderer->getStateCache().getDepthStencilState( - depthStencilState, disableDepth, disableStencil, &dxDepthStencilState); - if (error.isError()) + if (mCurDisableStencil.value()) { - return error; + modifiedGLState.stencilWritemask = 0; + modifiedGLState.stencilBackWritemask = 0; + modifiedGLState.stencilTest = false; } - ASSERT(dxDepthStencilState); + const d3d11::DepthStencilState *d3dState = nullptr; + ANGLE_TRY(mRenderer->getDepthStencilState(modifiedGLState, &d3dState)); + ASSERT(d3dState); // Max D3D11 stencil reference value is 0xFF, // corresponding to the max 8 bits in a stencil buffer @@ -565,30 +1130,21 @@ gl::Error StateManager11::setDepthStencilState(const gl::State &glState) "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); + UINT dxStencilRef = std::min(mCurStencilRef, 0xFFu); - mRenderer->getDeviceContext()->OMSetDepthStencilState(dxDepthStencilState, dxStencilRef); + mRenderer->getDeviceContext()->OMSetDepthStencilState(d3dState->get(), dxStencilRef); - mCurDepthStencilState = depthStencilState; - mCurStencilRef = stencilRef; - mCurStencilBackRef = stencilBackRef; - mCurDisableDepth = disableDepth; - mCurDisableStencil = disableStencil; - - mDepthStencilStateIsDirty = false; - - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error StateManager11::setRasterizerState(const gl::RasterizerState &rasterState) +gl::Error StateManager11::syncRasterizerState(const gl::Context *context, bool pointDrawMode) { - if (!mRasterizerStateIsDirty) - { - return gl::Error(GL_NO_ERROR); - } + // TODO: Remove pointDrawMode and multiSample from gl::RasterizerState. + gl::RasterizerState rasterState = context->getGLState().getRasterizerState(); + rasterState.pointDrawMode = pointDrawMode; + rasterState.multiSample = mCurRasterState.multiSample; ID3D11RasterizerState *dxRasterState = nullptr; - gl::Error error(GL_NO_ERROR); if (mCurPresentPathFastEnabled) { @@ -607,33 +1163,23 @@ gl::Error StateManager11::setRasterizerState(const gl::RasterizerState &rasterSt modifiedRasterState.frontFace = GL_CCW; } - error = mRenderer->getStateCache().getRasterizerState(modifiedRasterState, - mCurScissorEnabled, &dxRasterState); + ANGLE_TRY( + mRenderer->getRasterizerState(modifiedRasterState, mCurScissorEnabled, &dxRasterState)); } else { - error = mRenderer->getStateCache().getRasterizerState(rasterState, mCurScissorEnabled, - &dxRasterState); - } - - if (error.isError()) - { - return error; + ANGLE_TRY(mRenderer->getRasterizerState(rasterState, mCurScissorEnabled, &dxRasterState)); } mRenderer->getDeviceContext()->RSSetState(dxRasterState); - mCurRasterState = rasterState; - mRasterizerStateIsDirty = false; + mCurRasterState = rasterState; - return error; + return gl::NoError(); } -void StateManager11::setScissorRectangle(const gl::Rectangle &scissor, bool enabled) +void StateManager11::syncScissorRectangle(const gl::Rectangle &scissor, bool enabled) { - if (!mScissorStateIsDirty) - return; - int modifiedScissorY = scissor.y; if (mCurPresentPathFastEnabled) { @@ -642,37 +1188,41 @@ void StateManager11::setScissorRectangle(const gl::Rectangle &scissor, bool enab if (enabled) { - D3D11_RECT rect; - rect.left = std::max(0, scissor.x); - rect.top = std::max(0, modifiedScissorY); - rect.right = scissor.x + std::max(0, scissor.width); - rect.bottom = modifiedScissorY + std::max(0, scissor.height); - - mRenderer->getDeviceContext()->RSSetScissorRects(1, &rect); + std::array rectangles; + const UINT numRectangles = static_cast(mViewportOffsets.size()); + for (UINT i = 0u; i < numRectangles; ++i) + { + D3D11_RECT &rect = rectangles[i]; + int x = scissor.x + mViewportOffsets[i].x; + int y = modifiedScissorY + mViewportOffsets[i].y; + rect.left = std::max(0, x); + rect.top = std::max(0, y); + rect.right = x + std::max(0, scissor.width); + rect.bottom = y + std::max(0, scissor.height); + } + mRenderer->getDeviceContext()->RSSetScissorRects(numRectangles, rectangles.data()); } mCurScissorRect = scissor; mCurScissorEnabled = enabled; - mScissorStateIsDirty = false; } -void StateManager11::setViewport(const gl::Caps *caps, - const gl::Rectangle &viewport, - float zNear, - float zFar) +void StateManager11::syncViewport(const gl::Context *context) { - if (!mViewportStateIsDirty) - return; - - float actualZNear = gl::clamp01(zNear); - float actualZFar = gl::clamp01(zFar); - - int dxMaxViewportBoundsX = static_cast(caps->maxViewportWidth); - int dxMaxViewportBoundsY = static_cast(caps->maxViewportHeight); + const auto &glState = context->getGLState(); + gl::Framebuffer *framebuffer = glState.getDrawFramebuffer(); + float actualZNear = gl::clamp01(glState.getNearPlane()); + float actualZFar = gl::clamp01(glState.getFarPlane()); + + const auto &caps = context->getCaps(); + int dxMaxViewportBoundsX = static_cast(caps.maxViewportWidth); + int dxMaxViewportBoundsY = static_cast(caps.maxViewportHeight); int dxMinViewportBoundsX = -dxMaxViewportBoundsX; int dxMinViewportBoundsY = -dxMaxViewportBoundsY; - if (mRenderer->getRenderer11DeviceCaps().featureLevel <= D3D_FEATURE_LEVEL_9_3) + bool is9_3 = mRenderer->getRenderer11DeviceCaps().featureLevel <= D3D_FEATURE_LEVEL_9_3; + + if (is9_3) { // Feature Level 9 viewports shouldn't exceed the dimensions of the rendertarget. dxMaxViewportBoundsX = static_cast(mViewportBounds.width); @@ -681,173 +1231,295 @@ void StateManager11::setViewport(const gl::Caps *caps, dxMinViewportBoundsY = 0; } - int dxViewportTopLeftX = gl::clamp(viewport.x, dxMinViewportBoundsX, dxMaxViewportBoundsX); - int dxViewportTopLeftY = gl::clamp(viewport.y, dxMinViewportBoundsY, dxMaxViewportBoundsY); - int dxViewportWidth = gl::clamp(viewport.width, 0, dxMaxViewportBoundsX - dxViewportTopLeftX); - int dxViewportHeight = gl::clamp(viewport.height, 0, dxMaxViewportBoundsY - dxViewportTopLeftY); + const auto &viewport = glState.getViewport(); + std::array dxViewports; + const UINT numRectangles = static_cast(mViewportOffsets.size()); - D3D11_VIEWPORT dxViewport; - dxViewport.TopLeftX = static_cast(dxViewportTopLeftX); + int dxViewportTopLeftX = 0; + int dxViewportTopLeftY = 0; + int dxViewportWidth = 0; + int dxViewportHeight = 0; - if (mCurPresentPathFastEnabled) - { - // When present path fast is active and we're rendering to framebuffer 0, we must invert - // the viewport in Y-axis. - // NOTE: We delay the inversion until right before the call to RSSetViewports, and leave - // dxViewportTopLeftY unchanged. This allows us to calculate viewAdjust below using the - // unaltered dxViewportTopLeftY value. - dxViewport.TopLeftY = static_cast(mCurPresentPathFastColorBufferHeight - - dxViewportTopLeftY - dxViewportHeight); - } - else + for (UINT i = 0u; i < numRectangles; ++i) { - dxViewport.TopLeftY = static_cast(dxViewportTopLeftY); - } + dxViewportTopLeftX = gl::clamp(viewport.x + mViewportOffsets[i].x, dxMinViewportBoundsX, + dxMaxViewportBoundsX); + dxViewportTopLeftY = gl::clamp(viewport.y + mViewportOffsets[i].y, dxMinViewportBoundsY, + dxMaxViewportBoundsY); + dxViewportWidth = gl::clamp(viewport.width, 0, dxMaxViewportBoundsX - dxViewportTopLeftX); + dxViewportHeight = gl::clamp(viewport.height, 0, dxMaxViewportBoundsY - dxViewportTopLeftY); + + D3D11_VIEWPORT &dxViewport = dxViewports[i]; + dxViewport.TopLeftX = static_cast(dxViewportTopLeftX); + if (mCurPresentPathFastEnabled) + { + // When present path fast is active and we're rendering to framebuffer 0, we must invert + // the viewport in Y-axis. + // NOTE: We delay the inversion until right before the call to RSSetViewports, and leave + // dxViewportTopLeftY unchanged. This allows us to calculate viewAdjust below using the + // unaltered dxViewportTopLeftY value. + dxViewport.TopLeftY = static_cast(mCurPresentPathFastColorBufferHeight - + dxViewportTopLeftY - dxViewportHeight); + } + else + { + dxViewport.TopLeftY = static_cast(dxViewportTopLeftY); + } - dxViewport.Width = static_cast(dxViewportWidth); - dxViewport.Height = static_cast(dxViewportHeight); - dxViewport.MinDepth = actualZNear; - dxViewport.MaxDepth = actualZFar; + // The es 3.1 spec section 9.2 states that, "If there are no attachments, rendering + // will be limited to a rectangle having a lower left of (0, 0) and an upper right of + // (width, height), where width and height are the framebuffer object's default width + // and height." See http://anglebug.com/1594 + // If the Framebuffer has no color attachment and the default width or height is smaller + // than the current viewport, use the smaller of the two sizes. + // If framebuffer default width or height is 0, the params should not set. + if (!framebuffer->getFirstNonNullAttachment() && + (framebuffer->getDefaultWidth() || framebuffer->getDefaultHeight())) + { + dxViewport.Width = + static_cast(std::min(viewport.width, framebuffer->getDefaultWidth())); + dxViewport.Height = + static_cast(std::min(viewport.height, framebuffer->getDefaultHeight())); + } + else + { + dxViewport.Width = static_cast(dxViewportWidth); + dxViewport.Height = static_cast(dxViewportHeight); + } + dxViewport.MinDepth = actualZNear; + dxViewport.MaxDepth = actualZFar; + } - mRenderer->getDeviceContext()->RSSetViewports(1, &dxViewport); + mRenderer->getDeviceContext()->RSSetViewports(numRectangles, dxViewports.data()); mCurViewport = viewport; 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 (mRenderer->getRenderer11DeviceCaps().featureLevel <= D3D_FEATURE_LEVEL_9_3) + const D3D11_VIEWPORT adjustViewport = {static_cast(dxViewportTopLeftX), + static_cast(dxViewportTopLeftY), + static_cast(dxViewportWidth), + static_cast(dxViewportHeight), + actualZNear, + actualZFar}; + mShaderConstants.onViewportChange(viewport, adjustViewport, is9_3, mCurPresentPathFastEnabled); +} + +void StateManager11::invalidateRenderTarget() +{ + mRenderTargetIsDirty = true; +} + +void StateManager11::processFramebufferInvalidation(const gl::Context *context) +{ + if (!mRenderTargetIsDirty) { - mVertexConstants.viewAdjust[0] = static_cast((viewport.width - dxViewportWidth) + - 2 * (viewport.x - dxViewportTopLeftX)) / - dxViewport.Width; - mVertexConstants.viewAdjust[1] = static_cast((viewport.height - dxViewportHeight) + - 2 * (viewport.y - dxViewportTopLeftY)) / - dxViewport.Height; - mVertexConstants.viewAdjust[2] = static_cast(viewport.width) / dxViewport.Width; - mVertexConstants.viewAdjust[3] = static_cast(viewport.height) / dxViewport.Height; + return; } - mPixelConstants.viewCoords[0] = viewport.width * 0.5f; - mPixelConstants.viewCoords[1] = viewport.height * 0.5f; - mPixelConstants.viewCoords[2] = viewport.x + (viewport.width * 0.5f); - mPixelConstants.viewCoords[3] = viewport.y + (viewport.height * 0.5f); + ASSERT(context); - // 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]; + mRenderTargetIsDirty = false; + mInternalDirtyBits.set(DIRTY_BIT_RENDER_TARGET); - mPixelConstants.depthFront[0] = (actualZFar - actualZNear) * 0.5f; - mPixelConstants.depthFront[1] = (actualZNear + actualZFar) * 0.5f; + // The pixel shader is dependent on the output layout. + invalidateShaders(); - 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; + // The D3D11 blend state is heavily dependent on the current render target. + mInternalDirtyBits.set(DIRTY_BIT_BLEND_STATE); - mPixelConstants.viewScale[0] = 1.0f; - mPixelConstants.viewScale[1] = mCurPresentPathFastEnabled ? 1.0f : -1.0f; - mPixelConstants.viewScale[2] = 1.0f; - mPixelConstants.viewScale[3] = 1.0f; + gl::Framebuffer *fbo = context->getGLState().getDrawFramebuffer(); + ASSERT(fbo); - mVertexConstants.viewScale[0] = mPixelConstants.viewScale[0]; - mVertexConstants.viewScale[1] = mPixelConstants.viewScale[1]; - mVertexConstants.viewScale[2] = mPixelConstants.viewScale[2]; - mVertexConstants.viewScale[3] = mPixelConstants.viewScale[3]; + // Disable the depth test/depth write if we are using a stencil-only attachment. + // This is because ANGLE emulates stencil-only with D24S8 on D3D11 - we should neither read + // nor write to the unused depth part of this emulated texture. + bool disableDepth = (!fbo->hasDepth() && fbo->hasStencil()); - mViewportStateIsDirty = false; -} + // Similarly we disable the stencil portion of the DS attachment if the app only binds depth. + bool disableStencil = (fbo->hasDepth() && !fbo->hasStencil()); -void StateManager11::invalidateRenderTarget() -{ - for (auto &appliedRTV : mAppliedRTVs) + if (!mCurDisableDepth.valid() || disableDepth != mCurDisableDepth.value() || + !mCurDisableStencil.valid() || disableStencil != mCurDisableStencil.value()) + { + mInternalDirtyBits.set(DIRTY_BIT_DEPTH_STENCIL_STATE); + mCurDisableDepth = disableDepth; + mCurDisableStencil = disableStencil; + } + + bool multiSample = (fbo->getCachedSamples(context) != 0); + if (multiSample != mCurRasterState.multiSample) + { + mInternalDirtyBits.set(DIRTY_BIT_RASTERIZER_STATE); + mCurRasterState.multiSample = multiSample; + } + + checkPresentPath(context); + + if (mRenderer->getRenderer11DeviceCaps().featureLevel <= D3D_FEATURE_LEVEL_9_3) { - appliedRTV = angle::DirtyPointer; + const auto *firstAttachment = fbo->getFirstNonNullAttachment(); + if (firstAttachment) + { + const auto &size = firstAttachment->getSize(); + if (mViewportBounds.width != size.width || mViewportBounds.height != size.height) + { + mViewportBounds = gl::Extents(size.width, size.height, 1); + invalidateViewport(context); + } + } } - mAppliedDSV = angle::DirtyPointer; } -void StateManager11::invalidateEverything() +void StateManager11::invalidateBoundViews() { - mBlendStateIsDirty = true; - mDepthStencilStateIsDirty = true; - mRasterizerStateIsDirty = true; - mScissorStateIsDirty = true; - mViewportStateIsDirty = true; - - // 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. mCurVertexSRVs.clear(); mCurPixelSRVs.clear(); invalidateRenderTarget(); } -bool StateManager11::setRenderTargets(const RenderTargetArray &renderTargets, - ID3D11DepthStencilView *depthStencil) +void StateManager11::invalidateVertexBuffer() { - // TODO(jmadill): Use context caps? - UINT drawBuffers = mRenderer->getRendererCaps().maxDrawBuffers; + unsigned int limit = std::min(mRenderer->getNativeCaps().maxVertexAttributes, + gl::MAX_VERTEX_ATTRIBS); + mDirtyVertexBufferRange = gl::RangeUI(0, limit); + mInputLayoutIsDirty = true; + mInternalDirtyBits.set(DIRTY_BIT_CURRENT_VALUE_ATTRIBS); + invalidateVertexAttributeTranslation(); +} - // Apply the render target and depth stencil - size_t arraySize = sizeof(uintptr_t) * drawBuffers; - if (memcmp(renderTargets.data(), mAppliedRTVs.data(), arraySize) == 0 && - reinterpret_cast(depthStencil) == mAppliedDSV) +void StateManager11::invalidateViewport(const gl::Context *context) +{ + mInternalDirtyBits.set(DIRTY_BIT_VIEWPORT_STATE); + + // Viewport affects the driver constants. + invalidateDriverUniforms(); +} + +void StateManager11::invalidateTexturesAndSamplers() +{ + mInternalDirtyBits.set(DIRTY_BIT_TEXTURE_AND_SAMPLER_STATE); + invalidateSwizzles(); + + // Texture state affects the driver uniforms (base level, etc). + invalidateDriverUniforms(); +} + +void StateManager11::invalidateSwizzles() +{ + mDirtySwizzles = true; +} + +void StateManager11::invalidateProgramUniforms() +{ + mInternalDirtyBits.set(DIRTY_BIT_PROGRAM_UNIFORMS); +} + +void StateManager11::invalidateDriverUniforms() +{ + mInternalDirtyBits.set(DIRTY_BIT_DRIVER_UNIFORMS); +} + +void StateManager11::invalidateProgramUniformBuffers() +{ + mInternalDirtyBits.set(DIRTY_BIT_PROGRAM_UNIFORM_BUFFERS); +} + +void StateManager11::invalidateConstantBuffer(unsigned int slot) +{ + if (slot == d3d11::RESERVED_CONSTANT_BUFFER_SLOT_DRIVER) + { + invalidateDriverUniforms(); + } + else if (slot == d3d11::RESERVED_CONSTANT_BUFFER_SLOT_DEFAULT_UNIFORM_BLOCK) + { + invalidateProgramUniforms(); + } + else { - return false; + invalidateProgramUniformBuffers(); } +} - // The D3D11 blend state is heavily dependent on the current render target. - mBlendStateIsDirty = true; +void StateManager11::invalidateShaders() +{ + mInternalDirtyBits.set(DIRTY_BIT_SHADERS); +} + +void StateManager11::setRenderTarget(ID3D11RenderTargetView *rtv, ID3D11DepthStencilView *dsv) +{ + if ((rtv && unsetConflictingView(rtv)) || (dsv && unsetConflictingView(dsv))) + { + mInternalDirtyBits.set(DIRTY_BIT_TEXTURE_AND_SAMPLER_STATE); + } + + mRenderer->getDeviceContext()->OMSetRenderTargets(1, &rtv, dsv); + mInternalDirtyBits.set(DIRTY_BIT_RENDER_TARGET); +} + +void StateManager11::setRenderTargets(ID3D11RenderTargetView **rtvs, + UINT numRTVs, + ID3D11DepthStencilView *dsv) +{ + bool anyDirty = false; + + for (UINT rtvIndex = 0; rtvIndex < numRTVs; ++rtvIndex) + { + anyDirty = anyDirty || unsetConflictingView(rtvs[rtvIndex]); + } - for (UINT rtIndex = 0; rtIndex < drawBuffers; rtIndex++) + if (dsv) { - mAppliedRTVs[rtIndex] = reinterpret_cast(renderTargets[rtIndex]); + anyDirty = anyDirty || unsetConflictingView(dsv); } - mAppliedDSV = reinterpret_cast(depthStencil); - mRenderer->getDeviceContext()->OMSetRenderTargets(drawBuffers, renderTargets.data(), - depthStencil); - return true; + if (anyDirty) + { + mInternalDirtyBits.set(DIRTY_BIT_TEXTURE_AND_SAMPLER_STATE); + } + + mRenderer->getDeviceContext()->OMSetRenderTargets(numRTVs, (numRTVs > 0) ? rtvs : nullptr, dsv); + mInternalDirtyBits.set(DIRTY_BIT_RENDER_TARGET); } -void StateManager11::setRenderTarget(ID3D11RenderTargetView *renderTarget, - ID3D11DepthStencilView *depthStencil) +void StateManager11::invalidateVertexAttributeTranslation() { - mRenderer->getDeviceContext()->OMSetRenderTargets(1, &renderTarget, depthStencil); + mVertexAttribsNeedTranslation = true; } -void StateManager11::setShaderResource(gl::SamplerType shaderType, - UINT resourceSlot, - ID3D11ShaderResourceView *srv) +void StateManager11::onBeginQuery(Query11 *query) { - auto ¤tSRVs = (shaderType == gl::SAMPLER_VERTEX ? mCurVertexSRVs : mCurPixelSRVs); + mCurrentQueries.insert(query); +} - ASSERT(static_cast(resourceSlot) < currentSRVs.size()); - const SRVRecord &record = currentSRVs[resourceSlot]; +void StateManager11::onDeleteQueryObject(Query11 *query) +{ + mCurrentQueries.erase(query); +} - if (record.srv != reinterpret_cast(srv)) +gl::Error StateManager11::onMakeCurrent(const gl::Context *context) +{ + const gl::State &state = context->getGLState(); + + for (Query11 *query : mCurrentQueries) { - auto deviceContext = mRenderer->getDeviceContext(); - if (shaderType == gl::SAMPLER_VERTEX) - { - deviceContext->VSSetShaderResources(resourceSlot, 1, &srv); - } - else + ANGLE_TRY(query->pause()); + } + mCurrentQueries.clear(); + + for (GLenum queryType : QueryTypes) + { + gl::Query *query = state.getActiveQuery(queryType); + if (query != nullptr) { - deviceContext->PSSetShaderResources(resourceSlot, 1, &srv); + Query11 *query11 = GetImplAs(query); + ANGLE_TRY(query11->resume()); + mCurrentQueries.insert(query11); } - - currentSRVs.update(resourceSlot, srv); } + + return gl::NoError(); } gl::Error StateManager11::clearTextures(gl::SamplerType samplerType, @@ -856,185 +1528,1548 @@ gl::Error StateManager11::clearTextures(gl::SamplerType samplerType, { if (rangeStart == rangeEnd) { - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } auto ¤tSRVs = (samplerType == gl::SAMPLER_VERTEX ? mCurVertexSRVs : mCurPixelSRVs); - gl::Range clearRange(rangeStart, rangeStart); - clearRange.extend(std::min(rangeEnd, currentSRVs.highestUsed())); - + gl::Range clearRange(rangeStart, std::min(rangeEnd, currentSRVs.highestUsed())); if (clearRange.empty()) { - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } - auto deviceContext = mRenderer->getDeviceContext(); + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); if (samplerType == gl::SAMPLER_VERTEX) { - deviceContext->VSSetShaderResources(static_cast(rangeStart), - static_cast(rangeEnd - rangeStart), + deviceContext->VSSetShaderResources(static_cast(clearRange.low()), + static_cast(clearRange.length()), &mNullSRVs[0]); } else { - deviceContext->PSSetShaderResources(static_cast(rangeStart), - static_cast(rangeEnd - rangeStart), + deviceContext->PSSetShaderResources(static_cast(clearRange.low()), + static_cast(clearRange.length()), &mNullSRVs[0]); } - for (size_t samplerIndex = rangeStart; samplerIndex < rangeEnd; ++samplerIndex) + for (size_t samplerIndex : clearRange) { currentSRVs.update(samplerIndex, nullptr); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -void StateManager11::unsetConflictingSRVs(gl::SamplerType samplerType, +bool StateManager11::unsetConflictingView(ID3D11View *view) +{ + uintptr_t resource = reinterpret_cast(GetViewResource(view)); + return unsetConflictingSRVs(gl::SAMPLER_VERTEX, resource, nullptr) || + unsetConflictingSRVs(gl::SAMPLER_PIXEL, resource, nullptr); +} + +bool StateManager11::unsetConflictingSRVs(gl::SamplerType samplerType, uintptr_t resource, - const gl::ImageIndex &index) + const gl::ImageIndex *index) { auto ¤tSRVs = (samplerType == gl::SAMPLER_VERTEX ? mCurVertexSRVs : mCurPixelSRVs); + bool foundOne = false; + for (size_t resourceIndex = 0; resourceIndex < currentSRVs.size(); ++resourceIndex) { auto &record = currentSRVs[resourceIndex]; if (record.srv && record.resource == resource && - ImageIndexConflictsWithSRV(index, record.desc)) + (!index || ImageIndexConflictsWithSRV(*index, record.desc))) { - setShaderResource(samplerType, static_cast(resourceIndex), NULL); + setShaderResourceInternal( + samplerType, static_cast(resourceIndex), nullptr); + foundOne = true; } } + + return foundOne; +} + +void StateManager11::unsetConflictingAttachmentResources( + const gl::FramebufferAttachment *attachment, + ID3D11Resource *resource) +{ + // Unbind render target SRVs from the shader here to prevent D3D11 warnings. + if (attachment->type() == GL_TEXTURE) + { + uintptr_t resourcePtr = reinterpret_cast(resource); + const gl::ImageIndex &index = attachment->getTextureImageIndex(); + // The index doesn't need to be corrected for the small compressed texture workaround + // because a rendertarget is never compressed. + unsetConflictingSRVs(gl::SAMPLER_VERTEX, resourcePtr, &index); + unsetConflictingSRVs(gl::SAMPLER_PIXEL, resourcePtr, &index); + } + else if (attachment->type() == GL_FRAMEBUFFER_DEFAULT) + { + uintptr_t resourcePtr = reinterpret_cast(resource); + unsetConflictingSRVs(gl::SAMPLER_VERTEX, resourcePtr, nullptr); + unsetConflictingSRVs(gl::SAMPLER_PIXEL, resourcePtr, nullptr); + } } -void StateManager11::initialize(const gl::Caps &caps) +gl::Error StateManager11::initialize(const gl::Caps &caps, const gl::Extensions &extensions) { mCurVertexSRVs.initialize(caps.maxVertexTextureImageUnits); mCurPixelSRVs.initialize(caps.maxTextureImageUnits); // Initialize cached NULL SRV block mNullSRVs.resize(caps.maxTextureImageUnits, nullptr); + + mCurrentValueAttribs.resize(caps.maxVertexAttributes); + + mForceSetVertexSamplerStates.resize(caps.maxVertexTextureImageUnits, true); + mForceSetPixelSamplerStates.resize(caps.maxTextureImageUnits, true); + mForceSetComputeSamplerStates.resize(caps.maxComputeTextureImageUnits, true); + + mCurVertexSamplerStates.resize(caps.maxVertexTextureImageUnits); + mCurPixelSamplerStates.resize(caps.maxTextureImageUnits); + mCurComputeSamplerStates.resize(caps.maxComputeTextureImageUnits); + + mShaderConstants.init(caps); + + mIsMultiviewEnabled = extensions.multiview; + mViewportOffsets.resize(1u); + + ANGLE_TRY(mVertexDataManager.initialize()); + + mCurrentAttributes.reserve(gl::MAX_VERTEX_ATTRIBS); + + return gl::NoError(); } -gl::Error StateManager11::syncFramebuffer(const gl::Framebuffer *framebuffer) +void StateManager11::deinitialize() { - // 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; - RenderTargetArray framebufferRTVs; - bool missingColorRenderTarget = true; + mCurrentValueAttribs.clear(); + mInputLayoutCache.clear(); + mVertexDataManager.deinitialize(); + mIndexDataManager.deinitialize(); + + mDriverConstantBufferVS.reset(); + mDriverConstantBufferPS.reset(); + mDriverConstantBufferCS.reset(); +} - framebufferRTVs.fill(nullptr); +gl::Error StateManager11::syncFramebuffer(const gl::Context *context, gl::Framebuffer *framebuffer) +{ + Framebuffer11 *framebuffer11 = GetImplAs(framebuffer); - const Framebuffer11 *framebuffer11 = GetImplAs(framebuffer); - const gl::AttachmentList &colorbuffers = framebuffer11->getColorAttachmentsForRender(); + // Applies the render target surface, depth stencil surface, viewport rectangle and + // scissor rectangle to the renderer + ASSERT(framebuffer && !framebuffer->hasAnyDirtyBit() && framebuffer->cachedComplete()); - for (size_t colorAttachment = 0; colorAttachment < colorbuffers.size(); ++colorAttachment) + // 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 (framebuffer->id() == 0) { - const gl::FramebufferAttachment *colorbuffer = colorbuffers[colorAttachment]; - - if (colorbuffer) + ASSERT(!framebuffer11->hasAnyInternalDirtyBit()); + const gl::Extents &size = framebuffer->getFirstColorbuffer()->getSize(); + if (size.width == 0 || size.height == 0) { - // 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. - const gl::Extents &size = colorbuffer->getSize(); - if (size.width == 0 || size.height == 0) - { - return gl::Error(GL_NO_ERROR); - } + return gl::NoError(); + } + } - // Extract the render target dimensions and view - RenderTarget11 *renderTarget = NULL; - gl::Error error = colorbuffer->getRenderTarget(&renderTarget); - if (error.isError()) - { - return error; - } - ASSERT(renderTarget); + RTVArray framebufferRTVs = {{}}; - framebufferRTVs[colorAttachment] = renderTarget->getRenderTargetView(); - ASSERT(framebufferRTVs[colorAttachment]); + const auto &colorRTs = framebuffer11->getCachedColorRenderTargets(); - if (missingColorRenderTarget) - { - renderTargetWidth = renderTarget->getWidth(); - renderTargetHeight = renderTarget->getHeight(); - renderTargetFormat = renderTarget->getDXGIFormat(); - missingColorRenderTarget = false; - } + size_t appliedRTIndex = 0; + bool skipInactiveRTs = mRenderer->getWorkarounds().mrtPerfWorkaround; + const auto &drawStates = framebuffer->getDrawBufferStates(); + gl::DrawBufferMask activeProgramOutputs = + context->getContextState().getState().getProgram()->getActiveOutputVariables(); + UINT maxExistingRT = 0; - // 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(); - // 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); - } + for (size_t rtIndex = 0; rtIndex < colorRTs.size(); ++rtIndex) + { + const RenderTarget11 *renderTarget = colorRTs[rtIndex]; + + // Skip inactive rendertargets if the workaround is enabled. + if (skipInactiveRTs && + (!renderTarget || drawStates[rtIndex] == GL_NONE || !activeProgramOutputs[rtIndex])) + { + continue; } - } - // Get the depth stencil buffers - ID3D11DepthStencilView *framebufferDSV = NULL; - const gl::FramebufferAttachment *depthStencil = framebuffer->getDepthOrStencilbuffer(); - if (depthStencil) - { - RenderTarget11 *depthStencilRenderTarget = NULL; - gl::Error error = depthStencil->getRenderTarget(&depthStencilRenderTarget); - if (error.isError()) + if (renderTarget) { - return error; + framebufferRTVs[appliedRTIndex] = renderTarget->getRenderTargetView().get(); + ASSERT(framebufferRTVs[appliedRTIndex]); + maxExistingRT = static_cast(appliedRTIndex) + 1; + + // Unset conflicting texture SRVs + const auto *attachment = framebuffer->getColorbuffer(rtIndex); + ASSERT(attachment); + unsetConflictingAttachmentResources(attachment, renderTarget->getTexture().get()); } - ASSERT(depthStencilRenderTarget); - framebufferDSV = depthStencilRenderTarget->getDepthStencilView(); + appliedRTIndex++; + } + + // Get the depth stencil buffers + ID3D11DepthStencilView *framebufferDSV = nullptr; + const auto *depthStencilRenderTarget = framebuffer11->getCachedDepthStencilRenderTarget(); + if (depthStencilRenderTarget) + { + framebufferDSV = depthStencilRenderTarget->getDepthStencilView().get(); 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(); - } + // Unset conflicting texture SRVs + const auto *attachment = framebuffer->getDepthOrStencilbuffer(); + ASSERT(attachment); + unsetConflictingAttachmentResources(attachment, + depthStencilRenderTarget->getTexture().get()); + } + + // TODO(jmadill): Use context caps? + ASSERT(maxExistingRT <= static_cast(mRenderer->getNativeCaps().maxDrawBuffers)); + + // Apply the render target and depth stencil + mRenderer->getDeviceContext()->OMSetRenderTargets(maxExistingRT, framebufferRTVs.data(), + framebufferDSV); + + return gl::NoError(); +} + +void StateManager11::invalidateCurrentValueAttrib(size_t attribIndex) +{ + mDirtyCurrentValueAttribs.set(attribIndex); + mInternalDirtyBits.set(DIRTY_BIT_CURRENT_VALUE_ATTRIBS); +} + +gl::Error StateManager11::syncCurrentValueAttribs(const gl::State &glState) +{ + const auto &activeAttribsMask = glState.getProgram()->getActiveAttribLocationsMask(); + const auto &dirtyActiveAttribs = (activeAttribsMask & mDirtyCurrentValueAttribs); + + if (!dirtyActiveAttribs.any()) + { + return gl::NoError(); + } + + const auto &vertexAttributes = glState.getVertexArray()->getVertexAttributes(); + const auto &vertexBindings = glState.getVertexArray()->getVertexBindings(); + mDirtyCurrentValueAttribs = (mDirtyCurrentValueAttribs & ~dirtyActiveAttribs); + + for (auto attribIndex : dirtyActiveAttribs) + { + if (vertexAttributes[attribIndex].enabled) + continue; + + const auto *attrib = &vertexAttributes[attribIndex]; + const auto ¤tValue = glState.getVertexAttribCurrentValue(attribIndex); + TranslatedAttribute *currentValueAttrib = &mCurrentValueAttribs[attribIndex]; + currentValueAttrib->currentValueType = currentValue.Type; + currentValueAttrib->attribute = attrib; + currentValueAttrib->binding = &vertexBindings[attrib->bindingIndex]; - // Unbind render target SRVs from the shader here to prevent D3D11 warnings. - if (depthStencil->type() == GL_TEXTURE) + mDirtyVertexBufferRange.extend(static_cast(attribIndex)); + mInputLayoutIsDirty = true; + + ANGLE_TRY(mVertexDataManager.storeCurrentValue(currentValue, currentValueAttrib, + static_cast(attribIndex))); + } + + return gl::NoError(); +} + +void StateManager11::setInputLayout(const d3d11::InputLayout *inputLayout) +{ + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); + if (inputLayout == nullptr) + { + if (!mCurrentInputLayout.empty()) { - uintptr_t depthStencilResource = - reinterpret_cast(GetViewResource(framebufferDSV)); - const gl::ImageIndex &index = depthStencil->getTextureImageIndex(); - // 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); + deviceContext->IASetInputLayout(nullptr); + mCurrentInputLayout.clear(); + mInputLayoutIsDirty = true; } } + else if (inputLayout->getSerial() != mCurrentInputLayout) + { + deviceContext->IASetInputLayout(inputLayout->get()); + mCurrentInputLayout = inputLayout->getSerial(); + mInputLayoutIsDirty = true; + } +} + +bool StateManager11::queueVertexBufferChange(size_t bufferIndex, + ID3D11Buffer *buffer, + UINT stride, + UINT offset) +{ + if (buffer != mCurrentVertexBuffers[bufferIndex] || + stride != mCurrentVertexStrides[bufferIndex] || + offset != mCurrentVertexOffsets[bufferIndex]) + { + mInputLayoutIsDirty = true; + mDirtyVertexBufferRange.extend(static_cast(bufferIndex)); + + mCurrentVertexBuffers[bufferIndex] = buffer; + mCurrentVertexStrides[bufferIndex] = stride; + mCurrentVertexOffsets[bufferIndex] = offset; + return true; + } + + return false; +} + +bool StateManager11::queueVertexOffsetChange(size_t bufferIndex, UINT offsetOnly) +{ + if (offsetOnly != mCurrentVertexOffsets[bufferIndex]) + { + mInputLayoutIsDirty = true; + mDirtyVertexBufferRange.extend(static_cast(bufferIndex)); + mCurrentVertexOffsets[bufferIndex] = offsetOnly; + return true; + } + return false; +} + +void StateManager11::applyVertexBufferChanges() +{ + if (mDirtyVertexBufferRange.empty()) + { + return; + } + + ASSERT(mDirtyVertexBufferRange.high() <= gl::MAX_VERTEX_ATTRIBS); + + UINT start = static_cast(mDirtyVertexBufferRange.low()); + + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); + deviceContext->IASetVertexBuffers(start, static_cast(mDirtyVertexBufferRange.length()), + &mCurrentVertexBuffers[start], &mCurrentVertexStrides[start], + &mCurrentVertexOffsets[start]); + + mDirtyVertexBufferRange = gl::RangeUI(gl::MAX_VERTEX_ATTRIBS, 0); +} + +void StateManager11::setSingleVertexBuffer(const d3d11::Buffer *buffer, UINT stride, UINT offset) +{ + ID3D11Buffer *native = buffer ? buffer->get() : nullptr; + if (queueVertexBufferChange(0, native, stride, offset)) + { + applyVertexBufferChanges(); + } +} + +gl::Error StateManager11::updateState(const gl::Context *context, GLenum drawMode) +{ + const auto &glState = context->getGLState(); + auto *programD3D = GetImplAs(glState.getProgram()); + + // TODO(jmadill): Use dirty bits. + processFramebufferInvalidation(context); + + // TODO(jmadill): Use dirty bits. + if (programD3D->updateSamplerMapping() == ProgramD3D::SamplerMapping::WasDirty) + { + invalidateTexturesAndSamplers(); + } + + // TODO(jmadill): Use dirty bits. + if (programD3D->areVertexUniformsDirty() || programD3D->areFragmentUniformsDirty()) + { + mInternalDirtyBits.set(DIRTY_BIT_PROGRAM_UNIFORMS); + } + + // Transform feedback affects the stream-out geometry shader. + // TODO(jmadill): Use dirty bits. + if (glState.isTransformFeedbackActiveUnpaused() != mIsTransformFeedbackCurrentlyActiveUnpaused) + { + mIsTransformFeedbackCurrentlyActiveUnpaused = glState.isTransformFeedbackActiveUnpaused(); + invalidateShaders(); + } + + // Swizzling can cause internal state changes with blit shaders. + if (mDirtySwizzles) + { + ANGLE_TRY(generateSwizzles(context)); + mDirtySwizzles = false; + } + + gl::Framebuffer *framebuffer = glState.getDrawFramebuffer(); + Framebuffer11 *framebuffer11 = GetImplAs(framebuffer); + ANGLE_TRY(framebuffer11->markAttachmentsDirty(context)); + + if (framebuffer11->hasAnyInternalDirtyBit()) + { + ASSERT(framebuffer->id() != 0); + framebuffer11->syncInternalState(context); + } + + bool pointDrawMode = (drawMode == GL_POINTS); + if (pointDrawMode != mCurRasterState.pointDrawMode) + { + mInternalDirtyBits.set(DIRTY_BIT_RASTERIZER_STATE); + + // Changing from points to not points (or vice-versa) affects the geometry shader. + invalidateShaders(); + } + + // TODO(jiawei.shao@intel.com): This can be recomputed only on framebuffer or multisample mask + // state changes. + RenderTarget11 *firstRT = framebuffer11->getFirstRenderTarget(); + int samples = (firstRT ? firstRT->getSamples() : 0); + unsigned int sampleMask = GetBlendSampleMask(glState, samples); + if (sampleMask != mCurSampleMask) + { + mInternalDirtyBits.set(DIRTY_BIT_BLEND_STATE); + } + + // Changing the vertex attribute state can affect the vertex shader. + gl::VertexArray *vao = glState.getVertexArray(); + VertexArray11 *vao11 = GetImplAs(vao); + if (vao11->flushAttribUpdates(context)) + { + mInternalDirtyBits.set(DIRTY_BIT_SHADERS); + } - if (setRenderTargets(framebufferRTVs, framebufferDSV)) + auto dirtyBitsCopy = mInternalDirtyBits; + mInternalDirtyBits.reset(); + + for (auto dirtyBit : dirtyBitsCopy) { - setViewportBounds(renderTargetWidth, renderTargetHeight); + switch (dirtyBit) + { + case DIRTY_BIT_RENDER_TARGET: + ANGLE_TRY(syncFramebuffer(context, framebuffer)); + break; + case DIRTY_BIT_VIEWPORT_STATE: + syncViewport(context); + break; + case DIRTY_BIT_SCISSOR_STATE: + syncScissorRectangle(glState.getScissor(), glState.isScissorTestEnabled()); + break; + case DIRTY_BIT_RASTERIZER_STATE: + ANGLE_TRY(syncRasterizerState(context, pointDrawMode)); + break; + case DIRTY_BIT_BLEND_STATE: + ANGLE_TRY(syncBlendState(context, framebuffer, glState.getBlendState(), + glState.getBlendColor(), sampleMask)); + break; + case DIRTY_BIT_DEPTH_STENCIL_STATE: + ANGLE_TRY(syncDepthStencilState(glState)); + break; + case DIRTY_BIT_TEXTURE_AND_SAMPLER_STATE: + // TODO(jmadill): More fine-grained update. + ANGLE_TRY(syncTextures(context)); + break; + case DIRTY_BIT_PROGRAM_UNIFORMS: + ANGLE_TRY(applyUniforms(programD3D)); + break; + case DIRTY_BIT_DRIVER_UNIFORMS: + // This must happen after viewport sync; the viewport affects builtin uniforms. + ANGLE_TRY(applyDriverUniforms(*programD3D)); + break; + case DIRTY_BIT_PROGRAM_UNIFORM_BUFFERS: + ANGLE_TRY(syncUniformBuffers(context, programD3D)); + break; + case DIRTY_BIT_SHADERS: + ANGLE_TRY(syncProgram(context, drawMode)); + break; + case DIRTY_BIT_CURRENT_VALUE_ATTRIBS: + ANGLE_TRY(syncCurrentValueAttribs(glState)); + break; + default: + UNREACHABLE(); + break; + } } - gl::Error error = framebuffer11->invalidateSwizzles(); - if (error.isError()) + ANGLE_TRY(syncTransformFeedbackBuffers(context)); + + // Check that we haven't set any dirty bits in the flushing of the dirty bits loop. + ASSERT(mInternalDirtyBits.none()); + + return gl::NoError(); +} + +void StateManager11::setShaderResourceShared(gl::SamplerType shaderType, + UINT resourceSlot, + const d3d11::SharedSRV *srv) +{ + setShaderResourceInternal(shaderType, resourceSlot, srv); + + // TODO(jmadill): Narrower dirty region. + mInternalDirtyBits.set(DIRTY_BIT_TEXTURE_AND_SAMPLER_STATE); +} + +void StateManager11::setShaderResource(gl::SamplerType shaderType, + UINT resourceSlot, + const d3d11::ShaderResourceView *srv) +{ + setShaderResourceInternal(shaderType, resourceSlot, srv); + + // TODO(jmadill): Narrower dirty region. + mInternalDirtyBits.set(DIRTY_BIT_TEXTURE_AND_SAMPLER_STATE); +} + +void StateManager11::setPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY primitiveTopology) +{ + if (primitiveTopology != mCurrentPrimitiveTopology) { - return error; + mRenderer->getDeviceContext()->IASetPrimitiveTopology(primitiveTopology); + mCurrentPrimitiveTopology = primitiveTopology; } +} - return gl::Error(GL_NO_ERROR); +void StateManager11::setDrawShaders(const d3d11::VertexShader *vertexShader, + const d3d11::GeometryShader *geometryShader, + const d3d11::PixelShader *pixelShader) +{ + setVertexShader(vertexShader); + setGeometryShader(geometryShader); + setPixelShader(pixelShader); +} + +void StateManager11::setVertexShader(const d3d11::VertexShader *shader) +{ + ResourceSerial serial = shader ? shader->getSerial() : ResourceSerial(0); + + if (serial != mAppliedVertexShader) + { + ID3D11VertexShader *appliedShader = shader ? shader->get() : nullptr; + mRenderer->getDeviceContext()->VSSetShader(appliedShader, nullptr, 0); + mAppliedVertexShader = serial; + invalidateShaders(); + } +} + +void StateManager11::setGeometryShader(const d3d11::GeometryShader *shader) +{ + ResourceSerial serial = shader ? shader->getSerial() : ResourceSerial(0); + + if (serial != mAppliedGeometryShader) + { + ID3D11GeometryShader *appliedShader = shader ? shader->get() : nullptr; + mRenderer->getDeviceContext()->GSSetShader(appliedShader, nullptr, 0); + mAppliedGeometryShader = serial; + invalidateShaders(); + } +} + +void StateManager11::setPixelShader(const d3d11::PixelShader *shader) +{ + ResourceSerial serial = shader ? shader->getSerial() : ResourceSerial(0); + + if (serial != mAppliedPixelShader) + { + ID3D11PixelShader *appliedShader = shader ? shader->get() : nullptr; + mRenderer->getDeviceContext()->PSSetShader(appliedShader, nullptr, 0); + mAppliedPixelShader = serial; + invalidateShaders(); + } +} + +void StateManager11::setComputeShader(const d3d11::ComputeShader *shader) +{ + ResourceSerial serial = shader ? shader->getSerial() : ResourceSerial(0); + + if (serial != mAppliedComputeShader) + { + ID3D11ComputeShader *appliedShader = shader ? shader->get() : nullptr; + mRenderer->getDeviceContext()->CSSetShader(appliedShader, nullptr, 0); + mAppliedComputeShader = serial; + // TODO(jmadill): Dirty bits for compute. + } +} + +void StateManager11::setVertexConstantBuffer(unsigned int slot, const d3d11::Buffer *buffer) +{ + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); + auto ¤tSerial = mCurrentConstantBufferVS[slot]; + + mCurrentConstantBufferVSOffset[slot] = 0; + mCurrentConstantBufferVSSize[slot] = 0; + + if (buffer) + { + if (currentSerial != buffer->getSerial()) + { + deviceContext->VSSetConstantBuffers(slot, 1, buffer->getPointer()); + currentSerial = buffer->getSerial(); + invalidateConstantBuffer(slot); + } + } + else + { + if (!currentSerial.empty()) + { + ID3D11Buffer *nullBuffer = nullptr; + deviceContext->VSSetConstantBuffers(slot, 1, &nullBuffer); + currentSerial.clear(); + invalidateConstantBuffer(slot); + } + } +} + +void StateManager11::setPixelConstantBuffer(unsigned int slot, const d3d11::Buffer *buffer) +{ + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); + auto ¤tSerial = mCurrentConstantBufferPS[slot]; + + mCurrentConstantBufferPSOffset[slot] = 0; + mCurrentConstantBufferPSSize[slot] = 0; + + if (buffer) + { + if (currentSerial != buffer->getSerial()) + { + deviceContext->PSSetConstantBuffers(slot, 1, buffer->getPointer()); + currentSerial = buffer->getSerial(); + invalidateConstantBuffer(slot); + } + } + else + { + if (!currentSerial.empty()) + { + ID3D11Buffer *nullBuffer = nullptr; + deviceContext->PSSetConstantBuffers(slot, 1, &nullBuffer); + currentSerial.clear(); + invalidateConstantBuffer(slot); + } + } +} + +void StateManager11::setDepthStencilState(const d3d11::DepthStencilState *depthStencilState, + UINT stencilRef) +{ + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); + + if (depthStencilState) + { + deviceContext->OMSetDepthStencilState(depthStencilState->get(), stencilRef); + } + else + { + deviceContext->OMSetDepthStencilState(nullptr, stencilRef); + } + + mInternalDirtyBits.set(DIRTY_BIT_DEPTH_STENCIL_STATE); +} + +void StateManager11::setSimpleBlendState(const d3d11::BlendState *blendState) +{ + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); + + if (blendState) + { + deviceContext->OMSetBlendState(blendState->get(), nullptr, 0xFFFFFFFF); + } + else + { + deviceContext->OMSetBlendState(nullptr, nullptr, 0xFFFFFFFF); + } + + mInternalDirtyBits.set(DIRTY_BIT_BLEND_STATE); +} + +void StateManager11::setRasterizerState(const d3d11::RasterizerState *rasterizerState) +{ + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); + + if (rasterizerState) + { + deviceContext->RSSetState(rasterizerState->get()); + } + else + { + deviceContext->RSSetState(nullptr); + } + + mInternalDirtyBits.set(DIRTY_BIT_RASTERIZER_STATE); +} + +void StateManager11::setSimpleViewport(const gl::Extents &extents) +{ + setSimpleViewport(extents.width, extents.height); +} + +void StateManager11::setSimpleViewport(int width, int height) +{ + D3D11_VIEWPORT viewport; + viewport.TopLeftX = 0; + viewport.TopLeftY = 0; + viewport.Width = static_cast(width); + viewport.Height = static_cast(height); + viewport.MinDepth = 0.0f; + viewport.MaxDepth = 1.0f; + + mRenderer->getDeviceContext()->RSSetViewports(1, &viewport); + mInternalDirtyBits.set(DIRTY_BIT_VIEWPORT_STATE); +} + +void StateManager11::setSimplePixelTextureAndSampler(const d3d11::SharedSRV &srv, + const d3d11::SamplerState &samplerState) +{ + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); + + setShaderResourceInternal(gl::SAMPLER_PIXEL, 0, &srv); + deviceContext->PSSetSamplers(0, 1, samplerState.getPointer()); + + mInternalDirtyBits.set(DIRTY_BIT_TEXTURE_AND_SAMPLER_STATE); + mForceSetPixelSamplerStates[0] = true; +} + +void StateManager11::setSimpleScissorRect(const gl::Rectangle &glRect) +{ + D3D11_RECT scissorRect; + scissorRect.left = glRect.x; + scissorRect.right = glRect.x + glRect.width; + scissorRect.top = glRect.y; + scissorRect.bottom = glRect.y + glRect.height; + setScissorRectD3D(scissorRect); +} + +void StateManager11::setScissorRectD3D(const D3D11_RECT &d3dRect) +{ + mRenderer->getDeviceContext()->RSSetScissorRects(1, &d3dRect); + mInternalDirtyBits.set(DIRTY_BIT_SCISSOR_STATE); +} + +// 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). +// Sampler mapping needs to be up-to-date on the program object before this is called. +gl::Error StateManager11::applyTextures(const gl::Context *context, gl::SamplerType shaderType) +{ + const auto &glState = context->getGLState(); + const auto &caps = context->getCaps(); + ProgramD3D *programD3D = GetImplAs(glState.getProgram()); + + ASSERT(!programD3D->isSamplerMappingDirty()); + + // TODO(jmadill): Use the Program's sampler bindings. + const auto &completeTextures = glState.getCompleteTextureCache(); + + unsigned int samplerRange = programD3D->getUsedSamplerRange(shaderType); + for (unsigned int samplerIndex = 0; samplerIndex < samplerRange; samplerIndex++) + { + GLint textureUnit = programD3D->getSamplerMapping(shaderType, samplerIndex, caps); + ASSERT(textureUnit != -1); + gl::Texture *texture = completeTextures[textureUnit]; + + // A nullptr texture indicates incomplete. + if (texture) + { + gl::Sampler *samplerObject = glState.getSampler(textureUnit); + + const gl::SamplerState &samplerState = + samplerObject ? samplerObject->getSamplerState() : texture->getSamplerState(); + + ANGLE_TRY(setSamplerState(context, shaderType, samplerIndex, texture, samplerState)); + ANGLE_TRY(setTexture(context, shaderType, samplerIndex, texture)); + } + else + { + GLenum textureType = programD3D->getSamplerTextureType(shaderType, samplerIndex); + + // Texture is not sampler complete or it is in use by the framebuffer. Bind the + // incomplete texture. + gl::Texture *incompleteTexture = nullptr; + ANGLE_TRY(mRenderer->getIncompleteTexture(context, textureType, &incompleteTexture)); + ANGLE_TRY(setSamplerState(context, shaderType, samplerIndex, incompleteTexture, + incompleteTexture->getSamplerState())); + ANGLE_TRY(setTexture(context, shaderType, samplerIndex, incompleteTexture)); + } + } + + // Set all the remaining textures to NULL + size_t samplerCount = (shaderType == gl::SAMPLER_PIXEL) ? caps.maxTextureImageUnits + : caps.maxVertexTextureImageUnits; + ANGLE_TRY(clearTextures(shaderType, samplerRange, samplerCount)); + + return gl::NoError(); +} + +gl::Error StateManager11::syncTextures(const gl::Context *context) +{ + ANGLE_TRY(applyTextures(context, gl::SAMPLER_VERTEX)); + ANGLE_TRY(applyTextures(context, gl::SAMPLER_PIXEL)); + return gl::NoError(); +} + +gl::Error StateManager11::setSamplerState(const gl::Context *context, + gl::SamplerType type, + int index, + gl::Texture *texture, + const gl::SamplerState &samplerState) +{ +#if !defined(NDEBUG) + // Storage should exist, texture should be complete. Only verified in Debug. + TextureD3D *textureD3D = GetImplAs(texture); + TextureStorage *storage = nullptr; + ANGLE_TRY(textureD3D->getNativeTexture(context, &storage)); + ASSERT(storage); +#endif // !defined(NDEBUG) + + auto *deviceContext = mRenderer->getDeviceContext(); + + if (type == gl::SAMPLER_PIXEL) + { + ASSERT(static_cast(index) < mRenderer->getNativeCaps().maxTextureImageUnits); + + if (mForceSetPixelSamplerStates[index] || + memcmp(&samplerState, &mCurPixelSamplerStates[index], sizeof(gl::SamplerState)) != 0) + { + ID3D11SamplerState *dxSamplerState = nullptr; + ANGLE_TRY(mRenderer->getSamplerState(samplerState, &dxSamplerState)); + + ASSERT(dxSamplerState != nullptr); + deviceContext->PSSetSamplers(index, 1, &dxSamplerState); + + mCurPixelSamplerStates[index] = samplerState; + } + + mForceSetPixelSamplerStates[index] = false; + } + else if (type == gl::SAMPLER_VERTEX) + { + ASSERT(static_cast(index) < + mRenderer->getNativeCaps().maxVertexTextureImageUnits); + + if (mForceSetVertexSamplerStates[index] || + memcmp(&samplerState, &mCurVertexSamplerStates[index], sizeof(gl::SamplerState)) != 0) + { + ID3D11SamplerState *dxSamplerState = nullptr; + ANGLE_TRY(mRenderer->getSamplerState(samplerState, &dxSamplerState)); + + ASSERT(dxSamplerState != nullptr); + deviceContext->VSSetSamplers(index, 1, &dxSamplerState); + + mCurVertexSamplerStates[index] = samplerState; + } + + mForceSetVertexSamplerStates[index] = false; + } + else if (type == gl::SAMPLER_COMPUTE) + { + ASSERT(static_cast(index) < + mRenderer->getNativeCaps().maxComputeTextureImageUnits); + + if (mForceSetComputeSamplerStates[index] || + memcmp(&samplerState, &mCurComputeSamplerStates[index], sizeof(gl::SamplerState)) != 0) + { + ID3D11SamplerState *dxSamplerState = nullptr; + ANGLE_TRY(mRenderer->getSamplerState(samplerState, &dxSamplerState)); + + ASSERT(dxSamplerState != nullptr); + deviceContext->CSSetSamplers(index, 1, &dxSamplerState); + + mCurComputeSamplerStates[index] = samplerState; + } + + mForceSetComputeSamplerStates[index] = false; + } + else + UNREACHABLE(); + + // Sampler metadata that's passed to shaders in uniforms is stored separately from rest of the + // sampler state since having it in contiguous memory makes it possible to memcpy to a constant + // buffer, and it doesn't affect the state set by PSSetSamplers/VSSetSamplers. + mShaderConstants.onSamplerChange(type, index, *texture); + + return gl::NoError(); +} + +gl::Error StateManager11::setTexture(const gl::Context *context, + gl::SamplerType type, + int index, + gl::Texture *texture) +{ + const d3d11::SharedSRV *textureSRV = nullptr; + + if (texture) + { + TextureD3D *textureImpl = GetImplAs(texture); + + TextureStorage *texStorage = nullptr; + ANGLE_TRY(textureImpl->getNativeTexture(context, &texStorage)); + + // Texture should be complete and have a storage + ASSERT(texStorage); + + TextureStorage11 *storage11 = GetAs(texStorage); + + ANGLE_TRY(storage11->getSRV(context, texture->getTextureState(), &textureSRV)); + + // If we get an invalid SRV here, something went wrong in the texture class and we're + // unexpectedly missing the shader resource view. + ASSERT(textureSRV->valid()); + + textureImpl->resetDirty(); + } + + ASSERT( + (type == gl::SAMPLER_PIXEL && + static_cast(index) < mRenderer->getNativeCaps().maxTextureImageUnits) || + (type == gl::SAMPLER_VERTEX && + static_cast(index) < mRenderer->getNativeCaps().maxVertexTextureImageUnits)); + + setShaderResourceInternal(type, index, textureSRV); + return gl::NoError(); +} + +// Things that affect a program's dirtyness: +// 1. Directly changing the program executable -> triggered in StateManager11::syncState. +// 2. The vertex attribute layout -> triggered in VertexArray11::syncState/signal. +// 3. The fragment shader's rendertargets -> triggered in Framebuffer11::syncState/signal. +// 4. Enabling/disabling rasterizer discard. -> triggered in StateManager11::syncState. +// 5. Enabling/disabling transform feedback. -> checked in StateManager11::updateState. +// 6. An internal shader was used. -> triggered in StateManager11::set*Shader. +// 7. Drawing with/without point sprites. -> checked in StateManager11::updateState. +// TODO(jmadill): Use dirty bits for transform feedback. +gl::Error StateManager11::syncProgram(const gl::Context *context, GLenum drawMode) +{ + Context11 *context11 = GetImplAs(context); + ANGLE_TRY(context11->triggerDrawCallProgramRecompilation(context, drawMode)); + + const auto &glState = context->getGLState(); + const auto *va11 = GetImplAs(glState.getVertexArray()); + auto *programD3D = GetImplAs(glState.getProgram()); + + programD3D->updateCachedInputLayout(va11->getCurrentStateSerial(), glState); + + // Binaries must be compiled before the sync. + ASSERT(programD3D->hasVertexExecutableForCachedInputLayout()); + ASSERT(programD3D->hasGeometryExecutableForPrimitiveType(drawMode)); + ASSERT(programD3D->hasPixelExecutableForCachedOutputLayout()); + + ShaderExecutableD3D *vertexExe = nullptr; + ANGLE_TRY(programD3D->getVertexExecutableForCachedInputLayout(&vertexExe, nullptr)); + + ShaderExecutableD3D *pixelExe = nullptr; + ANGLE_TRY(programD3D->getPixelExecutableForCachedOutputLayout(&pixelExe, nullptr)); + + ShaderExecutableD3D *geometryExe = nullptr; + ANGLE_TRY(programD3D->getGeometryExecutableForPrimitiveType(context, drawMode, &geometryExe, + nullptr)); + + const d3d11::VertexShader *vertexShader = + (vertexExe ? &GetAs(vertexExe)->getVertexShader() : nullptr); + + // Skip pixel shader if we're doing rasterizer discard. + const d3d11::PixelShader *pixelShader = nullptr; + if (!glState.getRasterizerState().rasterizerDiscard) + { + pixelShader = (pixelExe ? &GetAs(pixelExe)->getPixelShader() : nullptr); + } + + const d3d11::GeometryShader *geometryShader = nullptr; + if (glState.isTransformFeedbackActiveUnpaused()) + { + geometryShader = + (vertexExe ? &GetAs(vertexExe)->getStreamOutShader() : nullptr); + } + else + { + geometryShader = + (geometryExe ? &GetAs(geometryExe)->getGeometryShader() : nullptr); + } + + setDrawShaders(vertexShader, geometryShader, pixelShader); + + // Explicitly clear the shaders dirty bit. + mInternalDirtyBits.reset(DIRTY_BIT_SHADERS); + + return gl::NoError(); +} + +gl::Error StateManager11::applyVertexBuffer(const gl::Context *context, + GLenum mode, + const DrawCallVertexParams &vertexParams, + bool isIndexedRendering) +{ + const auto &state = context->getGLState(); + const gl::VertexArray *vertexArray = state.getVertexArray(); + VertexArray11 *vertexArray11 = GetImplAs(vertexArray); + + if (mVertexAttribsNeedTranslation) + { + ANGLE_TRY(vertexArray11->updateDirtyAndDynamicAttribs(context, &mVertexDataManager, + vertexParams)); + mInputLayoutIsDirty = true; + + // Determine if we need to update attribs on the next draw. + mVertexAttribsNeedTranslation = (vertexArray11->hasActiveDynamicAttrib(context)); + } + + if (!mLastFirstVertex.valid() || mLastFirstVertex.value() != vertexParams.firstVertex()) + { + mLastFirstVertex = vertexParams.firstVertex(); + mInputLayoutIsDirty = true; + } + + if (!mInputLayoutIsDirty) + { + return gl::NoError(); + } + + const auto &vertexArrayAttribs = vertexArray11->getTranslatedAttribs(); + gl::Program *program = state.getProgram(); + + // Sort the attributes according to ensure we re-use similar input layouts. + AttribIndexArray sortedSemanticIndices; + SortAttributesByLayout(program, vertexArrayAttribs, mCurrentValueAttribs, + &sortedSemanticIndices, &mCurrentAttributes); + + auto featureLevel = mRenderer->getRenderer11DeviceCaps().featureLevel; + + // If we are using FL 9_3, make sure the first attribute is not instanced + if (featureLevel <= D3D_FEATURE_LEVEL_9_3 && !mCurrentAttributes.empty()) + { + if (mCurrentAttributes[0]->divisor > 0) + { + Optional firstNonInstancedIndex = FindFirstNonInstanced(mCurrentAttributes); + if (firstNonInstancedIndex.valid()) + { + size_t index = firstNonInstancedIndex.value(); + std::swap(mCurrentAttributes[0], mCurrentAttributes[index]); + std::swap(sortedSemanticIndices[0], sortedSemanticIndices[index]); + } + } + } + + // Update the applied input layout by querying the cache. + ANGLE_TRY(mInputLayoutCache.updateInputLayout(mRenderer, state, mCurrentAttributes, mode, + sortedSemanticIndices, vertexParams)); + + // Update the applied vertex buffers. + ANGLE_TRY(mInputLayoutCache.applyVertexBuffers(context, mCurrentAttributes, mode, + vertexParams.firstVertex(), isIndexedRendering)); + + // InputLayoutCache::applyVertexBuffers calls through to the Bufer11 to get the native vertex + // buffer (ID3D11Buffer *). Because we allocate these buffers lazily, this will trigger + // allocation. This in turn will signal that the buffer is dirty. Since we just resolved the + // dirty-ness in VertexArray11::updateDirtyAndDynamicAttribs, this can make us do a needless + // update on the second draw call. + // Hence we clear the flags here, after we've applied vertex data, since we know everything + // is clean. This is a bit of a hack. + vertexArray11->clearDirtyAndPromoteDynamicAttribs(context, vertexParams); + + mInputLayoutIsDirty = false; + return gl::NoError(); +} + +gl::Error StateManager11::applyIndexBuffer(const gl::Context *context, + const void *indices, + GLsizei count, + GLenum type, + const gl::HasIndexRange &lazyIndexRange, + bool usePrimitiveRestartWorkaround) +{ + const auto &glState = context->getGLState(); + gl::VertexArray *vao = glState.getVertexArray(); + VertexArray11 *vao11 = GetImplAs(vao); + + GLenum destElementType = + GetIndexTranslationDestType(type, lazyIndexRange, usePrimitiveRestartWorkaround); + + if (!vao11->updateElementArrayStorage(context, type, destElementType, indices) && + !mIndexBufferIsDirty) + { + // No streaming or index buffer application necessary. + return gl::NoError(); + } + + gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get(); + + TranslatedIndexData *indexInfo = vao11->getCachedIndexInfo(); + ANGLE_TRY(mIndexDataManager.prepareIndexData(context, type, destElementType, count, + elementArrayBuffer, indices, indexInfo)); + + ID3D11Buffer *buffer = nullptr; + DXGI_FORMAT bufferFormat = + (indexInfo->indexType == GL_UNSIGNED_INT) ? DXGI_FORMAT_R32_UINT : DXGI_FORMAT_R16_UINT; + + if (indexInfo->storage) + { + Buffer11 *storage = GetAs(indexInfo->storage); + ANGLE_TRY_RESULT(storage->getBuffer(context, BUFFER_USAGE_INDEX), buffer); + } + else + { + IndexBuffer11 *indexBuffer = GetAs(indexInfo->indexBuffer); + buffer = indexBuffer->getBuffer().get(); + } + + // Track dirty indices in the index range cache. + indexInfo->srcIndexData.srcIndicesChanged = + syncIndexBuffer(buffer, bufferFormat, indexInfo->startOffset); + + mIndexBufferIsDirty = false; + + vao11->setCachedIndexInfoValid(); + return gl::NoError(); +} + +void StateManager11::setIndexBuffer(ID3D11Buffer *buffer, + DXGI_FORMAT indexFormat, + unsigned int offset) +{ + if (syncIndexBuffer(buffer, indexFormat, offset)) + { + mIndexBufferIsDirty = true; + } +} + +bool StateManager11::syncIndexBuffer(ID3D11Buffer *buffer, + DXGI_FORMAT indexFormat, + unsigned int offset) +{ + if (buffer != mAppliedIB || indexFormat != mAppliedIBFormat || offset != mAppliedIBOffset) + { + mRenderer->getDeviceContext()->IASetIndexBuffer(buffer, indexFormat, offset); + + mAppliedIB = buffer; + mAppliedIBFormat = indexFormat; + mAppliedIBOffset = offset; + return true; + } + + return false; +} + +// Vertex buffer is invalidated outside this function. +gl::Error StateManager11::updateVertexOffsetsForPointSpritesEmulation(GLint startVertex, + GLsizei emulatedInstanceId) +{ + return mInputLayoutCache.updateVertexOffsetsForPointSpritesEmulation( + mRenderer, mCurrentAttributes, startVertex, emulatedInstanceId); +} + +gl::Error StateManager11::generateSwizzle(const gl::Context *context, gl::Texture *texture) +{ + if (!texture) + { + return gl::NoError(); + } + + TextureD3D *textureD3D = GetImplAs(texture); + ASSERT(textureD3D); + + TextureStorage *texStorage = nullptr; + ANGLE_TRY(textureD3D->getNativeTexture(context, &texStorage)); + + if (texStorage) + { + TextureStorage11 *storage11 = GetAs(texStorage); + const gl::TextureState &textureState = texture->getTextureState(); + ANGLE_TRY(storage11->generateSwizzles(context, textureState.getSwizzleState())); + } + + return gl::NoError(); +} + +gl::Error StateManager11::generateSwizzlesForShader(const gl::Context *context, + gl::SamplerType type) +{ + const auto &glState = context->getGLState(); + ProgramD3D *programD3D = GetImplAs(glState.getProgram()); + + unsigned int samplerRange = programD3D->getUsedSamplerRange(type); + + for (unsigned int i = 0; i < samplerRange; i++) + { + GLenum textureType = programD3D->getSamplerTextureType(type, i); + GLint textureUnit = programD3D->getSamplerMapping(type, i, context->getCaps()); + if (textureUnit != -1) + { + gl::Texture *texture = glState.getSamplerTexture(textureUnit, textureType); + ASSERT(texture); + if (texture->getTextureState().swizzleRequired()) + { + ANGLE_TRY(generateSwizzle(context, texture)); + } + } + } + + return gl::NoError(); +} + +gl::Error StateManager11::generateSwizzles(const gl::Context *context) +{ + ANGLE_TRY(generateSwizzlesForShader(context, gl::SAMPLER_VERTEX)); + ANGLE_TRY(generateSwizzlesForShader(context, gl::SAMPLER_PIXEL)); + return gl::NoError(); +} + +gl::Error StateManager11::applyUniforms(ProgramD3D *programD3D) +{ + UniformStorage11 *vertexUniformStorage = + GetAs(&programD3D->getVertexUniformStorage()); + UniformStorage11 *fragmentUniformStorage = + GetAs(&programD3D->getFragmentUniformStorage()); + ASSERT(vertexUniformStorage); + ASSERT(fragmentUniformStorage); + + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); + + const d3d11::Buffer *vertexConstantBuffer = nullptr; + ANGLE_TRY(vertexUniformStorage->getConstantBuffer(mRenderer, &vertexConstantBuffer)); + const d3d11::Buffer *pixelConstantBuffer = nullptr; + ANGLE_TRY(fragmentUniformStorage->getConstantBuffer(mRenderer, &pixelConstantBuffer)); + + if (vertexUniformStorage->size() > 0 && programD3D->areVertexUniformsDirty()) + { + UpdateUniformBuffer(deviceContext, vertexUniformStorage, vertexConstantBuffer); + } + + if (fragmentUniformStorage->size() > 0 && programD3D->areFragmentUniformsDirty()) + { + UpdateUniformBuffer(deviceContext, fragmentUniformStorage, pixelConstantBuffer); + } + + unsigned int slot = d3d11::RESERVED_CONSTANT_BUFFER_SLOT_DEFAULT_UNIFORM_BLOCK; + + if (mCurrentConstantBufferVS[slot] != vertexConstantBuffer->getSerial()) + { + deviceContext->VSSetConstantBuffers(slot, 1, vertexConstantBuffer->getPointer()); + mCurrentConstantBufferVS[slot] = vertexConstantBuffer->getSerial(); + mCurrentConstantBufferVSOffset[slot] = 0; + mCurrentConstantBufferVSSize[slot] = 0; + } + + if (mCurrentConstantBufferPS[slot] != pixelConstantBuffer->getSerial()) + { + deviceContext->PSSetConstantBuffers(slot, 1, pixelConstantBuffer->getPointer()); + mCurrentConstantBufferPS[slot] = pixelConstantBuffer->getSerial(); + mCurrentConstantBufferPSOffset[slot] = 0; + mCurrentConstantBufferPSSize[slot] = 0; + } + + programD3D->markUniformsClean(); + + return gl::NoError(); +} + +gl::Error StateManager11::applyDriverUniforms(const ProgramD3D &programD3D) +{ + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); + + if (!mDriverConstantBufferVS.valid()) + { + size_t requiredSize = mShaderConstants.getRequiredBufferSize(gl::SAMPLER_VERTEX); + + D3D11_BUFFER_DESC constantBufferDescription = {0}; + d3d11::InitConstantBufferDesc(&constantBufferDescription, requiredSize); + ANGLE_TRY(mRenderer->allocateResource(constantBufferDescription, &mDriverConstantBufferVS)); + + ID3D11Buffer *driverVSConstants = mDriverConstantBufferVS.get(); + deviceContext->VSSetConstantBuffers(d3d11::RESERVED_CONSTANT_BUFFER_SLOT_DRIVER, 1, + &driverVSConstants); + } + + if (!mDriverConstantBufferPS.valid()) + { + size_t requiredSize = mShaderConstants.getRequiredBufferSize(gl::SAMPLER_PIXEL); + + D3D11_BUFFER_DESC constantBufferDescription = {0}; + d3d11::InitConstantBufferDesc(&constantBufferDescription, requiredSize); + ANGLE_TRY(mRenderer->allocateResource(constantBufferDescription, &mDriverConstantBufferPS)); + + ID3D11Buffer *driverVSConstants = mDriverConstantBufferPS.get(); + deviceContext->PSSetConstantBuffers(d3d11::RESERVED_CONSTANT_BUFFER_SLOT_DRIVER, 1, + &driverVSConstants); + } + + // Sampler metadata and driver constants need to coexist in the same constant buffer to conserve + // constant buffer slots. We update both in the constant buffer if needed. + ANGLE_TRY(mShaderConstants.updateBuffer(deviceContext, gl::SAMPLER_VERTEX, programD3D, + mDriverConstantBufferVS)); + ANGLE_TRY(mShaderConstants.updateBuffer(deviceContext, gl::SAMPLER_PIXEL, programD3D, + mDriverConstantBufferPS)); + + // needed for the point sprite geometry shader + // GSSetConstantBuffers triggers device removal on 9_3, so we should only call it for ES3. + if (mRenderer->isES3Capable()) + { + if (mCurrentGeometryConstantBuffer != mDriverConstantBufferPS.getSerial()) + { + ASSERT(mDriverConstantBufferPS.valid()); + deviceContext->GSSetConstantBuffers(0, 1, mDriverConstantBufferPS.getPointer()); + mCurrentGeometryConstantBuffer = mDriverConstantBufferPS.getSerial(); + } + } + + return gl::NoError(); +} + +gl::Error StateManager11::applyComputeUniforms(ProgramD3D *programD3D) +{ + UniformStorage11 *computeUniformStorage = + GetAs(&programD3D->getComputeUniformStorage()); + ASSERT(computeUniformStorage); + + const d3d11::Buffer *constantBuffer = nullptr; + ANGLE_TRY(computeUniformStorage->getConstantBuffer(mRenderer, &constantBuffer)); + + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); + + if (computeUniformStorage->size() > 0 && programD3D->areComputeUniformsDirty()) + { + UpdateUniformBuffer(deviceContext, computeUniformStorage, constantBuffer); + programD3D->markUniformsClean(); + } + + if (mCurrentComputeConstantBuffer != constantBuffer->getSerial()) + { + deviceContext->CSSetConstantBuffers( + d3d11::RESERVED_CONSTANT_BUFFER_SLOT_DEFAULT_UNIFORM_BLOCK, 1, + constantBuffer->getPointer()); + mCurrentComputeConstantBuffer = constantBuffer->getSerial(); + } + + if (!mDriverConstantBufferCS.valid()) + { + size_t requiredSize = mShaderConstants.getRequiredBufferSize(gl::SAMPLER_COMPUTE); + + D3D11_BUFFER_DESC constantBufferDescription = {0}; + d3d11::InitConstantBufferDesc(&constantBufferDescription, requiredSize); + ANGLE_TRY(mRenderer->allocateResource(constantBufferDescription, &mDriverConstantBufferCS)); + ID3D11Buffer *buffer = mDriverConstantBufferCS.get(); + deviceContext->CSSetConstantBuffers(d3d11::RESERVED_CONSTANT_BUFFER_SLOT_DRIVER, 1, + &buffer); + } + + ANGLE_TRY(mShaderConstants.updateBuffer(deviceContext, gl::SAMPLER_COMPUTE, *programD3D, + mDriverConstantBufferCS)); + + return gl::NoError(); +} + +gl::Error StateManager11::syncUniformBuffers(const gl::Context *context, ProgramD3D *programD3D) +{ + unsigned int reservedVertex = mRenderer->getReservedVertexUniformBuffers(); + unsigned int reservedFragment = mRenderer->getReservedFragmentUniformBuffers(); + + programD3D->updateUniformBufferCache(context->getCaps(), reservedVertex, reservedFragment); + + const auto &vertexUniformBuffers = programD3D->getVertexUniformBufferCache(); + const auto &fragmentUniformBuffers = programD3D->getFragmentUniformBufferCache(); + const auto &glState = context->getGLState(); + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); + ID3D11DeviceContext1 *deviceContext1 = mRenderer->getDeviceContext1IfSupported(); + + for (size_t bufferIndex = 0; bufferIndex < vertexUniformBuffers.size(); bufferIndex++) + { + GLint binding = vertexUniformBuffers[bufferIndex]; + + if (binding == -1) + { + continue; + } + + const auto &uniformBuffer = glState.getIndexedUniformBuffer(binding); + GLintptr uniformBufferOffset = uniformBuffer.getOffset(); + GLsizeiptr uniformBufferSize = uniformBuffer.getSize(); + + if (uniformBuffer.get() == nullptr) + { + continue; + } + + Buffer11 *bufferStorage = GetImplAs(uniformBuffer.get()); + const d3d11::Buffer *constantBuffer = nullptr; + UINT firstConstant = 0; + UINT numConstants = 0; + + ANGLE_TRY(bufferStorage->getConstantBufferRange(context, uniformBufferOffset, + uniformBufferSize, &constantBuffer, + &firstConstant, &numConstants)); + + ASSERT(constantBuffer); + + if (mCurrentConstantBufferVS[bufferIndex] == constantBuffer->getSerial() && + mCurrentConstantBufferVSOffset[bufferIndex] == uniformBufferOffset && + mCurrentConstantBufferVSSize[bufferIndex] == uniformBufferSize) + { + continue; + } + + unsigned int appliedIndex = reservedVertex + static_cast(bufferIndex); + + if (firstConstant != 0 && uniformBufferSize != 0) + { + ASSERT(numConstants != 0); + deviceContext1->VSSetConstantBuffers1(appliedIndex, 1, constantBuffer->getPointer(), + &firstConstant, &numConstants); + } + else + { + deviceContext->VSSetConstantBuffers(appliedIndex, 1, constantBuffer->getPointer()); + } + + mCurrentConstantBufferVS[appliedIndex] = constantBuffer->getSerial(); + mCurrentConstantBufferVSOffset[appliedIndex] = uniformBufferOffset; + mCurrentConstantBufferVSSize[appliedIndex] = uniformBufferSize; + } + + for (size_t bufferIndex = 0; bufferIndex < fragmentUniformBuffers.size(); bufferIndex++) + { + GLint binding = fragmentUniformBuffers[bufferIndex]; + + if (binding == -1) + { + continue; + } + + const auto &uniformBuffer = glState.getIndexedUniformBuffer(binding); + GLintptr uniformBufferOffset = uniformBuffer.getOffset(); + GLsizeiptr uniformBufferSize = uniformBuffer.getSize(); + + if (uniformBuffer.get() == nullptr) + { + continue; + } + + Buffer11 *bufferStorage = GetImplAs(uniformBuffer.get()); + const d3d11::Buffer *constantBuffer = nullptr; + UINT firstConstant = 0; + UINT numConstants = 0; + + ANGLE_TRY(bufferStorage->getConstantBufferRange(context, uniformBufferOffset, + uniformBufferSize, &constantBuffer, + &firstConstant, &numConstants)); + + ASSERT(constantBuffer); + + if (mCurrentConstantBufferPS[bufferIndex] == constantBuffer->getSerial() && + mCurrentConstantBufferPSOffset[bufferIndex] == uniformBufferOffset && + mCurrentConstantBufferPSSize[bufferIndex] == uniformBufferSize) + { + continue; + } + + unsigned int appliedIndex = reservedFragment + static_cast(bufferIndex); + + if (firstConstant != 0 && uniformBufferSize != 0) + { + deviceContext1->PSSetConstantBuffers1(appliedIndex, 1, constantBuffer->getPointer(), + &firstConstant, &numConstants); + } + else + { + deviceContext->PSSetConstantBuffers(appliedIndex, 1, constantBuffer->getPointer()); + } + + mCurrentConstantBufferPS[appliedIndex] = constantBuffer->getSerial(); + mCurrentConstantBufferPSOffset[appliedIndex] = uniformBufferOffset; + mCurrentConstantBufferPSSize[appliedIndex] = uniformBufferSize; + } + + return gl::NoError(); +} + +gl::Error StateManager11::syncTransformFeedbackBuffers(const gl::Context *context) +{ + const auto &glState = context->getGLState(); + + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); + + // If transform feedback is not active, unbind all buffers + if (!glState.isTransformFeedbackActiveUnpaused()) + { + if (mAppliedTFSerial != mEmptySerial) + { + deviceContext->SOSetTargets(0, nullptr, nullptr); + mAppliedTFSerial = mEmptySerial; + } + return gl::NoError(); + } + + gl::TransformFeedback *transformFeedback = glState.getCurrentTransformFeedback(); + TransformFeedback11 *tf11 = GetImplAs(transformFeedback); + if (mAppliedTFSerial == tf11->getSerial() && !tf11->isDirty()) + { + return gl::NoError(); + } + + const std::vector *soBuffers = nullptr; + ANGLE_TRY_RESULT(tf11->getSOBuffers(context), soBuffers); + const std::vector &soOffsets = tf11->getSOBufferOffsets(); + + deviceContext->SOSetTargets(tf11->getNumSOBuffers(), soBuffers->data(), soOffsets.data()); + + mAppliedTFSerial = tf11->getSerial(); + tf11->onApply(); + + return gl::NoError(); +} + +// DrawCallVertexParams implementation. +DrawCallVertexParams::DrawCallVertexParams(GLint firstVertex, + GLsizei vertexCount, + GLsizei instances) + : mHasIndexRange(nullptr), + mFirstVertex(firstVertex), + mVertexCount(vertexCount), + mInstances(instances), + mBaseVertex(0) +{ +} + +// Use when in a drawElements call. +DrawCallVertexParams::DrawCallVertexParams(bool firstVertexDefinitelyZero, + const gl::HasIndexRange &hasIndexRange, + GLint baseVertex, + GLsizei instances) + : mHasIndexRange(&hasIndexRange), + mFirstVertex(), + mVertexCount(0), + mInstances(instances), + mBaseVertex(baseVertex) +{ + if (firstVertexDefinitelyZero) + { + mFirstVertex = baseVertex; + } +} + +GLint DrawCallVertexParams::firstVertex() const +{ + if (!mFirstVertex.valid()) + { + ensureResolved(); + ASSERT(mFirstVertex.valid()); + } + return mFirstVertex.value(); +} + +GLsizei DrawCallVertexParams::vertexCount() const +{ + ensureResolved(); + return mVertexCount; +} + +GLsizei DrawCallVertexParams::instances() const +{ + return mInstances; +} + +void DrawCallVertexParams::ensureResolved() const +{ + if (mHasIndexRange) + { + ASSERT(!mFirstVertex.valid() || mFirstVertex == mBaseVertex); + + // Resolve the index range now if we need to. + const auto &indexRange = mHasIndexRange->getIndexRange().value(); + mFirstVertex = mBaseVertex + static_cast(indexRange.start); + mVertexCount = static_cast(indexRange.vertexCount()); + mHasIndexRange = nullptr; + } } } // namespace rx diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/StateManager11.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/StateManager11.h index f900882d7e..e48bc83a22 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/StateManager11.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/StateManager11.h @@ -11,12 +11,15 @@ #include -#include "libANGLE/angletypes.h" -#include "libANGLE/Data.h" +#include "libANGLE/ContextState.h" #include "libANGLE/State.h" +#include "libANGLE/angletypes.h" +#include "libANGLE/renderer/d3d/IndexDataManager.h" +#include "libANGLE/renderer/d3d/RendererD3D.h" +#include "libANGLE/renderer/d3d/d3d11/InputLayoutCache.h" +#include "libANGLE/renderer/d3d/d3d11/Query11.h" #include "libANGLE/renderer/d3d/d3d11/RenderStateCache.h" #include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h" -#include "libANGLE/renderer/d3d/RendererD3D.h" namespace rx { @@ -24,20 +27,147 @@ namespace rx struct RenderTargetDesc; struct Renderer11DeviceCaps; -struct dx_VertexConstants11 +class ShaderConstants11 : angle::NonCopyable { - float depthRange[4]; - float viewAdjust[4]; - float viewCoords[4]; - float viewScale[4]; + public: + ShaderConstants11(); + ~ShaderConstants11(); + + void init(const gl::Caps &caps); + size_t getRequiredBufferSize(gl::SamplerType samplerType) const; + void markDirty(); + + void setComputeWorkGroups(GLuint numGroupsX, GLuint numGroupsY, GLuint numGroupsZ); + void setMultiviewWriteToViewportIndex(GLfloat index); + void onViewportChange(const gl::Rectangle &glViewport, + const D3D11_VIEWPORT &dxViewport, + bool is9_3, + bool presentPathFast); + void onSamplerChange(gl::SamplerType samplerType, + unsigned int samplerIndex, + const gl::Texture &texture); + + gl::Error updateBuffer(ID3D11DeviceContext *deviceContext, + gl::SamplerType samplerType, + const ProgramD3D &programD3D, + const d3d11::Buffer &driverConstantBuffer); + + private: + struct Vertex + { + Vertex() + : depthRange{.0f}, + viewAdjust{.0f}, + viewCoords{.0f}, + viewScale{.0f}, + multiviewWriteToViewportIndex{.0f}, + padding{.0f} + { + } + + float depthRange[4]; + float viewAdjust[4]; + float viewCoords[4]; + float viewScale[2]; + // multiviewWriteToViewportIndex is used to select either the side-by-side or layered + // code-path in the GS. It's value, if set, is either 0.0f or 1.0f. The value is updated + // whenever a multi-view draw framebuffer is made active. + float multiviewWriteToViewportIndex; + + // Added here to manually pad the struct. + float padding; + }; + + struct Pixel + { + Pixel() + : depthRange{.0f}, + viewCoords{.0f}, + depthFront{.0f}, + viewScale{.0f}, + multiviewWriteToViewportIndex(0), + padding(0) + { + } + + float depthRange[4]; + float viewCoords[4]; + float depthFront[4]; + float viewScale[2]; + // multiviewWriteToViewportIndex is used to select either the side-by-side or layered + // code-path in the GS. It's value, if set, is either 0.0f or 1.0f. The value is updated + // whenever a multi-view draw framebuffer is made active. + float multiviewWriteToViewportIndex; + + // Added here to manually pad the struct. + float padding; + }; + + struct Compute + { + Compute() : numWorkGroups{0u}, padding(0u) {} + unsigned int numWorkGroups[3]; + unsigned int padding; // This just pads the struct to 16 bytes + }; + + struct SamplerMetadata + { + SamplerMetadata() : baseLevel(0), internalFormatBits(0), wrapModes(0), padding(0) {} + + int baseLevel; + int internalFormatBits; + int wrapModes; + int padding; // This just pads the struct to 16 bytes + }; + + static_assert(sizeof(SamplerMetadata) == 16u, + "Sampler metadata struct must be one 4-vec / 16 bytes."); + + // Return true if dirty. + bool updateSamplerMetadata(SamplerMetadata *data, const gl::Texture &texture); + + Vertex mVertex; + bool mVertexDirty; + Pixel mPixel; + bool mPixelDirty; + Compute mCompute; + bool mComputeDirty; + + std::vector mSamplerMetadataVS; + bool mSamplerMetadataVSDirty; + std::vector mSamplerMetadataPS; + bool mSamplerMetadataPSDirty; + std::vector mSamplerMetadataCS; + bool mSamplerMetadataCSDirty; }; -struct dx_PixelConstants11 +class DrawCallVertexParams final : angle::NonCopyable { - float depthRange[4]; - float viewCoords[4]; - float depthFront[4]; - float viewScale[4]; + public: + // Use when in a drawArrays call. + DrawCallVertexParams(GLint firstVertex, GLsizei vertexCount, GLsizei instances); + + // Use when in a drawElements call. + DrawCallVertexParams(bool firstVertexDefinitelyZero, + const gl::HasIndexRange &hasIndexRange, + GLint baseVertex, + GLsizei instances); + + // It should be possible to also use an overload to handle the 'slow' indirect draw path. + // TODO(jmadill): Indirect draw slow path overload. + + GLint firstVertex() const; + GLsizei vertexCount() const; + GLsizei instances() const; + + private: + void ensureResolved() const; + + mutable const gl::HasIndexRange *mHasIndexRange; + mutable Optional mFirstVertex; + mutable GLsizei mVertexCount; + GLsizei mInstances; + GLint mBaseVertex; }; class StateManager11 final : angle::NonCopyable @@ -46,62 +176,221 @@ class StateManager11 final : angle::NonCopyable StateManager11(Renderer11 *renderer); ~StateManager11(); - void initialize(const gl::Caps &caps); - void syncState(const gl::State &state, const gl::State::DirtyBits &dirtyBits); + gl::Error initialize(const gl::Caps &caps, const gl::Extensions &extensions); + void deinitialize(); - gl::Error setBlendState(const gl::Framebuffer *framebuffer, - const gl::BlendState &blendState, - const gl::ColorF &blendColor, - unsigned int sampleMask); + void syncState(const gl::Context *context, const gl::State::DirtyBits &dirtyBits); - gl::Error setDepthStencilState(const gl::State &glState); + gl::Error updateStateForCompute(const gl::Context *context, + GLuint numGroupsX, + GLuint numGroupsY, + GLuint numGroupsZ); - gl::Error setRasterizerState(const gl::RasterizerState &rasterState); + void updateStencilSizeIfChanged(bool depthStencilInitialized, unsigned int stencilSize); - void setScissorRectangle(const gl::Rectangle &scissor, bool enabled); + // These invalidations methods are called externally. - void setViewport(const gl::Caps *caps, const gl::Rectangle &viewport, float zNear, float zFar); + // Called from TextureStorage11. + void invalidateBoundViews(); - void updatePresentPath(bool presentPathFastActive, - const gl::FramebufferAttachment *framebufferAttachment); + // Called from VertexArray11::updateVertexAttribStorage. + void invalidateCurrentValueAttrib(size_t attribIndex); - const dx_VertexConstants11 &getVertexConstants() const { return mVertexConstants; } - const dx_PixelConstants11 &getPixelConstants() const { return mPixelConstants; } + // Checks are done on a framebuffer state change to trigger other state changes. + // The Context is allowed to be nullptr for these methods, when called in EGL init code. + void invalidateRenderTarget(); - void updateStencilSizeIfChanged(bool depthStencilInitialized, unsigned int stencilSize); + // Called by instanced point sprite emulation. + void invalidateVertexBuffer(); + + // Called by Framebuffer11::syncState for the default sized viewport. + void invalidateViewport(const gl::Context *context); + + // Called by TextureStorage11::markLevelDirty. + void invalidateSwizzles(); + + // Called by the Framebuffer11 and VertexArray11. + void invalidateShaders(); + // Called by VertexArray11 to trigger attribute translation. + void invalidateVertexAttributeTranslation(); + + void setRenderTarget(ID3D11RenderTargetView *rtv, ID3D11DepthStencilView *dsv); + void setRenderTargets(ID3D11RenderTargetView **rtvs, UINT numRtvs, ID3D11DepthStencilView *dsv); + + void onBeginQuery(Query11 *query); + void onDeleteQueryObject(Query11 *query); + gl::Error onMakeCurrent(const gl::Context *context); + + void setInputLayout(const d3d11::InputLayout *inputLayout); + + // TODO(jmadill): Migrate to d3d11::Buffer. + bool queueVertexBufferChange(size_t bufferIndex, + ID3D11Buffer *buffer, + UINT stride, + UINT offset); + bool queueVertexOffsetChange(size_t bufferIndex, UINT offsetOnly); + void applyVertexBufferChanges(); + + void setSingleVertexBuffer(const d3d11::Buffer *buffer, UINT stride, UINT offset); + + gl::Error updateState(const gl::Context *context, GLenum drawMode); + + void setShaderResourceShared(gl::SamplerType shaderType, + UINT resourceSlot, + const d3d11::SharedSRV *srv); void setShaderResource(gl::SamplerType shaderType, UINT resourceSlot, - ID3D11ShaderResourceView *srv); + const d3d11::ShaderResourceView *srv); + void setPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY primitiveTopology); + + void setDrawShaders(const d3d11::VertexShader *vertexShader, + const d3d11::GeometryShader *geometryShader, + const d3d11::PixelShader *pixelShader); + void setVertexShader(const d3d11::VertexShader *shader); + void setGeometryShader(const d3d11::GeometryShader *shader); + void setPixelShader(const d3d11::PixelShader *shader); + void setComputeShader(const d3d11::ComputeShader *shader); + void setVertexConstantBuffer(unsigned int slot, const d3d11::Buffer *buffer); + void setPixelConstantBuffer(unsigned int slot, const d3d11::Buffer *buffer); + void setDepthStencilState(const d3d11::DepthStencilState *depthStencilState, UINT stencilRef); + void setSimpleBlendState(const d3d11::BlendState *blendState); + void setRasterizerState(const d3d11::RasterizerState *rasterizerState); + void setSimpleViewport(const gl::Extents &viewportExtents); + void setSimpleViewport(int width, int height); + void setSimplePixelTextureAndSampler(const d3d11::SharedSRV &srv, + const d3d11::SamplerState &samplerState); + void setSimpleScissorRect(const gl::Rectangle &glRect); + void setScissorRectD3D(const D3D11_RECT &d3dRect); + + // Not handled by an internal dirty bit because of the extra draw parameters. + gl::Error applyVertexBuffer(const gl::Context *context, + GLenum mode, + const DrawCallVertexParams &vertexParams, + bool isIndexedRendering); + + gl::Error applyIndexBuffer(const gl::Context *context, + const void *indices, + GLsizei count, + GLenum type, + const gl::HasIndexRange &lazyIndexRange, + bool usePrimitiveRestartWorkaround); + + void setIndexBuffer(ID3D11Buffer *buffer, DXGI_FORMAT indexFormat, unsigned int offset); + + gl::Error updateVertexOffsetsForPointSpritesEmulation(GLint startVertex, + GLsizei emulatedInstanceId); + + // TODO(jmadill): Should be private. + gl::Error applyComputeUniforms(ProgramD3D *programD3D); + + // Only used in testing. + InputLayoutCache *getInputLayoutCache() { return &mInputLayoutCache; } + + private: + template + void setShaderResourceInternal(gl::SamplerType shaderType, + UINT resourceSlot, + const SRVType *srv); + + bool unsetConflictingView(ID3D11View *view); + bool unsetConflictingSRVs(gl::SamplerType shaderType, + uintptr_t resource, + const gl::ImageIndex *index); + void unsetConflictingAttachmentResources(const gl::FramebufferAttachment *attachment, + ID3D11Resource *resource); + + gl::Error syncBlendState(const gl::Context *context, + const gl::Framebuffer *framebuffer, + const gl::BlendState &blendState, + const gl::ColorF &blendColor, + unsigned int sampleMask); + + gl::Error syncDepthStencilState(const gl::State &glState); + + gl::Error syncRasterizerState(const gl::Context *context, bool pointDrawMode); + + void syncScissorRectangle(const gl::Rectangle &scissor, bool enabled); + + void syncViewport(const gl::Context *context); + + void checkPresentPath(const gl::Context *context); + + gl::Error syncFramebuffer(const gl::Context *context, gl::Framebuffer *framebuffer); + gl::Error syncProgram(const gl::Context *context, GLenum drawMode); + + gl::Error syncTextures(const gl::Context *context); + gl::Error applyTextures(const gl::Context *context, gl::SamplerType shaderType); + + gl::Error setSamplerState(const gl::Context *context, + gl::SamplerType type, + int index, + gl::Texture *texture, + const gl::SamplerState &sampler); + gl::Error setTexture(const gl::Context *context, + gl::SamplerType type, + int index, + gl::Texture *texture); + + // Faster than calling setTexture a jillion times gl::Error clearTextures(gl::SamplerType samplerType, size_t rangeStart, size_t rangeEnd); + void handleMultiviewDrawFramebufferChange(const gl::Context *context); - gl::Error syncFramebuffer(const gl::Framebuffer *framebuffer); + gl::Error syncCurrentValueAttribs(const gl::State &glState); - void invalidateRenderTarget(); - void invalidateEverything(); - bool setRenderTargets(const RenderTargetArray &renderTargets, - ID3D11DepthStencilView *depthStencil); - void setRenderTarget(ID3D11RenderTargetView *renderTarget, - ID3D11DepthStencilView *depthStencil); + gl::Error generateSwizzle(const gl::Context *context, gl::Texture *texture); + gl::Error generateSwizzlesForShader(const gl::Context *context, gl::SamplerType type); + gl::Error generateSwizzles(const gl::Context *context); - private: - void unsetConflictingSRVs(gl::SamplerType shaderType, - uintptr_t resource, - const gl::ImageIndex &index); - void setViewportBounds(const int width, const int height); + gl::Error applyDriverUniforms(const ProgramD3D &programD3D); + gl::Error applyUniforms(ProgramD3D *programD3D); + + gl::Error syncUniformBuffers(const gl::Context *context, ProgramD3D *programD3D); + gl::Error syncTransformFeedbackBuffers(const gl::Context *context); + + // These are currently only called internally. + void invalidateTexturesAndSamplers(); + void invalidateDriverUniforms(); + void invalidateProgramUniforms(); + void invalidateProgramUniformBuffers(); + void invalidateConstantBuffer(unsigned int slot); + + // Called by the Framebuffer11 directly. + void processFramebufferInvalidation(const gl::Context *context); + + bool syncIndexBuffer(ID3D11Buffer *buffer, DXGI_FORMAT indexFormat, unsigned int offset); + + enum DirtyBitType + { + DIRTY_BIT_RENDER_TARGET, + DIRTY_BIT_VIEWPORT_STATE, + DIRTY_BIT_SCISSOR_STATE, + DIRTY_BIT_RASTERIZER_STATE, + DIRTY_BIT_BLEND_STATE, + DIRTY_BIT_DEPTH_STENCIL_STATE, + DIRTY_BIT_TEXTURE_AND_SAMPLER_STATE, + DIRTY_BIT_PROGRAM_UNIFORMS, + DIRTY_BIT_DRIVER_UNIFORMS, + DIRTY_BIT_PROGRAM_UNIFORM_BUFFERS, + DIRTY_BIT_SHADERS, + DIRTY_BIT_CURRENT_VALUE_ATTRIBS, + DIRTY_BIT_INVALID, + DIRTY_BIT_MAX = DIRTY_BIT_INVALID, + }; + + using DirtyBits = angle::BitSet; Renderer11 *mRenderer; + // Internal dirty bits. + DirtyBits mInternalDirtyBits; + // Blend State - bool mBlendStateIsDirty; - // TODO(dianx) temporary representation of a dirty bit. once we move enough states in, - // try experimenting with dirty bit instead of a bool gl::BlendState mCurBlendState; gl::ColorF mCurBlendColor; unsigned int mCurSampleMask; // Currently applied depth stencil state - bool mDepthStencilStateIsDirty; gl::DepthStencilState mCurDepthStencilState; int mCurStencilRef; int mCurStencilBackRef; @@ -110,34 +399,35 @@ class StateManager11 final : angle::NonCopyable Optional mCurDisableStencil; // Currently applied rasterizer state - bool mRasterizerStateIsDirty; gl::RasterizerState mCurRasterState; // Currently applied scissor rectangle state - bool mScissorStateIsDirty; bool mCurScissorEnabled; gl::Rectangle mCurScissorRect; // Currently applied viewport state - bool mViewportStateIsDirty; gl::Rectangle mCurViewport; float mCurNear; float mCurFar; + // The viewport offsets are guaranteed to be updated whenever the gl::State::DirtyBits are + // resolved and can be applied to the viewport and scissor whenever the internal viewport and + // scissor bits are resolved. + std::vector mViewportOffsets; + // Things needed in viewport state - dx_VertexConstants11 mVertexConstants; - dx_PixelConstants11 mPixelConstants; + ShaderConstants11 mShaderConstants; // Render target variables gl::Extents mViewportBounds; + bool mRenderTargetIsDirty; // EGL_ANGLE_experimental_present_path variables bool mCurPresentPathFastEnabled; int mCurPresentPathFastColorBufferHeight; - // Current RenderTarget state - std::array mAppliedRTVs; - uintptr_t mAppliedDSV; + // Queries that are currently active in this state + std::set mCurrentQueries; // Currently applied textures struct SRVRecord @@ -154,7 +444,8 @@ class StateManager11 final : angle::NonCopyable class SRVCache : angle::NonCopyable { public: - SRVCache() : mHighestUsedSRV(0) {} + SRVCache(); + ~SRVCache(); void initialize(size_t size) { mCurrentSRVs.resize(size); } @@ -175,6 +466,91 @@ class StateManager11 final : angle::NonCopyable // A block of NULL pointers, cached so we don't re-allocate every draw call std::vector mNullSRVs; + + // Current translations of "Current-Value" data - owned by Context, not VertexArray. + gl::AttributesMask mDirtyCurrentValueAttribs; + std::vector mCurrentValueAttribs; + + // Current applied input layout. + ResourceSerial mCurrentInputLayout; + bool mInputLayoutIsDirty; + bool mVertexAttribsNeedTranslation; + + // Current applied vertex states. + // TODO(jmadill): Figure out how to use ResourceSerial here. + std::array mCurrentVertexBuffers; + std::array mCurrentVertexStrides; + std::array mCurrentVertexOffsets; + gl::RangeUI mDirtyVertexBufferRange; + + // Currently applied primitive topology + D3D11_PRIMITIVE_TOPOLOGY mCurrentPrimitiveTopology; + + // Currently applied shaders + ResourceSerial mAppliedVertexShader; + ResourceSerial mAppliedGeometryShader; + ResourceSerial mAppliedPixelShader; + ResourceSerial mAppliedComputeShader; + + // Currently applied sampler states + std::vector mForceSetVertexSamplerStates; + std::vector mCurVertexSamplerStates; + + std::vector mForceSetPixelSamplerStates; + std::vector mCurPixelSamplerStates; + + std::vector mForceSetComputeSamplerStates; + std::vector mCurComputeSamplerStates; + + // Special dirty bit for swizzles. Since they use internal shaders, must be done in a pre-pass. + bool mDirtySwizzles; + + // Currently applied index buffer + ID3D11Buffer *mAppliedIB; + DXGI_FORMAT mAppliedIBFormat; + unsigned int mAppliedIBOffset; + bool mIndexBufferIsDirty; + + // Vertex, index and input layouts + VertexDataManager mVertexDataManager; + IndexDataManager mIndexDataManager; + InputLayoutCache mInputLayoutCache; + std::vector mCurrentAttributes; + Optional mLastFirstVertex; + + // ANGLE_multiview. + bool mIsMultiviewEnabled; + + // Driver Constants. + d3d11::Buffer mDriverConstantBufferVS; + d3d11::Buffer mDriverConstantBufferPS; + d3d11::Buffer mDriverConstantBufferCS; + + ResourceSerial mCurrentComputeConstantBuffer; + ResourceSerial mCurrentGeometryConstantBuffer; + + template + using VertexConstantBufferArray = + std::array; + + VertexConstantBufferArray mCurrentConstantBufferVS; + VertexConstantBufferArray mCurrentConstantBufferVSOffset; + VertexConstantBufferArray mCurrentConstantBufferVSSize; + + template + using FragmentConstantBufferArray = + std::array; + + FragmentConstantBufferArray mCurrentConstantBufferPS; + FragmentConstantBufferArray mCurrentConstantBufferPSOffset; + FragmentConstantBufferArray mCurrentConstantBufferPSSize; + + // Currently applied transform feedback buffers + Serial mAppliedTFSerial; + + Serial mEmptySerial; + + bool mIsTransformFeedbackCurrentlyActiveUnpaused; }; } // namespace rx diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/StreamProducerNV12.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/StreamProducerNV12.cpp new file mode 100644 index 0000000000..1981b5f7b2 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/StreamProducerNV12.cpp @@ -0,0 +1,102 @@ +// +// Copyright (c) 2016 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. +// + +// StreamProducerNV12.cpp: Implements the stream producer for NV12 textures + +#include "libANGLE/renderer/d3d/d3d11/StreamProducerNV12.h" + +#include "common/utilities.h" +#include "libANGLE/renderer/d3d/d3d11/Renderer11.h" +#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h" + +namespace rx +{ + +StreamProducerNV12::StreamProducerNV12(Renderer11 *renderer) + : mRenderer(renderer), mTexture(nullptr), mArraySlice(0), mTextureWidth(0), mTextureHeight(0) +{ +} + +StreamProducerNV12::~StreamProducerNV12() +{ + SafeRelease(mTexture); +} + +egl::Error StreamProducerNV12::validateD3DNV12Texture(void *pointer) const +{ + ID3D11Texture2D *textureD3D = static_cast(pointer); + + // Check that the texture originated from our device + ID3D11Device *device; + textureD3D->GetDevice(&device); + if (device != mRenderer->getDevice()) + { + return egl::EglBadParameter() << "Texture not created on ANGLE D3D device"; + } + + // Get the description and validate it + D3D11_TEXTURE2D_DESC desc; + textureD3D->GetDesc(&desc); + if (desc.Format != DXGI_FORMAT_NV12) + { + return egl::EglBadParameter() << "Texture format not DXGI_FORMAT_NV12"; + } + if (desc.Width < 1 || desc.Height < 1) + { + return egl::EglBadParameter() << "Texture is of size 0"; + } + if ((desc.Width % 2) != 0 || (desc.Height % 2) != 0) + { + return egl::EglBadParameter() << "Texture dimensions are not even"; + } + return egl::NoError(); +} + +void StreamProducerNV12::postD3DNV12Texture(void *pointer, const egl::AttributeMap &attributes) +{ + ASSERT(pointer != nullptr); + ID3D11Texture2D *textureD3D = static_cast(pointer); + + // Check that the texture originated from our device + ID3D11Device *device; + textureD3D->GetDevice(&device); + + // Get the description + D3D11_TEXTURE2D_DESC desc; + textureD3D->GetDesc(&desc); + + // Release the previous texture if there is one + SafeRelease(mTexture); + + mTexture = textureD3D; + mTexture->AddRef(); + mTextureWidth = desc.Width; + mTextureHeight = desc.Height; + mArraySlice = static_cast(attributes.get(EGL_D3D_TEXTURE_SUBRESOURCE_ID_ANGLE, 0)); +} + +egl::Stream::GLTextureDescription StreamProducerNV12::getGLFrameDescription(int planeIndex) +{ + // The UV plane of NV12 textures has half the width/height of the Y plane + egl::Stream::GLTextureDescription desc; + desc.width = (planeIndex == 0) ? mTextureWidth : (mTextureWidth / 2); + desc.height = (planeIndex == 0) ? mTextureHeight : (mTextureHeight / 2); + desc.internalFormat = (planeIndex == 0) ? GL_R8 : GL_RG8; + desc.mipLevels = 0; + return desc; +} + +ID3D11Texture2D *StreamProducerNV12::getD3DTexture() +{ + return mTexture; +} + +UINT StreamProducerNV12::getArraySlice() +{ + return mArraySlice; +} + +} // namespace rx diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/StreamProducerNV12.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/StreamProducerNV12.h new file mode 100644 index 0000000000..304c9dfe53 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/StreamProducerNV12.h @@ -0,0 +1,44 @@ +// +// Copyright (c) 2016 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. +// + +// StreamProducerNV12.h: Interface for a NV12 texture stream producer + +#ifndef LIBANGLE_RENDERER_D3D_D3D11_STREAM11_H_ +#define LIBANGLE_RENDERER_D3D_D3D11_STREAM11_H_ + +#include "libANGLE/renderer/StreamProducerImpl.h" + +namespace rx +{ +class Renderer11; + +class StreamProducerNV12 : public StreamProducerImpl +{ + public: + StreamProducerNV12(Renderer11 *renderer); + ~StreamProducerNV12() override; + + egl::Error validateD3DNV12Texture(void *pointer) const override; + void postD3DNV12Texture(void *pointer, const egl::AttributeMap &attributes) override; + egl::Stream::GLTextureDescription getGLFrameDescription(int planeIndex) override; + + // Gets a pointer to the internal D3D texture + ID3D11Texture2D *getD3DTexture(); + + // Gets the slice index for the D3D texture that the frame is in + UINT getArraySlice(); + + private: + Renderer11 *mRenderer; + + ID3D11Texture2D *mTexture; + UINT mArraySlice; + UINT mTextureWidth; + UINT mTextureHeight; +}; +} // namespace rx + +#endif // LIBANGLE_RENDERER_D3D_D3D11_STREAM11_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 index 42c336c8cf..dcfd06484d 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/SwapChain11.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/SwapChain11.cpp @@ -11,9 +11,9 @@ #include #include "libANGLE/features.h" -#include "libANGLE/renderer/d3d/d3d11/formatutils11.h" -#include "libANGLE/renderer/d3d/d3d11/NativeWindow.h" +#include "libANGLE/renderer/d3d/d3d11/NativeWindow11.h" #include "libANGLE/renderer/d3d/d3d11/Renderer11.h" +#include "libANGLE/renderer/d3d/d3d11/formatutils11.h" #include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h" #include "libANGLE/renderer/d3d/d3d11/texture_format_table.h" #include "third_party/trace_event/trace_event.h" @@ -21,6 +21,7 @@ // Precompiled shaders #include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthrough2d11vs.h" #include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrgba2d11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrgba2dms11ps.h" #ifdef ANGLE_ENABLE_KEYEDMUTEX #define ANGLE_RESOURCE_SHARE_TYPE D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX @@ -33,22 +34,30 @@ namespace rx namespace { -bool NeedsOffscreenTexture(Renderer11 *renderer, NativeWindow nativeWindow, EGLint orientation) +// To avoid overflow in QPC to Microseconds calculations, since we multiply +// by kMicrosecondsPerSecond, then the QPC value should not exceed +// (2^63 - 1) / 1E6. If it exceeds that threshold, we divide then multiply. +static constexpr int64_t kQPCOverflowThreshold = 0x8637BD05AF7; +static constexpr int64_t kMicrosecondsPerSecond = 1000000; + +bool NeedsOffscreenTexture(Renderer11 *renderer, NativeWindow11 *nativeWindow, EGLint orientation) { // We don't need an offscreen texture if either orientation = INVERT_Y, // or present path fast is enabled and we're not rendering onto an offscreen surface. return orientation != EGL_SURFACE_ORIENTATION_INVERT_Y_ANGLE && - !(renderer->presentPathFastEnabled() && nativeWindow.getNativeWindow()); + !(renderer->presentPathFastEnabled() && nativeWindow->getNativeWindow()); } } // anonymous namespace SwapChain11::SwapChain11(Renderer11 *renderer, - NativeWindow nativeWindow, + NativeWindow11 *nativeWindow, HANDLE shareHandle, + IUnknown *d3dTexture, GLenum backBufferFormat, GLenum depthBufferFormat, - EGLint orientation) - : SwapChainD3D(nativeWindow, shareHandle, backBufferFormat, depthBufferFormat), + EGLint orientation, + EGLint samples) + : SwapChainD3D(shareHandle, d3dTexture, backBufferFormat, depthBufferFormat), mRenderer(renderer), mWidth(-1), mHeight(-1), @@ -56,33 +65,42 @@ SwapChain11::SwapChain11(Renderer11 *renderer, mAppCreatedShareHandle(mShareHandle != nullptr), mSwapInterval(0), mPassThroughResourcesInit(false), + mNativeWindow(nativeWindow), mFirstSwap(true), mSwapChain(nullptr), -#if defined(ANGLE_ENABLE_D3D11_1) mSwapChain1(nullptr), -#endif mKeyedMutex(nullptr), - mBackBufferTexture(nullptr), - mBackBufferRTView(nullptr), - mBackBufferSRView(nullptr), + mBackBufferTexture(), + mBackBufferRTView(), + mBackBufferSRView(), mNeedsOffscreenTexture(NeedsOffscreenTexture(renderer, nativeWindow, orientation)), - mOffscreenTexture(nullptr), - mOffscreenRTView(nullptr), - mOffscreenSRView(nullptr), - mDepthStencilTexture(nullptr), - mDepthStencilDSView(nullptr), - mDepthStencilSRView(nullptr), - mQuadVB(nullptr), - mPassThroughSampler(nullptr), - mPassThroughIL(nullptr), - mPassThroughVS(nullptr), - mPassThroughPS(nullptr), - mPassThroughRS(nullptr), + mOffscreenTexture(), + mOffscreenRTView(), + mOffscreenSRView(), + mNeedsOffscreenTextureCopy(false), + mOffscreenTextureCopyForSRV(), + mDepthStencilTexture(), + mDepthStencilDSView(), + mDepthStencilSRView(), + mQuadVB(), + mPassThroughSampler(), + mPassThroughIL(), + mPassThroughVS(), + mPassThroughPS(), + mPassThroughRS(), mColorRenderTarget(this, renderer, false), - mDepthStencilRenderTarget(this, renderer, true) + mDepthStencilRenderTarget(this, renderer, true), + mEGLSamples(samples) { // Sanity check that if present path fast is active then we're using the default orientation ASSERT(!mRenderer->presentPathFastEnabled() || orientation == 0); + + // Get the performance counter + LARGE_INTEGER counterFreqency = {}; + BOOL success = QueryPerformanceFrequency(&counterFreqency); + ASSERT(success); + + mQPCFrequency = counterFreqency.QuadPart; } SwapChain11::~SwapChain11() @@ -92,52 +110,56 @@ SwapChain11::~SwapChain11() void SwapChain11::release() { -#if defined(ANGLE_ENABLE_D3D11_1) + // TODO(jmadill): Should probably signal that the RenderTarget is dirty. + SafeRelease(mSwapChain1); -#endif SafeRelease(mSwapChain); SafeRelease(mKeyedMutex); - SafeRelease(mBackBufferTexture); - SafeRelease(mBackBufferRTView); - SafeRelease(mBackBufferSRView); - SafeRelease(mOffscreenTexture); - SafeRelease(mOffscreenRTView); - SafeRelease(mOffscreenSRView); - SafeRelease(mDepthStencilTexture); - SafeRelease(mDepthStencilDSView); - SafeRelease(mDepthStencilSRView); - SafeRelease(mQuadVB); - SafeRelease(mPassThroughSampler); - SafeRelease(mPassThroughIL); - SafeRelease(mPassThroughVS); - SafeRelease(mPassThroughPS); - SafeRelease(mPassThroughRS); + mBackBufferTexture.reset(); + mBackBufferRTView.reset(); + mBackBufferSRView.reset(); + mOffscreenTexture.reset(); + mOffscreenRTView.reset(); + mOffscreenSRView.reset(); + mDepthStencilTexture.reset(); + mDepthStencilDSView.reset(); + mDepthStencilSRView.reset(); + mQuadVB.reset(); + mPassThroughSampler.reset(); + mPassThroughIL.reset(); + mPassThroughVS.reset(); + mPassThroughPS.reset(); + mPassThroughRS.reset(); if (!mAppCreatedShareHandle) { - mShareHandle = NULL; + mShareHandle = nullptr; } } void SwapChain11::releaseOffscreenColorBuffer() { - SafeRelease(mOffscreenTexture); - SafeRelease(mOffscreenRTView); - SafeRelease(mOffscreenSRView); + mOffscreenTexture.reset(); + mOffscreenRTView.reset(); + mOffscreenSRView.reset(); + mNeedsOffscreenTextureCopy = false; + mOffscreenTextureCopyForSRV.reset(); } void SwapChain11::releaseOffscreenDepthBuffer() { - SafeRelease(mDepthStencilTexture); - SafeRelease(mDepthStencilDSView); - SafeRelease(mDepthStencilSRView); + mDepthStencilTexture.reset(); + mDepthStencilDSView.reset(); + mDepthStencilSRView.reset(); } -EGLint SwapChain11::resetOffscreenBuffers(int backbufferWidth, int backbufferHeight) +EGLint SwapChain11::resetOffscreenBuffers(const gl::Context *context, + int backbufferWidth, + int backbufferHeight) { if (mNeedsOffscreenTexture) { - EGLint result = resetOffscreenColorBuffer(backbufferWidth, backbufferHeight); + EGLint result = resetOffscreenColorBuffer(context, backbufferWidth, backbufferHeight); if (result != EGL_SUCCESS) { return result; @@ -156,117 +178,106 @@ EGLint SwapChain11::resetOffscreenBuffers(int backbufferWidth, int backbufferHei return EGL_SUCCESS; } -EGLint SwapChain11::resetOffscreenColorBuffer(int backbufferWidth, int backbufferHeight) +EGLint SwapChain11::resetOffscreenColorBuffer(const gl::Context *context, + int backbufferWidth, + int backbufferHeight) { ASSERT(mNeedsOffscreenTexture); TRACE_EVENT0("gpu.angle", "SwapChain11::resetOffscreenTexture"); ID3D11Device *device = mRenderer->getDevice(); - ASSERT(device != NULL); + ASSERT(device != nullptr); // 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(); - } + TextureHelper11 previousOffscreenTexture(std::move(mOffscreenTexture)); const int previousWidth = mWidth; const int previousHeight = mHeight; releaseOffscreenColorBuffer(); - const d3d11::TextureFormat &backbufferFormatInfo = d3d11::GetTextureFormatInfo(mOffscreenRenderTargetFormat, mRenderer->getRenderer11DeviceCaps()); + const d3d11::Format &backbufferFormatInfo = + d3d11::Format::Get(mOffscreenRenderTargetFormat, mRenderer->getRenderer11DeviceCaps()); + D3D11_TEXTURE2D_DESC offscreenTextureDesc = {0}; - // If the app passed in a share handle, open the resource - // See EGL_ANGLE_d3d_share_handle_client_buffer - if (mAppCreatedShareHandle) + // If the app passed in a share handle or D3D texture, open the resource + // See EGL_ANGLE_d3d_share_handle_client_buffer and EGL_ANGLE_d3d_texture_client_buffer + if (mAppCreatedShareHandle || mD3DTexture != nullptr) { - ID3D11Resource *tempResource11; - HRESULT result = device->OpenSharedResource(mShareHandle, __uuidof(ID3D11Resource), (void**)&tempResource11); + if (mAppCreatedShareHandle) + { + ID3D11Resource *tempResource11; + HRESULT result = device->OpenSharedResource(mShareHandle, __uuidof(ID3D11Resource), + (void **)&tempResource11); + ASSERT(SUCCEEDED(result)); - if (FAILED(result)) + mOffscreenTexture.set(d3d11::DynamicCastComObject(tempResource11), + backbufferFormatInfo); + SafeRelease(tempResource11); + } + else if (mD3DTexture != nullptr) { - ERR("Failed to open the swap chain pbuffer share handle: %08lX", result); - release(); - return EGL_BAD_PARAMETER; + mOffscreenTexture.set(d3d11::DynamicCastComObject(mD3DTexture), + backbufferFormatInfo); } - - result = tempResource11->QueryInterface(__uuidof(ID3D11Texture2D), (void**)&mOffscreenTexture); - SafeRelease(tempResource11); - - if (FAILED(result)) + else { - ERR("Failed to query texture2d interface in pbuffer share handle: %08lX", result); - release(); - return EGL_BAD_PARAMETER; + UNREACHABLE(); } + ASSERT(mOffscreenTexture.valid()); + mOffscreenTexture.getDesc(&offscreenTextureDesc); - // 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) + // Fail if the offscreen texture is not renderable. + if ((offscreenTextureDesc.BindFlags & D3D11_BIND_RENDER_TARGET) == 0) { - ERR("Invalid texture parameters in the shared offscreen texture pbuffer"); + ERR() << "Could not use provided offscreen texture, texture not renderable."; release(); - return EGL_BAD_PARAMETER; + return EGL_BAD_SURFACE; } } else { - const bool useSharedResource = !mNativeWindow.getNativeWindow() && mRenderer->getShareHandleSupport(); + const bool useSharedResource = + !mNativeWindow->getNativeWindow() && mRenderer->getShareHandleSupport(); - D3D11_TEXTURE2D_DESC offscreenTextureDesc = {0}; offscreenTextureDesc.Width = backbufferWidth; offscreenTextureDesc.Height = backbufferHeight; - offscreenTextureDesc.Format = backbufferFormatInfo.texFormat; + offscreenTextureDesc.Format = backbufferFormatInfo.texFormat; offscreenTextureDesc.MipLevels = 1; offscreenTextureDesc.ArraySize = 1; - offscreenTextureDesc.SampleDesc.Count = 1; + offscreenTextureDesc.SampleDesc.Count = getD3DSamples(); 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 ? ANGLE_RESOURCE_SHARE_TYPE : 0; - HRESULT result = device->CreateTexture2D(&offscreenTextureDesc, NULL, &mOffscreenTexture); - - if (FAILED(result)) + gl::Error err = mRenderer->allocateTexture(offscreenTextureDesc, backbufferFormatInfo, + &mOffscreenTexture); + if (err.isError()) { - ERR("Could not create offscreen texture: %08lX", result); + ERR() << "Could not create offscreen texture, " << err; release(); - - if (d3d11::isDeviceLostError(result)) - { - return EGL_CONTEXT_LOST; - } - else - { - return EGL_BAD_ALLOC; - } + return EGL_BAD_ALLOC; } - d3d11::SetDebugName(mOffscreenTexture, "Offscreen back buffer texture"); + mOffscreenTexture.setDebugName("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); + IDXGIResource *offscreenTextureResource = nullptr; + HRESULT result = mOffscreenTexture.get()->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); + ERR() << "Could not query offscreen texture resource, " << gl::FmtHR(result); } else { @@ -275,36 +286,49 @@ EGLint SwapChain11::resetOffscreenColorBuffer(int backbufferWidth, int backbuffe if (FAILED(result)) { - mShareHandle = NULL; - ERR("Could not get offscreen texture shared handle: %08lX", result); + mShareHandle = nullptr; + ERR() << "Could not get offscreen texture shared handle, " << gl::FmtHR(result); } } } } // This may return null if the original texture was created without a keyed mutex. - mKeyedMutex = d3d11::DynamicCastComObject(mOffscreenTexture); + mKeyedMutex = d3d11::DynamicCastComObject(mOffscreenTexture.get()); D3D11_RENDER_TARGET_VIEW_DESC offscreenRTVDesc; - offscreenRTVDesc.Format = backbufferFormatInfo.rtvFormat; - offscreenRTVDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; + offscreenRTVDesc.Format = backbufferFormatInfo.rtvFormat; + offscreenRTVDesc.ViewDimension = + (mEGLSamples <= 1) ? D3D11_RTV_DIMENSION_TEXTURE2D : D3D11_RTV_DIMENSION_TEXTURE2DMS; offscreenRTVDesc.Texture2D.MipSlice = 0; - HRESULT result = device->CreateRenderTargetView(mOffscreenTexture, &offscreenRTVDesc, &mOffscreenRTView); - ASSERT(SUCCEEDED(result)); - d3d11::SetDebugName(mOffscreenRTView, "Offscreen back buffer render target"); + gl::Error err = + mRenderer->allocateResource(offscreenRTVDesc, mOffscreenTexture.get(), &mOffscreenRTView); + ASSERT(!err.isError()); + mOffscreenRTView.setDebugName("Offscreen back buffer render target"); D3D11_SHADER_RESOURCE_VIEW_DESC offscreenSRVDesc; - offscreenSRVDesc.Format = backbufferFormatInfo.srvFormat; - offscreenSRVDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; + offscreenSRVDesc.Format = backbufferFormatInfo.srvFormat; + offscreenSRVDesc.ViewDimension = + (mEGLSamples <= 1) ? D3D11_SRV_DIMENSION_TEXTURE2D : D3D11_SRV_DIMENSION_TEXTURE2DMS; 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"); + if (offscreenTextureDesc.BindFlags & D3D11_BIND_SHADER_RESOURCE) + { + err = mRenderer->allocateResource(offscreenSRVDesc, mOffscreenTexture.get(), + &mOffscreenSRView); + ASSERT(!err.isError()); + mOffscreenSRView.setDebugName("Offscreen back buffer shader resource"); + } + else + { + // Special case for external textures that cannot support sampling. Since internally we + // assume our SwapChain is always readable, we make a copy texture that is compatible. + mNeedsOffscreenTextureCopy = true; + } - if (previousOffscreenTexture != nullptr) + if (previousOffscreenTexture.valid()) { D3D11_BOX sourceBox = {0}; sourceBox.left = 0; @@ -316,14 +340,12 @@ EGLint SwapChain11::resetOffscreenColorBuffer(int backbufferWidth, int backbuffe ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); const int yoffset = std::max(backbufferHeight - previousHeight, 0); - deviceContext->CopySubresourceRegion(mOffscreenTexture, 0, 0, yoffset, 0, - previousOffscreenTexture, 0, &sourceBox); - - SafeRelease(previousOffscreenTexture); + deviceContext->CopySubresourceRegion(mOffscreenTexture.get(), 0, 0, yoffset, 0, + previousOffscreenTexture.get(), 0, &sourceBox); if (mSwapChain) { - swapRect(0, 0, backbufferWidth, backbufferHeight); + swapRect(context, 0, 0, backbufferWidth, backbufferHeight); } } @@ -336,21 +358,38 @@ EGLint SwapChain11::resetOffscreenDepthBuffer(int backbufferWidth, int backbuffe if (mDepthBufferFormat != GL_NONE) { - const d3d11::TextureFormat &depthBufferFormatInfo = - d3d11::GetTextureFormatInfo(mDepthBufferFormat, mRenderer->getRenderer11DeviceCaps()); + const d3d11::Format &depthBufferFormatInfo = + d3d11::Format::Get(mDepthBufferFormat, mRenderer->getRenderer11DeviceCaps()); D3D11_TEXTURE2D_DESC depthStencilTextureDesc; depthStencilTextureDesc.Width = backbufferWidth; depthStencilTextureDesc.Height = backbufferHeight; - depthStencilTextureDesc.Format = depthBufferFormatInfo.texFormat; + depthStencilTextureDesc.Format = depthBufferFormatInfo.texFormat; depthStencilTextureDesc.MipLevels = 1; depthStencilTextureDesc.ArraySize = 1; - depthStencilTextureDesc.SampleDesc.Count = 1; - depthStencilTextureDesc.SampleDesc.Quality = 0; + depthStencilTextureDesc.SampleDesc.Count = getD3DSamples(); depthStencilTextureDesc.Usage = D3D11_USAGE_DEFAULT; depthStencilTextureDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL; - if (depthBufferFormatInfo.srvFormat != DXGI_FORMAT_UNKNOWN) + // If there is a multisampled offscreen color texture, the offscreen depth-stencil texture + // must also have the same quality value. + if (mOffscreenTexture.valid() && getD3DSamples() > 1) + { + D3D11_TEXTURE2D_DESC offscreenTextureDesc = {0}; + mOffscreenTexture.getDesc(&offscreenTextureDesc); + depthStencilTextureDesc.SampleDesc.Quality = offscreenTextureDesc.SampleDesc.Quality; + } + else + { + depthStencilTextureDesc.SampleDesc.Quality = 0; + } + + // Only create an SRV if it is supported + bool depthStencilSRV = + depthBufferFormatInfo.srvFormat != DXGI_FORMAT_UNKNOWN && + (mRenderer->getRenderer11DeviceCaps().supportsMultisampledDepthStencilSRVs || + depthStencilTextureDesc.SampleDesc.Count <= 1); + if (depthStencilSRV) { depthStencilTextureDesc.BindFlags |= D3D11_BIND_SHADER_RESOURCE; } @@ -358,58 +397,56 @@ EGLint SwapChain11::resetOffscreenDepthBuffer(int backbufferWidth, int backbuffe depthStencilTextureDesc.CPUAccessFlags = 0; depthStencilTextureDesc.MiscFlags = 0; - ID3D11Device *device = mRenderer->getDevice(); - HRESULT result = - device->CreateTexture2D(&depthStencilTextureDesc, NULL, &mDepthStencilTexture); - if (FAILED(result)) + gl::Error err = mRenderer->allocateTexture(depthStencilTextureDesc, depthBufferFormatInfo, + &mDepthStencilTexture); + if (err.isError()) { - ERR("Could not create depthstencil surface for new swap chain: 0x%08X", result); + ERR() << "Could not create depthstencil surface for new swap chain, " << err; release(); - - if (d3d11::isDeviceLostError(result)) - { - return EGL_CONTEXT_LOST; - } - else - { - return EGL_BAD_ALLOC; - } + return EGL_BAD_ALLOC; } - d3d11::SetDebugName(mDepthStencilTexture, "Offscreen depth stencil texture"); + mDepthStencilTexture.setDebugName("Offscreen depth stencil texture"); D3D11_DEPTH_STENCIL_VIEW_DESC depthStencilDesc; - depthStencilDesc.Format = depthBufferFormatInfo.dsvFormat; - depthStencilDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D; + depthStencilDesc.Format = depthBufferFormatInfo.dsvFormat; + depthStencilDesc.ViewDimension = + (mEGLSamples <= 1) ? D3D11_DSV_DIMENSION_TEXTURE2D : D3D11_DSV_DIMENSION_TEXTURE2DMS; depthStencilDesc.Flags = 0; depthStencilDesc.Texture2D.MipSlice = 0; - result = device->CreateDepthStencilView(mDepthStencilTexture, &depthStencilDesc, &mDepthStencilDSView); - ASSERT(SUCCEEDED(result)); - d3d11::SetDebugName(mDepthStencilDSView, "Offscreen depth stencil view"); + err = mRenderer->allocateResource(depthStencilDesc, mDepthStencilTexture.get(), + &mDepthStencilDSView); + ASSERT(!err.isError()); + mDepthStencilDSView.setDebugName("Offscreen depth stencil view"); - if (depthBufferFormatInfo.srvFormat != DXGI_FORMAT_UNKNOWN) + if (depthStencilSRV) { D3D11_SHADER_RESOURCE_VIEW_DESC depthStencilSRVDesc; - depthStencilSRVDesc.Format = depthBufferFormatInfo.srvFormat; - depthStencilSRVDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; + depthStencilSRVDesc.Format = depthBufferFormatInfo.srvFormat; + depthStencilSRVDesc.ViewDimension = (mEGLSamples <= 1) + ? D3D11_SRV_DIMENSION_TEXTURE2D + : D3D11_SRV_DIMENSION_TEXTURE2DMS; 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"); + err = mRenderer->allocateResource(depthStencilSRVDesc, mDepthStencilTexture.get(), + &mDepthStencilSRView); + ASSERT(!err.isError()); + mDepthStencilSRView.setDebugName("Offscreen depth stencil shader resource"); } } return EGL_SUCCESS; } -EGLint SwapChain11::resize(EGLint backbufferWidth, EGLint backbufferHeight) +EGLint SwapChain11::resize(const gl::Context *context, + EGLint backbufferWidth, + EGLint backbufferHeight) { TRACE_EVENT0("gpu.angle", "SwapChain11::resize"); ID3D11Device *device = mRenderer->getDevice(); - if (device == NULL) + if (device == nullptr) { return EGL_BAD_ACCESS; } @@ -427,18 +464,19 @@ EGLint SwapChain11::resize(EGLint backbufferWidth, EGLint backbufferHeight) } // Can only call resize if we have already created our swap buffer and resources - ASSERT(mSwapChain && mBackBufferTexture && mBackBufferRTView && mBackBufferSRView); + ASSERT(mSwapChain && mBackBufferTexture.valid() && mBackBufferRTView.valid() && + mBackBufferSRView.valid()); - SafeRelease(mBackBufferTexture); - SafeRelease(mBackBufferRTView); - SafeRelease(mBackBufferSRView); + mBackBufferTexture.reset(); + mBackBufferRTView.reset(); + mBackBufferSRView.reset(); // Resize swap chain DXGI_SWAP_CHAIN_DESC desc; HRESULT result = mSwapChain->GetDesc(&desc); if (FAILED(result)) { - ERR("Error reading swap chain description: 0x%08X", result); + ERR() << "Error reading swap chain description, " << gl::FmtHR(result); release(); return EGL_BAD_ALLOC; } @@ -447,7 +485,7 @@ EGLint SwapChain11::resize(EGLint backbufferWidth, EGLint backbufferHeight) if (FAILED(result)) { - ERR("Error resizing swap chain buffers: 0x%08X", result); + ERR() << "Error resizing swap chain buffers, " << gl::FmtHR(result); release(); if (d3d11::isDeviceLostError(result)) @@ -460,39 +498,64 @@ EGLint SwapChain11::resize(EGLint backbufferWidth, EGLint backbufferHeight) } } - result = mSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&mBackBufferTexture); + ID3D11Texture2D *backbufferTexture = nullptr; + result = mSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), + reinterpret_cast(&backbufferTexture)); 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"); - } - - result = device->CreateShaderResourceView(mBackBufferTexture, nullptr, &mBackBufferSRView); - ASSERT(SUCCEEDED(result)); - if (SUCCEEDED(result)) - { - d3d11::SetDebugName(mBackBufferSRView, "Back buffer shader resource"); - } + const auto &format = + d3d11::Format::Get(mOffscreenRenderTargetFormat, mRenderer->getRenderer11DeviceCaps()); + mBackBufferTexture.set(backbufferTexture, format); + mBackBufferTexture.setDebugName("Back buffer texture"); + + gl::Error err = + mRenderer->allocateResourceNoDesc(mBackBufferTexture.get(), &mBackBufferRTView); + ASSERT(!err.isError()); + mBackBufferRTView.setDebugName("Back buffer render target"); + + err = mRenderer->allocateResourceNoDesc(mBackBufferTexture.get(), &mBackBufferSRView); + ASSERT(!err.isError()); + mBackBufferSRView.setDebugName("Back buffer shader resource"); } mFirstSwap = true; - return resetOffscreenBuffers(backbufferWidth, backbufferHeight); + return resetOffscreenBuffers(context, backbufferWidth, backbufferHeight); } DXGI_FORMAT SwapChain11::getSwapChainNativeFormat() const { // Return a render target format for offscreen rendering is supported by IDXGISwapChain. // MSDN https://msdn.microsoft.com/en-us/library/windows/desktop/bb173064(v=vs.85).aspx - return (mOffscreenRenderTargetFormat == GL_BGRA8_EXT) ? DXGI_FORMAT_B8G8R8A8_UNORM : DXGI_FORMAT_R8G8B8A8_UNORM; + switch (mOffscreenRenderTargetFormat) + { + case GL_RGBA8: + case GL_RGBA4: + case GL_RGB5_A1: + case GL_RGB8: + case GL_RGB565: + return DXGI_FORMAT_R8G8B8A8_UNORM; + + case GL_BGRA8_EXT: + return DXGI_FORMAT_B8G8R8A8_UNORM; + + case GL_RGB10_A2: + return DXGI_FORMAT_R10G10B10A2_UNORM; + + case GL_RGBA16F: + return DXGI_FORMAT_R16G16B16A16_FLOAT; + + default: + UNREACHABLE(); + return DXGI_FORMAT_UNKNOWN; + } } -EGLint SwapChain11::reset(int backbufferWidth, int backbufferHeight, EGLint swapInterval) +EGLint SwapChain11::reset(const gl::Context *context, + EGLint backbufferWidth, + EGLint backbufferHeight, + EGLint swapInterval) { mSwapInterval = static_cast(swapInterval); if (mSwapInterval > 4) @@ -505,25 +568,23 @@ EGLint SwapChain11::reset(int backbufferWidth, int backbufferHeight, EGLint swap // If the swap chain already exists, just resize if (mSwapChain != nullptr) { - return resize(backbufferWidth, backbufferHeight); + return resize(context, backbufferWidth, backbufferHeight); } TRACE_EVENT0("gpu.angle", "SwapChain11::reset"); ID3D11Device *device = mRenderer->getDevice(); - if (device == NULL) + if (device == nullptr) { 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. -#if defined(ANGLE_ENABLE_D3D11_1) SafeRelease(mSwapChain1); -#endif SafeRelease(mSwapChain); - SafeRelease(mBackBufferTexture); - SafeRelease(mBackBufferRTView); + mBackBufferTexture.reset(); + mBackBufferRTView.reset(); // EGL allows creating a surface with 0x0 dimension, however, DXGI does not like 0x0 swapchains if (backbufferWidth < 1 || backbufferHeight < 1) @@ -532,15 +593,16 @@ EGLint SwapChain11::reset(int backbufferWidth, int backbufferHeight, EGLint swap return EGL_SUCCESS; } - if (mNativeWindow.getNativeWindow()) + if (mNativeWindow->getNativeWindow()) { - HRESULT result = mNativeWindow.createSwapChain(device, mRenderer->getDxgiFactory(), - getSwapChainNativeFormat(), - backbufferWidth, backbufferHeight, &mSwapChain); + HRESULT result = mNativeWindow->createSwapChain( + device, mRenderer->getDxgiFactory(), getSwapChainNativeFormat(), backbufferWidth, + backbufferHeight, getD3DSamples(), &mSwapChain); if (FAILED(result)) { - ERR("Could not create additional swap chains or offscreen surfaces: %08lX", result); + ERR() << "Could not create additional swap chains or offscreen surfaces, " + << gl::FmtHR(result); release(); if (d3d11::isDeviceLostError(result)) @@ -555,27 +617,31 @@ EGLint SwapChain11::reset(int backbufferWidth, int backbufferHeight, EGLint swap if (mRenderer->getRenderer11DeviceCaps().supportsDXGI1_2) { -#if defined(ANGLE_ENABLE_D3D11_1) mSwapChain1 = d3d11::DynamicCastComObject(mSwapChain); -#endif } - 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"); - - result = device->CreateShaderResourceView(mBackBufferTexture, nullptr, &mBackBufferSRView); + ID3D11Texture2D *backbufferTex = nullptr; + result = mSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), + reinterpret_cast(&backbufferTex)); ASSERT(SUCCEEDED(result)); - d3d11::SetDebugName(mBackBufferSRView, "Back buffer shader resource view"); + const auto &format = + d3d11::Format::Get(mOffscreenRenderTargetFormat, mRenderer->getRenderer11DeviceCaps()); + mBackBufferTexture.set(backbufferTex, format); + mBackBufferTexture.setDebugName("Back buffer texture"); + + gl::Error err = + mRenderer->allocateResourceNoDesc(mBackBufferTexture.get(), &mBackBufferRTView); + ASSERT(!err.isError()); + mBackBufferRTView.setDebugName("Back buffer render target"); + + err = mRenderer->allocateResourceNoDesc(mBackBufferTexture.get(), &mBackBufferSRView); + ASSERT(!err.isError()); + mBackBufferSRView.setDebugName("Back buffer shader resource view"); } mFirstSwap = true; - return resetOffscreenBuffers(backbufferWidth, backbufferHeight); + return resetOffscreenBuffers(context, backbufferWidth, backbufferHeight); } void SwapChain11::initPassThroughResources() @@ -588,11 +654,11 @@ void SwapChain11::initPassThroughResources() TRACE_EVENT0("gpu.angle", "SwapChain11::initPassThroughResources"); ID3D11Device *device = mRenderer->getDevice(); - ASSERT(device != NULL); + ASSERT(device != nullptr); // Make sure our resources are all not allocated, when we create - ASSERT(mQuadVB == NULL && mPassThroughSampler == NULL); - ASSERT(mPassThroughIL == NULL && mPassThroughVS == NULL && mPassThroughPS == NULL); + ASSERT(!mQuadVB.valid() && !mPassThroughSampler.valid()); + ASSERT(!mPassThroughIL.valid() && !mPassThroughVS.valid() && !mPassThroughPS.valid()); D3D11_BUFFER_DESC vbDesc; vbDesc.ByteWidth = sizeof(d3d11::PositionTexCoordVertex) * 4; @@ -602,9 +668,9 @@ void SwapChain11::initPassThroughResources() vbDesc.MiscFlags = 0; vbDesc.StructureByteStride = 0; - HRESULT result = device->CreateBuffer(&vbDesc, NULL, &mQuadVB); - ASSERT(SUCCEEDED(result)); - d3d11::SetDebugName(mQuadVB, "Swap chain quad vertex buffer"); + gl::Error err = mRenderer->allocateResource(vbDesc, &mQuadVB); + ASSERT(!err.isError()); + mQuadVB.setDebugName("Swap chain quad vertex buffer"); D3D11_SAMPLER_DESC samplerDesc; samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT; @@ -621,9 +687,9 @@ void SwapChain11::initPassThroughResources() samplerDesc.MinLOD = 0; samplerDesc.MaxLOD = D3D11_FLOAT32_MAX; - result = device->CreateSamplerState(&samplerDesc, &mPassThroughSampler); - ASSERT(SUCCEEDED(result)); - d3d11::SetDebugName(mPassThroughSampler, "Swap chain pass through sampler"); + err = mRenderer->allocateResource(samplerDesc, &mPassThroughSampler); + ASSERT(!err.isError()); + mPassThroughSampler.setDebugName("Swap chain pass through sampler"); D3D11_INPUT_ELEMENT_DESC quadLayout[] = { @@ -631,17 +697,30 @@ void SwapChain11::initPassThroughResources() { "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"); + InputElementArray quadElements(quadLayout); + ShaderData vertexShaderData(g_VS_Passthrough2D); - result = device->CreateVertexShader(g_VS_Passthrough2D, sizeof(g_VS_Passthrough2D), NULL, &mPassThroughVS); - ASSERT(SUCCEEDED(result)); - d3d11::SetDebugName(mPassThroughVS, "Swap chain pass through vertex shader"); + err = mRenderer->allocateResource(quadElements, &vertexShaderData, &mPassThroughIL); + ASSERT(!err.isError()); + mPassThroughIL.setDebugName("Swap chain pass through layout"); - result = device->CreatePixelShader(g_PS_PassthroughRGBA2D, sizeof(g_PS_PassthroughRGBA2D), NULL, &mPassThroughPS); - ASSERT(SUCCEEDED(result)); - d3d11::SetDebugName(mPassThroughPS, "Swap chain pass through pixel shader"); + err = mRenderer->allocateResource(vertexShaderData, &mPassThroughVS); + ASSERT(!err.isError()); + mPassThroughVS.setDebugName("Swap chain pass through vertex shader"); + + if (mEGLSamples <= 1) + { + ShaderData pixelShaderData(g_PS_PassthroughRGBA2D); + err = mRenderer->allocateResource(pixelShaderData, &mPassThroughPS); + } + else + { + ShaderData pixelShaderData(g_PS_PassthroughRGBA2DMS); + err = mRenderer->allocateResource(pixelShaderData, &mPassThroughPS); + } + + ASSERT(!err.isError()); + mPassThroughPS.setDebugName("Swap chain pass through pixel shader"); // Use the default rasterizer state but without culling D3D11_RASTERIZER_DESC rasterizerDesc; @@ -655,26 +734,31 @@ void SwapChain11::initPassThroughResources() rasterizerDesc.ScissorEnable = FALSE; rasterizerDesc.MultisampleEnable = FALSE; rasterizerDesc.AntialiasedLineEnable = FALSE; - result = device->CreateRasterizerState(&rasterizerDesc, &mPassThroughRS); - ASSERT(SUCCEEDED(result)); - d3d11::SetDebugName(mPassThroughRS, "Swap chain pass through rasterizer state"); + + err = mRenderer->allocateResource(rasterizerDesc, &mPassThroughRS); + ASSERT(!err.isError()); + mPassThroughRS.setDebugName("Swap chain pass through rasterizer state"); mPassThroughResourcesInit = true; } // parameters should be validated/clamped by caller -EGLint SwapChain11::swapRect(EGLint x, EGLint y, EGLint width, EGLint height) +EGLint SwapChain11::swapRect(const gl::Context *context, + EGLint x, + EGLint y, + EGLint width, + EGLint height) { if (mNeedsOffscreenTexture) { - EGLint result = copyOffscreenToBackbuffer(x, y, width, height); + EGLint result = copyOffscreenToBackbuffer(context, x, y, width, height); if (result != EGL_SUCCESS) { return result; } } - EGLint result = present(x, y, width, height); + EGLint result = present(context, x, y, width, height); if (result != EGL_SUCCESS) { return result; @@ -685,7 +769,11 @@ EGLint SwapChain11::swapRect(EGLint x, EGLint y, EGLint width, EGLint height) return EGL_SUCCESS; } -EGLint SwapChain11::copyOffscreenToBackbuffer(EGLint x, EGLint y, EGLint width, EGLint height) +EGLint SwapChain11::copyOffscreenToBackbuffer(const gl::Context *context, + EGLint x, + EGLint y, + EGLint width, + EGLint height) { if (!mSwapChain) { @@ -698,7 +786,8 @@ EGLint SwapChain11::copyOffscreenToBackbuffer(EGLint x, EGLint y, EGLint width, // Set vertices D3D11_MAPPED_SUBRESOURCE mappedResource; - HRESULT result = deviceContext->Map(mQuadVB, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); + HRESULT result = + deviceContext->Map(mQuadVB.get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); if (FAILED(result)) { return EGL_BAD_ACCESS; @@ -716,7 +805,6 @@ EGLint SwapChain11::copyOffscreenToBackbuffer(EGLint x, EGLint y, EGLint width, float v1 = y / float(height); float u2 = (x + width) / float(width); float v2 = (y + height) / float(height); - // Invert the quad vertices depending on the surface orientation. if ((mOrientation & EGL_SURFACE_ORIENTATION_INVERT_X_ANGLE) != 0) { @@ -732,60 +820,43 @@ EGLint SwapChain11::copyOffscreenToBackbuffer(EGLint x, EGLint y, EGLint width, d3d11::SetPositionTexCoordVertex(&vertices[2], x2, y1, u2, v1); d3d11::SetPositionTexCoordVertex(&vertices[3], x2, y2, u2, v2); - deviceContext->Unmap(mQuadVB, 0); + deviceContext->Unmap(mQuadVB.get(), 0); - static UINT stride = sizeof(d3d11::PositionTexCoordVertex); - static UINT startIdx = 0; - deviceContext->IASetVertexBuffers(0, 1, &mQuadVB, &stride, &startIdx); - - // Apply state - deviceContext->OMSetDepthStencilState(NULL, 0xFFFFFFFF); + StateManager11 *stateManager = mRenderer->getStateManager(); - static const float blendFactor[4] = { 1.0f, 1.0f, 1.0f, 1.0f }; - deviceContext->OMSetBlendState(NULL, blendFactor, 0xFFFFFFF); + constexpr UINT stride = sizeof(d3d11::PositionTexCoordVertex); + stateManager->setSingleVertexBuffer(&mQuadVB, stride, 0); - deviceContext->RSSetState(mPassThroughRS); + // Apply state + stateManager->setDepthStencilState(nullptr, 0xFFFFFFFF); + stateManager->setSimpleBlendState(nullptr); + stateManager->setRasterizerState(&mPassThroughRS); // 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); + stateManager->setInputLayout(&mPassThroughIL); + stateManager->setPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); + stateManager->setDrawShaders(&mPassThroughVS, nullptr, &mPassThroughPS); - // Apply render targets - mRenderer->setOneTimeRenderTarget(mBackBufferRTView); + // Apply render targets. Use the proxy context in display. + stateManager->setRenderTarget(mBackBufferRTView.get(), nullptr); // Set the viewport - D3D11_VIEWPORT viewport; - viewport.TopLeftX = 0; - viewport.TopLeftY = 0; - viewport.Width = static_cast(width); - viewport.Height = static_cast(height); - viewport.MinDepth = 0.0f; - viewport.MaxDepth = 1.0f; - deviceContext->RSSetViewports(1, &viewport); + stateManager->setSimpleViewport(mWidth, mHeight); // Apply textures - auto stateManager = mRenderer->getStateManager(); - stateManager->setShaderResource(gl::SAMPLER_PIXEL, 0, mOffscreenSRView); - deviceContext->PSSetSamplers(0, 1, &mPassThroughSampler); + stateManager->setSimplePixelTextureAndSampler(mOffscreenSRView, mPassThroughSampler); // Draw deviceContext->Draw(4, 0); - // Rendering to the swapchain is now complete. Now we can call Present(). - // Before that, we perform any cleanup on the D3D device. We do this before Present() to make sure the - // cleanup is caught under the current eglSwapBuffers() PIX/Graphics Diagnostics call rather than the next one. - stateManager->setShaderResource(gl::SAMPLER_PIXEL, 0, NULL); - - mRenderer->unapplyRenderTargets(); - mRenderer->markAllStateDirty(); - return EGL_SUCCESS; } -EGLint SwapChain11::present(EGLint x, EGLint y, EGLint width, EGLint height) +EGLint SwapChain11::present(const gl::Context *context, + EGLint x, + EGLint y, + EGLint width, + EGLint height) { if (!mSwapChain) { @@ -799,9 +870,9 @@ EGLint SwapChain11::present(EGLint x, EGLint y, EGLint width, EGLint height) HRESULT result = S_OK; -#if defined(ANGLE_ENABLE_D3D11_1) // Use IDXGISwapChain1::Present1 with a dirty rect if DXGI 1.2 is available. - if (mSwapChain1 != nullptr) + // Dirty rect present is not supported with a multisampled swapchain. + if (mSwapChain1 != nullptr && mEGLSamples <= 1) { if (mFirstSwap) { @@ -818,7 +889,6 @@ EGLint SwapChain11::present(EGLint x, EGLint y, EGLint width, EGLint height) } } else -#endif { result = mSwapChain->Present(swapInterval, 0); } @@ -826,60 +896,111 @@ EGLint SwapChain11::present(EGLint x, EGLint y, EGLint width, EGLint height) mFirstSwap = false; // Some swapping mechanisms such as DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL unbind the current render - // target. Mark it dirty. + // target. Mark it dirty. Use the proxy context in display since there is none available. mRenderer->getStateManager()->invalidateRenderTarget(); if (result == DXGI_ERROR_DEVICE_REMOVED) { - ERR("Present failed: the D3D11 device was removed: 0x%08X", - mRenderer->getDevice()->GetDeviceRemovedReason()); + ERR() << "Present failed: the D3D11 device was removed, " + << gl::FmtHR(mRenderer->getDevice()->GetDeviceRemovedReason()); return EGL_CONTEXT_LOST; } else if (result == DXGI_ERROR_DEVICE_RESET) { - ERR("Present failed: the D3D11 device was reset from a bad command."); + 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); + ERR() << "Present failed with " << gl::FmtHR(result); } - mNativeWindow.commitChange(); + mNativeWindow->commitChange(); return EGL_SUCCESS; } -ID3D11Texture2D *SwapChain11::getOffscreenTexture() +const TextureHelper11 &SwapChain11::getOffscreenTexture() { return mNeedsOffscreenTexture ? mOffscreenTexture : mBackBufferTexture; } -ID3D11RenderTargetView *SwapChain11::getRenderTarget() +const d3d11::RenderTargetView &SwapChain11::getRenderTarget() { return mNeedsOffscreenTexture ? mOffscreenRTView : mBackBufferRTView; } -ID3D11ShaderResourceView *SwapChain11::getRenderTargetShaderResource() +const d3d11::SharedSRV &SwapChain11::getRenderTargetShaderResource() { - return mNeedsOffscreenTexture ? mOffscreenSRView : mBackBufferSRView; + if (!mNeedsOffscreenTexture) + { + ASSERT(mBackBufferSRView.valid()); + return mBackBufferSRView; + } + + if (!mNeedsOffscreenTextureCopy) + { + ASSERT(mOffscreenSRView.valid()); + return mOffscreenSRView; + } + + if (!mOffscreenTextureCopyForSRV.valid()) + { + const d3d11::Format &backbufferFormatInfo = + d3d11::Format::Get(mOffscreenRenderTargetFormat, mRenderer->getRenderer11DeviceCaps()); + + D3D11_TEXTURE2D_DESC offscreenCopyDesc; + mOffscreenTexture.getDesc(&offscreenCopyDesc); + + offscreenCopyDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE; + offscreenCopyDesc.MiscFlags = 0; + offscreenCopyDesc.CPUAccessFlags = 0; + gl::Error err = mRenderer->allocateTexture(offscreenCopyDesc, backbufferFormatInfo, + &mOffscreenTextureCopyForSRV); + ASSERT(!err.isError()); + mOffscreenTextureCopyForSRV.setDebugName("Offscreen back buffer copy for SRV"); + + D3D11_SHADER_RESOURCE_VIEW_DESC offscreenSRVDesc; + offscreenSRVDesc.Format = backbufferFormatInfo.srvFormat; + offscreenSRVDesc.ViewDimension = + (mEGLSamples <= 1) ? D3D11_SRV_DIMENSION_TEXTURE2D : D3D11_SRV_DIMENSION_TEXTURE2DMS; + offscreenSRVDesc.Texture2D.MostDetailedMip = 0; + offscreenSRVDesc.Texture2D.MipLevels = static_cast(-1); + + err = mRenderer->allocateResource(offscreenSRVDesc, mOffscreenTextureCopyForSRV.get(), + &mOffscreenSRView); + ASSERT(!err.isError()); + mOffscreenSRView.setDebugName("Offscreen back buffer shader resource"); + } + + // Need to copy the offscreen texture into the shader-readable copy, since it's external and + // we don't know if the copy is up-to-date. This works around the problem we have when the app + // passes in a texture that isn't shader-readable. + mRenderer->getDeviceContext()->CopyResource(mOffscreenTextureCopyForSRV.get(), + mOffscreenTexture.get()); + return mOffscreenSRView; } -ID3D11DepthStencilView *SwapChain11::getDepthStencil() +const d3d11::DepthStencilView &SwapChain11::getDepthStencil() { return mDepthStencilDSView; } -ID3D11ShaderResourceView * SwapChain11::getDepthStencilShaderResource() +const d3d11::SharedSRV &SwapChain11::getDepthStencilShaderResource() { return mDepthStencilSRView; } -ID3D11Texture2D *SwapChain11::getDepthStencilTexture() +const TextureHelper11 &SwapChain11::getDepthStencilTexture() { return mDepthStencilTexture; } +void *SwapChain11::getKeyedMutex() +{ + return mKeyedMutex; +} + void SwapChain11::recreate() { // possibly should use this method instead of reset @@ -890,4 +1011,61 @@ void *rx::SwapChain11::getDevice() return mRenderer->getDevice(); } +RenderTargetD3D *SwapChain11::getColorRenderTarget() +{ + return &mColorRenderTarget; +} + +RenderTargetD3D *SwapChain11::getDepthStencilRenderTarget() +{ + return &mDepthStencilRenderTarget; +} + +egl::Error SwapChain11::getSyncValues(EGLuint64KHR *ust, EGLuint64KHR *msc, EGLuint64KHR *sbc) +{ + if (!mSwapChain) + { + return egl::EglNotInitialized() << "Swap chain uninitialized"; + } + + DXGI_FRAME_STATISTICS stats = {}; + HRESULT result = mSwapChain->GetFrameStatistics(&stats); + + if (FAILED(result)) + { + return egl::EglBadAlloc() << "Failed to get frame statistics, " << gl::FmtHR(result); + } + + // Conversion from DXGI_FRAME_STATISTICS to the output values: + // stats.SyncRefreshCount -> msc + // stats.PresentCount -> sbc + // stats.SyncQPCTime -> ust with conversion to microseconds via QueryPerformanceFrequency + *msc = stats.SyncRefreshCount; + *sbc = stats.PresentCount; + + LONGLONG syncQPCValue = stats.SyncQPCTime.QuadPart; + // If the QPC Value is below the overflow threshold, we proceed with + // simple multiply and divide. + if (syncQPCValue < kQPCOverflowThreshold) + { + *ust = syncQPCValue * kMicrosecondsPerSecond / mQPCFrequency; + } + else + { + // Otherwise, calculate microseconds in a round about manner to avoid + // overflow and precision issues. + int64_t wholeSeconds = syncQPCValue / mQPCFrequency; + int64_t leftoverTicks = syncQPCValue - (wholeSeconds * mQPCFrequency); + *ust = wholeSeconds * kMicrosecondsPerSecond + + leftoverTicks * kMicrosecondsPerSecond / mQPCFrequency; + } + + return egl::NoError(); +} + +UINT SwapChain11::getD3DSamples() const +{ + return (mEGLSamples == 0) ? 1 : mEGLSamples; } + +} // namespace rx diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/SwapChain11.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/SwapChain11.h index adcd07adb0..eca068210b 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/SwapChain11.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/SwapChain11.h @@ -16,39 +16,54 @@ namespace rx { class Renderer11; +class NativeWindow11; -class SwapChain11 : public SwapChainD3D +class SwapChain11 final : public SwapChainD3D { public: SwapChain11(Renderer11 *renderer, - NativeWindow nativeWindow, + NativeWindow11 *nativeWindow, HANDLE shareHandle, + IUnknown *d3dTexture, GLenum backBufferFormat, GLenum depthBufferFormat, - EGLint orientation); - 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 orientation, + EGLint samples); + ~SwapChain11() override; + + EGLint resize(const gl::Context *context, + EGLint backbufferWidth, + EGLint backbufferHeight) override; + EGLint reset(const gl::Context *context, + EGLint backbufferWidth, + EGLint backbufferHeight, + EGLint swapInterval) override; + EGLint swapRect(const gl::Context *context, + EGLint x, + EGLint y, + EGLint width, + EGLint height) override; + void recreate() override; + + RenderTargetD3D *getColorRenderTarget() override; + RenderTargetD3D *getDepthStencilRenderTarget() override; + + const TextureHelper11 &getOffscreenTexture(); + const d3d11::RenderTargetView &getRenderTarget(); + const d3d11::SharedSRV &getRenderTargetShaderResource(); + + const TextureHelper11 &getDepthStencilTexture(); + const d3d11::DepthStencilView &getDepthStencil(); + const d3d11::SharedSRV &getDepthStencilShaderResource(); EGLint getWidth() const { return mWidth; } EGLint getHeight() const { return mHeight; } - void *getKeyedMutex() override { return mKeyedMutex; } + void *getKeyedMutex() override; + EGLint getSamples() const { return mEGLSamples; } + + void *getDevice() override; - virtual void *getDevice(); + egl::Error getSyncValues(EGLuint64KHR *ust, EGLuint64KHR *msc, EGLuint64KHR *sbc) override; private: void release(); @@ -56,14 +71,23 @@ class SwapChain11 : public SwapChainD3D void releaseOffscreenColorBuffer(); void releaseOffscreenDepthBuffer(); - EGLint resetOffscreenBuffers(int backbufferWidth, int backbufferHeight); - EGLint resetOffscreenColorBuffer(int backbufferWidth, int backbufferHeight); + EGLint resetOffscreenBuffers(const gl::Context *context, + int backbufferWidth, + int backbufferHeight); + EGLint resetOffscreenColorBuffer(const gl::Context *context, + int backbufferWidth, + int backbufferHeight); EGLint resetOffscreenDepthBuffer(int backbufferWidth, int backbufferHeight); DXGI_FORMAT getSwapChainNativeFormat() const; - EGLint copyOffscreenToBackbuffer(EGLint x, EGLint y, EGLint width, EGLint height); - EGLint present(EGLint x, EGLint y, EGLint width, EGLint height); + EGLint copyOffscreenToBackbuffer(const gl::Context *context, + EGLint x, + EGLint y, + EGLint width, + EGLint height); + EGLint present(const gl::Context *context, EGLint x, EGLint y, EGLint width, EGLint height); + UINT getD3DSamples() const; Renderer11 *mRenderer; EGLint mWidth; @@ -73,36 +97,41 @@ class SwapChain11 : public SwapChainD3D unsigned int mSwapInterval; bool mPassThroughResourcesInit; + NativeWindow11 *mNativeWindow; // Handler for the Window that the surface is created for. + bool mFirstSwap; - DXGISwapChain *mSwapChain; -#if defined(ANGLE_ENABLE_D3D11_1) + IDXGISwapChain *mSwapChain; IDXGISwapChain1 *mSwapChain1; -#endif IDXGIKeyedMutex *mKeyedMutex; - ID3D11Texture2D *mBackBufferTexture; - ID3D11RenderTargetView *mBackBufferRTView; - ID3D11ShaderResourceView *mBackBufferSRView; + TextureHelper11 mBackBufferTexture; + d3d11::RenderTargetView mBackBufferRTView; + d3d11::SharedSRV mBackBufferSRView; const bool mNeedsOffscreenTexture; - ID3D11Texture2D *mOffscreenTexture; - ID3D11RenderTargetView *mOffscreenRTView; - ID3D11ShaderResourceView *mOffscreenSRView; - - ID3D11Texture2D *mDepthStencilTexture; - ID3D11DepthStencilView *mDepthStencilDSView; - ID3D11ShaderResourceView *mDepthStencilSRView; - - ID3D11Buffer *mQuadVB; - ID3D11SamplerState *mPassThroughSampler; - ID3D11InputLayout *mPassThroughIL; - ID3D11VertexShader *mPassThroughVS; - ID3D11PixelShader *mPassThroughPS; - ID3D11RasterizerState *mPassThroughRS; + TextureHelper11 mOffscreenTexture; + d3d11::RenderTargetView mOffscreenRTView; + d3d11::SharedSRV mOffscreenSRView; + bool mNeedsOffscreenTextureCopy; + TextureHelper11 mOffscreenTextureCopyForSRV; + + TextureHelper11 mDepthStencilTexture; + d3d11::DepthStencilView mDepthStencilDSView; + d3d11::SharedSRV mDepthStencilSRView; + + d3d11::Buffer mQuadVB; + d3d11::SamplerState mPassThroughSampler; + d3d11::InputLayout mPassThroughIL; + d3d11::VertexShader mPassThroughVS; + d3d11::PixelShader mPassThroughPS; + d3d11::RasterizerState mPassThroughRS; SurfaceRenderTarget11 mColorRenderTarget; SurfaceRenderTarget11 mDepthStencilRenderTarget; + + EGLint mEGLSamples; + LONGLONG mQPCFrequency; }; -} +} // namespace rx #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 index 11b9f76464..b702450ded 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/TextureStorage11.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/TextureStorage11.cpp @@ -5,7 +5,8 @@ // // 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. +// classes TextureStorage11_2D and TextureStorage11_Cube, which act as the interface to the D3D11 +// texture. #include "libANGLE/renderer/d3d/d3d11/TextureStorage11.h" @@ -21,6 +22,7 @@ #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/StreamProducerNV12.h" #include "libANGLE/renderer/d3d/d3d11/SwapChain11.h" #include "libANGLE/renderer/d3d/d3d11/texture_format_table.h" #include "libANGLE/renderer/d3d/EGLImageD3D.h" @@ -29,82 +31,79 @@ namespace rx { -TextureStorage11::SwizzleCacheValue::SwizzleCacheValue() - : swizzleRed(GL_INVALID_INDEX), - swizzleGreen(GL_INVALID_INDEX), - swizzleBlue(GL_INVALID_INDEX), - swizzleAlpha(GL_INVALID_INDEX) +namespace { + +void InvalidateRenderTarget(const gl::Context *context, RenderTarget11 *renderTarget) +{ + if (renderTarget) + { + renderTarget->signalDirty(context); + } } -TextureStorage11::SwizzleCacheValue::SwizzleCacheValue(GLenum red, GLenum green, GLenum blue, GLenum alpha) - : swizzleRed(red), swizzleGreen(green), swizzleBlue(blue), swizzleAlpha(alpha) +RenderTarget11 *GetRenderTarget(std::unique_ptr *pointer) { + return pointer->get(); } -bool TextureStorage11::SwizzleCacheValue::operator==(const SwizzleCacheValue &other) const +template +RenderTarget11 *GetRenderTarget(std::pair> *pair) { - return swizzleRed == other.swizzleRed && - swizzleGreen == other.swizzleGreen && - swizzleBlue == other.swizzleBlue && - swizzleAlpha == other.swizzleAlpha; + return pair->second.get(); } -bool TextureStorage11::SwizzleCacheValue::operator!=(const SwizzleCacheValue &other) const +template +void InvalidateRenderTargetContainer(const gl::Context *context, T *renderTargetContainer) { - return !(*this == other); + for (auto &rt : *renderTargetContainer) + { + InvalidateRenderTarget(context, GetRenderTarget(&rt)); + } } -TextureStorage11::SRVKey::SRVKey(int baseLevel, int mipLevels, bool swizzle) - : baseLevel(baseLevel), mipLevels(mipLevels), swizzle(swizzle) +} // anonymous namespace + +TextureStorage11::SRVKey::SRVKey(int baseLevel, int mipLevels, bool swizzle, bool dropStencil) + : baseLevel(baseLevel), mipLevels(mipLevels), swizzle(swizzle), dropStencil(dropStencil) { } bool TextureStorage11::SRVKey::operator<(const SRVKey &rhs) const { - return std::tie(baseLevel, mipLevels, swizzle) < std::tie(rhs.baseLevel, rhs.mipLevels, rhs.swizzle); + return std::tie(baseLevel, mipLevels, swizzle, dropStencil) < + std::tie(rhs.baseLevel, rhs.mipLevels, rhs.swizzle, rhs.dropStencil); } -TextureStorage11::TextureStorage11(Renderer11 *renderer, UINT bindFlags, UINT miscFlags) +TextureStorage11::TextureStorage11(Renderer11 *renderer, + UINT bindFlags, + UINT miscFlags, + GLenum internalFormat) : mRenderer(renderer), mTopLevel(0), mMipLevels(0), - mInternalFormat(GL_NONE), - mTextureFormat(DXGI_FORMAT_UNKNOWN), - mShaderResourceFormat(DXGI_FORMAT_UNKNOWN), - mRenderTargetFormat(DXGI_FORMAT_UNKNOWN), - mDepthStencilFormat(DXGI_FORMAT_UNKNOWN), + mFormatInfo(d3d11::Format::Get(internalFormat, mRenderer->getRenderer11DeviceCaps())), mTextureWidth(0), mTextureHeight(0), mTextureDepth(0), + mDropStencilTexture(), mBindFlags(bindFlags), mMiscFlags(miscFlags) { - for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) - { - mLevelSRVs[i] = nullptr; - } } 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(); } -DWORD TextureStorage11::GetTextureBindFlags(GLenum internalFormat, const Renderer11DeviceCaps &renderer11DeviceCaps, bool renderTarget) +DWORD TextureStorage11::GetTextureBindFlags(GLenum internalFormat, + const Renderer11DeviceCaps &renderer11DeviceCaps, + bool renderTarget) { UINT bindFlags = 0; - const d3d11::TextureFormat &formatInfo = d3d11::GetTextureFormatInfo(internalFormat, renderer11DeviceCaps); + const d3d11::Format &formatInfo = d3d11::Format::Get(internalFormat, renderer11DeviceCaps); if (formatInfo.srvFormat != DXGI_FORMAT_UNKNOWN) { bindFlags |= D3D11_BIND_SHADER_RESOURCE; @@ -121,16 +120,17 @@ DWORD TextureStorage11::GetTextureBindFlags(GLenum internalFormat, const Rendere return bindFlags; } -DWORD TextureStorage11::GetTextureMiscFlags(GLenum internalFormat, const Renderer11DeviceCaps &renderer11DeviceCaps, bool renderTarget, int levels) +DWORD TextureStorage11::GetTextureMiscFlags(GLenum internalFormat, + const Renderer11DeviceCaps &renderer11DeviceCaps, + bool renderTarget, + int levels) { UINT miscFlags = 0; - const d3d11::TextureFormat &formatInfo = d3d11::GetTextureFormatInfo(internalFormat, renderer11DeviceCaps); + const d3d11::Format &formatInfo = d3d11::Format::Get(internalFormat, renderer11DeviceCaps); if (renderTarget && levels > 1) { - const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(formatInfo.texFormat); - - if (dxgiFormatInfo.nativeMipmapSupport(renderer11DeviceCaps.featureLevel)) + if (d3d11::SupportsMipGen(formatInfo.texFormat, renderer11DeviceCaps.featureLevel)) { miscFlags |= D3D11_RESOURCE_MISC_GENERATE_MIPS; } @@ -151,6 +151,8 @@ UINT TextureStorage11::getMiscFlags() const int TextureStorage11::getTopLevel() const { + // Applying top level is meant to be encapsulated inside TextureStorage11. + UNREACHABLE(); return mTopLevel; } @@ -189,24 +191,35 @@ int TextureStorage11::getLevelDepth(int mipLevel) const return std::max(static_cast(mTextureDepth) >> mipLevel, 1); } +gl::Error TextureStorage11::getMippedResource(const gl::Context *context, + const TextureHelper11 **outResource) +{ + return getResource(context, outResource); +} + 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 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::TextureState &textureState, - ID3D11ShaderResourceView **outSRV) +gl::Error TextureStorage11::getSRV(const gl::Context *context, + const gl::TextureState &textureState, + const d3d11::SharedSRV **outSRV) { - bool swizzleRequired = textureState.swizzleRequired(); - bool mipmapping = gl::IsMipmapFiltered(textureState.samplerState); - unsigned int mipLevels = mipmapping ? (textureState.maxLevel - textureState.baseLevel + 1) : 1; + // Make sure to add the level offset for our tiny compressed texture workaround + const GLuint effectiveBaseLevel = textureState.getEffectiveBaseLevel(); + bool swizzleRequired = textureState.swizzleRequired(); + bool mipmapping = gl::IsMipmapFiltered(textureState.getSamplerState()); + unsigned int mipLevels = + mipmapping ? (textureState.getEffectiveMaxLevel() - effectiveBaseLevel + 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 - textureState.baseLevel); + // 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 - effectiveBaseLevel); if (mRenderer->getRenderer11DeviceCaps().featureLevel <= D3D_FEATURE_LEVEL_9_3) { @@ -217,89 +230,133 @@ gl::Error TextureStorage11::getSRV(const gl::TextureState &textureState, 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; - } + ANGLE_TRY(useLevelZeroWorkaroundTexture(context, mipLevels == 1)); } if (swizzleRequired) { - verifySwizzleExists(textureState.swizzleRed, textureState.swizzleGreen, - textureState.swizzleBlue, textureState.swizzleAlpha); + verifySwizzleExists(textureState.getSwizzleState()); + } + + // We drop the stencil when sampling from the SRV if three conditions hold: + // 1. the drop stencil workaround is enabled. + bool workaround = mRenderer->getWorkarounds().emulateTinyStencilTextures; + // 2. this is a stencil texture. + bool hasStencil = (mFormatInfo.format().stencilBits > 0); + // 3. the texture has a 1x1 or 2x2 mip. + int effectiveTopLevel = effectiveBaseLevel + mipLevels - 1; + bool hasSmallMips = + (getLevelWidth(effectiveTopLevel) <= 2 || getLevelHeight(effectiveTopLevel) <= 2); + + bool useDropStencil = (workaround && hasStencil && hasSmallMips); + SRVKey key(effectiveBaseLevel, mipLevels, swizzleRequired, useDropStencil); + if (useDropStencil) + { + // Ensure drop texture gets created. + DropStencil result = DropStencil::CREATED; + ANGLE_TRY_RESULT(ensureDropStencilTexture(context), result); + + // Clear the SRV cache if necessary. + // TODO(jmadill): Re-use find query result. + auto srvEntry = mSrvCache.find(key); + if (result == DropStencil::CREATED && srvEntry != mSrvCache.end()) + { + mSrvCache.erase(key); + } } - SRVKey key(textureState.baseLevel, mipLevels, swizzleRequired); + ANGLE_TRY(getCachedOrCreateSRV(context, key, outSRV)); + + return gl::NoError(); +} + +gl::Error TextureStorage11::getCachedOrCreateSRV(const gl::Context *context, + const SRVKey &key, + const d3d11::SharedSRV **outSRV) +{ auto iter = mSrvCache.find(key); if (iter != mSrvCache.end()) { - *outSRV = iter->second; - return gl::Error(GL_NO_ERROR); + *outSRV = &iter->second; + return gl::NoError(); } - ID3D11Resource *texture = nullptr; - if (swizzleRequired) + const TextureHelper11 *texture = nullptr; + DXGI_FORMAT format = DXGI_FORMAT_UNKNOWN; + + if (key.swizzle) { - gl::Error error = getSwizzleTexture(&texture); - if (error.isError()) - { - return error; - } + const auto &swizzleFormat = + mFormatInfo.getSwizzleFormat(mRenderer->getRenderer11DeviceCaps()); + ASSERT(!key.dropStencil || swizzleFormat.format().stencilBits == 0); + ANGLE_TRY(getSwizzleTexture(&texture)); + format = swizzleFormat.srvFormat; } - else + else if (key.dropStencil) { - gl::Error error = getResource(&texture); - if (error.isError()) - { - return error; - } + ASSERT(mDropStencilTexture.valid()); + texture = &mDropStencilTexture; + format = DXGI_FORMAT_R32_FLOAT; } - - ID3D11ShaderResourceView *srv = nullptr; - DXGI_FORMAT format = (swizzleRequired ? mSwizzleShaderResourceFormat : mShaderResourceFormat); - gl::Error error = createSRV(textureState.baseLevel, mipLevels, format, texture, &srv); - if (error.isError()) + else { - return error; + ANGLE_TRY(getResource(context, &texture)); + format = mFormatInfo.srvFormat; } - mSrvCache.insert(std::make_pair(key, srv)); - *outSRV = srv; + d3d11::SharedSRV srv; + + ANGLE_TRY(createSRV(context, key.baseLevel, key.mipLevels, format, *texture, &srv)); - return gl::Error(GL_NO_ERROR); + const auto &insertIt = mSrvCache.insert(std::make_pair(key, std::move(srv))); + *outSRV = &insertIt.first->second; + + return gl::NoError(); } -gl::Error TextureStorage11::getSRVLevel(int mipLevel, ID3D11ShaderResourceView **outSRV) +gl::Error TextureStorage11::getSRVLevel(const gl::Context *context, + int mipLevel, + bool blitSRV, + const d3d11::SharedSRV **outSRV) { ASSERT(mipLevel >= 0 && mipLevel < getLevelCount()); - if (!mLevelSRVs[mipLevel]) + auto &levelSRVs = (blitSRV) ? mLevelBlitSRVs : mLevelSRVs; + auto &otherLevelSRVs = (blitSRV) ? mLevelSRVs : mLevelBlitSRVs; + + if (!levelSRVs[mipLevel].valid()) { - ID3D11Resource *resource = NULL; - gl::Error error = getResource(&resource); - if (error.isError()) + // Only create a different SRV for blit if blit format is different from regular srv format + if (otherLevelSRVs[mipLevel].valid() && mFormatInfo.srvFormat == mFormatInfo.blitSRVFormat) { - return error; + levelSRVs[mipLevel] = otherLevelSRVs[mipLevel].makeCopy(); } - - error = createSRV(mipLevel, 1, mShaderResourceFormat, resource, &mLevelSRVs[mipLevel]); - if (error.isError()) + else { - return error; + const TextureHelper11 *resource = nullptr; + ANGLE_TRY(getResource(context, &resource)); + + DXGI_FORMAT resourceFormat = + blitSRV ? mFormatInfo.blitSRVFormat : mFormatInfo.srvFormat; + ANGLE_TRY( + createSRV(context, mipLevel, 1, resourceFormat, *resource, &levelSRVs[mipLevel])); } } - *outSRV = mLevelSRVs[mipLevel]; + *outSRV = &levelSRVs[mipLevel]; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureStorage11::getSRVLevels(GLint baseLevel, GLint maxLevel, ID3D11ShaderResourceView **outSRV) +gl::Error TextureStorage11::getSRVLevels(const gl::Context *context, + GLint baseLevel, + GLint maxLevel, + const d3d11::SharedSRV **outSRV) { unsigned int mipLevels = maxLevel - baseLevel + 1; - // Make sure there's 'mipLevels' mipmap levels below the base level (offset by the top level, which corresponds to GL level 0) + // 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 - baseLevel); if (mRenderer->getRenderer11DeviceCaps().featureLevel <= D3D_FEATURE_LEVEL_9_3) @@ -310,245 +367,218 @@ gl::Error TextureStorage11::getSRVLevels(GLint baseLevel, GLint maxLevel, ID3D11 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; - } - } - - SRVKey key(baseLevel, mipLevels, false); - auto iter = mSrvCache.find(key); - if (iter != mSrvCache.end()) - { - *outSRV = iter->second; - return gl::Error(GL_NO_ERROR); + ANGLE_TRY(useLevelZeroWorkaroundTexture(context, mipLevels == 1)); } - ID3D11Resource *texture = nullptr; - gl::Error error = getResource(&texture); - if (error.isError()) - { - return error; - } + // TODO(jmadill): Assert we don't need to drop stencil. - ID3D11ShaderResourceView *srv = nullptr; - error = createSRV(baseLevel, mipLevels, mShaderResourceFormat, texture, &srv); - if (error.isError()) - { - return error; - } + SRVKey key(baseLevel, mipLevels, false, false); + ANGLE_TRY(getCachedOrCreateSRV(context, key, outSRV)); - mSrvCache[key] = srv; - *outSRV = srv; + return gl::NoError(); +} - return gl::Error(GL_NO_ERROR); +const d3d11::Format &TextureStorage11::getFormatSet() const +{ + return mFormatInfo; } -gl::Error TextureStorage11::generateSwizzles(GLenum swizzleRed, GLenum swizzleGreen, GLenum swizzleBlue, GLenum swizzleAlpha) +gl::Error TextureStorage11::generateSwizzles(const gl::Context *context, + const gl::SwizzleState &swizzleTarget) { - 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; - } + const d3d11::SharedSRV *sourceSRV = nullptr; + ANGLE_TRY(getSRVLevel(context, level, true, &sourceSRV)); - ID3D11RenderTargetView *destRTV = NULL; - error = getSwizzleRenderTarget(level, &destRTV); - if (error.isError()) - { - return error; - } + const d3d11::RenderTargetView *destRTV; + ANGLE_TRY(getSwizzleRenderTarget(level, &destRTV)); 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; - } + ANGLE_TRY(blitter->swizzleTexture(context, *sourceSRV, *destRTV, size, swizzleTarget)); mSwizzleCache[level] = swizzleTarget; } } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -void TextureStorage11::invalidateSwizzleCacheLevel(int mipLevel) +void TextureStorage11::markLevelDirty(int mipLevel) { - if (mipLevel >= 0 && static_cast(mipLevel) < ArraySize(mSwizzleCache)) + if (mipLevel >= 0 && static_cast(mipLevel) < mSwizzleCache.size()) + { + // The default constructor of SwizzleState has GL_INVALID_INDEX for all channels which is + // not a valid swizzle combination + if (mSwizzleCache[mipLevel] != gl::SwizzleState()) + { + // TODO(jmadill): Invalidate specific swizzle. + mRenderer->getStateManager()->invalidateSwizzles(); + mSwizzleCache[mipLevel] = gl::SwizzleState(); + } + } + + if (mDropStencilTexture.valid()) { - // The default constructor of SwizzleCacheValue has GL_NONE for all channels which is not a - // valid swizzle combination - mSwizzleCache[mipLevel] = SwizzleCacheValue(); + mDropStencilTexture.reset(); } } -void TextureStorage11::invalidateSwizzleCache() +void TextureStorage11::markDirty() { - for (unsigned int mipLevel = 0; mipLevel < ArraySize(mSwizzleCache); mipLevel++) + for (size_t mipLevel = 0; mipLevel < mSwizzleCache.size(); ++mipLevel) { - invalidateSwizzleCacheLevel(mipLevel); + markLevelDirty(static_cast(mipLevel)); } } -gl::Error TextureStorage11::updateSubresourceLevel(ID3D11Resource *srcTexture, unsigned int sourceSubresource, - const gl::ImageIndex &index, const gl::Box ©Area) +gl::Error TextureStorage11::updateSubresourceLevel(const gl::Context *context, + const TextureHelper11 &srcTexture, + unsigned int sourceSubresource, + const gl::ImageIndex &index, + const gl::Box ©Area) { - ASSERT(srcTexture); + ASSERT(srcTexture.valid()); - GLint level = index.mipIndex; + const GLint level = index.mipIndex; - invalidateSwizzleCacheLevel(level); + markLevelDirty(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; + 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); + const TextureHelper11 *dstTexture = nullptr; - // 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 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); + ANGLE_TRY(getMippedResource(context, &dstTexture)); } else { - error = getResource(&dstTexture); - } - - if (error.isError()) - { - return error; + ANGLE_TRY(getResource(context, &dstTexture)); } unsigned int dstSubresource = getSubresourceIndex(index); - ASSERT(dstTexture); + ASSERT(dstTexture->valid()); - const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(mTextureFormat); - if (!fullCopy && (dxgiFormatInfo.depthBits > 0 || dxgiFormatInfo.stencilBits > 0)) + const d3d11::DXGIFormatSize &dxgiFormatSizeInfo = + d3d11::GetDXGIFormatSizeInfo(mFormatInfo.texFormat); + if (!fullCopy && mFormatInfo.dsvFormat != DXGI_FORMAT_UNKNOWN) { // CopySubresourceRegion cannot copy partial depth stencils, use the blitter instead - Blit11 *blitter = mRenderer->getBlitter(); - + Blit11 *blitter = mRenderer->getBlitter(); return blitter->copyDepthStencil(srcTexture, sourceSubresource, copyArea, texSize, - dstTexture, dstSubresource, copyArea, texSize, - NULL); + *dstTexture, dstSubresource, copyArea, texSize, nullptr); } - 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(); + D3D11_BOX srcBox; + srcBox.left = copyArea.x; + srcBox.top = copyArea.y; + srcBox.right = + copyArea.x + roundUp(static_cast(copyArea.width), dxgiFormatSizeInfo.blockWidth); + srcBox.bottom = + copyArea.y + roundUp(static_cast(copyArea.height), dxgiFormatSizeInfo.blockHeight); + srcBox.front = copyArea.z; + srcBox.back = copyArea.z + copyArea.depth; + + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); - context->CopySubresourceRegion(dstTexture, dstSubresource, copyArea.x, copyArea.y, copyArea.z, - srcTexture, sourceSubresource, fullCopy ? NULL : &srcBox); - return gl::Error(GL_NO_ERROR); - } + deviceContext->CopySubresourceRegion(dstTexture->get(), dstSubresource, copyArea.x, copyArea.y, + copyArea.z, srcTexture.get(), sourceSubresource, + fullCopy ? nullptr : &srcBox); + return gl::NoError(); } -gl::Error TextureStorage11::copySubresourceLevel(ID3D11Resource* dstTexture, unsigned int dstSubresource, - const gl::ImageIndex &index, const gl::Box ®ion) +gl::Error TextureStorage11::copySubresourceLevel(const gl::Context *context, + const TextureHelper11 &dstTexture, + unsigned int dstSubresource, + const gl::ImageIndex &index, + const gl::Box ®ion) { - ASSERT(dstTexture); + ASSERT(dstTexture.valid()); - ID3D11Resource *srcTexture = NULL; - gl::Error error(GL_NO_ERROR); + const TextureHelper11 *srcTexture = nullptr; - // 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 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); + ANGLE_TRY(getMippedResource(context, &srcTexture)); } else { - error = getResource(&srcTexture); - } - - if (error.isError()) - { - return error; + ANGLE_TRY(getResource(context, &srcTexture)); } - ASSERT(srcTexture); + ASSERT(srcTexture->valid()); unsigned int srcSubresource = getSubresourceIndex(index); - ID3D11DeviceContext *context = mRenderer->getDeviceContext(); + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); - // D3D11 can't perform partial CopySubresourceRegion on depth/stencil textures, so pSrcBox should be NULL. + // D3D11 can't perform partial CopySubresourceRegion on depth/stencil textures, so pSrcBox + // should be nullptr. D3D11_BOX srcBox; - D3D11_BOX *pSrcBox = NULL; + D3D11_BOX *pSrcBox = nullptr; if (mRenderer->getRenderer11DeviceCaps().featureLevel <= 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; + GLsizei width = region.width; + GLsizei height = region.height; + d3d11::MakeValidSize(false, mFormatInfo.texFormat, &width, &height, nullptr); + + // Keep srcbox as nullptr if we're dealing with tiny mips of compressed textures. + if (width == region.width && height == region.height) + { + // 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(mFormatInfo.dsvFormat == DXGI_FORMAT_UNKNOWN); + 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); + deviceContext->CopySubresourceRegion(dstTexture.get(), dstSubresource, region.x, region.y, + region.z, srcTexture->get(), srcSubresource, pSrcBox); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureStorage11::generateMipmap(const gl::ImageIndex &sourceIndex, const gl::ImageIndex &destIndex) +gl::Error TextureStorage11::generateMipmap(const gl::Context *context, + const gl::ImageIndex &sourceIndex, + const gl::ImageIndex &destIndex) { ASSERT(sourceIndex.layerIndex == destIndex.layerIndex); - invalidateSwizzleCacheLevel(destIndex.mipIndex); + markLevelDirty(destIndex.mipIndex); - RenderTargetD3D *source = NULL; - gl::Error error = getRenderTarget(sourceIndex, &source); - if (error.isError()) - { - return error; - } + RenderTargetD3D *source = nullptr; + ANGLE_TRY(getRenderTarget(context, sourceIndex, &source)); - RenderTargetD3D *dest = NULL; - error = getRenderTarget(destIndex, &dest); - if (error.isError()) - { - return error; - } + RenderTargetD3D *dest = nullptr; + ANGLE_TRY(getRenderTarget(context, destIndex, &dest)); - ID3D11ShaderResourceView *sourceSRV = GetAs(source)->getShaderResourceView(); - ID3D11RenderTargetView *destRTV = GetAs(dest)->getRenderTargetView(); + RenderTarget11 *rt11 = GetAs(source); + const d3d11::SharedSRV &sourceSRV = rt11->getBlitShaderResourceView(); + const d3d11::RenderTargetView &destRTV = rt11->getRenderTargetView(); gl::Box sourceArea(0, 0, 0, source->getWidth(), source->getHeight(), source->getDepth()); gl::Extents sourceSize(source->getWidth(), source->getHeight(), source->getDepth()); @@ -557,90 +587,75 @@ gl::Error TextureStorage11::generateMipmap(const gl::ImageIndex &sourceIndex, co 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, false); + GLenum format = gl::GetUnsizedFormat(source->getInternalFormat()); + return blitter->copyTexture(context, sourceSRV, sourceArea, sourceSize, format, destRTV, + destArea, destSize, nullptr, format, GL_LINEAR, false, false, + false); } -void TextureStorage11::verifySwizzleExists(GLenum swizzleRed, GLenum swizzleGreen, GLenum swizzleBlue, GLenum swizzleAlpha) +void TextureStorage11::verifySwizzleExists(const gl::SwizzleState &swizzleState) { - SwizzleCacheValue swizzleTarget(swizzleRed, swizzleGreen, swizzleBlue, swizzleAlpha); for (unsigned int level = 0; level < mMipLevels; level++) { - ASSERT(mSwizzleCache[level] == swizzleTarget); + ASSERT(mSwizzleCache[level] == swizzleState); } } void TextureStorage11::clearSRVCache() { - invalidateSwizzleCache(); - - auto iter = mSrvCache.begin(); - while (iter != mSrvCache.end()) - { - if (!iter->first.swizzle) - { - SafeRelease(iter->second); - iter = mSrvCache.erase(iter); - } - else - { - iter++; - } - } + markDirty(); + mSrvCache.clear(); - for (size_t level = 0; level < ArraySize(mLevelSRVs); level++) + for (size_t level = 0; level < mLevelSRVs.size(); level++) { - SafeRelease(mLevelSRVs[level]); + mLevelSRVs[level].reset(); + mLevelBlitSRVs[level].reset(); } } -gl::Error TextureStorage11::copyToStorage(TextureStorage *destStorage) +gl::Error TextureStorage11::copyToStorage(const gl::Context *context, TextureStorage *destStorage) { ASSERT(destStorage); - ID3D11Resource *sourceResouce = NULL; - gl::Error error = getResource(&sourceResouce); - if (error.isError()) - { - return error; - } + const TextureHelper11 *sourceResouce = nullptr; + ANGLE_TRY(getResource(context, &sourceResouce)); - TextureStorage11 *dest11 = GetAs(destStorage); - ID3D11Resource *destResource = NULL; - error = dest11->getResource(&destResource); - if (error.isError()) - { - return error; - } + TextureStorage11 *dest11 = GetAs(destStorage); + const TextureHelper11 *destResource = nullptr; + ANGLE_TRY(dest11->getResource(context, &destResource)); ID3D11DeviceContext *immediateContext = mRenderer->getDeviceContext(); - immediateContext->CopyResource(destResource, sourceResouce); + immediateContext->CopyResource(destResource->get(), sourceResouce->get()); - dest11->invalidateSwizzleCache(); + dest11->markDirty(); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureStorage11::setData(const gl::ImageIndex &index, ImageD3D *image, const gl::Box *destBox, GLenum type, - const gl::PixelUnpackState &unpack, const uint8_t *pixelData) +gl::Error TextureStorage11::setData(const gl::Context *context, + 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); + markLevelDirty(index.mipIndex); + + const TextureHelper11 *resource = nullptr; + ANGLE_TRY(getResource(context, &resource)); + ASSERT(resource && resource->valid()); UINT destSubresource = getSubresourceIndex(index); - const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(image->getInternalFormat()); + const gl::InternalFormat &internalFormatInfo = + gl::GetInternalFormatInfo(image->getInternalFormat(), type); - gl::Box levelBox(0, 0, 0, getLevelWidth(index.mipIndex), getLevelHeight(index.mipIndex), getLevelDepth(index.mipIndex)); - bool fullUpdate = (destBox == NULL || *destBox == levelBox); + gl::Box levelBox(0, 0, 0, getLevelWidth(index.mipIndex), getLevelHeight(index.mipIndex), + getLevelDepth(index.mipIndex)); + bool fullUpdate = (destBox == nullptr || *destBox == levelBox); ASSERT(internalFormatInfo.depthBits == 0 || fullUpdate); // TODO(jmadill): Handle compressed formats @@ -649,36 +664,44 @@ gl::Error TextureStorage11::setData(const gl::ImageIndex &index, ImageD3D *image // 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, unpack.imageHeight); - GLsizei srcSkipBytes = internalFormatInfo.computeSkipPixels( - srcRowPitch, srcDepthPitch, unpack.skipImages, unpack.skipRows, unpack.skipPixels); - - const d3d11::TextureFormat &d3d11Format = d3d11::GetTextureFormatInfo(image->getInternalFormat(), mRenderer->getRenderer11DeviceCaps()); - const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(d3d11Format.texFormat); - - size_t outputPixelSize = dxgiFormatInfo.pixelBytes; + const int imageWidth = static_cast(image->getWidth()); + const int width = destBox ? destBox->width : imageWidth; + const int imageHeight = static_cast(image->getHeight()); + const int height = destBox ? destBox->height : imageHeight; + const int imageDepth = static_cast(image->getDepth()); + const int depth = destBox ? destBox->depth : imageDepth; + if (imageWidth < width || imageHeight < height || imageDepth < depth) + fullUpdate = true; + GLuint srcRowPitch = 0; + ANGLE_TRY_RESULT( + internalFormatInfo.computeRowPitch(type, width, unpack.alignment, unpack.rowLength), + srcRowPitch); + GLuint srcDepthPitch = 0; + ANGLE_TRY_RESULT(internalFormatInfo.computeDepthPitch(height, unpack.imageHeight, srcRowPitch), + srcDepthPitch); + GLuint srcSkipBytes = 0; + ANGLE_TRY_RESULT( + internalFormatInfo.computeSkipBytes(srcRowPitch, srcDepthPitch, unpack, index.is3D()), + srcSkipBytes); + + const d3d11::Format &d3d11Format = + d3d11::Format::Get(image->getInternalFormat(), mRenderer->getRenderer11DeviceCaps()); + const d3d11::DXGIFormatSize &dxgiFormatInfo = + d3d11::GetDXGIFormatSizeInfo(d3d11Format.texFormat); + + const size_t outputPixelSize = dxgiFormatInfo.pixelBytes; UINT bufferRowPitch = static_cast(outputPixelSize) * width; UINT bufferDepthPitch = bufferRowPitch * height; - size_t neededSize = bufferDepthPitch * depth; - MemoryBuffer *conversionBuffer = nullptr; + const size_t neededSize = bufferDepthPitch * depth; + angle::MemoryBuffer *conversionBuffer = nullptr; const uint8_t *data = nullptr; - d3d11::LoadImageFunctionInfo loadFunctionInfo = d3d11Format.loadFunctions.at(type); + LoadImageFunctionInfo loadFunctionInfo = d3d11Format.getLoadFunctions()(type); if (loadFunctionInfo.requiresConversion) { - error = mRenderer->getScratchMemoryBuffer(neededSize, &conversionBuffer); - if (error.isError()) - { - return error; - } - + ANGLE_TRY(mRenderer->getScratchMemoryBuffer(neededSize, &conversionBuffer)); loadFunctionInfo.loadFunction(width, height, depth, pixelData + srcSkipBytes, srcRowPitch, srcDepthPitch, conversionBuffer->data(), bufferRowPitch, bufferDepthPitch); @@ -698,264 +721,233 @@ gl::Error TextureStorage11::setData(const gl::ImageIndex &index, ImageD3D *image ASSERT(destBox); D3D11_BOX destD3DBox; - destD3DBox.left = destBox->x; - destD3DBox.right = destBox->x + destBox->width; - destD3DBox.top = destBox->y; + 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; + destD3DBox.front = destBox->z; + destD3DBox.back = destBox->z + destBox->depth; - immediateContext->UpdateSubresource(resource, destSubresource, &destD3DBox, data, + immediateContext->UpdateSubresource(resource->get(), destSubresource, &destD3DBox, data, bufferRowPitch, bufferDepthPitch); } else { - immediateContext->UpdateSubresource(resource, destSubresource, NULL, data, bufferRowPitch, - bufferDepthPitch); + immediateContext->UpdateSubresource(resource->get(), destSubresource, nullptr, data, + bufferRowPitch, bufferDepthPitch); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); +} + +gl::ErrorOrResult TextureStorage11::ensureDropStencilTexture( + const gl::Context *context) +{ + UNIMPLEMENTED(); + return gl::InternalError() << "Drop stencil texture not implemented."; } TextureStorage11_2D::TextureStorage11_2D(Renderer11 *renderer, SwapChain11 *swapchain) - : TextureStorage11(renderer, D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE, 0), + : TextureStorage11(renderer, + D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE, + 0, + swapchain->getRenderTargetInternalFormat()), mTexture(swapchain->getOffscreenTexture()), - mLevelZeroTexture(NULL), - mLevelZeroRenderTarget(NULL), + mLevelZeroTexture(), + mLevelZeroRenderTarget(nullptr), mUseLevelZeroTexture(false), - mSwizzleTexture(NULL) + mSwizzleTexture() { - mTexture->AddRef(); - for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) { - mAssociatedImages[i] = NULL; - mRenderTarget[i] = NULL; - mSwizzleRenderTargets[i] = NULL; + mAssociatedImages[i] = nullptr; + mRenderTarget[i] = nullptr; } D3D11_TEXTURE2D_DESC texDesc; - mTexture->GetDesc(&texDesc); - mMipLevels = texDesc.MipLevels; - mTextureFormat = texDesc.Format; - mTextureWidth = texDesc.Width; + mTexture.getDesc(&texDesc); + mMipLevels = texDesc.MipLevels; + mTextureWidth = texDesc.Width; mTextureHeight = texDesc.Height; - mTextureDepth = 1; - - mInternalFormat = swapchain->GetRenderTargetInternalFormat(); - - 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->getRenderer11DeviceCaps()); - mSwizzleTextureFormat = formatInfo.swizzleTexFormat; - mSwizzleShaderResourceFormat = formatInfo.swizzleSRVFormat; - mSwizzleRenderTargetFormat = formatInfo.swizzleRTVFormat; - - mDepthStencilFormat = DXGI_FORMAT_UNKNOWN; -} - -TextureStorage11_2D::TextureStorage11_2D(Renderer11 *renderer, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels, bool hintLevelZeroOnly) - : TextureStorage11(renderer, - GetTextureBindFlags(internalformat, renderer->getRenderer11DeviceCaps(), renderTarget), - GetTextureMiscFlags(internalformat, renderer->getRenderer11DeviceCaps(), renderTarget, levels)), - mTexture(NULL), - mLevelZeroTexture(NULL), - mLevelZeroRenderTarget(NULL), - mUseLevelZeroTexture(false), - mSwizzleTexture(NULL) + mTextureDepth = 1; + mHasKeyedMutex = (texDesc.MiscFlags & D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX) != 0; +} + +TextureStorage11_2D::TextureStorage11_2D(Renderer11 *renderer, + GLenum internalformat, + bool renderTarget, + GLsizei width, + GLsizei height, + int levels, + bool hintLevelZeroOnly) + : TextureStorage11( + renderer, + GetTextureBindFlags(internalformat, renderer->getRenderer11DeviceCaps(), renderTarget), + GetTextureMiscFlags(internalformat, + renderer->getRenderer11DeviceCaps(), + renderTarget, + levels), + internalformat), + mTexture(), + mHasKeyedMutex(false), + mLevelZeroTexture(), + mLevelZeroRenderTarget(nullptr), + mUseLevelZeroTexture(hintLevelZeroOnly && levels > 1), + mSwizzleTexture() { for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) { - mAssociatedImages[i] = NULL; - mRenderTarget[i] = NULL; - mSwizzleRenderTargets[i] = NULL; + mAssociatedImages[i] = nullptr; + mRenderTarget[i] = nullptr; } - mInternalFormat = internalformat; - - const d3d11::TextureFormat &formatInfo = d3d11::GetTextureFormatInfo(internalformat, renderer->getRenderer11DeviceCaps()); - 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; + d3d11::MakeValidSize(false, mFormatInfo.texFormat, &width, &height, &mTopLevel); + mMipLevels = mTopLevel + levels; + mTextureWidth = width; mTextureHeight = height; - mTextureDepth = 1; + 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; - } + // The LevelZeroOnly hint should only be true if the zero max LOD workaround is active. + ASSERT(!mUseLevelZeroTexture || mRenderer->getWorkarounds().zeroMaxLodWorkaround); } -TextureStorage11_2D::~TextureStorage11_2D() +gl::Error TextureStorage11_2D::onDestroy(const gl::Context *context) { for (unsigned i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) { - if (mAssociatedImages[i] != NULL) + if (mAssociatedImages[i] != nullptr) { - bool imageAssociationCorrect = mAssociatedImages[i]->isAssociatedStorageValid(this); - ASSERT(imageAssociationCorrect); + mAssociatedImages[i]->verifyAssociatedStorageValid(this); - 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 - } - } + // We must let the Images recover their data before we delete it from the + // TextureStorage. + ANGLE_TRY(mAssociatedImages[i]->recoverFromAssociatedStorage(context)); } } - SafeRelease(mTexture); - SafeRelease(mSwizzleTexture); - - SafeRelease(mLevelZeroTexture); - SafeDelete(mLevelZeroRenderTarget); - - for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) + if (mHasKeyedMutex) { - SafeDelete(mRenderTarget[i]); - SafeRelease(mSwizzleRenderTargets[i]); + // If the keyed mutex is released that will unbind it and cause the state cache to become + // desynchronized. + mRenderer->getStateManager()->invalidateBoundViews(); } + + // Invalidate RenderTargets. + InvalidateRenderTargetContainer(context, &mRenderTarget); + InvalidateRenderTarget(context, mLevelZeroRenderTarget.get()); + + return gl::NoError(); +} + +TextureStorage11_2D::~TextureStorage11_2D() +{ } -gl::Error TextureStorage11_2D::copyToStorage(TextureStorage *destStorage) +gl::Error TextureStorage11_2D::copyToStorage(const gl::Context *context, + TextureStorage *destStorage) { ASSERT(destStorage); - TextureStorage11_2D *dest11 = GetAs(destStorage); + TextureStorage11_2D *dest11 = GetAs(destStorage); + ID3D11DeviceContext *immediateContext = mRenderer->getDeviceContext(); 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) + // If either mTexture or mLevelZeroTexture exist, then we need to copy them into the + // corresponding textures in destStorage. + if (mTexture.valid()) { - gl::Error error = dest11->useLevelZeroWorkaroundTexture(false); - if (error.isError()) - { - return error; - } + ANGLE_TRY(dest11->useLevelZeroWorkaroundTexture(context, false)); - ID3D11Resource *destResource = NULL; - error = dest11->getResource(&destResource); - if (error.isError()) - { - return error; - } + const TextureHelper11 *destResource = nullptr; + ANGLE_TRY(dest11->getResource(context, &destResource)); - immediateContext->CopyResource(destResource, mTexture); + immediateContext->CopyResource(destResource->get(), mTexture.get()); } - if (mLevelZeroTexture) + if (mLevelZeroTexture.valid()) { - gl::Error error = dest11->useLevelZeroWorkaroundTexture(true); - if (error.isError()) - { - return error; - } + ANGLE_TRY(dest11->useLevelZeroWorkaroundTexture(context, true)); - ID3D11Resource *destResource = NULL; - error = dest11->getResource(&destResource); - if (error.isError()) - { - return error; - } + const TextureHelper11 *destResource = nullptr; + ANGLE_TRY(dest11->getResource(context, &destResource)); - immediateContext->CopyResource(destResource, mLevelZeroTexture); + immediateContext->CopyResource(destResource->get(), mLevelZeroTexture.get()); } + + return gl::NoError(); } - 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; - } + const TextureHelper11 *sourceResouce = nullptr; + ANGLE_TRY(getResource(context, &sourceResouce)); - ID3D11DeviceContext *immediateContext = mRenderer->getDeviceContext(); - immediateContext->CopyResource(destResource, sourceResouce); - } + const TextureHelper11 *destResource = nullptr; + ANGLE_TRY(dest11->getResource(context, &destResource)); - dest11->invalidateSwizzleCache(); + immediateContext->CopyResource(destResource->get(), sourceResouce->get()); + dest11->markDirty(); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureStorage11_2D::useLevelZeroWorkaroundTexture(bool useLevelZeroTexture) +gl::Error TextureStorage11_2D::useLevelZeroWorkaroundTexture(const gl::Context *context, + bool useLevelZeroTexture) { + bool lastSetting = mUseLevelZeroTexture; + if (useLevelZeroTexture && mMipLevels > 1) { - if (!mUseLevelZeroTexture && mTexture) + if (!mUseLevelZeroTexture && mTexture.valid()) { - gl::Error error = ensureTextureExists(1); - if (error.isError()) - { - return error; - } + ANGLE_TRY(ensureTextureExists(1)); // 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); + ASSERT(mLevelZeroTexture.valid()); + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); + deviceContext->CopySubresourceRegion(mLevelZeroTexture.get(), 0, 0, 0, 0, + mTexture.get(), 0, nullptr); } mUseLevelZeroTexture = true; } else { - if (mUseLevelZeroTexture && mLevelZeroTexture) + if (mUseLevelZeroTexture && mLevelZeroTexture.valid()) { - gl::Error error = ensureTextureExists(mMipLevels); - if (error.isError()) - { - return error; - } + ANGLE_TRY(ensureTextureExists(mMipLevels)); // 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); + ASSERT(mTexture.valid()); + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); + deviceContext->CopySubresourceRegion(mTexture.get(), 0, 0, 0, 0, + mLevelZeroTexture.get(), 0, nullptr); } mUseLevelZeroTexture = false; } - return gl::Error(GL_NO_ERROR); + if (lastSetting != mUseLevelZeroTexture) + { + // Mark everything as dirty to be conservative. + if (mLevelZeroRenderTarget) + { + mLevelZeroRenderTarget->signalDirty(context); + } + for (auto &renderTarget : mRenderTarget) + { + if (renderTarget) + { + renderTarget->signalDirty(context); + } + } + } + + return gl::NoError(); } -void TextureStorage11_2D::associateImage(Image11* image, const gl::ImageIndex &index) +void TextureStorage11_2D::associateImage(Image11 *image, const gl::ImageIndex &index) { - GLint level = index.mipIndex; + const GLint level = index.mipIndex; ASSERT(0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); @@ -965,539 +957,569 @@ void TextureStorage11_2D::associateImage(Image11* image, const gl::ImageIndex &i } } -bool TextureStorage11_2D::isAssociatedImageValid(const gl::ImageIndex &index, Image11* expectedImage) +void TextureStorage11_2D::verifyAssociatedImageValid(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; - } + const GLint level = index.mipIndex; - return false; + ASSERT(0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); + // This validation check should never return false. It means the Image/TextureStorage + // association is broken. + ASSERT(mAssociatedImages[level] == expectedImage); } // disassociateImage allows an Image to end its association with a Storage. -void TextureStorage11_2D::disassociateImage(const gl::ImageIndex &index, Image11* expectedImage) +void TextureStorage11_2D::disassociateImage(const gl::ImageIndex &index, Image11 *expectedImage) { - GLint level = index.mipIndex; + const 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; - } - } + ASSERT(mAssociatedImages[level] == expectedImage); + mAssociatedImages[level] = nullptr; } -// 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) +// 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::Context *context, + const gl::ImageIndex &index, + Image11 *incomingImage) { - GLint level = index.mipIndex; + const 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) + if (mAssociatedImages[level] != nullptr && 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); + // Ensure that the Image is still associated with this TextureStorage. + mAssociatedImages[level]->verifyAssociatedStorageValid(this); - 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; - } - } + // Force the image to recover from storage before its data is overwritten. + // This will reset mAssociatedImages[level] to nullptr too. + ANGLE_TRY(mAssociatedImages[level]->recoverFromAssociatedStorage(context)); } } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureStorage11_2D::getResource(ID3D11Resource **outResource) +gl::Error TextureStorage11_2D::getResource(const gl::Context *context, + const TextureHelper11 **outResource) { if (mUseLevelZeroTexture && mMipLevels > 1) { - gl::Error error = ensureTextureExists(1); - if (error.isError()) - { - return error; - } + ANGLE_TRY(ensureTextureExists(1)); - *outResource = mLevelZeroTexture; - return gl::Error(GL_NO_ERROR); + *outResource = &mLevelZeroTexture; + return gl::NoError(); } - else - { - gl::Error error = ensureTextureExists(mMipLevels); - if (error.isError()) - { - return error; - } - *outResource = mTexture; - return gl::Error(GL_NO_ERROR); - } + ANGLE_TRY(ensureTextureExists(mMipLevels)); + + *outResource = &mTexture; + return gl::NoError(); } -gl::Error TextureStorage11_2D::getMippedResource(ID3D11Resource **outResource) +gl::Error TextureStorage11_2D::getMippedResource(const gl::Context *context, + const TextureHelper11 **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; - } + ANGLE_TRY(ensureTextureExists(mMipLevels)); - *outResource = mTexture; - return gl::Error(GL_NO_ERROR); + *outResource = &mTexture; + return gl::NoError(); } 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; + bool useLevelZeroTexture = mRenderer->getWorkarounds().zeroMaxLodWorkaround + ? (mipLevels == 1) && (mMipLevels > 1) + : false; + TextureHelper11 *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) + if (!outputTexture->valid() && 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.Width = mTextureWidth; // Compressed texture size constraints? + desc.Height = mTextureHeight; + desc.MipLevels = mipLevels; + desc.ArraySize = 1; + desc.Format = mFormatInfo.texFormat; + desc.SampleDesc.Count = 1; desc.SampleDesc.Quality = 0; - desc.Usage = D3D11_USAGE_DEFAULT; - desc.BindFlags = getBindFlags(); - desc.CPUAccessFlags = 0; - desc.MiscFlags = getMiscFlags(); - - 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); - } + desc.Usage = D3D11_USAGE_DEFAULT; + desc.BindFlags = getBindFlags(); + desc.CPUAccessFlags = 0; + desc.MiscFlags = getMiscFlags(); - d3d11::SetDebugName(*outputTexture, "TexStorage2D.Texture"); + ANGLE_TRY(mRenderer->allocateTexture(desc, mFormatInfo, outputTexture)); + outputTexture->setDebugName("TexStorage2D.Texture"); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureStorage11_2D::getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT) +gl::Error TextureStorage11_2D::getRenderTarget(const gl::Context *context, + const gl::ImageIndex &index, + RenderTargetD3D **outRT) { ASSERT(!index.hasLayer()); - int level = index.mipIndex; + const 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->getRenderer11DeviceCaps().featureLevel <= D3D_FEATURE_LEVEL_9_3 && level > 0)); - - if (!mRenderTarget[level]) + // 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->getRenderer11DeviceCaps().featureLevel <= D3D_FEATURE_LEVEL_9_3 && level > 0)); + ASSERT(outRT); + 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; - } + *outRT = mRenderTarget[level].get(); + return gl::NoError(); + } - if (mUseLevelZeroTexture) - { - if (!mLevelZeroRenderTarget) - { - ID3D11Device *device = mRenderer->getDevice(); + if (mRenderer->getWorkarounds().zeroMaxLodWorkaround) + { + ASSERT(index.mipIndex == 0); + ANGLE_TRY(useLevelZeroWorkaroundTexture(context, true)); + } - D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; - rtvDesc.Format = mRenderTargetFormat; - rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; - rtvDesc.Texture2D.MipSlice = mTopLevel + level; + const TextureHelper11 *texture = nullptr; + ANGLE_TRY(getResource(context, &texture)); - ID3D11RenderTargetView *rtv; - HRESULT result = device->CreateRenderTargetView(mLevelZeroTexture, &rtvDesc, &rtv); + const d3d11::SharedSRV *srv = nullptr; + ANGLE_TRY(getSRVLevel(context, level, false, &srv)); - 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)); + const d3d11::SharedSRV *blitSRV = nullptr; + ANGLE_TRY(getSRVLevel(context, level, true, &blitSRV)); - mLevelZeroRenderTarget = new TextureRenderTarget11(rtv, mLevelZeroTexture, NULL, mInternalFormat, getLevelWidth(level), getLevelHeight(level), 1, 0); + if (mUseLevelZeroTexture) + { + if (!mLevelZeroRenderTarget) + { + D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; + rtvDesc.Format = mFormatInfo.rtvFormat; + rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; + rtvDesc.Texture2D.MipSlice = mTopLevel + level; - // RenderTarget will take ownership of these resources - SafeRelease(rtv); - } + d3d11::RenderTargetView rtv; + ANGLE_TRY(mRenderer->allocateResource(rtvDesc, mLevelZeroTexture.get(), &rtv)); - ASSERT(outRT); - *outRT = mLevelZeroRenderTarget; - return gl::Error(GL_NO_ERROR); + mLevelZeroRenderTarget.reset(new TextureRenderTarget11( + std::move(rtv), mLevelZeroTexture, d3d11::SharedSRV(), d3d11::SharedSRV(), + mFormatInfo.internalFormat, getFormatSet(), getLevelWidth(level), + getLevelHeight(level), 1, 0)); } - if (mRenderTargetFormat != DXGI_FORMAT_UNKNOWN) - { - ID3D11Device *device = mRenderer->getDevice(); + *outRT = mLevelZeroRenderTarget.get(); + return gl::NoError(); + } - D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; - rtvDesc.Format = mRenderTargetFormat; - rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; - rtvDesc.Texture2D.MipSlice = mTopLevel + level; + if (mFormatInfo.rtvFormat != DXGI_FORMAT_UNKNOWN) + { + D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; + rtvDesc.Format = mFormatInfo.rtvFormat; + rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; + rtvDesc.Texture2D.MipSlice = mTopLevel + level; - ID3D11RenderTargetView *rtv; - HRESULT result = device->CreateRenderTargetView(texture, &rtvDesc, &rtv); + d3d11::RenderTargetView rtv; + ANGLE_TRY(mRenderer->allocateResource(rtvDesc, texture->get(), &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].reset(new TextureRenderTarget11( + std::move(rtv), *texture, *srv, *blitSRV, mFormatInfo.internalFormat, getFormatSet(), + getLevelWidth(level), getLevelHeight(level), 1, 0)); - mRenderTarget[level] = new TextureRenderTarget11(rtv, texture, srv, mInternalFormat, getLevelWidth(level), getLevelHeight(level), 1, 0); + *outRT = mRenderTarget[level].get(); + return gl::NoError(); + } - // RenderTarget will take ownership of these resources - SafeRelease(rtv); - } - else if (mDepthStencilFormat != DXGI_FORMAT_UNKNOWN) - { - ID3D11Device *device = mRenderer->getDevice(); + ASSERT(mFormatInfo.dsvFormat != DXGI_FORMAT_UNKNOWN); - D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc; - dsvDesc.Format = mDepthStencilFormat; - dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D; - dsvDesc.Texture2D.MipSlice = mTopLevel + level; - dsvDesc.Flags = 0; + D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc; + dsvDesc.Format = mFormatInfo.dsvFormat; + dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D; + dsvDesc.Texture2D.MipSlice = mTopLevel + level; + dsvDesc.Flags = 0; - ID3D11DepthStencilView *dsv; - HRESULT result = device->CreateDepthStencilView(texture, &dsvDesc, &dsv); + d3d11::DepthStencilView dsv; + ANGLE_TRY(mRenderer->allocateResource(dsvDesc, texture->get(), &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].reset(new TextureRenderTarget11( + std::move(dsv), *texture, *srv, mFormatInfo.internalFormat, getFormatSet(), + getLevelWidth(level), getLevelHeight(level), 1, 0)); - mRenderTarget[level] = new TextureRenderTarget11(dsv, texture, srv, mInternalFormat, getLevelWidth(level), getLevelHeight(level), 1, 0); + *outRT = mRenderTarget[level].get(); + return gl::NoError(); +} - // 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 +gl::Error TextureStorage11_2D::createSRV(const gl::Context *context, + int baseLevel, + int mipLevels, + DXGI_FORMAT format, + const TextureHelper11 &texture, + d3d11::SharedSRV *outSRV) { ASSERT(outSRV); D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; - srvDesc.Format = format; - srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; + srvDesc.Format = format; + srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; srvDesc.Texture2D.MostDetailedMip = mTopLevel + baseLevel; - srvDesc.Texture2D.MipLevels = mipLevels; + srvDesc.Texture2D.MipLevels = mipLevels; - ID3D11Resource *srvTexture = texture; + const TextureHelper11 *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. + // 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; + ANGLE_TRY(ensureTextureExists(1)); + srvTexture = &mLevelZeroTexture; } else { ASSERT(mipLevels == static_cast(mMipLevels)); - ASSERT(mTexture != NULL && texture == mTexture); - srvTexture = mTexture; + ASSERT(mTexture.valid() && 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); - } - - d3d11::SetDebugName(*outSRV, "TexStorage2D.SRV"); + ANGLE_TRY(mRenderer->allocateResource(srvDesc, srvTexture->get(), outSRV)); + outSRV->setDebugName("TexStorage2D.SRV"); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureStorage11_2D::getSwizzleTexture(ID3D11Resource **outTexture) +gl::Error TextureStorage11_2D::getSwizzleTexture(const TextureHelper11 **outTexture) { ASSERT(outTexture); - if (!mSwizzleTexture) + if (!mSwizzleTexture.valid()) { - ID3D11Device *device = mRenderer->getDevice(); + const auto &format = mFormatInfo.getSwizzleFormat(mRenderer->getRenderer11DeviceCaps()); D3D11_TEXTURE2D_DESC desc; - desc.Width = mTextureWidth; - desc.Height = mTextureHeight; - desc.MipLevels = mMipLevels; - desc.ArraySize = 1; - desc.Format = mSwizzleTextureFormat; - desc.SampleDesc.Count = 1; + desc.Width = mTextureWidth; + desc.Height = mTextureHeight; + desc.MipLevels = mMipLevels; + desc.ArraySize = 1; + desc.Format = format.texFormat; + 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); - } + desc.Usage = D3D11_USAGE_DEFAULT; + desc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET; + desc.CPUAccessFlags = 0; + desc.MiscFlags = 0; - d3d11::SetDebugName(mSwizzleTexture, "TexStorage2D.SwizzleTexture"); + ANGLE_TRY(mRenderer->allocateTexture(desc, format, &mSwizzleTexture)); + mSwizzleTexture.setDebugName("TexStorage2D.SwizzleTexture"); } - *outTexture = mSwizzleTexture; - return gl::Error(GL_NO_ERROR); + *outTexture = &mSwizzleTexture; + return gl::NoError(); } -gl::Error TextureStorage11_2D::getSwizzleRenderTarget(int mipLevel, ID3D11RenderTargetView **outRTV) +gl::Error TextureStorage11_2D::getSwizzleRenderTarget(int mipLevel, + const d3d11::RenderTargetView **outRTV) { ASSERT(mipLevel >= 0 && mipLevel < getLevelCount()); ASSERT(outRTV); - if (!mSwizzleRenderTargets[mipLevel]) + if (!mSwizzleRenderTargets[mipLevel].valid()) { - ID3D11Resource *swizzleTexture = NULL; - gl::Error error = getSwizzleTexture(&swizzleTexture); - if (error.isError()) - { - return error; - } - - ID3D11Device *device = mRenderer->getDevice(); + const TextureHelper11 *swizzleTexture = nullptr; + ANGLE_TRY(getSwizzleTexture(&swizzleTexture)); D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; - rtvDesc.Format = mSwizzleRenderTargetFormat; - rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; + rtvDesc.Format = + mFormatInfo.getSwizzleFormat(mRenderer->getRenderer11DeviceCaps()).rtvFormat; + 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); - } + ANGLE_TRY(mRenderer->allocateResource(rtvDesc, mSwizzleTexture.get(), + &mSwizzleRenderTargets[mipLevel])); } - *outRTV = mSwizzleRenderTargets[mipLevel]; - return gl::Error(GL_NO_ERROR); + *outRTV = &mSwizzleRenderTargets[mipLevel]; + return gl::NoError(); } -TextureStorage11_EGLImage::TextureStorage11_EGLImage(Renderer11 *renderer, EGLImageD3D *eglImage) - : TextureStorage11(renderer, D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE, 0), - mImage(eglImage), - mCurrentRenderTarget(0), - mSwizzleTexture(nullptr), - mSwizzleRenderTargets(gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS, nullptr) +gl::ErrorOrResult TextureStorage11_2D::ensureDropStencilTexture( + const gl::Context *context) { - RenderTargetD3D *renderTargetD3D = nullptr; - mImage->getRenderTarget(&renderTargetD3D); - RenderTarget11 *renderTarget11 = GetAs(renderTargetD3D); - mCurrentRenderTarget = reinterpret_cast(renderTarget11); - - mMipLevels = 1; - mTextureFormat = renderTarget11->getDXGIFormat(); - mTextureWidth = renderTarget11->getWidth(); - mTextureHeight = renderTarget11->getHeight(); - mTextureDepth = 1; - mInternalFormat = renderTarget11->getInternalFormat(); - - ID3D11ShaderResourceView *srv = renderTarget11->getShaderResourceView(); - D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; - srv->GetDesc(&srvDesc); - mShaderResourceFormat = srvDesc.Format; - - ID3D11RenderTargetView *rtv = renderTarget11->getRenderTargetView(); - if (rtv != nullptr) - { - D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; - rtv->GetDesc(&rtvDesc); - mRenderTargetFormat = rtvDesc.Format; - } - else + if (mDropStencilTexture.valid()) { - mRenderTargetFormat = DXGI_FORMAT_UNKNOWN; + return DropStencil::ALREADY_EXISTS; } - ID3D11DepthStencilView *dsv = renderTarget11->getDepthStencilView(); - if (dsv != nullptr) - { - D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc; - dsv->GetDesc(&dsvDesc); - mDepthStencilFormat = dsvDesc.Format; - } - else - { - mDepthStencilFormat = DXGI_FORMAT_UNKNOWN; - } + D3D11_TEXTURE2D_DESC dropDesc = {}; + dropDesc.ArraySize = 1; + dropDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_DEPTH_STENCIL; + dropDesc.CPUAccessFlags = 0; + dropDesc.Format = DXGI_FORMAT_R32_TYPELESS; + dropDesc.Height = mTextureHeight; + dropDesc.MipLevels = mMipLevels; + dropDesc.MiscFlags = 0; + dropDesc.SampleDesc.Count = 1; + dropDesc.SampleDesc.Quality = 0; + dropDesc.Usage = D3D11_USAGE_DEFAULT; + dropDesc.Width = mTextureWidth; + + const auto &format = + d3d11::Format::Get(GL_DEPTH_COMPONENT32F, mRenderer->getRenderer11DeviceCaps()); + ANGLE_TRY(mRenderer->allocateTexture(dropDesc, format, &mDropStencilTexture)); + mDropStencilTexture.setDebugName("TexStorage2D.DropStencil"); + + ANGLE_TRY(initDropStencilTexture(context, gl::ImageIndexIterator::Make2D(0, mMipLevels))); - const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(mTextureFormat); - const d3d11::TextureFormat &formatInfo = d3d11::GetTextureFormatInfo( - dxgiFormatInfo.internalFormat, mRenderer->getRenderer11DeviceCaps()); - mSwizzleTextureFormat = formatInfo.swizzleTexFormat; - mSwizzleShaderResourceFormat = formatInfo.swizzleSRVFormat; - mSwizzleRenderTargetFormat = formatInfo.swizzleRTVFormat; + return DropStencil::CREATED; } -TextureStorage11_EGLImage::~TextureStorage11_EGLImage() +TextureStorage11_External::TextureStorage11_External( + Renderer11 *renderer, + egl::Stream *stream, + const egl::Stream::GLTextureDescription &glDesc) + : TextureStorage11(renderer, D3D11_BIND_SHADER_RESOURCE, 0, glDesc.internalFormat) { - SafeRelease(mSwizzleTexture); - for (size_t i = 0; i < mSwizzleRenderTargets.size(); i++) - { - SafeRelease(mSwizzleRenderTargets[i]); - } + ASSERT(stream->getProducerType() == egl::Stream::ProducerType::D3D11TextureNV12); + StreamProducerNV12 *producer = static_cast(stream->getImplementation()); + mTexture.set(producer->getD3DTexture(), mFormatInfo); + mSubresourceIndex = producer->getArraySlice(); + mTexture.get()->AddRef(); + mMipLevels = 1; + + D3D11_TEXTURE2D_DESC desc; + mTexture.getDesc(&desc); + mTextureWidth = desc.Width; + mTextureHeight = desc.Height; + mTextureDepth = 1; + mHasKeyedMutex = (desc.MiscFlags & D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX) != 0; } -gl::Error TextureStorage11_EGLImage::getResource(ID3D11Resource **outResource) +gl::Error TextureStorage11_External::onDestroy(const gl::Context *context) { - gl::Error error = checkForUpdatedRenderTarget(); - if (error.isError()) + if (mHasKeyedMutex) { - return error; + // If the keyed mutex is released that will unbind it and cause the state cache to become + // desynchronized. + mRenderer->getStateManager()->invalidateBoundViews(); } - RenderTarget11 *renderTarget11 = nullptr; - error = getImageRenderTarget(&renderTarget11); - if (error.isError()) - { - return error; - } + return gl::NoError(); +} + +TextureStorage11_External::~TextureStorage11_External() +{ +} + +gl::Error TextureStorage11_External::copyToStorage(const gl::Context *context, + TextureStorage *destStorage) +{ + UNIMPLEMENTED(); + return gl::NoError(); +} + +void TextureStorage11_External::associateImage(Image11 *image, const gl::ImageIndex &index) +{ + ASSERT(index.mipIndex == 0); + mAssociatedImage = image; +} + +void TextureStorage11_External::verifyAssociatedImageValid(const gl::ImageIndex &index, + Image11 *expectedImage) +{ + ASSERT(index.mipIndex == 0 && mAssociatedImage == expectedImage); +} - *outResource = renderTarget11->getTexture(); - return gl::Error(GL_NO_ERROR); +void TextureStorage11_External::disassociateImage(const gl::ImageIndex &index, + Image11 *expectedImage) +{ + ASSERT(index.mipIndex == 0); + ASSERT(mAssociatedImage == expectedImage); + mAssociatedImage = nullptr; } -gl::Error TextureStorage11_EGLImage::getSRV(const gl::TextureState &textureState, - ID3D11ShaderResourceView **outSRV) +gl::Error TextureStorage11_External::releaseAssociatedImage(const gl::Context *context, + const gl::ImageIndex &index, + Image11 *incomingImage) { - gl::Error error = checkForUpdatedRenderTarget(); - if (error.isError()) + ASSERT(index.mipIndex == 0); + + if (mAssociatedImage != nullptr && mAssociatedImage != incomingImage) { - return error; + mAssociatedImage->verifyAssociatedStorageValid(this); + + ANGLE_TRY(mAssociatedImage->recoverFromAssociatedStorage(context)); } - return TextureStorage11::getSRV(textureState, outSRV); + return gl::NoError(); +} + +gl::Error TextureStorage11_External::getResource(const gl::Context *context, + const TextureHelper11 **outResource) +{ + *outResource = &mTexture; + return gl::NoError(); +} + +gl::Error TextureStorage11_External::getMippedResource(const gl::Context *context, + const TextureHelper11 **outResource) +{ + *outResource = &mTexture; + return gl::NoError(); +} + +gl::Error TextureStorage11_External::getRenderTarget(const gl::Context *context, + const gl::ImageIndex &index, + RenderTargetD3D **outRT) +{ + // Render targets are not supported for external textures + UNREACHABLE(); + return gl::InternalError(); +} + +gl::Error TextureStorage11_External::createSRV(const gl::Context *context, + int baseLevel, + int mipLevels, + DXGI_FORMAT format, + const TextureHelper11 &texture, + d3d11::SharedSRV *outSRV) +{ + // Since external textures are treates as non-mipmapped textures, we ignore mipmap levels and + // use the specified subresource ID the storage was created with. + ASSERT(mipLevels == 1); + ASSERT(outSRV); + + D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; + srvDesc.Format = format; + srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY; + // subresource index is equal to the mip level for 2D textures + srvDesc.Texture2DArray.MostDetailedMip = 0; + srvDesc.Texture2DArray.MipLevels = 1; + srvDesc.Texture2DArray.FirstArraySlice = mSubresourceIndex; + srvDesc.Texture2DArray.ArraySize = 1; + + ANGLE_TRY(mRenderer->allocateResource(srvDesc, texture.get(), outSRV)); + outSRV->setDebugName("TexStorage2D.SRV"); + + return gl::NoError(); +} + +gl::Error TextureStorage11_External::getSwizzleTexture(const TextureHelper11 **outTexture) +{ + UNIMPLEMENTED(); + return gl::InternalError(); +} + +gl::Error TextureStorage11_External::getSwizzleRenderTarget(int mipLevel, + const d3d11::RenderTargetView **outRTV) +{ + UNIMPLEMENTED(); + return gl::InternalError(); +} + +TextureStorage11_EGLImage::TextureStorage11_EGLImage(Renderer11 *renderer, + EGLImageD3D *eglImage, + RenderTarget11 *renderTarget11) + : TextureStorage11(renderer, + D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE, + 0, + renderTarget11->getInternalFormat()), + mImage(eglImage), + mCurrentRenderTarget(0), + mSwizzleTexture(), + mSwizzleRenderTargets(gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) +{ + mCurrentRenderTarget = reinterpret_cast(renderTarget11); + + mMipLevels = 1; + mTextureWidth = renderTarget11->getWidth(); + mTextureHeight = renderTarget11->getHeight(); + mTextureDepth = 1; +} + +TextureStorage11_EGLImage::~TextureStorage11_EGLImage() +{ +} + +gl::Error TextureStorage11_EGLImage::getResource(const gl::Context *context, + const TextureHelper11 **outResource) +{ + ANGLE_TRY(checkForUpdatedRenderTarget(context)); + + RenderTarget11 *renderTarget11 = nullptr; + ANGLE_TRY(getImageRenderTarget(context, &renderTarget11)); + *outResource = &renderTarget11->getTexture(); + return gl::NoError(); +} + +gl::Error TextureStorage11_EGLImage::getSRV(const gl::Context *context, + const gl::TextureState &textureState, + const d3d11::SharedSRV **outSRV) +{ + ANGLE_TRY(checkForUpdatedRenderTarget(context)); + return TextureStorage11::getSRV(context, textureState, outSRV); } -gl::Error TextureStorage11_EGLImage::getMippedResource(ID3D11Resource **) +gl::Error TextureStorage11_EGLImage::getMippedResource(const gl::Context *context, + const TextureHelper11 **) { // This shouldn't be called unless the zero max LOD workaround is active. // EGL images are unavailable in this configuration. UNREACHABLE(); - return gl::Error(GL_INVALID_OPERATION); + return gl::InternalError(); } -gl::Error TextureStorage11_EGLImage::getRenderTarget(const gl::ImageIndex &index, +gl::Error TextureStorage11_EGLImage::getRenderTarget(const gl::Context *context, + const gl::ImageIndex &index, RenderTargetD3D **outRT) { ASSERT(!index.hasLayer()); ASSERT(index.mipIndex == 0); - UNUSED_ASSERTION_VARIABLE(index); - gl::Error error = checkForUpdatedRenderTarget(); - if (error.isError()) - { - return error; - } + ANGLE_TRY(checkForUpdatedRenderTarget(context)); - return mImage->getRenderTarget(outRT); + return mImage->getRenderTarget(context, outRT); } -gl::Error TextureStorage11_EGLImage::copyToStorage(TextureStorage *destStorage) +gl::Error TextureStorage11_EGLImage::copyToStorage(const gl::Context *context, + TextureStorage *destStorage) { - ID3D11Resource *sourceResouce = nullptr; - gl::Error error = getResource(&sourceResouce); - if (error.isError()) - { - return error; - } + const TextureHelper11 *sourceResouce = nullptr; + ANGLE_TRY(getResource(context, &sourceResouce)); ASSERT(destStorage); TextureStorage11_2D *dest11 = GetAs(destStorage); - ID3D11Resource *destResource = nullptr; - error = dest11->getResource(&destResource); - if (error.isError()) - { - return error; - } + const TextureHelper11 *destResource = nullptr; + ANGLE_TRY(dest11->getResource(context, &destResource)); ID3D11DeviceContext *immediateContext = mRenderer->getDeviceContext(); - immediateContext->CopyResource(destResource, sourceResouce); + immediateContext->CopyResource(destResource->get(), sourceResouce->get()); - dest11->invalidateSwizzleCache(); + dest11->markDirty(); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } void TextureStorage11_EGLImage::associateImage(Image11 *, const gl::ImageIndex &) @@ -1508,36 +1530,37 @@ void TextureStorage11_EGLImage::disassociateImage(const gl::ImageIndex &, Image1 { } -bool TextureStorage11_EGLImage::isAssociatedImageValid(const gl::ImageIndex &, Image11 *) +void TextureStorage11_EGLImage::verifyAssociatedImageValid(const gl::ImageIndex &, Image11 *) { - return false; } -gl::Error TextureStorage11_EGLImage::releaseAssociatedImage(const gl::ImageIndex &, Image11 *) +gl::Error TextureStorage11_EGLImage::releaseAssociatedImage(const gl::Context *context, + const gl::ImageIndex &, + Image11 *) { - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureStorage11_EGLImage::useLevelZeroWorkaroundTexture(bool) +gl::Error TextureStorage11_EGLImage::useLevelZeroWorkaroundTexture(const gl::Context *context, bool) { UNREACHABLE(); - return gl::Error(GL_INVALID_OPERATION); + return gl::InternalError(); } -gl::Error TextureStorage11_EGLImage::getSwizzleTexture(ID3D11Resource **outTexture) +gl::Error TextureStorage11_EGLImage::getSwizzleTexture(const TextureHelper11 **outTexture) { ASSERT(outTexture); - if (!mSwizzleTexture) + if (!mSwizzleTexture.valid()) { - ID3D11Device *device = mRenderer->getDevice(); + const auto &format = mFormatInfo.getSwizzleFormat(mRenderer->getRenderer11DeviceCaps()); D3D11_TEXTURE2D_DESC desc; desc.Width = mTextureWidth; desc.Height = mTextureHeight; desc.MipLevels = mMipLevels; desc.ArraySize = 1; - desc.Format = mSwizzleTextureFormat; + desc.Format = format.texFormat; desc.SampleDesc.Count = 1; desc.SampleDesc.Quality = 0; desc.Usage = D3D11_USAGE_DEFAULT; @@ -1545,68 +1568,43 @@ gl::Error TextureStorage11_EGLImage::getSwizzleTexture(ID3D11Resource **outTextu 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); - } - - d3d11::SetDebugName(mSwizzleTexture, "TexStorageEGLImage.SwizzleTexture"); + ANGLE_TRY(mRenderer->allocateTexture(desc, format, &mSwizzleTexture)); + mSwizzleTexture.setDebugName("TexStorageEGLImage.SwizzleTexture"); } - *outTexture = mSwizzleTexture; - return gl::Error(GL_NO_ERROR); + *outTexture = &mSwizzleTexture; + return gl::NoError(); } gl::Error TextureStorage11_EGLImage::getSwizzleRenderTarget(int mipLevel, - ID3D11RenderTargetView **outRTV) + const d3d11::RenderTargetView **outRTV) { ASSERT(mipLevel >= 0 && mipLevel < getLevelCount()); ASSERT(outRTV); - if (!mSwizzleRenderTargets[mipLevel]) + if (!mSwizzleRenderTargets[mipLevel].valid()) { - ID3D11Resource *swizzleTexture = NULL; - gl::Error error = getSwizzleTexture(&swizzleTexture); - if (error.isError()) - { - return error; - } - - ID3D11Device *device = mRenderer->getDevice(); + const TextureHelper11 *swizzleTexture = nullptr; + ANGLE_TRY(getSwizzleTexture(&swizzleTexture)); D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; - rtvDesc.Format = mSwizzleRenderTargetFormat; + rtvDesc.Format = + mFormatInfo.getSwizzleFormat(mRenderer->getRenderer11DeviceCaps()).rtvFormat; 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); - } + ANGLE_TRY(mRenderer->allocateResource(rtvDesc, mSwizzleTexture.get(), + &mSwizzleRenderTargets[mipLevel])); } - *outRTV = mSwizzleRenderTargets[mipLevel]; - return gl::Error(GL_NO_ERROR); + *outRTV = &mSwizzleRenderTargets[mipLevel]; + return gl::NoError(); } -gl::Error TextureStorage11_EGLImage::checkForUpdatedRenderTarget() +gl::Error TextureStorage11_EGLImage::checkForUpdatedRenderTarget(const gl::Context *context) { RenderTarget11 *renderTarget11 = nullptr; - gl::Error error = getImageRenderTarget(&renderTarget11); - if (error.isError()) - { - return error; - } + ANGLE_TRY(getImageRenderTarget(context, &renderTarget11)); if (mCurrentRenderTarget != reinterpret_cast(renderTarget11)) { @@ -1614,14 +1612,15 @@ gl::Error TextureStorage11_EGLImage::checkForUpdatedRenderTarget() mCurrentRenderTarget = reinterpret_cast(renderTarget11); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureStorage11_EGLImage::createSRV(int baseLevel, +gl::Error TextureStorage11_EGLImage::createSRV(const gl::Context *context, + int baseLevel, int mipLevels, DXGI_FORMAT format, - ID3D11Resource *texture, - ID3D11ShaderResourceView **outSRV) const + const TextureHelper11 &texture, + d3d11::SharedSRV *outSRV) { ASSERT(baseLevel == 0); ASSERT(mipLevels == 1); @@ -1637,163 +1636,129 @@ gl::Error TextureStorage11_EGLImage::createSRV(int baseLevel, srvDesc.Texture2D.MostDetailedMip = mTopLevel + baseLevel; srvDesc.Texture2D.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); - } - - d3d11::SetDebugName(*outSRV, "TexStorageEGLImage.SRV"); + ANGLE_TRY(mRenderer->allocateResource(srvDesc, texture.get(), outSRV)); + outSRV->setDebugName("TexStorageEGLImage.SRV"); } else { RenderTarget11 *renderTarget = nullptr; - gl::Error error = getImageRenderTarget(&renderTarget); - if (error.isError()) - { - return error; - } + ANGLE_TRY(getImageRenderTarget(context, &renderTarget)); ASSERT(texture == renderTarget->getTexture()); - *outSRV = renderTarget->getShaderResourceView(); - (*outSRV)->AddRef(); + *outSRV = renderTarget->getShaderResourceView().makeCopy(); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureStorage11_EGLImage::getImageRenderTarget(RenderTarget11 **outRT) const +gl::Error TextureStorage11_EGLImage::getImageRenderTarget(const gl::Context *context, + RenderTarget11 **outRT) const { RenderTargetD3D *renderTargetD3D = nullptr; - gl::Error error = mImage->getRenderTarget(&renderTargetD3D); - if (error.isError()) - { - return error; - } - + ANGLE_TRY(mImage->getRenderTarget(context, &renderTargetD3D)); *outRT = GetAs(renderTargetD3D); - 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->getRenderer11DeviceCaps(), renderTarget), - GetTextureMiscFlags(internalformat, renderer->getRenderer11DeviceCaps(), renderTarget, levels)) + return gl::NoError(); +} + +TextureStorage11_Cube::TextureStorage11_Cube(Renderer11 *renderer, + GLenum internalformat, + bool renderTarget, + int size, + int levels, + bool hintLevelZeroOnly) + : TextureStorage11( + renderer, + GetTextureBindFlags(internalformat, renderer->getRenderer11DeviceCaps(), renderTarget), + GetTextureMiscFlags(internalformat, + renderer->getRenderer11DeviceCaps(), + renderTarget, + levels), + internalformat), + mTexture(), + mLevelZeroTexture(), + mUseLevelZeroTexture(hintLevelZeroOnly && levels > 1), + mSwizzleTexture() { - 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++) + for (unsigned int face = 0; face < gl::CUBE_FACE_COUNT; face++) { - mAssociatedImages[face][level] = NULL; - mRenderTarget[face][level] = NULL; + mAssociatedImages[face][level] = nullptr; + mRenderTarget[face][level] = nullptr; } } - mLevelZeroTexture = NULL; - mUseLevelZeroTexture = false; - - for (unsigned int face = 0; face < CUBE_FACE_COUNT; face++) + for (unsigned int face = 0; face < gl::CUBE_FACE_COUNT; face++) { - mLevelZeroRenderTarget[face] = NULL; + mLevelZeroRenderTarget[face] = nullptr; } - mInternalFormat = internalformat; - - const d3d11::TextureFormat &formatInfo = d3d11::GetTextureFormatInfo(internalformat, renderer->getRenderer11DeviceCaps()); - 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); + d3d11::MakeValidSize(false, mFormatInfo.texFormat, &size, &height, &mTopLevel); - mMipLevels = mTopLevel + levels; - mTextureWidth = size; + mMipLevels = mTopLevel + levels; + mTextureWidth = size; mTextureHeight = size; - mTextureDepth = 1; + 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; - } + // The LevelZeroOnly hint should only be true if the zero max LOD workaround is active. + ASSERT(!mUseLevelZeroTexture || mRenderer->getWorkarounds().zeroMaxLodWorkaround); } -TextureStorage11_Cube::~TextureStorage11_Cube() +gl::Error TextureStorage11_Cube::onDestroy(const gl::Context *context) { for (unsigned int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) { - for (unsigned int face = 0; face < CUBE_FACE_COUNT; face++) + for (unsigned int face = 0; face < gl::CUBE_FACE_COUNT; face++) { - if (mAssociatedImages[face][level] != NULL) + if (mAssociatedImages[face][level] != nullptr) { - 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(); - } + mAssociatedImages[face][level]->verifyAssociatedStorageValid(this); + + // We must let the Images recover their data before we delete it from the + // TextureStorage. + ANGLE_TRY(mAssociatedImages[face][level]->recoverFromAssociatedStorage(context)); } } } - SafeRelease(mTexture); - SafeRelease(mSwizzleTexture); - SafeRelease(mLevelZeroTexture); - - for (unsigned int face = 0; face < CUBE_FACE_COUNT; face++) + for (auto &faceRenderTargets : mRenderTarget) { - SafeDelete(mLevelZeroRenderTarget[face]); + InvalidateRenderTargetContainer(context, &faceRenderTargets); } + InvalidateRenderTargetContainer(context, &mLevelZeroRenderTarget); - 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]); - } - } + return gl::NoError(); +} + +TextureStorage11_Cube::~TextureStorage11_Cube() +{ } UINT TextureStorage11_Cube::getSubresourceIndex(const gl::ImageIndex &index) const { - if (mRenderer->getWorkarounds().zeroMaxLodWorkaround && mUseLevelZeroTexture && index.mipIndex == 0) + if (mRenderer->getWorkarounds().zeroMaxLodWorkaround && mUseLevelZeroTexture && + index.mipIndex == 0) { - UINT arraySlice = static_cast(index.hasLayer() ? index.layerIndex : 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 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) +gl::Error TextureStorage11_Cube::copyToStorage(const gl::Context *context, + TextureStorage *destStorage) { ASSERT(destStorage); @@ -1803,87 +1768,63 @@ gl::Error TextureStorage11_Cube::copyToStorage(TextureStorage *destStorage) { ID3D11DeviceContext *immediateContext = mRenderer->getDeviceContext(); - // If either mTexture or mLevelZeroTexture exist, then we need to copy them into the corresponding textures in destStorage. - if (mTexture) + // If either mTexture or mLevelZeroTexture exist, then we need to copy them into the + // corresponding textures in destStorage. + if (mTexture.valid()) { - gl::Error error = dest11->useLevelZeroWorkaroundTexture(false); - if (error.isError()) - { - return error; - } + ANGLE_TRY(dest11->useLevelZeroWorkaroundTexture(context, false)); - ID3D11Resource *destResource = NULL; - error = dest11->getResource(&destResource); - if (error.isError()) - { - return error; - } + const TextureHelper11 *destResource = nullptr; + ANGLE_TRY(dest11->getResource(context, &destResource)); - immediateContext->CopyResource(destResource, mTexture); + immediateContext->CopyResource(destResource->get(), mTexture.get()); } - if (mLevelZeroTexture) + if (mLevelZeroTexture.valid()) { - gl::Error error = dest11->useLevelZeroWorkaroundTexture(true); - if (error.isError()) - { - return error; - } + ANGLE_TRY(dest11->useLevelZeroWorkaroundTexture(context, true)); - ID3D11Resource *destResource = NULL; - error = dest11->getResource(&destResource); - if (error.isError()) - { - return error; - } + const TextureHelper11 *destResource = nullptr; + ANGLE_TRY(dest11->getResource(context, &destResource)); - immediateContext->CopyResource(destResource, mLevelZeroTexture); + immediateContext->CopyResource(destResource->get(), mLevelZeroTexture.get()); } } else { - ID3D11Resource *sourceResouce = NULL; - gl::Error error = getResource(&sourceResouce); - if (error.isError()) - { - return error; - } + const TextureHelper11 *sourceResouce = nullptr; + ANGLE_TRY(getResource(context, &sourceResouce)); - ID3D11Resource *destResource = NULL; - error = dest11->getResource(&destResource); - if (error.isError()) - { - return error; - } + const TextureHelper11 *destResource = nullptr; + ANGLE_TRY(dest11->getResource(context, &destResource)); ID3D11DeviceContext *immediateContext = mRenderer->getDeviceContext(); - immediateContext->CopyResource(destResource, sourceResouce); + immediateContext->CopyResource(destResource->get(), sourceResouce->get()); } - dest11->invalidateSwizzleCache(); + dest11->markDirty(); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureStorage11_Cube::useLevelZeroWorkaroundTexture(bool useLevelZeroTexture) +gl::Error TextureStorage11_Cube::useLevelZeroWorkaroundTexture(const gl::Context *context, + bool useLevelZeroTexture) { if (useLevelZeroTexture && mMipLevels > 1) { - if (!mUseLevelZeroTexture && mTexture) + if (!mUseLevelZeroTexture && mTexture.valid()) { - gl::Error error = ensureTextureExists(1); - if (error.isError()) - { - return error; - } + ANGLE_TRY(ensureTextureExists(1)); // Pull data back from the mipped texture if necessary. - ASSERT(mLevelZeroTexture); - ID3D11DeviceContext *context = mRenderer->getDeviceContext(); + ASSERT(mLevelZeroTexture.valid()); + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); for (int face = 0; face < 6; face++) { - context->CopySubresourceRegion(mLevelZeroTexture, D3D11CalcSubresource(0, face, 1), 0, 0, 0, mTexture, face * mMipLevels, NULL); + deviceContext->CopySubresourceRegion(mLevelZeroTexture.get(), + D3D11CalcSubresource(0, face, 1), 0, 0, 0, + mTexture.get(), face * mMipLevels, nullptr); } } @@ -1891,346 +1832,286 @@ gl::Error TextureStorage11_Cube::useLevelZeroWorkaroundTexture(bool useLevelZero } else { - if (mUseLevelZeroTexture && mLevelZeroTexture) + if (mUseLevelZeroTexture && mLevelZeroTexture.valid()) { - gl::Error error = ensureTextureExists(mMipLevels); - if (error.isError()) - { - return error; - } + ANGLE_TRY(ensureTextureExists(mMipLevels)); // Pull data back from the level zero texture if necessary. - ASSERT(mTexture); - ID3D11DeviceContext *context = mRenderer->getDeviceContext(); + ASSERT(mTexture.valid()); + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); for (int face = 0; face < 6; face++) { - context->CopySubresourceRegion(mTexture, D3D11CalcSubresource(0, face, mMipLevels), 0, 0, 0, mLevelZeroTexture, face, NULL); + deviceContext->CopySubresourceRegion(mTexture.get(), + D3D11CalcSubresource(0, face, mMipLevels), 0, + 0, 0, mLevelZeroTexture.get(), face, nullptr); } } mUseLevelZeroTexture = false; } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -void TextureStorage11_Cube::associateImage(Image11* image, const gl::ImageIndex &index) +void TextureStorage11_Cube::associateImage(Image11 *image, const gl::ImageIndex &index) { - GLint level = index.mipIndex; - GLint layerTarget = index.layerIndex; + const GLint level = index.mipIndex; + const GLint layerTarget = index.layerIndex; ASSERT(0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); - ASSERT(0 <= layerTarget && layerTarget < CUBE_FACE_COUNT); + ASSERT(0 <= layerTarget && layerTarget < static_cast(gl::CUBE_FACE_COUNT)); if (0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) { - if (0 <= layerTarget && layerTarget < CUBE_FACE_COUNT) + if (0 <= layerTarget && layerTarget < static_cast(gl::CUBE_FACE_COUNT)) { mAssociatedImages[layerTarget][level] = image; } } } -bool TextureStorage11_Cube::isAssociatedImageValid(const gl::ImageIndex &index, Image11* expectedImage) +void TextureStorage11_Cube::verifyAssociatedImageValid(const gl::ImageIndex &index, + Image11 *expectedImage) { - GLint level = index.mipIndex; - GLint layerTarget = index.layerIndex; + const GLint level = index.mipIndex; + const 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; + ASSERT(0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); + ASSERT(0 <= layerTarget && layerTarget < static_cast(gl::CUBE_FACE_COUNT)); + // This validation check should never return false. It means the Image/TextureStorage + // association is broken. + ASSERT(mAssociatedImages[layerTarget][level] == expectedImage); } // disassociateImage allows an Image to end its association with a Storage. -void TextureStorage11_Cube::disassociateImage(const gl::ImageIndex &index, Image11* expectedImage) +void TextureStorage11_Cube::disassociateImage(const gl::ImageIndex &index, Image11 *expectedImage) { - GLint level = index.mipIndex; - GLint layerTarget = index.layerIndex; + const GLint level = index.mipIndex; + const 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; - } - } - } + ASSERT(0 <= layerTarget && layerTarget < static_cast(gl::CUBE_FACE_COUNT)); + ASSERT(mAssociatedImages[layerTarget][level] == expectedImage); + mAssociatedImages[layerTarget][level] = nullptr; } -// 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) +// 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::Context *context, + const gl::ImageIndex &index, + Image11 *incomingImage) { - GLint level = index.mipIndex; - GLint layerTarget = index.layerIndex; + const GLint level = index.mipIndex; + const GLint layerTarget = index.layerIndex; ASSERT(0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); - ASSERT(0 <= layerTarget && layerTarget < CUBE_FACE_COUNT); + ASSERT(0 <= layerTarget && layerTarget < static_cast(gl::CUBE_FACE_COUNT)); if ((0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)) { - if (0 <= layerTarget && layerTarget < CUBE_FACE_COUNT) + if (0 <= layerTarget && layerTarget < static_cast(gl::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) + if (mAssociatedImages[layerTarget][level] != nullptr && + 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; - } - } + // Ensure that the Image is still associated with this TextureStorage. + mAssociatedImages[layerTarget][level]->verifyAssociatedStorageValid(this); + + // Force the image to recover from storage before its data is overwritten. + // This will reset mAssociatedImages[level] to nullptr too. + ANGLE_TRY( + mAssociatedImages[layerTarget][level]->recoverFromAssociatedStorage(context)); } } } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureStorage11_Cube::getResource(ID3D11Resource **outResource) +gl::Error TextureStorage11_Cube::getResource(const gl::Context *context, + const TextureHelper11 **outResource) { if (mUseLevelZeroTexture && mMipLevels > 1) { - gl::Error error = ensureTextureExists(1); - if (error.isError()) - { - return error; - } - - *outResource = mLevelZeroTexture; - return gl::Error(GL_NO_ERROR); + ANGLE_TRY(ensureTextureExists(1)); + *outResource = &mLevelZeroTexture; + return gl::NoError(); } else { - gl::Error error = ensureTextureExists(mMipLevels); - if (error.isError()) - { - return error; - } - - *outResource = mTexture; - return gl::Error(GL_NO_ERROR); + ANGLE_TRY(ensureTextureExists(mMipLevels)); + *outResource = &mTexture; + return gl::NoError(); } } -gl::Error TextureStorage11_Cube::getMippedResource(ID3D11Resource **outResource) +gl::Error TextureStorage11_Cube::getMippedResource(const gl::Context *context, + const TextureHelper11 **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); + ANGLE_TRY(ensureTextureExists(mMipLevels)); + *outResource = &mTexture; + return gl::NoError(); } 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; + bool useLevelZeroTexture = mRenderer->getWorkarounds().zeroMaxLodWorkaround + ? (mipLevels == 1) && (mMipLevels > 1) + : false; + TextureHelper11 *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) + if (!outputTexture->valid() && 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.Width = mTextureWidth; + desc.Height = mTextureHeight; + desc.MipLevels = mipLevels; + desc.ArraySize = gl::CUBE_FACE_COUNT; + desc.Format = mFormatInfo.texFormat; + 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 | getMiscFlags(); + desc.Usage = D3D11_USAGE_DEFAULT; + desc.BindFlags = getBindFlags(); + desc.CPUAccessFlags = 0; + desc.MiscFlags = D3D11_RESOURCE_MISC_TEXTURECUBE | getMiscFlags(); - HRESULT result = device->CreateTexture2D(&desc, NULL, outputTexture); + ANGLE_TRY(mRenderer->allocateTexture(desc, mFormatInfo, outputTexture)); + outputTexture->setDebugName("TexStorageCube.Texture"); + } - // 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::NoError(); +} + +gl::Error TextureStorage11_Cube::createRenderTargetSRV(const TextureHelper11 &texture, + const gl::ImageIndex &index, + DXGI_FORMAT resourceFormat, + d3d11::SharedSRV *srv) const +{ + D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; + srvDesc.Format = resourceFormat; + srvDesc.Texture2DArray.MostDetailedMip = mTopLevel + index.mipIndex; + srvDesc.Texture2DArray.MipLevels = 1; + srvDesc.Texture2DArray.FirstArraySlice = index.layerIndex; + srvDesc.Texture2DArray.ArraySize = 1; - d3d11::SetDebugName(*outputTexture, "TexStorageCube.Texture"); + if (mRenderer->getRenderer11DeviceCaps().featureLevel <= D3D_FEATURE_LEVEL_10_0) + { + srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBE; + } + else + { + // Will be used with Texture2D sampler, not TextureCube + srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY; } - return gl::Error(GL_NO_ERROR); + ANGLE_TRY(mRenderer->allocateResource(srvDesc, texture.get(), srv)); + return gl::NoError(); } -gl::Error TextureStorage11_Cube::getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT) +gl::Error TextureStorage11_Cube::getRenderTarget(const gl::Context *context, + const gl::ImageIndex &index, + RenderTargetD3D **outRT) { - int faceIndex = index.layerIndex; - int level = index.mipIndex; + const int faceIndex = index.layerIndex; + const int level = index.mipIndex; ASSERT(level >= 0 && level < getLevelCount()); - ASSERT(faceIndex >= 0 && faceIndex < CUBE_FACE_COUNT); + ASSERT(faceIndex >= 0 && faceIndex < static_cast(gl::CUBE_FACE_COUNT)); if (!mRenderTarget[faceIndex][level]) { - ID3D11Device *device = mRenderer->getDevice(); - HRESULT result; - - ID3D11Resource *texture = NULL; - gl::Error error = getResource(&texture); - if (error.isError()) + if (mRenderer->getWorkarounds().zeroMaxLodWorkaround) { - return error; + ASSERT(index.mipIndex == 0); + ANGLE_TRY(useLevelZeroWorkaroundTexture(context, true)); } + const TextureHelper11 *texture = nullptr; + ANGLE_TRY(getResource(context, &texture)); + 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.Format = mFormatInfo.rtvFormat; + rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY; + rtvDesc.Texture2DArray.MipSlice = mTopLevel + level; rtvDesc.Texture2DArray.FirstArraySlice = faceIndex; - rtvDesc.Texture2DArray.ArraySize = 1; + rtvDesc.Texture2DArray.ArraySize = 1; - ID3D11RenderTargetView *rtv; - result = device->CreateRenderTargetView(mLevelZeroTexture, &rtvDesc, &rtv); + d3d11::RenderTargetView rtv; + ANGLE_TRY(mRenderer->allocateResource(rtvDesc, mLevelZeroTexture.get(), &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); + mLevelZeroRenderTarget[faceIndex].reset(new TextureRenderTarget11( + std::move(rtv), mLevelZeroTexture, d3d11::SharedSRV(), d3d11::SharedSRV(), + mFormatInfo.internalFormat, getFormatSet(), getLevelWidth(level), + getLevelHeight(level), 1, 0)); } ASSERT(outRT); - *outRT = mLevelZeroRenderTarget[faceIndex]; - return gl::Error(GL_NO_ERROR); + *outRT = mLevelZeroRenderTarget[faceIndex].get(); + return gl::NoError(); } - 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->getRenderer11DeviceCaps().featureLevel <= D3D_FEATURE_LEVEL_9_3) + d3d11::SharedSRV srv; + ANGLE_TRY(createRenderTargetSRV(*texture, index, mFormatInfo.srvFormat, &srv)); + d3d11::SharedSRV blitSRV; + if (mFormatInfo.blitSRVFormat != mFormatInfo.srvFormat) { - srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBE; + ANGLE_TRY(createRenderTargetSRV(*texture, index, mFormatInfo.blitSRVFormat, &blitSRV)); } else { - srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY; // Will be used with Texture2D sampler, not TextureCube + blitSRV = srv.makeCopy(); } - ID3D11ShaderResourceView *srv; - result = device->CreateShaderResourceView(texture, &srvDesc, &srv); + srv.setDebugName("TexStorageCube.RenderTargetSRV"); - ASSERT(result == E_OUTOFMEMORY || SUCCEEDED(result)); - if (FAILED(result)) + if (mFormatInfo.rtvFormat != DXGI_FORMAT_UNKNOWN) { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal shader resource view for texture storage, result: 0x%X.", result); - } + D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; + rtvDesc.Format = mFormatInfo.rtvFormat; + rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY; + rtvDesc.Texture2DArray.MipSlice = mTopLevel + level; + rtvDesc.Texture2DArray.FirstArraySlice = faceIndex; + rtvDesc.Texture2DArray.ArraySize = 1; - d3d11::SetDebugName(srv, "TexStorageCube.RenderTargetSRV"); + d3d11::RenderTargetView rtv; + ANGLE_TRY(mRenderer->allocateResource(rtvDesc, texture->get(), &rtv)); + rtv.setDebugName("TexStorageCube.RenderTargetRTV"); - if (mRenderTargetFormat != DXGI_FORMAT_UNKNOWN) + mRenderTarget[faceIndex][level].reset(new TextureRenderTarget11( + std::move(rtv), *texture, srv, blitSRV, mFormatInfo.internalFormat, getFormatSet(), + getLevelWidth(level), getLevelHeight(level), 1, 0)); + } + else if (mFormatInfo.dsvFormat != 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; + D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc; + dsvDesc.Format = mFormatInfo.dsvFormat; + dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DARRAY; + dsvDesc.Flags = 0; + dsvDesc.Texture2DArray.MipSlice = mTopLevel + level; + dsvDesc.Texture2DArray.FirstArraySlice = faceIndex; + dsvDesc.Texture2DArray.ArraySize = 1; - ID3D11RenderTargetView *rtv; - result = device->CreateRenderTargetView(texture, &rtvDesc, &rtv); + d3d11::DepthStencilView dsv; + ANGLE_TRY(mRenderer->allocateResource(dsvDesc, texture->get(), &dsv)); + dsv.setDebugName("TexStorageCube.RenderTargetDSV"); - 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); - } - - d3d11::SetDebugName(rtv, "TexStorageCube.RenderTargetRTV"); - - 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); - } - - d3d11::SetDebugName(dsv, "TexStorageCube.RenderTargetDSV"); - - 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); + mRenderTarget[faceIndex][level].reset(new TextureRenderTarget11( + std::move(dsv), *texture, srv, mFormatInfo.internalFormat, getFormatSet(), + getLevelWidth(level), getLevelHeight(level), 1, 0)); } else { @@ -2239,215 +2120,237 @@ gl::Error TextureStorage11_Cube::getRenderTarget(const gl::ImageIndex &index, Re } ASSERT(outRT); - *outRT = mRenderTarget[faceIndex][level]; - return gl::Error(GL_NO_ERROR); + *outRT = mRenderTarget[faceIndex][level].get(); + return gl::NoError(); } -gl::Error TextureStorage11_Cube::createSRV(int baseLevel, int mipLevels, DXGI_FORMAT format, ID3D11Resource *texture, - ID3D11ShaderResourceView **outSRV) const +gl::Error TextureStorage11_Cube::createSRV(const gl::Context *context, + int baseLevel, + int mipLevels, + DXGI_FORMAT format, + const TextureHelper11 &texture, + d3d11::SharedSRV *outSRV) { 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) + // Unnormalized integer cube maps are not supported by DX11; we emulate them as an array of six + // 2D textures + const GLenum componentType = d3d11::GetComponentType(format); + if (componentType == GL_INT || componentType == GL_UNSIGNED_INT) { - srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY; + srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY; srvDesc.Texture2DArray.MostDetailedMip = mTopLevel + baseLevel; srvDesc.Texture2DArray.MipLevels = mipLevels; srvDesc.Texture2DArray.FirstArraySlice = 0; - srvDesc.Texture2DArray.ArraySize = CUBE_FACE_COUNT; + srvDesc.Texture2DArray.ArraySize = gl::CUBE_FACE_COUNT; } else { - srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBE; - srvDesc.TextureCube.MipLevels = mipLevels; + srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBE; + srvDesc.TextureCube.MipLevels = mipLevels; srvDesc.TextureCube.MostDetailedMip = mTopLevel + baseLevel; } - ID3D11Resource *srvTexture = texture; + const TextureHelper11 *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. + // 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; + ANGLE_TRY(ensureTextureExists(1)); + srvTexture = &mLevelZeroTexture; } else { ASSERT(mipLevels == static_cast(mMipLevels)); - ASSERT(mTexture != NULL && texture == mTexture); - srvTexture = mTexture; + ASSERT(mTexture.valid() && texture == mTexture); + srvTexture = &mTexture; } } - ID3D11Device *device = mRenderer->getDevice(); - HRESULT result = device->CreateShaderResourceView(srvTexture, &srvDesc, outSRV); + ANGLE_TRY(mRenderer->allocateResource(srvDesc, srvTexture->get(), outSRV)); + outSRV->setDebugName("TexStorageCube.SRV"); - 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); - } - - d3d11::SetDebugName(*outSRV, "TexStorageCube.SRV"); - - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureStorage11_Cube::getSwizzleTexture(ID3D11Resource **outTexture) +gl::Error TextureStorage11_Cube::getSwizzleTexture(const TextureHelper11 **outTexture) { ASSERT(outTexture); - if (!mSwizzleTexture) + if (!mSwizzleTexture.valid()) { - ID3D11Device *device = mRenderer->getDevice(); + const auto &format = mFormatInfo.getSwizzleFormat(mRenderer->getRenderer11DeviceCaps()); 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.Width = mTextureWidth; + desc.Height = mTextureHeight; + desc.MipLevels = mMipLevels; + desc.ArraySize = gl::CUBE_FACE_COUNT; + desc.Format = format.texFormat; + 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); - } + desc.Usage = D3D11_USAGE_DEFAULT; + desc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET; + desc.CPUAccessFlags = 0; + desc.MiscFlags = D3D11_RESOURCE_MISC_TEXTURECUBE; - d3d11::SetDebugName(*outTexture, "TexStorageCube.SwizzleTexture"); + ANGLE_TRY(mRenderer->allocateTexture(desc, format, &mSwizzleTexture)); + mSwizzleTexture.setDebugName("TexStorageCube.SwizzleTexture"); } - *outTexture = mSwizzleTexture; - return gl::Error(GL_NO_ERROR); + *outTexture = &mSwizzleTexture; + return gl::NoError(); } -gl::Error TextureStorage11_Cube::getSwizzleRenderTarget(int mipLevel, ID3D11RenderTargetView **outRTV) +gl::Error TextureStorage11_Cube::getSwizzleRenderTarget(int mipLevel, + const d3d11::RenderTargetView **outRTV) { ASSERT(mipLevel >= 0 && mipLevel < getLevelCount()); ASSERT(outRTV); - if (!mSwizzleRenderTargets[mipLevel]) + if (!mSwizzleRenderTargets[mipLevel].valid()) { - ID3D11Resource *swizzleTexture = NULL; - gl::Error error = getSwizzleTexture(&swizzleTexture); - if (error.isError()) - { - return error; - } - - ID3D11Device *device = mRenderer->getDevice(); + const TextureHelper11 *swizzleTexture = nullptr; + ANGLE_TRY(getSwizzleTexture(&swizzleTexture)); D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; - rtvDesc.Format = mSwizzleRenderTargetFormat; - rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY; - rtvDesc.Texture2DArray.MipSlice = mTopLevel + mipLevel; + rtvDesc.Format = + mFormatInfo.getSwizzleFormat(mRenderer->getRenderer11DeviceCaps()).rtvFormat; + rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY; + rtvDesc.Texture2DArray.MipSlice = mTopLevel + mipLevel; rtvDesc.Texture2DArray.FirstArraySlice = 0; - rtvDesc.Texture2DArray.ArraySize = CUBE_FACE_COUNT; + rtvDesc.Texture2DArray.ArraySize = gl::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); - } + ANGLE_TRY(mRenderer->allocateResource(rtvDesc, mSwizzleTexture.get(), + &mSwizzleRenderTargets[mipLevel])); } - *outRTV = mSwizzleRenderTargets[mipLevel]; - return gl::Error(GL_NO_ERROR); + *outRTV = &mSwizzleRenderTargets[mipLevel]; + return gl::NoError(); } -TextureStorage11_3D::TextureStorage11_3D(Renderer11 *renderer, GLenum internalformat, bool renderTarget, - GLsizei width, GLsizei height, GLsizei depth, int levels) - : TextureStorage11(renderer, - GetTextureBindFlags(internalformat, renderer->getRenderer11DeviceCaps(), renderTarget), - GetTextureMiscFlags(internalformat, renderer->getRenderer11DeviceCaps(), renderTarget, levels)) +gl::Error TextureStorage11::initDropStencilTexture(const gl::Context *context, + const gl::ImageIndexIterator &it) { - mTexture = NULL; - mSwizzleTexture = NULL; + const TextureHelper11 *sourceTexture = nullptr; + ANGLE_TRY(getResource(context, &sourceTexture)); - for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) + gl::ImageIndexIterator itCopy = it; + + while (itCopy.hasNext()) + { + gl::ImageIndex index = itCopy.next(); + gl::Box wholeArea(0, 0, 0, getLevelWidth(index.mipIndex), getLevelHeight(index.mipIndex), + 1); + gl::Extents wholeSize(wholeArea.width, wholeArea.height, 1); + UINT subresource = getSubresourceIndex(index); + ANGLE_TRY(mRenderer->getBlitter()->copyDepthStencil( + *sourceTexture, subresource, wholeArea, wholeSize, mDropStencilTexture, subresource, + wholeArea, wholeSize, nullptr)); + } + + return gl::NoError(); +} + +gl::ErrorOrResult TextureStorage11_Cube::ensureDropStencilTexture( + const gl::Context *context) +{ + if (mDropStencilTexture.valid()) { - mAssociatedImages[i] = NULL; - mLevelRenderTargets[i] = NULL; - mSwizzleRenderTargets[i] = NULL; + return DropStencil::ALREADY_EXISTS; } - mInternalFormat = internalformat; + D3D11_TEXTURE2D_DESC dropDesc = {}; + dropDesc.ArraySize = 6; + dropDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_DEPTH_STENCIL; + dropDesc.CPUAccessFlags = 0; + dropDesc.Format = DXGI_FORMAT_R32_TYPELESS; + dropDesc.Height = mTextureHeight; + dropDesc.MipLevels = mMipLevels; + dropDesc.MiscFlags = D3D11_RESOURCE_MISC_TEXTURECUBE; + dropDesc.SampleDesc.Count = 1; + dropDesc.SampleDesc.Quality = 0; + dropDesc.Usage = D3D11_USAGE_DEFAULT; + dropDesc.Width = mTextureWidth; - const d3d11::TextureFormat &formatInfo = d3d11::GetTextureFormatInfo(internalformat, renderer->getRenderer11DeviceCaps()); - mTextureFormat = formatInfo.texFormat; - mShaderResourceFormat = formatInfo.srvFormat; - mDepthStencilFormat = formatInfo.dsvFormat; - mRenderTargetFormat = formatInfo.rtvFormat; - mSwizzleTextureFormat = formatInfo.swizzleTexFormat; - mSwizzleShaderResourceFormat = formatInfo.swizzleSRVFormat; - mSwizzleRenderTargetFormat = formatInfo.swizzleRTVFormat; + const auto &format = + d3d11::Format::Get(GL_DEPTH_COMPONENT32F, mRenderer->getRenderer11DeviceCaps()); + ANGLE_TRY(mRenderer->allocateTexture(dropDesc, format, &mDropStencilTexture)); + mDropStencilTexture.setDebugName("TexStorageCube.DropStencil"); + + ANGLE_TRY(initDropStencilTexture(context, gl::ImageIndexIterator::MakeCube(0, mMipLevels))); + + return DropStencil::CREATED; +} + +TextureStorage11_3D::TextureStorage11_3D(Renderer11 *renderer, + GLenum internalformat, + bool renderTarget, + GLsizei width, + GLsizei height, + GLsizei depth, + int levels) + : TextureStorage11( + renderer, + GetTextureBindFlags(internalformat, renderer->getRenderer11DeviceCaps(), renderTarget), + GetTextureMiscFlags(internalformat, + renderer->getRenderer11DeviceCaps(), + renderTarget, + levels), + internalformat) +{ + for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) + { + mAssociatedImages[i] = nullptr; + mLevelRenderTargets[i] = nullptr; + } // adjust size if needed for compressed textures - d3d11::MakeValidSize(false, mTextureFormat, &width, &height, &mTopLevel); + d3d11::MakeValidSize(false, mFormatInfo.texFormat, &width, &height, &mTopLevel); - mMipLevels = mTopLevel + levels; - mTextureWidth = width; + mMipLevels = mTopLevel + levels; + mTextureWidth = width; mTextureHeight = height; - mTextureDepth = depth; + mTextureDepth = depth; } -TextureStorage11_3D::~TextureStorage11_3D() +gl::Error TextureStorage11_3D::onDestroy(const gl::Context *context) { for (unsigned i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) { - if (mAssociatedImages[i] != NULL) + if (mAssociatedImages[i] != nullptr) { - bool imageAssociationCorrect = mAssociatedImages[i]->isAssociatedStorageValid(this); - ASSERT(imageAssociationCorrect); + mAssociatedImages[i]->verifyAssociatedStorageValid(this); - if (imageAssociationCorrect) - { - // We must let the Images recover their data before we delete it from the TextureStorage. - mAssociatedImages[i]->recoverFromAssociatedStorage(); - } + // We must let the Images recover their data before we delete it from the + // TextureStorage. + ANGLE_TRY(mAssociatedImages[i]->recoverFromAssociatedStorage(context)); } } - SafeRelease(mTexture); - SafeRelease(mSwizzleTexture); + InvalidateRenderTargetContainer(context, &mLevelRenderTargets); + InvalidateRenderTargetContainer(context, &mLevelLayerRenderTargets); - for (RenderTargetMap::iterator i = mLevelLayerRenderTargets.begin(); i != mLevelLayerRenderTargets.end(); i++) - { - SafeDelete(i->second); - } - mLevelLayerRenderTargets.clear(); + return gl::NoError(); +} - for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) - { - SafeDelete(mLevelRenderTargets[i]); - SafeRelease(mSwizzleRenderTargets[i]); - } +TextureStorage11_3D::~TextureStorage11_3D() +{ } -void TextureStorage11_3D::associateImage(Image11* image, const gl::ImageIndex &index) +void TextureStorage11_3D::associateImage(Image11 *image, const gl::ImageIndex &index) { - GLint level = index.mipIndex; + const GLint level = index.mipIndex; ASSERT(0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); @@ -2457,676 +2360,796 @@ void TextureStorage11_3D::associateImage(Image11* image, const gl::ImageIndex &i } } -bool TextureStorage11_3D::isAssociatedImageValid(const gl::ImageIndex &index, Image11* expectedImage) +void TextureStorage11_3D::verifyAssociatedImageValid(const gl::ImageIndex &index, + Image11 *expectedImage) { - GLint level = index.mipIndex; + const 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; + ASSERT(0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); + // This validation check should never return false. It means the Image/TextureStorage + // association is broken. + ASSERT(mAssociatedImages[level] == expectedImage); } // disassociateImage allows an Image to end its association with a Storage. -void TextureStorage11_3D::disassociateImage(const gl::ImageIndex &index, Image11* expectedImage) +void TextureStorage11_3D::disassociateImage(const gl::ImageIndex &index, Image11 *expectedImage) { - GLint level = index.mipIndex; + const 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; - } - } + ASSERT(mAssociatedImages[level] == expectedImage); + mAssociatedImages[level] = nullptr; } -// 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) +// 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::Context *context, + const gl::ImageIndex &index, + Image11 *incomingImage) { - GLint level = index.mipIndex; + const 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) + if (mAssociatedImages[level] != nullptr && 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); + // Ensure that the Image is still associated with this TextureStorage. + mAssociatedImages[level]->verifyAssociatedStorageValid(this); - 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; - } - } + // Force the image to recover from storage before its data is overwritten. + // This will reset mAssociatedImages[level] to nullptr too. + ANGLE_TRY(mAssociatedImages[level]->recoverFromAssociatedStorage(context)); } } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureStorage11_3D::getResource(ID3D11Resource **outResource) +gl::Error TextureStorage11_3D::getResource(const gl::Context *context, + const TextureHelper11 **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) + // 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.valid() && 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.Width = mTextureWidth; + desc.Height = mTextureHeight; + desc.Depth = mTextureDepth; + desc.MipLevels = mMipLevels; + desc.Format = mFormatInfo.texFormat; + desc.Usage = D3D11_USAGE_DEFAULT; + desc.BindFlags = getBindFlags(); desc.CPUAccessFlags = 0; - desc.MiscFlags = getMiscFlags(); - - 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); - } + desc.MiscFlags = getMiscFlags(); - d3d11::SetDebugName(mTexture, "TexStorage3D.Texture"); + ANGLE_TRY(mRenderer->allocateTexture(desc, mFormatInfo, &mTexture)); + mTexture.setDebugName("TexStorage3D.Texture"); } - *outResource = mTexture; - return gl::Error(GL_NO_ERROR); + *outResource = &mTexture; + return gl::NoError(); } -gl::Error TextureStorage11_3D::createSRV(int baseLevel, int mipLevels, DXGI_FORMAT format, ID3D11Resource *texture, - ID3D11ShaderResourceView **outSRV) const +gl::Error TextureStorage11_3D::createSRV(const gl::Context *context, + int baseLevel, + int mipLevels, + DXGI_FORMAT format, + const TextureHelper11 &texture, + d3d11::SharedSRV *outSRV) { ASSERT(outSRV); D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; - srvDesc.Format = format; - srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE3D; + srvDesc.Format = format; + srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE3D; srvDesc.Texture3D.MostDetailedMip = baseLevel; - srvDesc.Texture3D.MipLevels = mipLevels; + srvDesc.Texture3D.MipLevels = mipLevels; - ID3D11Device *device = mRenderer->getDevice(); - HRESULT result = device->CreateShaderResourceView(texture, &srvDesc, outSRV); + ANGLE_TRY(mRenderer->allocateResource(srvDesc, texture.get(), outSRV)); + outSRV->setDebugName("TexStorage3D.SRV"); - 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); - } - - d3d11::SetDebugName(*outSRV, "TexStorage3D.SRV"); - - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureStorage11_3D::getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT) +gl::Error TextureStorage11_3D::getRenderTarget(const gl::Context *context, + const gl::ImageIndex &index, + RenderTargetD3D **outRT) { - int mipLevel = index.mipIndex; + const int mipLevel = index.mipIndex; ASSERT(mipLevel >= 0 && mipLevel < getLevelCount()); - ASSERT(mRenderTargetFormat != DXGI_FORMAT_UNKNOWN); + ASSERT(mFormatInfo.rtvFormat != DXGI_FORMAT_UNKNOWN); if (!index.hasLayer()) { if (!mLevelRenderTargets[mipLevel]) { - ID3D11Resource *texture = NULL; - gl::Error error = getResource(&texture); - if (error.isError()) - { - return error; - } + const TextureHelper11 *texture = nullptr; + ANGLE_TRY(getResource(context, &texture)); - ID3D11ShaderResourceView *srv = NULL; - error = getSRVLevel(mipLevel, &srv); - if (error.isError()) - { - return error; - } + const d3d11::SharedSRV *srv = nullptr; + ANGLE_TRY(getSRVLevel(context, mipLevel, false, &srv)); - ID3D11Device *device = mRenderer->getDevice(); + const d3d11::SharedSRV *blitSRV = nullptr; + ANGLE_TRY(getSRVLevel(context, mipLevel, true, &blitSRV)); D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; - rtvDesc.Format = mRenderTargetFormat; - rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE3D; - rtvDesc.Texture3D.MipSlice = mTopLevel + mipLevel; + rtvDesc.Format = mFormatInfo.rtvFormat; + 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); - } - - d3d11::SetDebugName(rtv, "TexStorage3D.RTV"); + rtvDesc.Texture3D.WSize = static_cast(-1); - mLevelRenderTargets[mipLevel] = new TextureRenderTarget11(rtv, texture, srv, mInternalFormat, getLevelWidth(mipLevel), getLevelHeight(mipLevel), getLevelDepth(mipLevel), 0); + d3d11::RenderTargetView rtv; + ANGLE_TRY(mRenderer->allocateResource(rtvDesc, texture->get(), &rtv)); + rtv.setDebugName("TexStorage3D.RTV"); - // RenderTarget will take ownership of these resources - SafeRelease(rtv); + mLevelRenderTargets[mipLevel].reset(new TextureRenderTarget11( + std::move(rtv), *texture, *srv, *blitSRV, mFormatInfo.internalFormat, + getFormatSet(), getLevelWidth(mipLevel), getLevelHeight(mipLevel), + getLevelDepth(mipLevel), 0)); } ASSERT(outRT); - *outRT = mLevelRenderTargets[mipLevel]; - return gl::Error(GL_NO_ERROR); + *outRT = mLevelRenderTargets[mipLevel].get(); + return gl::NoError(); } - 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; + const int layer = index.layerIndex; - 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)); + LevelLayerKey key(mipLevel, layer); + if (mLevelLayerRenderTargets.find(key) == mLevelLayerRenderTargets.end()) + { + const TextureHelper11 *texture = nullptr; + ANGLE_TRY(getResource(context, &texture)); - d3d11::SetDebugName(rtv, "TexStorage3D.LayerRTV"); + // TODO, what kind of SRV is expected here? + const d3d11::SharedSRV srv; + const d3d11::SharedSRV blitSRV; - mLevelLayerRenderTargets[key] = new TextureRenderTarget11(rtv, texture, srv, mInternalFormat, getLevelWidth(mipLevel), getLevelHeight(mipLevel), 1, 0); + D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; + rtvDesc.Format = mFormatInfo.rtvFormat; + rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE3D; + rtvDesc.Texture3D.MipSlice = mTopLevel + mipLevel; + rtvDesc.Texture3D.FirstWSlice = layer; + rtvDesc.Texture3D.WSize = 1; - // RenderTarget will take ownership of these resources - SafeRelease(rtv); - } + d3d11::RenderTargetView rtv; + ANGLE_TRY(mRenderer->allocateResource(rtvDesc, texture->get(), &rtv)); + rtv.setDebugName("TexStorage3D.LayerRTV"); - ASSERT(outRT); - *outRT = mLevelLayerRenderTargets[key]; - return gl::Error(GL_NO_ERROR); + mLevelLayerRenderTargets[key].reset(new TextureRenderTarget11( + std::move(rtv), *texture, srv, blitSRV, mFormatInfo.internalFormat, getFormatSet(), + getLevelWidth(mipLevel), getLevelHeight(mipLevel), 1, 0)); } + + ASSERT(outRT); + *outRT = mLevelLayerRenderTargets[key].get(); + return gl::NoError(); } -gl::Error TextureStorage11_3D::getSwizzleTexture(ID3D11Resource **outTexture) +gl::Error TextureStorage11_3D::getSwizzleTexture(const TextureHelper11 **outTexture) { ASSERT(outTexture); - if (!mSwizzleTexture) + if (!mSwizzleTexture.valid()) { - ID3D11Device *device = mRenderer->getDevice(); + const auto &format = mFormatInfo.getSwizzleFormat(mRenderer->getRenderer11DeviceCaps()); 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.Width = mTextureWidth; + desc.Height = mTextureHeight; + desc.Depth = mTextureDepth; + desc.MipLevels = mMipLevels; + desc.Format = format.texFormat; + 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); - } + desc.MiscFlags = 0; - d3d11::SetDebugName(mSwizzleTexture, "TexStorage3D.SwizzleTexture"); + ANGLE_TRY(mRenderer->allocateTexture(desc, format, &mSwizzleTexture)); + mSwizzleTexture.setDebugName("TexStorage3D.SwizzleTexture"); } - *outTexture = mSwizzleTexture; - return gl::Error(GL_NO_ERROR); + *outTexture = &mSwizzleTexture; + return gl::NoError(); } -gl::Error TextureStorage11_3D::getSwizzleRenderTarget(int mipLevel, ID3D11RenderTargetView **outRTV) +gl::Error TextureStorage11_3D::getSwizzleRenderTarget(int mipLevel, + const d3d11::RenderTargetView **outRTV) { ASSERT(mipLevel >= 0 && mipLevel < getLevelCount()); ASSERT(outRTV); - if (!mSwizzleRenderTargets[mipLevel]) + if (!mSwizzleRenderTargets[mipLevel].valid()) { - ID3D11Resource *swizzleTexture = NULL; - gl::Error error = getSwizzleTexture(&swizzleTexture); - if (error.isError()) - { - return error; - } - - ID3D11Device *device = mRenderer->getDevice(); + const TextureHelper11 *swizzleTexture = nullptr; + ANGLE_TRY(getSwizzleTexture(&swizzleTexture)); D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; - rtvDesc.Format = mSwizzleRenderTargetFormat; - rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE3D; - rtvDesc.Texture3D.MipSlice = mTopLevel + mipLevel; + rtvDesc.Format = + mFormatInfo.getSwizzleFormat(mRenderer->getRenderer11DeviceCaps()).rtvFormat; + rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE3D; + rtvDesc.Texture3D.MipSlice = mTopLevel + mipLevel; rtvDesc.Texture3D.FirstWSlice = 0; - rtvDesc.Texture3D.WSize = static_cast(-1); + 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); - } - - d3d11::SetDebugName(mSwizzleTexture, "TexStorage3D.SwizzleRTV"); + ANGLE_TRY(mRenderer->allocateResource(rtvDesc, mSwizzleTexture.get(), + &mSwizzleRenderTargets[mipLevel])); + mSwizzleRenderTargets[mipLevel].setDebugName("TexStorage3D.SwizzleRTV"); } - *outRTV = mSwizzleRenderTargets[mipLevel]; - return gl::Error(GL_NO_ERROR); + *outRTV = &mSwizzleRenderTargets[mipLevel]; + return gl::NoError(); } -TextureStorage11_2DArray::TextureStorage11_2DArray(Renderer11 *renderer, GLenum internalformat, bool renderTarget, - GLsizei width, GLsizei height, GLsizei depth, int levels) - : TextureStorage11(renderer, - GetTextureBindFlags(internalformat, renderer->getRenderer11DeviceCaps(), renderTarget), - GetTextureMiscFlags(internalformat, renderer->getRenderer11DeviceCaps(), renderTarget, levels)) +TextureStorage11_2DArray::TextureStorage11_2DArray(Renderer11 *renderer, + GLenum internalformat, + bool renderTarget, + GLsizei width, + GLsizei height, + GLsizei depth, + int levels) + : TextureStorage11( + renderer, + GetTextureBindFlags(internalformat, renderer->getRenderer11DeviceCaps(), renderTarget), + GetTextureMiscFlags(internalformat, + renderer->getRenderer11DeviceCaps(), + renderTarget, + levels), + internalformat) { - 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->getRenderer11DeviceCaps()); - 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); + d3d11::MakeValidSize(false, mFormatInfo.texFormat, &width, &height, &mTopLevel); - mMipLevels = mTopLevel + levels; - mTextureWidth = width; + mMipLevels = mTopLevel + levels; + mTextureWidth = width; mTextureHeight = height; - mTextureDepth = depth; + mTextureDepth = depth; } -TextureStorage11_2DArray::~TextureStorage11_2DArray() +gl::Error TextureStorage11_2DArray::onDestroy(const gl::Context *context) { - for (ImageMap::iterator i = mAssociatedImages.begin(); i != mAssociatedImages.end(); i++) + for (auto iter : mAssociatedImages) { - if (i->second) + if (iter.second) { - bool imageAssociationCorrect = i->second->isAssociatedStorageValid(this); - ASSERT(imageAssociationCorrect); + iter.second->verifyAssociatedStorageValid(this); - if (imageAssociationCorrect) - { - // We must let the Images recover their data before we delete it from the TextureStorage. - i->second->recoverFromAssociatedStorage(); - } + // We must let the Images recover their data before we delete it from the + // TextureStorage. + ANGLE_TRY(iter.second->recoverFromAssociatedStorage(context)); } } mAssociatedImages.clear(); - SafeRelease(mTexture); - SafeRelease(mSwizzleTexture); + InvalidateRenderTargetContainer(context, &mRenderTargets); - for (unsigned int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) - { - SafeRelease(mSwizzleRenderTargets[level]); - } + return gl::NoError(); +} - for (RenderTargetMap::iterator i = mRenderTargets.begin(); i != mRenderTargets.end(); i++) - { - SafeDelete(i->second); - } - mRenderTargets.clear(); +TextureStorage11_2DArray::~TextureStorage11_2DArray() +{ } -void TextureStorage11_2DArray::associateImage(Image11* image, const gl::ImageIndex &index) +void TextureStorage11_2DArray::associateImage(Image11 *image, const gl::ImageIndex &index) { - GLint level = index.mipIndex; - GLint layerTarget = index.layerIndex; + const GLint level = index.mipIndex; + const GLint layerTarget = index.layerIndex; + const GLint numLayers = index.numLayers; ASSERT(0 <= level && level < getLevelCount()); if (0 <= level && level < getLevelCount()) { - LevelLayerKey key(level, layerTarget); + LevelLayerRangeKey key(level, layerTarget, numLayers); mAssociatedImages[key] = image; } } -bool TextureStorage11_2DArray::isAssociatedImageValid(const gl::ImageIndex &index, Image11* expectedImage) +void TextureStorage11_2DArray::verifyAssociatedImageValid(const gl::ImageIndex &index, + Image11 *expectedImage) { - GLint level = index.mipIndex; - GLint layerTarget = index.layerIndex; + const GLint level = index.mipIndex; + const GLint layerTarget = index.layerIndex; + const GLint numLayers = index.numLayers; - LevelLayerKey key(level, layerTarget); + LevelLayerRangeKey key(level, layerTarget, numLayers); - // 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)); + // 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) +void TextureStorage11_2DArray::disassociateImage(const gl::ImageIndex &index, + Image11 *expectedImage) { - GLint level = index.mipIndex; - GLint layerTarget = index.layerIndex; + const GLint level = index.mipIndex; + const GLint layerTarget = index.layerIndex; + const GLint numLayers = index.numLayers; - LevelLayerKey key(level, layerTarget); + LevelLayerRangeKey key(level, layerTarget, numLayers); - bool imageAssociationCorrect = (mAssociatedImages.find(key) != mAssociatedImages.end() && (mAssociatedImages[key] == expectedImage)); + bool imageAssociationCorrect = (mAssociatedImages.find(key) != mAssociatedImages.end() && + (mAssociatedImages[key] == expectedImage)); ASSERT(imageAssociationCorrect); - - if (imageAssociationCorrect) - { - mAssociatedImages[key] = NULL; - } + mAssociatedImages[key] = nullptr; } -// 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) +// 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::Context *context, + const gl::ImageIndex &index, + Image11 *incomingImage) { - GLint level = index.mipIndex; - GLint layerTarget = index.layerIndex; + const GLint level = index.mipIndex; + const GLint layerTarget = index.layerIndex; + const GLint numLayers = index.numLayers; - LevelLayerKey key(level, layerTarget); + LevelLayerRangeKey key(level, layerTarget, numLayers); if (mAssociatedImages.find(key) != mAssociatedImages.end()) { - if (mAssociatedImages[key] != NULL && mAssociatedImages[key] != incomingImage) + if (mAssociatedImages[key] != nullptr && 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); + // Ensure that the Image is still associated with this TextureStorage. + mAssociatedImages[key]->verifyAssociatedStorageValid(this); - 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; - } - } + // Force the image to recover from storage before its data is overwritten. + // This will reset mAssociatedImages[level] to nullptr too. + ANGLE_TRY(mAssociatedImages[key]->recoverFromAssociatedStorage(context)); } } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureStorage11_2DArray::getResource(ID3D11Resource **outResource) +gl::Error TextureStorage11_2DArray::getResource(const gl::Context *context, + const TextureHelper11 **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) + if (!mTexture.valid() && 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.Width = mTextureWidth; + desc.Height = mTextureHeight; + desc.MipLevels = mMipLevels; + desc.ArraySize = mTextureDepth; + desc.Format = mFormatInfo.texFormat; + desc.SampleDesc.Count = 1; desc.SampleDesc.Quality = 0; - desc.Usage = D3D11_USAGE_DEFAULT; - desc.BindFlags = getBindFlags(); - desc.CPUAccessFlags = 0; - desc.MiscFlags = getMiscFlags(); - - 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); - } + desc.Usage = D3D11_USAGE_DEFAULT; + desc.BindFlags = getBindFlags(); + desc.CPUAccessFlags = 0; + desc.MiscFlags = getMiscFlags(); - d3d11::SetDebugName(mTexture, "TexStorage2DArray.Texture"); + ANGLE_TRY(mRenderer->allocateTexture(desc, mFormatInfo, &mTexture)); + mTexture.setDebugName("TexStorage2DArray.Texture"); } - *outResource = mTexture; - return gl::Error(GL_NO_ERROR); + *outResource = &mTexture; + return gl::NoError(); } -gl::Error TextureStorage11_2DArray::createSRV(int baseLevel, int mipLevels, DXGI_FORMAT format, ID3D11Resource *texture, - ID3D11ShaderResourceView **outSRV) const +gl::Error TextureStorage11_2DArray::createSRV(const gl::Context *context, + int baseLevel, + int mipLevels, + DXGI_FORMAT format, + const TextureHelper11 &texture, + d3d11::SharedSRV *outSRV) { D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; - srvDesc.Format = format; - srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY; + srvDesc.Format = format; + srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY; srvDesc.Texture2DArray.MostDetailedMip = mTopLevel + baseLevel; - srvDesc.Texture2DArray.MipLevels = mipLevels; + srvDesc.Texture2DArray.MipLevels = mipLevels; srvDesc.Texture2DArray.FirstArraySlice = 0; - srvDesc.Texture2DArray.ArraySize = mTextureDepth; + srvDesc.Texture2DArray.ArraySize = mTextureDepth; - ID3D11Device *device = mRenderer->getDevice(); - HRESULT result = device->CreateShaderResourceView(texture, &srvDesc, outSRV); + ANGLE_TRY(mRenderer->allocateResource(srvDesc, texture.get(), outSRV)); + outSRV->setDebugName("TexStorage2DArray.SRV"); - 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::NoError(); +} + +gl::Error TextureStorage11_2DArray::createRenderTargetSRV(const TextureHelper11 &texture, + const gl::ImageIndex &index, + DXGI_FORMAT resourceFormat, + d3d11::SharedSRV *srv) const +{ + D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; + srvDesc.Format = resourceFormat; + srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY; + srvDesc.Texture2DArray.MostDetailedMip = mTopLevel + index.mipIndex; + srvDesc.Texture2DArray.MipLevels = 1; + srvDesc.Texture2DArray.FirstArraySlice = index.layerIndex; + srvDesc.Texture2DArray.ArraySize = index.numLayers; - d3d11::SetDebugName(*outSRV, "TexStorage2DArray.SRV"); + ANGLE_TRY(mRenderer->allocateResource(srvDesc, texture.get(), srv)); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureStorage11_2DArray::getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT) +gl::Error TextureStorage11_2DArray::getRenderTarget(const gl::Context *context, + const gl::ImageIndex &index, + RenderTargetD3D **outRT) { ASSERT(index.hasLayer()); - int mipLevel = index.mipIndex; - int layer = index.layerIndex; + const int mipLevel = index.mipIndex; + const int layer = index.layerIndex; + const int numLayers = index.numLayers; ASSERT(mipLevel >= 0 && mipLevel < getLevelCount()); - LevelLayerKey key(mipLevel, layer); + LevelLayerRangeKey key(mipLevel, layer, numLayers); if (mRenderTargets.find(key) == mRenderTargets.end()) { - ID3D11Device *device = mRenderer->getDevice(); - HRESULT result; - - ID3D11Resource *texture = NULL; - gl::Error error = getResource(&texture); - if (error.isError()) + const TextureHelper11 *texture = nullptr; + ANGLE_TRY(getResource(context, &texture)); + d3d11::SharedSRV srv; + ANGLE_TRY(createRenderTargetSRV(*texture, index, mFormatInfo.srvFormat, &srv)); + d3d11::SharedSRV blitSRV; + if (mFormatInfo.blitSRVFormat != mFormatInfo.srvFormat) { - return error; + ANGLE_TRY(createRenderTargetSRV(*texture, index, mFormatInfo.blitSRVFormat, &blitSRV)); } - - 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)) + else { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal shader resource view for texture storage, result: 0x%X.", result); + blitSRV = srv.makeCopy(); } - d3d11::SetDebugName(srv, "TexStorage2DArray.RenderTargetSRV"); + srv.setDebugName("TexStorage2DArray.RenderTargetSRV"); - if (mRenderTargetFormat != DXGI_FORMAT_UNKNOWN) + if (mFormatInfo.rtvFormat != DXGI_FORMAT_UNKNOWN) { D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; - rtvDesc.Format = mRenderTargetFormat; - rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY; - rtvDesc.Texture2DArray.MipSlice = mTopLevel + mipLevel; + rtvDesc.Format = mFormatInfo.rtvFormat; + 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); - } + rtvDesc.Texture2DArray.ArraySize = numLayers; - d3d11::SetDebugName(rtv, "TexStorage2DArray.RenderTargetRTV"); + d3d11::RenderTargetView rtv; + ANGLE_TRY(mRenderer->allocateResource(rtvDesc, texture->get(), &rtv)); + rtv.setDebugName("TexStorage2DArray.RenderTargetRTV"); - 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); + mRenderTargets[key].reset(new TextureRenderTarget11( + std::move(rtv), *texture, srv, blitSRV, mFormatInfo.internalFormat, getFormatSet(), + getLevelWidth(mipLevel), getLevelHeight(mipLevel), 1, 0)); } else { - UNREACHABLE(); + ASSERT(mFormatInfo.dsvFormat != DXGI_FORMAT_UNKNOWN); + + D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc; + dsvDesc.Format = mFormatInfo.dsvFormat; + dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DARRAY; + dsvDesc.Texture2DArray.MipSlice = mTopLevel + mipLevel; + dsvDesc.Texture2DArray.FirstArraySlice = layer; + dsvDesc.Texture2DArray.ArraySize = numLayers; + dsvDesc.Flags = 0; + + d3d11::DepthStencilView dsv; + ANGLE_TRY(mRenderer->allocateResource(dsvDesc, texture->get(), &dsv)); + dsv.setDebugName("TexStorage2DArray.RenderTargetDSV"); + + mRenderTargets[key].reset(new TextureRenderTarget11( + std::move(dsv), *texture, srv, mFormatInfo.internalFormat, getFormatSet(), + getLevelWidth(mipLevel), getLevelHeight(mipLevel), 1, 0)); } } ASSERT(outRT); - *outRT = mRenderTargets[key]; - return gl::Error(GL_NO_ERROR); + *outRT = mRenderTargets[key].get(); + return gl::NoError(); } -gl::Error TextureStorage11_2DArray::getSwizzleTexture(ID3D11Resource **outTexture) +gl::Error TextureStorage11_2DArray::getSwizzleTexture(const TextureHelper11 **outTexture) { - if (!mSwizzleTexture) + if (!mSwizzleTexture.valid()) { - ID3D11Device *device = mRenderer->getDevice(); + const auto &format = mFormatInfo.getSwizzleFormat(mRenderer->getRenderer11DeviceCaps()); D3D11_TEXTURE2D_DESC desc; - desc.Width = mTextureWidth; - desc.Height = mTextureHeight; - desc.MipLevels = mMipLevels; - desc.ArraySize = mTextureDepth; - desc.Format = mSwizzleTextureFormat; - desc.SampleDesc.Count = 1; + desc.Width = mTextureWidth; + desc.Height = mTextureHeight; + desc.MipLevels = mMipLevels; + desc.ArraySize = mTextureDepth; + desc.Format = format.texFormat; + 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); - } + desc.Usage = D3D11_USAGE_DEFAULT; + desc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET; + desc.CPUAccessFlags = 0; + desc.MiscFlags = 0; - d3d11::SetDebugName(*outTexture, "TexStorage2DArray.SwizzleTexture"); + ANGLE_TRY(mRenderer->allocateTexture(desc, format, &mSwizzleTexture)); + mSwizzleTexture.setDebugName("TexStorage2DArray.SwizzleTexture"); } - *outTexture = mSwizzleTexture; - return gl::Error(GL_NO_ERROR); + *outTexture = &mSwizzleTexture; + return gl::NoError(); } -gl::Error TextureStorage11_2DArray::getSwizzleRenderTarget(int mipLevel, ID3D11RenderTargetView **outRTV) +gl::Error TextureStorage11_2DArray::getSwizzleRenderTarget(int mipLevel, + const d3d11::RenderTargetView **outRTV) { ASSERT(mipLevel >= 0 && mipLevel < getLevelCount()); ASSERT(outRTV); - if (!mSwizzleRenderTargets[mipLevel]) + if (!mSwizzleRenderTargets[mipLevel].valid()) { - ID3D11Resource *swizzleTexture = NULL; - gl::Error error = getSwizzleTexture(&swizzleTexture); - if (error.isError()) - { - return error; - } - - ID3D11Device *device = mRenderer->getDevice(); + const TextureHelper11 *swizzleTexture = nullptr; + ANGLE_TRY(getSwizzleTexture(&swizzleTexture)); D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; - rtvDesc.Format = mSwizzleRenderTargetFormat; - rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY; - rtvDesc.Texture2DArray.MipSlice = mTopLevel + mipLevel; + rtvDesc.Format = + mFormatInfo.getSwizzleFormat(mRenderer->getRenderer11DeviceCaps()).rtvFormat; + rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY; + rtvDesc.Texture2DArray.MipSlice = mTopLevel + mipLevel; rtvDesc.Texture2DArray.FirstArraySlice = 0; - rtvDesc.Texture2DArray.ArraySize = mTextureDepth; + rtvDesc.Texture2DArray.ArraySize = mTextureDepth; - HRESULT result = device->CreateRenderTargetView(mSwizzleTexture, &rtvDesc, &mSwizzleRenderTargets[mipLevel]); + ANGLE_TRY(mRenderer->allocateResource(rtvDesc, mSwizzleTexture.get(), + &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::NoError(); +} + +gl::ErrorOrResult TextureStorage11_2DArray::ensureDropStencilTexture( + const gl::Context *context) +{ + if (mDropStencilTexture.valid()) + { + return DropStencil::ALREADY_EXISTS; } - *outRTV = mSwizzleRenderTargets[mipLevel]; - return gl::Error(GL_NO_ERROR); + D3D11_TEXTURE2D_DESC dropDesc = {}; + dropDesc.ArraySize = mTextureDepth; + dropDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_DEPTH_STENCIL; + dropDesc.CPUAccessFlags = 0; + dropDesc.Format = DXGI_FORMAT_R32_TYPELESS; + dropDesc.Height = mTextureHeight; + dropDesc.MipLevels = mMipLevels; + dropDesc.MiscFlags = 0; + dropDesc.SampleDesc.Count = 1; + dropDesc.SampleDesc.Quality = 0; + dropDesc.Usage = D3D11_USAGE_DEFAULT; + dropDesc.Width = mTextureWidth; + + const auto &format = + d3d11::Format::Get(GL_DEPTH_COMPONENT32F, mRenderer->getRenderer11DeviceCaps()); + ANGLE_TRY(mRenderer->allocateTexture(dropDesc, format, &mDropStencilTexture)); + mDropStencilTexture.setDebugName("TexStorage2DArray.DropStencil"); + + std::vector layerCounts(mMipLevels, mTextureDepth); + + ANGLE_TRY(initDropStencilTexture( + context, gl::ImageIndexIterator::Make2DArray(0, mMipLevels, layerCounts.data()))); + + return DropStencil::CREATED; } +TextureStorage11_2DMultisample::TextureStorage11_2DMultisample(Renderer11 *renderer, + GLenum internalformat, + GLsizei width, + GLsizei height, + int levels, + int samples, + bool fixedSampleLocations) + : TextureStorage11( + renderer, + GetTextureBindFlags(internalformat, renderer->getRenderer11DeviceCaps(), true), + GetTextureMiscFlags(internalformat, renderer->getRenderer11DeviceCaps(), true, levels), + internalformat), + mTexture(), + mRenderTarget(nullptr) +{ + // adjust size if needed for compressed textures + d3d11::MakeValidSize(false, mFormatInfo.texFormat, &width, &height, &mTopLevel); + + mMipLevels = 1; + mTextureWidth = width; + mTextureHeight = height; + mTextureDepth = 1; + mSamples = samples; + mFixedSampleLocations = fixedSampleLocations; +} + +gl::Error TextureStorage11_2DMultisample::onDestroy(const gl::Context *context) +{ + InvalidateRenderTarget(context, mRenderTarget.get()); + mRenderTarget.reset(); + return gl::NoError(); } + +TextureStorage11_2DMultisample::~TextureStorage11_2DMultisample() +{ +} + +gl::Error TextureStorage11_2DMultisample::copyToStorage(const gl::Context *context, + TextureStorage *destStorage) +{ + UNIMPLEMENTED(); + return gl::InternalError() << "copyToStorage is unimplemented"; +} + +void TextureStorage11_2DMultisample::associateImage(Image11 *image, const gl::ImageIndex &index) +{ +} + +void TextureStorage11_2DMultisample::verifyAssociatedImageValid(const gl::ImageIndex &index, + Image11 *expectedImage) +{ +} + +void TextureStorage11_2DMultisample::disassociateImage(const gl::ImageIndex &index, + Image11 *expectedImage) +{ +} + +gl::Error TextureStorage11_2DMultisample::releaseAssociatedImage(const gl::Context *context, + const gl::ImageIndex &index, + Image11 *incomingImage) +{ + return gl::NoError(); +} + +gl::Error TextureStorage11_2DMultisample::getResource(const gl::Context *context, + const TextureHelper11 **outResource) +{ + ANGLE_TRY(ensureTextureExists(1)); + + *outResource = &mTexture; + return gl::NoError(); +} + +gl::Error TextureStorage11_2DMultisample::ensureTextureExists(int mipLevels) +{ + // For Multisampled textures, mipLevels always equals 1. + ASSERT(mipLevels == 1); + + // 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.valid() && mTextureWidth > 0 && mTextureHeight > 0) + { + D3D11_TEXTURE2D_DESC desc; + ZeroMemory(&desc, sizeof(desc)); + desc.Width = mTextureWidth; // Compressed texture size constraints? + desc.Height = mTextureHeight; + desc.MipLevels = mipLevels; + desc.ArraySize = 1; + desc.Format = mFormatInfo.texFormat; + desc.Usage = D3D11_USAGE_DEFAULT; + desc.BindFlags = getBindFlags(); + desc.CPUAccessFlags = 0; + desc.MiscFlags = getMiscFlags(); + + const gl::TextureCaps &textureCaps = + mRenderer->getNativeTextureCaps().get(mFormatInfo.internalFormat); + GLuint supportedSamples = textureCaps.getNearestSamples(mSamples); + desc.SampleDesc.Count = (supportedSamples == 0) ? 1 : supportedSamples; + desc.SampleDesc.Quality = static_cast(D3D11_STANDARD_MULTISAMPLE_PATTERN); + + ANGLE_TRY(mRenderer->allocateTexture(desc, mFormatInfo, &mTexture)); + mTexture.setDebugName("TexStorage2DMS.Texture"); + } + + return gl::NoError(); +} + +gl::Error TextureStorage11_2DMultisample::getRenderTarget(const gl::Context *context, + const gl::ImageIndex &index, + RenderTargetD3D **outRT) +{ + ASSERT(!index.hasLayer()); + + const int level = index.mipIndex; + ASSERT(level == 0); + + ASSERT(outRT); + if (mRenderTarget) + { + *outRT = mRenderTarget.get(); + return gl::NoError(); + } + + const TextureHelper11 *texture = nullptr; + ANGLE_TRY(getResource(context, &texture)); + + const d3d11::SharedSRV *srv = nullptr; + ANGLE_TRY(getSRVLevel(context, level, false, &srv)); + + const d3d11::SharedSRV *blitSRV = nullptr; + ANGLE_TRY(getSRVLevel(context, level, true, &blitSRV)); + + if (mFormatInfo.rtvFormat != DXGI_FORMAT_UNKNOWN) + { + D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; + rtvDesc.Format = mFormatInfo.rtvFormat; + rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DMS; + + d3d11::RenderTargetView rtv; + ANGLE_TRY(mRenderer->allocateResource(rtvDesc, texture->get(), &rtv)); + + mRenderTarget.reset(new TextureRenderTarget11( + std::move(rtv), *texture, *srv, *blitSRV, mFormatInfo.internalFormat, getFormatSet(), + getLevelWidth(level), getLevelHeight(level), 1, mSamples)); + + *outRT = mRenderTarget.get(); + return gl::NoError(); + } + + ASSERT(mFormatInfo.dsvFormat != DXGI_FORMAT_UNKNOWN); + + D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc; + dsvDesc.Format = mFormatInfo.dsvFormat; + dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DMS; + dsvDesc.Flags = 0; + + d3d11::DepthStencilView dsv; + ANGLE_TRY(mRenderer->allocateResource(dsvDesc, texture->get(), &dsv)); + + mRenderTarget.reset(new TextureRenderTarget11( + std::move(dsv), *texture, *srv, mFormatInfo.internalFormat, getFormatSet(), + getLevelWidth(level), getLevelHeight(level), 1, mSamples)); + + *outRT = mRenderTarget.get(); + return gl::NoError(); +} + +gl::Error TextureStorage11_2DMultisample::createSRV(const gl::Context *context, + int baseLevel, + int mipLevels, + DXGI_FORMAT format, + const TextureHelper11 &texture, + d3d11::SharedSRV *outSRV) +{ + ASSERT(outSRV); + + D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; + srvDesc.Format = format; + srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DMS; + + ANGLE_TRY(mRenderer->allocateResource(srvDesc, texture.get(), outSRV)); + outSRV->setDebugName("TexStorage2DMS.SRV"); + return gl::NoError(); +} + +gl::Error TextureStorage11_2DMultisample::getSwizzleTexture(const TextureHelper11 **outTexture) +{ + UNIMPLEMENTED(); + return gl::InternalError() << "getSwizzleTexture is unimplemented."; +} + +gl::Error TextureStorage11_2DMultisample::getSwizzleRenderTarget( + int mipLevel, + const d3d11::RenderTargetView **outRTV) +{ + UNIMPLEMENTED(); + return gl::InternalError() << "getSwizzleRenderTarget is unimplemented."; +} + +gl::ErrorOrResult +TextureStorage11_2DMultisample::ensureDropStencilTexture(const gl::Context *context) +{ + UNIMPLEMENTED(); + return gl::InternalError() << "Drop stencil texture not implemented."; +} + +} // namespace rx diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/TextureStorage11.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/TextureStorage11.h index a88db2f0af..336aa495a8 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/TextureStorage11.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/TextureStorage11.h @@ -10,10 +10,13 @@ #ifndef LIBANGLE_RENDERER_D3D_D3D11_TEXTURESTORAGE11_H_ #define LIBANGLE_RENDERER_D3D_D3D11_TEXTURESTORAGE11_H_ -#include "libANGLE/Texture.h" #include "libANGLE/Error.h" +#include "libANGLE/Texture.h" #include "libANGLE/renderer/d3d/TextureStorage.h" +#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h" +#include "libANGLE/renderer/d3d/d3d11/texture_format_table.h" +#include #include namespace gl @@ -31,69 +34,111 @@ class SwapChain11; class Image11; struct Renderer11DeviceCaps; +template +using TexLevelArray = std::array; + +template +using CubeFaceArray = std::array; + class TextureStorage11 : public TextureStorage { public: - virtual ~TextureStorage11(); + ~TextureStorage11() override; static DWORD GetTextureBindFlags(GLenum internalFormat, const Renderer11DeviceCaps &renderer11DeviceCaps, bool renderTarget); static DWORD GetTextureMiscFlags(GLenum internalFormat, const Renderer11DeviceCaps &renderer11DeviceCaps, bool renderTarget, int levels); UINT getBindFlags() const; UINT getMiscFlags() const; - - virtual gl::Error getResource(ID3D11Resource **outResource) = 0; - virtual gl::Error getSRV(const gl::TextureState &textureState, - 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; + const d3d11::Format &getFormatSet() const; + gl::Error getSRVLevels(const gl::Context *context, + GLint baseLevel, + GLint maxLevel, + const d3d11::SharedSRV **outSRV); + gl::Error generateSwizzles(const gl::Context *context, const gl::SwizzleState &swizzleTarget); + void markLevelDirty(int mipLevel); + void markDirty(); + + gl::Error updateSubresourceLevel(const gl::Context *context, + const TextureHelper11 &texture, + unsigned int sourceSubresource, + const gl::ImageIndex &index, + const gl::Box ©Area); + + gl::Error copySubresourceLevel(const gl::Context *context, + const TextureHelper11 &dstTexture, + unsigned int dstSubresource, + const gl::ImageIndex &index, + const gl::Box ®ion); + + // TextureStorage virtual functions + int getTopLevel() const override; + bool isRenderTarget() const override; + bool isManaged() const override; bool supportsNativeMipmapFunction() const override; - virtual int getLevelCount() const; + int getLevelCount() const override; + gl::Error generateMipmap(const gl::Context *context, + const gl::ImageIndex &sourceIndex, + const gl::ImageIndex &destIndex) override; + gl::Error copyToStorage(const gl::Context *context, TextureStorage *destStorage) override; + gl::Error setData(const gl::Context *context, + const gl::ImageIndex &index, + ImageD3D *image, + const gl::Box *destBox, + GLenum type, + const gl::PixelUnpackState &unpack, + const uint8_t *pixelData) override; + + virtual gl::Error getSRV(const gl::Context *context, + const gl::TextureState &textureState, + const d3d11::SharedSRV **outSRV); 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 gl::Error getResource(const gl::Context *context, + const TextureHelper11 **outResource) = 0; 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); - - gl::Error getSRVLevels(GLint baseLevel, GLint maxLevel, ID3D11ShaderResourceView **outSRV); + virtual void verifyAssociatedImageValid(const gl::ImageIndex &index, + Image11 *expectedImage) = 0; + virtual gl::Error releaseAssociatedImage(const gl::Context *context, + const gl::ImageIndex &index, + Image11 *incomingImage) = 0; protected: - TextureStorage11(Renderer11 *renderer, UINT bindFlags, UINT miscFlags); + TextureStorage11(Renderer11 *renderer, UINT bindFlags, UINT miscFlags, GLenum internalFormat); 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 getMippedResource(const gl::Context *context, + const TextureHelper11 **outResource); + + virtual gl::Error getSwizzleTexture(const TextureHelper11 **outTexture) = 0; + virtual gl::Error getSwizzleRenderTarget(int mipLevel, + const d3d11::RenderTargetView **outRTV) = 0; + gl::Error getSRVLevel(const gl::Context *context, + int mipLevel, + bool blitSRV, + const d3d11::SharedSRV **outSRV); + + // Get a version of a depth texture with only depth information, not stencil. + enum DropStencil + { + CREATED, + ALREADY_EXISTS + }; + virtual gl::ErrorOrResult ensureDropStencilTexture(const gl::Context *context); + gl::Error initDropStencilTexture(const gl::Context *context, const gl::ImageIndexIterator &it); - virtual gl::Error createSRV(int baseLevel, int mipLevels, DXGI_FORMAT format, ID3D11Resource *texture, - ID3D11ShaderResourceView **outSRV) const = 0; + // The baseLevel parameter should *not* have mTopLevel applied. + virtual gl::Error createSRV(const gl::Context *context, + int baseLevel, + int mipLevels, + DXGI_FORMAT format, + const TextureHelper11 &texture, + d3d11::SharedSRV *outSRV) = 0; - void verifySwizzleExists(GLenum swizzleRed, GLenum swizzleGreen, GLenum swizzleBlue, GLenum swizzleAlpha); + void verifySwizzleExists(const gl::SwizzleState &swizzleState); // Clear all cached non-swizzle SRVs and invalidate the swizzle cache. void clearSRVCache(); @@ -102,32 +147,13 @@ class TextureStorage11 : public TextureStorage 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; + const d3d11::Format &mFormatInfo; 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]; + TexLevelArray mSwizzleCache; + TextureHelper11 mDropStencilTexture; private: const UINT mBindFlags; @@ -135,18 +161,24 @@ class TextureStorage11 : public TextureStorage struct SRVKey { - SRVKey(int baseLevel = 0, int mipLevels = 0, bool swizzle = false); + SRVKey(int baseLevel, int mipLevels, bool swizzle, bool dropStencil); bool operator<(const SRVKey &rhs) const; - int baseLevel; - int mipLevels; - bool swizzle; + int baseLevel = 0; // Without mTopLevel applied. + int mipLevels = 0; + bool swizzle = false; + bool dropStencil = false; }; - typedef std::map SRVCache; + typedef std::map SRVCache; + + gl::Error getCachedOrCreateSRV(const gl::Context *context, + const SRVKey &key, + const d3d11::SharedSRV **outSRV); SRVCache mSrvCache; - ID3D11ShaderResourceView *mLevelSRVs[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; + TexLevelArray mLevelSRVs; + TexLevelArray mLevelBlitSRVs; }; class TextureStorage11_2D : public TextureStorage11 @@ -154,33 +186,48 @@ 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(); + ~TextureStorage11_2D() override; - virtual gl::Error getResource(ID3D11Resource **outResource); - virtual gl::Error getMippedResource(ID3D11Resource **outResource); - virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT); + gl::Error onDestroy(const gl::Context *context) override; - virtual gl::Error copyToStorage(TextureStorage *destStorage); + gl::Error getResource(const gl::Context *context, const TextureHelper11 **outResource) override; + gl::Error getMippedResource(const gl::Context *context, + const TextureHelper11 **outResource) override; + gl::Error getRenderTarget(const gl::Context *context, + const gl::ImageIndex &index, + RenderTargetD3D **outRT) override; - 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); + gl::Error copyToStorage(const gl::Context *context, TextureStorage *destStorage) override; - virtual gl::Error useLevelZeroWorkaroundTexture(bool useLevelZeroTexture); + void associateImage(Image11 *image, const gl::ImageIndex &index) override; + void disassociateImage(const gl::ImageIndex &index, Image11 *expectedImage) override; + void verifyAssociatedImageValid(const gl::ImageIndex &index, Image11 *expectedImage) override; + gl::Error releaseAssociatedImage(const gl::Context *context, + const gl::ImageIndex &index, + Image11 *incomingImage) override; + + gl::Error useLevelZeroWorkaroundTexture(const gl::Context *context, + bool useLevelZeroTexture) override; protected: - virtual gl::Error getSwizzleTexture(ID3D11Resource **outTexture); - virtual gl::Error getSwizzleRenderTarget(int mipLevel, ID3D11RenderTargetView **outRTV); + gl::Error getSwizzleTexture(const TextureHelper11 **outTexture) override; + gl::Error getSwizzleRenderTarget(int mipLevel, const d3d11::RenderTargetView **outRTV) override; + + gl::ErrorOrResult ensureDropStencilTexture(const gl::Context *context) override; gl::Error ensureTextureExists(int mipLevels); private: - virtual gl::Error createSRV(int baseLevel, int mipLevels, DXGI_FORMAT format, ID3D11Resource *texture, - ID3D11ShaderResourceView **outSRV) const; + gl::Error createSRV(const gl::Context *context, + int baseLevel, + int mipLevels, + DXGI_FORMAT format, + const TextureHelper11 &texture, + d3d11::SharedSRV *outSRV) override; - ID3D11Texture2D *mTexture; - RenderTarget11 *mRenderTarget[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; + TextureHelper11 mTexture; + TexLevelArray> mRenderTarget; + bool mHasKeyedMutex; // 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). @@ -191,108 +238,179 @@ class TextureStorage11_2D : public TextureStorage11 // 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; + TextureHelper11 mLevelZeroTexture; + std::unique_ptr mLevelZeroRenderTarget; bool mUseLevelZeroTexture; // Swizzle-related variables - ID3D11Texture2D *mSwizzleTexture; - ID3D11RenderTargetView *mSwizzleRenderTargets[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; + TextureHelper11 mSwizzleTexture; + TexLevelArray mSwizzleRenderTargets; + + TexLevelArray mAssociatedImages; +}; + +class TextureStorage11_External : public TextureStorage11 +{ + public: + TextureStorage11_External(Renderer11 *renderer, + egl::Stream *stream, + const egl::Stream::GLTextureDescription &glDesc); + ~TextureStorage11_External() override; + + gl::Error onDestroy(const gl::Context *context) override; + + gl::Error getResource(const gl::Context *context, const TextureHelper11 **outResource) override; + gl::Error getMippedResource(const gl::Context *context, + const TextureHelper11 **outResource) override; + gl::Error getRenderTarget(const gl::Context *context, + const gl::ImageIndex &index, + RenderTargetD3D **outRT) override; + + gl::Error copyToStorage(const gl::Context *context, TextureStorage *destStorage) override; + + void associateImage(Image11 *image, const gl::ImageIndex &index) override; + void disassociateImage(const gl::ImageIndex &index, Image11 *expectedImage) override; + void verifyAssociatedImageValid(const gl::ImageIndex &index, Image11 *expectedImage) override; + gl::Error releaseAssociatedImage(const gl::Context *context, + const gl::ImageIndex &index, + Image11 *incomingImage) override; + + protected: + gl::Error getSwizzleTexture(const TextureHelper11 **outTexture) override; + gl::Error getSwizzleRenderTarget(int mipLevel, const d3d11::RenderTargetView **outRTV) override; + + private: + gl::Error createSRV(const gl::Context *context, + int baseLevel, + int mipLevels, + DXGI_FORMAT format, + const TextureHelper11 &texture, + d3d11::SharedSRV *outSRV) override; + + TextureHelper11 mTexture; + int mSubresourceIndex; + bool mHasKeyedMutex; - Image11 *mAssociatedImages[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; + Image11 *mAssociatedImage; }; class TextureStorage11_EGLImage final : public TextureStorage11 { public: - TextureStorage11_EGLImage(Renderer11 *renderer, EGLImageD3D *eglImage); + TextureStorage11_EGLImage(Renderer11 *renderer, + EGLImageD3D *eglImage, + RenderTarget11 *renderTarget11); ~TextureStorage11_EGLImage() override; - gl::Error getResource(ID3D11Resource **outResource) override; - gl::Error getSRV(const gl::TextureState &textureState, - ID3D11ShaderResourceView **outSRV) override; - gl::Error getMippedResource(ID3D11Resource **outResource) override; - gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT) override; + gl::Error getResource(const gl::Context *context, const TextureHelper11 **outResource) override; + gl::Error getSRV(const gl::Context *context, + const gl::TextureState &textureState, + const d3d11::SharedSRV **outSRV) override; + gl::Error getMippedResource(const gl::Context *context, + const TextureHelper11 **outResource) override; + gl::Error getRenderTarget(const gl::Context *context, + const gl::ImageIndex &index, + RenderTargetD3D **outRT) override; - gl::Error copyToStorage(TextureStorage *destStorage) override; + gl::Error copyToStorage(const gl::Context *context, TextureStorage *destStorage) override; void associateImage(Image11 *image, const gl::ImageIndex &index) override; void disassociateImage(const gl::ImageIndex &index, Image11 *expectedImage) override; - bool isAssociatedImageValid(const gl::ImageIndex &index, Image11 *expectedImage) override; - gl::Error releaseAssociatedImage(const gl::ImageIndex &index, Image11 *incomingImage) override; + void verifyAssociatedImageValid(const gl::ImageIndex &index, Image11 *expectedImage) override; + gl::Error releaseAssociatedImage(const gl::Context *context, + const gl::ImageIndex &index, + Image11 *incomingImage) override; - gl::Error useLevelZeroWorkaroundTexture(bool useLevelZeroTexture) override; + gl::Error useLevelZeroWorkaroundTexture(const gl::Context *context, + bool useLevelZeroTexture) override; protected: - gl::Error getSwizzleTexture(ID3D11Resource **outTexture) override; - gl::Error getSwizzleRenderTarget(int mipLevel, ID3D11RenderTargetView **outRTV) override; + gl::Error getSwizzleTexture(const TextureHelper11 **outTexture) override; + gl::Error getSwizzleRenderTarget(int mipLevel, const d3d11::RenderTargetView **outRTV) override; private: // Check if the EGL image's render target has been updated due to orphaning and delete // any SRVs and other resources based on the image's old render target. - gl::Error checkForUpdatedRenderTarget(); + gl::Error checkForUpdatedRenderTarget(const gl::Context *context); - gl::Error createSRV(int baseLevel, + gl::Error createSRV(const gl::Context *context, + int baseLevel, int mipLevels, DXGI_FORMAT format, - ID3D11Resource *texture, - ID3D11ShaderResourceView **outSRV) const override; + const TextureHelper11 &texture, + d3d11::SharedSRV *outSRV) override; - gl::Error getImageRenderTarget(RenderTarget11 **outRT) const; + gl::Error getImageRenderTarget(const gl::Context *context, RenderTarget11 **outRT) const; EGLImageD3D *mImage; uintptr_t mCurrentRenderTarget; // Swizzle-related variables - ID3D11Texture2D *mSwizzleTexture; - std::vector mSwizzleRenderTargets; + TextureHelper11 mSwizzleTexture; + std::vector mSwizzleRenderTargets; }; class TextureStorage11_Cube : public TextureStorage11 { public: TextureStorage11_Cube(Renderer11 *renderer, GLenum internalformat, bool renderTarget, int size, int levels, bool hintLevelZeroOnly); - virtual ~TextureStorage11_Cube(); + ~TextureStorage11_Cube() override; - virtual UINT getSubresourceIndex(const gl::ImageIndex &index) const; + gl::Error onDestroy(const gl::Context *context) override; + + UINT getSubresourceIndex(const gl::ImageIndex &index) const override; - virtual gl::Error getResource(ID3D11Resource **outResource); - virtual gl::Error getMippedResource(ID3D11Resource **outResource); - virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT); + gl::Error getResource(const gl::Context *context, const TextureHelper11 **outResource) override; + gl::Error getMippedResource(const gl::Context *context, + const TextureHelper11 **outResource) override; + gl::Error getRenderTarget(const gl::Context *context, + const gl::ImageIndex &index, + RenderTargetD3D **outRT) override; - virtual gl::Error copyToStorage(TextureStorage *destStorage); + gl::Error copyToStorage(const gl::Context *context, TextureStorage *destStorage) override; - 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); + void associateImage(Image11 *image, const gl::ImageIndex &index) override; + void disassociateImage(const gl::ImageIndex &index, Image11 *expectedImage) override; + void verifyAssociatedImageValid(const gl::ImageIndex &index, Image11 *expectedImage) override; + gl::Error releaseAssociatedImage(const gl::Context *context, + const gl::ImageIndex &index, + Image11 *incomingImage) override; - virtual gl::Error useLevelZeroWorkaroundTexture(bool useLevelZeroTexture); + gl::Error useLevelZeroWorkaroundTexture(const gl::Context *context, + bool useLevelZeroTexture) override; protected: - virtual gl::Error getSwizzleTexture(ID3D11Resource **outTexture); - virtual gl::Error getSwizzleRenderTarget(int mipLevel, ID3D11RenderTargetView **outRTV); + gl::Error getSwizzleTexture(const TextureHelper11 **outTexture) override; + gl::Error getSwizzleRenderTarget(int mipLevel, const d3d11::RenderTargetView **outRTV) override; + + gl::ErrorOrResult ensureDropStencilTexture(const gl::Context *context) override; 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; + gl::Error createSRV(const gl::Context *context, + int baseLevel, + int mipLevels, + DXGI_FORMAT format, + const TextureHelper11 &texture, + d3d11::SharedSRV *outSRV) override; + gl::Error createRenderTargetSRV(const TextureHelper11 &texture, + const gl::ImageIndex &index, + DXGI_FORMAT resourceFormat, + d3d11::SharedSRV *srv) const; - ID3D11Texture2D *mTexture; - RenderTarget11 *mRenderTarget[CUBE_FACE_COUNT][gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; + TextureHelper11 mTexture; + CubeFaceArray>> mRenderTarget; // Level-zero workaround members. See TextureStorage11_2D's workaround members for a description. - ID3D11Texture2D *mLevelZeroTexture; - RenderTarget11 *mLevelZeroRenderTarget[CUBE_FACE_COUNT]; + TextureHelper11 mLevelZeroTexture; + CubeFaceArray> mLevelZeroRenderTarget; bool mUseLevelZeroTexture; - ID3D11Texture2D *mSwizzleTexture; - ID3D11RenderTargetView *mSwizzleRenderTargets[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; + TextureHelper11 mSwizzleTexture; + TexLevelArray mSwizzleRenderTargets; - Image11 *mAssociatedImages[CUBE_FACE_COUNT][gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; + CubeFaceArray> mAssociatedImages; }; class TextureStorage11_3D : public TextureStorage11 @@ -300,37 +418,46 @@ 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(); + ~TextureStorage11_3D() override; + + gl::Error onDestroy(const gl::Context *context) override; - virtual gl::Error getResource(ID3D11Resource **outResource); + gl::Error getResource(const gl::Context *context, const TextureHelper11 **outResource) override; // Handles both layer and non-layer RTs - virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT); + gl::Error getRenderTarget(const gl::Context *context, + const gl::ImageIndex &index, + RenderTargetD3D **outRT) override; - 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); + void associateImage(Image11 *image, const gl::ImageIndex &index) override; + void disassociateImage(const gl::ImageIndex &index, Image11 *expectedImage) override; + void verifyAssociatedImageValid(const gl::ImageIndex &index, Image11 *expectedImage) override; + gl::Error releaseAssociatedImage(const gl::Context *context, + const gl::ImageIndex &index, + Image11 *incomingImage) override; protected: - virtual gl::Error getSwizzleTexture(ID3D11Resource **outTexture); - virtual gl::Error getSwizzleRenderTarget(int mipLevel, ID3D11RenderTargetView **outRTV); + gl::Error getSwizzleTexture(const TextureHelper11 **outTexture) override; + gl::Error getSwizzleRenderTarget(int mipLevel, const d3d11::RenderTargetView **outRTV) override; private: - virtual gl::Error createSRV(int baseLevel, int mipLevels, DXGI_FORMAT format, ID3D11Resource *texture, - ID3D11ShaderResourceView **outSRV) const; + gl::Error createSRV(const gl::Context *context, + int baseLevel, + int mipLevels, + DXGI_FORMAT format, + const TextureHelper11 &texture, + d3d11::SharedSRV *outSRV) override; typedef std::pair LevelLayerKey; - typedef std::map RenderTargetMap; - RenderTargetMap mLevelLayerRenderTargets; + std::map> mLevelLayerRenderTargets; - RenderTarget11 *mLevelRenderTargets[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; + TexLevelArray> mLevelRenderTargets; - ID3D11Texture3D *mTexture; - ID3D11Texture3D *mSwizzleTexture; - ID3D11RenderTargetView *mSwizzleRenderTargets[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; + TextureHelper11 mTexture; + TextureHelper11 mSwizzleTexture; + TexLevelArray mSwizzleRenderTargets; - Image11 *mAssociatedImages[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; + TexLevelArray mAssociatedImages; }; class TextureStorage11_2DArray : public TextureStorage11 @@ -338,37 +465,125 @@ 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(); + ~TextureStorage11_2DArray() override; + + gl::Error onDestroy(const gl::Context *context) override; - virtual gl::Error getResource(ID3D11Resource **outResource); - virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT); + gl::Error getResource(const gl::Context *context, const TextureHelper11 **outResource) override; + gl::Error getRenderTarget(const gl::Context *context, + const gl::ImageIndex &index, + RenderTargetD3D **outRT) override; - 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); + void associateImage(Image11 *image, const gl::ImageIndex &index) override; + void disassociateImage(const gl::ImageIndex &index, Image11 *expectedImage) override; + void verifyAssociatedImageValid(const gl::ImageIndex &index, Image11 *expectedImage) override; + gl::Error releaseAssociatedImage(const gl::Context *context, + const gl::ImageIndex &index, + Image11 *incomingImage) override; protected: - virtual gl::Error getSwizzleTexture(ID3D11Resource **outTexture); - virtual gl::Error getSwizzleRenderTarget(int mipLevel, ID3D11RenderTargetView **outRTV); + gl::Error getSwizzleTexture(const TextureHelper11 **outTexture) override; + gl::Error getSwizzleRenderTarget(int mipLevel, const d3d11::RenderTargetView **outRTV) override; + + gl::ErrorOrResult ensureDropStencilTexture(const gl::Context *context) override; private: - virtual gl::Error createSRV(int baseLevel, int mipLevels, DXGI_FORMAT format, ID3D11Resource *texture, - ID3D11ShaderResourceView **outSRV) const; + struct LevelLayerRangeKey + { + LevelLayerRangeKey(int mipLevelIn, int layerIn, int numLayersIn) + : mipLevel(mipLevelIn), layer(layerIn), numLayers(numLayersIn) + { + } + bool operator<(const LevelLayerRangeKey &other) const + { + if (mipLevel != other.mipLevel) + { + return mipLevel < other.mipLevel; + } + if (layer != other.layer) + { + return layer < other.layer; + } + return numLayers < other.numLayers; + } + int mipLevel; + int layer; + int numLayers; + }; - typedef std::pair LevelLayerKey; - typedef std::map RenderTargetMap; - RenderTargetMap mRenderTargets; + private: + gl::Error createSRV(const gl::Context *context, + int baseLevel, + int mipLevels, + DXGI_FORMAT format, + const TextureHelper11 &texture, + d3d11::SharedSRV *outSRV) override; + gl::Error createRenderTargetSRV(const TextureHelper11 &texture, + const gl::ImageIndex &index, + DXGI_FORMAT resourceFormat, + d3d11::SharedSRV *srv) const; + + std::map> mRenderTargets; - ID3D11Texture2D *mTexture; + TextureHelper11 mTexture; - ID3D11Texture2D *mSwizzleTexture; - ID3D11RenderTargetView *mSwizzleRenderTargets[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; + TextureHelper11 mSwizzleTexture; + TexLevelArray mSwizzleRenderTargets; - typedef std::map ImageMap; + typedef std::map ImageMap; ImageMap mAssociatedImages; }; +class TextureStorage11_2DMultisample : public TextureStorage11 +{ + public: + TextureStorage11_2DMultisample(Renderer11 *renderer, + GLenum internalformat, + GLsizei width, + GLsizei height, + int levels, + int samples, + bool fixedSampleLocations); + ~TextureStorage11_2DMultisample() override; + + gl::Error onDestroy(const gl::Context *context) override; + + gl::Error getResource(const gl::Context *context, const TextureHelper11 **outResource) override; + gl::Error getRenderTarget(const gl::Context *context, + const gl::ImageIndex &index, + RenderTargetD3D **outRT) override; + + gl::Error copyToStorage(const gl::Context *context, TextureStorage *destStorage) override; + + void associateImage(Image11 *image, const gl::ImageIndex &index) override; + void disassociateImage(const gl::ImageIndex &index, Image11 *expectedImage) override; + void verifyAssociatedImageValid(const gl::ImageIndex &index, Image11 *expectedImage) override; + gl::Error releaseAssociatedImage(const gl::Context *context, + const gl::ImageIndex &index, + Image11 *incomingImage) override; + + protected: + gl::Error getSwizzleTexture(const TextureHelper11 **outTexture) override; + gl::Error getSwizzleRenderTarget(int mipLevel, const d3d11::RenderTargetView **outRTV) override; + + gl::ErrorOrResult ensureDropStencilTexture(const gl::Context *context) override; + + gl::Error ensureTextureExists(int mipLevels); + + private: + gl::Error createSRV(const gl::Context *context, + int baseLevel, + int mipLevels, + DXGI_FORMAT format, + const TextureHelper11 &texture, + d3d11::SharedSRV *outSRV) override; + + TextureHelper11 mTexture; + std::unique_ptr mRenderTarget; + + unsigned int mSamples; + GLboolean mFixedSampleLocations; +}; } #endif // LIBANGLE_RENDERER_D3D_D3D11_TEXTURESTORAGE11_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/TransformFeedback11.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/TransformFeedback11.cpp new file mode 100644 index 0000000000..4b08edf71f --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/TransformFeedback11.cpp @@ -0,0 +1,124 @@ +// +// 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/d3d11/TransformFeedback11.h" + +#include "libANGLE/Buffer.h" +#include "libANGLE/renderer/d3d/d3d11/Buffer11.h" +#include "libANGLE/renderer/d3d/d3d11/Renderer11.h" + +namespace rx +{ + +TransformFeedback11::TransformFeedback11(const gl::TransformFeedbackState &state, + Renderer11 *renderer) + : TransformFeedbackImpl(state), + mRenderer(renderer), + mIsDirty(true), + mBuffers(state.getIndexedBuffers().size(), nullptr), + mBufferOffsets(state.getIndexedBuffers().size(), 0), + mSerial(mRenderer->generateSerial()) +{ +} + +TransformFeedback11::~TransformFeedback11() +{ +} + +void TransformFeedback11::begin(GLenum primitiveMode) +{ + // Reset all the cached offsets to the binding offsets + mIsDirty = true; + for (size_t bindingIdx = 0; bindingIdx < mBuffers.size(); bindingIdx++) + { + const auto &binding = mState.getIndexedBuffer(bindingIdx); + if (binding.get() != nullptr) + { + mBufferOffsets[bindingIdx] = static_cast(binding.getOffset()); + } + else + { + mBufferOffsets[bindingIdx] = 0; + } + } +} + +void TransformFeedback11::end() +{ + if (mRenderer->getWorkarounds().flushAfterEndingTransformFeedback) + { + mRenderer->getDeviceContext()->Flush(); + } +} + +void TransformFeedback11::pause() +{ +} + +void TransformFeedback11::resume() +{ +} + +void TransformFeedback11::bindGenericBuffer(const gl::BindingPointer &binding) +{ +} + +void TransformFeedback11::bindIndexedBuffer(size_t index, + const gl::OffsetBindingPointer &binding) +{ + mIsDirty = true; + mBufferOffsets[index] = static_cast(binding.getOffset()); +} + +void TransformFeedback11::onApply() +{ + mIsDirty = false; + + // Change all buffer offsets to -1 so that if any of them need to be re-applied, the are set to + // append + std::fill(mBufferOffsets.begin(), mBufferOffsets.end(), -1); +} + +bool TransformFeedback11::isDirty() const +{ + return mIsDirty; +} + +UINT TransformFeedback11::getNumSOBuffers() const +{ + return static_cast(mBuffers.size()); +} + +gl::ErrorOrResult *> TransformFeedback11::getSOBuffers( + const gl::Context *context) +{ + for (size_t bindingIdx = 0; bindingIdx < mBuffers.size(); bindingIdx++) + { + const auto &binding = mState.getIndexedBuffer(bindingIdx); + if (binding.get() != nullptr) + { + Buffer11 *storage = GetImplAs(binding.get()); + ANGLE_TRY_RESULT(storage->getBuffer(context, BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK), + mBuffers[bindingIdx]); + } + } + + return &mBuffers; +} + +const std::vector &TransformFeedback11::getSOBufferOffsets() const +{ + return mBufferOffsets; +} + +Serial TransformFeedback11::getSerial() const +{ + return mSerial; +} + +} // namespace rx diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/TransformFeedback11.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/TransformFeedback11.h new file mode 100644 index 0000000000..cc9fcc335a --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/TransformFeedback11.h @@ -0,0 +1,60 @@ +// +// 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. +// + +// TransformFeedback11.h: Implements the abstract rx::TransformFeedbackImpl class. + +#ifndef LIBANGLE_RENDERER_D3D_D3D11_TRANSFORMFEEDBACK11_H_ +#define LIBANGLE_RENDERER_D3D_D3D11_TRANSFORMFEEDBACK11_H_ + +#include "common/platform.h" + +#include "libANGLE/Error.h" +#include "libANGLE/angletypes.h" +#include "libANGLE/renderer/TransformFeedbackImpl.h" +#include "libANGLE/renderer/renderer_utils.h" + +namespace rx +{ + +class Renderer11; + +class TransformFeedback11 : public TransformFeedbackImpl +{ + public: + TransformFeedback11(const gl::TransformFeedbackState &state, Renderer11 *renderer); + ~TransformFeedback11() override; + + void begin(GLenum primitiveMode) override; + void end() override; + void pause() override; + void resume() override; + + void bindGenericBuffer(const gl::BindingPointer &binding) override; + void bindIndexedBuffer(size_t index, + const gl::OffsetBindingPointer &binding) override; + + void onApply(); + + bool isDirty() const; + + UINT getNumSOBuffers() const; + gl::ErrorOrResult *> getSOBuffers(const gl::Context *context); + const std::vector &getSOBufferOffsets() const; + + Serial getSerial() const; + + private: + Renderer11 *mRenderer; + + bool mIsDirty; + std::vector mBuffers; + std::vector mBufferOffsets; + + Serial mSerial; +}; +} // namespace rx + +#endif // LIBANGLE_RENDERER_D3D_D3D11_TRANSFORMFEEDBACK11_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 index 213ce31817..29185a9d93 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Trim11.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Trim11.cpp @@ -11,9 +11,15 @@ #include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h" #if defined (ANGLE_ENABLE_WINDOWS_STORE) -using namespace ABI::Windows::Foundation; +#include +#include +#include +using namespace Microsoft::WRL; +using namespace Microsoft::WRL::Wrappers; using namespace ABI::Windows::ApplicationModel; using namespace ABI::Windows::ApplicationModel::Core; +using namespace ABI::Windows::Foundation; +using namespace ABI::Windows::Foundation::Collections; #endif namespace rx @@ -41,7 +47,6 @@ void Trim11::trim() #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) { diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Trim11.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Trim11.h index 4741e81601..69fa05a57b 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Trim11.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Trim11.h @@ -13,9 +13,7 @@ #include "libANGLE/angletypes.h" #include "libANGLE/Error.h" -#if !defined(ANGLE_ENABLE_WINDOWS_STORE) -typedef void* EventRegistrationToken; -#else +#if defined(ANGLE_ENABLE_WINDOWS_STORE) #include #endif diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/VertexArray11.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/VertexArray11.cpp new file mode 100644 index 0000000000..97c29415ed --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/VertexArray11.cpp @@ -0,0 +1,413 @@ +// +// Copyright 2016 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: +// Implementation of rx::VertexArray11. +// + +#include "libANGLE/renderer/d3d/d3d11/VertexArray11.h" + +#include "common/bitset_utils.h" +#include "libANGLE/Context.h" +#include "libANGLE/renderer/d3d/d3d11/Buffer11.h" +#include "libANGLE/renderer/d3d/d3d11/Context11.h" + +using namespace angle; + +namespace rx +{ + +namespace +{ +OnBufferDataDirtyChannel *GetBufferBroadcastChannel(Buffer11 *buffer11, + IndexStorageType storageType) +{ + switch (storageType) + { + case IndexStorageType::Direct: + return buffer11->getDirectBroadcastChannel(); + case IndexStorageType::Static: + return buffer11->getStaticBroadcastChannel(); + case IndexStorageType::Dynamic: + return buffer11 ? buffer11->getStaticBroadcastChannel() : nullptr; + default: + UNREACHABLE(); + return nullptr; + } +} +} // anonymous namespace + +VertexArray11::VertexArray11(const gl::VertexArrayState &data) + : VertexArrayImpl(data), + mAttributeStorageTypes(data.getMaxAttribs(), VertexStorageType::CURRENT_VALUE), + mTranslatedAttribs(data.getMaxAttribs()), + mCurrentArrayBuffers(data.getMaxAttribs()), + mCurrentElementArrayBuffer(), + mOnArrayBufferDataDirty(), + mOnElementArrayBufferDataDirty(this, mCurrentArrayBuffers.size()), + mAppliedNumViewsToDivisor(1), + mLastElementType(GL_NONE), + mLastDrawElementsOffset(0), + mCurrentElementArrayStorage(IndexStorageType::Invalid), + mCachedIndexInfoValid(false) +{ + for (size_t attribIndex = 0; attribIndex < mCurrentArrayBuffers.size(); ++attribIndex) + { + mOnArrayBufferDataDirty.emplace_back(this, attribIndex); + } +} + +VertexArray11::~VertexArray11() +{ +} + +void VertexArray11::destroy(const gl::Context *context) +{ + for (auto &buffer : mCurrentArrayBuffers) + { + if (buffer.get()) + { + buffer.set(context, nullptr); + } + } + + mCurrentElementArrayBuffer.set(context, nullptr); +} + +void VertexArray11::syncState(const gl::Context *context, + const gl::VertexArray::DirtyBits &dirtyBits) +{ + ASSERT(dirtyBits.any()); + + // Generate a state serial. This serial is used in the program class to validate the cached + // input layout, and skip recomputation in the fast path. + Renderer11 *renderer = GetImplAs(context)->getRenderer(); + mCurrentStateSerial = renderer->generateSerial(); + + // TODO(jmadill): Individual attribute invalidation. + renderer->getStateManager()->invalidateVertexBuffer(); + + for (auto dirtyBit : dirtyBits) + { + if (dirtyBit == gl::VertexArray::DIRTY_BIT_ELEMENT_ARRAY_BUFFER) + { + mCachedIndexInfoValid = false; + mLastElementType = GL_NONE; + } + else + { + size_t index = gl::VertexArray::GetVertexIndexFromDirtyBit(dirtyBit); + // TODO(jiawei.shao@intel.com): Vertex Attrib Bindings + ASSERT(index == mState.getBindingIndexFromAttribIndex(index)); + mAttribsToUpdate.set(index); + } + } +} + +bool VertexArray11::flushAttribUpdates(const gl::Context *context) +{ + if (mAttribsToUpdate.any()) + { + const auto &activeLocations = + context->getGLState().getProgram()->getActiveAttribLocationsMask(); + + // Skip attrib locations the program doesn't use. + gl::AttributesMask activeToUpdate = mAttribsToUpdate & activeLocations; + + for (auto toUpdateIndex : activeToUpdate) + { + mAttribsToUpdate.reset(toUpdateIndex); + updateVertexAttribStorage(context, toUpdateIndex); + } + + return true; + } + + return false; +} + +bool VertexArray11::updateElementArrayStorage(const gl::Context *context, + GLenum elementType, + GLenum destElementType, + const void *indices) +{ + unsigned int offset = static_cast(reinterpret_cast(indices)); + + if (mCachedIndexInfoValid && mLastElementType == elementType && + offset == mLastDrawElementsOffset) + { + // Dynamic index buffers must be re-streamed every draw. + return (mCurrentElementArrayStorage == IndexStorageType::Dynamic); + } + + gl::Buffer *newBuffer = mState.getElementArrayBuffer().get(); + gl::Buffer *oldBuffer = mCurrentElementArrayBuffer.get(); + bool needsTranslation = false; + IndexStorageType newStorageType = ClassifyIndexStorage( + context->getGLState(), newBuffer, elementType, destElementType, offset, &needsTranslation); + + if (newBuffer != oldBuffer) + { + mCurrentElementArrayBuffer.set(context, newBuffer); + } + + if (newStorageType != mCurrentElementArrayStorage || newBuffer != oldBuffer) + { + Buffer11 *newBuffer11 = SafeGetImplAs(newBuffer); + + auto *newChannel = GetBufferBroadcastChannel(newBuffer11, newStorageType); + + mCurrentElementArrayStorage = newStorageType; + mOnElementArrayBufferDataDirty.bind(newChannel); + needsTranslation = true; + } + + if (mLastDrawElementsOffset != offset) + { + needsTranslation = true; + mLastDrawElementsOffset = offset; + } + + if (mLastElementType != elementType) + { + needsTranslation = true; + mLastElementType = elementType; + } + + // TODO(jmadill): We should probably promote static usage immediately, because this can change + // the storage type for dynamic buffers. + return needsTranslation || !mCachedIndexInfoValid; +} + +void VertexArray11::updateVertexAttribStorage(const gl::Context *context, size_t attribIndex) +{ + const auto &attrib = mState.getVertexAttribute(attribIndex); + const auto &binding = mState.getBindingFromAttribIndex(attribIndex); + + // Note: having an unchanged storage type doesn't mean the attribute is clean. + auto oldStorageType = mAttributeStorageTypes[attribIndex]; + auto newStorageType = ClassifyAttributeStorage(attrib, binding); + + mAttributeStorageTypes[attribIndex] = newStorageType; + + StateManager11 *stateManager = GetImplAs(context)->getRenderer()->getStateManager(); + + if (newStorageType == VertexStorageType::DYNAMIC) + { + if (oldStorageType != VertexStorageType::DYNAMIC) + { + // Sync dynamic attribs in a different set. + mAttribsToTranslate.reset(attribIndex); + mDynamicAttribsMask.set(attribIndex); + } + } + else + { + mAttribsToTranslate.set(attribIndex); + stateManager->invalidateVertexAttributeTranslation(); + + if (oldStorageType == VertexStorageType::DYNAMIC) + { + ASSERT(mDynamicAttribsMask[attribIndex]); + mDynamicAttribsMask.reset(attribIndex); + } + } + + gl::Buffer *oldBufferGL = mCurrentArrayBuffers[attribIndex].get(); + gl::Buffer *newBufferGL = binding.getBuffer().get(); + Buffer11 *oldBuffer11 = oldBufferGL ? GetImplAs(oldBufferGL) : nullptr; + Buffer11 *newBuffer11 = newBufferGL ? GetImplAs(newBufferGL) : nullptr; + + if (oldBuffer11 != newBuffer11 || oldStorageType != newStorageType) + { + OnBufferDataDirtyChannel *newChannel = nullptr; + + if (newStorageType == VertexStorageType::CURRENT_VALUE) + { + stateManager->invalidateCurrentValueAttrib(attribIndex); + } + else if (newBuffer11 != nullptr) + { + // Note that for static callbacks, promotion to a static buffer from a dynamic buffer + // means we need to tag dynamic buffers with static callbacks. + switch (newStorageType) + { + case VertexStorageType::DIRECT: + newChannel = newBuffer11->getDirectBroadcastChannel(); + break; + case VertexStorageType::STATIC: + case VertexStorageType::DYNAMIC: + newChannel = newBuffer11->getStaticBroadcastChannel(); + break; + default: + UNREACHABLE(); + break; + } + } + + mOnArrayBufferDataDirty[attribIndex].bind(newChannel); + mCurrentArrayBuffers[attribIndex].set(context, binding.getBuffer().get()); + } +} + +bool VertexArray11::hasActiveDynamicAttrib(const gl::Context *context) +{ + flushAttribUpdates(context); + const auto &activeLocations = + context->getGLState().getProgram()->getActiveAttribLocationsMask(); + auto activeDynamicAttribs = (mDynamicAttribsMask & activeLocations); + return activeDynamicAttribs.any(); +} + +gl::Error VertexArray11::updateDirtyAndDynamicAttribs(const gl::Context *context, + VertexDataManager *vertexDataManager, + const DrawCallVertexParams &vertexParams) +{ + flushAttribUpdates(context); + + const auto &glState = context->getGLState(); + const gl::Program *program = glState.getProgram(); + const auto &activeLocations = program->getActiveAttribLocationsMask(); + const auto &attribs = mState.getVertexAttributes(); + const auto &bindings = mState.getVertexBindings(); + mAppliedNumViewsToDivisor = + (program != nullptr && program->usesMultiview()) ? program->getNumViews() : 1; + + if (mAttribsToTranslate.any()) + { + // Skip attrib locations the program doesn't use, saving for the next frame. + gl::AttributesMask dirtyActiveAttribs = (mAttribsToTranslate & activeLocations); + + for (auto dirtyAttribIndex : dirtyActiveAttribs) + { + mAttribsToTranslate.reset(dirtyAttribIndex); + + auto *translatedAttrib = &mTranslatedAttribs[dirtyAttribIndex]; + const auto ¤tValue = glState.getVertexAttribCurrentValue(dirtyAttribIndex); + + // Record basic attrib info + translatedAttrib->attribute = &attribs[dirtyAttribIndex]; + translatedAttrib->binding = &bindings[translatedAttrib->attribute->bindingIndex]; + translatedAttrib->currentValueType = currentValue.Type; + translatedAttrib->divisor = + translatedAttrib->binding->getDivisor() * mAppliedNumViewsToDivisor; + + switch (mAttributeStorageTypes[dirtyAttribIndex]) + { + case VertexStorageType::DIRECT: + VertexDataManager::StoreDirectAttrib(translatedAttrib); + break; + case VertexStorageType::STATIC: + { + ANGLE_TRY(VertexDataManager::StoreStaticAttrib(context, translatedAttrib)); + break; + } + case VertexStorageType::CURRENT_VALUE: + // Current value attribs are managed by the StateManager11. + break; + default: + UNREACHABLE(); + break; + } + } + } + + if (mDynamicAttribsMask.any()) + { + auto activeDynamicAttribs = (mDynamicAttribsMask & activeLocations); + if (activeDynamicAttribs.none()) + { + return gl::NoError(); + } + + for (auto dynamicAttribIndex : activeDynamicAttribs) + { + auto *dynamicAttrib = &mTranslatedAttribs[dynamicAttribIndex]; + const auto ¤tValue = glState.getVertexAttribCurrentValue(dynamicAttribIndex); + + // Record basic attrib info + dynamicAttrib->attribute = &attribs[dynamicAttribIndex]; + dynamicAttrib->binding = &bindings[dynamicAttrib->attribute->bindingIndex]; + dynamicAttrib->currentValueType = currentValue.Type; + dynamicAttrib->divisor = + dynamicAttrib->binding->getDivisor() * mAppliedNumViewsToDivisor; + } + + ANGLE_TRY(vertexDataManager->storeDynamicAttribs( + context, &mTranslatedAttribs, activeDynamicAttribs, vertexParams.firstVertex(), + vertexParams.vertexCount(), vertexParams.instances())); + } + + return gl::NoError(); +} + +const std::vector &VertexArray11::getTranslatedAttribs() const +{ + return mTranslatedAttribs; +} + +void VertexArray11::signal(size_t channelID, const gl::Context *context) +{ + if (channelID == mAttributeStorageTypes.size()) + { + mCachedIndexInfoValid = false; + mLastElementType = GL_NONE; + mLastDrawElementsOffset = 0; + } + else + { + ASSERT(mAttributeStorageTypes[channelID] != VertexStorageType::CURRENT_VALUE); + + // This can change a buffer's storage, we'll need to re-check. + mAttribsToUpdate.set(channelID); + + // Changing the vertex attribute state can affect the vertex shader. + Renderer11 *renderer = GetImplAs(context)->getRenderer(); + renderer->getStateManager()->invalidateShaders(); + } +} + +void VertexArray11::clearDirtyAndPromoteDynamicAttribs(const gl::Context *context, + const DrawCallVertexParams &vertexParams) +{ + const gl::State &state = context->getGLState(); + const gl::Program *program = state.getProgram(); + const auto &activeLocations = program->getActiveAttribLocationsMask(); + mAttribsToUpdate &= ~activeLocations; + + // Promote to static after we clear the dirty attributes, otherwise we can lose dirtyness. + auto activeDynamicAttribs = (mDynamicAttribsMask & activeLocations); + if (activeDynamicAttribs.any()) + { + VertexDataManager::PromoteDynamicAttribs(context, mTranslatedAttribs, activeDynamicAttribs, + vertexParams.vertexCount()); + } +} + +void VertexArray11::markAllAttributeDivisorsForAdjustment(int numViews) +{ + if (mAppliedNumViewsToDivisor != numViews) + { + mAppliedNumViewsToDivisor = numViews; + mAttribsToUpdate.set(); + } +} + +TranslatedIndexData *VertexArray11::getCachedIndexInfo() +{ + return &mCachedIndexInfo; +} + +void VertexArray11::setCachedIndexInfoValid() +{ + mCachedIndexInfoValid = true; +} + +bool VertexArray11::isCachedIndexInfoValid() const +{ + return mCachedIndexInfoValid; +} + +} // namespace rx diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/VertexArray11.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/VertexArray11.h index b397140e71..4cdc92531d 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/VertexArray11.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/VertexArray11.h @@ -9,23 +9,91 @@ #ifndef LIBANGLE_RENDERER_D3D_D3D11_VERTEXARRAY11_H_ #define LIBANGLE_RENDERER_D3D_D3D11_VERTEXARRAY11_H_ +#include "libANGLE/Framebuffer.h" #include "libANGLE/renderer/VertexArrayImpl.h" #include "libANGLE/renderer/d3d/d3d11/Renderer11.h" +#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h" +#include "libANGLE/signal_utils.h" namespace rx { class Renderer11; -class VertexArray11 : public VertexArrayImpl +class VertexArray11 : public VertexArrayImpl, public OnBufferDataDirtyReceiver { public: - VertexArray11(const gl::VertexArray::Data &data) - : VertexArrayImpl(data) - { - } - virtual ~VertexArray11() {} + VertexArray11(const gl::VertexArrayState &data); + ~VertexArray11() override; + void destroy(const gl::Context *context) override; + + void syncState(const gl::Context *context, + const gl::VertexArray::DirtyBits &dirtyBits) override; + // This will flush any pending attrib updates and then check the dynamic attribs mask. + bool hasActiveDynamicAttrib(const gl::Context *context); + gl::Error updateDirtyAndDynamicAttribs(const gl::Context *context, + VertexDataManager *vertexDataManager, + const DrawCallVertexParams &vertexParams); + void clearDirtyAndPromoteDynamicAttribs(const gl::Context *context, + const DrawCallVertexParams &vertexParams); + + const std::vector &getTranslatedAttribs() const; + + // SignalReceiver implementation + void signal(size_t channelID, const gl::Context *context) override; + + Serial getCurrentStateSerial() const { return mCurrentStateSerial; } + + // In case of a multi-view program change, we have to update all attributes so that the divisor + // is adjusted. + void markAllAttributeDivisorsForAdjustment(int numViews); + + bool flushAttribUpdates(const gl::Context *context); + + // Returns true if the element array buffer needs to be translated. + bool updateElementArrayStorage(const gl::Context *context, + GLenum elementType, + GLenum destElementType, + const void *indices); + + TranslatedIndexData *getCachedIndexInfo(); + void setCachedIndexInfoValid(); + bool isCachedIndexInfoValid() const; + + private: + void updateVertexAttribStorage(const gl::Context *context, size_t attribIndex); + + std::vector mAttributeStorageTypes; + std::vector mTranslatedAttribs; + + // The mask of attributes marked as dynamic. + gl::AttributesMask mDynamicAttribsMask; + + // A mask of attributes that need to be re-evaluated. + gl::AttributesMask mAttribsToUpdate; + + // A set of attributes we know are dirty, and need to be re-translated. + gl::AttributesMask mAttribsToTranslate; + + // We need to keep a safe pointer to the Buffer so we can attach the correct dirty callbacks. + std::vector> mCurrentArrayBuffers; + gl::BindingPointer mCurrentElementArrayBuffer; + + std::vector mOnArrayBufferDataDirty; + OnBufferDataDirtyBinding mOnElementArrayBufferDataDirty; + + Serial mCurrentStateSerial; + + // The numViews value used to adjust the divisor. + int mAppliedNumViewsToDivisor; + + // If the index buffer needs re-streaming. + GLenum mLastElementType; + unsigned int mLastDrawElementsOffset; + IndexStorageType mCurrentElementArrayStorage; + TranslatedIndexData mCachedIndexInfo; + bool mCachedIndexInfoValid; }; -} +} // namespace rx #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 index 098cefcd53..611bd0f18b 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/VertexBuffer11.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/VertexBuffer11.cpp @@ -19,92 +19,88 @@ namespace rx { -VertexBuffer11::VertexBuffer11(Renderer11 *const renderer) : mRenderer(renderer) +VertexBuffer11::VertexBuffer11(Renderer11 *const renderer) + : mRenderer(renderer), + mBuffer(), + mBufferSize(0), + mDynamicUsage(false), + mMappedResourceData(nullptr) { - mBuffer = NULL; - mBufferSize = 0; - mDynamicUsage = false; - mMappedResourceData = NULL; } VertexBuffer11::~VertexBuffer11() { - ASSERT(mMappedResourceData == NULL); - SafeRelease(mBuffer); + ASSERT(mMappedResourceData == nullptr); } gl::Error VertexBuffer11::initialize(unsigned int size, bool dynamicUsage) { - SafeRelease(mBuffer); - + mBuffer.reset(); 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.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); - } + ANGLE_TRY(mRenderer->allocateResource(bufferDesc, &mBuffer)); if (dynamicUsage) { - d3d11::SetDebugName(mBuffer, "VertexBuffer11 (dynamic)"); + mBuffer.setDebugName("VertexBuffer11 (dynamic)"); } else { - d3d11::SetDebugName(mBuffer, "VertexBuffer11 (static)"); + mBuffer.setDebugName("VertexBuffer11 (static)"); } } - mBufferSize = size; + mBufferSize = size; mDynamicUsage = dynamicUsage; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } gl::Error VertexBuffer11::mapResource() { - if (mMappedResourceData == NULL) + if (mMappedResourceData == nullptr) { ID3D11DeviceContext *dxContext = mRenderer->getDeviceContext(); D3D11_MAPPED_SUBRESOURCE mappedResource; - HRESULT result = dxContext->Map(mBuffer, 0, D3D11_MAP_WRITE_NO_OVERWRITE, 0, &mappedResource); + HRESULT result = + dxContext->Map(mBuffer.get(), 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); + return gl::OutOfMemory() + << "Failed to map internal vertex buffer, " << gl::FmtHR(result); } - mMappedResourceData = reinterpret_cast(mappedResource.pData); + mMappedResourceData = reinterpret_cast(mappedResource.pData); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } void VertexBuffer11::hintUnmapResource() { - if (mMappedResourceData != NULL) + if (mMappedResourceData != nullptr) { ID3D11DeviceContext *dxContext = mRenderer->getDeviceContext(); - dxContext->Unmap(mBuffer, 0); + dxContext->Unmap(mBuffer.get(), 0); - mMappedResourceData = NULL; + mMappedResourceData = nullptr; } } gl::Error VertexBuffer11::storeVertexAttributes(const gl::VertexAttribute &attrib, + const gl::VertexBinding &binding, GLenum currentValueType, GLint start, GLsizei count, @@ -112,81 +108,33 @@ gl::Error VertexBuffer11::storeVertexAttributes(const gl::VertexAttribute &attri unsigned int offset, const uint8_t *sourceData) { - if (!mBuffer) + if (!mBuffer.valid()) { - return gl::Error(GL_OUT_OF_MEMORY, "Internal vertex buffer is not initialized."); + return gl::OutOfMemory() << "Internal vertex buffer is not initialized."; } - int inputStride = static_cast(ComputeVertexAttributeStride(attrib)); + int inputStride = static_cast(ComputeVertexAttributeStride(attrib, binding)); // This will map the resource if it isn't already mapped. - gl::Error error = mapResource(); - if (error.isError()) - { - return error; - } + ANGLE_TRY(mapResource()); uint8_t *output = mMappedResourceData + offset; const uint8_t *input = sourceData; - if (instances == 0 || attrib.divisor == 0) + if (instances == 0 || binding.getDivisor() == 0) { input += inputStride * start; } gl::VertexFormatType vertexFormatType = gl::GetVertexFormatType(attrib, currentValueType); - const D3D_FEATURE_LEVEL featureLevel = mRenderer->getRenderer11DeviceCaps().featureLevel; - const d3d11::VertexFormat &vertexFormatInfo = d3d11::GetVertexFormatInfo(vertexFormatType, featureLevel); - ASSERT(vertexFormatInfo.copyFunction != NULL); + const D3D_FEATURE_LEVEL featureLevel = mRenderer->getRenderer11DeviceCaps().featureLevel; + const d3d11::VertexFormat &vertexFormatInfo = + d3d11::GetVertexFormatInfo(vertexFormatType, featureLevel); + ASSERT(vertexFormatInfo.copyFunction != nullptr); 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::VertexFormatType formatType = gl::GetVertexFormatType(attrib); - const D3D_FEATURE_LEVEL featureLevel = mRenderer->getRenderer11DeviceCaps().featureLevel; - const d3d11::VertexFormat &vertexFormatInfo = d3d11::GetVertexFormatInfo(formatType, featureLevel); - 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); - } + return gl::NoError(); } unsigned int VertexBuffer11::getBufferSize() const @@ -202,34 +150,35 @@ gl::Error VertexBuffer11::setBufferSize(unsigned int size) } else { - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } } gl::Error VertexBuffer11::discard() { - if (!mBuffer) + if (!mBuffer.valid()) { - return gl::Error(GL_OUT_OF_MEMORY, "Internal vertex buffer is not initialized."); + return gl::OutOfMemory() << "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); + HRESULT result = dxContext->Map(mBuffer.get(), 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); + return gl::OutOfMemory() << "Failed to map internal buffer for discarding, " + << gl::FmtHR(result); } - dxContext->Unmap(mBuffer, 0); + dxContext->Unmap(mBuffer.get(), 0); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -ID3D11Buffer *VertexBuffer11::getBuffer() const +const d3d11::Buffer &VertexBuffer11::getBuffer() const { return mBuffer; } -} +} // namespace rx diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/VertexBuffer11.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/VertexBuffer11.h index 773c4474e1..ab619ae503 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/VertexBuffer11.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/VertexBuffer11.h @@ -12,6 +12,7 @@ #include #include "libANGLE/renderer/d3d/VertexBuffer.h" +#include "libANGLE/renderer/d3d/d3d11/ResourceManager11.h" namespace rx { @@ -21,11 +22,13 @@ class VertexBuffer11 : public VertexBuffer { public: explicit VertexBuffer11(Renderer11 *const renderer); - virtual ~VertexBuffer11(); - virtual gl::Error initialize(unsigned int size, bool dynamicUsage); + gl::Error initialize(unsigned int size, bool dynamicUsage) override; + // Warning: you should ensure binding really matches attrib.bindingIndex before using this + // function. gl::Error storeVertexAttributes(const gl::VertexAttribute &attrib, + const gl::VertexBinding &binding, GLenum currentValueType, GLint start, GLsizei count, @@ -33,29 +36,27 @@ class VertexBuffer11 : public VertexBuffer unsigned int offset, const uint8_t *sourceData) override; - virtual gl::Error getSpaceRequired(const gl::VertexAttribute &attrib, GLsizei count, GLsizei instances, - unsigned int *outSpaceRequired) const; + unsigned int getBufferSize() const override; + gl::Error setBufferSize(unsigned int size) override; + gl::Error discard() override; - virtual unsigned int getBufferSize() const; - virtual gl::Error setBufferSize(unsigned int size); - virtual gl::Error discard(); + void hintUnmapResource() override; - virtual void hintUnmapResource(); - - ID3D11Buffer *getBuffer() const; + const d3d11::Buffer &getBuffer() const; private: + ~VertexBuffer11() override; gl::Error mapResource(); Renderer11 *const mRenderer; - ID3D11Buffer *mBuffer; + d3d11::Buffer mBuffer; unsigned int mBufferSize; bool mDynamicUsage; uint8_t *mMappedResourceData; }; -} +} // namespace rx #endif // LIBANGLE_RENDERER_D3D_D3D11_VERTEXBUFFER11_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 index 1ec21dee55..7c5c157c6f 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/copyvertex.inl +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/copyvertex.inl @@ -15,33 +15,42 @@ inline void CopyNativeVertexData(const uint8_t *input, size_t stride, size_t cou if (attribSize == stride && inputComponentCount == outputComponentCount) { memcpy(output, input, count * attribSize); + return; } - else - { - const T defaultAlphaValue = gl::bitCast(alphaDefaultValueBits); - const size_t lastNonAlphaOutputComponent = std::min(outputComponentCount, 3); + if (inputComponentCount == outputComponentCount) + { 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]; - } + memcpy(offsetOutput, offsetInput, attribSize); + } + return; + } - for (size_t j = inputComponentCount; j < lastNonAlphaOutputComponent; j++) - { - // Set the remaining G/B channels to 0. - offsetOutput[j] = 0; - } + const T defaultAlphaValue = gl::bitCast(alphaDefaultValueBits); + const size_t lastNonAlphaOutputComponent = std::min(outputComponentCount, 3); - if (inputComponentCount < outputComponentCount && outputComponentCount == 4) - { - // Set the remaining alpha channel to the defaultAlphaValue. - offsetOutput[3] = defaultAlphaValue; - } + for (size_t i = 0; i < count; i++) + { + const T *offsetInput = reinterpret_cast(input + (i * stride)); + T *offsetOutput = reinterpret_cast(output) + i * outputComponentCount; + + memcpy(offsetOutput, offsetInput, attribSize); + + if (inputComponentCount < lastNonAlphaOutputComponent) + { + // Set the remaining G/B channels to 0. + size_t numComponents = (lastNonAlphaOutputComponent - inputComponentCount); + memset(&offsetOutput[inputComponentCount], 0, numComponents * sizeof(T)); + } + + if (inputComponentCount < outputComponentCount && outputComponentCount == 4) + { + // Set the remaining alpha channel to the defaultAlphaValue. + offsetOutput[3] = defaultAlphaValue; } } } diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/dxgi_format_data.json b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/dxgi_format_data.json new file mode 100644 index 0000000000..891d30d252 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/dxgi_format_data.json @@ -0,0 +1,118 @@ +{ + "UNKNOWN": "NONE", + "R32G32B32A32_TYPELESS": "", + "R32G32B32A32_FLOAT": "", + "R32G32B32A32_UINT": "", + "R32G32B32A32_SINT": "", + "R32G32B32_TYPELESS": "", + "R32G32B32_FLOAT": "", + "R32G32B32_UINT": "", + "R32G32B32_SINT": "", + "R16G16B16A16_TYPELESS": "", + "R16G16B16A16_FLOAT": "", + "R16G16B16A16_UNORM": "", + "R16G16B16A16_UINT": "", + "R16G16B16A16_SNORM": "", + "R16G16B16A16_SINT": "", + "R32G32_TYPELESS": "", + "R32G32_FLOAT": "", + "R32G32_UINT": "", + "R32G32_SINT": "", + "R32G8X24_TYPELESS": "", + "D32_FLOAT_S8X24_UINT": "", + "R32_FLOAT_X8X24_TYPELESS": "", + "X32_TYPELESS_G8X24_UINT": "", + "R10G10B10A2_TYPELESS": "", + "R10G10B10A2_UNORM": "", + "R10G10B10A2_UINT": "", + "R11G11B10_FLOAT": "", + "R8G8B8A8_TYPELESS": "", + "R8G8B8A8_UNORM": "", + "R8G8B8A8_UNORM_SRGB": "", + "R8G8B8A8_UINT": "", + "R8G8B8A8_SNORM": "", + "R8G8B8A8_SINT": "", + "R16G16_TYPELESS": "", + "R16G16_FLOAT": "", + "R16G16_UNORM": "", + "R16G16_UINT": "", + "R16G16_SNORM": "", + "R16G16_SINT": "", + "R32_TYPELESS": "", + "D32_FLOAT": "", + "R32_FLOAT": "", + "R32_UINT": "", + "R32_SINT": "", + "R24G8_TYPELESS": "", + "D24_UNORM_S8_UINT": "", + "R24_UNORM_X8_TYPELESS": "", + "X24_TYPELESS_G8_UINT": "", + "R8G8_TYPELESS": "", + "R8G8_UNORM": "", + "R8G8_UINT": "", + "R8G8_SNORM": "", + "R8G8_SINT": "", + "R16_TYPELESS": "", + "R16_FLOAT": "", + "D16_UNORM": "", + "R16_UNORM": "", + "R16_UINT": "", + "R16_SNORM": "", + "R16_SINT": "", + "R8_TYPELESS": "", + "R8_UNORM": "", + "R8_UINT": "", + "R8_SNORM": "", + "R8_SINT": "", + "A8_UNORM": "", + "R1_UNORM": "", + "R9G9B9E5_SHAREDEXP": "", + "R8G8_B8G8_UNORM": "", + "G8R8_G8B8_UNORM": "", + "BC1_TYPELESS": "", + "BC1_UNORM": "BC1_RGBA_UNORM_BLOCK", + "BC1_UNORM_SRGB": "BC1_RGBA_UNORM_SRGB_BLOCK", + "BC2_TYPELESS": "", + "BC2_UNORM": "BC2_RGBA_UNORM_BLOCK", + "BC2_UNORM_SRGB": "BC2_RGBA_UNORM_SRGB_BLOCK", + "BC3_TYPELESS": "", + "BC3_UNORM": "BC3_RGBA_UNORM_BLOCK", + "BC3_UNORM_SRGB": "BC3_RGBA_UNORM_SRGB_BLOCK", + "BC4_TYPELESS": "", + "BC4_UNORM": "", + "BC4_SNORM": "", + "BC5_TYPELESS": "", + "BC5_UNORM": "", + "BC5_SNORM": "", + "B5G6R5_UNORM": "", + "B5G5R5A1_UNORM": "", + "B8G8R8A8_UNORM": "", + "B8G8R8X8_UNORM": "", + "R10G10B10_XR_BIAS_A2_UNORM": "", + "B8G8R8A8_TYPELESS": "", + "B8G8R8A8_UNORM_SRGB": "", + "B8G8R8X8_TYPELESS": "", + "B8G8R8X8_UNORM_SRGB": "", + "BC6H_TYPELESS": "", + "BC6H_UF16": "", + "BC6H_SF16": "", + "BC7_TYPELESS": "", + "BC7_UNORM": "", + "BC7_UNORM_SRGB": "", + "AYUV": "", + "Y410": "", + "Y416": "", + "NV12": "", + "P010": "", + "P016": "", + "420_OPAQUE": "", + "YUY2": "", + "Y210": "", + "Y216": "", + "NV11": "", + "AI44": "", + "IA44": "", + "P8": "", + "A8P8": "", + "B4G4R4A4_UNORM": "" +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/dxgi_format_map_autogen.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/dxgi_format_map_autogen.cpp new file mode 100644 index 0000000000..b0697bc5db --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/dxgi_format_map_autogen.cpp @@ -0,0 +1,516 @@ +// GENERATED FILE - DO NOT EDIT. +// Generated by gen_dxgi_format_table.py using data from dxgi_format_data.json. +// +// Copyright 2017 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. +// +// DXGI format info: +// Determining metadata about a DXGI format. + +#include "libANGLE/renderer/Format.h" + +using namespace angle; + +namespace rx +{ + +namespace d3d11 +{ + +GLenum GetComponentType(DXGI_FORMAT dxgiFormat) +{ + switch (dxgiFormat) + { + case DXGI_FORMAT_420_OPAQUE: + break; + case DXGI_FORMAT_A8P8: + break; + case DXGI_FORMAT_A8_UNORM: + return GL_UNSIGNED_NORMALIZED; + case DXGI_FORMAT_AI44: + break; + case DXGI_FORMAT_AYUV: + break; + case DXGI_FORMAT_B4G4R4A4_UNORM: + return GL_UNSIGNED_NORMALIZED; + case DXGI_FORMAT_B5G5R5A1_UNORM: + return GL_UNSIGNED_NORMALIZED; + case DXGI_FORMAT_B5G6R5_UNORM: + return GL_UNSIGNED_NORMALIZED; + case DXGI_FORMAT_B8G8R8A8_TYPELESS: + break; + case DXGI_FORMAT_B8G8R8A8_UNORM: + return GL_UNSIGNED_NORMALIZED; + case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: + return GL_UNSIGNED_NORMALIZED; + case DXGI_FORMAT_B8G8R8X8_TYPELESS: + break; + case DXGI_FORMAT_B8G8R8X8_UNORM: + return GL_UNSIGNED_NORMALIZED; + case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB: + return GL_UNSIGNED_NORMALIZED; + case DXGI_FORMAT_BC1_TYPELESS: + break; + case DXGI_FORMAT_BC1_UNORM: + return GL_UNSIGNED_NORMALIZED; + case DXGI_FORMAT_BC1_UNORM_SRGB: + return GL_UNSIGNED_NORMALIZED; + case DXGI_FORMAT_BC2_TYPELESS: + break; + case DXGI_FORMAT_BC2_UNORM: + return GL_UNSIGNED_NORMALIZED; + case DXGI_FORMAT_BC2_UNORM_SRGB: + return GL_UNSIGNED_NORMALIZED; + case DXGI_FORMAT_BC3_TYPELESS: + break; + case DXGI_FORMAT_BC3_UNORM: + return GL_UNSIGNED_NORMALIZED; + case DXGI_FORMAT_BC3_UNORM_SRGB: + return GL_UNSIGNED_NORMALIZED; + case DXGI_FORMAT_BC4_SNORM: + return GL_SIGNED_NORMALIZED; + case DXGI_FORMAT_BC4_TYPELESS: + break; + case DXGI_FORMAT_BC4_UNORM: + return GL_UNSIGNED_NORMALIZED; + case DXGI_FORMAT_BC5_SNORM: + return GL_SIGNED_NORMALIZED; + case DXGI_FORMAT_BC5_TYPELESS: + break; + case DXGI_FORMAT_BC5_UNORM: + return GL_UNSIGNED_NORMALIZED; + case DXGI_FORMAT_BC6H_SF16: + break; + case DXGI_FORMAT_BC6H_TYPELESS: + break; + case DXGI_FORMAT_BC6H_UF16: + break; + case DXGI_FORMAT_BC7_TYPELESS: + break; + case DXGI_FORMAT_BC7_UNORM: + return GL_UNSIGNED_NORMALIZED; + case DXGI_FORMAT_BC7_UNORM_SRGB: + return GL_UNSIGNED_NORMALIZED; + case DXGI_FORMAT_D16_UNORM: + return GL_UNSIGNED_NORMALIZED; + case DXGI_FORMAT_D24_UNORM_S8_UINT: + break; + case DXGI_FORMAT_D32_FLOAT: + return GL_FLOAT; + case DXGI_FORMAT_D32_FLOAT_S8X24_UINT: + break; + case DXGI_FORMAT_G8R8_G8B8_UNORM: + return GL_UNSIGNED_NORMALIZED; + case DXGI_FORMAT_IA44: + break; + case DXGI_FORMAT_NV11: + break; + case DXGI_FORMAT_NV12: + break; + case DXGI_FORMAT_P010: + break; + case DXGI_FORMAT_P016: + break; + case DXGI_FORMAT_P8: + break; + case DXGI_FORMAT_R10G10B10A2_TYPELESS: + break; + case DXGI_FORMAT_R10G10B10A2_UINT: + return GL_UNSIGNED_INT; + case DXGI_FORMAT_R10G10B10A2_UNORM: + return GL_UNSIGNED_NORMALIZED; + case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM: + return GL_UNSIGNED_NORMALIZED; + case DXGI_FORMAT_R11G11B10_FLOAT: + return GL_FLOAT; + case DXGI_FORMAT_R16G16B16A16_FLOAT: + return GL_FLOAT; + case DXGI_FORMAT_R16G16B16A16_SINT: + return GL_INT; + case DXGI_FORMAT_R16G16B16A16_SNORM: + return GL_SIGNED_NORMALIZED; + case DXGI_FORMAT_R16G16B16A16_TYPELESS: + break; + case DXGI_FORMAT_R16G16B16A16_UINT: + return GL_UNSIGNED_INT; + case DXGI_FORMAT_R16G16B16A16_UNORM: + return GL_UNSIGNED_NORMALIZED; + case DXGI_FORMAT_R16G16_FLOAT: + return GL_FLOAT; + case DXGI_FORMAT_R16G16_SINT: + return GL_INT; + case DXGI_FORMAT_R16G16_SNORM: + return GL_SIGNED_NORMALIZED; + case DXGI_FORMAT_R16G16_TYPELESS: + break; + case DXGI_FORMAT_R16G16_UINT: + return GL_UNSIGNED_INT; + case DXGI_FORMAT_R16G16_UNORM: + return GL_UNSIGNED_NORMALIZED; + case DXGI_FORMAT_R16_FLOAT: + return GL_FLOAT; + case DXGI_FORMAT_R16_SINT: + return GL_INT; + case DXGI_FORMAT_R16_SNORM: + return GL_SIGNED_NORMALIZED; + case DXGI_FORMAT_R16_TYPELESS: + break; + case DXGI_FORMAT_R16_UINT: + return GL_UNSIGNED_INT; + case DXGI_FORMAT_R16_UNORM: + return GL_UNSIGNED_NORMALIZED; + case DXGI_FORMAT_R1_UNORM: + return GL_UNSIGNED_NORMALIZED; + case DXGI_FORMAT_R24G8_TYPELESS: + break; + case DXGI_FORMAT_R24_UNORM_X8_TYPELESS: + return GL_UNSIGNED_NORMALIZED; + case DXGI_FORMAT_R32G32B32A32_FLOAT: + return GL_FLOAT; + case DXGI_FORMAT_R32G32B32A32_SINT: + return GL_INT; + case DXGI_FORMAT_R32G32B32A32_TYPELESS: + break; + case DXGI_FORMAT_R32G32B32A32_UINT: + return GL_UNSIGNED_INT; + case DXGI_FORMAT_R32G32B32_FLOAT: + return GL_FLOAT; + case DXGI_FORMAT_R32G32B32_SINT: + return GL_INT; + case DXGI_FORMAT_R32G32B32_TYPELESS: + break; + case DXGI_FORMAT_R32G32B32_UINT: + return GL_UNSIGNED_INT; + case DXGI_FORMAT_R32G32_FLOAT: + return GL_FLOAT; + case DXGI_FORMAT_R32G32_SINT: + return GL_INT; + case DXGI_FORMAT_R32G32_TYPELESS: + break; + case DXGI_FORMAT_R32G32_UINT: + return GL_UNSIGNED_INT; + case DXGI_FORMAT_R32G8X24_TYPELESS: + break; + case DXGI_FORMAT_R32_FLOAT: + return GL_FLOAT; + case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS: + return GL_FLOAT; + case DXGI_FORMAT_R32_SINT: + return GL_INT; + case DXGI_FORMAT_R32_TYPELESS: + break; + case DXGI_FORMAT_R32_UINT: + return GL_UNSIGNED_INT; + case DXGI_FORMAT_R8G8B8A8_SINT: + return GL_INT; + case DXGI_FORMAT_R8G8B8A8_SNORM: + return GL_SIGNED_NORMALIZED; + case DXGI_FORMAT_R8G8B8A8_TYPELESS: + break; + case DXGI_FORMAT_R8G8B8A8_UINT: + return GL_UNSIGNED_INT; + case DXGI_FORMAT_R8G8B8A8_UNORM: + return GL_UNSIGNED_NORMALIZED; + case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: + return GL_UNSIGNED_NORMALIZED; + case DXGI_FORMAT_R8G8_B8G8_UNORM: + return GL_UNSIGNED_NORMALIZED; + case DXGI_FORMAT_R8G8_SINT: + return GL_INT; + case DXGI_FORMAT_R8G8_SNORM: + return GL_SIGNED_NORMALIZED; + case DXGI_FORMAT_R8G8_TYPELESS: + break; + case DXGI_FORMAT_R8G8_UINT: + return GL_UNSIGNED_INT; + case DXGI_FORMAT_R8G8_UNORM: + return GL_UNSIGNED_NORMALIZED; + case DXGI_FORMAT_R8_SINT: + return GL_INT; + case DXGI_FORMAT_R8_SNORM: + return GL_SIGNED_NORMALIZED; + case DXGI_FORMAT_R8_TYPELESS: + break; + case DXGI_FORMAT_R8_UINT: + return GL_UNSIGNED_INT; + case DXGI_FORMAT_R8_UNORM: + return GL_UNSIGNED_NORMALIZED; + case DXGI_FORMAT_R9G9B9E5_SHAREDEXP: + return GL_FLOAT; + case DXGI_FORMAT_UNKNOWN: + break; + case DXGI_FORMAT_X24_TYPELESS_G8_UINT: + return GL_UNSIGNED_INT; + case DXGI_FORMAT_X32_TYPELESS_G8X24_UINT: + return GL_UNSIGNED_INT; + case DXGI_FORMAT_Y210: + break; + case DXGI_FORMAT_Y216: + break; + case DXGI_FORMAT_Y410: + break; + case DXGI_FORMAT_Y416: + break; + case DXGI_FORMAT_YUY2: + break; + default: + break; + } + + UNREACHABLE(); + return GL_NONE; +} + +} // namespace d3d11 + +namespace d3d11_angle +{ + +const Format &GetFormat(DXGI_FORMAT dxgiFormat) +{ + switch (dxgiFormat) + { + case DXGI_FORMAT_420_OPAQUE: + break; + case DXGI_FORMAT_A8P8: + break; + case DXGI_FORMAT_A8_UNORM: + return Format::Get(Format::ID::A8_UNORM); + case DXGI_FORMAT_AI44: + break; + case DXGI_FORMAT_AYUV: + break; + case DXGI_FORMAT_B4G4R4A4_UNORM: + return Format::Get(Format::ID::B4G4R4A4_UNORM); + case DXGI_FORMAT_B5G5R5A1_UNORM: + return Format::Get(Format::ID::B5G5R5A1_UNORM); + case DXGI_FORMAT_B5G6R5_UNORM: + return Format::Get(Format::ID::B5G6R5_UNORM); + case DXGI_FORMAT_B8G8R8A8_TYPELESS: + break; + case DXGI_FORMAT_B8G8R8A8_UNORM: + return Format::Get(Format::ID::B8G8R8A8_UNORM); + case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: + return Format::Get(Format::ID::B8G8R8A8_UNORM_SRGB); + case DXGI_FORMAT_B8G8R8X8_TYPELESS: + break; + case DXGI_FORMAT_B8G8R8X8_UNORM: + return Format::Get(Format::ID::B8G8R8X8_UNORM); + case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB: + break; + case DXGI_FORMAT_BC1_TYPELESS: + break; + case DXGI_FORMAT_BC1_UNORM: + return Format::Get(Format::ID::BC1_RGBA_UNORM_BLOCK); + case DXGI_FORMAT_BC1_UNORM_SRGB: + return Format::Get(Format::ID::BC1_RGBA_UNORM_SRGB_BLOCK); + case DXGI_FORMAT_BC2_TYPELESS: + break; + case DXGI_FORMAT_BC2_UNORM: + return Format::Get(Format::ID::BC2_RGBA_UNORM_BLOCK); + case DXGI_FORMAT_BC2_UNORM_SRGB: + return Format::Get(Format::ID::BC2_RGBA_UNORM_SRGB_BLOCK); + case DXGI_FORMAT_BC3_TYPELESS: + break; + case DXGI_FORMAT_BC3_UNORM: + return Format::Get(Format::ID::BC3_RGBA_UNORM_BLOCK); + case DXGI_FORMAT_BC3_UNORM_SRGB: + return Format::Get(Format::ID::BC3_RGBA_UNORM_SRGB_BLOCK); + case DXGI_FORMAT_BC4_SNORM: + break; + case DXGI_FORMAT_BC4_TYPELESS: + break; + case DXGI_FORMAT_BC4_UNORM: + break; + case DXGI_FORMAT_BC5_SNORM: + break; + case DXGI_FORMAT_BC5_TYPELESS: + break; + case DXGI_FORMAT_BC5_UNORM: + break; + case DXGI_FORMAT_BC6H_SF16: + break; + case DXGI_FORMAT_BC6H_TYPELESS: + break; + case DXGI_FORMAT_BC6H_UF16: + break; + case DXGI_FORMAT_BC7_TYPELESS: + break; + case DXGI_FORMAT_BC7_UNORM: + break; + case DXGI_FORMAT_BC7_UNORM_SRGB: + break; + case DXGI_FORMAT_D16_UNORM: + return Format::Get(Format::ID::D16_UNORM); + case DXGI_FORMAT_D24_UNORM_S8_UINT: + return Format::Get(Format::ID::D24_UNORM_S8_UINT); + case DXGI_FORMAT_D32_FLOAT: + return Format::Get(Format::ID::D32_FLOAT); + case DXGI_FORMAT_D32_FLOAT_S8X24_UINT: + return Format::Get(Format::ID::D32_FLOAT_S8X24_UINT); + case DXGI_FORMAT_G8R8_G8B8_UNORM: + break; + case DXGI_FORMAT_IA44: + break; + case DXGI_FORMAT_NV11: + break; + case DXGI_FORMAT_NV12: + break; + case DXGI_FORMAT_P010: + break; + case DXGI_FORMAT_P016: + break; + case DXGI_FORMAT_P8: + break; + case DXGI_FORMAT_R10G10B10A2_TYPELESS: + break; + case DXGI_FORMAT_R10G10B10A2_UINT: + return Format::Get(Format::ID::R10G10B10A2_UINT); + case DXGI_FORMAT_R10G10B10A2_UNORM: + return Format::Get(Format::ID::R10G10B10A2_UNORM); + case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM: + break; + case DXGI_FORMAT_R11G11B10_FLOAT: + return Format::Get(Format::ID::R11G11B10_FLOAT); + case DXGI_FORMAT_R16G16B16A16_FLOAT: + return Format::Get(Format::ID::R16G16B16A16_FLOAT); + case DXGI_FORMAT_R16G16B16A16_SINT: + return Format::Get(Format::ID::R16G16B16A16_SINT); + case DXGI_FORMAT_R16G16B16A16_SNORM: + return Format::Get(Format::ID::R16G16B16A16_SNORM); + case DXGI_FORMAT_R16G16B16A16_TYPELESS: + break; + case DXGI_FORMAT_R16G16B16A16_UINT: + return Format::Get(Format::ID::R16G16B16A16_UINT); + case DXGI_FORMAT_R16G16B16A16_UNORM: + return Format::Get(Format::ID::R16G16B16A16_UNORM); + case DXGI_FORMAT_R16G16_FLOAT: + return Format::Get(Format::ID::R16G16_FLOAT); + case DXGI_FORMAT_R16G16_SINT: + return Format::Get(Format::ID::R16G16_SINT); + case DXGI_FORMAT_R16G16_SNORM: + return Format::Get(Format::ID::R16G16_SNORM); + case DXGI_FORMAT_R16G16_TYPELESS: + break; + case DXGI_FORMAT_R16G16_UINT: + return Format::Get(Format::ID::R16G16_UINT); + case DXGI_FORMAT_R16G16_UNORM: + return Format::Get(Format::ID::R16G16_UNORM); + case DXGI_FORMAT_R16_FLOAT: + return Format::Get(Format::ID::R16_FLOAT); + case DXGI_FORMAT_R16_SINT: + return Format::Get(Format::ID::R16_SINT); + case DXGI_FORMAT_R16_SNORM: + return Format::Get(Format::ID::R16_SNORM); + case DXGI_FORMAT_R16_TYPELESS: + break; + case DXGI_FORMAT_R16_UINT: + return Format::Get(Format::ID::R16_UINT); + case DXGI_FORMAT_R16_UNORM: + return Format::Get(Format::ID::R16_UNORM); + case DXGI_FORMAT_R1_UNORM: + break; + case DXGI_FORMAT_R24G8_TYPELESS: + break; + case DXGI_FORMAT_R24_UNORM_X8_TYPELESS: + break; + case DXGI_FORMAT_R32G32B32A32_FLOAT: + return Format::Get(Format::ID::R32G32B32A32_FLOAT); + case DXGI_FORMAT_R32G32B32A32_SINT: + return Format::Get(Format::ID::R32G32B32A32_SINT); + case DXGI_FORMAT_R32G32B32A32_TYPELESS: + break; + case DXGI_FORMAT_R32G32B32A32_UINT: + return Format::Get(Format::ID::R32G32B32A32_UINT); + case DXGI_FORMAT_R32G32B32_FLOAT: + return Format::Get(Format::ID::R32G32B32_FLOAT); + case DXGI_FORMAT_R32G32B32_SINT: + return Format::Get(Format::ID::R32G32B32_SINT); + case DXGI_FORMAT_R32G32B32_TYPELESS: + break; + case DXGI_FORMAT_R32G32B32_UINT: + return Format::Get(Format::ID::R32G32B32_UINT); + case DXGI_FORMAT_R32G32_FLOAT: + return Format::Get(Format::ID::R32G32_FLOAT); + case DXGI_FORMAT_R32G32_SINT: + return Format::Get(Format::ID::R32G32_SINT); + case DXGI_FORMAT_R32G32_TYPELESS: + break; + case DXGI_FORMAT_R32G32_UINT: + return Format::Get(Format::ID::R32G32_UINT); + case DXGI_FORMAT_R32G8X24_TYPELESS: + break; + case DXGI_FORMAT_R32_FLOAT: + return Format::Get(Format::ID::R32_FLOAT); + case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS: + break; + case DXGI_FORMAT_R32_SINT: + return Format::Get(Format::ID::R32_SINT); + case DXGI_FORMAT_R32_TYPELESS: + break; + case DXGI_FORMAT_R32_UINT: + return Format::Get(Format::ID::R32_UINT); + case DXGI_FORMAT_R8G8B8A8_SINT: + return Format::Get(Format::ID::R8G8B8A8_SINT); + case DXGI_FORMAT_R8G8B8A8_SNORM: + return Format::Get(Format::ID::R8G8B8A8_SNORM); + case DXGI_FORMAT_R8G8B8A8_TYPELESS: + break; + case DXGI_FORMAT_R8G8B8A8_UINT: + return Format::Get(Format::ID::R8G8B8A8_UINT); + case DXGI_FORMAT_R8G8B8A8_UNORM: + return Format::Get(Format::ID::R8G8B8A8_UNORM); + case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: + return Format::Get(Format::ID::R8G8B8A8_UNORM_SRGB); + case DXGI_FORMAT_R8G8_B8G8_UNORM: + break; + case DXGI_FORMAT_R8G8_SINT: + return Format::Get(Format::ID::R8G8_SINT); + case DXGI_FORMAT_R8G8_SNORM: + return Format::Get(Format::ID::R8G8_SNORM); + case DXGI_FORMAT_R8G8_TYPELESS: + break; + case DXGI_FORMAT_R8G8_UINT: + return Format::Get(Format::ID::R8G8_UINT); + case DXGI_FORMAT_R8G8_UNORM: + return Format::Get(Format::ID::R8G8_UNORM); + case DXGI_FORMAT_R8_SINT: + return Format::Get(Format::ID::R8_SINT); + case DXGI_FORMAT_R8_SNORM: + return Format::Get(Format::ID::R8_SNORM); + case DXGI_FORMAT_R8_TYPELESS: + break; + case DXGI_FORMAT_R8_UINT: + return Format::Get(Format::ID::R8_UINT); + case DXGI_FORMAT_R8_UNORM: + return Format::Get(Format::ID::R8_UNORM); + case DXGI_FORMAT_R9G9B9E5_SHAREDEXP: + return Format::Get(Format::ID::R9G9B9E5_SHAREDEXP); + case DXGI_FORMAT_UNKNOWN: + return Format::Get(Format::ID::NONE); + case DXGI_FORMAT_X24_TYPELESS_G8_UINT: + break; + case DXGI_FORMAT_X32_TYPELESS_G8X24_UINT: + break; + case DXGI_FORMAT_Y210: + break; + case DXGI_FORMAT_Y216: + break; + case DXGI_FORMAT_Y410: + break; + case DXGI_FORMAT_Y416: + break; + case DXGI_FORMAT_YUY2: + break; + default: + break; + } + + UNREACHABLE(); + return Format::Get(Format::ID::NONE); +} + +} // namespace d3d11_angle + +} // namespace rx diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/dxgi_support_data.json b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/dxgi_support_data.json index e81b4deea5..942745674f 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/dxgi_support_data.json +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/dxgi_support_data.json @@ -8,7 +8,8 @@ "shaderSample": "never", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_R32G32B32A32_TYPELESS": { @@ -18,7 +19,8 @@ "shaderSample": "never", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_R32G32B32A32_FLOAT": { @@ -28,27 +30,30 @@ "shaderSample": "10_0check10_1always", "renderTarget": "always", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "always" }, "DXGI_FORMAT_R32G32B32A32_UINT": { - "texture2D": "always", - "texture3D": "always", - "textureCube": "always", + "texture2D": "10_0", + "texture3D": "10_0", + "textureCube": "10_0", "shaderSample": "never", - "renderTarget": "always", + "renderTarget": "10_0", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_R32G32B32A32_SINT": { - "texture2D": "always", - "texture3D": "always", - "textureCube": "always", + "texture2D": "10_0", + "texture3D": "10_0", + "textureCube": "10_0", "shaderSample": "never", - "renderTarget": "always", + "renderTarget": "10_0", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_R32G32B32_TYPELESS": { @@ -58,7 +63,8 @@ "shaderSample": "never", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_R32G32B32_FLOAT": { @@ -68,7 +74,8 @@ "shaderSample": "11_0check", "renderTarget": "check", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_R32G32B32_UINT": { @@ -78,7 +85,8 @@ "shaderSample": "never", "renderTarget": "check", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_R32G32B32_SINT": { @@ -88,7 +96,8 @@ "shaderSample": "never", "renderTarget": "check", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_R16G16B16A16_TYPELESS": { @@ -98,57 +107,63 @@ "shaderSample": "never", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_R16G16B16A16_FLOAT": { "texture2D": "always", "texture3D": "always", "textureCube": "always", - "shaderSample": "10_0", + "shaderSample": "9_3check_10_0always", "renderTarget": "always", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "always" }, "DXGI_FORMAT_R16G16B16A16_UNORM": { "texture2D": "always", "texture3D": "always", "textureCube": "always", - "shaderSample": "10_0", + "shaderSample": "always", "renderTarget": "always", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "always" }, "DXGI_FORMAT_R16G16B16A16_UINT": { - "texture2D": "always", - "texture3D": "always", - "textureCube": "always", + "texture2D": "10_0", + "texture3D": "10_0", + "textureCube": "10_0", "shaderSample": "never", - "renderTarget": "always", + "renderTarget": "10_0", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_R16G16B16A16_SNORM": { - "texture2D": "always", - "texture3D": "always", - "textureCube": "always", + "texture2D": "10_0", + "texture3D": "10_0", + "textureCube": "10_0", "shaderSample": "10_0", - "renderTarget": "always", + "renderTarget": "10_0", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "10_0" }, "DXGI_FORMAT_R16G16B16A16_SINT": { - "texture2D": "always", - "texture3D": "always", - "textureCube": "always", + "texture2D": "10_0", + "texture3D": "10_0", + "textureCube": "10_0", "shaderSample": "never", - "renderTarget": "always", + "renderTarget": "10_0", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_R32G32_TYPELESS": { @@ -158,7 +173,8 @@ "shaderSample": "never", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_R32G32_FLOAT": { @@ -168,37 +184,41 @@ "shaderSample": "10_0check10_1always", "renderTarget": "always", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "10_0" }, "DXGI_FORMAT_R32G32_UINT": { - "texture2D": "always", - "texture3D": "always", - "textureCube": "always", + "texture2D": "10_0", + "texture3D": "10_0", + "textureCube": "10_0", "shaderSample": "never", - "renderTarget": "always", + "renderTarget": "10_0", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_R32G32_SINT": { - "texture2D": "always", - "texture3D": "always", - "textureCube": "always", + "texture2D": "10_0", + "texture3D": "10_0", + "textureCube": "10_0", "shaderSample": "never", - "renderTarget": "always", + "renderTarget": "10_0", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_R32G8X24_TYPELESS": { - "texture2D": "always", + "texture2D": "10_0", "texture3D": "never", - "textureCube": "always", + "textureCube": "10_0", "shaderSample": "never", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_D32_FLOAT_S8X24_UINT": { @@ -208,7 +228,8 @@ "shaderSample": "never", "renderTarget": "never", "multisampleRT": "check", - "depthStencil": "always" + "depthStencil": "10_0", + "mipAutoGen": "never" }, "DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS": { @@ -218,7 +239,8 @@ "shaderSample": "10_0check10_1always", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_X32_TYPELESS_G8X24_UINT": { @@ -228,47 +250,52 @@ "shaderSample": "never", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_R10G10B10A2_TYPELESS": { - "texture2D": "always", - "texture3D": "always", - "textureCube": "always", + "texture2D": "10_0", + "texture3D": "10_0", + "textureCube": "10_0", "shaderSample": "never", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_R10G10B10A2_UNORM": { - "texture2D": "always", - "texture3D": "always", - "textureCube": "always", + "texture2D": "10_0", + "texture3D": "10_0", + "textureCube": "10_0", "shaderSample": "10_0", - "renderTarget": "always", + "renderTarget": "10_0", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "10_0" }, "DXGI_FORMAT_R10G10B10A2_UINT": { - "texture2D": "always", - "texture3D": "always", - "textureCube": "always", + "texture2D": "10_0", + "texture3D": "10_0", + "textureCube": "10_0", "shaderSample": "never", - "renderTarget": "always", + "renderTarget": "10_0", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_R11G11B10_FLOAT": { - "texture2D": "always", - "texture3D": "always", - "textureCube": "always", + "texture2D": "10_0", + "texture3D": "10_0", + "textureCube": "10_0", "shaderSample": "10_0", - "renderTarget": "always", + "renderTarget": "10_0", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "10_0" }, "DXGI_FORMAT_R8G8B8A8_TYPELESS": { @@ -278,57 +305,63 @@ "shaderSample": "never", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_R8G8B8A8_UNORM": { "texture2D": "always", "texture3D": "always", "textureCube": "always", - "shaderSample": "10_0", + "shaderSample": "always", "renderTarget": "always", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "always" }, "DXGI_FORMAT_R8G8B8A8_UNORM_SRGB": { "texture2D": "always", "texture3D": "always", "textureCube": "always", - "shaderSample": "10_0", + "shaderSample": "always", "renderTarget": "always", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "always" }, "DXGI_FORMAT_R8G8B8A8_UINT": { - "texture2D": "always", - "texture3D": "always", - "textureCube": "always", + "texture2D": "10_0", + "texture3D": "10_0", + "textureCube": "10_0", "shaderSample": "never", - "renderTarget": "always", + "renderTarget": "10_0", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_R8G8B8A8_SNORM": { "texture2D": "always", "texture3D": "always", "textureCube": "always", - "shaderSample": "10_0", + "shaderSample": "always", "renderTarget": "always", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "10_0" }, "DXGI_FORMAT_R8G8B8A8_SINT": { - "texture2D": "always", - "texture3D": "always", - "textureCube": "always", + "texture2D": "10_0", + "texture3D": "10_0", + "textureCube": "10_0", "shaderSample": "never", - "renderTarget": "always", + "renderTarget": "10_0", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_R16G16_TYPELESS": { @@ -338,7 +371,8 @@ "shaderSample": "never", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_R16G16_FLOAT": { @@ -348,57 +382,63 @@ "shaderSample": "10_0", "renderTarget": "always", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "always" }, "DXGI_FORMAT_R16G16_UNORM": { "texture2D": "always", "texture3D": "always", "textureCube": "always", - "shaderSample": "10_0", + "shaderSample": "always", "renderTarget": "always", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "always" }, "DXGI_FORMAT_R16G16_UINT": { - "texture2D": "always", - "texture3D": "always", - "textureCube": "always", + "texture2D": "10_0", + "texture3D": "10_0", + "textureCube": "10_0", "shaderSample": "never", - "renderTarget": "always", + "renderTarget": "10_0", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_R16G16_SNORM": { "texture2D": "always", "texture3D": "always", "textureCube": "always", - "shaderSample": "10_0", + "shaderSample": "always", "renderTarget": "always", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "10_0" }, "DXGI_FORMAT_R16G16_SINT": { - "texture2D": "always", - "texture3D": "always", - "textureCube": "always", + "texture2D": "10_0", + "texture3D": "10_0", + "textureCube": "10_0", "shaderSample": "never", - "renderTarget": "always", + "renderTarget": "10_0", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_R32_TYPELESS": { - "texture2D": "always", - "texture3D": "always", - "textureCube": "always", + "texture2D": "10_0", + "texture3D": "10_0", + "textureCube": "10_0", "shaderSample": "never", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_D32_FLOAT": { @@ -408,7 +448,8 @@ "shaderSample": "never", "renderTarget": "never", "multisampleRT": "check", - "depthStencil": "always" + "depthStencil": "10_0", + "mipAutoGen": "never" }, "DXGI_FORMAT_R32_FLOAT": { @@ -418,27 +459,30 @@ "shaderSample": "10_0check10_1always", "renderTarget": "always", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "always" }, "DXGI_FORMAT_R32_UINT": { - "texture2D": "always", - "texture3D": "always", - "textureCube": "always", + "texture2D": "10_0", + "texture3D": "10_0", + "textureCube": "10_0", "shaderSample": "never", - "renderTarget": "always", + "renderTarget": "10_0", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_R32_SINT": { - "texture2D": "always", - "texture3D": "always", - "textureCube": "always", + "texture2D": "10_0", + "texture3D": "10_0", + "textureCube": "10_0", "shaderSample": "never", - "renderTarget": "always", + "renderTarget": "10_0", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_R24G8_TYPELESS": { @@ -448,7 +492,8 @@ "shaderSample": "never", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_D24_UNORM_S8_UINT": { @@ -468,7 +513,8 @@ "shaderSample": "10_0check10_1always", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_X24_TYPELESS_G8_UINT": { @@ -478,7 +524,8 @@ "shaderSample": "never", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_R8G8_TYPELESS": { @@ -488,47 +535,52 @@ "shaderSample": "never", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_R8G8_UNORM": { - "texture2D": "always", - "texture3D": "always", - "textureCube": "always", - "shaderSample": "10_0", - "renderTarget": "always", + "texture2D": "10_0", + "texture3D": "10_0", + "textureCube": "10_0", + "shaderSample": "9_3check_10_0always", + "renderTarget": "9_3check_10_0always", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "10_0" }, "DXGI_FORMAT_R8G8_UINT": { - "texture2D": "always", - "texture3D": "always", - "textureCube": "always", + "texture2D": "10_0", + "texture3D": "10_0", + "textureCube": "10_0", "shaderSample": "never", - "renderTarget": "always", + "renderTarget": "10_0", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_R8G8_SNORM": { "texture2D": "always", - "texture3D": "always", - "textureCube": "always", - "shaderSample": "10_0", - "renderTarget": "always", + "texture3D": "10_0", + "textureCube": "10_0", + "shaderSample": "always", + "renderTarget": "10_0", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "10_0" }, "DXGI_FORMAT_R8G8_SINT": { - "texture2D": "always", - "texture3D": "always", - "textureCube": "always", + "texture2D": "10_0", + "texture3D": "10_0", + "textureCube": "10_0", "shaderSample": "never", - "renderTarget": "always", + "renderTarget": "10_0", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_R16_TYPELESS": { @@ -538,17 +590,19 @@ "shaderSample": "never", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_R16_FLOAT": { - "texture2D": "always", - "texture3D": "always", - "textureCube": "always", + "texture2D": "10_0", + "texture3D": "10_0", + "textureCube": "10_0", "shaderSample": "10_0", - "renderTarget": "always", + "renderTarget": "10_0", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "10_0" }, "DXGI_FORMAT_D16_UNORM": { @@ -558,47 +612,52 @@ "shaderSample": "never", "renderTarget": "never", "multisampleRT": "check", - "depthStencil": "always" + "depthStencil": "always", + "mipAutoGen": "never" }, "DXGI_FORMAT_R16_UNORM": { "texture2D": "always", "texture3D": "always", "textureCube": "always", - "shaderSample": "10_0", - "renderTarget": "always", + "shaderSample": "always", + "renderTarget": "10_0", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "10_0" }, "DXGI_FORMAT_R16_UINT": { - "texture2D": "always", - "texture3D": "always", - "textureCube": "always", + "texture2D": "10_0", + "texture3D": "10_0", + "textureCube": "10_0", "shaderSample": "never", - "renderTarget": "always", + "renderTarget": "10_0", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_R16_SNORM": { - "texture2D": "always", - "texture3D": "always", - "textureCube": "always", + "texture2D": "10_0", + "texture3D": "10_0", + "textureCube": "10_0", "shaderSample": "10_0", - "renderTarget": "always", + "renderTarget": "10_0", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "10_0" }, "DXGI_FORMAT_R16_SINT": { - "texture2D": "always", - "texture3D": "always", - "textureCube": "always", + "texture2D": "10_0", + "texture3D": "10_0", + "textureCube": "10_0", "shaderSample": "never", - "renderTarget": "always", + "renderTarget": "10_0", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_R8_TYPELESS": { @@ -608,47 +667,52 @@ "shaderSample": "never", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_R8_UNORM": { "texture2D": "always", "texture3D": "always", "textureCube": "always", - "shaderSample": "10_0", - "renderTarget": "always", + "shaderSample": "always", + "renderTarget": "9_3check_10_0always", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "10_0" }, "DXGI_FORMAT_R8_UINT": { - "texture2D": "always", - "texture3D": "always", - "textureCube": "always", + "texture2D": "10_0", + "texture3D": "10_0", + "textureCube": "10_0", "shaderSample": "never", - "renderTarget": "always", + "renderTarget": "10_0", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_R8_SNORM": { - "texture2D": "always", - "texture3D": "always", - "textureCube": "always", + "texture2D": "10_0", + "texture3D": "10_0", + "textureCube": "10_0", "shaderSample": "10_0", - "renderTarget": "always", + "renderTarget": "10_0", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "10_0" }, "DXGI_FORMAT_R8_SINT": { - "texture2D": "always", - "texture3D": "always", - "textureCube": "always", + "texture2D": "10_0", + "texture3D": "10_0", + "textureCube": "10_0", "shaderSample": "never", - "renderTarget": "always", + "renderTarget": "10_0", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_A8_UNORM": { @@ -658,7 +722,8 @@ "shaderSample": "10_0", "renderTarget": "always", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "10_0" }, "DXGI_FORMAT_R1_UNORM": { @@ -668,17 +733,19 @@ "shaderSample": "never", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_R9G9B9E5_SHAREDEXP": { - "texture2D": "always", - "texture3D": "always", - "textureCube": "always", + "texture2D": "10_0", + "texture3D": "10_0", + "textureCube": "10_0", "shaderSample": "10_0", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_R8G8_B8G8_UNORM": { @@ -688,7 +755,8 @@ "shaderSample": "10_0", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_G8R8_G8B8_UNORM": { @@ -698,7 +766,8 @@ "shaderSample": "10_0", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_BC1_TYPELESS": { @@ -708,27 +777,30 @@ "shaderSample": "never", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_BC1_UNORM": { "texture2D": "always", "texture3D": "always", "textureCube": "always", - "shaderSample": "10_0", + "shaderSample": "always", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_BC1_UNORM_SRGB": { "texture2D": "always", "texture3D": "always", "textureCube": "always", - "shaderSample": "10_0", + "shaderSample": "always", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_BC2_TYPELESS": { @@ -738,27 +810,30 @@ "shaderSample": "never", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_BC2_UNORM": { "texture2D": "always", "texture3D": "always", "textureCube": "always", - "shaderSample": "10_0", + "shaderSample": "always", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_BC2_UNORM_SRGB": { "texture2D": "always", "texture3D": "always", "textureCube": "always", - "shaderSample": "10_0", + "shaderSample": "always", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_BC3_TYPELESS": { @@ -768,27 +843,30 @@ "shaderSample": "never", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_BC3_UNORM": { "texture2D": "always", "texture3D": "always", "textureCube": "always", - "shaderSample": "10_0", + "shaderSample": "always", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_BC3_UNORM_SRGB": { "texture2D": "always", "texture3D": "always", "textureCube": "always", - "shaderSample": "10_0", + "shaderSample": "always", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_BC4_TYPELESS": { @@ -798,7 +876,8 @@ "shaderSample": "never", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_BC4_UNORM": { @@ -808,7 +887,8 @@ "shaderSample": "10_0", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_BC4_SNORM": { @@ -818,7 +898,8 @@ "shaderSample": "10_0", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_BC5_TYPELESS": { @@ -828,7 +909,8 @@ "shaderSample": "never", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_BC5_UNORM": { @@ -838,7 +920,8 @@ "shaderSample": "10_0", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_BC5_SNORM": { @@ -848,7 +931,8 @@ "shaderSample": "10_0", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_B5G6R5_UNORM": { @@ -858,7 +942,8 @@ "shaderSample": "dxgi1_2", "renderTarget": "dxgi1_2", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "dxgi1_2" }, "DXGI_FORMAT_B5G5R5A1_UNORM": { @@ -868,17 +953,19 @@ "shaderSample": "dxgi1_2", "renderTarget": "check", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "dxgi1_2" }, "DXGI_FORMAT_B8G8R8A8_UNORM": { "texture2D": "check", "texture3D": "check", "textureCube": "check", - "shaderSample": "10_0check11_0always", - "renderTarget": "10_0check11_0always", + "shaderSample": "9_3always_10_0check11_0always", + "renderTarget": "9_3always_10_0check11_0always", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "always" }, "DXGI_FORMAT_B8G8R8X8_UNORM": { @@ -888,7 +975,8 @@ "shaderSample": "10_0check11_0always", "renderTarget": "11_0", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM": { @@ -898,7 +986,8 @@ "shaderSample": "never", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_B8G8R8A8_TYPELESS": { @@ -908,7 +997,8 @@ "shaderSample": "never", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_B8G8R8A8_UNORM_SRGB": { @@ -918,7 +1008,8 @@ "shaderSample": "10_0check11_0always", "renderTarget": "11_0", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_B8G8R8X8_TYPELESS": { @@ -928,7 +1019,8 @@ "shaderSample": "never", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_B8G8R8X8_UNORM_SRGB": { @@ -938,7 +1030,8 @@ "shaderSample": "10_0check11_0always", "renderTarget": "11_0", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_BC6H_TYPELESS": { @@ -948,7 +1041,8 @@ "shaderSample": "never", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_BC6H_UF16": { @@ -958,7 +1052,8 @@ "shaderSample": "11_0", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_BC6H_SF16": { @@ -968,7 +1063,8 @@ "shaderSample": "11_0", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_BC7_TYPELESS": { @@ -978,7 +1074,8 @@ "shaderSample": "never", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_BC7_UNORM": { @@ -988,7 +1085,8 @@ "shaderSample": "11_0", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_BC7_UNORM_SRGB": { @@ -998,7 +1096,8 @@ "shaderSample": "11_0", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_AYUV": { @@ -1008,7 +1107,8 @@ "shaderSample": "11_1", "renderTarget": "11_1", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_Y410": { @@ -1018,7 +1118,8 @@ "shaderSample": "11_1", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_Y416": { @@ -1028,7 +1129,8 @@ "shaderSample": "11_1", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_NV12": { @@ -1038,7 +1140,8 @@ "shaderSample": "11_1", "renderTarget": "11_1", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_P010": { @@ -1048,7 +1151,8 @@ "shaderSample": "11_1", "renderTarget": "11_1", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_P016": { @@ -1058,7 +1162,8 @@ "shaderSample": "11_1", "renderTarget": "11_1", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_420_OPAQUE": { @@ -1068,7 +1173,8 @@ "shaderSample": "never", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_YUY2": { @@ -1078,7 +1184,8 @@ "shaderSample": "11_1", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_Y210": { @@ -1088,7 +1195,8 @@ "shaderSample": "11_1", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_Y216": { @@ -1098,7 +1206,8 @@ "shaderSample": "11_1", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_NV11": { @@ -1108,7 +1217,8 @@ "shaderSample": "11_1", "renderTarget": "11_1", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_AI44": { @@ -1118,7 +1228,8 @@ "shaderSample": "never", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_IA44": { @@ -1128,7 +1239,8 @@ "shaderSample": "never", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_P8": { @@ -1138,7 +1250,8 @@ "shaderSample": "never", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_A8P8": { @@ -1148,7 +1261,8 @@ "shaderSample": "never", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_B4G4R4A4_UNORM": { @@ -1158,7 +1272,8 @@ "shaderSample": "dxgi1_2", "renderTarget": "check", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "dxgi1_2" } } ] diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/dxgi_support_table.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/dxgi_support_table.cpp index cbc36445e6..4d7e46bdf2 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/dxgi_support_table.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/dxgi_support_table.cpp @@ -26,205 +26,205 @@ namespace d3d11 #define F_RT D3D11_FORMAT_SUPPORT_RENDER_TARGET #define F_MS D3D11_FORMAT_SUPPORT_MULTISAMPLE_RENDERTARGET #define F_DS D3D11_FORMAT_SUPPORT_DEPTH_STENCIL +#define F_MIPGEN D3D11_FORMAT_SUPPORT_MIP_AUTOGEN namespace { const DXGISupport &GetDefaultSupport() { - static UINT AllSupportFlags = D3D11_FORMAT_SUPPORT_TEXTURE2D | - D3D11_FORMAT_SUPPORT_TEXTURE3D | - D3D11_FORMAT_SUPPORT_TEXTURECUBE | - D3D11_FORMAT_SUPPORT_SHADER_SAMPLE | - D3D11_FORMAT_SUPPORT_RENDER_TARGET | - D3D11_FORMAT_SUPPORT_MULTISAMPLE_RENDERTARGET | - D3D11_FORMAT_SUPPORT_DEPTH_STENCIL; + static UINT AllSupportFlags = + D3D11_FORMAT_SUPPORT_TEXTURE2D | D3D11_FORMAT_SUPPORT_TEXTURE3D | + D3D11_FORMAT_SUPPORT_TEXTURECUBE | D3D11_FORMAT_SUPPORT_SHADER_SAMPLE | + D3D11_FORMAT_SUPPORT_RENDER_TARGET | D3D11_FORMAT_SUPPORT_MULTISAMPLE_RENDERTARGET | + D3D11_FORMAT_SUPPORT_DEPTH_STENCIL | D3D11_FORMAT_SUPPORT_MIP_AUTOGEN; static const DXGISupport defaultSupport(0, 0, AllSupportFlags); return defaultSupport; } -const DXGISupport &GetDXGISupport_10_0(DXGI_FORMAT dxgiFormat) +const DXGISupport &GetDXGISupport_9_3(DXGI_FORMAT dxgiFormat) { + // clang-format off switch (dxgiFormat) { case DXGI_FORMAT_420_OPAQUE: { - static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); return info; } case DXGI_FORMAT_A8P8: { - static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); return info; } case DXGI_FORMAT_A8_UNORM: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS, F_MS); return info; } case DXGI_FORMAT_AI44: { - static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); return info; } case DXGI_FORMAT_AYUV: { - static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_RT | F_SAMPLE, F_MS); + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN, F_MS); return info; } case DXGI_FORMAT_B4G4R4A4_UNORM: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS, F_MS | F_RT); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_SAMPLE, F_DS, F_MS | F_RT); return info; } case DXGI_FORMAT_B5G5R5A1_UNORM: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS, F_MS | F_RT); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_SAMPLE, F_DS, F_MS | F_RT); return info; } case DXGI_FORMAT_B5G6R5_UNORM: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT | F_SAMPLE, F_DS, F_MS); return info; } case DXGI_FORMAT_B8G8R8A8_TYPELESS: { - static const DXGISupport info(0, F_DS | F_MS | F_RT | F_SAMPLE, F_2D | F_3D | F_CUBE); + static const DXGISupport info(0, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, F_2D | F_3D | F_CUBE); return info; } case DXGI_FORMAT_B8G8R8A8_UNORM: { - static const DXGISupport info(0, F_DS, F_2D | F_3D | F_CUBE | F_MS | F_RT | F_SAMPLE); + static const DXGISupport info(F_MIPGEN | F_RT | F_SAMPLE, F_DS, F_2D | F_3D | F_CUBE | F_MS); return info; } case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: { - static const DXGISupport info(0, F_DS, F_2D | F_3D | F_CUBE | F_MS | F_SAMPLE); + static const DXGISupport info(0, F_DS | F_MIPGEN, F_2D | F_3D | F_CUBE | F_MS); return info; } case DXGI_FORMAT_B8G8R8X8_TYPELESS: { - static const DXGISupport info(0, F_DS | F_MS | F_RT | F_SAMPLE, F_2D | F_3D | F_CUBE); + static const DXGISupport info(0, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, F_2D | F_3D | F_CUBE); return info; } case DXGI_FORMAT_B8G8R8X8_UNORM: { - static const DXGISupport info(0, F_DS, F_2D | F_3D | F_CUBE | F_MS | F_SAMPLE); + static const DXGISupport info(0, F_DS | F_MIPGEN, F_2D | F_3D | F_CUBE | F_MS); return info; } case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB: { - static const DXGISupport info(0, F_DS, F_2D | F_3D | F_CUBE | F_MS | F_SAMPLE); + static const DXGISupport info(0, F_DS | F_MIPGEN, F_2D | F_3D | F_CUBE | F_MS); return info; } case DXGI_FORMAT_BC1_TYPELESS: { - static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); return info; } case DXGI_FORMAT_BC1_UNORM: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MS | F_RT, 0); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MIPGEN | F_MS | F_RT, 0); return info; } case DXGI_FORMAT_BC1_UNORM_SRGB: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MS | F_RT, 0); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MIPGEN | F_MS | F_RT, 0); return info; } case DXGI_FORMAT_BC2_TYPELESS: { - static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); return info; } case DXGI_FORMAT_BC2_UNORM: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MS | F_RT, 0); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MIPGEN | F_MS | F_RT, 0); return info; } case DXGI_FORMAT_BC2_UNORM_SRGB: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MS | F_RT, 0); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MIPGEN | F_MS | F_RT, 0); return info; } case DXGI_FORMAT_BC3_TYPELESS: { - static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); return info; } case DXGI_FORMAT_BC3_UNORM: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MS | F_RT, 0); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MIPGEN | F_MS | F_RT, 0); return info; } case DXGI_FORMAT_BC3_UNORM_SRGB: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MS | F_RT, 0); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MIPGEN | F_MS | F_RT, 0); return info; } case DXGI_FORMAT_BC4_SNORM: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MS | F_RT, 0); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_MS | F_RT, 0); return info; } case DXGI_FORMAT_BC4_TYPELESS: { - static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); return info; } case DXGI_FORMAT_BC4_UNORM: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MS | F_RT, 0); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_MS | F_RT, 0); return info; } case DXGI_FORMAT_BC5_SNORM: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MS | F_RT, 0); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_MS | F_RT, 0); return info; } case DXGI_FORMAT_BC5_TYPELESS: { - static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); return info; } case DXGI_FORMAT_BC5_UNORM: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MS | F_RT, 0); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_MS | F_RT, 0); return info; } case DXGI_FORMAT_BC6H_SF16: { - static const DXGISupport info(0, F_DS | F_MS | F_RT, 0); + static const DXGISupport info(0, F_DS | F_MIPGEN | F_MS | F_RT, 0); return info; } case DXGI_FORMAT_BC6H_TYPELESS: { - static const DXGISupport info(0, F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(0, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); return info; } case DXGI_FORMAT_BC6H_UF16: { - static const DXGISupport info(0, F_DS | F_MS | F_RT, 0); + static const DXGISupport info(0, F_DS | F_MIPGEN | F_MS | F_RT, 0); return info; } case DXGI_FORMAT_BC7_TYPELESS: { - static const DXGISupport info(0, F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(0, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); return info; } case DXGI_FORMAT_BC7_UNORM: { - static const DXGISupport info(0, F_DS | F_MS | F_RT, 0); + static const DXGISupport info(0, F_DS | F_MIPGEN | F_MS | F_RT, 0); return info; } case DXGI_FORMAT_BC7_UNORM_SRGB: { - static const DXGISupport info(0, F_DS | F_MS | F_RT, 0); + static const DXGISupport info(0, F_DS | F_MIPGEN | F_MS | F_RT, 0); return info; } case DXGI_FORMAT_D16_UNORM: { - static const DXGISupport info(F_2D | F_CUBE | F_DS, F_3D | F_RT | F_SAMPLE, F_MS); + static const DXGISupport info(F_2D | F_CUBE | F_DS, F_3D | F_MIPGEN | F_RT | F_SAMPLE, F_MS); return info; } case DXGI_FORMAT_D24_UNORM_S8_UINT: @@ -234,112 +234,112 @@ const DXGISupport &GetDXGISupport_10_0(DXGI_FORMAT dxgiFormat) } case DXGI_FORMAT_D32_FLOAT: { - static const DXGISupport info(F_2D | F_CUBE | F_DS, F_3D | F_RT | F_SAMPLE, F_MS); + static const DXGISupport info(F_2D | F_CUBE, F_3D | F_MIPGEN | F_RT | F_SAMPLE, F_MS); return info; } case DXGI_FORMAT_D32_FLOAT_S8X24_UINT: { - static const DXGISupport info(F_2D | F_CUBE | F_DS, F_3D | F_RT | F_SAMPLE, F_MS); + static const DXGISupport info(F_2D | F_CUBE, F_3D | F_MIPGEN | F_RT | F_SAMPLE, F_MS); return info; } case DXGI_FORMAT_G8R8_G8B8_UNORM: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MS | F_RT, 0); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_MS | F_RT, 0); return info; } case DXGI_FORMAT_IA44: { - static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); return info; } case DXGI_FORMAT_NV11: { - static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_RT | F_SAMPLE, F_MS); + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN, F_MS); return info; } case DXGI_FORMAT_NV12: { - static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_RT | F_SAMPLE, F_MS); + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN, F_MS); return info; } case DXGI_FORMAT_P010: { - static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_RT | F_SAMPLE, F_MS); + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN, F_MS); return info; } case DXGI_FORMAT_P016: { - static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_RT | F_SAMPLE, F_MS); + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN, F_MS); return info; } case DXGI_FORMAT_P8: { - static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); return info; } case DXGI_FORMAT_R10G10B10A2_TYPELESS: { - static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(0, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); return info; } case DXGI_FORMAT_R10G10B10A2_UINT: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS); + static const DXGISupport info(0, F_DS | F_MIPGEN | F_SAMPLE, F_MS); return info; } case DXGI_FORMAT_R10G10B10A2_UNORM: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS); + static const DXGISupport info(0, F_DS, F_MS); return info; } case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM: { - static const DXGISupport info(0, F_CUBE | F_DS | F_MS | F_RT | F_SAMPLE, F_2D | F_3D); + static const DXGISupport info(0, F_CUBE | F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, F_2D | F_3D); return info; } case DXGI_FORMAT_R11G11B10_FLOAT: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS); + static const DXGISupport info(0, F_DS, F_MS); return info; } case DXGI_FORMAT_R16G16B16A16_FLOAT: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT, F_DS, F_MS | F_SAMPLE); return info; } case DXGI_FORMAT_R16G16B16A16_SINT: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS); + static const DXGISupport info(0, F_DS | F_MIPGEN | F_SAMPLE, F_MS); return info; } case DXGI_FORMAT_R16G16B16A16_SNORM: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS); + static const DXGISupport info(0, F_DS, F_MS); return info; } case DXGI_FORMAT_R16G16B16A16_TYPELESS: { - static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); return info; } case DXGI_FORMAT_R16G16B16A16_UINT: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS); + static const DXGISupport info(0, F_DS | F_MIPGEN | F_SAMPLE, F_MS); return info; } case DXGI_FORMAT_R16G16B16A16_UNORM: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT | F_SAMPLE, F_DS, F_MS); return info; } case DXGI_FORMAT_R16G16_FLOAT: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT, F_DS, F_MS); return info; } case DXGI_FORMAT_R16G16_SINT: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS); + static const DXGISupport info(0, F_DS | F_MIPGEN | F_SAMPLE, F_MS); return info; } case DXGI_FORMAT_R16G16_SNORM: @@ -349,157 +349,157 @@ const DXGISupport &GetDXGISupport_10_0(DXGI_FORMAT dxgiFormat) } case DXGI_FORMAT_R16G16_TYPELESS: { - static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); return info; } case DXGI_FORMAT_R16G16_UINT: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS); + static const DXGISupport info(0, F_DS | F_MIPGEN | F_SAMPLE, F_MS); return info; } case DXGI_FORMAT_R16G16_UNORM: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT | F_SAMPLE, F_DS, F_MS); return info; } case DXGI_FORMAT_R16_FLOAT: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS); + static const DXGISupport info(0, F_DS, F_MS); return info; } case DXGI_FORMAT_R16_SINT: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS); + static const DXGISupport info(0, F_DS | F_MIPGEN | F_SAMPLE, F_MS); return info; } case DXGI_FORMAT_R16_SNORM: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS); + static const DXGISupport info(0, F_DS, F_MS); return info; } case DXGI_FORMAT_R16_TYPELESS: { - static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); return info; } case DXGI_FORMAT_R16_UINT: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS); + static const DXGISupport info(0, F_DS | F_MIPGEN | F_SAMPLE, F_MS); return info; } case DXGI_FORMAT_R16_UNORM: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS, F_MS); return info; } case DXGI_FORMAT_R1_UNORM: { - static const DXGISupport info(F_2D, F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(F_2D, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); return info; } case DXGI_FORMAT_R24G8_TYPELESS: { - static const DXGISupport info(F_2D | F_CUBE, F_3D | F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(F_2D | F_CUBE, F_3D | F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); return info; } case DXGI_FORMAT_R24_UNORM_X8_TYPELESS: { - static const DXGISupport info(F_2D | F_CUBE, F_3D | F_DS | F_MS | F_RT, F_SAMPLE); + static const DXGISupport info(F_2D | F_CUBE, F_3D | F_DS | F_MIPGEN | F_MS | F_RT, 0); return info; } case DXGI_FORMAT_R32G32B32A32_FLOAT: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS, F_MS | F_SAMPLE); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT, F_DS, F_MS); return info; } case DXGI_FORMAT_R32G32B32A32_SINT: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS); + static const DXGISupport info(0, F_DS | F_MIPGEN | F_SAMPLE, F_MS); return info; } case DXGI_FORMAT_R32G32B32A32_TYPELESS: { - static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); return info; } case DXGI_FORMAT_R32G32B32A32_UINT: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS); + static const DXGISupport info(0, F_DS | F_MIPGEN | F_SAMPLE, F_MS); return info; } case DXGI_FORMAT_R32G32B32_FLOAT: { - static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS, F_MS | F_RT); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN, F_MS | F_RT); return info; } case DXGI_FORMAT_R32G32B32_SINT: { - static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_SAMPLE, F_MS | F_RT); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_SAMPLE, F_MS | F_RT); return info; } case DXGI_FORMAT_R32G32B32_TYPELESS: { - static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); return info; } case DXGI_FORMAT_R32G32B32_UINT: { - static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_SAMPLE, F_MS | F_RT); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_SAMPLE, F_MS | F_RT); return info; } case DXGI_FORMAT_R32G32_FLOAT: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS, F_MS | F_SAMPLE); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS, F_MS); return info; } case DXGI_FORMAT_R32G32_SINT: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS); + static const DXGISupport info(0, F_DS | F_MIPGEN | F_SAMPLE, F_MS); return info; } case DXGI_FORMAT_R32G32_TYPELESS: { - static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); return info; } case DXGI_FORMAT_R32G32_UINT: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS); + static const DXGISupport info(0, F_DS | F_MIPGEN | F_SAMPLE, F_MS); return info; } case DXGI_FORMAT_R32G8X24_TYPELESS: { - static const DXGISupport info(F_2D | F_CUBE, F_3D | F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(0, F_3D | F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); return info; } case DXGI_FORMAT_R32_FLOAT: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS, F_MS | F_SAMPLE); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT, F_DS, F_MS); return info; } case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS: { - static const DXGISupport info(F_2D | F_CUBE, F_3D | F_DS | F_MS | F_RT, F_SAMPLE); + static const DXGISupport info(F_2D | F_CUBE, F_3D | F_DS | F_MIPGEN | F_MS | F_RT, 0); return info; } case DXGI_FORMAT_R32_SINT: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS); + static const DXGISupport info(0, F_DS | F_MIPGEN | F_SAMPLE, F_MS); return info; } case DXGI_FORMAT_R32_TYPELESS: { - static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(0, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); return info; } case DXGI_FORMAT_R32_UINT: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS); + static const DXGISupport info(0, F_DS | F_MIPGEN | F_SAMPLE, F_MS); return info; } case DXGI_FORMAT_R8G8B8A8_SINT: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS); + static const DXGISupport info(0, F_DS | F_MIPGEN | F_SAMPLE, F_MS); return info; } case DXGI_FORMAT_R8G8B8A8_SNORM: @@ -509,122 +509,122 @@ const DXGISupport &GetDXGISupport_10_0(DXGI_FORMAT dxgiFormat) } case DXGI_FORMAT_R8G8B8A8_TYPELESS: { - static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); return info; } case DXGI_FORMAT_R8G8B8A8_UINT: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS); + static const DXGISupport info(0, F_DS | F_MIPGEN | F_SAMPLE, F_MS); return info; } case DXGI_FORMAT_R8G8B8A8_UNORM: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT | F_SAMPLE, F_DS, F_MS); return info; } case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT | F_SAMPLE, F_DS, F_MS); return info; } case DXGI_FORMAT_R8G8_B8G8_UNORM: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MS | F_RT, 0); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_MS | F_RT, 0); return info; } case DXGI_FORMAT_R8G8_SINT: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS); + static const DXGISupport info(0, F_DS | F_MIPGEN | F_SAMPLE, F_MS); return info; } case DXGI_FORMAT_R8G8_SNORM: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS); + static const DXGISupport info(F_2D | F_SAMPLE, F_DS, F_MS); return info; } case DXGI_FORMAT_R8G8_TYPELESS: { - static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); return info; } case DXGI_FORMAT_R8G8_UINT: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS); + static const DXGISupport info(0, F_DS | F_MIPGEN | F_SAMPLE, F_MS); return info; } case DXGI_FORMAT_R8G8_UNORM: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS); + static const DXGISupport info(0, F_DS, F_MS | F_RT | F_SAMPLE); return info; } case DXGI_FORMAT_R8_SINT: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS); + static const DXGISupport info(0, F_DS | F_MIPGEN | F_SAMPLE, F_MS); return info; } case DXGI_FORMAT_R8_SNORM: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS); + static const DXGISupport info(0, F_DS, F_MS); return info; } case DXGI_FORMAT_R8_TYPELESS: { - static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); return info; } case DXGI_FORMAT_R8_UINT: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS); + static const DXGISupport info(0, F_DS | F_MIPGEN | F_SAMPLE, F_MS); return info; } case DXGI_FORMAT_R8_UNORM: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS, F_MS | F_RT); return info; } case DXGI_FORMAT_R9G9B9E5_SHAREDEXP: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MS | F_RT, 0); + static const DXGISupport info(0, F_DS | F_MIPGEN | F_MS | F_RT, 0); return info; } case DXGI_FORMAT_UNKNOWN: { - static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); return info; } case DXGI_FORMAT_X24_TYPELESS_G8_UINT: { - static const DXGISupport info(F_2D | F_CUBE, F_3D | F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(F_2D | F_CUBE, F_3D | F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); return info; } case DXGI_FORMAT_X32_TYPELESS_G8X24_UINT: { - static const DXGISupport info(F_2D | F_CUBE, F_3D | F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(F_2D | F_CUBE, F_3D | F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); return info; } case DXGI_FORMAT_Y210: { - static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN | F_MS | F_RT, 0); return info; } case DXGI_FORMAT_Y216: { - static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN | F_MS | F_RT, 0); return info; } case DXGI_FORMAT_Y410: { - static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN | F_MS | F_RT, 0); return info; } case DXGI_FORMAT_Y416: { - static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN | F_MS | F_RT, 0); return info; } case DXGI_FORMAT_YUY2: { - static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN | F_MS | F_RT, 0); return info; } @@ -632,190 +632,192 @@ const DXGISupport &GetDXGISupport_10_0(DXGI_FORMAT dxgiFormat) UNREACHABLE(); return GetDefaultSupport(); } + // clang-format on } -const DXGISupport &GetDXGISupport_10_1(DXGI_FORMAT dxgiFormat) +const DXGISupport &GetDXGISupport_10_0(DXGI_FORMAT dxgiFormat) { + // clang-format off switch (dxgiFormat) { case DXGI_FORMAT_420_OPAQUE: { - static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); return info; } case DXGI_FORMAT_A8P8: { - static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); return info; } case DXGI_FORMAT_A8_UNORM: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT | F_SAMPLE, F_DS, F_MS); return info; } case DXGI_FORMAT_AI44: { - static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); return info; } case DXGI_FORMAT_AYUV: { - static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_RT | F_SAMPLE, F_MS); + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN, F_MS); return info; } case DXGI_FORMAT_B4G4R4A4_UNORM: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS, F_MS | F_RT); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_SAMPLE, F_DS, F_MS | F_RT); return info; } case DXGI_FORMAT_B5G5R5A1_UNORM: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS, F_MS | F_RT); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_SAMPLE, F_DS, F_MS | F_RT); return info; } case DXGI_FORMAT_B5G6R5_UNORM: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT | F_SAMPLE, F_DS, F_MS); return info; } case DXGI_FORMAT_B8G8R8A8_TYPELESS: { - static const DXGISupport info(0, F_DS | F_MS | F_RT | F_SAMPLE, F_2D | F_3D | F_CUBE); + static const DXGISupport info(0, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, F_2D | F_3D | F_CUBE); return info; } case DXGI_FORMAT_B8G8R8A8_UNORM: { - static const DXGISupport info(0, F_DS, F_2D | F_3D | F_CUBE | F_MS | F_RT | F_SAMPLE); + static const DXGISupport info(F_MIPGEN, F_DS, F_2D | F_3D | F_CUBE | F_MS | F_RT | F_SAMPLE); return info; } case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: { - static const DXGISupport info(0, F_DS, F_2D | F_3D | F_CUBE | F_MS | F_SAMPLE); + static const DXGISupport info(0, F_DS | F_MIPGEN, F_2D | F_3D | F_CUBE | F_MS | F_SAMPLE); return info; } case DXGI_FORMAT_B8G8R8X8_TYPELESS: { - static const DXGISupport info(0, F_DS | F_MS | F_RT | F_SAMPLE, F_2D | F_3D | F_CUBE); + static const DXGISupport info(0, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, F_2D | F_3D | F_CUBE); return info; } case DXGI_FORMAT_B8G8R8X8_UNORM: { - static const DXGISupport info(0, F_DS, F_2D | F_3D | F_CUBE | F_MS | F_SAMPLE); + static const DXGISupport info(0, F_DS | F_MIPGEN, F_2D | F_3D | F_CUBE | F_MS | F_SAMPLE); return info; } case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB: { - static const DXGISupport info(0, F_DS, F_2D | F_3D | F_CUBE | F_MS | F_SAMPLE); + static const DXGISupport info(0, F_DS | F_MIPGEN, F_2D | F_3D | F_CUBE | F_MS | F_SAMPLE); return info; } case DXGI_FORMAT_BC1_TYPELESS: { - static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); return info; } case DXGI_FORMAT_BC1_UNORM: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MS | F_RT, 0); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MIPGEN | F_MS | F_RT, 0); return info; } case DXGI_FORMAT_BC1_UNORM_SRGB: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MS | F_RT, 0); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MIPGEN | F_MS | F_RT, 0); return info; } case DXGI_FORMAT_BC2_TYPELESS: { - static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); return info; } case DXGI_FORMAT_BC2_UNORM: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MS | F_RT, 0); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MIPGEN | F_MS | F_RT, 0); return info; } case DXGI_FORMAT_BC2_UNORM_SRGB: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MS | F_RT, 0); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MIPGEN | F_MS | F_RT, 0); return info; } case DXGI_FORMAT_BC3_TYPELESS: { - static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); return info; } case DXGI_FORMAT_BC3_UNORM: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MS | F_RT, 0); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MIPGEN | F_MS | F_RT, 0); return info; } case DXGI_FORMAT_BC3_UNORM_SRGB: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MS | F_RT, 0); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MIPGEN | F_MS | F_RT, 0); return info; } case DXGI_FORMAT_BC4_SNORM: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MS | F_RT, 0); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MIPGEN | F_MS | F_RT, 0); return info; } case DXGI_FORMAT_BC4_TYPELESS: { - static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); return info; } case DXGI_FORMAT_BC4_UNORM: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MS | F_RT, 0); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MIPGEN | F_MS | F_RT, 0); return info; } case DXGI_FORMAT_BC5_SNORM: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MS | F_RT, 0); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MIPGEN | F_MS | F_RT, 0); return info; } case DXGI_FORMAT_BC5_TYPELESS: { - static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); return info; } case DXGI_FORMAT_BC5_UNORM: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MS | F_RT, 0); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MIPGEN | F_MS | F_RT, 0); return info; } case DXGI_FORMAT_BC6H_SF16: { - static const DXGISupport info(0, F_DS | F_MS | F_RT, 0); + static const DXGISupport info(0, F_DS | F_MIPGEN | F_MS | F_RT, 0); return info; } case DXGI_FORMAT_BC6H_TYPELESS: { - static const DXGISupport info(0, F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(0, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); return info; } case DXGI_FORMAT_BC6H_UF16: { - static const DXGISupport info(0, F_DS | F_MS | F_RT, 0); + static const DXGISupport info(0, F_DS | F_MIPGEN | F_MS | F_RT, 0); return info; } case DXGI_FORMAT_BC7_TYPELESS: { - static const DXGISupport info(0, F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(0, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); return info; } case DXGI_FORMAT_BC7_UNORM: { - static const DXGISupport info(0, F_DS | F_MS | F_RT, 0); + static const DXGISupport info(0, F_DS | F_MIPGEN | F_MS | F_RT, 0); return info; } case DXGI_FORMAT_BC7_UNORM_SRGB: { - static const DXGISupport info(0, F_DS | F_MS | F_RT, 0); + static const DXGISupport info(0, F_DS | F_MIPGEN | F_MS | F_RT, 0); return info; } case DXGI_FORMAT_D16_UNORM: { - static const DXGISupport info(F_2D | F_CUBE | F_DS, F_3D | F_RT | F_SAMPLE, F_MS); + static const DXGISupport info(F_2D | F_CUBE | F_DS, F_3D | F_MIPGEN | F_RT | F_SAMPLE, F_MS); return info; } case DXGI_FORMAT_D24_UNORM_S8_UINT: @@ -825,397 +827,397 @@ const DXGISupport &GetDXGISupport_10_1(DXGI_FORMAT dxgiFormat) } case DXGI_FORMAT_D32_FLOAT: { - static const DXGISupport info(F_2D | F_CUBE | F_DS, F_3D | F_RT | F_SAMPLE, F_MS); + static const DXGISupport info(F_2D | F_CUBE | F_DS, F_3D | F_MIPGEN | F_RT | F_SAMPLE, F_MS); return info; } case DXGI_FORMAT_D32_FLOAT_S8X24_UINT: { - static const DXGISupport info(F_2D | F_CUBE | F_DS, F_3D | F_RT | F_SAMPLE, F_MS); + static const DXGISupport info(F_2D | F_CUBE | F_DS, F_3D | F_MIPGEN | F_RT | F_SAMPLE, F_MS); return info; } case DXGI_FORMAT_G8R8_G8B8_UNORM: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MS | F_RT, 0); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MIPGEN | F_MS | F_RT, 0); return info; } case DXGI_FORMAT_IA44: { - static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); return info; } case DXGI_FORMAT_NV11: { - static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_RT | F_SAMPLE, F_MS); + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN, F_MS); return info; } case DXGI_FORMAT_NV12: { - static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_RT | F_SAMPLE, F_MS); + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN, F_MS); return info; } case DXGI_FORMAT_P010: { - static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_RT | F_SAMPLE, F_MS); + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN, F_MS); return info; } case DXGI_FORMAT_P016: { - static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_RT | F_SAMPLE, F_MS); + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN, F_MS); return info; } case DXGI_FORMAT_P8: { - static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); return info; } case DXGI_FORMAT_R10G10B10A2_TYPELESS: { - static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); return info; } case DXGI_FORMAT_R10G10B10A2_UINT: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | F_SAMPLE, F_MS); return info; } case DXGI_FORMAT_R10G10B10A2_UNORM: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT | F_SAMPLE, F_DS, F_MS); return info; } case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM: { - static const DXGISupport info(0, F_CUBE | F_DS | F_MS | F_RT | F_SAMPLE, F_2D | F_3D); + static const DXGISupport info(0, F_CUBE | F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, F_2D | F_3D); return info; } case DXGI_FORMAT_R11G11B10_FLOAT: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT | F_SAMPLE, F_DS, F_MS); return info; } case DXGI_FORMAT_R16G16B16A16_FLOAT: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT | F_SAMPLE, F_DS, F_MS); return info; } case DXGI_FORMAT_R16G16B16A16_SINT: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | F_SAMPLE, F_MS); return info; } case DXGI_FORMAT_R16G16B16A16_SNORM: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT | F_SAMPLE, F_DS, F_MS); return info; } case DXGI_FORMAT_R16G16B16A16_TYPELESS: { - static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); return info; } case DXGI_FORMAT_R16G16B16A16_UINT: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | F_SAMPLE, F_MS); return info; } case DXGI_FORMAT_R16G16B16A16_UNORM: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT | F_SAMPLE, F_DS, F_MS); return info; } case DXGI_FORMAT_R16G16_FLOAT: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT | F_SAMPLE, F_DS, F_MS); return info; } case DXGI_FORMAT_R16G16_SINT: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | F_SAMPLE, F_MS); return info; } case DXGI_FORMAT_R16G16_SNORM: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT | F_SAMPLE, F_DS, F_MS); return info; } case DXGI_FORMAT_R16G16_TYPELESS: { - static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); return info; } case DXGI_FORMAT_R16G16_UINT: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | F_SAMPLE, F_MS); return info; } case DXGI_FORMAT_R16G16_UNORM: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT | F_SAMPLE, F_DS, F_MS); return info; } case DXGI_FORMAT_R16_FLOAT: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT | F_SAMPLE, F_DS, F_MS); return info; } case DXGI_FORMAT_R16_SINT: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | F_SAMPLE, F_MS); return info; } case DXGI_FORMAT_R16_SNORM: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT | F_SAMPLE, F_DS, F_MS); return info; } case DXGI_FORMAT_R16_TYPELESS: { - static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); return info; } case DXGI_FORMAT_R16_UINT: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | F_SAMPLE, F_MS); return info; } case DXGI_FORMAT_R16_UNORM: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT | F_SAMPLE, F_DS, F_MS); return info; } case DXGI_FORMAT_R1_UNORM: { - static const DXGISupport info(F_2D, F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(F_2D, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); return info; } case DXGI_FORMAT_R24G8_TYPELESS: { - static const DXGISupport info(F_2D | F_CUBE, F_3D | F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(F_2D | F_CUBE, F_3D | F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); return info; } case DXGI_FORMAT_R24_UNORM_X8_TYPELESS: { - static const DXGISupport info(F_2D | F_CUBE | F_SAMPLE, F_3D | F_DS | F_MS | F_RT, 0); + static const DXGISupport info(F_2D | F_CUBE, F_3D | F_DS | F_MIPGEN | F_MS | F_RT, F_SAMPLE); return info; } case DXGI_FORMAT_R32G32B32A32_FLOAT: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT, F_DS, F_MS | F_SAMPLE); return info; } case DXGI_FORMAT_R32G32B32A32_SINT: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | F_SAMPLE, F_MS); return info; } case DXGI_FORMAT_R32G32B32A32_TYPELESS: { - static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); return info; } case DXGI_FORMAT_R32G32B32A32_UINT: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | F_SAMPLE, F_MS); return info; } case DXGI_FORMAT_R32G32B32_FLOAT: { - static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS, F_MS | F_RT); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN, F_MS | F_RT); return info; } case DXGI_FORMAT_R32G32B32_SINT: { - static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_SAMPLE, F_MS | F_RT); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_SAMPLE, F_MS | F_RT); return info; } case DXGI_FORMAT_R32G32B32_TYPELESS: { - static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); return info; } case DXGI_FORMAT_R32G32B32_UINT: { - static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_SAMPLE, F_MS | F_RT); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_SAMPLE, F_MS | F_RT); return info; } case DXGI_FORMAT_R32G32_FLOAT: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT, F_DS, F_MS | F_SAMPLE); return info; } case DXGI_FORMAT_R32G32_SINT: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | F_SAMPLE, F_MS); return info; } case DXGI_FORMAT_R32G32_TYPELESS: { - static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); return info; } case DXGI_FORMAT_R32G32_UINT: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | F_SAMPLE, F_MS); return info; } case DXGI_FORMAT_R32G8X24_TYPELESS: { - static const DXGISupport info(F_2D | F_CUBE, F_3D | F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(F_2D | F_CUBE, F_3D | F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); return info; } case DXGI_FORMAT_R32_FLOAT: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT, F_DS, F_MS | F_SAMPLE); return info; } case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS: { - static const DXGISupport info(F_2D | F_CUBE | F_SAMPLE, F_3D | F_DS | F_MS | F_RT, 0); + static const DXGISupport info(F_2D | F_CUBE, F_3D | F_DS | F_MIPGEN | F_MS | F_RT, F_SAMPLE); return info; } case DXGI_FORMAT_R32_SINT: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | F_SAMPLE, F_MS); return info; } case DXGI_FORMAT_R32_TYPELESS: { - static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); return info; } case DXGI_FORMAT_R32_UINT: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | F_SAMPLE, F_MS); return info; } case DXGI_FORMAT_R8G8B8A8_SINT: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | F_SAMPLE, F_MS); return info; } case DXGI_FORMAT_R8G8B8A8_SNORM: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT | F_SAMPLE, F_DS, F_MS); return info; } case DXGI_FORMAT_R8G8B8A8_TYPELESS: { - static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); return info; } case DXGI_FORMAT_R8G8B8A8_UINT: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | F_SAMPLE, F_MS); return info; } case DXGI_FORMAT_R8G8B8A8_UNORM: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT | F_SAMPLE, F_DS, F_MS); return info; } case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT | F_SAMPLE, F_DS, F_MS); return info; } case DXGI_FORMAT_R8G8_B8G8_UNORM: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MS | F_RT, 0); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MIPGEN | F_MS | F_RT, 0); return info; } case DXGI_FORMAT_R8G8_SINT: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | F_SAMPLE, F_MS); return info; } case DXGI_FORMAT_R8G8_SNORM: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT | F_SAMPLE, F_DS, F_MS); return info; } case DXGI_FORMAT_R8G8_TYPELESS: { - static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); return info; } case DXGI_FORMAT_R8G8_UINT: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | F_SAMPLE, F_MS); return info; } case DXGI_FORMAT_R8G8_UNORM: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT | F_SAMPLE, F_DS, F_MS); return info; } case DXGI_FORMAT_R8_SINT: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | F_SAMPLE, F_MS); return info; } case DXGI_FORMAT_R8_SNORM: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT | F_SAMPLE, F_DS, F_MS); return info; } case DXGI_FORMAT_R8_TYPELESS: { - static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); return info; } case DXGI_FORMAT_R8_UINT: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | F_SAMPLE, F_MS); return info; } case DXGI_FORMAT_R8_UNORM: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT | F_SAMPLE, F_DS, F_MS); return info; } case DXGI_FORMAT_R9G9B9E5_SHAREDEXP: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MS | F_RT, 0); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MIPGEN | F_MS | F_RT, 0); return info; } case DXGI_FORMAT_UNKNOWN: { - static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); return info; } case DXGI_FORMAT_X24_TYPELESS_G8_UINT: { - static const DXGISupport info(F_2D | F_CUBE, F_3D | F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(F_2D | F_CUBE, F_3D | F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); return info; } case DXGI_FORMAT_X32_TYPELESS_G8X24_UINT: { - static const DXGISupport info(F_2D | F_CUBE, F_3D | F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(F_2D | F_CUBE, F_3D | F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); return info; } case DXGI_FORMAT_Y210: { - static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN | F_MS | F_RT, 0); return info; } case DXGI_FORMAT_Y216: { - static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN | F_MS | F_RT, 0); return info; } case DXGI_FORMAT_Y410: { - static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN | F_MS | F_RT, 0); return info; } case DXGI_FORMAT_Y416: { - static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN | F_MS | F_RT, 0); return info; } case DXGI_FORMAT_YUY2: { - static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN | F_MS | F_RT, 0); return info; } @@ -1223,190 +1225,192 @@ const DXGISupport &GetDXGISupport_10_1(DXGI_FORMAT dxgiFormat) UNREACHABLE(); return GetDefaultSupport(); } + // clang-format on } -const DXGISupport &GetDXGISupport_11_0(DXGI_FORMAT dxgiFormat) +const DXGISupport &GetDXGISupport_10_1(DXGI_FORMAT dxgiFormat) { + // clang-format off switch (dxgiFormat) { case DXGI_FORMAT_420_OPAQUE: { - static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); return info; } case DXGI_FORMAT_A8P8: { - static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); return info; } case DXGI_FORMAT_A8_UNORM: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT | F_SAMPLE, F_DS, F_MS); return info; } case DXGI_FORMAT_AI44: { - static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); return info; } case DXGI_FORMAT_AYUV: { - static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_RT | F_SAMPLE, F_MS); + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN, F_MS); return info; } case DXGI_FORMAT_B4G4R4A4_UNORM: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS, F_MS | F_RT); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_SAMPLE, F_DS, F_MS | F_RT); return info; } case DXGI_FORMAT_B5G5R5A1_UNORM: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS, F_MS | F_RT); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_SAMPLE, F_DS, F_MS | F_RT); return info; } case DXGI_FORMAT_B5G6R5_UNORM: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT | F_SAMPLE, F_DS, F_MS); return info; } case DXGI_FORMAT_B8G8R8A8_TYPELESS: { - static const DXGISupport info(0, F_DS | F_MS | F_RT | F_SAMPLE, F_2D | F_3D | F_CUBE); + static const DXGISupport info(0, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, F_2D | F_3D | F_CUBE); return info; } case DXGI_FORMAT_B8G8R8A8_UNORM: { - static const DXGISupport info(F_RT | F_SAMPLE, F_DS, F_2D | F_3D | F_CUBE | F_MS); + static const DXGISupport info(F_MIPGEN, F_DS, F_2D | F_3D | F_CUBE | F_MS | F_RT | F_SAMPLE); return info; } case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: { - static const DXGISupport info(F_RT | F_SAMPLE, F_DS, F_2D | F_3D | F_CUBE | F_MS); + static const DXGISupport info(0, F_DS | F_MIPGEN, F_2D | F_3D | F_CUBE | F_MS | F_SAMPLE); return info; } case DXGI_FORMAT_B8G8R8X8_TYPELESS: { - static const DXGISupport info(0, F_DS | F_MS | F_RT | F_SAMPLE, F_2D | F_3D | F_CUBE); + static const DXGISupport info(0, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, F_2D | F_3D | F_CUBE); return info; } case DXGI_FORMAT_B8G8R8X8_UNORM: { - static const DXGISupport info(F_RT | F_SAMPLE, F_DS, F_2D | F_3D | F_CUBE | F_MS); + static const DXGISupport info(0, F_DS | F_MIPGEN, F_2D | F_3D | F_CUBE | F_MS | F_SAMPLE); return info; } case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB: { - static const DXGISupport info(F_RT | F_SAMPLE, F_DS, F_2D | F_3D | F_CUBE | F_MS); + static const DXGISupport info(0, F_DS | F_MIPGEN, F_2D | F_3D | F_CUBE | F_MS | F_SAMPLE); return info; } case DXGI_FORMAT_BC1_TYPELESS: { - static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); return info; } case DXGI_FORMAT_BC1_UNORM: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MS | F_RT, 0); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MIPGEN | F_MS | F_RT, 0); return info; } case DXGI_FORMAT_BC1_UNORM_SRGB: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MS | F_RT, 0); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MIPGEN | F_MS | F_RT, 0); return info; } case DXGI_FORMAT_BC2_TYPELESS: { - static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); return info; } case DXGI_FORMAT_BC2_UNORM: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MS | F_RT, 0); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MIPGEN | F_MS | F_RT, 0); return info; } case DXGI_FORMAT_BC2_UNORM_SRGB: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MS | F_RT, 0); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MIPGEN | F_MS | F_RT, 0); return info; } case DXGI_FORMAT_BC3_TYPELESS: { - static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); return info; } case DXGI_FORMAT_BC3_UNORM: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MS | F_RT, 0); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MIPGEN | F_MS | F_RT, 0); return info; } case DXGI_FORMAT_BC3_UNORM_SRGB: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MS | F_RT, 0); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MIPGEN | F_MS | F_RT, 0); return info; } case DXGI_FORMAT_BC4_SNORM: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MS | F_RT, 0); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MIPGEN | F_MS | F_RT, 0); return info; } case DXGI_FORMAT_BC4_TYPELESS: { - static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); return info; } case DXGI_FORMAT_BC4_UNORM: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MS | F_RT, 0); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MIPGEN | F_MS | F_RT, 0); return info; } case DXGI_FORMAT_BC5_SNORM: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MS | F_RT, 0); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MIPGEN | F_MS | F_RT, 0); return info; } case DXGI_FORMAT_BC5_TYPELESS: { - static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); return info; } case DXGI_FORMAT_BC5_UNORM: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MS | F_RT, 0); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MIPGEN | F_MS | F_RT, 0); return info; } case DXGI_FORMAT_BC6H_SF16: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MS | F_RT, 0); + static const DXGISupport info(0, F_DS | F_MIPGEN | F_MS | F_RT, 0); return info; } case DXGI_FORMAT_BC6H_TYPELESS: { - static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(0, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); return info; } case DXGI_FORMAT_BC6H_UF16: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MS | F_RT, 0); + static const DXGISupport info(0, F_DS | F_MIPGEN | F_MS | F_RT, 0); return info; } case DXGI_FORMAT_BC7_TYPELESS: { - static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(0, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); return info; } case DXGI_FORMAT_BC7_UNORM: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MS | F_RT, 0); + static const DXGISupport info(0, F_DS | F_MIPGEN | F_MS | F_RT, 0); return info; } case DXGI_FORMAT_BC7_UNORM_SRGB: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MS | F_RT, 0); + static const DXGISupport info(0, F_DS | F_MIPGEN | F_MS | F_RT, 0); return info; } case DXGI_FORMAT_D16_UNORM: { - static const DXGISupport info(F_2D | F_CUBE | F_DS, F_3D | F_RT | F_SAMPLE, F_MS); + static const DXGISupport info(F_2D | F_CUBE | F_DS, F_3D | F_MIPGEN | F_RT | F_SAMPLE, F_MS); return info; } case DXGI_FORMAT_D24_UNORM_S8_UINT: @@ -1416,397 +1420,1583 @@ const DXGISupport &GetDXGISupport_11_0(DXGI_FORMAT dxgiFormat) } case DXGI_FORMAT_D32_FLOAT: { - static const DXGISupport info(F_2D | F_CUBE | F_DS, F_3D | F_RT | F_SAMPLE, F_MS); + static const DXGISupport info(F_2D | F_CUBE | F_DS, F_3D | F_MIPGEN | F_RT | F_SAMPLE, F_MS); return info; } case DXGI_FORMAT_D32_FLOAT_S8X24_UINT: { - static const DXGISupport info(F_2D | F_CUBE | F_DS, F_3D | F_RT | F_SAMPLE, F_MS); + static const DXGISupport info(F_2D | F_CUBE | F_DS, F_3D | F_MIPGEN | F_RT | F_SAMPLE, F_MS); return info; } case DXGI_FORMAT_G8R8_G8B8_UNORM: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MS | F_RT, 0); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MIPGEN | F_MS | F_RT, 0); return info; } case DXGI_FORMAT_IA44: { - static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); return info; } case DXGI_FORMAT_NV11: { - static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_RT | F_SAMPLE, F_MS); + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN, F_MS); return info; } case DXGI_FORMAT_NV12: { - static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_RT | F_SAMPLE, F_MS); + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN, F_MS); return info; } case DXGI_FORMAT_P010: { - static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_RT | F_SAMPLE, F_MS); + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN, F_MS); return info; } case DXGI_FORMAT_P016: { - static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_RT | F_SAMPLE, F_MS); + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN, F_MS); return info; } case DXGI_FORMAT_P8: { - static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); return info; } case DXGI_FORMAT_R10G10B10A2_TYPELESS: { - static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); return info; } case DXGI_FORMAT_R10G10B10A2_UINT: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | F_SAMPLE, F_MS); return info; } case DXGI_FORMAT_R10G10B10A2_UNORM: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT | F_SAMPLE, F_DS, F_MS); return info; } case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM: { - static const DXGISupport info(0, F_CUBE | F_DS | F_MS | F_RT | F_SAMPLE, F_2D | F_3D); + static const DXGISupport info(0, F_CUBE | F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, F_2D | F_3D); return info; } case DXGI_FORMAT_R11G11B10_FLOAT: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT | F_SAMPLE, F_DS, F_MS); return info; } case DXGI_FORMAT_R16G16B16A16_FLOAT: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT | F_SAMPLE, F_DS, F_MS); return info; } case DXGI_FORMAT_R16G16B16A16_SINT: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | F_SAMPLE, F_MS); return info; } case DXGI_FORMAT_R16G16B16A16_SNORM: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT | F_SAMPLE, F_DS, F_MS); return info; } case DXGI_FORMAT_R16G16B16A16_TYPELESS: { - static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); return info; } case DXGI_FORMAT_R16G16B16A16_UINT: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | F_SAMPLE, F_MS); return info; } case DXGI_FORMAT_R16G16B16A16_UNORM: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT | F_SAMPLE, F_DS, F_MS); return info; } case DXGI_FORMAT_R16G16_FLOAT: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT | F_SAMPLE, F_DS, F_MS); return info; } case DXGI_FORMAT_R16G16_SINT: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | F_SAMPLE, F_MS); return info; } case DXGI_FORMAT_R16G16_SNORM: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT | F_SAMPLE, F_DS, F_MS); return info; } case DXGI_FORMAT_R16G16_TYPELESS: { - static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); return info; } case DXGI_FORMAT_R16G16_UINT: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | F_SAMPLE, F_MS); return info; } case DXGI_FORMAT_R16G16_UNORM: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT | F_SAMPLE, F_DS, F_MS); return info; } case DXGI_FORMAT_R16_FLOAT: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT | F_SAMPLE, F_DS, F_MS); return info; } case DXGI_FORMAT_R16_SINT: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | F_SAMPLE, F_MS); return info; } case DXGI_FORMAT_R16_SNORM: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT | F_SAMPLE, F_DS, F_MS); return info; } case DXGI_FORMAT_R16_TYPELESS: { - static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); return info; } case DXGI_FORMAT_R16_UINT: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | F_SAMPLE, F_MS); return info; } case DXGI_FORMAT_R16_UNORM: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT | F_SAMPLE, F_DS, F_MS); return info; } case DXGI_FORMAT_R1_UNORM: { - static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(F_2D, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); return info; } case DXGI_FORMAT_R24G8_TYPELESS: { - static const DXGISupport info(F_2D | F_CUBE, F_3D | F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(F_2D | F_CUBE, F_3D | F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); return info; } case DXGI_FORMAT_R24_UNORM_X8_TYPELESS: { - static const DXGISupport info(F_2D | F_CUBE | F_SAMPLE, F_3D | F_DS | F_MS | F_RT, 0); + static const DXGISupport info(F_2D | F_CUBE | F_SAMPLE, F_3D | F_DS | F_MIPGEN | F_MS | F_RT, 0); return info; } case DXGI_FORMAT_R32G32B32A32_FLOAT: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT | F_SAMPLE, F_DS, F_MS); return info; } case DXGI_FORMAT_R32G32B32A32_SINT: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | F_SAMPLE, F_MS); return info; } case DXGI_FORMAT_R32G32B32A32_TYPELESS: { - static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); return info; } case DXGI_FORMAT_R32G32B32A32_UINT: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | F_SAMPLE, F_MS); return info; } case DXGI_FORMAT_R32G32B32_FLOAT: { - static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS, F_MS | F_RT); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN, F_MS | F_RT); return info; } case DXGI_FORMAT_R32G32B32_SINT: { - static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_SAMPLE, F_MS | F_RT); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_SAMPLE, F_MS | F_RT); return info; } case DXGI_FORMAT_R32G32B32_TYPELESS: { - static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); return info; } case DXGI_FORMAT_R32G32B32_UINT: { - static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_SAMPLE, F_MS | F_RT); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_SAMPLE, F_MS | F_RT); return info; } case DXGI_FORMAT_R32G32_FLOAT: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT | F_SAMPLE, F_DS, F_MS); return info; } case DXGI_FORMAT_R32G32_SINT: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | F_SAMPLE, F_MS); return info; } case DXGI_FORMAT_R32G32_TYPELESS: { - static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); return info; } case DXGI_FORMAT_R32G32_UINT: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | F_SAMPLE, F_MS); return info; } case DXGI_FORMAT_R32G8X24_TYPELESS: { - static const DXGISupport info(F_2D | F_CUBE, F_3D | F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(F_2D | F_CUBE, F_3D | F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); return info; } case DXGI_FORMAT_R32_FLOAT: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT | F_SAMPLE, F_DS, F_MS); return info; } case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS: { - static const DXGISupport info(F_2D | F_CUBE | F_SAMPLE, F_3D | F_DS | F_MS | F_RT, 0); + static const DXGISupport info(F_2D | F_CUBE | F_SAMPLE, F_3D | F_DS | F_MIPGEN | F_MS | F_RT, 0); return info; } case DXGI_FORMAT_R32_SINT: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | F_SAMPLE, F_MS); return info; } case DXGI_FORMAT_R32_TYPELESS: { - static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); return info; } case DXGI_FORMAT_R32_UINT: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | F_SAMPLE, F_MS); return info; } case DXGI_FORMAT_R8G8B8A8_SINT: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | F_SAMPLE, F_MS); return info; } case DXGI_FORMAT_R8G8B8A8_SNORM: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT | F_SAMPLE, F_DS, F_MS); return info; } case DXGI_FORMAT_R8G8B8A8_TYPELESS: { - static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); return info; } case DXGI_FORMAT_R8G8B8A8_UINT: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | F_SAMPLE, F_MS); return info; } case DXGI_FORMAT_R8G8B8A8_UNORM: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT | F_SAMPLE, F_DS, F_MS); return info; } case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT | F_SAMPLE, F_DS, F_MS); return info; } case DXGI_FORMAT_R8G8_B8G8_UNORM: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MS | F_RT, 0); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MIPGEN | F_MS | F_RT, 0); return info; } case DXGI_FORMAT_R8G8_SINT: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | F_SAMPLE, F_MS); return info; } case DXGI_FORMAT_R8G8_SNORM: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT | F_SAMPLE, F_DS, F_MS); return info; } case DXGI_FORMAT_R8G8_TYPELESS: { - static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); return info; } case DXGI_FORMAT_R8G8_UINT: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | F_SAMPLE, F_MS); return info; } case DXGI_FORMAT_R8G8_UNORM: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT | F_SAMPLE, F_DS, F_MS); return info; } case DXGI_FORMAT_R8_SINT: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | F_SAMPLE, F_MS); return info; } case DXGI_FORMAT_R8_SNORM: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT | F_SAMPLE, F_DS, F_MS); return info; } case DXGI_FORMAT_R8_TYPELESS: { - static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); return info; } case DXGI_FORMAT_R8_UINT: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | F_SAMPLE, F_MS); return info; } case DXGI_FORMAT_R8_UNORM: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT | F_SAMPLE, F_DS, F_MS); + return info; + } + case DXGI_FORMAT_R9G9B9E5_SHAREDEXP: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MIPGEN | F_MS | F_RT, 0); + return info; + } + case DXGI_FORMAT_UNKNOWN: + { + static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); + return info; + } + case DXGI_FORMAT_X24_TYPELESS_G8_UINT: + { + static const DXGISupport info(F_2D | F_CUBE, F_3D | F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); + return info; + } + case DXGI_FORMAT_X32_TYPELESS_G8X24_UINT: + { + static const DXGISupport info(F_2D | F_CUBE, F_3D | F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); + return info; + } + case DXGI_FORMAT_Y210: + { + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN | F_MS | F_RT, 0); + return info; + } + case DXGI_FORMAT_Y216: + { + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN | F_MS | F_RT, 0); + return info; + } + case DXGI_FORMAT_Y410: + { + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN | F_MS | F_RT, 0); + return info; + } + case DXGI_FORMAT_Y416: + { + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN | F_MS | F_RT, 0); + return info; + } + case DXGI_FORMAT_YUY2: + { + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN | F_MS | F_RT, 0); + return info; + } + + default: + UNREACHABLE(); + return GetDefaultSupport(); + } + // clang-format on +} + +const DXGISupport &GetDXGISupport_11_0(DXGI_FORMAT dxgiFormat) +{ + // clang-format off + switch (dxgiFormat) + { + case DXGI_FORMAT_420_OPAQUE: + { + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); + return info; + } + case DXGI_FORMAT_A8P8: + { + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); + return info; + } + case DXGI_FORMAT_A8_UNORM: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT | F_SAMPLE, F_DS, F_MS); + return info; + } + case DXGI_FORMAT_AI44: + { + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); + return info; + } + case DXGI_FORMAT_AYUV: + { + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN, F_MS); + return info; + } + case DXGI_FORMAT_B4G4R4A4_UNORM: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_SAMPLE, F_DS, F_MS | F_RT); + return info; + } + case DXGI_FORMAT_B5G5R5A1_UNORM: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_SAMPLE, F_DS, F_MS | F_RT); + return info; + } + case DXGI_FORMAT_B5G6R5_UNORM: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT | F_SAMPLE, F_DS, F_MS); + return info; + } + case DXGI_FORMAT_B8G8R8A8_TYPELESS: + { + static const DXGISupport info(0, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, F_2D | F_3D | F_CUBE); + return info; + } + case DXGI_FORMAT_B8G8R8A8_UNORM: + { + static const DXGISupport info(F_MIPGEN | F_RT | F_SAMPLE, F_DS, F_2D | F_3D | F_CUBE | F_MS); + return info; + } + case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: + { + static const DXGISupport info(F_RT | F_SAMPLE, F_DS | F_MIPGEN, F_2D | F_3D | F_CUBE | F_MS); + return info; + } + case DXGI_FORMAT_B8G8R8X8_TYPELESS: + { + static const DXGISupport info(0, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, F_2D | F_3D | F_CUBE); + return info; + } + case DXGI_FORMAT_B8G8R8X8_UNORM: + { + static const DXGISupport info(F_RT | F_SAMPLE, F_DS | F_MIPGEN, F_2D | F_3D | F_CUBE | F_MS); + return info; + } + case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB: + { + static const DXGISupport info(F_RT | F_SAMPLE, F_DS | F_MIPGEN, F_2D | F_3D | F_CUBE | F_MS); + return info; + } + case DXGI_FORMAT_BC1_TYPELESS: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); + return info; + } + case DXGI_FORMAT_BC1_UNORM: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MIPGEN | F_MS | F_RT, 0); + return info; + } + case DXGI_FORMAT_BC1_UNORM_SRGB: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MIPGEN | F_MS | F_RT, 0); + return info; + } + case DXGI_FORMAT_BC2_TYPELESS: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); + return info; + } + case DXGI_FORMAT_BC2_UNORM: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MIPGEN | F_MS | F_RT, 0); + return info; + } + case DXGI_FORMAT_BC2_UNORM_SRGB: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MIPGEN | F_MS | F_RT, 0); + return info; + } + case DXGI_FORMAT_BC3_TYPELESS: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); + return info; + } + case DXGI_FORMAT_BC3_UNORM: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MIPGEN | F_MS | F_RT, 0); + return info; + } + case DXGI_FORMAT_BC3_UNORM_SRGB: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MIPGEN | F_MS | F_RT, 0); + return info; + } + case DXGI_FORMAT_BC4_SNORM: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MIPGEN | F_MS | F_RT, 0); + return info; + } + case DXGI_FORMAT_BC4_TYPELESS: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); + return info; + } + case DXGI_FORMAT_BC4_UNORM: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MIPGEN | F_MS | F_RT, 0); + return info; + } + case DXGI_FORMAT_BC5_SNORM: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MIPGEN | F_MS | F_RT, 0); + return info; + } + case DXGI_FORMAT_BC5_TYPELESS: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); + return info; + } + case DXGI_FORMAT_BC5_UNORM: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MIPGEN | F_MS | F_RT, 0); + return info; + } + case DXGI_FORMAT_BC6H_SF16: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MIPGEN | F_MS | F_RT, 0); + return info; + } + case DXGI_FORMAT_BC6H_TYPELESS: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); + return info; + } + case DXGI_FORMAT_BC6H_UF16: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MIPGEN | F_MS | F_RT, 0); + return info; + } + case DXGI_FORMAT_BC7_TYPELESS: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); + return info; + } + case DXGI_FORMAT_BC7_UNORM: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MIPGEN | F_MS | F_RT, 0); + return info; + } + case DXGI_FORMAT_BC7_UNORM_SRGB: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MIPGEN | F_MS | F_RT, 0); + return info; + } + case DXGI_FORMAT_D16_UNORM: + { + static const DXGISupport info(F_2D | F_CUBE | F_DS, F_3D | F_MIPGEN | F_RT | F_SAMPLE, F_MS); + return info; + } + case DXGI_FORMAT_D24_UNORM_S8_UINT: + { + static const DXGISupport info(F_2D | F_CUBE | F_DS, F_3D | F_RT | F_SAMPLE, F_MS); + return info; + } + case DXGI_FORMAT_D32_FLOAT: + { + static const DXGISupport info(F_2D | F_CUBE | F_DS, F_3D | F_MIPGEN | F_RT | F_SAMPLE, F_MS); + return info; + } + case DXGI_FORMAT_D32_FLOAT_S8X24_UINT: + { + static const DXGISupport info(F_2D | F_CUBE | F_DS, F_3D | F_MIPGEN | F_RT | F_SAMPLE, F_MS); + return info; + } + case DXGI_FORMAT_G8R8_G8B8_UNORM: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MIPGEN | F_MS | F_RT, 0); + return info; + } + case DXGI_FORMAT_IA44: + { + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); + return info; + } + case DXGI_FORMAT_NV11: + { + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN, F_MS); + return info; + } + case DXGI_FORMAT_NV12: + { + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN, F_MS); + return info; + } + case DXGI_FORMAT_P010: + { + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN, F_MS); + return info; + } + case DXGI_FORMAT_P016: + { + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN, F_MS); + return info; + } + case DXGI_FORMAT_P8: + { + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); + return info; + } + case DXGI_FORMAT_R10G10B10A2_TYPELESS: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); + return info; + } + case DXGI_FORMAT_R10G10B10A2_UINT: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | F_SAMPLE, F_MS); + return info; + } + case DXGI_FORMAT_R10G10B10A2_UNORM: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT | F_SAMPLE, F_DS, F_MS); + return info; + } + case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM: + { + static const DXGISupport info(0, F_CUBE | F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, F_2D | F_3D); + return info; + } + case DXGI_FORMAT_R11G11B10_FLOAT: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT | F_SAMPLE, F_DS, F_MS); + return info; + } + case DXGI_FORMAT_R16G16B16A16_FLOAT: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT | F_SAMPLE, F_DS, F_MS); + return info; + } + case DXGI_FORMAT_R16G16B16A16_SINT: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | F_SAMPLE, F_MS); + return info; + } + case DXGI_FORMAT_R16G16B16A16_SNORM: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT | F_SAMPLE, F_DS, F_MS); + return info; + } + case DXGI_FORMAT_R16G16B16A16_TYPELESS: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); + return info; + } + case DXGI_FORMAT_R16G16B16A16_UINT: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | F_SAMPLE, F_MS); + return info; + } + case DXGI_FORMAT_R16G16B16A16_UNORM: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT | F_SAMPLE, F_DS, F_MS); + return info; + } + case DXGI_FORMAT_R16G16_FLOAT: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT | F_SAMPLE, F_DS, F_MS); + return info; + } + case DXGI_FORMAT_R16G16_SINT: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | F_SAMPLE, F_MS); + return info; + } + case DXGI_FORMAT_R16G16_SNORM: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT | F_SAMPLE, F_DS, F_MS); + return info; + } + case DXGI_FORMAT_R16G16_TYPELESS: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); + return info; + } + case DXGI_FORMAT_R16G16_UINT: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | F_SAMPLE, F_MS); + return info; + } + case DXGI_FORMAT_R16G16_UNORM: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT | F_SAMPLE, F_DS, F_MS); + return info; + } + case DXGI_FORMAT_R16_FLOAT: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT | F_SAMPLE, F_DS, F_MS); + return info; + } + case DXGI_FORMAT_R16_SINT: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | F_SAMPLE, F_MS); + return info; + } + case DXGI_FORMAT_R16_SNORM: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT | F_SAMPLE, F_DS, F_MS); + return info; + } + case DXGI_FORMAT_R16_TYPELESS: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); + return info; + } + case DXGI_FORMAT_R16_UINT: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | F_SAMPLE, F_MS); + return info; + } + case DXGI_FORMAT_R16_UNORM: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT | F_SAMPLE, F_DS, F_MS); + return info; + } + case DXGI_FORMAT_R1_UNORM: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); + return info; + } + case DXGI_FORMAT_R24G8_TYPELESS: + { + static const DXGISupport info(F_2D | F_CUBE, F_3D | F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); + return info; + } + case DXGI_FORMAT_R24_UNORM_X8_TYPELESS: + { + static const DXGISupport info(F_2D | F_CUBE | F_SAMPLE, F_3D | F_DS | F_MIPGEN | F_MS | F_RT, 0); + return info; + } + case DXGI_FORMAT_R32G32B32A32_FLOAT: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT | F_SAMPLE, F_DS, F_MS); + return info; + } + case DXGI_FORMAT_R32G32B32A32_SINT: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | F_SAMPLE, F_MS); + return info; + } + case DXGI_FORMAT_R32G32B32A32_TYPELESS: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); + return info; + } + case DXGI_FORMAT_R32G32B32A32_UINT: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | F_SAMPLE, F_MS); + return info; + } + case DXGI_FORMAT_R32G32B32_FLOAT: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN, F_MS | F_RT); + return info; + } + case DXGI_FORMAT_R32G32B32_SINT: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_SAMPLE, F_MS | F_RT); + return info; + } + case DXGI_FORMAT_R32G32B32_TYPELESS: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); + return info; + } + case DXGI_FORMAT_R32G32B32_UINT: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_SAMPLE, F_MS | F_RT); + return info; + } + case DXGI_FORMAT_R32G32_FLOAT: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT | F_SAMPLE, F_DS, F_MS); + return info; + } + case DXGI_FORMAT_R32G32_SINT: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | F_SAMPLE, F_MS); + return info; + } + case DXGI_FORMAT_R32G32_TYPELESS: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); + return info; + } + case DXGI_FORMAT_R32G32_UINT: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | F_SAMPLE, F_MS); + return info; + } + case DXGI_FORMAT_R32G8X24_TYPELESS: + { + static const DXGISupport info(F_2D | F_CUBE, F_3D | F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); + return info; + } + case DXGI_FORMAT_R32_FLOAT: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT | F_SAMPLE, F_DS, F_MS); + return info; + } + case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS: + { + static const DXGISupport info(F_2D | F_CUBE | F_SAMPLE, F_3D | F_DS | F_MIPGEN | F_MS | F_RT, 0); + return info; + } + case DXGI_FORMAT_R32_SINT: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | F_SAMPLE, F_MS); + return info; + } + case DXGI_FORMAT_R32_TYPELESS: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); + return info; + } + case DXGI_FORMAT_R32_UINT: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | F_SAMPLE, F_MS); + return info; + } + case DXGI_FORMAT_R8G8B8A8_SINT: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | F_SAMPLE, F_MS); + return info; + } + case DXGI_FORMAT_R8G8B8A8_SNORM: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT | F_SAMPLE, F_DS, F_MS); + return info; + } + case DXGI_FORMAT_R8G8B8A8_TYPELESS: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); + return info; + } + case DXGI_FORMAT_R8G8B8A8_UINT: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | F_SAMPLE, F_MS); + return info; + } + case DXGI_FORMAT_R8G8B8A8_UNORM: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT | F_SAMPLE, F_DS, F_MS); + return info; + } + case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT | F_SAMPLE, F_DS, F_MS); + return info; + } + case DXGI_FORMAT_R8G8_B8G8_UNORM: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MIPGEN | F_MS | F_RT, 0); + return info; + } + case DXGI_FORMAT_R8G8_SINT: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | F_SAMPLE, F_MS); + return info; + } + case DXGI_FORMAT_R8G8_SNORM: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT | F_SAMPLE, F_DS, F_MS); + return info; + } + case DXGI_FORMAT_R8G8_TYPELESS: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); + return info; + } + case DXGI_FORMAT_R8G8_UINT: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | F_SAMPLE, F_MS); + return info; + } + case DXGI_FORMAT_R8G8_UNORM: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT | F_SAMPLE, F_DS, F_MS); + return info; + } + case DXGI_FORMAT_R8_SINT: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | F_SAMPLE, F_MS); + return info; + } + case DXGI_FORMAT_R8_SNORM: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT | F_SAMPLE, F_DS, F_MS); + return info; + } + case DXGI_FORMAT_R8_TYPELESS: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); + return info; + } + case DXGI_FORMAT_R8_UINT: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | F_SAMPLE, F_MS); + return info; + } + case DXGI_FORMAT_R8_UNORM: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT | F_SAMPLE, F_DS, F_MS); + return info; + } + case DXGI_FORMAT_R9G9B9E5_SHAREDEXP: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MIPGEN | F_MS | F_RT, 0); + return info; + } + case DXGI_FORMAT_UNKNOWN: + { + static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); + return info; + } + case DXGI_FORMAT_X24_TYPELESS_G8_UINT: + { + static const DXGISupport info(F_2D | F_CUBE, F_3D | F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); + return info; + } + case DXGI_FORMAT_X32_TYPELESS_G8X24_UINT: + { + static const DXGISupport info(F_2D | F_CUBE, F_3D | F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); + return info; + } + case DXGI_FORMAT_Y210: + { + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN | F_MS | F_RT, 0); + return info; + } + case DXGI_FORMAT_Y216: + { + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN | F_MS | F_RT, 0); + return info; + } + case DXGI_FORMAT_Y410: + { + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN | F_MS | F_RT, 0); + return info; + } + case DXGI_FORMAT_Y416: + { + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN | F_MS | F_RT, 0); + return info; + } + case DXGI_FORMAT_YUY2: + { + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN | F_MS | F_RT, 0); + return info; + } + + default: + UNREACHABLE(); + return GetDefaultSupport(); + } + // clang-format on +} + +const DXGISupport &GetDXGISupport_11_1(DXGI_FORMAT dxgiFormat) +{ + // clang-format off + switch (dxgiFormat) + { + case DXGI_FORMAT_420_OPAQUE: + { + static const DXGISupport info(F_2D, F_3D | F_CUBE | F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); + return info; + } + case DXGI_FORMAT_A8P8: + { + static const DXGISupport info(F_2D, F_3D | F_CUBE | F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); + return info; + } + case DXGI_FORMAT_A8_UNORM: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT | F_SAMPLE, F_DS, F_MS); + return info; + } + case DXGI_FORMAT_AI44: + { + static const DXGISupport info(F_2D, F_3D | F_CUBE | F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); + return info; + } + case DXGI_FORMAT_AYUV: + { + static const DXGISupport info(F_2D | F_RT | F_SAMPLE, F_3D | F_CUBE | F_DS | F_MIPGEN, F_MS); + return info; + } + case DXGI_FORMAT_B4G4R4A4_UNORM: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_SAMPLE, F_DS, F_MS | F_RT); + return info; + } + case DXGI_FORMAT_B5G5R5A1_UNORM: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_SAMPLE, F_DS, F_MS | F_RT); + return info; + } + case DXGI_FORMAT_B5G6R5_UNORM: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT | F_SAMPLE, F_DS, F_MS); + return info; + } + case DXGI_FORMAT_B8G8R8A8_TYPELESS: + { + static const DXGISupport info(0, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, F_2D | F_3D | F_CUBE); + return info; + } + case DXGI_FORMAT_B8G8R8A8_UNORM: + { + static const DXGISupport info(F_MIPGEN | F_RT | F_SAMPLE, F_DS, F_2D | F_3D | F_CUBE | F_MS); + return info; + } + case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: + { + static const DXGISupport info(F_RT | F_SAMPLE, F_DS | F_MIPGEN, F_2D | F_3D | F_CUBE | F_MS); + return info; + } + case DXGI_FORMAT_B8G8R8X8_TYPELESS: + { + static const DXGISupport info(0, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, F_2D | F_3D | F_CUBE); + return info; + } + case DXGI_FORMAT_B8G8R8X8_UNORM: + { + static const DXGISupport info(F_RT | F_SAMPLE, F_DS | F_MIPGEN, F_2D | F_3D | F_CUBE | F_MS); + return info; + } + case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB: + { + static const DXGISupport info(F_RT | F_SAMPLE, F_DS | F_MIPGEN, F_2D | F_3D | F_CUBE | F_MS); + return info; + } + case DXGI_FORMAT_BC1_TYPELESS: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); + return info; + } + case DXGI_FORMAT_BC1_UNORM: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MIPGEN | F_MS | F_RT, 0); + return info; + } + case DXGI_FORMAT_BC1_UNORM_SRGB: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MIPGEN | F_MS | F_RT, 0); + return info; + } + case DXGI_FORMAT_BC2_TYPELESS: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); + return info; + } + case DXGI_FORMAT_BC2_UNORM: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MIPGEN | F_MS | F_RT, 0); + return info; + } + case DXGI_FORMAT_BC2_UNORM_SRGB: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MIPGEN | F_MS | F_RT, 0); + return info; + } + case DXGI_FORMAT_BC3_TYPELESS: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); + return info; + } + case DXGI_FORMAT_BC3_UNORM: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MIPGEN | F_MS | F_RT, 0); + return info; + } + case DXGI_FORMAT_BC3_UNORM_SRGB: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MIPGEN | F_MS | F_RT, 0); + return info; + } + case DXGI_FORMAT_BC4_SNORM: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MIPGEN | F_MS | F_RT, 0); + return info; + } + case DXGI_FORMAT_BC4_TYPELESS: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); + return info; + } + case DXGI_FORMAT_BC4_UNORM: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MIPGEN | F_MS | F_RT, 0); + return info; + } + case DXGI_FORMAT_BC5_SNORM: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MIPGEN | F_MS | F_RT, 0); + return info; + } + case DXGI_FORMAT_BC5_TYPELESS: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); + return info; + } + case DXGI_FORMAT_BC5_UNORM: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MIPGEN | F_MS | F_RT, 0); + return info; + } + case DXGI_FORMAT_BC6H_SF16: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MIPGEN | F_MS | F_RT, 0); + return info; + } + case DXGI_FORMAT_BC6H_TYPELESS: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); + return info; + } + case DXGI_FORMAT_BC6H_UF16: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MIPGEN | F_MS | F_RT, 0); + return info; + } + case DXGI_FORMAT_BC7_TYPELESS: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); + return info; + } + case DXGI_FORMAT_BC7_UNORM: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MIPGEN | F_MS | F_RT, 0); + return info; + } + case DXGI_FORMAT_BC7_UNORM_SRGB: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MIPGEN | F_MS | F_RT, 0); + return info; + } + case DXGI_FORMAT_D16_UNORM: + { + static const DXGISupport info(F_2D | F_CUBE | F_DS, F_3D | F_MIPGEN | F_RT | F_SAMPLE, F_MS); + return info; + } + case DXGI_FORMAT_D24_UNORM_S8_UINT: + { + static const DXGISupport info(F_2D | F_CUBE | F_DS, F_3D | F_RT | F_SAMPLE, F_MS); + return info; + } + case DXGI_FORMAT_D32_FLOAT: + { + static const DXGISupport info(F_2D | F_CUBE | F_DS, F_3D | F_MIPGEN | F_RT | F_SAMPLE, F_MS); + return info; + } + case DXGI_FORMAT_D32_FLOAT_S8X24_UINT: + { + static const DXGISupport info(F_2D | F_CUBE | F_DS, F_3D | F_MIPGEN | F_RT | F_SAMPLE, F_MS); + return info; + } + case DXGI_FORMAT_G8R8_G8B8_UNORM: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MIPGEN | F_MS | F_RT, 0); + return info; + } + case DXGI_FORMAT_IA44: + { + static const DXGISupport info(F_2D, F_3D | F_CUBE | F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); + return info; + } + case DXGI_FORMAT_NV11: + { + static const DXGISupport info(F_2D | F_RT | F_SAMPLE, F_3D | F_CUBE | F_DS | F_MIPGEN, F_MS); + return info; + } + case DXGI_FORMAT_NV12: + { + static const DXGISupport info(F_2D | F_RT | F_SAMPLE, F_3D | F_CUBE | F_DS | F_MIPGEN, F_MS); + return info; + } + case DXGI_FORMAT_P010: + { + static const DXGISupport info(F_2D | F_RT | F_SAMPLE, F_3D | F_CUBE | F_DS | F_MIPGEN, F_MS); + return info; + } + case DXGI_FORMAT_P016: + { + static const DXGISupport info(F_2D | F_RT | F_SAMPLE, F_3D | F_CUBE | F_DS | F_MIPGEN, F_MS); + return info; + } + case DXGI_FORMAT_P8: + { + static const DXGISupport info(F_2D, F_3D | F_CUBE | F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); + return info; + } + case DXGI_FORMAT_R10G10B10A2_TYPELESS: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); + return info; + } + case DXGI_FORMAT_R10G10B10A2_UINT: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | F_SAMPLE, F_MS); + return info; + } + case DXGI_FORMAT_R10G10B10A2_UNORM: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT | F_SAMPLE, F_DS, F_MS); + return info; + } + case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM: + { + static const DXGISupport info(0, F_CUBE | F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, F_2D | F_3D); + return info; + } + case DXGI_FORMAT_R11G11B10_FLOAT: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT | F_SAMPLE, F_DS, F_MS); + return info; + } + case DXGI_FORMAT_R16G16B16A16_FLOAT: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT | F_SAMPLE, F_DS, F_MS); + return info; + } + case DXGI_FORMAT_R16G16B16A16_SINT: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | F_SAMPLE, F_MS); + return info; + } + case DXGI_FORMAT_R16G16B16A16_SNORM: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT | F_SAMPLE, F_DS, F_MS); + return info; + } + case DXGI_FORMAT_R16G16B16A16_TYPELESS: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); + return info; + } + case DXGI_FORMAT_R16G16B16A16_UINT: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | F_SAMPLE, F_MS); + return info; + } + case DXGI_FORMAT_R16G16B16A16_UNORM: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT | F_SAMPLE, F_DS, F_MS); + return info; + } + case DXGI_FORMAT_R16G16_FLOAT: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT | F_SAMPLE, F_DS, F_MS); + return info; + } + case DXGI_FORMAT_R16G16_SINT: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | F_SAMPLE, F_MS); + return info; + } + case DXGI_FORMAT_R16G16_SNORM: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT | F_SAMPLE, F_DS, F_MS); + return info; + } + case DXGI_FORMAT_R16G16_TYPELESS: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); + return info; + } + case DXGI_FORMAT_R16G16_UINT: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | F_SAMPLE, F_MS); + return info; + } + case DXGI_FORMAT_R16G16_UNORM: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT | F_SAMPLE, F_DS, F_MS); + return info; + } + case DXGI_FORMAT_R16_FLOAT: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT | F_SAMPLE, F_DS, F_MS); + return info; + } + case DXGI_FORMAT_R16_SINT: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | F_SAMPLE, F_MS); + return info; + } + case DXGI_FORMAT_R16_SNORM: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT | F_SAMPLE, F_DS, F_MS); + return info; + } + case DXGI_FORMAT_R16_TYPELESS: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); + return info; + } + case DXGI_FORMAT_R16_UINT: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | F_SAMPLE, F_MS); + return info; + } + case DXGI_FORMAT_R16_UNORM: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT | F_SAMPLE, F_DS, F_MS); + return info; + } + case DXGI_FORMAT_R1_UNORM: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); + return info; + } + case DXGI_FORMAT_R24G8_TYPELESS: + { + static const DXGISupport info(F_2D | F_CUBE, F_3D | F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); + return info; + } + case DXGI_FORMAT_R24_UNORM_X8_TYPELESS: + { + static const DXGISupport info(F_2D | F_CUBE | F_SAMPLE, F_3D | F_DS | F_MIPGEN | F_MS | F_RT, 0); + return info; + } + case DXGI_FORMAT_R32G32B32A32_FLOAT: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT | F_SAMPLE, F_DS, F_MS); + return info; + } + case DXGI_FORMAT_R32G32B32A32_SINT: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | F_SAMPLE, F_MS); + return info; + } + case DXGI_FORMAT_R32G32B32A32_TYPELESS: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); + return info; + } + case DXGI_FORMAT_R32G32B32A32_UINT: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | F_SAMPLE, F_MS); + return info; + } + case DXGI_FORMAT_R32G32B32_FLOAT: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN, F_MS | F_RT); + return info; + } + case DXGI_FORMAT_R32G32B32_SINT: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_SAMPLE, F_MS | F_RT); + return info; + } + case DXGI_FORMAT_R32G32B32_TYPELESS: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); + return info; + } + case DXGI_FORMAT_R32G32B32_UINT: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_SAMPLE, F_MS | F_RT); + return info; + } + case DXGI_FORMAT_R32G32_FLOAT: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT | F_SAMPLE, F_DS, F_MS); + return info; + } + case DXGI_FORMAT_R32G32_SINT: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | F_SAMPLE, F_MS); + return info; + } + case DXGI_FORMAT_R32G32_TYPELESS: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); + return info; + } + case DXGI_FORMAT_R32G32_UINT: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | F_SAMPLE, F_MS); + return info; + } + case DXGI_FORMAT_R32G8X24_TYPELESS: + { + static const DXGISupport info(F_2D | F_CUBE, F_3D | F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); + return info; + } + case DXGI_FORMAT_R32_FLOAT: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT | F_SAMPLE, F_DS, F_MS); + return info; + } + case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS: + { + static const DXGISupport info(F_2D | F_CUBE | F_SAMPLE, F_3D | F_DS | F_MIPGEN | F_MS | F_RT, 0); + return info; + } + case DXGI_FORMAT_R32_SINT: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | F_SAMPLE, F_MS); + return info; + } + case DXGI_FORMAT_R32_TYPELESS: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); + return info; + } + case DXGI_FORMAT_R32_UINT: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | F_SAMPLE, F_MS); + return info; + } + case DXGI_FORMAT_R8G8B8A8_SINT: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | F_SAMPLE, F_MS); + return info; + } + case DXGI_FORMAT_R8G8B8A8_SNORM: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT | F_SAMPLE, F_DS, F_MS); + return info; + } + case DXGI_FORMAT_R8G8B8A8_TYPELESS: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); + return info; + } + case DXGI_FORMAT_R8G8B8A8_UINT: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | F_SAMPLE, F_MS); + return info; + } + case DXGI_FORMAT_R8G8B8A8_UNORM: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT | F_SAMPLE, F_DS, F_MS); + return info; + } + case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT | F_SAMPLE, F_DS, F_MS); + return info; + } + case DXGI_FORMAT_R8G8_B8G8_UNORM: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MIPGEN | F_MS | F_RT, 0); + return info; + } + case DXGI_FORMAT_R8G8_SINT: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | F_SAMPLE, F_MS); + return info; + } + case DXGI_FORMAT_R8G8_SNORM: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT | F_SAMPLE, F_DS, F_MS); + return info; + } + case DXGI_FORMAT_R8G8_TYPELESS: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); + return info; + } + case DXGI_FORMAT_R8G8_UINT: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | F_SAMPLE, F_MS); + return info; + } + case DXGI_FORMAT_R8G8_UNORM: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT | F_SAMPLE, F_DS, F_MS); + return info; + } + case DXGI_FORMAT_R8_SINT: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | F_SAMPLE, F_MS); + return info; + } + case DXGI_FORMAT_R8_SNORM: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT | F_SAMPLE, F_DS, F_MS); + return info; + } + case DXGI_FORMAT_R8_TYPELESS: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); + return info; + } + case DXGI_FORMAT_R8_UINT: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | F_SAMPLE, F_MS); + return info; + } + case DXGI_FORMAT_R8_UNORM: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT | F_SAMPLE, F_DS, F_MS); return info; } case DXGI_FORMAT_R9G9B9E5_SHAREDEXP: { - static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MS | F_RT, 0); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MIPGEN | F_MS | F_RT, 0); return info; } case DXGI_FORMAT_UNKNOWN: { - static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); return info; } case DXGI_FORMAT_X24_TYPELESS_G8_UINT: { - static const DXGISupport info(F_2D | F_CUBE, F_3D | F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(F_2D | F_CUBE, F_3D | F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); return info; } case DXGI_FORMAT_X32_TYPELESS_G8X24_UINT: { - static const DXGISupport info(F_2D | F_CUBE, F_3D | F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(F_2D | F_CUBE, F_3D | F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); return info; } case DXGI_FORMAT_Y210: { - static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(F_2D | F_SAMPLE, F_3D | F_CUBE | F_DS | F_MIPGEN | F_MS | F_RT, 0); return info; } case DXGI_FORMAT_Y216: { - static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(F_2D | F_SAMPLE, F_3D | F_CUBE | F_DS | F_MIPGEN | F_MS | F_RT, 0); return info; } case DXGI_FORMAT_Y410: { - static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(F_2D | F_SAMPLE, F_3D | F_CUBE | F_DS | F_MIPGEN | F_MS | F_RT, 0); return info; } case DXGI_FORMAT_Y416: { - static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(F_2D | F_SAMPLE, F_3D | F_CUBE | F_DS | F_MIPGEN | F_MS | F_RT, 0); return info; } case DXGI_FORMAT_YUY2: { - static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(F_2D | F_SAMPLE, F_3D | F_CUBE | F_DS | F_MIPGEN | F_MS | F_RT, 0); return info; } @@ -1814,6 +3004,7 @@ const DXGISupport &GetDXGISupport_11_0(DXGI_FORMAT dxgiFormat) UNREACHABLE(); return GetDefaultSupport(); } + // clang-format on } } @@ -1825,17 +3016,22 @@ const DXGISupport &GetDXGISupport_11_0(DXGI_FORMAT dxgiFormat) #undef F_RT #undef F_MS #undef F_DS +#undef F_MIPGEN const DXGISupport &GetDXGISupport(DXGI_FORMAT dxgiFormat, D3D_FEATURE_LEVEL featureLevel) { switch (featureLevel) { + case D3D_FEATURE_LEVEL_9_3: + return GetDXGISupport_9_3(dxgiFormat); case D3D_FEATURE_LEVEL_10_0: return GetDXGISupport_10_0(dxgiFormat); case D3D_FEATURE_LEVEL_10_1: return GetDXGISupport_10_1(dxgiFormat); case D3D_FEATURE_LEVEL_11_0: return GetDXGISupport_11_0(dxgiFormat); + case D3D_FEATURE_LEVEL_11_1: + return GetDXGISupport_11_1(dxgiFormat); default: return GetDefaultSupport(); } diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/dxgi_support_table.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/dxgi_support_table.h index 1d8d68565e..a818f376ef 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/dxgi_support_table.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/dxgi_support_table.h @@ -8,6 +8,9 @@ // version, D3D feature level, and is sometimes guaranteed or optional. // +#ifndef LIBANGLE_RENDERER_D3D_D3D11_DXGI_SUPPORT_TABLE_H_ +#define LIBANGLE_RENDERER_D3D_D3D11_DXGI_SUPPORT_TABLE_H_ + #include "common/platform.h" namespace rx @@ -42,3 +45,5 @@ const DXGISupport &GetDXGISupport(DXGI_FORMAT dxgiFormat, D3D_FEATURE_LEVEL feat } // namespace d3d11 } // namespace rx + +#endif // LIBANGLE_RENDERER_D3D_D3D11_DXGI_SUPPORT_TABLE_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/formatutils11.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/formatutils11.cpp index f073e9f46f..ce4edd26db 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/formatutils11.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/formatutils11.cpp @@ -9,14 +9,15 @@ #include "libANGLE/renderer/d3d/d3d11/formatutils11.h" +#include "image_util/copyimage.h" +#include "image_util/generatemip.h" +#include "image_util/loadimage.h" + #include "libANGLE/formatutils.h" -#include "libANGLE/renderer/d3d/copyimage.h" #include "libANGLE/renderer/d3d/d3d11/copyvertex.h" +#include "libANGLE/renderer/d3d/d3d11/dxgi_support_table.h" #include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h" #include "libANGLE/renderer/d3d/d3d11/Renderer11.h" -#include "libANGLE/renderer/d3d/generatemip.h" -#include "libANGLE/renderer/d3d/loadimage.h" -#include "libANGLE/renderer/Renderer.h" namespace rx { @@ -24,559 +25,388 @@ namespace rx namespace d3d11 { -typedef std::map DXGIToESFormatMap; - -inline void AddDXGIToESEntry(DXGIToESFormatMap *map, DXGI_FORMAT key, GLenum value) +bool SupportsMipGen(DXGI_FORMAT dxgiFormat, D3D_FEATURE_LEVEL featureLevel) { - map->insert(std::make_pair(key, value)); + const auto &support = GetDXGISupport(dxgiFormat, featureLevel); + ASSERT((support.optionallySupportedFlags & D3D11_FORMAT_SUPPORT_MIP_AUTOGEN) == 0); + return ((support.alwaysSupportedFlags & D3D11_FORMAT_SUPPORT_MIP_AUTOGEN) != 0); } -static DXGIToESFormatMap BuildDXGIToESFormatMap() +DXGIFormatSize::DXGIFormatSize(GLuint pixelBits, GLuint blockWidth, GLuint blockHeight) + : pixelBytes(pixelBits / 8), blockWidth(blockWidth), blockHeight(blockHeight) { - 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); - - AddDXGIToESEntry(&map, DXGI_FORMAT_B5G6R5_UNORM, GL_RGB565); - AddDXGIToESEntry(&map, DXGI_FORMAT_B5G5R5A1_UNORM, GL_RGB5_A1); - AddDXGIToESEntry(&map, DXGI_FORMAT_B4G4R4A4_UNORM, GL_RGBA4); - - return map; } -struct D3D11FastCopyFormat +const DXGIFormatSize &GetDXGIFormatSizeInfo(DXGI_FORMAT format) { - 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 + static const DXGIFormatSize sizeUnknown(0, 0, 0); + static const DXGIFormatSize size128(128, 1, 1); + static const DXGIFormatSize size96(96, 1, 1); + static const DXGIFormatSize size64(64, 1, 1); + static const DXGIFormatSize size32(32, 1, 1); + static const DXGIFormatSize size16(16, 1, 1); + static const DXGIFormatSize size8(8, 1, 1); + static const DXGIFormatSize sizeBC1(64, 4, 4); + static const DXGIFormatSize sizeBC2(128, 4, 4); + static const DXGIFormatSize sizeBC3(128, 4, 4); + static const DXGIFormatSize sizeBC4(64, 4, 4); + static const DXGIFormatSize sizeBC5(128, 4, 4); + static const DXGIFormatSize sizeBC6H(128, 4, 4); + static const DXGIFormatSize sizeBC7(128, 4, 4); + switch (format) { - return memcmp(this, &other, sizeof(D3D11FastCopyFormat)) < 0; + case DXGI_FORMAT_UNKNOWN: + return sizeUnknown; + case DXGI_FORMAT_R32G32B32A32_TYPELESS: + case DXGI_FORMAT_R32G32B32A32_FLOAT: + case DXGI_FORMAT_R32G32B32A32_UINT: + case DXGI_FORMAT_R32G32B32A32_SINT: + return size128; + case DXGI_FORMAT_R32G32B32_TYPELESS: + case DXGI_FORMAT_R32G32B32_FLOAT: + case DXGI_FORMAT_R32G32B32_UINT: + case DXGI_FORMAT_R32G32B32_SINT: + return size96; + case DXGI_FORMAT_R16G16B16A16_TYPELESS: + case DXGI_FORMAT_R16G16B16A16_FLOAT: + case DXGI_FORMAT_R16G16B16A16_UNORM: + case DXGI_FORMAT_R16G16B16A16_UINT: + case DXGI_FORMAT_R16G16B16A16_SNORM: + case DXGI_FORMAT_R16G16B16A16_SINT: + case DXGI_FORMAT_R32G32_TYPELESS: + case DXGI_FORMAT_R32G32_FLOAT: + case DXGI_FORMAT_R32G32_UINT: + case DXGI_FORMAT_R32G32_SINT: + case DXGI_FORMAT_R32G8X24_TYPELESS: + case DXGI_FORMAT_D32_FLOAT_S8X24_UINT: + case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS: + case DXGI_FORMAT_X32_TYPELESS_G8X24_UINT: + return size64; + case DXGI_FORMAT_R10G10B10A2_TYPELESS: + case DXGI_FORMAT_R10G10B10A2_UNORM: + case DXGI_FORMAT_R10G10B10A2_UINT: + case DXGI_FORMAT_R11G11B10_FLOAT: + case DXGI_FORMAT_R8G8B8A8_TYPELESS: + case DXGI_FORMAT_R8G8B8A8_UNORM: + case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: + case DXGI_FORMAT_R8G8B8A8_UINT: + case DXGI_FORMAT_R8G8B8A8_SNORM: + case DXGI_FORMAT_R8G8B8A8_SINT: + case DXGI_FORMAT_R16G16_TYPELESS: + case DXGI_FORMAT_R16G16_FLOAT: + case DXGI_FORMAT_R16G16_UNORM: + case DXGI_FORMAT_R16G16_UINT: + case DXGI_FORMAT_R16G16_SNORM: + case DXGI_FORMAT_R16G16_SINT: + case DXGI_FORMAT_R32_TYPELESS: + case DXGI_FORMAT_D32_FLOAT: + case DXGI_FORMAT_R32_FLOAT: + case DXGI_FORMAT_R32_UINT: + case DXGI_FORMAT_R32_SINT: + case DXGI_FORMAT_R24G8_TYPELESS: + case DXGI_FORMAT_D24_UNORM_S8_UINT: + case DXGI_FORMAT_R24_UNORM_X8_TYPELESS: + case DXGI_FORMAT_X24_TYPELESS_G8_UINT: + return size32; + case DXGI_FORMAT_R8G8_TYPELESS: + case DXGI_FORMAT_R8G8_UNORM: + case DXGI_FORMAT_R8G8_UINT: + case DXGI_FORMAT_R8G8_SNORM: + case DXGI_FORMAT_R8G8_SINT: + case DXGI_FORMAT_R16_TYPELESS: + case DXGI_FORMAT_R16_FLOAT: + case DXGI_FORMAT_D16_UNORM: + case DXGI_FORMAT_R16_UNORM: + case DXGI_FORMAT_R16_UINT: + case DXGI_FORMAT_R16_SNORM: + case DXGI_FORMAT_R16_SINT: + return size16; + case DXGI_FORMAT_R8_TYPELESS: + case DXGI_FORMAT_R8_UNORM: + case DXGI_FORMAT_R8_UINT: + case DXGI_FORMAT_R8_SNORM: + case DXGI_FORMAT_R8_SINT: + case DXGI_FORMAT_A8_UNORM: + return size8; + case DXGI_FORMAT_R1_UNORM: + UNREACHABLE(); + return sizeUnknown; + case DXGI_FORMAT_R9G9B9E5_SHAREDEXP: + case DXGI_FORMAT_R8G8_B8G8_UNORM: + case DXGI_FORMAT_G8R8_G8B8_UNORM: + return size32; + case DXGI_FORMAT_BC1_TYPELESS: + case DXGI_FORMAT_BC1_UNORM: + case DXGI_FORMAT_BC1_UNORM_SRGB: + return sizeBC1; + case DXGI_FORMAT_BC2_TYPELESS: + case DXGI_FORMAT_BC2_UNORM: + case DXGI_FORMAT_BC2_UNORM_SRGB: + return sizeBC2; + case DXGI_FORMAT_BC3_TYPELESS: + case DXGI_FORMAT_BC3_UNORM: + case DXGI_FORMAT_BC3_UNORM_SRGB: + return sizeBC3; + case DXGI_FORMAT_BC4_TYPELESS: + case DXGI_FORMAT_BC4_UNORM: + case DXGI_FORMAT_BC4_SNORM: + return sizeBC4; + case DXGI_FORMAT_BC5_TYPELESS: + case DXGI_FORMAT_BC5_UNORM: + case DXGI_FORMAT_BC5_SNORM: + return sizeBC5; + case DXGI_FORMAT_B5G6R5_UNORM: + case DXGI_FORMAT_B5G5R5A1_UNORM: + return size16; + case DXGI_FORMAT_B8G8R8A8_UNORM: + case DXGI_FORMAT_B8G8R8X8_UNORM: + case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM: + case DXGI_FORMAT_B8G8R8A8_TYPELESS: + case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: + case DXGI_FORMAT_B8G8R8X8_TYPELESS: + case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB: + return size32; + case DXGI_FORMAT_BC6H_TYPELESS: + case DXGI_FORMAT_BC6H_UF16: + case DXGI_FORMAT_BC6H_SF16: + return sizeBC6H; + case DXGI_FORMAT_BC7_TYPELESS: + case DXGI_FORMAT_BC7_UNORM: + case DXGI_FORMAT_BC7_UNORM_SRGB: + return sizeBC7; + case DXGI_FORMAT_AYUV: + case DXGI_FORMAT_Y410: + case DXGI_FORMAT_Y416: + case DXGI_FORMAT_NV12: + case DXGI_FORMAT_P010: + case DXGI_FORMAT_P016: + case DXGI_FORMAT_420_OPAQUE: + case DXGI_FORMAT_YUY2: + case DXGI_FORMAT_Y210: + case DXGI_FORMAT_Y216: + case DXGI_FORMAT_NV11: + case DXGI_FORMAT_AI44: + case DXGI_FORMAT_IA44: + case DXGI_FORMAT_P8: + case DXGI_FORMAT_A8P8: + UNREACHABLE(); + return sizeUnknown; + case DXGI_FORMAT_B4G4R4A4_UNORM: + return size16; + default: + UNREACHABLE(); + return sizeUnknown; } -}; - -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); - - InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_B5G6R5_UNORM, 5, 6, 5, 0, 0); - InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_B4G4R4A4_UNORM, 4, 4, 4, 4, 0); - InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_B5G5R5A1_UNORM, 5, 5, 5, 1, 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() +constexpr VertexFormat::VertexFormat() + : conversionType(VERTEX_CONVERT_NONE), nativeFormat(DXGI_FORMAT_UNKNOWN), copyFunction(nullptr) { - 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(), - nativeMipmapSupport(NULL) -{ -} - -static bool NeverSupported(D3D_FEATURE_LEVEL) -{ - return false; -} - -template -static bool RequiresFeatureLevel(D3D_FEATURE_LEVEL featureLevel) -{ - return featureLevel >= requiredFeatureLevel; } -ColorCopyFunction DXGIFormat::getFastCopyFunction(GLenum format, GLenum type) const +constexpr VertexFormat::VertexFormat(VertexConversionType conversionTypeIn, + DXGI_FORMAT nativeFormatIn, + VertexCopyFunction copyFunctionIn) + : conversionType(conversionTypeIn), nativeFormat(nativeFormatIn), copyFunction(copyFunctionIn) { - 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, NativeMipmapGenerationSupportFunction nativeMipmapSupport) +const VertexFormat *GetVertexFormatInfo_FL_9_3(gl::VertexFormatType vertexFormatType) { - 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 = static_cast(colorInfo.redBits); - info.greenBits = static_cast(colorInfo.greenBits); - info.blueBits = static_cast(colorInfo.blueBits); - info.alphaBits = static_cast(colorInfo.alphaBits); - info.sharedBits = static_cast(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; + // 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 - static const D3D11FastCopyMap fastCopyMap = BuildFastCopyMap(); - std::pair fastCopyIter = fastCopyMap.equal_range(dxgiFormat); - for (D3D11FastCopyMap::const_iterator i = fastCopyIter.first; i != fastCopyIter.second; i++) + switch (vertexFormatType) { - info.fastCopyFunctions.insert(std::make_pair(std::make_pair(i->second.destFormat, i->second.destType), i->second.copyFunction)); - } - - info.nativeMipmapSupport = nativeMipmapSupport; - - 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 | Native mipmap function - AddDXGIFormat(&map, DXGI_FORMAT_UNKNOWN, 0, 0, 0, GL_NONE, NULL, NULL, NeverSupported); - - AddDXGIFormat(&map, DXGI_FORMAT_A8_UNORM, 8, 1, 1, GL_UNSIGNED_NORMALIZED, GenerateMip, ReadColor, RequiresFeatureLevel); - AddDXGIFormat(&map, DXGI_FORMAT_R8_UNORM, 8, 1, 1, GL_UNSIGNED_NORMALIZED, GenerateMip, ReadColor, RequiresFeatureLevel); - AddDXGIFormat(&map, DXGI_FORMAT_R8G8_UNORM, 16, 1, 1, GL_UNSIGNED_NORMALIZED, GenerateMip, ReadColor, RequiresFeatureLevel); - AddDXGIFormat(&map, DXGI_FORMAT_R8G8B8A8_UNORM, 32, 1, 1, GL_UNSIGNED_NORMALIZED, GenerateMip, ReadColor, RequiresFeatureLevel); - AddDXGIFormat(&map, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, 32, 1, 1, GL_UNSIGNED_NORMALIZED, GenerateMip, ReadColor, RequiresFeatureLevel); - AddDXGIFormat(&map, DXGI_FORMAT_B8G8R8A8_UNORM, 32, 1, 1, GL_UNSIGNED_NORMALIZED, GenerateMip, ReadColor, RequiresFeatureLevel); - - AddDXGIFormat(&map, DXGI_FORMAT_R8_SNORM, 8, 1, 1, GL_SIGNED_NORMALIZED, GenerateMip, ReadColor , RequiresFeatureLevel); - AddDXGIFormat(&map, DXGI_FORMAT_R8G8_SNORM, 16, 1, 1, GL_SIGNED_NORMALIZED, GenerateMip, ReadColor , RequiresFeatureLevel); - AddDXGIFormat(&map, DXGI_FORMAT_R8G8B8A8_SNORM, 32, 1, 1, GL_SIGNED_NORMALIZED, GenerateMip, ReadColor, RequiresFeatureLevel); - - AddDXGIFormat(&map, DXGI_FORMAT_R8_UINT, 8, 1, 1, GL_UNSIGNED_INT, GenerateMip, ReadColor, NeverSupported); - AddDXGIFormat(&map, DXGI_FORMAT_R16_UINT, 16, 1, 1, GL_UNSIGNED_INT, GenerateMip, ReadColor, NeverSupported); - AddDXGIFormat(&map, DXGI_FORMAT_R32_UINT, 32, 1, 1, GL_UNSIGNED_INT, GenerateMip, ReadColor, NeverSupported); - AddDXGIFormat(&map, DXGI_FORMAT_R8G8_UINT, 16, 1, 1, GL_UNSIGNED_INT, GenerateMip, ReadColor, NeverSupported); - AddDXGIFormat(&map, DXGI_FORMAT_R16G16_UINT, 32, 1, 1, GL_UNSIGNED_INT, GenerateMip, ReadColor, NeverSupported); - AddDXGIFormat(&map, DXGI_FORMAT_R32G32_UINT, 64, 1, 1, GL_UNSIGNED_INT, GenerateMip, ReadColor, NeverSupported); - AddDXGIFormat(&map, DXGI_FORMAT_R32G32B32_UINT, 96, 1, 1, GL_UNSIGNED_INT, GenerateMip, ReadColor, NeverSupported); - AddDXGIFormat(&map, DXGI_FORMAT_R8G8B8A8_UINT, 32, 1, 1, GL_UNSIGNED_INT, GenerateMip, ReadColor, NeverSupported); - AddDXGIFormat(&map, DXGI_FORMAT_R16G16B16A16_UINT, 64, 1, 1, GL_UNSIGNED_INT, GenerateMip, ReadColor, NeverSupported); - AddDXGIFormat(&map, DXGI_FORMAT_R32G32B32A32_UINT, 128, 1, 1, GL_UNSIGNED_INT, GenerateMip, ReadColor, NeverSupported); + // GL_BYTE -- unnormalized + case gl::VERTEX_FORMAT_SBYTE1: + { + static constexpr VertexFormat info(VERTEX_CONVERT_BOTH, DXGI_FORMAT_R16G16_SINT, + &Copy8SintTo16SintVertexData<1, 2>); + return &info; + } + case gl::VERTEX_FORMAT_SBYTE2: + { + static constexpr VertexFormat info(VERTEX_CONVERT_BOTH, DXGI_FORMAT_R16G16_SINT, + &Copy8SintTo16SintVertexData<2, 2>); + return &info; + } + case gl::VERTEX_FORMAT_SBYTE3: + { + static constexpr VertexFormat info(VERTEX_CONVERT_BOTH, DXGI_FORMAT_R16G16B16A16_SINT, + &Copy8SintTo16SintVertexData<3, 4>); + return &info; + } + case gl::VERTEX_FORMAT_SBYTE4: + { + static constexpr VertexFormat info(VERTEX_CONVERT_BOTH, DXGI_FORMAT_R16G16B16A16_SINT, + &Copy8SintTo16SintVertexData<4, 4>); + return &info; + } - AddDXGIFormat(&map, DXGI_FORMAT_R8_SINT, 8, 1, 1, GL_INT, GenerateMip, ReadColor, NeverSupported); - AddDXGIFormat(&map, DXGI_FORMAT_R16_SINT, 16, 1, 1, GL_INT, GenerateMip, ReadColor, NeverSupported); - AddDXGIFormat(&map, DXGI_FORMAT_R32_SINT, 32, 1, 1, GL_INT, GenerateMip, ReadColor, NeverSupported); - AddDXGIFormat(&map, DXGI_FORMAT_R8G8_SINT, 16, 1, 1, GL_INT, GenerateMip, ReadColor, NeverSupported); - AddDXGIFormat(&map, DXGI_FORMAT_R16G16_SINT, 32, 1, 1, GL_INT, GenerateMip, ReadColor, NeverSupported); - AddDXGIFormat(&map, DXGI_FORMAT_R32G32_SINT, 64, 1, 1, GL_INT, GenerateMip, ReadColor, NeverSupported); - AddDXGIFormat(&map, DXGI_FORMAT_R32G32B32_SINT, 96, 1, 1, GL_INT, GenerateMip, ReadColor, NeverSupported); - AddDXGIFormat(&map, DXGI_FORMAT_R8G8B8A8_SINT, 32, 1, 1, GL_INT, GenerateMip, ReadColor, NeverSupported); - AddDXGIFormat(&map, DXGI_FORMAT_R16G16B16A16_SINT, 64, 1, 1, GL_INT, GenerateMip, ReadColor, NeverSupported); - AddDXGIFormat(&map, DXGI_FORMAT_R32G32B32A32_SINT, 128, 1, 1, GL_INT, GenerateMip, ReadColor, NeverSupported); + // GL_BYTE -- normalized + case gl::VERTEX_FORMAT_SBYTE1_NORM: + { + static constexpr VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R16G16_SNORM, + &Copy8SnormTo16SnormVertexData<1, 2>); + return &info; + } + case gl::VERTEX_FORMAT_SBYTE2_NORM: + { + static constexpr VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R16G16_SNORM, + &Copy8SnormTo16SnormVertexData<2, 2>); + return &info; + } + case gl::VERTEX_FORMAT_SBYTE3_NORM: + { + static constexpr VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R16G16B16A16_SNORM, + &Copy8SnormTo16SnormVertexData<3, 4>); + return &info; + } + case gl::VERTEX_FORMAT_SBYTE4_NORM: + { + static constexpr VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R16G16B16A16_SNORM, + &Copy8SnormTo16SnormVertexData<4, 4>); + return &info; + } - AddDXGIFormat(&map, DXGI_FORMAT_R10G10B10A2_UNORM, 32, 1, 1, GL_UNSIGNED_NORMALIZED, GenerateMip, ReadColor, RequiresFeatureLevel); - AddDXGIFormat(&map, DXGI_FORMAT_R10G10B10A2_UINT, 32, 1, 1, GL_UNSIGNED_INT, GenerateMip, ReadColor, NeverSupported); + // GL_UNSIGNED_BYTE -- un-normalized + // NOTE: 3 and 4 component unnormalized GL_UNSIGNED_BYTE should use the default format + // table. + case gl::VERTEX_FORMAT_UBYTE1: + { + static constexpr VertexFormat info(VERTEX_CONVERT_BOTH, DXGI_FORMAT_R8G8B8A8_UINT, + &CopyNativeVertexData); + return &info; + } + case gl::VERTEX_FORMAT_UBYTE2: + { + static constexpr VertexFormat info(VERTEX_CONVERT_BOTH, DXGI_FORMAT_R8G8B8A8_UINT, + &CopyNativeVertexData); + return &info; + } - AddDXGIFormat(&map, DXGI_FORMAT_R16_FLOAT, 16, 1, 1, GL_FLOAT, GenerateMip, ReadColor, RequiresFeatureLevel); - AddDXGIFormat(&map, DXGI_FORMAT_R16G16_FLOAT, 32, 1, 1, GL_FLOAT, GenerateMip, ReadColor, RequiresFeatureLevel); - AddDXGIFormat(&map, DXGI_FORMAT_R16G16B16A16_FLOAT, 64, 1, 1, GL_FLOAT, GenerateMip, ReadColor, RequiresFeatureLevel); + // GL_UNSIGNED_BYTE -- normalized + // NOTE: 3 and 4 component normalized GL_UNSIGNED_BYTE should use the default format table. - AddDXGIFormat(&map, DXGI_FORMAT_R32_FLOAT, 32, 1, 1, GL_FLOAT, GenerateMip, ReadColor, RequiresFeatureLevel); - AddDXGIFormat(&map, DXGI_FORMAT_R32G32_FLOAT, 64, 1, 1, GL_FLOAT, GenerateMip, ReadColor, RequiresFeatureLevel); - AddDXGIFormat(&map, DXGI_FORMAT_R32G32B32_FLOAT, 96, 1, 1, GL_FLOAT, NULL, NULL, NeverSupported); - AddDXGIFormat(&map, DXGI_FORMAT_R32G32B32A32_FLOAT, 128, 1, 1, GL_FLOAT, GenerateMip, ReadColor, RequiresFeatureLevel); + // GL_UNSIGNED_BYTE -- normalized + case gl::VERTEX_FORMAT_UBYTE1_NORM: + { + static constexpr VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R8G8B8A8_UNORM, + &CopyNativeVertexData); + return &info; + } + case gl::VERTEX_FORMAT_UBYTE2_NORM: + { + static constexpr VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R8G8B8A8_UNORM, + &CopyNativeVertexData); + return &info; + } - AddDXGIFormat(&map, DXGI_FORMAT_R9G9B9E5_SHAREDEXP, 32, 1, 1, GL_FLOAT, GenerateMip, ReadColor, NeverSupported); - AddDXGIFormat(&map, DXGI_FORMAT_R11G11B10_FLOAT, 32, 1, 1, GL_FLOAT, GenerateMip, ReadColor, RequiresFeatureLevel); + // GL_SHORT -- un-normalized + // NOTE: 2, 3 and 4 component unnormalized GL_SHORT should use the default format table. + case gl::VERTEX_FORMAT_SSHORT1: + { + static constexpr VertexFormat info(VERTEX_CONVERT_BOTH, DXGI_FORMAT_R16G16_SINT, + &CopyNativeVertexData); + return &info; + } - AddDXGIFormat(&map, DXGI_FORMAT_R16_TYPELESS, 16, 1, 1, GL_NONE, NULL, NULL, NeverSupported); - AddDXGIFormat(&map, DXGI_FORMAT_R16_UNORM, 16, 1, 1, GL_UNSIGNED_NORMALIZED, NULL, NULL, NeverSupported); - AddDXGIFormat(&map, DXGI_FORMAT_D16_UNORM, 16, 1, 1, GL_UNSIGNED_NORMALIZED, NULL, NULL, NeverSupported); - AddDXGIFormat(&map, DXGI_FORMAT_R24G8_TYPELESS, 32, 1, 1, GL_NONE, NULL, NULL, NeverSupported); - AddDXGIFormat(&map, DXGI_FORMAT_R24_UNORM_X8_TYPELESS, 32, 1, 1, GL_NONE, NULL, NULL, NeverSupported); - AddDXGIFormat(&map, DXGI_FORMAT_D24_UNORM_S8_UINT, 32, 1, 1, GL_UNSIGNED_INT, NULL, NULL, NeverSupported); - AddDXGIFormat(&map, DXGI_FORMAT_R32G8X24_TYPELESS, 64, 1, 1, GL_NONE, NULL, NULL, NeverSupported); - AddDXGIFormat(&map, DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS, 64, 1, 1, GL_NONE, NULL, NULL, NeverSupported); - AddDXGIFormat(&map, DXGI_FORMAT_D32_FLOAT_S8X24_UINT, 64, 1, 1, GL_UNSIGNED_INT, NULL, NULL, NeverSupported); - AddDXGIFormat(&map, DXGI_FORMAT_R32_TYPELESS, 32, 1, 1, GL_NONE, NULL, NULL, NeverSupported); - AddDXGIFormat(&map, DXGI_FORMAT_D32_FLOAT, 32, 1, 1, GL_FLOAT, NULL, NULL, NeverSupported); + // GL_SHORT -- normalized + // NOTE: 2, 3 and 4 component normalized GL_SHORT should use the default format table. + case gl::VERTEX_FORMAT_SSHORT1_NORM: + { + static constexpr VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R16G16_SNORM, + &CopyNativeVertexData); + return &info; + } - AddDXGIFormat(&map, DXGI_FORMAT_BC1_UNORM, 64, 4, 4, GL_UNSIGNED_NORMALIZED, NULL, NULL, NeverSupported); - AddDXGIFormat(&map, DXGI_FORMAT_BC2_UNORM, 128, 4, 4, GL_UNSIGNED_NORMALIZED, NULL, NULL, NeverSupported); - AddDXGIFormat(&map, DXGI_FORMAT_BC3_UNORM, 128, 4, 4, GL_UNSIGNED_NORMALIZED, NULL, NULL, NeverSupported); + // GL_UNSIGNED_SHORT -- un-normalized + case gl::VERTEX_FORMAT_USHORT1: + { + static constexpr VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32_FLOAT, + &CopyTo32FVertexData); + return &info; + } + case gl::VERTEX_FORMAT_USHORT2: + { + static constexpr VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32_FLOAT, + &CopyTo32FVertexData); + return &info; + } + case gl::VERTEX_FORMAT_USHORT3: + { + static constexpr VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32_FLOAT, + &CopyTo32FVertexData); + return &info; + } + case gl::VERTEX_FORMAT_USHORT4: + { + static constexpr VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32A32_FLOAT, + &CopyTo32FVertexData); + return &info; + } - // B5G6R5 in D3D11 is treated the same as R5G6B5 in D3D9, so reuse the R5G6B5 functions used by the D3D9 renderer. - // The same applies to B4G4R4A4 and B5G5R5A1 with A4R4G4B4 and A1R5G5B5 respectively. - AddDXGIFormat(&map, DXGI_FORMAT_B5G6R5_UNORM, 16, 1, 1, GL_UNSIGNED_NORMALIZED, GenerateMip, ReadColor, RequiresFeatureLevel); - AddDXGIFormat(&map, DXGI_FORMAT_B4G4R4A4_UNORM, 16, 1, 1, GL_UNSIGNED_NORMALIZED, GenerateMip, ReadColor, NeverSupported); - AddDXGIFormat(&map, DXGI_FORMAT_B5G5R5A1_UNORM, 16, 1, 1, GL_UNSIGNED_NORMALIZED, GenerateMip, ReadColor, NeverSupported); + // GL_UNSIGNED_SHORT -- normalized + case gl::VERTEX_FORMAT_USHORT1_NORM: + { + static constexpr VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32_FLOAT, + &CopyTo32FVertexData); + return &info; + } + case gl::VERTEX_FORMAT_USHORT2_NORM: + { + static constexpr VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32_FLOAT, + &CopyTo32FVertexData); + return &info; + } + case gl::VERTEX_FORMAT_USHORT3_NORM: + { + static constexpr VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32_FLOAT, + &CopyTo32FVertexData); + return &info; + } + case gl::VERTEX_FORMAT_USHORT4_NORM: + { + static constexpr VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32A32_FLOAT, + &CopyTo32FVertexData); + return &info; + } - // Useful formats for vertex buffers - AddDXGIFormat(&map, DXGI_FORMAT_R16_UNORM, 16, 1, 1, GL_UNSIGNED_NORMALIZED, NULL, NULL, NeverSupported); - AddDXGIFormat(&map, DXGI_FORMAT_R16_SNORM, 16, 1, 1, GL_SIGNED_NORMALIZED, NULL, NULL, NeverSupported); - AddDXGIFormat(&map, DXGI_FORMAT_R16G16_UNORM, 32, 1, 1, GL_UNSIGNED_NORMALIZED, NULL, NULL, NeverSupported); - AddDXGIFormat(&map, DXGI_FORMAT_R16G16_SNORM, 32, 1, 1, GL_SIGNED_NORMALIZED, NULL, NULL, NeverSupported); - AddDXGIFormat(&map, DXGI_FORMAT_R16G16B16A16_UNORM, 64, 1, 1, GL_UNSIGNED_NORMALIZED, NULL, NULL, NeverSupported); - AddDXGIFormat(&map, DXGI_FORMAT_R16G16B16A16_SNORM, 64, 1, 1, GL_SIGNED_NORMALIZED, NULL, NULL, NeverSupported); + // GL_FIXED + // TODO: Add test to verify that this works correctly. + // NOTE: 2, 3 and 4 component GL_FIXED should use the default format table. + case gl::VERTEX_FORMAT_FIXED1: + { + static constexpr VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32_FLOAT, + &Copy32FixedTo32FVertexData<1, 2>); + return &info; + } - return map; -} + // GL_FLOAT + // TODO: Add test to verify that this works correctly. + // NOTE: 2, 3 and 4 component GL_FLOAT should use the default format table. + case gl::VERTEX_FORMAT_FLOAT1: + { + static constexpr VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32_FLOAT, + &CopyNativeVertexData); + return &info; + } -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; + default: + return nullptr; } } -typedef std::map D3D11VertexFormatInfoMap; -typedef std::pair D3D11VertexFormatPair; - -VertexFormat::VertexFormat() - : conversionType(VERTEX_CONVERT_NONE), - nativeFormat(DXGI_FORMAT_UNKNOWN), - copyFunction(NULL) -{ -} - -VertexFormat::VertexFormat(VertexConversionType conversionTypeIn, - DXGI_FORMAT nativeFormatIn, - VertexCopyFunction copyFunctionIn) - : conversionType(conversionTypeIn), - nativeFormat(nativeFormatIn), - copyFunction(copyFunctionIn) -{ -} - -static void AddVertexFormatInfo(D3D11VertexFormatInfoMap *map, - GLenum inputType, - GLboolean normalized, - GLuint componentCount, - VertexConversionType conversionType, - DXGI_FORMAT nativeFormat, - VertexCopyFunction copyFunction) -{ - gl::VertexFormatType formatType = gl::GetVertexFormatType(inputType, normalized, componentCount, false); - - VertexFormat info; - info.conversionType = conversionType; - info.nativeFormat = nativeFormat; - info.copyFunction = copyFunction; - - map->insert(D3D11VertexFormatPair(formatType, 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; -} - const VertexFormat &GetVertexFormatInfo(gl::VertexFormatType vertexFormatType, D3D_FEATURE_LEVEL featureLevel) { if (featureLevel == D3D_FEATURE_LEVEL_9_3) { - static const D3D11VertexFormatInfoMap vertexFormatMapFL9_3Override = - BuildD3D11_FL9_3VertexFormatInfoOverrideMap(); - - // First see if the format has a special mapping for FL9_3 - auto iter = vertexFormatMapFL9_3Override.find(vertexFormatType); - if (iter != vertexFormatMapFL9_3Override.end()) + const VertexFormat *result = GetVertexFormatInfo_FL_9_3(vertexFormatType); + if (result) { - return iter->second; + return *result; } } @@ -589,354 +419,418 @@ const VertexFormat &GetVertexFormatInfo(gl::VertexFormatType vertexFormatType, D // GL_BYTE -- un-normalized case gl::VERTEX_FORMAT_SBYTE1: { - static const VertexFormat info(VERTEX_CONVERT_GPU, DXGI_FORMAT_R8_SINT, &CopyNativeVertexData); + static constexpr VertexFormat info(VERTEX_CONVERT_GPU, DXGI_FORMAT_R8_SINT, + &CopyNativeVertexData); return info; } case gl::VERTEX_FORMAT_SBYTE2: { - static const VertexFormat info(VERTEX_CONVERT_GPU, DXGI_FORMAT_R8G8_SINT, &CopyNativeVertexData); + static constexpr VertexFormat info(VERTEX_CONVERT_GPU, DXGI_FORMAT_R8G8_SINT, + &CopyNativeVertexData); return info; } case gl::VERTEX_FORMAT_SBYTE3: { - static const VertexFormat info(VERTEX_CONVERT_BOTH, DXGI_FORMAT_R8G8B8A8_SINT, &CopyNativeVertexData); + static constexpr VertexFormat info(VERTEX_CONVERT_BOTH, DXGI_FORMAT_R8G8B8A8_SINT, + &CopyNativeVertexData); return info; } case gl::VERTEX_FORMAT_SBYTE4: { - static const VertexFormat info(VERTEX_CONVERT_GPU, DXGI_FORMAT_R8G8B8A8_SINT, &CopyNativeVertexData); + static constexpr VertexFormat info(VERTEX_CONVERT_GPU, DXGI_FORMAT_R8G8B8A8_SINT, + &CopyNativeVertexData); return info; } // GL_BYTE -- normalized case gl::VERTEX_FORMAT_SBYTE1_NORM: { - static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R8_SNORM, &CopyNativeVertexData); + static constexpr VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R8_SNORM, + &CopyNativeVertexData); return info; } case gl::VERTEX_FORMAT_SBYTE2_NORM: { - static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R8G8_SNORM, &CopyNativeVertexData); + static constexpr VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R8G8_SNORM, + &CopyNativeVertexData); return info; } case gl::VERTEX_FORMAT_SBYTE3_NORM: { - static const VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R8G8B8A8_SNORM, &CopyNativeVertexData); + static constexpr VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R8G8B8A8_SNORM, + &CopyNativeVertexData); return info; } case gl::VERTEX_FORMAT_SBYTE4_NORM: { - static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R8G8B8A8_SNORM, &CopyNativeVertexData); + static constexpr VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R8G8B8A8_SNORM, + &CopyNativeVertexData); return info; } // GL_UNSIGNED_BYTE -- un-normalized case gl::VERTEX_FORMAT_UBYTE1: { - static const VertexFormat info(VERTEX_CONVERT_GPU, DXGI_FORMAT_R8_UINT, &CopyNativeVertexData); + static constexpr VertexFormat info(VERTEX_CONVERT_GPU, DXGI_FORMAT_R8_UINT, + &CopyNativeVertexData); return info; } case gl::VERTEX_FORMAT_UBYTE2: { - static const VertexFormat info(VERTEX_CONVERT_GPU, DXGI_FORMAT_R8G8_UINT, &CopyNativeVertexData); + static constexpr VertexFormat info(VERTEX_CONVERT_GPU, DXGI_FORMAT_R8G8_UINT, + &CopyNativeVertexData); return info; } case gl::VERTEX_FORMAT_UBYTE3: { - static const VertexFormat info(VERTEX_CONVERT_BOTH, DXGI_FORMAT_R8G8B8A8_UINT, &CopyNativeVertexData); + static constexpr VertexFormat info(VERTEX_CONVERT_BOTH, DXGI_FORMAT_R8G8B8A8_UINT, + &CopyNativeVertexData); return info; } case gl::VERTEX_FORMAT_UBYTE4: { - static const VertexFormat info(VERTEX_CONVERT_GPU, DXGI_FORMAT_R8G8B8A8_UINT, &CopyNativeVertexData); + static constexpr VertexFormat info(VERTEX_CONVERT_GPU, DXGI_FORMAT_R8G8B8A8_UINT, + &CopyNativeVertexData); return info; } // GL_UNSIGNED_BYTE -- normalized case gl::VERTEX_FORMAT_UBYTE1_NORM: { - static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R8_UNORM, &CopyNativeVertexData); + static constexpr VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R8_UNORM, + &CopyNativeVertexData); return info; } case gl::VERTEX_FORMAT_UBYTE2_NORM: { - static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R8G8_UNORM, &CopyNativeVertexData); + static constexpr VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R8G8_UNORM, + &CopyNativeVertexData); return info; } case gl::VERTEX_FORMAT_UBYTE3_NORM: { - static const VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R8G8B8A8_UNORM, &CopyNativeVertexData); + static constexpr VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R8G8B8A8_UNORM, + &CopyNativeVertexData); return info; } case gl::VERTEX_FORMAT_UBYTE4_NORM: { - static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R8G8B8A8_UNORM, &CopyNativeVertexData); + static constexpr VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R8G8B8A8_UNORM, + &CopyNativeVertexData); return info; } // GL_SHORT -- un-normalized case gl::VERTEX_FORMAT_SSHORT1: { - static const VertexFormat info(VERTEX_CONVERT_GPU, DXGI_FORMAT_R16_SINT, &CopyNativeVertexData); + static constexpr VertexFormat info(VERTEX_CONVERT_GPU, DXGI_FORMAT_R16_SINT, + &CopyNativeVertexData); return info; } case gl::VERTEX_FORMAT_SSHORT2: { - static const VertexFormat info(VERTEX_CONVERT_GPU, DXGI_FORMAT_R16G16_SINT, &CopyNativeVertexData); + static constexpr VertexFormat info(VERTEX_CONVERT_GPU, DXGI_FORMAT_R16G16_SINT, + &CopyNativeVertexData); return info; } case gl::VERTEX_FORMAT_SSHORT3: { - static const VertexFormat info(VERTEX_CONVERT_BOTH, DXGI_FORMAT_R16G16B16A16_SINT, &CopyNativeVertexData); + static constexpr VertexFormat info(VERTEX_CONVERT_BOTH, DXGI_FORMAT_R16G16B16A16_SINT, + &CopyNativeVertexData); return info; } case gl::VERTEX_FORMAT_SSHORT4: { - static const VertexFormat info(VERTEX_CONVERT_GPU, DXGI_FORMAT_R16G16B16A16_SINT, &CopyNativeVertexData); + static constexpr VertexFormat info(VERTEX_CONVERT_GPU, DXGI_FORMAT_R16G16B16A16_SINT, + &CopyNativeVertexData); return info; } // GL_SHORT -- normalized case gl::VERTEX_FORMAT_SSHORT1_NORM: { - static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R16_SNORM, &CopyNativeVertexData); + static constexpr VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R16_SNORM, + &CopyNativeVertexData); return info; } case gl::VERTEX_FORMAT_SSHORT2_NORM: { - static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16_SNORM, &CopyNativeVertexData); + static constexpr VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16_SNORM, + &CopyNativeVertexData); return info; } case gl::VERTEX_FORMAT_SSHORT3_NORM: { - static const VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R16G16B16A16_SNORM, &CopyNativeVertexData); + static constexpr VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R16G16B16A16_SNORM, + &CopyNativeVertexData); return info; } case gl::VERTEX_FORMAT_SSHORT4_NORM: { - static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16B16A16_SNORM, &CopyNativeVertexData); + static constexpr VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16B16A16_SNORM, + &CopyNativeVertexData); return info; } // GL_UNSIGNED_SHORT -- un-normalized case gl::VERTEX_FORMAT_USHORT1: { - static const VertexFormat info(VERTEX_CONVERT_GPU, DXGI_FORMAT_R16_UINT, &CopyNativeVertexData); + static constexpr VertexFormat info(VERTEX_CONVERT_GPU, DXGI_FORMAT_R16_UINT, + &CopyNativeVertexData); return info; } case gl::VERTEX_FORMAT_USHORT2: { - static const VertexFormat info(VERTEX_CONVERT_GPU, DXGI_FORMAT_R16G16_UINT, &CopyNativeVertexData); + static constexpr VertexFormat info(VERTEX_CONVERT_GPU, DXGI_FORMAT_R16G16_UINT, + &CopyNativeVertexData); return info; } case gl::VERTEX_FORMAT_USHORT3: { - static const VertexFormat info(VERTEX_CONVERT_BOTH, DXGI_FORMAT_R16G16B16A16_UINT, &CopyNativeVertexData); + static constexpr VertexFormat info(VERTEX_CONVERT_BOTH, DXGI_FORMAT_R16G16B16A16_UINT, + &CopyNativeVertexData); return info; } case gl::VERTEX_FORMAT_USHORT4: { - static const VertexFormat info(VERTEX_CONVERT_GPU, DXGI_FORMAT_R16G16B16A16_UINT, &CopyNativeVertexData); + static constexpr VertexFormat info(VERTEX_CONVERT_GPU, DXGI_FORMAT_R16G16B16A16_UINT, + &CopyNativeVertexData); return info; } // GL_UNSIGNED_SHORT -- normalized case gl::VERTEX_FORMAT_USHORT1_NORM: { - static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R16_UNORM, &CopyNativeVertexData); + static constexpr VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R16_UNORM, + &CopyNativeVertexData); return info; } case gl::VERTEX_FORMAT_USHORT2_NORM: { - static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16_UNORM, &CopyNativeVertexData); + static constexpr VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16_UNORM, + &CopyNativeVertexData); return info; } case gl::VERTEX_FORMAT_USHORT3_NORM: { - static const VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R16G16B16A16_UNORM, &CopyNativeVertexData); + static constexpr VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R16G16B16A16_UNORM, + &CopyNativeVertexData); return info; } case gl::VERTEX_FORMAT_USHORT4_NORM: { - static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16B16A16_UNORM, &CopyNativeVertexData); + static constexpr VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16B16A16_UNORM, + &CopyNativeVertexData); return info; } // GL_INT -- un-normalized case gl::VERTEX_FORMAT_SINT1: { - static const VertexFormat info(VERTEX_CONVERT_GPU, DXGI_FORMAT_R32_SINT, &CopyNativeVertexData); + static constexpr VertexFormat info(VERTEX_CONVERT_GPU, DXGI_FORMAT_R32_SINT, + &CopyNativeVertexData); return info; } case gl::VERTEX_FORMAT_SINT2: { - static const VertexFormat info(VERTEX_CONVERT_GPU, DXGI_FORMAT_R32G32_SINT, &CopyNativeVertexData); + static constexpr VertexFormat info(VERTEX_CONVERT_GPU, DXGI_FORMAT_R32G32_SINT, + &CopyNativeVertexData); return info; } case gl::VERTEX_FORMAT_SINT3: { - static const VertexFormat info(VERTEX_CONVERT_GPU, DXGI_FORMAT_R32G32B32_SINT, &CopyNativeVertexData); + static constexpr VertexFormat info(VERTEX_CONVERT_GPU, DXGI_FORMAT_R32G32B32_SINT, + &CopyNativeVertexData); return info; } case gl::VERTEX_FORMAT_SINT4: { - static const VertexFormat info(VERTEX_CONVERT_GPU, DXGI_FORMAT_R32G32B32A32_SINT, &CopyNativeVertexData); + static constexpr VertexFormat info(VERTEX_CONVERT_GPU, DXGI_FORMAT_R32G32B32A32_SINT, + &CopyNativeVertexData); return info; } // GL_INT -- normalized case gl::VERTEX_FORMAT_SINT1_NORM: { - static const VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R32_FLOAT, &CopyTo32FVertexData); + static constexpr VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R32_FLOAT, + &CopyTo32FVertexData); return info; } case gl::VERTEX_FORMAT_SINT2_NORM: { - static const VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32_FLOAT, &CopyTo32FVertexData); + static constexpr VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32_FLOAT, + &CopyTo32FVertexData); return info; } case gl::VERTEX_FORMAT_SINT3_NORM: { - static const VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32_FLOAT, &CopyTo32FVertexData); + static constexpr VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32_FLOAT, + &CopyTo32FVertexData); return info; } case gl::VERTEX_FORMAT_SINT4_NORM: { - static const VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32A32_FLOAT, &CopyTo32FVertexData); + static constexpr VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32A32_FLOAT, + &CopyTo32FVertexData); return info; } // GL_UNSIGNED_INT -- un-normalized case gl::VERTEX_FORMAT_UINT1: { - static const VertexFormat info(VERTEX_CONVERT_GPU, DXGI_FORMAT_R32_UINT, &CopyNativeVertexData); + static constexpr VertexFormat info(VERTEX_CONVERT_GPU, DXGI_FORMAT_R32_UINT, + &CopyNativeVertexData); return info; } case gl::VERTEX_FORMAT_UINT2: { - static const VertexFormat info(VERTEX_CONVERT_GPU, DXGI_FORMAT_R32G32_UINT, &CopyNativeVertexData); + static constexpr VertexFormat info(VERTEX_CONVERT_GPU, DXGI_FORMAT_R32G32_UINT, + &CopyNativeVertexData); return info; } case gl::VERTEX_FORMAT_UINT3: { - static const VertexFormat info(VERTEX_CONVERT_GPU, DXGI_FORMAT_R32G32B32_UINT, &CopyNativeVertexData); + static constexpr VertexFormat info(VERTEX_CONVERT_GPU, DXGI_FORMAT_R32G32B32_UINT, + &CopyNativeVertexData); return info; } case gl::VERTEX_FORMAT_UINT4: { - static const VertexFormat info(VERTEX_CONVERT_GPU, DXGI_FORMAT_R32G32B32A32_UINT, &CopyNativeVertexData); + static constexpr VertexFormat info(VERTEX_CONVERT_GPU, DXGI_FORMAT_R32G32B32A32_UINT, + &CopyNativeVertexData); return info; } // GL_UNSIGNED_INT -- normalized case gl::VERTEX_FORMAT_UINT1_NORM: { - static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R32_FLOAT, &CopyTo32FVertexData); + static constexpr VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R32_FLOAT, + &CopyTo32FVertexData); return info; } case gl::VERTEX_FORMAT_UINT2_NORM: { - static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32_FLOAT, &CopyTo32FVertexData); + static constexpr VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32_FLOAT, + &CopyTo32FVertexData); return info; } case gl::VERTEX_FORMAT_UINT3_NORM: { - static const VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32_FLOAT, &CopyTo32FVertexData); + static constexpr VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32_FLOAT, + &CopyTo32FVertexData); return info; } case gl::VERTEX_FORMAT_UINT4_NORM: { - static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32B32A32_FLOAT, &CopyTo32FVertexData); + static constexpr VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32A32_FLOAT, + &CopyTo32FVertexData); return info; } // GL_FIXED case gl::VERTEX_FORMAT_FIXED1: { - static const VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R32_FLOAT, &Copy32FixedTo32FVertexData<1, 1>); + static constexpr VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R32_FLOAT, + &Copy32FixedTo32FVertexData<1, 1>); return info; } case gl::VERTEX_FORMAT_FIXED2: { - static const VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32_FLOAT, &Copy32FixedTo32FVertexData<2, 2>); + static constexpr VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32_FLOAT, + &Copy32FixedTo32FVertexData<2, 2>); return info; } case gl::VERTEX_FORMAT_FIXED3: { - static const VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32_FLOAT, &Copy32FixedTo32FVertexData<3, 3>); + static constexpr VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32_FLOAT, + &Copy32FixedTo32FVertexData<3, 3>); return info; } case gl::VERTEX_FORMAT_FIXED4: { - static const VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32A32_FLOAT, &Copy32FixedTo32FVertexData<4, 4>); + static constexpr VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32A32_FLOAT, + &Copy32FixedTo32FVertexData<4, 4>); return info; } // GL_HALF_FLOAT case gl::VERTEX_FORMAT_HALF1: { - static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R16_FLOAT, &CopyNativeVertexData); + static constexpr VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R16_FLOAT, + &CopyNativeVertexData); return info; } case gl::VERTEX_FORMAT_HALF2: { - static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16_FLOAT, &CopyNativeVertexData); + static constexpr VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16_FLOAT, + &CopyNativeVertexData); return info; } case gl::VERTEX_FORMAT_HALF3: { - static const VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R16G16B16A16_FLOAT, &CopyNativeVertexData); + static constexpr VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R16G16B16A16_FLOAT, + &CopyNativeVertexData); return info; } case gl::VERTEX_FORMAT_HALF4: { - static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16B16A16_FLOAT, &CopyNativeVertexData); + static constexpr VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16B16A16_FLOAT, + &CopyNativeVertexData); return info; } // GL_FLOAT case gl::VERTEX_FORMAT_FLOAT1: { - static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R32_FLOAT, &CopyNativeVertexData); + static constexpr VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R32_FLOAT, + &CopyNativeVertexData); return info; } case gl::VERTEX_FORMAT_FLOAT2: { - static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32_FLOAT, &CopyNativeVertexData); + static constexpr VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32_FLOAT, + &CopyNativeVertexData); return info; } case gl::VERTEX_FORMAT_FLOAT3: { - static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32B32_FLOAT, &CopyNativeVertexData); + static constexpr VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32B32_FLOAT, + &CopyNativeVertexData); return info; } case gl::VERTEX_FORMAT_FLOAT4: { - static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32B32A32_FLOAT, &CopyNativeVertexData); + static constexpr VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32B32A32_FLOAT, + &CopyNativeVertexData); return info; } // GL_INT_2_10_10_10_REV case gl::VERTEX_FORMAT_SINT210: { - static const VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32A32_FLOAT, &CopyXYZ10W2ToXYZW32FVertexData); + static constexpr VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32A32_FLOAT, + &CopyXYZ10W2ToXYZW32FVertexData); return info; } case gl::VERTEX_FORMAT_SINT210_NORM: { - static const VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32A32_FLOAT, &CopyXYZ10W2ToXYZW32FVertexData); + static constexpr VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32A32_FLOAT, + &CopyXYZ10W2ToXYZW32FVertexData); return info; } // GL_UNSIGNED_INT_2_10_10_10_REV case gl::VERTEX_FORMAT_UINT210: { - static const VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32A32_FLOAT, &CopyXYZ10W2ToXYZW32FVertexData); + static constexpr VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32A32_FLOAT, + &CopyXYZ10W2ToXYZW32FVertexData); return info; } case gl::VERTEX_FORMAT_UINT210_NORM: { - static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R10G10B10A2_UNORM, &CopyNativeVertexData); + static constexpr VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R10G10B10A2_UNORM, + &CopyNativeVertexData); return info; } @@ -947,157 +841,183 @@ const VertexFormat &GetVertexFormatInfo(gl::VertexFormatType vertexFormatType, D // GL_BYTE case gl::VERTEX_FORMAT_SBYTE1_INT: { - static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R8_SINT, &CopyNativeVertexData); + static constexpr VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R8_SINT, + &CopyNativeVertexData); return info; } case gl::VERTEX_FORMAT_SBYTE2_INT: { - static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R8G8_SINT, &CopyNativeVertexData); + static constexpr VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R8G8_SINT, + &CopyNativeVertexData); return info; } case gl::VERTEX_FORMAT_SBYTE3_INT: { - static const VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R8G8B8A8_SINT, &CopyNativeVertexData); + static constexpr VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R8G8B8A8_SINT, + &CopyNativeVertexData); return info; } case gl::VERTEX_FORMAT_SBYTE4_INT: { - static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R8G8B8A8_SINT, &CopyNativeVertexData); + static constexpr VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R8G8B8A8_SINT, + &CopyNativeVertexData); return info; } // GL_UNSIGNED_BYTE case gl::VERTEX_FORMAT_UBYTE1_INT: { - static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R8_UINT, &CopyNativeVertexData); + static constexpr VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R8_UINT, + &CopyNativeVertexData); return info; } case gl::VERTEX_FORMAT_UBYTE2_INT: { - static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R8G8_UINT, &CopyNativeVertexData); + static constexpr VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R8G8_UINT, + &CopyNativeVertexData); return info; } case gl::VERTEX_FORMAT_UBYTE3_INT: { - static const VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R8G8B8A8_UINT, &CopyNativeVertexData); + static constexpr VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R8G8B8A8_UINT, + &CopyNativeVertexData); return info; } case gl::VERTEX_FORMAT_UBYTE4_INT: { - static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R8G8B8A8_UINT, &CopyNativeVertexData); + static constexpr VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R8G8B8A8_UINT, + &CopyNativeVertexData); return info; } // GL_SHORT case gl::VERTEX_FORMAT_SSHORT1_INT: { - static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R16_SINT, &CopyNativeVertexData); + static constexpr VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R16_SINT, + &CopyNativeVertexData); return info; } case gl::VERTEX_FORMAT_SSHORT2_INT: { - static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16_SINT, &CopyNativeVertexData); + static constexpr VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16_SINT, + &CopyNativeVertexData); return info; } case gl::VERTEX_FORMAT_SSHORT3_INT: { - static const VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R16G16B16A16_SINT, &CopyNativeVertexData); + static constexpr VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R16G16B16A16_SINT, + &CopyNativeVertexData); return info; } case gl::VERTEX_FORMAT_SSHORT4_INT: { - static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16B16A16_SINT, &CopyNativeVertexData); + static constexpr VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16B16A16_SINT, + &CopyNativeVertexData); return info; } // GL_UNSIGNED_SHORT case gl::VERTEX_FORMAT_USHORT1_INT: { - static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R16_UINT, &CopyNativeVertexData); + static constexpr VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R16_UINT, + &CopyNativeVertexData); return info; } case gl::VERTEX_FORMAT_USHORT2_INT: { - static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16_UINT, &CopyNativeVertexData); + static constexpr VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16_UINT, + &CopyNativeVertexData); return info; } case gl::VERTEX_FORMAT_USHORT3_INT: { - static const VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R16G16B16A16_UINT, &CopyNativeVertexData); + static constexpr VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R16G16B16A16_UINT, + &CopyNativeVertexData); return info; } case gl::VERTEX_FORMAT_USHORT4_INT: { - static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16B16A16_UINT, &CopyNativeVertexData); + static constexpr VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16B16A16_UINT, + &CopyNativeVertexData); return info; } // GL_INT case gl::VERTEX_FORMAT_SINT1_INT: { - static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R32_SINT, &CopyNativeVertexData); + static constexpr VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R32_SINT, + &CopyNativeVertexData); return info; } case gl::VERTEX_FORMAT_SINT2_INT: { - static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32_SINT, &CopyNativeVertexData); + static constexpr VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32_SINT, + &CopyNativeVertexData); return info; } case gl::VERTEX_FORMAT_SINT3_INT: { - static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32B32_SINT, &CopyNativeVertexData); + static constexpr VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32B32_SINT, + &CopyNativeVertexData); return info; } case gl::VERTEX_FORMAT_SINT4_INT: { - static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32B32A32_SINT, &CopyNativeVertexData); + static constexpr VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32B32A32_SINT, + &CopyNativeVertexData); return info; } // GL_UNSIGNED_INT case gl::VERTEX_FORMAT_UINT1_INT: { - static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R32_SINT, &CopyNativeVertexData); + static constexpr VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R32_SINT, + &CopyNativeVertexData); return info; } case gl::VERTEX_FORMAT_UINT2_INT: { - static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32_SINT, &CopyNativeVertexData); + static constexpr VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32_SINT, + &CopyNativeVertexData); return info; } case gl::VERTEX_FORMAT_UINT3_INT: { - static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32B32_SINT, &CopyNativeVertexData); + static constexpr VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32B32_SINT, + &CopyNativeVertexData); return info; } case gl::VERTEX_FORMAT_UINT4_INT: { - static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32B32A32_SINT, &CopyNativeVertexData); + static constexpr VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32B32A32_SINT, + &CopyNativeVertexData); return info; } // GL_INT_2_10_10_10_REV case gl::VERTEX_FORMAT_SINT210_INT: { - static const VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R16G16B16A16_SINT, &CopyXYZ10W2ToXYZW32FVertexData); + static constexpr VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R16G16B16A16_SINT, + &CopyXYZ10W2ToXYZW32FVertexData); return info; } // GL_UNSIGNED_INT_2_10_10_10_REV case gl::VERTEX_FORMAT_UINT210_INT: { - static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R10G10B10A2_UINT, &CopyNativeVertexData); + static constexpr VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R10G10B10A2_UINT, + &CopyNativeVertexData); return info; } default: { - static const VertexFormat info; + static constexpr VertexFormat info; return info; } } } -} +} // namespace d3d11 -} +} // namespace rx diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/formatutils11.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/formatutils11.h index 7b97527140..883d338377 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/formatutils11.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/formatutils11.h @@ -15,6 +15,7 @@ #include "common/platform.h" #include "libANGLE/angletypes.h" #include "libANGLE/formatutils.h" +#include "libANGLE/renderer/renderer_utils.h" #include "libANGLE/renderer/d3d/formatutilsD3D.h" namespace rx @@ -24,58 +25,47 @@ struct Renderer11DeviceCaps; namespace d3d11 { -typedef std::map, ColorCopyFunction> FastCopyFunctionMap; -typedef bool (*NativeMipmapGenerationSupportFunction)(D3D_FEATURE_LEVEL); +// A texture might be stored as DXGI_FORMAT_R16_TYPELESS but store integer components, +// which are accessed through an DXGI_FORMAT_R16_SINT view. It's easy to write code which queries +// information about the wrong format. Therefore, use of this should be avoided where possible. -struct DXGIFormat +bool SupportsMipGen(DXGI_FORMAT dxgiFormat, D3D_FEATURE_LEVEL featureLevel); + +struct DXGIFormatSize { - DXGIFormat(); + DXGIFormatSize(GLuint pixelBits, GLuint blockWidth, GLuint blockHeight); 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; - - NativeMipmapGenerationSupportFunction nativeMipmapSupport; - - ColorCopyFunction getFastCopyFunction(GLenum format, GLenum type) const; }; -const DXGIFormat &GetDXGIFormatInfo(DXGI_FORMAT format); +const DXGIFormatSize &GetDXGIFormatSizeInfo(DXGI_FORMAT format); -struct VertexFormat +struct VertexFormat : private angle::NonCopyable { - VertexFormat(); - VertexFormat(VertexConversionType conversionType, - DXGI_FORMAT nativeFormat, - VertexCopyFunction copyFunction); + constexpr VertexFormat(); + constexpr VertexFormat(VertexConversionType conversionType, + DXGI_FORMAT nativeFormat, + VertexCopyFunction copyFunction); VertexConversionType conversionType; DXGI_FORMAT nativeFormat; VertexCopyFunction copyFunction; }; + const VertexFormat &GetVertexFormatInfo(gl::VertexFormatType vertexFormatType, D3D_FEATURE_LEVEL featureLevel); +// Auto-generated in dxgi_format_map_autogen.cpp. +GLenum GetComponentType(DXGI_FORMAT dxgiFormat); + } // namespace d3d11 +namespace d3d11_angle +{ +const angle::Format &GetFormat(DXGI_FORMAT dxgiFormat); +} + } // namespace rx #endif // LIBANGLE_RENDERER_D3D_D3D11_FORMATUTILS11_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/gen_load_functions_table.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/gen_load_functions_table.cpp deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/internal_format_initializer_table.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/internal_format_initializer_table.cpp deleted file mode 100644 index adb20a5e60..0000000000 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/internal_format_initializer_table.cpp +++ /dev/null @@ -1,170 +0,0 @@ -// -// 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. -// -// internal_format_initializer_table: -// Contains table to go from internal format and dxgi format to initializer function -// for TextureFormat -// - -#include "libANGLE/renderer/d3d/d3d11/internal_format_initializer_table.h" -#include "libANGLE/renderer/d3d/loadimage.h" - -namespace rx -{ - -namespace d3d11 -{ - -// TODO: This should be generated by a JSON file -InitializeTextureDataFunction GetInternalFormatInitializer(GLenum internalFormat, - DXGI_FORMAT dxgiFormat) -{ - switch (internalFormat) - { - case GL_RGB8: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_R8G8B8A8_UNORM: - { - return Initialize4ComponentData; - } - default: - break; - } - } - case GL_RGB565: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_R8G8B8A8_UNORM: - { - return Initialize4ComponentData; - } - default: - break; - } - } - case GL_SRGB8: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: - { - return Initialize4ComponentData; - } - default: - break; - } - } - case GL_RGB16F: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_R16G16B16A16_FLOAT: - { - return Initialize4ComponentData; - } - default: - break; - } - } - case GL_RGB32F: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_R32G32B32A32_FLOAT: - { - return Initialize4ComponentData; - } - default: - break; - } - } - case GL_RGB8UI: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_R8G8B8A8_UINT: - { - return Initialize4ComponentData; - } - default: - break; - } - } - case GL_RGB8I: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_R8G8B8A8_SINT: - { - return Initialize4ComponentData; - } - default: - break; - } - } - case GL_RGB16UI: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_R16G16B16A16_UINT: - { - return Initialize4ComponentData; - } - default: - break; - } - } - case GL_RGB16I: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_R16G16B16A16_SINT: - { - return Initialize4ComponentData; - } - default: - break; - } - } - case GL_RGB32UI: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_R32G32B32A32_UINT: - { - return Initialize4ComponentData; - } - default: - break; - } - } - case GL_RGB32I: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_R32G32B32A32_SINT: - { - return Initialize4ComponentData; - } - default: - break; - } - } - default: - { - return nullptr; - } - } -} - -} // namespace d3d11 - -} // namespace rx diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/internal_format_initializer_table.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/internal_format_initializer_table.h deleted file mode 100644 index 2d538e1d82..0000000000 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/internal_format_initializer_table.h +++ /dev/null @@ -1,31 +0,0 @@ -// -// 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. -// -// internal_format_initializer_table: -// Contains table to go from internal format and dxgi format to initializer function -// for TextureFormat -// - -#ifndef LIBANGLE_RENDERER_D3D_D3D11_INTERNALFORMATINITIALIZERTABLE_H_ -#define LIBANGLE_RENDERER_D3D_D3D11_INTERNALFORMATINITIALIZERTABLE_H_ - -#include "libANGLE/renderer/d3d/d3d11/Renderer11.h" - -#include - -namespace rx -{ - -namespace d3d11 -{ - -InitializeTextureDataFunction GetInternalFormatInitializer(GLenum internalFormat, - DXGI_FORMAT dxgiFormat); - -} // namespace d3d11 - -} // namespace rx - -#endif // LIBANGLE_RENDERER_D3D_D3D11_INTERNALFORMATINITIALIZERTABLE_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/load_functions_data.json b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/load_functions_data.json deleted file mode 100644 index c85393e06b..0000000000 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/load_functions_data.json +++ /dev/null @@ -1,1116 +0,0 @@ -{ - "GL_RG8_SNORM": { - "GL_BYTE": [ - { - "loadFunction": "LoadToNative", - "dxgiFormat": "DXGI_FORMAT_R8G8_SNORM", - "requiresConversion": "false" - } - ] - }, - "GL_SRGB8": { - "GL_UNSIGNED_BYTE": [ - { - "loadFunction": "LoadToNative3To4", - "dxgiFormat": "DXGI_FORMAT_R8G8B8A8_UNORM_SRGB", - "requiresConversion": "true" - } - ] - }, - "GL_RGBA8I": { - "GL_BYTE": [ - { - "loadFunction": "LoadToNative", - "dxgiFormat": "DXGI_FORMAT_R8G8B8A8_SINT", - "requiresConversion": "false" - } - ] - }, - "GL_R8_SNORM": { - "GL_BYTE": [ - { - "loadFunction": "LoadToNative", - "dxgiFormat": "DXGI_FORMAT_R8_SNORM", - "requiresConversion": "false" - } - ] - }, - "GL_RGBA8_SNORM": { - "GL_BYTE": [ - { - "loadFunction": "LoadToNative", - "dxgiFormat": "DXGI_FORMAT_R8G8B8A8_SNORM", - "requiresConversion": "false" - } - ] - }, - "GL_R16I": { - "GL_SHORT": [ - { - "loadFunction": "LoadToNative", - "dxgiFormat": "DXGI_FORMAT_R16_SINT", - "requiresConversion": "false" - } - ] - }, - "GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC": { - "GL_UNSIGNED_BYTE": [ - { - "loadFunction": "LoadETC2SRGBA8ToSRGBA8", - "dxgiFormat": "DXGI_FORMAT_R8G8B8A8_UNORM_SRGB", - "requiresConversion": "true" - } - ] - }, - "GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2": { - "GL_UNSIGNED_BYTE": [ - { - "loadFunction": "LoadETC2RGB8A1ToRGBA8", - "dxgiFormat": "DXGI_FORMAT_R8G8B8A8_UNORM", - "requiresConversion": "true" - } - ] - }, - "GL_RGB32UI": { - "GL_UNSIGNED_INT": [ - { - "loadFunction": "LoadToNative3To4", - "dxgiFormat": "DXGI_FORMAT_R32G32B32A32_UINT", - "requiresConversion": "true" - } - ] - }, - "GL_ALPHA32F_EXT": { - "GL_FLOAT": [ - { - "loadFunction": "LoadA32FToRGBA32F", - "dxgiFormat": "DXGI_FORMAT_UNKNOWN", - "requiresConversion": "true" - } - ] - }, - "GL_R16UI": { - "GL_UNSIGNED_SHORT": [ - { - "loadFunction": "LoadToNative", - "dxgiFormat": "DXGI_FORMAT_R16_UINT", - "requiresConversion": "false" - } - ] - }, - "GL_RGB9_E5": { - "GL_HALF_FLOAT": [ - { - "loadFunction": "LoadRGB16FToRGB9E5", - "dxgiFormat": "DXGI_FORMAT_R9G9B9E5_SHAREDEXP", - "requiresConversion": "true" - } - ], - "GL_UNSIGNED_INT_5_9_9_9_REV": [ - { - "loadFunction": "LoadToNative", - "dxgiFormat": "DXGI_FORMAT_R9G9B9E5_SHAREDEXP", - "requiresConversion": "false" - } - ], - "GL_FLOAT": [ - { - "loadFunction": "LoadRGB32FToRGB9E5", - "dxgiFormat": "DXGI_FORMAT_R9G9B9E5_SHAREDEXP", - "requiresConversion": "true" - } - ], - "GL_HALF_FLOAT_OES": [ - { - "loadFunction": "LoadRGB16FToRGB9E5", - "dxgiFormat": "DXGI_FORMAT_R9G9B9E5_SHAREDEXP", - "requiresConversion": "true" - } - ] - }, - "GL_COMPRESSED_R11_EAC": { - "GL_UNSIGNED_BYTE": [ - { - "loadFunction": "LoadEACR11ToR8", - "dxgiFormat": "DXGI_FORMAT_R8_UNORM", - "requiresConversion": "true" - } - ] - }, - "GL_RGBA32UI": { - "GL_UNSIGNED_INT": [ - { - "loadFunction": "LoadToNative", - "dxgiFormat": "DXGI_FORMAT_R32G32B32A32_UINT", - "requiresConversion": "false" - } - ] - }, - "GL_RG8UI": { - "GL_UNSIGNED_BYTE": [ - { - "loadFunction": "LoadToNative", - "dxgiFormat": "DXGI_FORMAT_R8G8_UINT", - "requiresConversion": "false" - } - ] - }, - "GL_LUMINANCE32F_EXT": { - "GL_FLOAT": [ - { - "loadFunction": "LoadL32FToRGBA32F", - "dxgiFormat": "DXGI_FORMAT_UNKNOWN", - "requiresConversion": "true" - } - ] - }, - "GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2": { - "GL_UNSIGNED_BYTE": [ - { - "loadFunction": "LoadETC2SRGB8A1ToRGBA8", - "dxgiFormat": "DXGI_FORMAT_R8G8B8A8_UNORM_SRGB", - "requiresConversion": "true" - } - ] - }, - "GL_R16F": { - "GL_HALF_FLOAT": [ - { - "loadFunction": "LoadToNative", - "dxgiFormat": "DXGI_FORMAT_R16_FLOAT", - "requiresConversion": "false" - } - ], - "GL_FLOAT": [ - { - "loadFunction": "Load32FTo16F<1>", - "dxgiFormat": "DXGI_FORMAT_R16_FLOAT", - "requiresConversion": "true" - } - ], - "GL_HALF_FLOAT_OES": [ - { - "loadFunction": "LoadToNative", - "dxgiFormat": "DXGI_FORMAT_R16_FLOAT", - "requiresConversion": "false" - } - ] - }, - "GL_RGBA8UI": { - "GL_UNSIGNED_BYTE": [ - { - "loadFunction": "LoadToNative", - "dxgiFormat": "DXGI_FORMAT_R8G8B8A8_UINT", - "requiresConversion": "false" - } - ] - }, - "GL_BGRA4_ANGLEX": { - "GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT": [ - { - "loadFunction": "LoadRGBA4ToRGBA8", - "dxgiFormat": "DXGI_FORMAT_UNKNOWN", - "requiresConversion": "true" - } - ], - "GL_UNSIGNED_BYTE": [ - { - "loadFunction": "LoadToNative", - "dxgiFormat": "DXGI_FORMAT_UNKNOWN", - "requiresConversion": "false" - } - ] - }, - "GL_RGBA16F": { - "GL_HALF_FLOAT": [ - { - "loadFunction": "LoadToNative", - "dxgiFormat": "DXGI_FORMAT_R16G16B16A16_FLOAT", - "requiresConversion": "false" - } - ], - "GL_FLOAT": [ - { - "loadFunction": "Load32FTo16F<4>", - "dxgiFormat": "DXGI_FORMAT_R16G16B16A16_FLOAT", - "requiresConversion": "true" - } - ], - "GL_HALF_FLOAT_OES": [ - { - "loadFunction": "LoadToNative", - "dxgiFormat": "DXGI_FORMAT_R16G16B16A16_FLOAT", - "requiresConversion": "false" - } - ] - }, - "GL_LUMINANCE8_EXT": { - "GL_UNSIGNED_BYTE": [ - { - "loadFunction": "LoadL8ToRGBA8", - "dxgiFormat": "DXGI_FORMAT_UNKNOWN", - "requiresConversion": "true" - } - ] - }, - "GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE": { - "GL_UNSIGNED_BYTE": [ - { - "loadFunction": "LoadCompressedToNative<4,4,16>", - "dxgiFormat": "DXGI_FORMAT_UNKNOWN", - "requiresConversion": "true" - } - ] - }, - "GL_RGB": { - "GL_UNSIGNED_BYTE": [ - { - "loadFunction": "UnreachableLoadFunction", - "dxgiFormat": "DXGI_FORMAT_UNKNOWN", - "requiresConversion": "true" - } - ], - "GL_UNSIGNED_SHORT_5_6_5": [ - { - "loadFunction": "UnreachableLoadFunction", - "dxgiFormat": "DXGI_FORMAT_UNKNOWN", - "requiresConversion": "true" - } - ] - }, - "GL_RGB5_A1": { - "GL_UNSIGNED_INT_2_10_10_10_REV": [ - { - "loadFunction": "LoadRGB10A2ToRGBA8", - "dxgiFormat": "DXGI_FORMAT_R8G8B8A8_UNORM", - "requiresConversion": "true" - } - ], - "GL_UNSIGNED_BYTE": [ - { - "loadFunction": "LoadToNative", - "dxgiFormat": "DXGI_FORMAT_R8G8B8A8_UNORM", - "requiresConversion": "false" - } - ], - "GL_UNSIGNED_SHORT_5_5_5_1": [ - { - "loadFunction": "LoadRGB5A1ToRGBA8", - "dxgiFormat": "DXGI_FORMAT_R8G8B8A8_UNORM", - "requiresConversion": "true" - }, - { - "loadFunction": "LoadRGB5A1ToA1RGB5", - "dxgiFormat": "DXGI_FORMAT_B5G5R5A1_UNORM", - "requiresConversion": "true" - } - ] - }, - "GL_RGB16UI": { - "GL_UNSIGNED_SHORT": [ - { - "loadFunction": "LoadToNative3To4", - "dxgiFormat": "DXGI_FORMAT_R16G16B16A16_UINT", - "requiresConversion": "true" - } - ] - }, - "GL_BGRA_EXT": { - "GL_UNSIGNED_BYTE": [ - { - "loadFunction": "UnreachableLoadFunction", - "dxgiFormat": "DXGI_FORMAT_UNKNOWN", - "requiresConversion": "true" - } - ] - }, - "GL_COMPRESSED_RGB8_ETC2": { - "GL_UNSIGNED_BYTE": [ - { - "loadFunction": "LoadETC2RGB8ToRGBA8", - "dxgiFormat": "DXGI_FORMAT_R8G8B8A8_UNORM", - "requiresConversion": "true" - } - ] - }, - "GL_RGBA32F": { - "GL_FLOAT": [ - { - "loadFunction": "LoadToNative", - "dxgiFormat": "DXGI_FORMAT_R32G32B32A32_FLOAT", - "requiresConversion": "false" - } - ] - }, - "GL_RGBA32I": { - "GL_INT": [ - { - "loadFunction": "LoadToNative", - "dxgiFormat": "DXGI_FORMAT_R32G32B32A32_SINT", - "requiresConversion": "false" - } - ] - }, - "GL_LUMINANCE8_ALPHA8_EXT": { - "GL_UNSIGNED_BYTE": [ - { - "loadFunction": "LoadLA8ToRGBA8", - "dxgiFormat": "DXGI_FORMAT_UNKNOWN", - "requiresConversion": "true" - } - ] - }, - "GL_RG8": { - "GL_UNSIGNED_BYTE": [ - { - "loadFunction": "LoadToNative", - "dxgiFormat": "DXGI_FORMAT_R8G8_UNORM", - "requiresConversion": "false" - } - ] - }, - "GL_RGB10_A2": { - "GL_UNSIGNED_INT_2_10_10_10_REV": [ - { - "loadFunction": "LoadToNative", - "dxgiFormat": "DXGI_FORMAT_R10G10B10A2_UNORM", - "requiresConversion": "false" - } - ] - }, - "GL_COMPRESSED_SIGNED_RG11_EAC": { - "GL_UNSIGNED_BYTE": [ - { - "loadFunction": "LoadEACRG11SToRG8", - "dxgiFormat": "DXGI_FORMAT_R8G8_SNORM", - "requiresConversion": "true" - } - ] - }, - "GL_DEPTH_COMPONENT16": { - "GL_UNSIGNED_INT": [ - { - "loadFunction": "LoadR32ToR16", - "dxgiFormat": "DXGI_FORMAT_R16_TYPELESS", - "requiresConversion": "true" - } - ], - "GL_UNSIGNED_SHORT": [ - { - "loadFunction": "LoadToNative", - "dxgiFormat": "DXGI_FORMAT_R16_TYPELESS", - "requiresConversion": "false" - }, - { - "loadFunction": "LoadToNative", - "dxgiFormat": "DXGI_FORMAT_D16_UNORM", - "requiresConversion": "false" - } - ] - }, - "GL_RGB32I": { - "GL_INT": [ - { - "loadFunction": "LoadToNative3To4", - "dxgiFormat": "DXGI_FORMAT_R32G32B32A32_SINT", - "requiresConversion": "true" - } - ] - }, - "GL_R8": { - "GL_UNSIGNED_BYTE": [ - { - "loadFunction": "LoadToNative", - "dxgiFormat": "DXGI_FORMAT_R8_UNORM", - "requiresConversion": "false" - } - ] - }, - "GL_RGB32F": { - "GL_FLOAT": [ - { - "loadFunction": "LoadToNative3To4", - "dxgiFormat": "DXGI_FORMAT_R32G32B32A32_FLOAT", - "requiresConversion": "true" - } - ] - }, - "GL_R11F_G11F_B10F": { - "GL_UNSIGNED_INT_10F_11F_11F_REV": [ - { - "loadFunction": "LoadToNative", - "dxgiFormat": "DXGI_FORMAT_R11G11B10_FLOAT", - "requiresConversion": "false" - } - ], - "GL_HALF_FLOAT": [ - { - "loadFunction": "LoadRGB16FToRG11B10F", - "dxgiFormat": "DXGI_FORMAT_R11G11B10_FLOAT", - "requiresConversion": "true" - } - ], - "GL_FLOAT": [ - { - "loadFunction": "LoadRGB32FToRG11B10F", - "dxgiFormat": "DXGI_FORMAT_R11G11B10_FLOAT", - "requiresConversion": "true" - } - ], - "GL_HALF_FLOAT_OES": [ - { - "loadFunction": "LoadRGB16FToRG11B10F", - "dxgiFormat": "DXGI_FORMAT_R11G11B10_FLOAT", - "requiresConversion": "true" - } - ] - }, - "GL_RGB8": { - "GL_UNSIGNED_BYTE": [ - { - "loadFunction": "LoadToNative3To4", - "dxgiFormat": "DXGI_FORMAT_R8G8B8A8_UNORM", - "requiresConversion": "true" - } - ] - }, - "GL_LUMINANCE_ALPHA": { - "GL_HALF_FLOAT": [ - { - "loadFunction": "LoadLA16FToRGBA16F", - "dxgiFormat": "DXGI_FORMAT_R16G16B16A16_FLOAT", - "requiresConversion": "true" - } - ], - "GL_UNSIGNED_BYTE": [ - { - "loadFunction": "UnreachableLoadFunction", - "dxgiFormat": "DXGI_FORMAT_UNKNOWN", - "requiresConversion": "true" - } - ], - "GL_FLOAT": [ - { - "loadFunction": "LoadLA32FToRGBA32F", - "dxgiFormat": "DXGI_FORMAT_R32G32B32A32_FLOAT", - "requiresConversion": "true" - } - ], - "GL_HALF_FLOAT_OES": [ - { - "loadFunction": "LoadLA16FToRGBA16F", - "dxgiFormat": "DXGI_FORMAT_R16G16B16A16_FLOAT", - "requiresConversion": "true" - } - ] - }, - "GL_RGBA16I": { - "GL_SHORT": [ - { - "loadFunction": "LoadToNative", - "dxgiFormat": "DXGI_FORMAT_R16G16B16A16_SINT", - "requiresConversion": "false" - } - ] - }, - "GL_R8I": { - "GL_BYTE": [ - { - "loadFunction": "LoadToNative", - "dxgiFormat": "DXGI_FORMAT_R8_SINT", - "requiresConversion": "false" - } - ] - }, - "GL_RGB8_SNORM": { - "GL_BYTE": [ - { - "loadFunction": "LoadToNative3To4", - "dxgiFormat": "DXGI_FORMAT_R8G8B8A8_SNORM", - "requiresConversion": "true" - } - ] - }, - "GL_RG32F": { - "GL_FLOAT": [ - { - "loadFunction": "LoadToNative", - "dxgiFormat": "DXGI_FORMAT_R32G32_FLOAT", - "requiresConversion": "false" - } - ] - }, - "GL_DEPTH_COMPONENT32F": { - "GL_FLOAT": [ - { - "loadFunction": "LoadToNative", - "dxgiFormat": "DXGI_FORMAT_R32_TYPELESS", - "requiresConversion": "false" - }, - { - "loadFunction": "UnimplementedLoadFunction", - "dxgiFormat": "DXGI_FORMAT_UNKNOWN", - "requiresConversion": "true" - } - ] - }, - "GL_RG32I": { - "GL_INT": [ - { - "loadFunction": "LoadToNative", - "dxgiFormat": "DXGI_FORMAT_R32G32_SINT", - "requiresConversion": "false" - } - ] - }, - "GL_ALPHA8_EXT": { - "GL_UNSIGNED_BYTE": [ - { - "loadFunction": "LoadToNative", - "dxgiFormat": "DXGI_FORMAT_A8_UNORM", - "requiresConversion": "false" - }, - { - "loadFunction": "LoadA8ToRGBA8", - "dxgiFormat": "DXGI_FORMAT_R8G8B8A8_UNORM", - "requiresConversion": "true" - } - ] - }, - "GL_RG32UI": { - "GL_UNSIGNED_INT": [ - { - "loadFunction": "LoadToNative", - "dxgiFormat": "DXGI_FORMAT_R32G32_UINT", - "requiresConversion": "false" - } - ] - }, - "GL_RGBA16UI": { - "GL_UNSIGNED_SHORT": [ - { - "loadFunction": "LoadToNative", - "dxgiFormat": "DXGI_FORMAT_R16G16B16A16_UINT", - "requiresConversion": "false" - } - ] - }, - "GL_COMPRESSED_RGBA8_ETC2_EAC": { - "GL_UNSIGNED_BYTE": [ - { - "loadFunction": "LoadETC2RGBA8ToRGBA8", - "dxgiFormat": "DXGI_FORMAT_R8G8B8A8_UNORM", - "requiresConversion": "true" - } - ] - }, - "GL_RGB8I": { - "GL_BYTE": [ - { - "loadFunction": "LoadToNative3To4", - "dxgiFormat": "DXGI_FORMAT_R8G8B8A8_SINT", - "requiresConversion": "true" - } - ] - }, - "GL_COMPRESSED_SRGB8_ETC2": { - "GL_UNSIGNED_BYTE": [ - { - "loadFunction": "LoadETC2SRGB8ToRGBA8", - "dxgiFormat": "DXGI_FORMAT_R8G8B8A8_UNORM_SRGB", - "requiresConversion": "true" - } - ] - }, - "GL_DEPTH32F_STENCIL8": { - "GL_FLOAT_32_UNSIGNED_INT_24_8_REV": [ - { - "loadFunction": "LoadToNative", - "dxgiFormat": "DXGI_FORMAT_R32G8X24_TYPELESS", - "requiresConversion": "false" - }, - { - "loadFunction": "UnimplementedLoadFunction", - "dxgiFormat": "DXGI_FORMAT_UNKNOWN", - "requiresConversion": "true" - } - ] - }, - "GL_RG8I": { - "GL_BYTE": [ - { - "loadFunction": "LoadToNative", - "dxgiFormat": "DXGI_FORMAT_R8G8_SINT", - "requiresConversion": "false" - } - ] - }, - "GL_R32UI": { - "GL_UNSIGNED_INT": [ - { - "loadFunction": "LoadToNative", - "dxgiFormat": "DXGI_FORMAT_R32_UINT", - "requiresConversion": "false" - } - ] - }, - "GL_BGR5_A1_ANGLEX": { - "GL_UNSIGNED_BYTE": [ - { - "loadFunction": "LoadToNative", - "dxgiFormat": "DXGI_FORMAT_UNKNOWN", - "requiresConversion": "false" - } - ], - "GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT": [ - { - "loadFunction": "LoadRGB5A1ToRGBA8", - "dxgiFormat": "DXGI_FORMAT_UNKNOWN", - "requiresConversion": "true" - } - ] - }, - "GL_COMPRESSED_RG11_EAC": { - "GL_UNSIGNED_BYTE": [ - { - "loadFunction": "LoadEACRG11ToRG8", - "dxgiFormat": "DXGI_FORMAT_R8G8_UNORM", - "requiresConversion": "true" - } - ] - }, - "GL_SRGB8_ALPHA8": { - "GL_UNSIGNED_BYTE": [ - { - "loadFunction": "LoadToNative", - "dxgiFormat": "DXGI_FORMAT_R8G8B8A8_UNORM_SRGB", - "requiresConversion": "false" - } - ] - }, - "GL_LUMINANCE_ALPHA16F_EXT": { - "GL_HALF_FLOAT": [ - { - "loadFunction": "LoadLA16FToRGBA16F", - "dxgiFormat": "DXGI_FORMAT_UNKNOWN", - "requiresConversion": "true" - } - ], - "GL_HALF_FLOAT_OES": [ - { - "loadFunction": "LoadLA16FToRGBA16F", - "dxgiFormat": "DXGI_FORMAT_UNKNOWN", - "requiresConversion": "true" - } - ] - }, - "GL_RGBA": { - "GL_UNSIGNED_BYTE": [ - { - "loadFunction": "UnreachableLoadFunction", - "dxgiFormat": "DXGI_FORMAT_UNKNOWN", - "requiresConversion": "true" - } - ], - "GL_UNSIGNED_SHORT_4_4_4_4": [ - { - "loadFunction": "UnreachableLoadFunction", - "dxgiFormat": "DXGI_FORMAT_UNKNOWN", - "requiresConversion": "true" - } - ], - "GL_UNSIGNED_SHORT_5_5_5_1": [ - { - "loadFunction": "UnreachableLoadFunction", - "dxgiFormat": "DXGI_FORMAT_UNKNOWN", - "requiresConversion": "true" - } - ] - }, - "GL_DEPTH24_STENCIL8": { - "GL_UNSIGNED_INT_24_8": [ - { - "loadFunction": "LoadR32ToR24G8", - "dxgiFormat": "DXGI_FORMAT_R24G8_TYPELESS", - "requiresConversion": "true" - }, - { - "loadFunction": "LoadR32ToR24G8", - "dxgiFormat": "DXGI_FORMAT_D24_UNORM_S8_UINT", - "requiresConversion": "true" - } - ] - }, - "GL_RGB16I": { - "GL_SHORT": [ - { - "loadFunction": "LoadToNative3To4", - "dxgiFormat": "DXGI_FORMAT_R16G16B16A16_SINT", - "requiresConversion": "true" - } - ] - }, - "GL_R8UI": { - "GL_UNSIGNED_BYTE": [ - { - "loadFunction": "LoadToNative", - "dxgiFormat": "DXGI_FORMAT_R8_UINT", - "requiresConversion": "false" - } - ] - }, - "GL_ALPHA": { - "GL_HALF_FLOAT": [ - { - "loadFunction": "LoadA16FToRGBA16F", - "dxgiFormat": "DXGI_FORMAT_R16G16B16A16_FLOAT", - "requiresConversion": "true" - } - ], - "GL_UNSIGNED_BYTE": [ - { - "loadFunction": "UnreachableLoadFunction", - "dxgiFormat": "DXGI_FORMAT_UNKNOWN", - "requiresConversion": "true" - } - ], - "GL_FLOAT": [ - { - "loadFunction": "LoadA32FToRGBA32F", - "dxgiFormat": "DXGI_FORMAT_R32G32B32A32_FLOAT", - "requiresConversion": "true" - } - ], - "GL_HALF_FLOAT_OES": [ - { - "loadFunction": "LoadA16FToRGBA16F", - "dxgiFormat": "DXGI_FORMAT_R16G16B16A16_FLOAT", - "requiresConversion": "true" - } - ] - }, - "GL_RGB16F": { - "GL_HALF_FLOAT": [ - { - "loadFunction": "LoadToNative3To4", - "dxgiFormat": "DXGI_FORMAT_R16G16B16A16_FLOAT", - "requiresConversion": "true" - } - ], - "GL_FLOAT": [ - { - "loadFunction": "LoadRGB32FToRGBA16F", - "dxgiFormat": "DXGI_FORMAT_R16G16B16A16_FLOAT", - "requiresConversion": "true" - } - ], - "GL_HALF_FLOAT_OES": [ - { - "loadFunction": "LoadToNative3To4", - "dxgiFormat": "DXGI_FORMAT_R16G16B16A16_FLOAT", - "requiresConversion": "true" - } - ] - }, - "GL_COMPRESSED_SIGNED_R11_EAC": { - "GL_UNSIGNED_BYTE": [ - { - "loadFunction": "LoadEACR11SToR8", - "dxgiFormat": "DXGI_FORMAT_R8_SNORM", - "requiresConversion": "true" - } - ] - }, - "GL_COMPRESSED_RGB_S3TC_DXT1_EXT": { - "GL_UNSIGNED_BYTE": [ - { - "loadFunction": "LoadCompressedToNative<4,4,8>", - "dxgiFormat": "DXGI_FORMAT_UNKNOWN", - "requiresConversion": "true" - } - ] - }, - "GL_COMPRESSED_RGBA_S3TC_DXT1_EXT": { - "GL_UNSIGNED_BYTE": [ - { - "loadFunction": "LoadCompressedToNative<4,4,8>", - "dxgiFormat": "DXGI_FORMAT_UNKNOWN", - "requiresConversion": "true" - } - ] - }, - "GL_STENCIL_INDEX8": { - "DXGI_FORMAT_R24G8_TYPELESS": [ - { - "loadFunction": "UnimplementedLoadFunction", - "dxgiFormat": "DXGI_FORMAT_UNKNOWN", - "requiresConversion": "true" - } - ], - "DXGI_FORMAT_D24_UNORM_S8_UINT": [ - { - "loadFunction": "UnimplementedLoadFunction", - "dxgiFormat": "DXGI_FORMAT_UNKNOWN", - "requiresConversion": "true" - } - ] - }, - "GL_LUMINANCE_ALPHA32F_EXT": { - "GL_FLOAT": [ - { - "loadFunction": "LoadLA32FToRGBA32F", - "dxgiFormat": "DXGI_FORMAT_UNKNOWN", - "requiresConversion": "true" - } - ] - }, - "GL_RGB8UI": { - "GL_UNSIGNED_BYTE": [ - { - "loadFunction": "LoadToNative3To4", - "dxgiFormat": "DXGI_FORMAT_R8G8B8A8_UINT", - "requiresConversion": "true" - } - ] - }, - "GL_DEPTH_COMPONENT24": { - "GL_UNSIGNED_INT": [ - { - "loadFunction": "LoadR32ToR24G8", - "dxgiFormat": "DXGI_FORMAT_R24G8_TYPELESS", - "requiresConversion": "true" - }, - { - "loadFunction": "LoadR32ToR24G8", - "dxgiFormat": "DXGI_FORMAT_D24_UNORM_S8_UINT", - "requiresConversion": "true" - } - ] - }, - "GL_R32I": { - "GL_INT": [ - { - "loadFunction": "LoadToNative", - "dxgiFormat": "DXGI_FORMAT_R32_SINT", - "requiresConversion": "false" - } - ] - }, - "GL_DEPTH_COMPONENT32_OES": { - "GL_UNSIGNED_INT": [ - { - "loadFunction": "LoadR32ToR24G8", - "dxgiFormat": "DXGI_FORMAT_UNKNOWN", - "requiresConversion": "true" - } - ] - }, - "GL_R32F": { - "GL_FLOAT": [ - { - "loadFunction": "LoadToNative", - "dxgiFormat": "DXGI_FORMAT_R32_FLOAT", - "requiresConversion": "false" - } - ] - }, - "GL_RG16F": { - "GL_HALF_FLOAT": [ - { - "loadFunction": "LoadToNative", - "dxgiFormat": "DXGI_FORMAT_R16G16_FLOAT", - "requiresConversion": "false" - } - ], - "GL_FLOAT": [ - { - "loadFunction": "Load32FTo16F<2>", - "dxgiFormat": "DXGI_FORMAT_R16G16_FLOAT", - "requiresConversion": "true" - } - ], - "GL_HALF_FLOAT_OES": [ - { - "loadFunction": "LoadToNative", - "dxgiFormat": "DXGI_FORMAT_R16G16_FLOAT", - "requiresConversion": "false" - } - ] - }, - "GL_RGB565": { - "GL_UNSIGNED_BYTE": [ - { - "loadFunction": "LoadToNative3To4", - "dxgiFormat": "DXGI_FORMAT_R8G8B8A8_UNORM", - "requiresConversion": "true" - } - ], - "GL_UNSIGNED_SHORT_5_6_5": [ - { - "loadFunction": "LoadR5G6B5ToRGBA8", - "dxgiFormat": "DXGI_FORMAT_R8G8B8A8_UNORM", - "requiresConversion": "true" - }, - { - "loadFunction": "LoadToNative", - "dxgiFormat": "DXGI_FORMAT_B5G6R5_UNORM", - "requiresConversion": "false" - } - ] - }, - "GL_LUMINANCE16F_EXT": { - "GL_HALF_FLOAT": [ - { - "loadFunction": "LoadL16FToRGBA16F", - "dxgiFormat": "DXGI_FORMAT_UNKNOWN", - "requiresConversion": "true" - } - ], - "GL_HALF_FLOAT_OES": [ - { - "loadFunction": "LoadL16FToRGBA16F", - "dxgiFormat": "DXGI_FORMAT_UNKNOWN", - "requiresConversion": "true" - } - ] - }, - "GL_RG16UI": { - "GL_UNSIGNED_SHORT": [ - { - "loadFunction": "LoadToNative", - "dxgiFormat": "DXGI_FORMAT_R16G16_UINT", - "requiresConversion": "false" - } - ] - }, - "GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE": { - "GL_UNSIGNED_BYTE": [ - { - "loadFunction": "LoadCompressedToNative<4,4,16>", - "dxgiFormat": "DXGI_FORMAT_UNKNOWN", - "requiresConversion": "true" - } - ] - }, - "GL_RG16I": { - "GL_SHORT": [ - { - "loadFunction": "LoadToNative", - "dxgiFormat": "DXGI_FORMAT_R16G16_SINT", - "requiresConversion": "false" - } - ] - }, - "GL_BGRA8_EXT": { - "GL_UNSIGNED_BYTE": [ - { - "loadFunction": "LoadToNative", - "dxgiFormat": "DXGI_FORMAT_UNKNOWN", - "requiresConversion": "false" - } - ] - }, - "GL_ALPHA16F_EXT": { - "GL_HALF_FLOAT": [ - { - "loadFunction": "LoadA16FToRGBA16F", - "dxgiFormat": "DXGI_FORMAT_UNKNOWN", - "requiresConversion": "true" - } - ], - "GL_HALF_FLOAT_OES": [ - { - "loadFunction": "LoadA16FToRGBA16F", - "dxgiFormat": "DXGI_FORMAT_UNKNOWN", - "requiresConversion": "true" - } - ] - }, - "GL_RGBA4": { - "GL_UNSIGNED_BYTE": [ - { - "loadFunction": "LoadToNative", - "dxgiFormat": "DXGI_FORMAT_R8G8B8A8_UNORM", - "requiresConversion": "false" - } - ], - "GL_UNSIGNED_SHORT_4_4_4_4": [ - { - "loadFunction": "LoadRGBA4ToRGBA8", - "dxgiFormat": "DXGI_FORMAT_R8G8B8A8_UNORM", - "requiresConversion": "true" - }, - { - "loadFunction": "LoadRGBA4ToARGB4", - "dxgiFormat": "DXGI_FORMAT_B4G4R4A4_UNORM", - "requiresConversion": "true" - } - ] - }, - "GL_RGBA8": { - "GL_UNSIGNED_BYTE": [ - { - "loadFunction": "LoadToNative", - "dxgiFormat": "DXGI_FORMAT_R8G8B8A8_UNORM", - "requiresConversion": "false" - } - ] - }, - "GL_LUMINANCE": { - "GL_HALF_FLOAT": [ - { - "loadFunction": "LoadL16FToRGBA16F", - "dxgiFormat": "DXGI_FORMAT_R16G16B16A16_FLOAT", - "requiresConversion": "true" - } - ], - "GL_UNSIGNED_BYTE": [ - { - "loadFunction": "UnreachableLoadFunction", - "dxgiFormat": "DXGI_FORMAT_UNKNOWN", - "requiresConversion": "true" - } - ], - "GL_FLOAT": [ - { - "loadFunction": "LoadL32FToRGBA32F", - "dxgiFormat": "DXGI_FORMAT_R32G32B32A32_FLOAT", - "requiresConversion": "true" - } - ], - "GL_HALF_FLOAT_OES": [ - { - "loadFunction": "LoadL16FToRGBA16F", - "dxgiFormat": "DXGI_FORMAT_R16G16B16A16_FLOAT", - "requiresConversion": "true" - } - ] - }, - "GL_RGB10_A2UI": { - "GL_UNSIGNED_INT_2_10_10_10_REV": [ - { - "loadFunction": "LoadToNative", - "dxgiFormat": "DXGI_FORMAT_R10G10B10A2_UINT", - "requiresConversion": "false" - } - ] - }, - "GL_ETC1_RGB8_OES": { - "GL_UNSIGNED_BYTE": [ - { - "loadFunction": "LoadETC1RGB8ToRGBA8", - "dxgiFormat": "DXGI_FORMAT_R8G8B8A8_UNORM", - "requiresConversion": "true" - } - ] - }, - "GL_ETC1_RGB8_LOSSY_DECODE_ANGLE": { - "GL_UNSIGNED_BYTE": [ - { - "loadFunction": "LoadETC1RGB8ToBC1", - "dxgiFormat": "DXGI_FORMAT_BC1_UNORM", - "requiresConversion": "true" - } - ] - } -} \ No newline at end of file diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/load_functions_table.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/load_functions_table.h deleted file mode 100644 index b17062f68d..0000000000 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/load_functions_table.h +++ /dev/null @@ -1,31 +0,0 @@ -// -// 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. -// -// load_functions_table: -// Contains load functions table depending on internal format and dxgi format -// - -#ifndef LIBANGLE_RENDERER_D3D_D3D11_LOADFUNCTIONSTABLE_H_ -#define LIBANGLE_RENDERER_D3D_D3D11_LOADFUNCTIONSTABLE_H_ - -#include - -#include "libANGLE/renderer/d3d/d3d11/Renderer11.h" -#include "libANGLE/renderer/d3d/d3d11/texture_format_table.h" - -namespace rx -{ - -namespace d3d11 -{ - -const std::map &GetLoadFunctionsMap(GLenum internalFormat, - DXGI_FORMAT dxgiFormat); - -} // namespace d3d11 - -} // namespace rx - -#endif // LIBANGLE_RENDERER_D3D_D3D11_LOADFUNCTIONSTABLE_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/load_functions_table_autogen.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/load_functions_table_autogen.cpp deleted file mode 100644 index acb48b9573..0000000000 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/load_functions_table_autogen.cpp +++ /dev/null @@ -1,2098 +0,0 @@ -// GENERATED FILE - DO NOT EDIT. -// Generated by gen_load_functions_table.py using data from load_functions_data.json -// -// 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. -// -// load_functions_table: -// Contains the GetLoadFunctionsMap for texture_format_util.h -// - -#include "libANGLE/renderer/d3d/d3d11/load_functions_table.h" -#include "libANGLE/renderer/d3d/d3d11/formatutils11.h" -#include "libANGLE/renderer/d3d/d3d11/texture_format_table.h" -#include "libANGLE/renderer/d3d/loadimage.h" -#include "libANGLE/renderer/d3d/loadimage_etc.h" - -namespace rx -{ - -namespace d3d11 -{ - -namespace -{ - -// ES3 image loading functions vary based on: -// - the GL internal format (supplied to glTex*Image*D) -// - the GL data type given (supplied to glTex*Image*D) -// - the target DXGI_FORMAT that the image will be loaded into (which is chosen based on the D3D -// device's capabilities) -// This map type determines which loading function to use, based on these three parameters. -// Source formats and types are taken from Tables 3.2 and 3.3 of the ES 3 spec. -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(); -} - -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(); -} - -} // namespace - -// TODO we can replace these maps with more generated code -const std::map &GetLoadFunctionsMap(GLenum internalFormat, - DXGI_FORMAT dxgiFormat) -{ - // clang-format off - switch (internalFormat) - { - case GL_ALPHA: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_R16G16B16A16_FLOAT: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_HALF_FLOAT] = LoadImageFunctionInfo(LoadA16FToRGBA16F, true); - loadMap[GL_HALF_FLOAT_OES] = LoadImageFunctionInfo(LoadA16FToRGBA16F, true); - loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(UnreachableLoadFunction, true); - return loadMap; - }(); - - return loadFunctionsMap; - } - case DXGI_FORMAT_R32G32B32A32_FLOAT: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_FLOAT] = LoadImageFunctionInfo(LoadA32FToRGBA32F, true); - loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(UnreachableLoadFunction, true); - return loadMap; - }(); - - return loadFunctionsMap; - } - case DXGI_FORMAT_UNKNOWN: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(UnreachableLoadFunction, true); - return loadMap; - }(); - - return loadFunctionsMap; - } - default: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(UnreachableLoadFunction, true); - return loadMap; - }(); - - return loadFunctionsMap; - } - } - } - case GL_ALPHA16F_EXT: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_UNKNOWN: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_HALF_FLOAT] = LoadImageFunctionInfo(LoadA16FToRGBA16F, true); - loadMap[GL_HALF_FLOAT_OES] = LoadImageFunctionInfo(LoadA16FToRGBA16F, true); - return loadMap; - }(); - - return loadFunctionsMap; - } - default: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_HALF_FLOAT] = LoadImageFunctionInfo(LoadA16FToRGBA16F, true); - loadMap[GL_HALF_FLOAT_OES] = LoadImageFunctionInfo(LoadA16FToRGBA16F, true); - return loadMap; - }(); - - return loadFunctionsMap; - } - } - } - case GL_ALPHA32F_EXT: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_UNKNOWN: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_FLOAT] = LoadImageFunctionInfo(LoadA32FToRGBA32F, true); - return loadMap; - }(); - - return loadFunctionsMap; - } - default: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_FLOAT] = LoadImageFunctionInfo(LoadA32FToRGBA32F, true); - return loadMap; - }(); - - return loadFunctionsMap; - } - } - } - case GL_ALPHA8_EXT: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_A8_UNORM: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadToNative, false); - return loadMap; - }(); - - return loadFunctionsMap; - } - case DXGI_FORMAT_R8G8B8A8_UNORM: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadA8ToRGBA8, true); - return loadMap; - }(); - - return loadFunctionsMap; - } - default: - break; - } - } - case GL_BGR5_A1_ANGLEX: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_UNKNOWN: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT] = LoadImageFunctionInfo(LoadRGB5A1ToRGBA8, true); - loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadToNative, false); - return loadMap; - }(); - - return loadFunctionsMap; - } - default: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadToNative, true); - loadMap[GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT] = LoadImageFunctionInfo(LoadRGB5A1ToRGBA8, true); - return loadMap; - }(); - - return loadFunctionsMap; - } - } - } - case GL_BGRA4_ANGLEX: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_UNKNOWN: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT] = LoadImageFunctionInfo(LoadRGBA4ToRGBA8, true); - loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadToNative, false); - return loadMap; - }(); - - return loadFunctionsMap; - } - default: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadToNative, true); - loadMap[GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT] = LoadImageFunctionInfo(LoadRGBA4ToRGBA8, true); - return loadMap; - }(); - - return loadFunctionsMap; - } - } - } - case GL_BGRA8_EXT: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_UNKNOWN: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadToNative, false); - return loadMap; - }(); - - return loadFunctionsMap; - } - default: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadToNative, true); - return loadMap; - }(); - - return loadFunctionsMap; - } - } - } - case GL_BGRA_EXT: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_UNKNOWN: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(UnreachableLoadFunction, true); - return loadMap; - }(); - - return loadFunctionsMap; - } - default: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(UnreachableLoadFunction, true); - return loadMap; - }(); - - return loadFunctionsMap; - } - } - } - case GL_COMPRESSED_R11_EAC: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_R8_UNORM: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadEACR11ToR8, true); - return loadMap; - }(); - - return loadFunctionsMap; - } - default: - break; - } - } - case GL_COMPRESSED_RG11_EAC: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_R8G8_UNORM: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadEACRG11ToRG8, true); - return loadMap; - }(); - - return loadFunctionsMap; - } - default: - break; - } - } - case GL_COMPRESSED_RGB8_ETC2: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_R8G8B8A8_UNORM: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadETC2RGB8ToRGBA8, true); - return loadMap; - }(); - - return loadFunctionsMap; - } - default: - break; - } - } - case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_R8G8B8A8_UNORM: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadETC2RGB8A1ToRGBA8, true); - return loadMap; - }(); - - return loadFunctionsMap; - } - default: - break; - } - } - case GL_COMPRESSED_RGBA8_ETC2_EAC: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_R8G8B8A8_UNORM: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadETC2RGBA8ToRGBA8, true); - return loadMap; - }(); - - return loadFunctionsMap; - } - default: - break; - } - } - case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_UNKNOWN: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadCompressedToNative<4,4,8>, true); - return loadMap; - }(); - - return loadFunctionsMap; - } - default: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadCompressedToNative<4,4,8>, true); - return loadMap; - }(); - - return loadFunctionsMap; - } - } - } - case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_UNKNOWN: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadCompressedToNative<4,4,16>, true); - return loadMap; - }(); - - return loadFunctionsMap; - } - default: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadCompressedToNative<4,4,16>, true); - return loadMap; - }(); - - return loadFunctionsMap; - } - } - } - case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_UNKNOWN: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadCompressedToNative<4,4,16>, true); - return loadMap; - }(); - - return loadFunctionsMap; - } - default: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadCompressedToNative<4,4,16>, true); - return loadMap; - }(); - - return loadFunctionsMap; - } - } - } - case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_UNKNOWN: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadCompressedToNative<4,4,8>, true); - return loadMap; - }(); - - return loadFunctionsMap; - } - default: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadCompressedToNative<4,4,8>, true); - return loadMap; - }(); - - return loadFunctionsMap; - } - } - } - case GL_COMPRESSED_SIGNED_R11_EAC: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_R8_SNORM: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadEACR11SToR8, true); - return loadMap; - }(); - - return loadFunctionsMap; - } - default: - break; - } - } - case GL_COMPRESSED_SIGNED_RG11_EAC: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_R8G8_SNORM: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadEACRG11SToRG8, true); - return loadMap; - }(); - - return loadFunctionsMap; - } - default: - break; - } - } - case GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadETC2SRGBA8ToSRGBA8, true); - return loadMap; - }(); - - return loadFunctionsMap; - } - default: - break; - } - } - case GL_COMPRESSED_SRGB8_ETC2: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadETC2SRGB8ToRGBA8, true); - return loadMap; - }(); - - return loadFunctionsMap; - } - default: - break; - } - } - case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadETC2SRGB8A1ToRGBA8, true); - return loadMap; - }(); - - return loadFunctionsMap; - } - default: - break; - } - } - case GL_DEPTH24_STENCIL8: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_D24_UNORM_S8_UINT: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_UNSIGNED_INT_24_8] = LoadImageFunctionInfo(LoadR32ToR24G8, true); - return loadMap; - }(); - - return loadFunctionsMap; - } - case DXGI_FORMAT_R24G8_TYPELESS: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_UNSIGNED_INT_24_8] = LoadImageFunctionInfo(LoadR32ToR24G8, true); - return loadMap; - }(); - - return loadFunctionsMap; - } - default: - break; - } - } - case GL_DEPTH32F_STENCIL8: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_R32G8X24_TYPELESS: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_FLOAT_32_UNSIGNED_INT_24_8_REV] = LoadImageFunctionInfo(LoadToNative, false); - return loadMap; - }(); - - return loadFunctionsMap; - } - case DXGI_FORMAT_UNKNOWN: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_FLOAT_32_UNSIGNED_INT_24_8_REV] = LoadImageFunctionInfo(UnimplementedLoadFunction, true); - return loadMap; - }(); - - return loadFunctionsMap; - } - default: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_FLOAT_32_UNSIGNED_INT_24_8_REV] = LoadImageFunctionInfo(UnimplementedLoadFunction, true); - return loadMap; - }(); - - return loadFunctionsMap; - } - } - } - case GL_DEPTH_COMPONENT16: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_D16_UNORM: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_UNSIGNED_SHORT] = LoadImageFunctionInfo(LoadToNative, false); - return loadMap; - }(); - - return loadFunctionsMap; - } - case DXGI_FORMAT_R16_TYPELESS: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_UNSIGNED_INT] = LoadImageFunctionInfo(LoadR32ToR16, true); - loadMap[GL_UNSIGNED_SHORT] = LoadImageFunctionInfo(LoadToNative, false); - return loadMap; - }(); - - return loadFunctionsMap; - } - default: - break; - } - } - case GL_DEPTH_COMPONENT24: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_D24_UNORM_S8_UINT: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_UNSIGNED_INT] = LoadImageFunctionInfo(LoadR32ToR24G8, true); - return loadMap; - }(); - - return loadFunctionsMap; - } - case DXGI_FORMAT_R24G8_TYPELESS: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_UNSIGNED_INT] = LoadImageFunctionInfo(LoadR32ToR24G8, true); - return loadMap; - }(); - - return loadFunctionsMap; - } - default: - break; - } - } - case GL_DEPTH_COMPONENT32F: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_R32_TYPELESS: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_FLOAT] = LoadImageFunctionInfo(LoadToNative, false); - return loadMap; - }(); - - return loadFunctionsMap; - } - case DXGI_FORMAT_UNKNOWN: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_FLOAT] = LoadImageFunctionInfo(UnimplementedLoadFunction, true); - return loadMap; - }(); - - return loadFunctionsMap; - } - default: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_FLOAT] = LoadImageFunctionInfo(UnimplementedLoadFunction, true); - return loadMap; - }(); - - return loadFunctionsMap; - } - } - } - case GL_DEPTH_COMPONENT32_OES: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_UNKNOWN: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_UNSIGNED_INT] = LoadImageFunctionInfo(LoadR32ToR24G8, true); - return loadMap; - }(); - - return loadFunctionsMap; - } - default: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_UNSIGNED_INT] = LoadImageFunctionInfo(LoadR32ToR24G8, true); - return loadMap; - }(); - - return loadFunctionsMap; - } - } - } - case GL_ETC1_RGB8_LOSSY_DECODE_ANGLE: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_BC1_UNORM: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadETC1RGB8ToBC1, true); - return loadMap; - }(); - - return loadFunctionsMap; - } - default: - break; - } - } - case GL_ETC1_RGB8_OES: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_R8G8B8A8_UNORM: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadETC1RGB8ToRGBA8, true); - return loadMap; - }(); - - return loadFunctionsMap; - } - default: - break; - } - } - case GL_LUMINANCE: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_R16G16B16A16_FLOAT: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_HALF_FLOAT] = LoadImageFunctionInfo(LoadL16FToRGBA16F, true); - loadMap[GL_HALF_FLOAT_OES] = LoadImageFunctionInfo(LoadL16FToRGBA16F, true); - loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(UnreachableLoadFunction, true); - return loadMap; - }(); - - return loadFunctionsMap; - } - case DXGI_FORMAT_R32G32B32A32_FLOAT: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_FLOAT] = LoadImageFunctionInfo(LoadL32FToRGBA32F, true); - loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(UnreachableLoadFunction, true); - return loadMap; - }(); - - return loadFunctionsMap; - } - case DXGI_FORMAT_UNKNOWN: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(UnreachableLoadFunction, true); - return loadMap; - }(); - - return loadFunctionsMap; - } - default: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(UnreachableLoadFunction, true); - return loadMap; - }(); - - return loadFunctionsMap; - } - } - } - case GL_LUMINANCE16F_EXT: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_UNKNOWN: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_HALF_FLOAT] = LoadImageFunctionInfo(LoadL16FToRGBA16F, true); - loadMap[GL_HALF_FLOAT_OES] = LoadImageFunctionInfo(LoadL16FToRGBA16F, true); - return loadMap; - }(); - - return loadFunctionsMap; - } - default: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_HALF_FLOAT] = LoadImageFunctionInfo(LoadL16FToRGBA16F, true); - loadMap[GL_HALF_FLOAT_OES] = LoadImageFunctionInfo(LoadL16FToRGBA16F, true); - return loadMap; - }(); - - return loadFunctionsMap; - } - } - } - case GL_LUMINANCE32F_EXT: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_UNKNOWN: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_FLOAT] = LoadImageFunctionInfo(LoadL32FToRGBA32F, true); - return loadMap; - }(); - - return loadFunctionsMap; - } - default: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_FLOAT] = LoadImageFunctionInfo(LoadL32FToRGBA32F, true); - return loadMap; - }(); - - return loadFunctionsMap; - } - } - } - case GL_LUMINANCE8_ALPHA8_EXT: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_UNKNOWN: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadLA8ToRGBA8, true); - return loadMap; - }(); - - return loadFunctionsMap; - } - default: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadLA8ToRGBA8, true); - return loadMap; - }(); - - return loadFunctionsMap; - } - } - } - case GL_LUMINANCE8_EXT: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_UNKNOWN: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadL8ToRGBA8, true); - return loadMap; - }(); - - return loadFunctionsMap; - } - default: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadL8ToRGBA8, true); - return loadMap; - }(); - - return loadFunctionsMap; - } - } - } - case GL_LUMINANCE_ALPHA: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_R16G16B16A16_FLOAT: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_HALF_FLOAT] = LoadImageFunctionInfo(LoadLA16FToRGBA16F, true); - loadMap[GL_HALF_FLOAT_OES] = LoadImageFunctionInfo(LoadLA16FToRGBA16F, true); - loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(UnreachableLoadFunction, true); - return loadMap; - }(); - - return loadFunctionsMap; - } - case DXGI_FORMAT_R32G32B32A32_FLOAT: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_FLOAT] = LoadImageFunctionInfo(LoadLA32FToRGBA32F, true); - loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(UnreachableLoadFunction, true); - return loadMap; - }(); - - return loadFunctionsMap; - } - case DXGI_FORMAT_UNKNOWN: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(UnreachableLoadFunction, true); - return loadMap; - }(); - - return loadFunctionsMap; - } - default: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(UnreachableLoadFunction, true); - return loadMap; - }(); - - return loadFunctionsMap; - } - } - } - case GL_LUMINANCE_ALPHA16F_EXT: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_UNKNOWN: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_HALF_FLOAT] = LoadImageFunctionInfo(LoadLA16FToRGBA16F, true); - loadMap[GL_HALF_FLOAT_OES] = LoadImageFunctionInfo(LoadLA16FToRGBA16F, true); - return loadMap; - }(); - - return loadFunctionsMap; - } - default: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_HALF_FLOAT] = LoadImageFunctionInfo(LoadLA16FToRGBA16F, true); - loadMap[GL_HALF_FLOAT_OES] = LoadImageFunctionInfo(LoadLA16FToRGBA16F, true); - return loadMap; - }(); - - return loadFunctionsMap; - } - } - } - case GL_LUMINANCE_ALPHA32F_EXT: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_UNKNOWN: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_FLOAT] = LoadImageFunctionInfo(LoadLA32FToRGBA32F, true); - return loadMap; - }(); - - return loadFunctionsMap; - } - default: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_FLOAT] = LoadImageFunctionInfo(LoadLA32FToRGBA32F, true); - return loadMap; - }(); - - return loadFunctionsMap; - } - } - } - case GL_R11F_G11F_B10F: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_R11G11B10_FLOAT: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_HALF_FLOAT] = LoadImageFunctionInfo(LoadRGB16FToRG11B10F, true); - loadMap[GL_HALF_FLOAT_OES] = LoadImageFunctionInfo(LoadRGB16FToRG11B10F, true); - loadMap[GL_FLOAT] = LoadImageFunctionInfo(LoadRGB32FToRG11B10F, true); - loadMap[GL_UNSIGNED_INT_10F_11F_11F_REV] = LoadImageFunctionInfo(LoadToNative, false); - return loadMap; - }(); - - return loadFunctionsMap; - } - default: - break; - } - } - case GL_R16F: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_R16_FLOAT: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_FLOAT] = LoadImageFunctionInfo(Load32FTo16F<1>, true); - loadMap[GL_HALF_FLOAT] = LoadImageFunctionInfo(LoadToNative, false); - loadMap[GL_HALF_FLOAT_OES] = LoadImageFunctionInfo(LoadToNative, false); - return loadMap; - }(); - - return loadFunctionsMap; - } - default: - break; - } - } - case GL_R16I: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_R16_SINT: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_SHORT] = LoadImageFunctionInfo(LoadToNative, false); - return loadMap; - }(); - - return loadFunctionsMap; - } - default: - break; - } - } - case GL_R16UI: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_R16_UINT: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_UNSIGNED_SHORT] = LoadImageFunctionInfo(LoadToNative, false); - return loadMap; - }(); - - return loadFunctionsMap; - } - default: - break; - } - } - case GL_R32F: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_R32_FLOAT: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_FLOAT] = LoadImageFunctionInfo(LoadToNative, false); - return loadMap; - }(); - - return loadFunctionsMap; - } - default: - break; - } - } - case GL_R32I: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_R32_SINT: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_INT] = LoadImageFunctionInfo(LoadToNative, false); - return loadMap; - }(); - - return loadFunctionsMap; - } - default: - break; - } - } - case GL_R32UI: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_R32_UINT: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_UNSIGNED_INT] = LoadImageFunctionInfo(LoadToNative, false); - return loadMap; - }(); - - return loadFunctionsMap; - } - default: - break; - } - } - case GL_R8: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_R8_UNORM: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadToNative, false); - return loadMap; - }(); - - return loadFunctionsMap; - } - default: - break; - } - } - case GL_R8I: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_R8_SINT: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_BYTE] = LoadImageFunctionInfo(LoadToNative, false); - return loadMap; - }(); - - return loadFunctionsMap; - } - default: - break; - } - } - case GL_R8UI: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_R8_UINT: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadToNative, false); - return loadMap; - }(); - - return loadFunctionsMap; - } - default: - break; - } - } - case GL_R8_SNORM: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_R8_SNORM: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_BYTE] = LoadImageFunctionInfo(LoadToNative, false); - return loadMap; - }(); - - return loadFunctionsMap; - } - default: - break; - } - } - case GL_RG16F: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_R16G16_FLOAT: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_FLOAT] = LoadImageFunctionInfo(Load32FTo16F<2>, true); - loadMap[GL_HALF_FLOAT] = LoadImageFunctionInfo(LoadToNative, false); - loadMap[GL_HALF_FLOAT_OES] = LoadImageFunctionInfo(LoadToNative, false); - return loadMap; - }(); - - return loadFunctionsMap; - } - default: - break; - } - } - case GL_RG16I: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_R16G16_SINT: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_SHORT] = LoadImageFunctionInfo(LoadToNative, false); - return loadMap; - }(); - - return loadFunctionsMap; - } - default: - break; - } - } - case GL_RG16UI: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_R16G16_UINT: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_UNSIGNED_SHORT] = LoadImageFunctionInfo(LoadToNative, false); - return loadMap; - }(); - - return loadFunctionsMap; - } - default: - break; - } - } - case GL_RG32F: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_R32G32_FLOAT: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_FLOAT] = LoadImageFunctionInfo(LoadToNative, false); - return loadMap; - }(); - - return loadFunctionsMap; - } - default: - break; - } - } - case GL_RG32I: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_R32G32_SINT: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_INT] = LoadImageFunctionInfo(LoadToNative, false); - return loadMap; - }(); - - return loadFunctionsMap; - } - default: - break; - } - } - case GL_RG32UI: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_R32G32_UINT: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_UNSIGNED_INT] = LoadImageFunctionInfo(LoadToNative, false); - return loadMap; - }(); - - return loadFunctionsMap; - } - default: - break; - } - } - case GL_RG8: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_R8G8_UNORM: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadToNative, false); - return loadMap; - }(); - - return loadFunctionsMap; - } - default: - break; - } - } - case GL_RG8I: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_R8G8_SINT: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_BYTE] = LoadImageFunctionInfo(LoadToNative, false); - return loadMap; - }(); - - return loadFunctionsMap; - } - default: - break; - } - } - case GL_RG8UI: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_R8G8_UINT: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadToNative, false); - return loadMap; - }(); - - return loadFunctionsMap; - } - default: - break; - } - } - case GL_RG8_SNORM: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_R8G8_SNORM: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_BYTE] = LoadImageFunctionInfo(LoadToNative, false); - return loadMap; - }(); - - return loadFunctionsMap; - } - default: - break; - } - } - case GL_RGB: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_UNKNOWN: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(UnreachableLoadFunction, true); - loadMap[GL_UNSIGNED_SHORT_5_6_5] = LoadImageFunctionInfo(UnreachableLoadFunction, true); - return loadMap; - }(); - - return loadFunctionsMap; - } - default: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(UnreachableLoadFunction, true); - loadMap[GL_UNSIGNED_SHORT_5_6_5] = LoadImageFunctionInfo(UnreachableLoadFunction, true); - return loadMap; - }(); - - return loadFunctionsMap; - } - } - } - case GL_RGB10_A2: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_R10G10B10A2_UNORM: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_UNSIGNED_INT_2_10_10_10_REV] = LoadImageFunctionInfo(LoadToNative, false); - return loadMap; - }(); - - return loadFunctionsMap; - } - default: - break; - } - } - case GL_RGB10_A2UI: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_R10G10B10A2_UINT: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_UNSIGNED_INT_2_10_10_10_REV] = LoadImageFunctionInfo(LoadToNative, false); - return loadMap; - }(); - - return loadFunctionsMap; - } - default: - break; - } - } - case GL_RGB16F: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_R16G16B16A16_FLOAT: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_FLOAT] = LoadImageFunctionInfo(LoadRGB32FToRGBA16F, true); - loadMap[GL_HALF_FLOAT] = LoadImageFunctionInfo(LoadToNative3To4, true); - loadMap[GL_HALF_FLOAT_OES] = LoadImageFunctionInfo(LoadToNative3To4, true); - return loadMap; - }(); - - return loadFunctionsMap; - } - default: - break; - } - } - case GL_RGB16I: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_R16G16B16A16_SINT: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_SHORT] = LoadImageFunctionInfo(LoadToNative3To4, true); - return loadMap; - }(); - - return loadFunctionsMap; - } - default: - break; - } - } - case GL_RGB16UI: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_R16G16B16A16_UINT: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_UNSIGNED_SHORT] = LoadImageFunctionInfo(LoadToNative3To4, true); - return loadMap; - }(); - - return loadFunctionsMap; - } - default: - break; - } - } - case GL_RGB32F: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_R32G32B32A32_FLOAT: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_FLOAT] = LoadImageFunctionInfo(LoadToNative3To4, true); - return loadMap; - }(); - - return loadFunctionsMap; - } - default: - break; - } - } - case GL_RGB32I: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_R32G32B32A32_SINT: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_INT] = LoadImageFunctionInfo(LoadToNative3To4, true); - return loadMap; - }(); - - return loadFunctionsMap; - } - default: - break; - } - } - case GL_RGB32UI: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_R32G32B32A32_UINT: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_UNSIGNED_INT] = LoadImageFunctionInfo(LoadToNative3To4, true); - return loadMap; - }(); - - return loadFunctionsMap; - } - default: - break; - } - } - case GL_RGB565: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_B5G6R5_UNORM: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_UNSIGNED_SHORT_5_6_5] = LoadImageFunctionInfo(LoadToNative, false); - return loadMap; - }(); - - return loadFunctionsMap; - } - case DXGI_FORMAT_R8G8B8A8_UNORM: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_UNSIGNED_SHORT_5_6_5] = LoadImageFunctionInfo(LoadR5G6B5ToRGBA8, true); - loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadToNative3To4, true); - return loadMap; - }(); - - return loadFunctionsMap; - } - default: - break; - } - } - case GL_RGB5_A1: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_B5G5R5A1_UNORM: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_UNSIGNED_SHORT_5_5_5_1] = LoadImageFunctionInfo(LoadRGB5A1ToA1RGB5, true); - return loadMap; - }(); - - return loadFunctionsMap; - } - case DXGI_FORMAT_R8G8B8A8_UNORM: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_UNSIGNED_INT_2_10_10_10_REV] = LoadImageFunctionInfo(LoadRGB10A2ToRGBA8, true); - loadMap[GL_UNSIGNED_SHORT_5_5_5_1] = LoadImageFunctionInfo(LoadRGB5A1ToRGBA8, true); - loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadToNative, false); - return loadMap; - }(); - - return loadFunctionsMap; - } - default: - break; - } - } - case GL_RGB8: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_R8G8B8A8_UNORM: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadToNative3To4, true); - return loadMap; - }(); - - return loadFunctionsMap; - } - default: - break; - } - } - case GL_RGB8I: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_R8G8B8A8_SINT: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_BYTE] = LoadImageFunctionInfo(LoadToNative3To4, true); - return loadMap; - }(); - - return loadFunctionsMap; - } - default: - break; - } - } - case GL_RGB8UI: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_R8G8B8A8_UINT: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadToNative3To4, true); - return loadMap; - }(); - - return loadFunctionsMap; - } - default: - break; - } - } - case GL_RGB8_SNORM: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_R8G8B8A8_SNORM: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_BYTE] = LoadImageFunctionInfo(LoadToNative3To4, true); - return loadMap; - }(); - - return loadFunctionsMap; - } - default: - break; - } - } - case GL_RGB9_E5: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_R9G9B9E5_SHAREDEXP: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_HALF_FLOAT] = LoadImageFunctionInfo(LoadRGB16FToRGB9E5, true); - loadMap[GL_HALF_FLOAT_OES] = LoadImageFunctionInfo(LoadRGB16FToRGB9E5, true); - loadMap[GL_FLOAT] = LoadImageFunctionInfo(LoadRGB32FToRGB9E5, true); - loadMap[GL_UNSIGNED_INT_5_9_9_9_REV] = LoadImageFunctionInfo(LoadToNative, false); - return loadMap; - }(); - - return loadFunctionsMap; - } - default: - break; - } - } - case GL_RGBA: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_UNKNOWN: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(UnreachableLoadFunction, true); - loadMap[GL_UNSIGNED_SHORT_4_4_4_4] = LoadImageFunctionInfo(UnreachableLoadFunction, true); - loadMap[GL_UNSIGNED_SHORT_5_5_5_1] = LoadImageFunctionInfo(UnreachableLoadFunction, true); - return loadMap; - }(); - - return loadFunctionsMap; - } - default: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(UnreachableLoadFunction, true); - loadMap[GL_UNSIGNED_SHORT_4_4_4_4] = LoadImageFunctionInfo(UnreachableLoadFunction, true); - loadMap[GL_UNSIGNED_SHORT_5_5_5_1] = LoadImageFunctionInfo(UnreachableLoadFunction, true); - return loadMap; - }(); - - return loadFunctionsMap; - } - } - } - case GL_RGBA16F: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_R16G16B16A16_FLOAT: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_FLOAT] = LoadImageFunctionInfo(Load32FTo16F<4>, true); - loadMap[GL_HALF_FLOAT] = LoadImageFunctionInfo(LoadToNative, false); - loadMap[GL_HALF_FLOAT_OES] = LoadImageFunctionInfo(LoadToNative, false); - return loadMap; - }(); - - return loadFunctionsMap; - } - default: - break; - } - } - case GL_RGBA16I: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_R16G16B16A16_SINT: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_SHORT] = LoadImageFunctionInfo(LoadToNative, false); - return loadMap; - }(); - - return loadFunctionsMap; - } - default: - break; - } - } - case GL_RGBA16UI: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_R16G16B16A16_UINT: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_UNSIGNED_SHORT] = LoadImageFunctionInfo(LoadToNative, false); - return loadMap; - }(); - - return loadFunctionsMap; - } - default: - break; - } - } - case GL_RGBA32F: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_R32G32B32A32_FLOAT: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_FLOAT] = LoadImageFunctionInfo(LoadToNative, false); - return loadMap; - }(); - - return loadFunctionsMap; - } - default: - break; - } - } - case GL_RGBA32I: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_R32G32B32A32_SINT: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_INT] = LoadImageFunctionInfo(LoadToNative, false); - return loadMap; - }(); - - return loadFunctionsMap; - } - default: - break; - } - } - case GL_RGBA32UI: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_R32G32B32A32_UINT: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_UNSIGNED_INT] = LoadImageFunctionInfo(LoadToNative, false); - return loadMap; - }(); - - return loadFunctionsMap; - } - default: - break; - } - } - case GL_RGBA4: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_B4G4R4A4_UNORM: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_UNSIGNED_SHORT_4_4_4_4] = LoadImageFunctionInfo(LoadRGBA4ToARGB4, true); - return loadMap; - }(); - - return loadFunctionsMap; - } - case DXGI_FORMAT_R8G8B8A8_UNORM: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_UNSIGNED_SHORT_4_4_4_4] = LoadImageFunctionInfo(LoadRGBA4ToRGBA8, true); - loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadToNative, false); - return loadMap; - }(); - - return loadFunctionsMap; - } - default: - break; - } - } - case GL_RGBA8: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_R8G8B8A8_UNORM: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadToNative, false); - return loadMap; - }(); - - return loadFunctionsMap; - } - default: - break; - } - } - case GL_RGBA8I: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_R8G8B8A8_SINT: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_BYTE] = LoadImageFunctionInfo(LoadToNative, false); - return loadMap; - }(); - - return loadFunctionsMap; - } - default: - break; - } - } - case GL_RGBA8UI: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_R8G8B8A8_UINT: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadToNative, false); - return loadMap; - }(); - - return loadFunctionsMap; - } - default: - break; - } - } - case GL_RGBA8_SNORM: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_R8G8B8A8_SNORM: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_BYTE] = LoadImageFunctionInfo(LoadToNative, false); - return loadMap; - }(); - - return loadFunctionsMap; - } - default: - break; - } - } - case GL_SRGB8: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadToNative3To4, true); - return loadMap; - }(); - - return loadFunctionsMap; - } - default: - break; - } - } - case GL_SRGB8_ALPHA8: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadToNative, false); - return loadMap; - }(); - - return loadFunctionsMap; - } - default: - break; - } - } - case GL_STENCIL_INDEX8: - { - switch (dxgiFormat) - { - case DXGI_FORMAT_UNKNOWN: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[DXGI_FORMAT_D24_UNORM_S8_UINT] = LoadImageFunctionInfo(UnimplementedLoadFunction, true); - loadMap[DXGI_FORMAT_R24G8_TYPELESS] = LoadImageFunctionInfo(UnimplementedLoadFunction, true); - return loadMap; - }(); - - return loadFunctionsMap; - } - default: - { - static const std::map loadFunctionsMap = []() { - std::map loadMap; - loadMap[DXGI_FORMAT_D24_UNORM_S8_UINT] = LoadImageFunctionInfo(UnimplementedLoadFunction, true); - loadMap[DXGI_FORMAT_R24G8_TYPELESS] = LoadImageFunctionInfo(UnimplementedLoadFunction, true); - return loadMap; - }(); - - return loadFunctionsMap; - } - } - } - - default: - { - static std::map emptyLoadFunctionsMap; - return emptyLoadFunctionsMap; - } - } - // clang-format on - -} // GetLoadFunctionsMap - -} // namespace d3d11 - -} // namespace rx 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 index a1175db9af..d059b36120 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.cpp @@ -12,369 +12,414 @@ #include #include "common/debug.h" -#include "libANGLE/formatutils.h" +#include "libANGLE/Buffer.h" +#include "libANGLE/Context.h" #include "libANGLE/Framebuffer.h" #include "libANGLE/Program.h" +#include "libANGLE/State.h" +#include "libANGLE/VertexArray.h" +#include "libANGLE/formatutils.h" +#include "libANGLE/renderer/d3d/BufferD3D.h" +#include "libANGLE/renderer/d3d/FramebufferD3D.h" +#include "libANGLE/renderer/d3d/IndexBuffer.h" +#include "libANGLE/renderer/d3d/d3d11/RenderTarget11.h" +#include "libANGLE/renderer/d3d/d3d11/Renderer11.h" #include "libANGLE/renderer/d3d/d3d11/dxgi_support_table.h" #include "libANGLE/renderer/d3d/d3d11/formatutils11.h" -#include "libANGLE/renderer/d3d/d3d11/Renderer11.h" -#include "libANGLE/renderer/d3d/d3d11/RenderTarget11.h" #include "libANGLE/renderer/d3d/d3d11/texture_format_table.h" -#include "libANGLE/renderer/d3d/FramebufferD3D.h" -#include "libANGLE/renderer/d3d/WorkaroundsD3D.h" - -#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 +#include "libANGLE/renderer/driver_utils.h" +#include "platform/Platform.h" +#include "platform/WorkaroundsD3D.h" namespace rx { -namespace gl_d3d11 +namespace d3d11_gl { - -D3D11_BLEND ConvertBlendFunc(GLenum glBlend, bool isAlpha) +namespace { - D3D11_BLEND d3dBlend = D3D11_BLEND_ZERO; +// Standard D3D sample positions from +// https://msdn.microsoft.com/en-us/library/windows/desktop/ff476218.aspx +using SamplePositionsArray = std::array; +static constexpr std::array kSamplePositions = { + {{{0.5f, 0.5f}}, + {{0.75f, 0.75f, 0.25f, 0.25f}}, + {{0.375f, 0.125f, 0.875f, 0.375f, 0.125f, 0.625f, 0.625f, 0.875f}}, + {{0.5625f, 0.3125f, 0.4375f, 0.6875f, 0.8125f, 0.5625f, 0.3125f, 0.1875f, 0.1875f, 0.8125f, + 0.0625f, 0.4375f, 0.6875f, 0.9375f, 0.9375f, 0.0625f}}, + {{0.5625f, 0.5625f, 0.4375f, 0.3125f, 0.3125f, 0.625f, 0.75f, 0.4375f, + 0.1875f, 0.375f, 0.625f, 0.8125f, 0.8125f, 0.6875f, 0.6875f, 0.1875f, + 0.375f, 0.875f, 0.5f, 0.0625f, 0.25f, 0.125f, 0.125f, 0.75f, + 0.0f, 0.5f, 0.9375f, 0.25f, 0.875f, 0.9375f, 0.0625f, 0.0f}}}}; - switch (glBlend) +// Helper functor for querying DXGI support. Saves passing the parameters repeatedly. +class DXGISupportHelper : angle::NonCopyable +{ + public: + DXGISupportHelper(ID3D11Device *device, D3D_FEATURE_LEVEL featureLevel) + : mDevice(device), mFeatureLevel(featureLevel) { - 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; -} + bool query(DXGI_FORMAT dxgiFormat, UINT supportMask) + { + if (dxgiFormat == DXGI_FORMAT_UNKNOWN) + return false; -D3D11_BLEND_OP ConvertBlendOp(GLenum glBlendOp) -{ - D3D11_BLEND_OP d3dBlendOp = D3D11_BLEND_OP_ADD; + auto dxgiSupport = d3d11::GetDXGISupport(dxgiFormat, mFeatureLevel); - 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(); + UINT supportedBits = dxgiSupport.alwaysSupportedFlags; + + if ((dxgiSupport.optionallySupportedFlags & supportMask) != 0) + { + UINT formatSupport; + if (SUCCEEDED(mDevice->CheckFormatSupport(dxgiFormat, &formatSupport))) + { + supportedBits |= (formatSupport & supportMask); + } + else + { + // TODO(jmadill): find out why we fail this call sometimes in FL9_3 + // ERR() << "Error checking format support for format 0x" << std::hex << dxgiFormat; + } + } + + return ((supportedBits & supportMask) == supportMask); } - return d3dBlendOp; -} + private: + ID3D11Device *mDevice; + D3D_FEATURE_LEVEL mFeatureLevel; +}; -UINT8 ConvertColorMask(bool red, bool green, bool blue, bool alpha) +gl::TextureCaps GenerateTextureFormatCaps(gl::Version maxClientVersion, + GLenum internalFormat, + ID3D11Device *device, + const Renderer11DeviceCaps &renderer11DeviceCaps) { - UINT8 mask = 0; - if (red) + gl::TextureCaps textureCaps; + + DXGISupportHelper support(device, renderer11DeviceCaps.featureLevel); + const d3d11::Format &formatInfo = d3d11::Format::Get(internalFormat, renderer11DeviceCaps); + + const gl::InternalFormat &internalFormatInfo = gl::GetSizedInternalFormatInfo(internalFormat); + + UINT texSupportMask = D3D11_FORMAT_SUPPORT_TEXTURE2D; + if (internalFormatInfo.depthBits == 0 && internalFormatInfo.stencilBits == 0) { - mask |= D3D11_COLOR_WRITE_ENABLE_RED; + texSupportMask |= D3D11_FORMAT_SUPPORT_TEXTURECUBE; + if (maxClientVersion.major > 2) + { + texSupportMask |= D3D11_FORMAT_SUPPORT_TEXTURE3D; + } } - if (green) + + textureCaps.texturable = support.query(formatInfo.texFormat, texSupportMask); + textureCaps.filterable = + support.query(formatInfo.srvFormat, D3D11_FORMAT_SUPPORT_SHADER_SAMPLE); + textureCaps.renderable = + (support.query(formatInfo.rtvFormat, D3D11_FORMAT_SUPPORT_RENDER_TARGET)) || + (support.query(formatInfo.dsvFormat, D3D11_FORMAT_SUPPORT_DEPTH_STENCIL)); + + DXGI_FORMAT renderFormat = DXGI_FORMAT_UNKNOWN; + if (formatInfo.dsvFormat != DXGI_FORMAT_UNKNOWN) { - mask |= D3D11_COLOR_WRITE_ENABLE_GREEN; + renderFormat = formatInfo.dsvFormat; } - if (blue) + else if (formatInfo.rtvFormat != DXGI_FORMAT_UNKNOWN) { - mask |= D3D11_COLOR_WRITE_ENABLE_BLUE; + renderFormat = formatInfo.rtvFormat; } - if (alpha) + if (renderFormat != DXGI_FORMAT_UNKNOWN && + support.query(renderFormat, D3D11_FORMAT_SUPPORT_MULTISAMPLE_RENDERTARGET)) { - mask |= D3D11_COLOR_WRITE_ENABLE_ALPHA; - } - return mask; -} - -D3D11_CULL_MODE ConvertCullMode(bool cullEnabled, GLenum cullMode) -{ - D3D11_CULL_MODE cull = D3D11_CULL_NONE; + // Assume 1x + textureCaps.sampleCounts.insert(1); - if (cullEnabled) - { - switch (cullMode) + for (unsigned int sampleCount = 2; sampleCount <= D3D11_MAX_MULTISAMPLE_SAMPLE_COUNT; + sampleCount *= 2) { - 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(); + UINT qualityCount = 0; + if (SUCCEEDED(device->CheckMultisampleQualityLevels(renderFormat, sampleCount, + &qualityCount))) + { + // Assume we always support lower sample counts + if (qualityCount == 0) + { + break; + } + textureCaps.sampleCounts.insert(sampleCount); + } } } - else - { - cull = D3D11_CULL_NONE; - } - return cull; + return textureCaps; } -D3D11_COMPARISON_FUNC ConvertComparison(GLenum comparison) +bool GetNPOTTextureSupport(D3D_FEATURE_LEVEL featureLevel) { - D3D11_COMPARISON_FUNC d3dComp = D3D11_COMPARISON_NEVER; - switch (comparison) + switch (featureLevel) { - 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(); - } + case D3D_FEATURE_LEVEL_11_1: + case D3D_FEATURE_LEVEL_11_0: + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: + return true; - return d3dComp; + // 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; + } } -D3D11_DEPTH_WRITE_MASK ConvertDepthMask(bool depthWriteEnabled) +float GetMaximumAnisotropy(D3D_FEATURE_LEVEL featureLevel) { - return depthWriteEnabled ? D3D11_DEPTH_WRITE_MASK_ALL : D3D11_DEPTH_WRITE_MASK_ZERO; + switch (featureLevel) + { + case D3D_FEATURE_LEVEL_11_1: + 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; + } } -UINT8 ConvertStencilMask(GLuint stencilmask) +bool GetOcclusionQuerySupport(D3D_FEATURE_LEVEL featureLevel) { - return static_cast(stencilmask); + switch (featureLevel) + { + case D3D_FEATURE_LEVEL_11_1: + 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; + } } -D3D11_STENCIL_OP ConvertStencilOp(GLenum stencilOp) +bool GetEventQuerySupport(D3D_FEATURE_LEVEL featureLevel) { - D3D11_STENCIL_OP d3dStencilOp = D3D11_STENCIL_OP_KEEP; + // From http://msdn.microsoft.com/en-us/library/windows/desktop/ff476150.aspx + // ID3D11Device::CreateQuery - switch (stencilOp) + switch (featureLevel) { - 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(); - } + case D3D_FEATURE_LEVEL_11_1: + 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; - return d3dStencilOp; + default: + UNREACHABLE(); + return false; + } } -D3D11_FILTER ConvertFilter(GLenum minFilter, GLenum magFilter, float maxAnisotropy, GLenum comparisonMode) +bool GetInstancingSupport(D3D_FEATURE_LEVEL featureLevel) { - bool comparison = comparisonMode != GL_NONE; + // From http://msdn.microsoft.com/en-us/library/windows/desktop/ff476150.aspx + // ID3D11Device::CreateInputLayout - if (maxAnisotropy > 1.0f) - { - return D3D11_ENCODE_ANISOTROPIC_FILTER(static_cast(comparison)); - } - else + switch (featureLevel) { - 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(); - } + case D3D_FEATURE_LEVEL_11_1: + 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; - 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(); - } + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: + return false; - return D3D11_ENCODE_BASIC_FILTER(dxMin, dxMag, dxMip, static_cast(comparison)); + default: + UNREACHABLE(); + return false; } } -D3D11_TEXTURE_ADDRESS_MODE ConvertTextureWrap(GLenum wrap) +bool GetFramebufferMultisampleSupport(D3D_FEATURE_LEVEL featureLevel) { - switch (wrap) + switch (featureLevel) { - 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(); - } + case D3D_FEATURE_LEVEL_11_1: + case D3D_FEATURE_LEVEL_11_0: + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: + return true; - return D3D11_TEXTURE_ADDRESS_WRAP; + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: + return false; + + default: + UNREACHABLE(); + return false; + } } -D3D11_QUERY ConvertQueryType(GLenum queryType) +bool GetFramebufferBlitSupport(D3D_FEATURE_LEVEL featureLevel) { - switch (queryType) + switch (featureLevel) { - 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; - case GL_TIME_ELAPSED_EXT: - // Two internal queries are also created for begin/end timestamps - return D3D11_QUERY_TIMESTAMP_DISJOINT; - default: UNREACHABLE(); return D3D11_QUERY_EVENT; + case D3D_FEATURE_LEVEL_11_1: + 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; } } -} // namespace gl_d3d11 - -namespace d3d11_gl +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). -namespace -{ + // http://msdn.microsoft.com/en-us/library/windows/desktop/ff476876.aspx states that + // feature level + // 9.3 supports shader model ps_2_x. -// Helper functor for querying DXGI support. Saves passing the parameters repeatedly. -class DXGISupportHelper : angle::NonCopyable -{ - public: - DXGISupportHelper(ID3D11Device *device, D3D_FEATURE_LEVEL featureLevel) - : mDevice(device), - mFeatureLevel(featureLevel) + switch (featureLevel) { + case D3D_FEATURE_LEVEL_11_1: + 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; } +} - bool query(DXGI_FORMAT dxgiFormat, UINT supportMask) +bool GetShaderTextureLODSupport(D3D_FEATURE_LEVEL featureLevel) +{ + switch (featureLevel) { - if (dxgiFormat == DXGI_FORMAT_UNKNOWN) + case D3D_FEATURE_LEVEL_11_1: + 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; - auto dxgiSupport = d3d11::GetDXGISupport(dxgiFormat, mFeatureLevel); + default: + UNREACHABLE(); + return false; + } +} - UINT supportedBits = dxgiSupport.alwaysSupportedFlags; +size_t GetMaximumSimultaneousRenderTargets(D3D_FEATURE_LEVEL featureLevel) +{ + // From http://msdn.microsoft.com/en-us/library/windows/desktop/ff476150.aspx + // ID3D11Device::CreateInputLayout - if ((dxgiSupport.optionallySupportedFlags & supportMask) != 0) - { - UINT formatSupport; - if (SUCCEEDED(mDevice->CheckFormatSupport(dxgiFormat, &formatSupport))) - { - supportedBits |= (formatSupport & supportMask); - } - else - { - // TODO(jmadill): find out why we fail this call sometimes in FL9_3 - // ERR("Error checking format support for format 0x%x", dxgiFormat); - } - } + switch (featureLevel) + { + case D3D_FEATURE_LEVEL_11_1: + case D3D_FEATURE_LEVEL_11_0: + return D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; - return ((supportedBits & supportMask) == supportMask); - } + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: + return D3D10_SIMULTANEOUS_RENDER_TARGET_COUNT; - private: - ID3D11Device *mDevice; - D3D_FEATURE_LEVEL mFeatureLevel; -}; + 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; -} // anonymous namespace + default: + UNREACHABLE(); + return 0; + } +} -unsigned int GetReservedVertexUniformVectors(D3D_FEATURE_LEVEL featureLevel) +size_t GetMaximum2DTextureSize(D3D_FEATURE_LEVEL featureLevel) { switch (featureLevel) { case D3D_FEATURE_LEVEL_11_1: 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 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 3; // dx_ViewAdjust, dx_ViewCoords and dx_ViewScale + return D3D_FL9_1_REQ_TEXTURE2D_U_OR_V_DIMENSION; default: UNREACHABLE(); @@ -382,20 +427,23 @@ unsigned int GetReservedVertexUniformVectors(D3D_FEATURE_LEVEL featureLevel) } } -unsigned int GetReservedFragmentUniformVectors(D3D_FEATURE_LEVEL featureLevel) +size_t GetMaximumCubeMapTextureSize(D3D_FEATURE_LEVEL featureLevel) { switch (featureLevel) { case D3D_FEATURE_LEVEL_11_1: case D3D_FEATURE_LEVEL_11_0: + return D3D11_REQ_TEXTURECUBE_DIMENSION; + case D3D_FEATURE_LEVEL_10_1: case D3D_FEATURE_LEVEL_10_0: - return 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 3; + return D3D_FL9_1_REQ_TEXTURECUBE_DIMENSION; default: UNREACHABLE(); @@ -403,757 +451,829 @@ unsigned int GetReservedFragmentUniformVectors(D3D_FEATURE_LEVEL featureLevel) } } -GLint GetMaximumClientVersion(D3D_FEATURE_LEVEL featureLevel) +size_t GetMaximum2DTextureArraySize(D3D_FEATURE_LEVEL featureLevel) { switch (featureLevel) { - case D3D_FEATURE_LEVEL_11_1: - case D3D_FEATURE_LEVEL_11_0: - case D3D_FEATURE_LEVEL_10_1: - case D3D_FEATURE_LEVEL_10_0: return 3; + case D3D_FEATURE_LEVEL_11_1: + case D3D_FEATURE_LEVEL_11_0: + return D3D11_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION; - case D3D_FEATURE_LEVEL_9_3: - case D3D_FEATURE_LEVEL_9_2: - case D3D_FEATURE_LEVEL_9_1: return 2; + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: + return D3D10_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION; - default: UNREACHABLE(); return 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 gl::TextureCaps GenerateTextureFormatCaps(GLint maxClientVersion, GLenum internalFormat, ID3D11Device *device, const Renderer11DeviceCaps &renderer11DeviceCaps) +size_t GetMaximum3DTextureSize(D3D_FEATURE_LEVEL featureLevel) { - gl::TextureCaps textureCaps; + switch (featureLevel) + { + case D3D_FEATURE_LEVEL_11_1: + case D3D_FEATURE_LEVEL_11_0: + return D3D11_REQ_TEXTURE3D_U_V_OR_W_DIMENSION; - DXGISupportHelper support(device, renderer11DeviceCaps.featureLevel); - const d3d11::TextureFormat &formatInfo = - d3d11::GetTextureFormatInfo(internalFormat, renderer11DeviceCaps); + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: + return D3D10_REQ_TEXTURE3D_U_V_OR_W_DIMENSION; - const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(internalFormat); + 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; - UINT texSupportMask = D3D11_FORMAT_SUPPORT_TEXTURE2D; - if (internalFormatInfo.depthBits == 0 && internalFormatInfo.stencilBits == 0) + default: + UNREACHABLE(); + return 0; + } +} + +size_t GetMaximumViewportSize(D3D_FEATURE_LEVEL featureLevel) +{ + switch (featureLevel) { - texSupportMask |= D3D11_FORMAT_SUPPORT_TEXTURECUBE; - if (maxClientVersion > 2) - { - texSupportMask |= D3D11_FORMAT_SUPPORT_TEXTURE3D; - } + case D3D_FEATURE_LEVEL_11_1: + 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; } +} - textureCaps.texturable = support.query(formatInfo.texFormat, texSupportMask); - textureCaps.filterable = support.query(formatInfo.srvFormat, D3D11_FORMAT_SUPPORT_SHADER_SAMPLE); - textureCaps.renderable = (support.query(formatInfo.rtvFormat, D3D11_FORMAT_SUPPORT_RENDER_TARGET)) || - (support.query(formatInfo.dsvFormat, D3D11_FORMAT_SUPPORT_DEPTH_STENCIL)); +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."); - if (support.query(formatInfo.renderFormat, D3D11_FORMAT_SUPPORT_MULTISAMPLE_RENDERTARGET)) + switch (featureLevel) { - // Assume 1x - textureCaps.sampleCounts.insert(1); + case D3D_FEATURE_LEVEL_11_1: + case D3D_FEATURE_LEVEL_11_0: + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: + return std::numeric_limits::max(); - for (unsigned int sampleCount = 2; sampleCount <= D3D11_MAX_MULTISAMPLE_SAMPLE_COUNT; - sampleCount *= 2) - { - UINT qualityCount = 0; - if (SUCCEEDED(device->CheckMultisampleQualityLevels(formatInfo.renderFormat, sampleCount, &qualityCount))) - { - // Assume we always support lower sample counts - if (qualityCount == 0) - { - break; - } - textureCaps.sampleCounts.insert(sampleCount); - } - } - } + 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; - return textureCaps; + default: + UNREACHABLE(); + return 0; + } } -static bool GetNPOTTextureSupport(D3D_FEATURE_LEVEL featureLevel) +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) { - case D3D_FEATURE_LEVEL_11_1: - case D3D_FEATURE_LEVEL_11_0: - case D3D_FEATURE_LEVEL_10_1: - case D3D_FEATURE_LEVEL_10_0: return true; + case D3D_FEATURE_LEVEL_11_1: + case D3D_FEATURE_LEVEL_11_0: + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: + return std::numeric_limits::max(); - // 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; + 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 false; + default: + UNREACHABLE(); + return 0; } } -static float GetMaximumAnisotropy(D3D_FEATURE_LEVEL featureLevel) +size_t GetMaximumVertexInputSlots(D3D_FEATURE_LEVEL featureLevel) { switch (featureLevel) { - case D3D_FEATURE_LEVEL_11_1: - case D3D_FEATURE_LEVEL_11_0: return D3D11_MAX_MAXANISOTROPY; + case D3D_FEATURE_LEVEL_11_1: + case D3D_FEATURE_LEVEL_11_0: + return D3D11_STANDARD_VERTEX_ELEMENT_COUNT; - case D3D_FEATURE_LEVEL_10_1: - case D3D_FEATURE_LEVEL_10_0: return D3D10_MAX_MAXANISOTROPY; + 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://msdn.microsoft.com/en-us/library/windows/desktop/ff476876.aspx - case D3D_FEATURE_LEVEL_9_3: - case D3D_FEATURE_LEVEL_9_2: return 16; + // 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; - case D3D_FEATURE_LEVEL_9_1: return D3D_FL9_1_DEFAULT_MAX_ANISOTROPY; + default: + UNREACHABLE(); + return 0; + } +} + +size_t GetMaximumVertexUniformVectors(D3D_FEATURE_LEVEL featureLevel) +{ + switch (featureLevel) + { + case D3D_FEATURE_LEVEL_11_1: + case D3D_FEATURE_LEVEL_11_0: + return D3D11_REQ_CONSTANT_BUFFER_ELEMENT_COUNT; + + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: + return 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 - d3d11_gl::GetReservedVertexUniformVectors(featureLevel); - default: UNREACHABLE(); return 0; + default: + UNREACHABLE(); + return 0; } } -static bool GetOcclusionQuerySupport(D3D_FEATURE_LEVEL featureLevel) +size_t GetMaximumVertexUniformBlocks(D3D_FEATURE_LEVEL featureLevel) { switch (featureLevel) { - case D3D_FEATURE_LEVEL_11_1: - case D3D_FEATURE_LEVEL_11_0: - case D3D_FEATURE_LEVEL_10_1: - case D3D_FEATURE_LEVEL_10_0: return true; + case D3D_FEATURE_LEVEL_11_1: + case D3D_FEATURE_LEVEL_11_0: + return D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - + d3d11::RESERVED_CONSTANT_BUFFER_SLOT_COUNT; - // 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; + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: + return D3D10_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - + d3d11::RESERVED_CONSTANT_BUFFER_SLOT_COUNT; + + // 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 false; + default: + UNREACHABLE(); + return 0; } } -static bool GetEventQuerySupport(D3D_FEATURE_LEVEL featureLevel) +size_t GetReservedVertexOutputVectors(D3D_FEATURE_LEVEL featureLevel) { - // From http://msdn.microsoft.com/en-us/library/windows/desktop/ff476150.aspx ID3D11Device::CreateQuery + // 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) { - case D3D_FEATURE_LEVEL_11_1: - 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; + // 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. + case D3D_FEATURE_LEVEL_11_1: + 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 false; + default: + UNREACHABLE(); + return 0; } } -static bool GetInstancingSupport(D3D_FEATURE_LEVEL featureLevel) +size_t GetMaximumVertexOutputVectors(D3D_FEATURE_LEVEL featureLevel) { - // From http://msdn.microsoft.com/en-us/library/windows/desktop/ff476150.aspx ID3D11Device::CreateInputLayout + static_assert(gl::IMPLEMENTATION_MAX_VARYING_VECTORS == D3D11_VS_OUTPUT_REGISTER_COUNT, + "Unexpected D3D11 constant value."); switch (featureLevel) { - case D3D_FEATURE_LEVEL_11_1: - case D3D_FEATURE_LEVEL_11_0: - case D3D_FEATURE_LEVEL_10_1: - case D3D_FEATURE_LEVEL_10_0: return true; + case D3D_FEATURE_LEVEL_11_1: + case D3D_FEATURE_LEVEL_11_0: + return D3D11_VS_OUTPUT_REGISTER_COUNT - GetReservedVertexOutputVectors(featureLevel); - // 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_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); - case D3D_FEATURE_LEVEL_9_2: - case D3D_FEATURE_LEVEL_9_1: return false; + // 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 false; + default: + UNREACHABLE(); + return 0; } } -static bool GetFramebufferMultisampleSupport(D3D_FEATURE_LEVEL featureLevel) +size_t GetMaximumVertexTextureUnits(D3D_FEATURE_LEVEL featureLevel) { switch (featureLevel) { - case D3D_FEATURE_LEVEL_11_1: - case D3D_FEATURE_LEVEL_11_0: - case D3D_FEATURE_LEVEL_10_1: - case D3D_FEATURE_LEVEL_10_0: return true; + case D3D_FEATURE_LEVEL_11_1: + 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; - case D3D_FEATURE_LEVEL_9_3: - case D3D_FEATURE_LEVEL_9_2: - case D3D_FEATURE_LEVEL_9_1: return false; + // 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 false; + default: + UNREACHABLE(); + return 0; } } -static bool GetFramebufferBlitSupport(D3D_FEATURE_LEVEL featureLevel) +size_t GetMaximumPixelUniformVectors(D3D_FEATURE_LEVEL featureLevel) { + // TODO(geofflang): Remove hard-coded limit once the gl-uniform-arrays test can pass switch (featureLevel) { - case D3D_FEATURE_LEVEL_11_1: - 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). + case D3D_FEATURE_LEVEL_11_1: + case D3D_FEATURE_LEVEL_11_0: + return 1024; // D3D11_REQ_CONSTANT_BUFFER_ELEMENT_COUNT; - // http://msdn.microsoft.com/en-us/library/windows/desktop/ff476876.aspx states that feature level - // 9.3 supports shader model ps_2_x. + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: + return 1024; // D3D10_REQ_CONSTANT_BUFFER_ELEMENT_COUNT; - switch (featureLevel) - { - case D3D_FEATURE_LEVEL_11_1: - 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; + // 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 - d3d11_gl::GetReservedFragmentUniformVectors(featureLevel); - default: UNREACHABLE(); return false; + default: + UNREACHABLE(); + return 0; } } -static bool GetShaderTextureLODSupport(D3D_FEATURE_LEVEL featureLevel) +size_t GetMaximumPixelUniformBlocks(D3D_FEATURE_LEVEL featureLevel) { switch (featureLevel) { - case D3D_FEATURE_LEVEL_11_1: - case D3D_FEATURE_LEVEL_11_0: - case D3D_FEATURE_LEVEL_10_1: - case D3D_FEATURE_LEVEL_10_0: return true; + case D3D_FEATURE_LEVEL_11_1: + case D3D_FEATURE_LEVEL_11_0: + return D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - + d3d11::RESERVED_CONSTANT_BUFFER_SLOT_COUNT; + + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: + return D3D10_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - + d3d11::RESERVED_CONSTANT_BUFFER_SLOT_COUNT; - case D3D_FEATURE_LEVEL_9_3: - case D3D_FEATURE_LEVEL_9_2: - case D3D_FEATURE_LEVEL_9_1: return false; + // 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 false; + default: + UNREACHABLE(); + return 0; } } -static size_t GetMaximumSimultaneousRenderTargets(D3D_FEATURE_LEVEL featureLevel) +size_t GetMaximumPixelInputVectors(D3D_FEATURE_LEVEL featureLevel) { - // From http://msdn.microsoft.com/en-us/library/windows/desktop/ff476150.aspx ID3D11Device::CreateInputLayout - switch (featureLevel) { - case D3D_FEATURE_LEVEL_11_1: - case D3D_FEATURE_LEVEL_11_0: return D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; + case D3D_FEATURE_LEVEL_11_1: + 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_SIMULTANEOUS_RENDER_TARGET_COUNT; + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: + return D3D10_PS_INPUT_REGISTER_COUNT - GetReservedVertexOutputVectors(featureLevel); - 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; + // 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; + default: + UNREACHABLE(); + return 0; } } -static size_t GetMaximum2DTextureSize(D3D_FEATURE_LEVEL featureLevel) +size_t GetMaximumPixelTextureUnits(D3D_FEATURE_LEVEL featureLevel) { switch (featureLevel) { - case D3D_FEATURE_LEVEL_11_1: - case D3D_FEATURE_LEVEL_11_0: return D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION; + case D3D_FEATURE_LEVEL_11_1: + 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_REQ_TEXTURE2D_U_OR_V_DIMENSION; + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: + return D3D10_COMMONSHADER_SAMPLER_SLOT_COUNT; - 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; + // 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; + default: + UNREACHABLE(); + return 0; } } -static size_t GetMaximumCubeMapTextureSize(D3D_FEATURE_LEVEL featureLevel) +std::array GetMaxComputeWorkGroupCount(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; + case D3D_FEATURE_LEVEL_11_1: + case D3D_FEATURE_LEVEL_11_0: + return {{D3D11_CS_DISPATCH_MAX_THREAD_GROUPS_PER_DIMENSION, + D3D11_CS_DISPATCH_MAX_THREAD_GROUPS_PER_DIMENSION, + D3D11_CS_DISPATCH_MAX_THREAD_GROUPS_PER_DIMENSION}}; + break; + default: + return {{0, 0, 0}}; } } -static size_t GetMaximum2DTextureArraySize(D3D_FEATURE_LEVEL featureLevel) +std::array GetMaxComputeWorkGroupSize(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; + case D3D_FEATURE_LEVEL_11_1: + case D3D_FEATURE_LEVEL_11_0: + return {{D3D11_CS_THREAD_GROUP_MAX_X, D3D11_CS_THREAD_GROUP_MAX_Y, + D3D11_CS_THREAD_GROUP_MAX_Z}}; + break; + default: + return {{0, 0, 0}}; } } -static size_t GetMaximum3DTextureSize(D3D_FEATURE_LEVEL featureLevel) +size_t GetMaxComputeWorkGroupInvocations(D3D_FEATURE_LEVEL featureLevel) { switch (featureLevel) { - case D3D_FEATURE_LEVEL_11_1: - 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; + case D3D_FEATURE_LEVEL_11_1: + case D3D_FEATURE_LEVEL_11_0: + return D3D11_CS_THREAD_GROUP_MAX_THREADS_PER_GROUP; + default: + return 0; } } -static size_t GetMaximumViewportSize(D3D_FEATURE_LEVEL featureLevel) +size_t GetMaximumComputeUniformVectors(D3D_FEATURE_LEVEL featureLevel) { switch (featureLevel) { - case D3D_FEATURE_LEVEL_11_1: - 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; + case D3D_FEATURE_LEVEL_11_1: + case D3D_FEATURE_LEVEL_11_0: + return D3D11_REQ_CONSTANT_BUFFER_ELEMENT_COUNT; + default: + return 0; } } -static size_t GetMaximumDrawIndexedIndexCount(D3D_FEATURE_LEVEL featureLevel) +size_t GetMaximumComputeUniformBlocks(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) { - case D3D_FEATURE_LEVEL_11_1: - 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; + case D3D_FEATURE_LEVEL_11_1: + case D3D_FEATURE_LEVEL_11_0: + return D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - + d3d11::RESERVED_CONSTANT_BUFFER_SLOT_COUNT; + default: + return 0; } } -static size_t GetMaximumDrawVertexCount(D3D_FEATURE_LEVEL featureLevel) +size_t GetMaximumComputeTextureUnits(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) { - case D3D_FEATURE_LEVEL_11_1: - 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; + case D3D_FEATURE_LEVEL_11_1: + case D3D_FEATURE_LEVEL_11_0: + return D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT; + default: + return 0; } } -static size_t GetMaximumVertexInputSlots(D3D_FEATURE_LEVEL featureLevel) +size_t GetMaximumImageUnits(D3D_FEATURE_LEVEL featureLevel) { switch (featureLevel) { - case D3D_FEATURE_LEVEL_11_1: - 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; + case D3D_FEATURE_LEVEL_11_1: + case D3D_FEATURE_LEVEL_11_0: + // TODO(xinghua.cao@intel.com): Get a more accurate limit. For now using + // the minimum requirement for GLES 3.1. + return 4; + default: + return 0; } } -static size_t GetMaximumVertexUniformVectors(D3D_FEATURE_LEVEL featureLevel) +size_t GetMaximumComputeImageUniforms(D3D_FEATURE_LEVEL featureLevel) { - // TODO(geofflang): Remove hard-coded limit once the gl-uniform-arrays test can pass switch (featureLevel) { - case D3D_FEATURE_LEVEL_11_1: - 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 - d3d11_gl::GetReservedVertexUniformVectors(featureLevel); - - default: UNREACHABLE(); return 0; + case D3D_FEATURE_LEVEL_11_1: + case D3D_FEATURE_LEVEL_11_0: + // TODO(xinghua.cao@intel.com): Get a more accurate limit. For now using + // the minimum requirement for GLES 3.1. + return 4; + default: + 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) +int GetMinimumTexelOffset(D3D_FEATURE_LEVEL featureLevel) { switch (featureLevel) { - case D3D_FEATURE_LEVEL_11_1: - case D3D_FEATURE_LEVEL_11_0: return D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - GetReservedVertexUniformBuffers(); + case D3D_FEATURE_LEVEL_11_1: + 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_CONSTANT_BUFFER_API_SLOT_COUNT - GetReservedVertexUniformBuffers(); + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: + return D3D10_COMMONSHADER_TEXEL_OFFSET_MAX_NEGATIVE; - // 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; + // 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; + default: + UNREACHABLE(); + return 0; } } -static size_t GetReservedVertexOutputVectors(D3D_FEATURE_LEVEL featureLevel) +int GetMaximumTexelOffset(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. - case D3D_FEATURE_LEVEL_11_1: - case D3D_FEATURE_LEVEL_11_0: - case D3D_FEATURE_LEVEL_10_1: - case D3D_FEATURE_LEVEL_10_0: return 2; + case D3D_FEATURE_LEVEL_11_1: + 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; - // 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; + // 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; + default: + UNREACHABLE(); + return 0; } - - return 1; } -static size_t GetMaximumVertexOutputVectors(D3D_FEATURE_LEVEL featureLevel) +size_t GetMaximumConstantBufferSize(D3D_FEATURE_LEVEL featureLevel) { - static_assert(gl::IMPLEMENTATION_MAX_VARYING_VECTORS == D3D11_VS_OUTPUT_REGISTER_COUNT, "Unexpected D3D11 constant value."); + // 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) { - case D3D_FEATURE_LEVEL_11_1: - case D3D_FEATURE_LEVEL_11_0: return D3D11_VS_OUTPUT_REGISTER_COUNT - GetReservedVertexOutputVectors(featureLevel); + case D3D_FEATURE_LEVEL_11_1: + case D3D_FEATURE_LEVEL_11_0: + return D3D11_REQ_CONSTANT_BUFFER_ELEMENT_COUNT * bytesPerComponent; - 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); + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: + return D3D10_REQ_CONSTANT_BUFFER_ELEMENT_COUNT * bytesPerComponent; - // 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); + // 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; + default: + UNREACHABLE(); + return 0; } } -static size_t GetMaximumVertexTextureUnits(D3D_FEATURE_LEVEL featureLevel) +size_t GetMaximumStreamOutputBuffers(D3D_FEATURE_LEVEL featureLevel) { switch (featureLevel) { - case D3D_FEATURE_LEVEL_11_1: - case D3D_FEATURE_LEVEL_11_0: return D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT; + case D3D_FEATURE_LEVEL_11_1: + case D3D_FEATURE_LEVEL_11_0: + return D3D11_SO_BUFFER_SLOT_COUNT; - case D3D_FEATURE_LEVEL_10_1: - case D3D_FEATURE_LEVEL_10_0: return D3D10_COMMONSHADER_SAMPLER_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; - // 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; + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: + return 0; - default: UNREACHABLE(); return 0; + default: + UNREACHABLE(); + return 0; } } -static size_t GetMaximumPixelUniformVectors(D3D_FEATURE_LEVEL featureLevel) +size_t GetMaximumStreamOutputInterleavedComponents(D3D_FEATURE_LEVEL featureLevel) { - // TODO(geofflang): Remove hard-coded limit once the gl-uniform-arrays test can pass switch (featureLevel) { - case D3D_FEATURE_LEVEL_11_1: - case D3D_FEATURE_LEVEL_11_0: return 1024; // D3D11_REQ_CONSTANT_BUFFER_ELEMENT_COUNT; + case D3D_FEATURE_LEVEL_11_1: + case D3D_FEATURE_LEVEL_11_0: - case D3D_FEATURE_LEVEL_10_1: - case D3D_FEATURE_LEVEL_10_0: return 1024; // D3D10_REQ_CONSTANT_BUFFER_ELEMENT_COUNT; + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: + return GetMaximumVertexOutputVectors(featureLevel) * 4; - // 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 - d3d11_gl::GetReservedFragmentUniformVectors(featureLevel); + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: + return 0; - default: UNREACHABLE(); return 0; + 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) +size_t GetMaximumStreamOutputSeparateComponents(D3D_FEATURE_LEVEL featureLevel) { switch (featureLevel) { - case D3D_FEATURE_LEVEL_11_1: - case D3D_FEATURE_LEVEL_11_0: return D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - GetReservedPixelUniformBuffers(); + case D3D_FEATURE_LEVEL_11_1: + case D3D_FEATURE_LEVEL_11_0: + return GetMaximumStreamOutputInterleavedComponents(featureLevel) / + GetMaximumStreamOutputBuffers(featureLevel); - case D3D_FEATURE_LEVEL_10_1: - case D3D_FEATURE_LEVEL_10_0: return D3D10_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - GetReservedPixelUniformBuffers(); + // 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; - // 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; + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: + return 0; - default: UNREACHABLE(); return 0; + default: + UNREACHABLE(); + return 0; } } -static size_t GetMaximumPixelInputVectors(D3D_FEATURE_LEVEL featureLevel) +size_t GetMaximumRenderToBufferWindowSize(D3D_FEATURE_LEVEL featureLevel) { switch (featureLevel) { - case D3D_FEATURE_LEVEL_11_1: - 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); + case D3D_FEATURE_LEVEL_11_1: + case D3D_FEATURE_LEVEL_11_0: + return D3D11_REQ_RENDER_TO_BUFFER_WINDOW_WIDTH; + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: + return D3D10_REQ_RENDER_TO_BUFFER_WINDOW_WIDTH; - // 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); + // REQ_RENDER_TO_BUFFER_WINDOW_WIDTH not supported on D3D11 Feature Level 9, + // 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; + default: + UNREACHABLE(); + return 0; } } -static size_t GetMaximumPixelTextureUnits(D3D_FEATURE_LEVEL featureLevel) +IntelDriverVersion GetIntelDriverVersion(const Optional driverVersion) { - switch (featureLevel) - { - case D3D_FEATURE_LEVEL_11_1: - 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; + if (!driverVersion.valid()) + return IntelDriverVersion(0); - // 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; - } + // According to http://www.intel.com/content/www/us/en/support/graphics-drivers/000005654.html, + // only the fourth part is necessary since it stands for the driver specific unique version + // number. + WORD part = LOWORD(driverVersion.value().LowPart); + return IntelDriverVersion(part); } -static int GetMinimumTexelOffset(D3D_FEATURE_LEVEL featureLevel) +} // anonymous namespace + +unsigned int GetReservedVertexUniformVectors(D3D_FEATURE_LEVEL featureLevel) { switch (featureLevel) { - case D3D_FEATURE_LEVEL_11_1: - 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; + case D3D_FEATURE_LEVEL_11_1: + case D3D_FEATURE_LEVEL_11_0: + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: + return 0; - // 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; + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: + return 3; // dx_ViewAdjust, dx_ViewCoords and dx_ViewScale - default: UNREACHABLE(); return 0; + default: + UNREACHABLE(); + return 0; } } -static int GetMaximumTexelOffset(D3D_FEATURE_LEVEL featureLevel) +unsigned int GetReservedFragmentUniformVectors(D3D_FEATURE_LEVEL featureLevel) { switch (featureLevel) { - case D3D_FEATURE_LEVEL_11_1: - 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; + case D3D_FEATURE_LEVEL_11_1: + case D3D_FEATURE_LEVEL_11_0: + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: + return 0; - // 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; + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: + return 3; - default: UNREACHABLE(); return 0; + default: + UNREACHABLE(); + return 0; } } -static size_t GetMaximumConstantBufferSize(D3D_FEATURE_LEVEL featureLevel) +gl::Version GetMaximumClientVersion(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) { - case D3D_FEATURE_LEVEL_11_1: - 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; + case D3D_FEATURE_LEVEL_11_1: + case D3D_FEATURE_LEVEL_11_0: + return gl::Version(3, 1); + case D3D_FEATURE_LEVEL_10_1: + return gl::Version(3, 0); - // 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; + 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 gl::Version(2, 0); - default: UNREACHABLE(); return 0; + default: + UNREACHABLE(); + return gl::Version(0, 0); } } -static size_t GetMaximumStreamOutputBuffers(D3D_FEATURE_LEVEL featureLevel) +unsigned int GetMaxViewportAndScissorRectanglesPerPipeline(D3D_FEATURE_LEVEL featureLevel) { switch (featureLevel) { - case D3D_FEATURE_LEVEL_11_1: - 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; + case D3D_FEATURE_LEVEL_11_1: + case D3D_FEATURE_LEVEL_11_0: + return D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE; + 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 1; + default: + UNREACHABLE(); + return 0; } } -static size_t GetMaximumStreamOutputInterleavedComponents(D3D_FEATURE_LEVEL featureLevel) +bool IsMultiviewSupported(D3D_FEATURE_LEVEL featureLevel) { + // The ANGLE_multiview extension can always be supported in D3D11 through geometry shaders. switch (featureLevel) { - case D3D_FEATURE_LEVEL_11_1: - 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; + case D3D_FEATURE_LEVEL_11_1: + case D3D_FEATURE_LEVEL_11_0: + return true; + default: + return false; } } -static size_t GetMaximumStreamOutputSeparateComponents(D3D_FEATURE_LEVEL featureLevel) +unsigned int GetMaxSampleMaskWords(D3D_FEATURE_LEVEL featureLevel) { switch (featureLevel) { - case D3D_FEATURE_LEVEL_11_1: - 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; + // D3D10+ only allows 1 sample mask. + case D3D_FEATURE_LEVEL_11_1: + case D3D_FEATURE_LEVEL_11_0: + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: + return 1u; + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: + return 0u; + default: + UNREACHABLE(); + return 0u; } } void GenerateCaps(ID3D11Device *device, ID3D11DeviceContext *deviceContext, const Renderer11DeviceCaps &renderer11DeviceCaps, gl::Caps *caps, gl::TextureCapsMap *textureCapsMap, gl::Extensions *extensions, gl::Limitations *limitations) { - GLuint maxSamples = 0; D3D_FEATURE_LEVEL featureLevel = renderer11DeviceCaps.featureLevel; const gl::FormatSet &allFormats = gl::GetAllSizedInternalFormats(); - for (gl::FormatSet::const_iterator internalFormat = allFormats.begin(); internalFormat != allFormats.end(); ++internalFormat) + for (GLenum internalFormat : allFormats) { - gl::TextureCaps textureCaps = GenerateTextureFormatCaps(GetMaximumClientVersion(featureLevel), *internalFormat, device, renderer11DeviceCaps); - textureCapsMap->insert(*internalFormat, textureCaps); - - maxSamples = std::max(maxSamples, textureCaps.getMaxSamples()); + gl::TextureCaps textureCaps = GenerateTextureFormatCaps( + GetMaximumClientVersion(featureLevel), internalFormat, device, renderer11DeviceCaps); + textureCapsMap->insert(internalFormat, textureCaps); - if (gl::GetInternalFormatInfo(*internalFormat).compressed) + if (gl::GetSizedInternalFormatInfo(internalFormat).compressed) { - caps->compressedTextureFormats.push_back(*internalFormat); + caps->compressedTextureFormats.push_back(internalFormat); } } @@ -1226,6 +1346,14 @@ void GenerateCaps(ID3D11Device *device, ID3D11DeviceContext *deviceContext, cons caps->maxVertexTextureImageUnits = static_cast(GetMaximumVertexTextureUnits(featureLevel)); + // Vertex Attribute Bindings are emulated on D3D11. + caps->maxVertexAttribBindings = caps->maxVertexAttributes; + // Experimental testing confirmed there is no explicit limit on maximum buffer offset in D3D11. + caps->maxVertexAttribRelativeOffset = std::numeric_limits::max(); + // Experimental testing confirmed 2048 is the maximum stride that D3D11 can support on all + // platforms. + caps->maxVertexAttribStride = 2048; + // Fragment shader limits caps->maxFragmentUniformComponents = static_cast(GetMaximumPixelUniformVectors(featureLevel)) * 4; @@ -1239,108 +1367,504 @@ void GenerateCaps(ID3D11Device *device, ID3D11DeviceContext *deviceContext, cons caps->minProgramTexelOffset = GetMinimumTexelOffset(featureLevel); caps->maxProgramTexelOffset = GetMaximumTexelOffset(featureLevel); - // Aggregate shader limits - caps->maxUniformBufferBindings = caps->maxVertexUniformBlocks + caps->maxFragmentUniformBlocks; - caps->maxUniformBlockSize = GetMaximumConstantBufferSize(featureLevel); + // Compute shader limits + caps->maxComputeWorkGroupCount = GetMaxComputeWorkGroupCount(featureLevel); + caps->maxComputeWorkGroupSize = GetMaxComputeWorkGroupSize(featureLevel); + caps->maxComputeWorkGroupInvocations = + static_cast(GetMaxComputeWorkGroupInvocations(featureLevel)); + caps->maxComputeUniformComponents = + static_cast(GetMaximumComputeUniformVectors(featureLevel)) * 4; + caps->maxComputeUniformBlocks = + static_cast(GetMaximumComputeUniformBlocks(featureLevel)); + caps->maxComputeTextureImageUnits = + static_cast(GetMaximumComputeTextureUnits(featureLevel)); + caps->maxImageUnits = static_cast(GetMaximumImageUnits(featureLevel)); + caps->maxComputeImageUniforms = + static_cast(GetMaximumComputeImageUniforms(featureLevel)); + + // Aggregate shader limits + caps->maxUniformBufferBindings = caps->maxVertexUniformBlocks + caps->maxFragmentUniformBlocks; + caps->maxUniformBlockSize = GetMaximumConstantBufferSize(featureLevel); + + // TODO(oetuaho): Get a more accurate limit. For now using the minimum requirement for GLES 3.1. + caps->maxUniformLocations = 1024; + + // 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 + // With DirectX 11.0, we emulate UBO offsets using copies of ranges of the UBO however + // we still keep the same alignment as 11.1 for consistency. + caps->uniformBufferOffsetAlignment = 256; + + 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->maxCombinedComputeUniformComponents = + static_cast(caps->maxComputeUniformBlocks * (caps->maxUniformBlockSize / 4) + + caps->maxComputeUniformComponents); + caps->maxVaryingComponents = + static_cast(GetMaximumVertexOutputVectors(featureLevel)) * 4; + caps->maxVaryingVectors = static_cast(GetMaximumVertexOutputVectors(featureLevel)); + caps->maxCombinedTextureImageUnits = caps->maxVertexTextureImageUnits + caps->maxTextureImageUnits; + + // Transform feedback limits + caps->maxTransformFeedbackInterleavedComponents = + static_cast(GetMaximumStreamOutputInterleavedComponents(featureLevel)); + caps->maxTransformFeedbackSeparateAttributes = + static_cast(GetMaximumStreamOutputBuffers(featureLevel)); + caps->maxTransformFeedbackSeparateComponents = + static_cast(GetMaximumStreamOutputSeparateComponents(featureLevel)); + + // Defer the computation of multisample limits to Context::updateCaps() where max*Samples values + // are determined according to available sample counts for each individual format. + caps->maxSamples = std::numeric_limits::max(); + caps->maxColorTextureSamples = std::numeric_limits::max(); + caps->maxDepthTextureSamples = std::numeric_limits::max(); + caps->maxIntegerSamples = std::numeric_limits::max(); + + // Sample mask words limits + caps->maxSampleMaskWords = GetMaxSampleMaskWords(featureLevel); + + // Framebuffer limits + caps->maxFramebufferSamples = std::numeric_limits::max(); + caps->maxFramebufferWidth = + static_cast(GetMaximumRenderToBufferWindowSize(featureLevel)); + caps->maxFramebufferHeight = caps->maxFramebufferWidth; + + // GL extension support + extensions->setTextureExtensionSupport(*textureCapsMap); + extensions->elementIndexUint = 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->disjointTimerQuery = true; + extensions->queryCounterBitsTimeElapsed = 64; + extensions->queryCounterBitsTimestamp = + 0; // Timestamps cannot be supported due to D3D11 limitations + extensions->robustness = true; + // Direct3D guarantees to return zero for any resource that is accessed out of bounds. + // See https://msdn.microsoft.com/en-us/library/windows/desktop/ff476332(v=vs.85).aspx + // and https://msdn.microsoft.com/en-us/library/windows/desktop/ff476900(v=vs.85).aspx + extensions->robustBufferAccessBehavior = true; + extensions->blendMinMax = true; + extensions->framebufferBlit = GetFramebufferBlitSupport(featureLevel); + extensions->framebufferMultisample = GetFramebufferMultisampleSupport(featureLevel); + extensions->instancedArrays = GetInstancingSupport(featureLevel); + extensions->packReverseRowOrder = true; + extensions->standardDerivatives = GetDerivativeInstructionSupport(featureLevel); + extensions->shaderTextureLOD = GetShaderTextureLODSupport(featureLevel); + extensions->fragDepth = true; + extensions->multiview = IsMultiviewSupported(featureLevel); + if (extensions->multiview) + { + extensions->maxViews = + std::min(static_cast(gl::IMPLEMENTATION_ANGLE_MULTIVIEW_MAX_VIEWS), + std::min(static_cast(GetMaximum2DTextureArraySize(featureLevel)), + GetMaxViewportAndScissorRectanglesPerPipeline(featureLevel))); + } + extensions->textureUsage = true; // This could be false since it has no effect in D3D11 + extensions->discardFramebuffer = true; + extensions->translatedShaderSource = true; + extensions->fboRenderMipmap = false; + extensions->debugMarker = true; + extensions->eglImage = true; + extensions->eglImageExternal = true; + extensions->eglImageExternalEssl3 = true; + extensions->eglStreamConsumerExternal = true; + extensions->unpackSubimage = true; + extensions->packSubimage = true; + extensions->lossyETCDecode = true; + extensions->syncQuery = GetEventQuerySupport(featureLevel); + extensions->copyTexture = true; + extensions->copyCompressedTexture = true; + + // D3D11 Feature Level 10_0+ uses SV_IsFrontFace in HLSL to emulate gl_FrontFacing. + // D3D11 Feature Level 9_3 doesn't support SV_IsFrontFace, and has no equivalent, so can't support gl_FrontFacing. + limitations->noFrontFacingSupport = (renderer11DeviceCaps.featureLevel <= D3D_FEATURE_LEVEL_9_3); + + // D3D11 Feature Level 9_3 doesn't support alpha-to-coverage + limitations->noSampleAlphaToCoverageSupport = (renderer11DeviceCaps.featureLevel <= D3D_FEATURE_LEVEL_9_3); + + // D3D11 Feature Levels 9_3 and below do not support non-constant loop indexing and require + // additional + // pre-validation of the shader at compile time to produce a better error message. + limitations->shadersRequireIndexedLoopValidation = + (renderer11DeviceCaps.featureLevel <= D3D_FEATURE_LEVEL_9_3); + + // D3D11 has no concept of separate masks and refs for front and back faces in the depth stencil + // state. + limitations->noSeparateStencilRefsAndMasks = true; + + // D3D11 cannot support constant color and alpha blend funcs together + limitations->noSimultaneousConstantColorAndAlphaBlendFunc = true; + +#ifdef ANGLE_ENABLE_WINDOWS_STORE + // Setting a non-zero divisor on attribute zero doesn't work on certain Windows Phone 8-era devices. + // We should prevent developers from doing this on ALL Windows Store devices. This will maintain consistency across all Windows devices. + // We allow non-zero divisors on attribute zero if the Client Version >= 3, since devices affected by this issue don't support ES3+. + limitations->attributeZeroRequiresZeroDivisorInEXT = true; +#endif +} + +void GetSamplePosition(GLsizei sampleCount, size_t index, GLfloat *xy) +{ + size_t indexKey = static_cast(ceil(log(sampleCount))); + ASSERT(indexKey < kSamplePositions.size() && + (2 * index + 1) < kSamplePositions[indexKey].size()); + + xy[0] = kSamplePositions[indexKey][2 * index]; + xy[1] = kSamplePositions[indexKey][2 * index + 1]; +} + +} // namespace d3d11_gl + +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, gl::CullFaceMode cullMode) +{ + D3D11_CULL_MODE cull = D3D11_CULL_NONE; + + if (cullEnabled) + { + switch (cullMode) + { + case gl::CullFaceMode::Front: + cull = D3D11_CULL_FRONT; + break; + case gl::CullFaceMode::Back: + cull = D3D11_CULL_BACK; + break; + case gl::CullFaceMode::FrontAndBack: + 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; +} - // 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 - // With DirectX 11.0, we emulate UBO offsets using copies of ranges of the UBO however - // we still keep the same alignment as 11.1 for consistency. - caps->uniformBufferOffsetAlignment = 256; +D3D11_DEPTH_WRITE_MASK ConvertDepthMask(bool depthWriteEnabled) +{ + return depthWriteEnabled ? D3D11_DEPTH_WRITE_MASK_ALL : D3D11_DEPTH_WRITE_MASK_ZERO; +} - 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 = - static_cast(GetMaximumVertexOutputVectors(featureLevel)) * 4; - caps->maxVaryingVectors = static_cast(GetMaximumVertexOutputVectors(featureLevel)); - caps->maxCombinedTextureImageUnits = caps->maxVertexTextureImageUnits + caps->maxTextureImageUnits; +UINT8 ConvertStencilMask(GLuint stencilmask) +{ + return static_cast(stencilmask); +} - // Transform feedback limits - caps->maxTransformFeedbackInterleavedComponents = - static_cast(GetMaximumStreamOutputInterleavedComponents(featureLevel)); - caps->maxTransformFeedbackSeparateAttributes = - static_cast(GetMaximumStreamOutputBuffers(featureLevel)); - caps->maxTransformFeedbackSeparateComponents = - static_cast(GetMaximumStreamOutputSeparateComponents(featureLevel)); +D3D11_STENCIL_OP ConvertStencilOp(GLenum stencilOp) +{ + D3D11_STENCIL_OP d3dStencilOp = D3D11_STENCIL_OP_KEEP; - // Multisample limits - caps->maxSamples = maxSamples; + 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(); + } - // GL extension support - extensions->setTextureExtensionSupport(*textureCapsMap); - extensions->elementIndexUint = 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->disjointTimerQuery = true; - extensions->queryCounterBitsTimeElapsed = 64; - extensions->queryCounterBitsTimestamp = - 0; // Timestamps cannot be supported due to D3D11 limitations - extensions->robustness = true; - extensions->blendMinMax = true; - extensions->framebufferBlit = GetFramebufferBlitSupport(featureLevel); - extensions->framebufferMultisample = GetFramebufferMultisampleSupport(featureLevel); - 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->discardFramebuffer = true; - extensions->translatedShaderSource = true; - extensions->fboRenderMipmap = false; - extensions->debugMarker = true; - extensions->eglImage = true; - extensions->unpackSubimage = true; - extensions->packSubimage = true; - extensions->vertexArrayObject = true; - extensions->noError = true; - extensions->lossyETCDecode = true; + return d3dStencilOp; +} - // D3D11 Feature Level 10_0+ uses SV_IsFrontFace in HLSL to emulate gl_FrontFacing. - // D3D11 Feature Level 9_3 doesn't support SV_IsFrontFace, and has no equivalent, so can't support gl_FrontFacing. - limitations->noFrontFacingSupport = (renderer11DeviceCaps.featureLevel <= D3D_FEATURE_LEVEL_9_3); +D3D11_FILTER ConvertFilter(GLenum minFilter, + GLenum magFilter, + float maxAnisotropy, + GLenum comparisonMode) +{ + bool comparison = comparisonMode != GL_NONE; - // D3D11 Feature Level 9_3 doesn't support alpha-to-coverage - limitations->noSampleAlphaToCoverageSupport = (renderer11DeviceCaps.featureLevel <= D3D_FEATURE_LEVEL_9_3); + 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 Feature Levels 9_3 and below do not support non-constant loop indexing and require - // additional - // pre-validation of the shader at compile time to produce a better error message. - limitations->shadersRequireIndexedLoopValidation = - (renderer11DeviceCaps.featureLevel <= D3D_FEATURE_LEVEL_9_3); + 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(); + } - // D3D11 has no concept of separate masks and refs for front and back faces in the depth stencil - // state. - limitations->noSeparateStencilRefsAndMasks = true; + return D3D11_ENCODE_BASIC_FILTER(dxMin, dxMag, dxMip, + static_cast(comparison)); + } +} - // D3D11 cannot support constant color and alpha blend funcs together - limitations->noSimultaneousConstantColorAndAlphaBlendFunc = true; +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(); + } -#ifdef ANGLE_ENABLE_WINDOWS_STORE - // Setting a non-zero divisor on attribute zero doesn't work on certain Windows Phone 8-era devices. - // We should prevent developers from doing this on ALL Windows Store devices. This will maintain consistency across all Windows devices. - // We allow non-zero divisors on attribute zero if the Client Version >= 3, since devices affected by this issue don't support ES3+. - limitations->attributeZeroRequiresZeroDivisorInEXT = true; -#endif + return D3D11_TEXTURE_ADDRESS_WRAP; } -} // namespace d3d11_gl +UINT ConvertMaxAnisotropy(float maxAnisotropy, D3D_FEATURE_LEVEL featureLevel) +{ + return static_cast(std::min(maxAnisotropy, d3d11_gl::GetMaximumAnisotropy(featureLevel))); +} + +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; + case GL_TIME_ELAPSED_EXT: + // Two internal queries are also created for begin/end timestamps + return D3D11_QUERY_TIMESTAMP_DISJOINT; + case GL_COMMANDS_COMPLETED_CHROMIUM: + return D3D11_QUERY_EVENT; + default: + UNREACHABLE(); + return D3D11_QUERY_EVENT; + } +} + +// Get the D3D11 write mask covering all color channels of a given format +UINT8 GetColorMask(const gl::InternalFormat &format) +{ + return ConvertColorMask(format.redBits > 0, format.greenBits > 0, format.blueBits > 0, + format.alphaBits > 0); +} + +} // namespace gl_d3d11 namespace d3d11 { @@ -1352,9 +1876,7 @@ ANGLED3D11DeviceType GetDeviceType(ID3D11Device *device) IDXGIDevice *dxgiDevice = nullptr; IDXGIAdapter *dxgiAdapter = nullptr; -#if defined(ANGLE_ENABLE_D3D11_1) IDXGIAdapter2 *dxgiAdapter2 = nullptr; -#endif ANGLED3D11DeviceType retDeviceType = ANGLE_D3D11_DEVICE_TYPE_UNKNOWN; @@ -1365,7 +1887,6 @@ ANGLED3D11DeviceType GetDeviceType(ID3D11Device *device) if (SUCCEEDED(hr)) { std::wstring adapterString; -#if defined(ANGLE_ENABLE_D3D11_1) HRESULT adapter2hr = dxgiAdapter->QueryInterface(__uuidof(dxgiAdapter2), (void **)&dxgiAdapter2); if (SUCCEEDED(adapter2hr)) @@ -1378,7 +1899,6 @@ ANGLED3D11DeviceType GetDeviceType(ID3D11Device *device) adapterString = std::wstring(adapterDesc2.Description); } else -#endif { DXGI_ADAPTER_DESC adapterDesc; dxgiAdapter->GetDesc(&adapterDesc); @@ -1410,16 +1930,14 @@ ANGLED3D11DeviceType GetDeviceType(ID3D11Device *device) SafeRelease(dxgiDevice); SafeRelease(dxgiAdapter); -#if defined(ANGLE_ENABLE_D3D11_1) SafeRelease(dxgiAdapter2); -#endif return retDeviceType; } void MakeValidSize(bool isImage, DXGI_FORMAT format, GLsizei *requestWidth, GLsizei *requestHeight, int *levelOffset) { - const DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(format); + const DXGIFormatSize &dxgiFormatInfo = d3d11::GetDXGIFormatSizeInfo(format); int upsampleCount = 0; // Don't expand the size of full textures that are at least (blockWidth x blockHeight) already. @@ -1433,7 +1951,10 @@ void MakeValidSize(bool isImage, DXGI_FORMAT format, GLsizei *requestWidth, GLsi upsampleCount++; } } - *levelOffset = upsampleCount; + if (levelOffset) + { + *levelOffset = upsampleCount; + } } void GenerateInitialTextureData(GLint internalFormat, @@ -1445,10 +1966,11 @@ void GenerateInitialTextureData(GLint internalFormat, std::vector *outSubresourceData, std::vector> *outData) { - const d3d11::TextureFormat &d3dFormatInfo = d3d11::GetTextureFormatInfo(internalFormat, renderer11DeviceCaps); - ASSERT(d3dFormatInfo.dataInitializerFunction != NULL); + const d3d11::Format &d3dFormatInfo = d3d11::Format::Get(internalFormat, renderer11DeviceCaps); + ASSERT(d3dFormatInfo.dataInitializerFunction != nullptr); - const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(d3dFormatInfo.texFormat); + const d3d11::DXGIFormatSize &dxgiFormatInfo = + d3d11::GetDXGIFormatSizeInfo(d3dFormatInfo.texFormat); outSubresourceData->resize(mipLevels); outData->resize(mipLevels); @@ -1495,6 +2017,36 @@ void SetPositionLayerTexCoord3DVertex(PositionLayerTexCoord3DVertex* vertex, flo vertex->s = s; } +BlendStateKey::BlendStateKey() +{ + memset(this, 0, sizeof(BlendStateKey)); +} + +bool operator==(const BlendStateKey &a, const BlendStateKey &b) +{ + return memcmp(&a, &b, sizeof(BlendStateKey)) == 0; +} + +bool operator!=(const BlendStateKey &a, const BlendStateKey &b) +{ + return !(a == b); +} + +RasterizerStateKey::RasterizerStateKey() +{ + memset(this, 0, sizeof(RasterizerStateKey)); +} + +bool operator==(const RasterizerStateKey &a, const RasterizerStateKey &b) +{ + return memcmp(&a, &b, sizeof(RasterizerStateKey)) == 0; +} + +bool operator!=(const RasterizerStateKey &a, const RasterizerStateKey &b) +{ + return !(a == b); +} + HRESULT SetDebugName(ID3D11DeviceChild *resource, const char *name) { #if defined(_DEBUG) @@ -1533,34 +2085,66 @@ HRESULT SetDebugName(ID3D11DeviceChild *resource, const char *name) #endif } +// Keep this in cpp file where it has visibility of Renderer11.h, otherwise calling +// allocateResource is only compatible with Clang and MSVS, which support calling a +// method on a forward declared class in a template. +template +gl::Error LazyResource::resolveImpl(Renderer11 *renderer, + const GetDescType &desc, + GetInitDataType *initData, + const char *name) +{ + if (!mResource.valid()) + { + ANGLE_TRY(renderer->allocateResource(desc, initData, &mResource)); + mResource.setDebugName(name); + } + return gl::NoError(); +} + +template gl::Error LazyResource::resolveImpl(Renderer11 *renderer, + const D3D11_BLEND_DESC &desc, + void *initData, + const char *name); +template gl::Error LazyResource::resolveImpl(Renderer11 *renderer, + const ShaderData &desc, + void *initData, + const char *name); +template gl::Error LazyResource::resolveImpl( + Renderer11 *renderer, + const ShaderData &desc, + const std::vector *initData, + const char *name); +template gl::Error LazyResource::resolveImpl( + Renderer11 *renderer, + const InputElementArray &desc, + const ShaderData *initData, + const char *name); +template gl::Error LazyResource::resolveImpl(Renderer11 *renderer, + const ShaderData &desc, + void *initData, + const char *name); +template gl::Error LazyResource::resolveImpl(Renderer11 *renderer, + const ShaderData &desc, + void *initData, + const char *name); + LazyInputLayout::LazyInputLayout(const D3D11_INPUT_ELEMENT_DESC *inputDesc, size_t inputDescLen, const BYTE *byteCode, size_t byteCodeLen, const char *debugName) - : mInputDesc(inputDescLen), - mByteCodeLen(byteCodeLen), - mByteCode(byteCode), - mDebugName(debugName) + : mInputDesc(inputDesc, inputDescLen), mByteCode(byteCode, byteCodeLen), mDebugName(debugName) { - memcpy(&mInputDesc[0], inputDesc, sizeof(D3D11_INPUT_ELEMENT_DESC) * inputDescLen); } -ID3D11InputLayout *LazyInputLayout::resolve(ID3D11Device *device) +LazyInputLayout::~LazyInputLayout() { - checkAssociatedDevice(device); - - if (mResource == nullptr) - { - HRESULT result = - device->CreateInputLayout(&mInputDesc[0], static_cast(mInputDesc.size()), - mByteCode, mByteCodeLen, &mResource); - ASSERT(SUCCEEDED(result)); - UNUSED_ASSERTION_VARIABLE(result); - d3d11::SetDebugName(mResource, mDebugName); - } +} - return mResource; +gl::Error LazyInputLayout::resolve(Renderer11 *renderer) +{ + return resolveImpl(renderer, mInputDesc, &mByteCode, mDebugName); } LazyBlendState::LazyBlendState(const D3D11_BLEND_DESC &desc, const char *debugName) @@ -1568,213 +2152,270 @@ LazyBlendState::LazyBlendState(const D3D11_BLEND_DESC &desc, const char *debugNa { } -ID3D11BlendState *LazyBlendState::resolve(ID3D11Device *device) +gl::Error LazyBlendState::resolve(Renderer11 *renderer) { - checkAssociatedDevice(device); + return resolveImpl(renderer, mDesc, nullptr, mDebugName); +} + +angle::WorkaroundsD3D GenerateWorkarounds(const Renderer11DeviceCaps &deviceCaps, + const DXGI_ADAPTER_DESC &adapterDesc) +{ + bool is9_3 = (deviceCaps.featureLevel <= D3D_FEATURE_LEVEL_9_3); + + angle::WorkaroundsD3D workarounds; + workarounds.mrtPerfWorkaround = true; + workarounds.setDataFasterThanImageUpload = true; + workarounds.zeroMaxLodWorkaround = is9_3; + workarounds.useInstancedPointSpriteEmulation = is9_3; + + // TODO(jmadill): Narrow problematic driver range. + if (IsNvidia(adapterDesc.VendorId)) + { + if (deviceCaps.driverVersion.valid()) + { + WORD part1 = HIWORD(deviceCaps.driverVersion.value().LowPart); + WORD part2 = LOWORD(deviceCaps.driverVersion.value().LowPart); + + // Disable the workaround to fix a second driver bug on newer NVIDIA. + workarounds.depthStencilBlitExtraCopy = (part1 <= 13u && part2 < 6881); + } + else + { + workarounds.depthStencilBlitExtraCopy = true; + } + } + + // TODO(jmadill): Disable workaround when we have a fixed compiler DLL. + workarounds.expandIntegerPowExpressions = true; + + workarounds.flushAfterEndingTransformFeedback = IsNvidia(adapterDesc.VendorId); + workarounds.getDimensionsIgnoresBaseLevel = IsNvidia(adapterDesc.VendorId); - if (mResource == nullptr) + if (IsIntel(adapterDesc.VendorId)) { - HRESULT result = device->CreateBlendState(&mDesc, &mResource); - ASSERT(SUCCEEDED(result)); - UNUSED_ASSERTION_VARIABLE(result); - d3d11::SetDebugName(mResource, mDebugName); + IntelDriverVersion capsVersion = d3d11_gl::GetIntelDriverVersion(deviceCaps.driverVersion); + + workarounds.preAddTexelFetchOffsets = true; + workarounds.useSystemMemoryForConstantBuffers = true; + workarounds.disableB5G6R5Support = capsVersion < IntelDriverVersion(4539); + workarounds.addDummyTextureNoRenderTarget = capsVersion < IntelDriverVersion(4815); + if (IsSkylake(adapterDesc.DeviceId)) + { + workarounds.callClearTwice = capsVersion < IntelDriverVersion(4771); + workarounds.emulateIsnanFloat = capsVersion < IntelDriverVersion(4542); + } + else if (IsBroadwell(adapterDesc.DeviceId) || IsHaswell(adapterDesc.DeviceId)) + { + workarounds.rewriteUnaryMinusOperator = capsVersion < IntelDriverVersion(4624); + } + } + + // TODO(jmadill): Disable when we have a fixed driver version. + workarounds.emulateTinyStencilTextures = IsAMD(adapterDesc.VendorId); + + // The tiny stencil texture workaround involves using CopySubresource or UpdateSubresource on a + // depth stencil texture. This is not allowed until feature level 10.1 but since it is not + // possible to support ES3 on these devices, there is no need for the workaround to begin with + // (anglebug.com/1572). + if (deviceCaps.featureLevel < D3D_FEATURE_LEVEL_10_1) + { + workarounds.emulateTinyStencilTextures = false; } - return mResource; + // If the VPAndRTArrayIndexFromAnyShaderFeedingRasterizer feature is not available, we have to + // select the viewport / RT array index in the geometry shader. + workarounds.selectViewInGeometryShader = + (deviceCaps.supportsVpRtIndexWriteFromVertexShader == false); + + // Call platform hooks for testing overrides. + auto *platform = ANGLEPlatformCurrent(); + platform->overrideWorkaroundsD3D(platform, &workarounds); + + return workarounds; } -WorkaroundsD3D GenerateWorkarounds(D3D_FEATURE_LEVEL featureLevel) +void InitConstantBufferDesc(D3D11_BUFFER_DESC *constantBufferDescription, size_t byteWidth) { - WorkaroundsD3D 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; + constantBufferDescription->ByteWidth = static_cast(byteWidth); + constantBufferDescription->Usage = D3D11_USAGE_DYNAMIC; + constantBufferDescription->BindFlags = D3D11_BIND_CONSTANT_BUFFER; + constantBufferDescription->CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + constantBufferDescription->MiscFlags = 0; + constantBufferDescription->StructureByteStride = 0; } } // namespace d3d11 -TextureHelper11::TextureHelper11() - : mTextureType(GL_NONE), - mFormat(DXGI_FORMAT_UNKNOWN), - mSampleCount(0), - mTexture2D(nullptr), - mTexture3D(nullptr) +// TextureHelper11 implementation. +TextureHelper11::TextureHelper11() : mFormatSet(nullptr), mSampleCount(0) { } -TextureHelper11::TextureHelper11(TextureHelper11 &&toCopy) - : mTextureType(toCopy.mTextureType), - mExtents(toCopy.mExtents), - mFormat(toCopy.mFormat), - mSampleCount(toCopy.mSampleCount), - mTexture2D(toCopy.mTexture2D), - mTexture3D(toCopy.mTexture3D) +TextureHelper11::TextureHelper11(TextureHelper11 &&toCopy) : TextureHelper11() { - toCopy.reset(); + *this = std::move(toCopy); } -// static -TextureHelper11 TextureHelper11::MakeAndReference(ID3D11Resource *genericResource) +TextureHelper11::TextureHelper11(const TextureHelper11 &other) + : mFormatSet(other.mFormatSet), mExtents(other.mExtents), mSampleCount(other.mSampleCount) { - TextureHelper11 newHelper; - newHelper.mTexture2D = d3d11::DynamicCastComObject(genericResource); - newHelper.mTexture3D = d3d11::DynamicCastComObject(genericResource); - newHelper.mTextureType = newHelper.mTexture2D ? GL_TEXTURE_2D : GL_TEXTURE_3D; - newHelper.initDesc(); - return newHelper; + mData = other.mData; } -// static -TextureHelper11 TextureHelper11::MakeAndPossess2D(ID3D11Texture2D *texToOwn) +TextureHelper11::~TextureHelper11() { - TextureHelper11 newHelper; - newHelper.mTexture2D = texToOwn; - newHelper.mTextureType = GL_TEXTURE_2D; - newHelper.initDesc(); - return newHelper; } -// static -TextureHelper11 TextureHelper11::MakeAndPossess3D(ID3D11Texture3D *texToOwn) +void TextureHelper11::getDesc(D3D11_TEXTURE2D_DESC *desc) const { - TextureHelper11 newHelper; - newHelper.mTexture3D = texToOwn; - newHelper.mTextureType = GL_TEXTURE_3D; - newHelper.initDesc(); - return newHelper; + static_cast(mData->object)->GetDesc(desc); } -void TextureHelper11::initDesc() +void TextureHelper11::getDesc(D3D11_TEXTURE3D_DESC *desc) const { - if (mTextureType == GL_TEXTURE_2D) - { - ASSERT(!mTexture3D); - D3D11_TEXTURE2D_DESC desc2D; - mTexture2D->GetDesc(&desc2D); + static_cast(mData->object)->GetDesc(desc); +} - mExtents.width = static_cast(desc2D.Width); - mExtents.height = static_cast(desc2D.Height); - mExtents.depth = 1; - mFormat = desc2D.Format; - mSampleCount = desc2D.SampleDesc.Count; - } - else - { - ASSERT(mTexture3D && mTextureType == GL_TEXTURE_3D); - D3D11_TEXTURE3D_DESC desc3D; - mTexture3D->GetDesc(&desc3D); +void TextureHelper11::initDesc(const D3D11_TEXTURE2D_DESC &desc2D) +{ + mData->resourceType = ResourceType::Texture2D; + mExtents.width = static_cast(desc2D.Width); + mExtents.height = static_cast(desc2D.Height); + mExtents.depth = 1; + mSampleCount = desc2D.SampleDesc.Count; +} - mExtents.width = static_cast(desc3D.Width); - mExtents.height = static_cast(desc3D.Height); - mExtents.depth = static_cast(desc3D.Depth); - mFormat = desc3D.Format; - mSampleCount = 1; - } +void TextureHelper11::initDesc(const D3D11_TEXTURE3D_DESC &desc3D) +{ + mData->resourceType = ResourceType::Texture3D; + mExtents.width = static_cast(desc3D.Width); + mExtents.height = static_cast(desc3D.Height); + mExtents.depth = static_cast(desc3D.Depth); + mSampleCount = 1; } -TextureHelper11::~TextureHelper11() +TextureHelper11 &TextureHelper11::operator=(TextureHelper11 &&other) { - SafeRelease(mTexture2D); - SafeRelease(mTexture3D); + std::swap(mData, other.mData); + std::swap(mExtents, other.mExtents); + std::swap(mFormatSet, other.mFormatSet); + std::swap(mSampleCount, other.mSampleCount); + return *this; } -ID3D11Resource *TextureHelper11::getResource() const +TextureHelper11 &TextureHelper11::operator=(const TextureHelper11 &other) { - return mTexture2D ? static_cast(mTexture2D) - : static_cast(mTexture3D); + mData = other.mData; + mExtents = other.mExtents; + mFormatSet = other.mFormatSet; + mSampleCount = other.mSampleCount; + return *this; } -TextureHelper11 &TextureHelper11::operator=(TextureHelper11 &&texture) +bool TextureHelper11::operator==(const TextureHelper11 &other) const { - SafeRelease(mTexture2D); - SafeRelease(mTexture3D); + return mData->object == other.mData->object; +} - mTextureType = texture.mTextureType; - mExtents = texture.mExtents; - mFormat = texture.mFormat; - mSampleCount = texture.mSampleCount; - mTexture2D = texture.mTexture2D; - mTexture3D = texture.mTexture3D; - texture.reset(); - return *this; +bool TextureHelper11::operator!=(const TextureHelper11 &other) const +{ + return mData->object != other.mData->object; +} + +bool UsePresentPathFast(const Renderer11 *renderer, + const gl::FramebufferAttachment *framebufferAttachment) +{ + if (framebufferAttachment == nullptr) + { + return false; + } + + return (framebufferAttachment->type() == GL_FRAMEBUFFER_DEFAULT && + renderer->presentPathFastEnabled()); } -void TextureHelper11::reset() +bool UsePrimitiveRestartWorkaround(bool primitiveRestartFixedIndexEnabled, GLenum type) { - mTextureType = GL_NONE; - mExtents = gl::Extents(); - mFormat = DXGI_FORMAT_UNKNOWN; - mSampleCount = 0; - mTexture2D = nullptr; - mTexture3D = nullptr; + // We should never have to deal with primitive restart workaround issue with GL_UNSIGNED_INT + // indices, since we restrict it via MAX_ELEMENT_INDEX. + return (!primitiveRestartFixedIndexEnabled && type == GL_UNSIGNED_SHORT); } -gl::ErrorOrResult CreateStagingTexture(GLenum textureType, - DXGI_FORMAT dxgiFormat, - const gl::Extents &size, - ID3D11Device *device) +bool IsStreamingIndexData(const gl::Context *context, GLenum srcType) { - if (textureType == GL_TEXTURE_2D) + const auto &glState = context->getGLState(); + gl::Buffer *glBuffer = glState.getVertexArray()->getElementArrayBuffer().get(); + + // Case 1: the indices are passed by pointer, which forces the streaming of index data + if (glBuffer == nullptr) { - D3D11_TEXTURE2D_DESC stagingDesc; - stagingDesc.Width = size.width; - stagingDesc.Height = size.height; - stagingDesc.MipLevels = 1; - stagingDesc.ArraySize = 1; - stagingDesc.Format = dxgiFormat; - 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; + return true; + } - ID3D11Texture2D *stagingTex = nullptr; - HRESULT result = device->CreateTexture2D(&stagingDesc, nullptr, &stagingTex); - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, "CreateStagingTextureFor failed, HRESULT: 0x%X.", - result); - } + bool primitiveRestartWorkaround = + UsePrimitiveRestartWorkaround(glState.isPrimitiveRestartEnabled(), srcType); + + BufferD3D *buffer = GetImplAs(glBuffer); + const GLenum dstType = (srcType == GL_UNSIGNED_INT || primitiveRestartWorkaround) + ? GL_UNSIGNED_INT + : GL_UNSIGNED_SHORT; - return TextureHelper11::MakeAndPossess2D(stagingTex); + // Case 2a: the buffer can be used directly + if (buffer->supportsDirectBinding() && dstType == srcType) + { + return false; } - ASSERT(textureType == GL_TEXTURE_3D); - D3D11_TEXTURE3D_DESC stagingDesc; - stagingDesc.Width = size.width; - stagingDesc.Height = size.height; - stagingDesc.Depth = 1; - stagingDesc.MipLevels = 1; - stagingDesc.Format = dxgiFormat; - stagingDesc.Usage = D3D11_USAGE_STAGING; - stagingDesc.BindFlags = 0; - stagingDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; - stagingDesc.MiscFlags = 0; + // Case 2b: use a static translated copy or fall back to streaming + StaticIndexBufferInterface *staticBuffer = buffer->getStaticIndexBuffer(); + if (staticBuffer == nullptr) + { + return true; + } - ID3D11Texture3D *stagingTex = nullptr; - HRESULT result = device->CreateTexture3D(&stagingDesc, nullptr, &stagingTex); - if (FAILED(result)) + if ((staticBuffer->getBufferSize() == 0) || (staticBuffer->getIndexType() != dstType)) { - return gl::Error(GL_OUT_OF_MEMORY, "CreateStagingTextureFor failed, HRESULT: 0x%X.", - result); + return true; } - return TextureHelper11::MakeAndPossess3D(stagingTex); + return false; } -bool UsePresentPathFast(const Renderer11 *renderer, - const gl::FramebufferAttachment *framebufferAttachment) +IndexStorageType ClassifyIndexStorage(const gl::State &glState, + const gl::Buffer *elementArrayBuffer, + GLenum elementType, + GLenum destElementType, + unsigned int offset, + bool *needsTranslation) { - if (framebufferAttachment == nullptr) + // No buffer bound means we are streaming from a client pointer. + if (!elementArrayBuffer || !IsOffsetAligned(elementType, offset)) { - return false; + *needsTranslation = true; + return IndexStorageType::Dynamic; } - return (framebufferAttachment->type() == GL_FRAMEBUFFER_DEFAULT && - renderer->presentPathFastEnabled()); + // The buffer can be used directly if the storage supports it and no translation needed. + BufferD3D *bufferD3D = GetImplAs(elementArrayBuffer); + if (bufferD3D->supportsDirectBinding() && destElementType == elementType) + { + *needsTranslation = false; + return IndexStorageType::Direct; + } + + // Use a static copy when available. + StaticIndexBufferInterface *staticBuffer = bufferD3D->getStaticIndexBuffer(); + if (staticBuffer != nullptr) + { + // Need to re-translate the static data if has never been used, or changed type. + *needsTranslation = + (staticBuffer->getBufferSize() == 0 || staticBuffer->getIndexType() != destElementType); + return IndexStorageType::Static; + } + + // Static buffer not available, fall back to streaming. + *needsTranslation = true; + return IndexStorageType::Dynamic; } } // namespace rx 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 index 4925a2d227..3af51bb0f6 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.h @@ -11,12 +11,16 @@ #define LIBANGLE_RENDERER_D3D_D3D11_RENDERER11_UTILS_H_ #include +#include #include -#include "libANGLE/angletypes.h" +#include "common/Color.h" + #include "libANGLE/Caps.h" #include "libANGLE/Error.h" #include "libANGLE/renderer/d3d/RendererD3D.h" +#include "libANGLE/renderer/d3d/d3d11/ResourceManager11.h" +#include "libANGLE/renderer/d3d/d3d11/texture_format_table.h" namespace gl { @@ -27,10 +31,10 @@ namespace rx { class Renderer11; class RenderTarget11; -struct WorkaroundsD3D; struct Renderer11DeviceCaps; -using RenderTargetArray = std::array; +using RenderTargetArray = std::array; +using RTVArray = std::array; namespace gl_d3d11 { @@ -39,7 +43,7 @@ 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_CULL_MODE ConvertCullMode(bool cullEnabled, gl::CullFaceMode cullMode); D3D11_COMPARISON_FUNC ConvertComparison(GLenum comparison); D3D11_DEPTH_WRITE_MASK ConvertDepthMask(bool depthWriteEnabled); @@ -48,9 +52,12 @@ D3D11_STENCIL_OP ConvertStencilOp(GLenum stencilOp); D3D11_FILTER ConvertFilter(GLenum minFilter, GLenum magFilter, float maxAnisotropy, GLenum comparisonMode); D3D11_TEXTURE_ADDRESS_MODE ConvertTextureWrap(GLenum wrap); +UINT ConvertMaxAnisotropy(float maxAnisotropy, D3D_FEATURE_LEVEL featureLevel); D3D11_QUERY ConvertQueryType(GLenum queryType); +UINT8 GetColorMask(const gl::InternalFormat &formatInfo); + } // namespace gl_d3d11 namespace d3d11_gl @@ -60,10 +67,12 @@ unsigned int GetReservedVertexUniformVectors(D3D_FEATURE_LEVEL featureLevel); unsigned int GetReservedFragmentUniformVectors(D3D_FEATURE_LEVEL featureLevel); -GLint GetMaximumClientVersion(D3D_FEATURE_LEVEL featureLevel); +gl::Version GetMaximumClientVersion(D3D_FEATURE_LEVEL featureLevel); void GenerateCaps(ID3D11Device *device, ID3D11DeviceContext *deviceContext, const Renderer11DeviceCaps &renderer11DeviceCaps, gl::Caps *caps, gl::TextureCapsMap *textureCapsMap, gl::Extensions *extensions, gl::Limitations *limitations); +void GetSamplePosition(GLsizei sampleCount, size_t index, GLfloat *xy); + } // namespace d3d11_gl namespace d3d11 @@ -108,32 +117,45 @@ struct PositionLayerTexCoord3DVertex void SetPositionLayerTexCoord3DVertex(PositionLayerTexCoord3DVertex* vertex, float x, float y, unsigned int layer, float u, float v, float s); -template -struct PositionDepthColorVertex +struct PositionVertex { - float x, y, z; - T r, g, b, a; + float x, y, z, w; }; -template -void SetPositionDepthColorVertex(PositionDepthColorVertex* vertex, float x, float y, float z, - const gl::Color &color) +struct BlendStateKey final { - 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; -} + // This will zero-initialize the struct, including padding. + BlendStateKey(); + + gl::BlendState blendState; + + // An int so struct size rounds nicely. + uint32_t rtvMax; + + uint8_t rtvMasks[D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT]; +}; + +bool operator==(const BlendStateKey &a, const BlendStateKey &b); +bool operator!=(const BlendStateKey &a, const BlendStateKey &b); + +struct RasterizerStateKey final +{ + // This will zero-initialize the struct, including padding. + RasterizerStateKey(); + + gl::RasterizerState rasterizerState; -HRESULT SetDebugName(ID3D11DeviceChild *resource, const char *name); + // Use a 32-bit int to round the struct nicely. + uint32_t scissorEnabled; +}; + +bool operator==(const RasterizerStateKey &a, const RasterizerStateKey &b); +bool operator!=(const RasterizerStateKey &a, const RasterizerStateKey &b); template outType* DynamicCastComObject(IUnknown* object) { - outType *outObject = NULL; + outType *outObject = nullptr; HRESULT result = object->QueryInterface(__uuidof(outType), reinterpret_cast(&outObject)); if (SUCCEEDED(result)) { @@ -142,7 +164,7 @@ outType* DynamicCastComObject(IUnknown* object) else { SafeRelease(outObject); - return NULL; + return nullptr; } } @@ -161,143 +183,63 @@ inline bool isDeviceLostError(HRESULT errorCode) } } -inline ID3D11VertexShader *CompileVS(ID3D11Device *device, const BYTE *byteCode, size_t N, const char *name) -{ - ID3D11VertexShader *vs = nullptr; - HRESULT result = device->CreateVertexShader(byteCode, N, nullptr, &vs); - ASSERT(SUCCEEDED(result)); - if (SUCCEEDED(result)) - { - SetDebugName(vs, name); - return vs; - } - return nullptr; -} - -template -ID3D11VertexShader *CompileVS(ID3D11Device *device, const BYTE (&byteCode)[N], const char *name) -{ - return CompileVS(device, byteCode, N, name); -} - -inline ID3D11GeometryShader *CompileGS(ID3D11Device *device, const BYTE *byteCode, size_t N, const char *name) -{ - ID3D11GeometryShader *gs = nullptr; - HRESULT result = device->CreateGeometryShader(byteCode, N, nullptr, &gs); - ASSERT(SUCCEEDED(result)); - if (SUCCEEDED(result)) - { - SetDebugName(gs, name); - return gs; - } - return nullptr; -} - -template -ID3D11GeometryShader *CompileGS(ID3D11Device *device, const BYTE (&byteCode)[N], const char *name) +template +class LazyResource : angle::NonCopyable { - return CompileGS(device, byteCode, N, name); -} + public: + constexpr LazyResource() : mResource() {} + virtual ~LazyResource() {} -inline ID3D11PixelShader *CompilePS(ID3D11Device *device, const BYTE *byteCode, size_t N, const char *name) -{ - ID3D11PixelShader *ps = nullptr; - HRESULT result = device->CreatePixelShader(byteCode, N, nullptr, &ps); - ASSERT(SUCCEEDED(result)); - if (SUCCEEDED(result)) + virtual gl::Error resolve(Renderer11 *renderer) = 0; + void reset() { mResource.reset(); } + GetD3D11Type *get() const { - SetDebugName(ps, name); - return ps; + ASSERT(mResource.valid()); + return mResource.get(); } - return nullptr; -} - -template -ID3D11PixelShader *CompilePS(ID3D11Device *device, const BYTE (&byteCode)[N], const char *name) -{ - return CompilePS(device, byteCode, N, name); -} - -template -class LazyResource : public angle::NonCopyable -{ - public: - LazyResource() : mResource(nullptr), mAssociatedDevice(nullptr) {} - virtual ~LazyResource() { release(); } - virtual ResourceType *resolve(ID3D11Device *device) = 0; - void release() { SafeRelease(mResource); } + const Resource11> &getObj() const { return mResource; } protected: - void checkAssociatedDevice(ID3D11Device *device); + LazyResource(LazyResource &&other) : mResource(std::move(other.mResource)) {} - ResourceType *mResource; - ID3D11Device *mAssociatedDevice; -}; + // Specialized in the cpp file to avoid MSVS/Clang specific code. + gl::Error resolveImpl(Renderer11 *renderer, + const GetDescType &desc, + GetInitDataType *initData, + const char *name); -template -void LazyResource::checkAssociatedDevice(ID3D11Device *device) -{ - ASSERT(mAssociatedDevice == nullptr || device == mAssociatedDevice); - mAssociatedDevice = device; -} + Resource11> mResource; +}; template -class LazyShader final : public LazyResource +class LazyShader final : public LazyResource()> { public: // All parameters must be constexpr. Not supported in VS2013. - LazyShader(const BYTE *byteCode, - size_t byteCodeSize, - const char *name) - : mByteCode(byteCode), - mByteCodeSize(byteCodeSize), - mName(name) + constexpr LazyShader(const BYTE *byteCode, size_t byteCodeSize, const char *name) + : mByteCode(byteCode, byteCodeSize), mName(name) { } - D3D11ShaderType *resolve(ID3D11Device *device) override; - - private: - const BYTE *mByteCode; - size_t mByteCodeSize; - const char *mName; -}; - -template <> -inline ID3D11VertexShader *LazyShader::resolve(ID3D11Device *device) -{ - checkAssociatedDevice(device); - if (mResource == nullptr) + constexpr LazyShader(LazyShader &&shader) + : LazyResource()>(std::move(shader)), + mByteCode(std::move(shader.mByteCode)), + mName(shader.mName) { - mResource = CompileVS(device, mByteCode, mByteCodeSize, mName); } - return mResource; -} -template <> -inline ID3D11GeometryShader *LazyShader::resolve(ID3D11Device *device) -{ - checkAssociatedDevice(device); - if (mResource == nullptr) + gl::Error resolve(Renderer11 *renderer) override { - mResource = CompileGS(device, mByteCode, mByteCodeSize, mName); + return this->resolveImpl(renderer, mByteCode, nullptr, mName); } - return mResource; -} -template <> -inline ID3D11PixelShader *LazyShader::resolve(ID3D11Device *device) -{ - checkAssociatedDevice(device); - if (mResource == nullptr) - { - mResource = CompilePS(device, mByteCode, mByteCodeSize, mName); - } - return mResource; -} + private: + ShaderData mByteCode; + const char *mName; +}; -class LazyInputLayout final : public LazyResource +class LazyInputLayout final : public LazyResource { public: LazyInputLayout(const D3D11_INPUT_ELEMENT_DESC *inputDesc, @@ -305,22 +247,22 @@ class LazyInputLayout final : public LazyResource const BYTE *byteCode, size_t byteCodeLen, const char *debugName); + ~LazyInputLayout() override; - ID3D11InputLayout *resolve(ID3D11Device *device) override; + gl::Error resolve(Renderer11 *renderer) override; private: - std::vector mInputDesc; - size_t mByteCodeLen; - const BYTE *mByteCode; + InputElementArray mInputDesc; + ShaderData mByteCode; const char *mDebugName; }; -class LazyBlendState final : public LazyResource +class LazyBlendState final : public LazyResource { public: LazyBlendState(const D3D11_BLEND_DESC &desc, const char *debugName); - ID3D11BlendState *resolve(ID3D11Device *device) override; + gl::Error resolve(Renderer11 *renderer) override; private: D3D11_BLEND_DESC mDesc; @@ -342,48 +284,147 @@ void SetBufferData(ID3D11DeviceContext *context, ID3D11Buffer *constantBuffer, c } } -WorkaroundsD3D GenerateWorkarounds(D3D_FEATURE_LEVEL featureLevel); +angle::WorkaroundsD3D GenerateWorkarounds(const Renderer11DeviceCaps &deviceCaps, + const DXGI_ADAPTER_DESC &adapterDesc); + +enum ReservedConstantBufferSlot +{ + RESERVED_CONSTANT_BUFFER_SLOT_DEFAULT_UNIFORM_BLOCK = 0, + RESERVED_CONSTANT_BUFFER_SLOT_DRIVER = 1, + + RESERVED_CONSTANT_BUFFER_SLOT_COUNT = 2 +}; + +void InitConstantBufferDesc(D3D11_BUFFER_DESC *constantBufferDescription, size_t byteWidth); } // namespace d3d11 +struct GenericData +{ + GenericData() {} + ~GenericData() + { + if (object) + { + // We can have a nullptr factory when holding passed-in resources. + if (manager) + { + manager->onReleaseGeneric(resourceType, object); + manager = nullptr; + } + object->Release(); + object = nullptr; + } + } + + ResourceType resourceType = ResourceType::Last; + ID3D11Resource *object = nullptr; + ResourceManager11 *manager = nullptr; +}; + // A helper class which wraps a 2D or 3D texture. -class TextureHelper11 : angle::NonCopyable +class TextureHelper11 : public Resource11Base { public: TextureHelper11(); - TextureHelper11(TextureHelper11 &&toCopy); - ~TextureHelper11(); - TextureHelper11 &operator=(TextureHelper11 &&texture); - - static TextureHelper11 MakeAndReference(ID3D11Resource *genericResource); - static TextureHelper11 MakeAndPossess2D(ID3D11Texture2D *texToOwn); - static TextureHelper11 MakeAndPossess3D(ID3D11Texture3D *texToOwn); - - GLenum getTextureType() const { return mTextureType; } + TextureHelper11(TextureHelper11 &&other); + TextureHelper11(const TextureHelper11 &other); + ~TextureHelper11() override; + TextureHelper11 &operator=(TextureHelper11 &&other); + TextureHelper11 &operator=(const TextureHelper11 &other); + + bool is2D() const { return mData->resourceType == ResourceType::Texture2D; } + bool is3D() const { return mData->resourceType == ResourceType::Texture3D; } + ResourceType getTextureType() const { return mData->resourceType; } gl::Extents getExtents() const { return mExtents; } - DXGI_FORMAT getFormat() const { return mFormat; } + DXGI_FORMAT getFormat() const { return mFormatSet->texFormat; } + const d3d11::Format &getFormatSet() const { return *mFormatSet; } int getSampleCount() const { return mSampleCount; } - ID3D11Texture2D *getTexture2D() const { return mTexture2D; } - ID3D11Texture3D *getTexture3D() const { return mTexture3D; } - ID3D11Resource *getResource() const; + + template + void init(Resource11 &&texture, const DescT &desc, const d3d11::Format &format) + { + std::swap(mData->manager, texture.mData->manager); + + // Can't use std::swap because texture is typed, and here we use ID3D11Resource. + ID3D11Resource *temp = mData->object; + mData->object = texture.mData->object; + texture.mData->object = static_cast(temp); + + mFormatSet = &format; + initDesc(desc); + } + + template + void set(ResourceT *object, const d3d11::Format &format) + { + ASSERT(!valid()); + mFormatSet = &format; + mData->object = object; + mData->manager = nullptr; + + GetDescFromD3D11 desc; + getDesc(&desc); + initDesc(desc); + } + + bool operator==(const TextureHelper11 &other) const; + bool operator!=(const TextureHelper11 &other) const; + + void getDesc(D3D11_TEXTURE2D_DESC *desc) const; + void getDesc(D3D11_TEXTURE3D_DESC *desc) const; private: - void reset(); - void initDesc(); + void initDesc(const D3D11_TEXTURE2D_DESC &desc2D); + void initDesc(const D3D11_TEXTURE3D_DESC &desc3D); - GLenum mTextureType; + const d3d11::Format *mFormatSet; gl::Extents mExtents; - DXGI_FORMAT mFormat; int mSampleCount; - ID3D11Texture2D *mTexture2D; - ID3D11Texture3D *mTexture3D; }; -gl::ErrorOrResult CreateStagingTexture(GLenum textureType, - DXGI_FORMAT dxgiFormat, - const gl::Extents &size, - ID3D11Device *device); +enum class StagingAccess +{ + READ, + READ_WRITE, +}; bool UsePresentPathFast(const Renderer11 *renderer, const gl::FramebufferAttachment *colorbuffer); +bool UsePrimitiveRestartWorkaround(bool primitiveRestartFixedIndexEnabled, GLenum type); +bool IsStreamingIndexData(const gl::Context *context, GLenum srcType); + +enum class IndexStorageType +{ + // Dynamic indexes are re-streamed every frame. They come from a client data pointer or + // from buffers that are updated frequently. + Dynamic, + + // Static indexes are translated from the original storage once, and re-used multiple times. + Static, + + // Direct indexes are never transated and are used directly from the source buffer. They are + // the fastest available path. + Direct, + + // Not a real storage type. + Invalid, +}; + +IndexStorageType ClassifyIndexStorage(const gl::State &glState, + const gl::Buffer *elementArrayBuffer, + GLenum elementType, + GLenum destElementType, + unsigned int offset, + bool *needsTranslation); + +// Used for state change notifications between buffers and vertex arrays. +using OnBufferDataDirtyBinding = angle::ChannelBinding; +using OnBufferDataDirtyChannel = angle::BroadcastChannel; +using OnBufferDataDirtyReceiver = angle::SignalReceiver; + +// Used for state change notifications between RenderTarget11 and Framebuffer11. +using OnRenderTargetDirtyBinding = angle::ChannelBinding; +using OnRenderTargetDirtyChannel = angle::BroadcastChannel; +using OnRenderTargetDirtyReceiver = angle::SignalReceiver; } // namespace rx 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 index 2b3e1ebe4c..48f5b427ec 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/shaders/Clear11.hlsl +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/shaders/Clear11.hlsl @@ -1,13 +1,152 @@ -// Assume we are in SM4+, which has 8 color outputs +// +// Copyright (c) 2017 The ANGLE Project. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// -void VS_ClearFloat( in float3 inPosition : POSITION, in float4 inColor : COLOR, - out float4 outPosition : SV_POSITION, out float4 outColor : COLOR) +// Clear11.hlsl: Shaders for clearing RTVs and DSVs using draw calls and +// specifying float depth values and either float, uint or sint clear colors. +// Notes: +// - UINT & SINT clears can only be compiled with FL10+ +// - VS_Clear_FL9 requires a VB to be bound with vertices to create +// a primitive covering the entire surface (in clip co-ordinates) + +// Constants +static const float2 g_Corners[6] = +{ + float2(-1.0f, 1.0f), + float2( 1.0f, -1.0f), + float2(-1.0f, -1.0f), + float2(-1.0f, 1.0f), + float2( 1.0f, 1.0f), + float2( 1.0f, -1.0f), +}; + +// Vertex Shaders +void VS_Clear(in uint id : SV_VertexID, + out float4 outPosition : SV_POSITION) +{ + float2 corner = g_Corners[id]; + outPosition = float4(corner.x, corner.y, 0.0f, 1.0f); +} + +void VS_Multiview_Clear(in uint id : SV_VertexID, + in uint instanceID : SV_InstanceID, + out float4 outPosition : SV_POSITION, + out uint outLayerID : TEXCOORD0) +{ + float2 corner = g_Corners[id]; + outPosition = float4(corner.x, corner.y, 0.0f, 1.0f); + outLayerID = instanceID; +} + +void VS_Clear_FL9( in float4 inPosition : POSITION, + out float4 outPosition : SV_POSITION) +{ + outPosition = inPosition; +} + +// Geometry shader for clearing multiview layered textures +struct GS_INPUT +{ + float4 inPosition : SV_Position; + uint inLayerID : TEXCOORD0; +}; + +struct GS_OUTPUT { - outPosition = float4(inPosition, 1.0f); - outColor = inColor; + float4 outPosition : SV_Position; + uint outLayerID : SV_RenderTargetArrayIndex; +}; + +[maxvertexcount(3)] +void GS_Multiview_Clear(triangle GS_INPUT input[3], inout TriangleStream outStream) +{ + GS_OUTPUT output = (GS_OUTPUT)0; + for (int i = 0; i < 3; i++) + { + output.outPosition = input[i].inPosition; + output.outLayerID = input[i].inLayerID; + outStream.Append(output); + } + outStream.RestartStrip(); +} + +// Pixel Shader Constant Buffers +cbuffer ColorAndDepthDataFloat : register(b0) +{ + float4 color_Float : packoffset(c0); + float zValueF_Float : packoffset(c1); +} + +cbuffer ColorAndDepthDataSint : register(b0) +{ + int4 color_Sint : packoffset(c0); + float zValueF_Sint : packoffset(c1); +} + +cbuffer ColorAndDepthDataUint : register(b0) +{ + uint4 color_Uint : packoffset(c0); + float zValueF_Uint : packoffset(c1); } -struct PS_OutputFloat +cbuffer DepthOnlyData : register(b0) +{ + float zValue_Depth : packoffset(c1); +} + +// Pixel Shader Output Structs +struct PS_OutputFloat_FL9 +{ + float4 color0 : SV_TARGET0; + float4 color1 : SV_TARGET1; + float4 color2 : SV_TARGET2; + float4 color3 : SV_TARGET3; + float depth : SV_DEPTH; +}; + +struct PS_OutputFloat1 +{ + float4 color0 : SV_TARGET0; + float depth : SV_DEPTH; +}; + +struct PS_OutputFloat2 +{ + float4 color0 : SV_TARGET0; + float4 color1 : SV_TARGET1; + float depth : SV_DEPTH; +}; + +struct PS_OutputFloat3 +{ + float4 color0 : SV_TARGET0; + float4 color1 : SV_TARGET1; + float4 color2 : SV_TARGET2; + float depth : SV_DEPTH; +}; + +struct PS_OutputFloat4 +{ + float4 color0 : SV_TARGET0; + float4 color1 : SV_TARGET1; + float4 color2 : SV_TARGET2; + float4 color3 : SV_TARGET3; + float depth : SV_DEPTH; +}; + +struct PS_OutputFloat5 +{ + float4 color0 : SV_TARGET0; + float4 color1 : SV_TARGET1; + float4 color2 : SV_TARGET2; + float4 color3 : SV_TARGET3; + float4 color4 : SV_TARGET4; + float depth : SV_DEPTH; +}; + +struct PS_OutputFloat6 { float4 color0 : SV_TARGET0; float4 color1 : SV_TARGET1; @@ -15,50 +154,98 @@ struct PS_OutputFloat float4 color3 : SV_TARGET3; float4 color4 : SV_TARGET4; float4 color5 : SV_TARGET5; - float4 color6 : SV_TARGET6; - float4 color7 : SV_TARGET7; + float depth : SV_DEPTH; }; -PS_OutputFloat PS_ClearFloat(in float4 inPosition : SV_POSITION, in float4 inColor : COLOR) +struct PS_OutputFloat7 { - 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; -} + 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; + float depth : SV_DEPTH; +}; -struct PS_OutputFloat_FL9 +struct PS_OutputFloat8 { 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; + float depth : SV_DEPTH; }; -PS_OutputFloat_FL9 PS_ClearFloat_FL9(in float4 inPosition : SV_POSITION, in float4 inColor : COLOR) +struct PS_OutputUint1 { - PS_OutputFloat_FL9 outColor; - outColor.color0 = inColor; - outColor.color1 = inColor; - outColor.color2 = inColor; - outColor.color3 = inColor; - return outColor; -} + uint4 color0 : SV_TARGET0; + float depth : SV_DEPTH; +}; -void VS_ClearUint( in float3 inPosition : POSITION, in uint4 inColor : COLOR, - out float4 outPosition : SV_POSITION, out uint4 outColor : COLOR) +struct PS_OutputUint2 { - outPosition = float4(inPosition, 1.0f); - outColor = inColor; -} + uint4 color0 : SV_TARGET0; + uint4 color1 : SV_TARGET1; + float depth : SV_DEPTH; +}; + +struct PS_OutputUint3 +{ + uint4 color0 : SV_TARGET0; + uint4 color1 : SV_TARGET1; + uint4 color2 : SV_TARGET2; + float depth : SV_DEPTH; +}; + +struct PS_OutputUint4 +{ + uint4 color0 : SV_TARGET0; + uint4 color1 : SV_TARGET1; + uint4 color2 : SV_TARGET2; + uint4 color3 : SV_TARGET3; + float depth : SV_DEPTH; +}; + +struct PS_OutputUint5 +{ + uint4 color0 : SV_TARGET0; + uint4 color1 : SV_TARGET1; + uint4 color2 : SV_TARGET2; + uint4 color3 : SV_TARGET3; + uint4 color4 : SV_TARGET4; + float depth : SV_DEPTH; +}; + +struct PS_OutputUint6 +{ + uint4 color0 : SV_TARGET0; + uint4 color1 : SV_TARGET1; + uint4 color2 : SV_TARGET2; + uint4 color3 : SV_TARGET3; + uint4 color4 : SV_TARGET4; + uint4 color5 : SV_TARGET5; + float depth : SV_DEPTH; +}; + +struct PS_OutputUint7 +{ + 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; + float depth : SV_DEPTH; +}; -struct PS_OutputUint +struct PS_OutputUint8 { uint4 color0 : SV_TARGET0; uint4 color1 : SV_TARGET1; @@ -68,31 +255,73 @@ struct PS_OutputUint uint4 color5 : SV_TARGET5; uint4 color6 : SV_TARGET6; uint4 color7 : SV_TARGET7; + float depth : SV_DEPTH; }; -PS_OutputUint PS_ClearUint(in float4 inPosition : SV_POSITION, in uint4 inColor : COLOR) +struct PS_OutputSint1 { - 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; -} + int4 color0 : SV_TARGET0; + float depth : SV_DEPTH; +}; +struct PS_OutputSint2 +{ + int4 color0 : SV_TARGET0; + int4 color1 : SV_TARGET1; + float depth : SV_DEPTH; +}; -void VS_ClearSint( in float3 inPosition : POSITION, in int4 inColor : COLOR, - out float4 outPosition : SV_POSITION, out int4 outColor : COLOR) +struct PS_OutputSint3 { - outPosition = float4(inPosition, 1.0f); - outColor = inColor; -} + int4 color0 : SV_TARGET0; + int4 color1 : SV_TARGET1; + int4 color2 : SV_TARGET2; + float depth : SV_DEPTH; +}; + +struct PS_OutputSint4 +{ + int4 color0 : SV_TARGET0; + int4 color1 : SV_TARGET1; + int4 color2 : SV_TARGET2; + int4 color3 : SV_TARGET3; + float depth : SV_DEPTH; +}; + +struct PS_OutputSint5 +{ + int4 color0 : SV_TARGET0; + int4 color1 : SV_TARGET1; + int4 color2 : SV_TARGET2; + int4 color3 : SV_TARGET3; + int4 color4 : SV_TARGET4; + float depth : SV_DEPTH; +}; + +struct PS_OutputSint6 +{ + int4 color0 : SV_TARGET0; + int4 color1 : SV_TARGET1; + int4 color2 : SV_TARGET2; + int4 color3 : SV_TARGET3; + int4 color4 : SV_TARGET4; + int4 color5 : SV_TARGET5; + float depth : SV_DEPTH; +}; + +struct PS_OutputSint7 +{ + 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; + float depth : SV_DEPTH; +}; -struct PS_OutputSint +struct PS_OutputSint8 { int4 color0 : SV_TARGET0; int4 color1 : SV_TARGET1; @@ -102,18 +331,305 @@ struct PS_OutputSint int4 color5 : SV_TARGET5; int4 color6 : SV_TARGET6; int4 color7 : SV_TARGET7; + float depth : SV_DEPTH; +}; + +struct PS_OutputDepth +{ + float depth : SV_DEPTH; }; -PS_OutputSint PS_ClearSint(in float4 inPosition : SV_POSITION, in int4 inColor : COLOR) +// Pixel Shaders +PS_OutputFloat_FL9 PS_ClearFloat_FL9(in float4 inPosition : SV_POSITION) +{ + PS_OutputFloat_FL9 outData; + outData.color0 = color_Float; + outData.color1 = color_Float; + outData.color2 = color_Float; + outData.color3 = color_Float; + outData.depth = zValueF_Float; + return outData; +} + +PS_OutputFloat1 PS_ClearFloat1(in float4 inPosition : SV_POSITION) +{ + PS_OutputFloat1 outData; + outData.color0 = color_Float; + outData.depth = zValueF_Float; + return outData; +} + +PS_OutputFloat2 PS_ClearFloat2(in float4 inPosition : SV_POSITION) +{ + PS_OutputFloat2 outData; + outData.color0 = color_Float; + outData.color1 = color_Float; + outData.depth = zValueF_Float; + return outData; +} + +PS_OutputFloat3 PS_ClearFloat3(in float4 inPosition : SV_POSITION) +{ + PS_OutputFloat3 outData; + outData.color0 = color_Float; + outData.color1 = color_Float; + outData.color2 = color_Float; + outData.depth = zValueF_Float; + return outData; +} + +PS_OutputFloat4 PS_ClearFloat4(in float4 inPosition : SV_POSITION) +{ + PS_OutputFloat4 outData; + outData.color0 = color_Float; + outData.color1 = color_Float; + outData.color2 = color_Float; + outData.color3 = color_Float; + outData.depth = zValueF_Float; + return outData; +} + +PS_OutputFloat5 PS_ClearFloat5(in float4 inPosition : SV_POSITION) +{ + PS_OutputFloat5 outData; + outData.color0 = color_Float; + outData.color1 = color_Float; + outData.color2 = color_Float; + outData.color3 = color_Float; + outData.color4 = color_Float; + outData.depth = zValueF_Float; + return outData; +} + +PS_OutputFloat6 PS_ClearFloat6(in float4 inPosition : SV_POSITION) +{ + PS_OutputFloat6 outData; + outData.color0 = color_Float; + outData.color1 = color_Float; + outData.color2 = color_Float; + outData.color3 = color_Float; + outData.color4 = color_Float; + outData.color5 = color_Float; + outData.depth = zValueF_Float; + return outData; +} + +PS_OutputFloat7 PS_ClearFloat7(in float4 inPosition : SV_POSITION) +{ + PS_OutputFloat7 outData; + outData.color0 = color_Float; + outData.color1 = color_Float; + outData.color2 = color_Float; + outData.color3 = color_Float; + outData.color4 = color_Float; + outData.color5 = color_Float; + outData.color6 = color_Float; + outData.depth = zValueF_Float; + return outData; +} + +PS_OutputFloat8 PS_ClearFloat8(in float4 inPosition : SV_POSITION) +{ + PS_OutputFloat8 outData; + outData.color0 = color_Float; + outData.color1 = color_Float; + outData.color2 = color_Float; + outData.color3 = color_Float; + outData.color4 = color_Float; + outData.color5 = color_Float; + outData.color6 = color_Float; + outData.color7 = color_Float; + outData.depth = zValueF_Float; + return outData; +} + +PS_OutputUint1 PS_ClearUint1(in float4 inPosition : SV_POSITION) +{ + PS_OutputUint1 outData; + outData.color0 = color_Uint; + outData.depth = zValueF_Uint; + return outData; +} + +PS_OutputUint2 PS_ClearUint2(in float4 inPosition : SV_POSITION) +{ + PS_OutputUint2 outData; + outData.color0 = color_Uint; + outData.color1 = color_Uint; + outData.depth = zValueF_Uint; + return outData; +} + +PS_OutputUint3 PS_ClearUint3(in float4 inPosition : SV_POSITION) +{ + PS_OutputUint3 outData; + outData.color0 = color_Uint; + outData.color1 = color_Uint; + outData.color2 = color_Uint; + outData.depth = zValueF_Uint; + return outData; +} + +PS_OutputUint4 PS_ClearUint4(in float4 inPosition : SV_POSITION) +{ + PS_OutputUint4 outData; + outData.color0 = color_Uint; + outData.color1 = color_Uint; + outData.color2 = color_Uint; + outData.color3 = color_Uint; + outData.depth = zValueF_Uint; + return outData; +} + +PS_OutputUint5 PS_ClearUint5(in float4 inPosition : SV_POSITION) +{ + PS_OutputUint5 outData; + outData.color0 = color_Uint; + outData.color1 = color_Uint; + outData.color2 = color_Uint; + outData.color3 = color_Uint; + outData.color4 = color_Uint; + outData.depth = zValueF_Uint; + return outData; +} + +PS_OutputUint6 PS_ClearUint6(in float4 inPosition : SV_POSITION) +{ + PS_OutputUint6 outData; + outData.color0 = color_Uint; + outData.color1 = color_Uint; + outData.color2 = color_Uint; + outData.color3 = color_Uint; + outData.color4 = color_Uint; + outData.color5 = color_Uint; + outData.depth = zValueF_Uint; + return outData; +} + +PS_OutputUint7 PS_ClearUint7(in float4 inPosition : SV_POSITION) +{ + PS_OutputUint7 outData; + outData.color0 = color_Uint; + outData.color1 = color_Uint; + outData.color2 = color_Uint; + outData.color3 = color_Uint; + outData.color4 = color_Uint; + outData.color5 = color_Uint; + outData.color6 = color_Uint; + outData.depth = zValueF_Uint; + return outData; +} + +PS_OutputUint8 PS_ClearUint8(in float4 inPosition : SV_POSITION) +{ + PS_OutputUint8 outData; + outData.color0 = color_Uint; + outData.color1 = color_Uint; + outData.color2 = color_Uint; + outData.color3 = color_Uint; + outData.color4 = color_Uint; + outData.color5 = color_Uint; + outData.color6 = color_Uint; + outData.color7 = color_Uint; + outData.depth = zValueF_Uint; + return outData; +} + +PS_OutputSint1 PS_ClearSint1(in float4 inPosition : SV_POSITION) +{ + PS_OutputSint1 outData; + outData.color0 = color_Sint; + outData.depth = zValueF_Sint; + return outData; +} + +PS_OutputSint2 PS_ClearSint2(in float4 inPosition : SV_POSITION) +{ + PS_OutputSint2 outData; + outData.color0 = color_Sint; + outData.color1 = color_Sint; + outData.depth = zValueF_Sint; + return outData; +} + +PS_OutputSint3 PS_ClearSint3(in float4 inPosition : SV_POSITION) +{ + PS_OutputSint3 outData; + outData.color0 = color_Sint; + outData.color1 = color_Sint; + outData.color2 = color_Sint; + outData.depth = zValueF_Sint; + return outData; +} + +PS_OutputSint4 PS_ClearSint4(in float4 inPosition : SV_POSITION) +{ + PS_OutputSint4 outData; + outData.color0 = color_Sint; + outData.color1 = color_Sint; + outData.color2 = color_Sint; + outData.color3 = color_Sint; + outData.depth = zValueF_Sint; + return outData; +} + +PS_OutputSint5 PS_ClearSint5(in float4 inPosition : SV_POSITION) +{ + PS_OutputSint5 outData; + outData.color0 = color_Sint; + outData.color1 = color_Sint; + outData.color2 = color_Sint; + outData.color3 = color_Sint; + outData.color4 = color_Sint; + outData.depth = zValueF_Sint; + return outData; +} + +PS_OutputSint6 PS_ClearSint6(in float4 inPosition : SV_POSITION) +{ + PS_OutputSint6 outData; + outData.color0 = color_Sint; + outData.color1 = color_Sint; + outData.color2 = color_Sint; + outData.color3 = color_Sint; + outData.color4 = color_Sint; + outData.color5 = color_Sint; + outData.depth = zValueF_Sint; + return outData; +} + +PS_OutputSint7 PS_ClearSint7(in float4 inPosition : SV_POSITION) +{ + PS_OutputSint7 outData; + outData.color0 = color_Sint; + outData.color1 = color_Sint; + outData.color2 = color_Sint; + outData.color3 = color_Sint; + outData.color4 = color_Sint; + outData.color5 = color_Sint; + outData.color6 = color_Sint; + outData.depth = zValueF_Sint; + return outData; +} + +PS_OutputSint8 PS_ClearSint8(in float4 inPosition : SV_POSITION) +{ + PS_OutputSint8 outData; + outData.color0 = color_Sint; + outData.color1 = color_Sint; + outData.color2 = color_Sint; + outData.color3 = color_Sint; + outData.color4 = color_Sint; + outData.color5 = color_Sint; + outData.color6 = color_Sint; + outData.color7 = color_Sint; + outData.depth = zValueF_Sint; + return outData; +} + +PS_OutputDepth PS_ClearDepth(in float4 inPosition : SV_POSITION) { - 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; + PS_OutputDepth outData; + outData.depth = zValue_Depth; + return outData; } diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/shaders/MultiplyAlpha.hlsl b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/shaders/MultiplyAlpha.hlsl new file mode 100644 index 0000000000..0d10b8eafa --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/shaders/MultiplyAlpha.hlsl @@ -0,0 +1,131 @@ +Texture2D TextureF : register(t0); +Texture2D TextureUI : register(t0); + +SamplerState Sampler : register(s0); + +// Notation: +// PM: premultiply, UM: unmulitply, PT: passthrough +// F: float, U: uint + +// Float to float LUMA +float4 PS_FtoF_PM_LUMA(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + float4 color = TextureF.Sample(Sampler, inTexCoord).rgba; + color.rgb = color.r * color.a; + color.a = 1.0f; + return color; +} +float4 PS_FtoF_UM_LUMA(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + float4 color = TextureF.Sample(Sampler, inTexCoord).rgba; + if (color.a > 0.0f) + { + color.rgb = color.r / color.a; + } + color.a = 1.0f; + return color; +} + +// Float to float LUMAALPHA +float4 PS_FtoF_PM_LUMAALPHA(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + float4 color = TextureF.Sample(Sampler, inTexCoord).rgba; + color.rgb = color.r * color.a; + return color; +} + +float4 PS_FtoF_UM_LUMAALPHA(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + float4 color = TextureF.Sample(Sampler, inTexCoord).rgba; + if (color.a > 0.0f) + { + color.rgb = color.r / color.a; + } + return color; +} + +// Float to float RGBA +float4 PS_FtoF_PM_RGBA(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + float4 color = TextureF.Sample(Sampler, inTexCoord).rgba; + color.rgb *= color.a; + return color; +} + +float4 PS_FtoF_UM_RGBA(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + float4 color = TextureF.Sample(Sampler, inTexCoord).rgba; + if (color.a > 0.0f) + { + color.rgb /= color.a; + } + return color; +} + +// Float to float RGB +float4 PS_FtoF_PM_RGB(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + float4 color = TextureF.Sample(Sampler, inTexCoord).rgba; + color.rgb *= color.a; + color.a = 1.0f; + return color; +} + +float4 PS_FtoF_UM_RGB(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + float4 color = TextureF.Sample(Sampler, inTexCoord).rgba; + if (color.a > 0.0f) + { + color.rgb /= color.a; + } + color.a = 1.0f; + return color; +} + +// Float to uint RGBA +uint4 PS_FtoU_PT_RGBA(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + float4 color = TextureF.Sample(Sampler, inTexCoord).rgba; + return uint4(color * 255); +} + +uint4 PS_FtoU_PM_RGBA(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + float4 color = TextureF.Sample(Sampler, inTexCoord).rgba; + color.rgb *= color.a; + return uint4(color * 255); +} + +uint4 PS_FtoU_UM_RGBA(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + float4 color = TextureF.Sample(Sampler, inTexCoord).rgba; + if (color.a > 0.0f) + { + color.rgb /= color.a; + } + return uint4(color * 255); +} + +// Float to uint RGB +uint4 PS_FtoU_PT_RGB(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + float4 color = TextureF.Sample(Sampler, inTexCoord).rgba; + return uint4(color.rgb * 255, 1); +} + +uint4 PS_FtoU_PM_RGB(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + float4 color = TextureF.Sample(Sampler, inTexCoord).rgba; + color.rgb *= color.a; + return uint4(color.rgb * 255, 1); +} + +uint4 PS_FtoU_UM_RGB(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + float4 color = TextureF.Sample(Sampler, inTexCoord).rgba; + if (color.a > 0.0f) + { + color.rgb /= color.a; + } + return uint4(color.rgb * 255, 1); +} 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 index 8671c39fb7..0b1a5ad169 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/shaders/Passthrough2D11.hlsl +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/shaders/Passthrough2D11.hlsl @@ -1,4 +1,5 @@ Texture2D TextureF : register(t0); +Texture2DMS TextureF_MS: register(t0); Texture2D TextureUI : register(t0); Texture2D TextureI : register(t0); @@ -21,6 +22,16 @@ float4 PS_PassthroughRGBA2D(in float4 inPosition : SV_POSITION, in float2 inTexC return TextureF.Sample(Sampler, inTexCoord).rgba; } +float4 PS_PassthroughA2D(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + return float4(0.0f, 0.0f, 0.0f, TextureF.Sample(Sampler, inTexCoord).a); +} + +float4 PS_PassthroughRGBA2DMS(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCORD0, in uint inSampleIndex : SV_SAMPLEINDEX) : SV_TARGET0 +{ + return TextureF_MS.sample[inSampleIndex][inTexCoord].rgba; +} + uint4 PS_PassthroughRGBA2DUI(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 { uint2 size; diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/shaders/ResolveDepthStencil.hlsl b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/shaders/ResolveDepthStencil.hlsl new file mode 100644 index 0000000000..7dc40d4b6a --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/shaders/ResolveDepthStencil.hlsl @@ -0,0 +1,56 @@ +static const float2 g_Corners[6] = +{ + float2(-1.0f, 1.0f), + float2( 1.0f, -1.0f), + float2(-1.0f, -1.0f), + float2(-1.0f, 1.0f), + float2( 1.0f, 1.0f), + float2( 1.0f, -1.0f), +}; + +void VS_ResolveDepthStencil(in uint id : SV_VertexID, + out float4 position : SV_Position, + out float2 texCoord : TEXCOORD0) +{ + float2 corner = g_Corners[id]; + position = float4(corner.x, corner.y, 0.0f, 1.0f); + texCoord = float2((corner.x + 1.0f) * 0.5f, (-corner.y + 1.0f) * 0.5f); +} + +Texture2DMS Depth : register(t0); +Texture2DMS Stencil : register(t1); + +void PS_ResolveDepth(in float4 position : SV_Position, + in float2 texCoord : TEXCOORD0, + out float depth : SV_Depth) +{ + // MS samplers must use Load + uint width, height, samples; + Depth.GetDimensions(width, height, samples); + uint2 coord = uint2(texCoord.x * float(width), texCoord.y * float(height)); + depth = Depth.Load(coord, 0).r; +} + +void PS_ResolveDepthStencil(in float4 position : SV_Position, + in float2 texCoord : TEXCOORD0, + out float2 depthStencil : SV_Target0) +{ + // MS samplers must use Load + uint width, height, samples; + Depth.GetDimensions(width, height, samples); + uint2 coord = uint2(texCoord.x * float(width), texCoord.y * float(height)); + depthStencil.r = Depth.Load(coord, 0).r; + depthStencil.g = float(Stencil.Load(coord, 0).g); +} + +void PS_ResolveStencil(in float4 position : SV_Position, + in float2 texCoord : TEXCOORD0, + out float2 stencil : SV_Target0) +{ + // MS samplers must use Load + uint width, height, samples; + Stencil.GetDimensions(width, height, samples); + uint2 coord = uint2(texCoord.x * float(width), texCoord.y * float(height)); + stencil.r = 0.0f; + stencil.g = float(Stencil.Load(coord, 0).g); +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrgba2dms11ps.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrgba2dms11ps.h new file mode 100644 index 0000000000..a5cccdc98e --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrgba2dms11ps.h @@ -0,0 +1,155 @@ +#if 0 +// +// Generated by Microsoft (R) HLSL Shader Compiler 10.1 +// +// +// Resource Bindings: +// +// Name Type Format Dim HLSL Bind Count +// ------------------------------ ---------- ------- ----------- -------------- ------ +// TextureF_MS texture float4 2dMS t0 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------- ------ +// SV_POSITION 0 xyzw 0 POS float +// TEXCORD 0 xy 1 NONE float xy +// SV_SAMPLEINDEX 0 x 2 SAMPLE uint x +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------- ------ +// SV_TARGET 0 xyzw 0 TARGET float xyzw +// +// Pixel Shader runs at sample frequency +// +ps_4_1 +dcl_globalFlags refactoringAllowed +dcl_resource_texture2dms(0) (float,float,float,float) t0 +dcl_input_ps linear v1.xy +dcl_input_ps_sgv constant v2.x, sampleIndex +dcl_output o0.xyzw +dcl_temps 1 +ftou r0.xy, v1.xyxx +mov r0.zw, l(0,0,0,0) +ldms o0.xyzw, r0.xyzw, t0.xyzw, v2.x +ret +// Approximately 4 instruction slots used +#endif + +const BYTE g_PS_PassthroughRGBA2DMS[] = +{ + 68, 88, 66, 67, 206, 115, + 73, 27, 160, 237, 59, 223, + 179, 180, 28, 146, 74, 174, + 29, 197, 1, 0, 0, 0, + 136, 2, 0, 0, 5, 0, + 0, 0, 52, 0, 0, 0, + 172, 0, 0, 0, 40, 1, + 0, 0, 92, 1, 0, 0, + 12, 2, 0, 0, 82, 68, + 69, 70, 112, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 28, 0, 0, 0, 1, 4, + 255, 255, 0, 1, 0, 0, + 72, 0, 0, 0, 60, 0, + 0, 0, 2, 0, 0, 0, + 5, 0, 0, 0, 6, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, + 0, 0, 13, 0, 0, 0, + 84, 101, 120, 116, 117, 114, + 101, 70, 95, 77, 83, 0, + 77, 105, 99, 114, 111, 115, + 111, 102, 116, 32, 40, 82, + 41, 32, 72, 76, 83, 76, + 32, 83, 104, 97, 100, 101, + 114, 32, 67, 111, 109, 112, + 105, 108, 101, 114, 32, 49, + 48, 46, 49, 0, 73, 83, + 71, 78, 116, 0, 0, 0, + 3, 0, 0, 0, 8, 0, + 0, 0, 80, 0, 0, 0, + 0, 0, 0, 0, 1, 0, + 0, 0, 3, 0, 0, 0, + 0, 0, 0, 0, 15, 0, + 0, 0, 92, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 3, 0, 0, 0, + 1, 0, 0, 0, 3, 3, + 0, 0, 100, 0, 0, 0, + 0, 0, 0, 0, 10, 0, + 0, 0, 1, 0, 0, 0, + 2, 0, 0, 0, 1, 1, + 0, 0, 83, 86, 95, 80, + 79, 83, 73, 84, 73, 79, + 78, 0, 84, 69, 88, 67, + 79, 82, 68, 0, 83, 86, + 95, 83, 65, 77, 80, 76, + 69, 73, 78, 68, 69, 88, + 0, 171, 79, 83, 71, 78, + 44, 0, 0, 0, 1, 0, + 0, 0, 8, 0, 0, 0, + 32, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 3, 0, 0, 0, 0, 0, + 0, 0, 15, 0, 0, 0, + 83, 86, 95, 84, 65, 82, + 71, 69, 84, 0, 171, 171, + 83, 72, 68, 82, 168, 0, + 0, 0, 65, 0, 0, 0, + 42, 0, 0, 0, 106, 8, + 0, 1, 88, 32, 0, 4, + 0, 112, 16, 0, 0, 0, + 0, 0, 85, 85, 0, 0, + 98, 16, 0, 3, 50, 16, + 16, 0, 1, 0, 0, 0, + 99, 8, 0, 4, 18, 16, + 16, 0, 2, 0, 0, 0, + 10, 0, 0, 0, 101, 0, + 0, 3, 242, 32, 16, 0, + 0, 0, 0, 0, 104, 0, + 0, 2, 1, 0, 0, 0, + 28, 0, 0, 5, 50, 0, + 16, 0, 0, 0, 0, 0, + 70, 16, 16, 0, 1, 0, + 0, 0, 54, 0, 0, 8, + 194, 0, 16, 0, 0, 0, + 0, 0, 2, 64, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 46, 0, + 0, 9, 242, 32, 16, 0, + 0, 0, 0, 0, 70, 14, + 16, 0, 0, 0, 0, 0, + 70, 126, 16, 0, 0, 0, + 0, 0, 10, 16, 16, 0, + 2, 0, 0, 0, 62, 0, + 0, 1, 83, 84, 65, 84, + 116, 0, 0, 0, 4, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 3, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0 +}; diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/swizzle_format_data.json b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/swizzle_format_data.json deleted file mode 100644 index 3e9e6877d9..0000000000 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/swizzle_format_data.json +++ /dev/null @@ -1,77 +0,0 @@ -{ - "GL_UNSIGNED_NORMALIZED": { - "8": { - "texFormat": "DXGI_FORMAT_R8G8B8A8_UNORM", - "srvFormat": "DXGI_FORMAT_R8G8B8A8_UNORM", - "rtvFormat": "DXGI_FORMAT_R8G8B8A8_UNORM" - }, - "16": { - "texFormat": "DXGI_FORMAT_R16G16B16A16_UNORM", - "srvFormat": "DXGI_FORMAT_R16G16B16A16_UNORM", - "rtvFormat": "DXGI_FORMAT_R16G16B16A16_UNORM" - }, - "24": { - "texFormat": "DXGI_FORMAT_R32G32B32A32_FLOAT", - "srvFormat": "DXGI_FORMAT_R32G32B32A32_FLOAT", - "rtvFormat": "DXGI_FORMAT_R32G32B32A32_FLOAT" - }, - "32": { - "texFormat": "DXGI_FORMAT_R32G32B32A32_FLOAT", - "srvFormat": "DXGI_FORMAT_R32G32B32A32_FLOAT", - "rtvFormat": "DXGI_FORMAT_R32G32B32A32_FLOAT" - } - }, - "GL_SIGNED_NORMALIZED": { - "8": { - "texFormat": "DXGI_FORMAT_R8G8B8A8_SNORM", - "srvFormat": "DXGI_FORMAT_R8G8B8A8_SNORM", - "rtvFormat": "DXGI_FORMAT_R8G8B8A8_SNORM" - } - }, - "GL_FLOAT": { - "16": { - "texFormat": "DXGI_FORMAT_R16G16B16A16_FLOAT", - "srvFormat": "DXGI_FORMAT_R16G16B16A16_FLOAT", - "rtvFormat": "DXGI_FORMAT_R16G16B16A16_FLOAT" - }, - "32": { - "texFormat": "DXGI_FORMAT_R32G32B32A32_FLOAT", - "srvFormat": "DXGI_FORMAT_R32G32B32A32_FLOAT", - "rtvFormat": "DXGI_FORMAT_R32G32B32A32_FLOAT" - } - }, - "GL_UNSIGNED_INT": { - "8": { - "texFormat": "DXGI_FORMAT_R8G8B8A8_UINT", - "srvFormat": "DXGI_FORMAT_R8G8B8A8_UINT", - "rtvFormat": "DXGI_FORMAT_R8G8B8A8_UINT" - }, - "16": { - "texFormat": "DXGI_FORMAT_R16G16B16A16_UINT", - "srvFormat": "DXGI_FORMAT_R16G16B16A16_UINT", - "rtvFormat": "DXGI_FORMAT_R16G16B16A16_UINT" - }, - "32": { - "texFormat": "DXGI_FORMAT_R32G32B32A32_UINT", - "srvFormat": "DXGI_FORMAT_R32G32B32A32_UINT", - "rtvFormat": "DXGI_FORMAT_R32G32B32A32_UINT" - } - }, - "GL_INT": { - "8": { - "texFormat": "DXGI_FORMAT_R8G8B8A8_SINT", - "srvFormat": "DXGI_FORMAT_R8G8B8A8_SINT", - "rtvFormat": "DXGI_FORMAT_R8G8B8A8_SINT" - }, - "16": { - "texFormat": "DXGI_FORMAT_R16G16B16A16_SINT", - "srvFormat": "DXGI_FORMAT_R16G16B16A16_SINT", - "rtvFormat": "DXGI_FORMAT_R16G16B16A16_SINT" - }, - "32": { - "texFormat": "DXGI_FORMAT_R32G32B32A32_SINT", - "srvFormat": "DXGI_FORMAT_R32G32B32A32_SINT", - "rtvFormat": "DXGI_FORMAT_R32G32B32A32_SINT" - } - } -} \ No newline at end of file diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/swizzle_format_info.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/swizzle_format_info.h deleted file mode 100644 index df9a30ff50..0000000000 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/swizzle_format_info.h +++ /dev/null @@ -1,51 +0,0 @@ -// -// 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. -// -// swizzle_format_info: -// Provides information for swizzle format and a map from type->formatinfo -// - -#ifndef LIBANGLE_RENDERER_D3D_D3D11_SWIZZLEFORMATINFO_H_ -#define LIBANGLE_RENDERER_D3D_D3D11_SWIZZLEFORMATINFO_H_ - -#include -#include - -#include "common/platform.h" - -namespace rx -{ - -namespace d3d11 -{ - -struct SwizzleSizeType -{ - size_t maxComponentSize; - GLenum componentType; - - SwizzleSizeType(); - SwizzleSizeType(size_t maxComponentSize, GLenum componentType); - - bool operator<(const SwizzleSizeType &other) const; -}; - -struct SwizzleFormatInfo -{ - DXGI_FORMAT mTexFormat; - DXGI_FORMAT mSRVFormat; - DXGI_FORMAT mRTVFormat; - - SwizzleFormatInfo(); - SwizzleFormatInfo(DXGI_FORMAT texFormat, DXGI_FORMAT srvFormat, DXGI_FORMAT rtvFormat); -}; - -const SwizzleFormatInfo &GetSwizzleFormatInfo(GLuint maxBits, GLenum componentType); - -} // namespace d3d11 - -} // namespace rx - -#endif // LIBANGLE_RENDERER_D3D_D3D11_SWIZZLEFORMATINFO_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/swizzle_format_info_autogen.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/swizzle_format_info_autogen.cpp deleted file mode 100644 index 84d6fada97..0000000000 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/swizzle_format_info_autogen.cpp +++ /dev/null @@ -1,203 +0,0 @@ -// GENERATED FILE - DO NOT EDIT -// Generated by gen_swizzle_format_table.py using data from swizzle_format_data.json -// -// 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. -// -// swizzle_format_info: -// Provides information for swizzle format and a map from type->formatinfo -// - -#include "libANGLE/renderer/d3d/d3d11/swizzle_format_info.h" - -#include - -namespace rx -{ - -namespace d3d11 -{ - -SwizzleSizeType::SwizzleSizeType() : maxComponentSize(0), componentType(GL_NONE) -{ -} - -SwizzleSizeType::SwizzleSizeType(size_t maxComponentSize, GLenum componentType) - : maxComponentSize(maxComponentSize), componentType(componentType) -{ -} - -bool SwizzleSizeType::operator<(const SwizzleSizeType &other) const -{ - return (maxComponentSize != other.maxComponentSize) - ? (maxComponentSize < other.maxComponentSize) - : (componentType < other.componentType); -} - -SwizzleFormatInfo::SwizzleFormatInfo() - : mTexFormat(DXGI_FORMAT_UNKNOWN), - mSRVFormat(DXGI_FORMAT_UNKNOWN), - mRTVFormat(DXGI_FORMAT_UNKNOWN) -{ -} - -SwizzleFormatInfo::SwizzleFormatInfo(DXGI_FORMAT texFormat, - DXGI_FORMAT srvFormat, - DXGI_FORMAT rtvFormat) - : mTexFormat(texFormat), mSRVFormat(srvFormat), mRTVFormat(rtvFormat) -{ -} - -const SwizzleFormatInfo &GetSwizzleFormatInfo(GLuint maxBits, GLenum componentType) -{ - // clang-format off - switch (componentType) - { - case GL_FLOAT: - { - switch (maxBits) - { - case 16: - { - static const SwizzleFormatInfo formatInfo(DXGI_FORMAT_R16G16B16A16_FLOAT, - DXGI_FORMAT_R16G16B16A16_FLOAT, - DXGI_FORMAT_R16G16B16A16_FLOAT); - return formatInfo; - } - case 32: - { - static const SwizzleFormatInfo formatInfo(DXGI_FORMAT_R32G32B32A32_FLOAT, - DXGI_FORMAT_R32G32B32A32_FLOAT, - DXGI_FORMAT_R32G32B32A32_FLOAT); - return formatInfo; - } - default: - break; - } - } - case GL_INT: - { - switch (maxBits) - { - case 16: - { - static const SwizzleFormatInfo formatInfo(DXGI_FORMAT_R16G16B16A16_SINT, - DXGI_FORMAT_R16G16B16A16_SINT, - DXGI_FORMAT_R16G16B16A16_SINT); - return formatInfo; - } - case 32: - { - static const SwizzleFormatInfo formatInfo(DXGI_FORMAT_R32G32B32A32_SINT, - DXGI_FORMAT_R32G32B32A32_SINT, - DXGI_FORMAT_R32G32B32A32_SINT); - return formatInfo; - } - case 8: - { - static const SwizzleFormatInfo formatInfo(DXGI_FORMAT_R8G8B8A8_SINT, - DXGI_FORMAT_R8G8B8A8_SINT, - DXGI_FORMAT_R8G8B8A8_SINT); - return formatInfo; - } - default: - break; - } - } - case GL_SIGNED_NORMALIZED: - { - switch (maxBits) - { - case 8: - { - static const SwizzleFormatInfo formatInfo(DXGI_FORMAT_R8G8B8A8_SNORM, - DXGI_FORMAT_R8G8B8A8_SNORM, - DXGI_FORMAT_R8G8B8A8_SNORM); - return formatInfo; - } - default: - break; - } - } - case GL_UNSIGNED_INT: - { - switch (maxBits) - { - case 16: - { - static const SwizzleFormatInfo formatInfo(DXGI_FORMAT_R16G16B16A16_UINT, - DXGI_FORMAT_R16G16B16A16_UINT, - DXGI_FORMAT_R16G16B16A16_UINT); - return formatInfo; - } - case 32: - { - static const SwizzleFormatInfo formatInfo(DXGI_FORMAT_R32G32B32A32_UINT, - DXGI_FORMAT_R32G32B32A32_UINT, - DXGI_FORMAT_R32G32B32A32_UINT); - return formatInfo; - } - case 8: - { - static const SwizzleFormatInfo formatInfo(DXGI_FORMAT_R8G8B8A8_UINT, - DXGI_FORMAT_R8G8B8A8_UINT, - DXGI_FORMAT_R8G8B8A8_UINT); - return formatInfo; - } - default: - break; - } - } - case GL_UNSIGNED_NORMALIZED: - { - switch (maxBits) - { - case 16: - { - static const SwizzleFormatInfo formatInfo(DXGI_FORMAT_R16G16B16A16_UNORM, - DXGI_FORMAT_R16G16B16A16_UNORM, - DXGI_FORMAT_R16G16B16A16_UNORM); - return formatInfo; - } - case 24: - { - static const SwizzleFormatInfo formatInfo(DXGI_FORMAT_R32G32B32A32_FLOAT, - DXGI_FORMAT_R32G32B32A32_FLOAT, - DXGI_FORMAT_R32G32B32A32_FLOAT); - return formatInfo; - } - case 32: - { - static const SwizzleFormatInfo formatInfo(DXGI_FORMAT_R32G32B32A32_FLOAT, - DXGI_FORMAT_R32G32B32A32_FLOAT, - DXGI_FORMAT_R32G32B32A32_FLOAT); - return formatInfo; - } - case 8: - { - static const SwizzleFormatInfo formatInfo(DXGI_FORMAT_R8G8B8A8_UNORM, - DXGI_FORMAT_R8G8B8A8_UNORM, - DXGI_FORMAT_R8G8B8A8_UNORM); - return formatInfo; - } - default: - break; - } - } - - default: - { - static const SwizzleFormatInfo defaultInfo(DXGI_FORMAT_UNKNOWN, - DXGI_FORMAT_UNKNOWN, - DXGI_FORMAT_UNKNOWN); - return defaultInfo; - } - } - // clang-format on - -} // GetSwizzleFormatInfo - -} // namespace d3d11 - -} // namespace rx diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/texture_format_data.json b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/texture_format_data.json index 87d303437f..61cd44a62b 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/texture_format_data.json +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/texture_format_data.json @@ -1,692 +1,523 @@ { - "GL_ALPHA": [ - { - "texFormat": "DXGI_FORMAT_A8_UNORM", - "srvFormat": "DXGI_FORMAT_A8_UNORM", - "rtvFormat": "DXGI_FORMAT_A8_UNORM", - "requirementsFcn": "OnlyFL10Plus" - }, - { - "texFormat": "DXGI_FORMAT_R8G8B8A8_UNORM", - "srvFormat": "DXGI_FORMAT_R8G8B8A8_UNORM", - "rtvFormat": "DXGI_FORMAT_R8G8B8A8_UNORM", - "requirementsFcn": "OnlyFL9_3" - } - ], - "GL_ALPHA16F_EXT": [ - { - "texFormat": "DXGI_FORMAT_R16G16B16A16_FLOAT", - "srvFormat": "DXGI_FORMAT_R16G16B16A16_FLOAT", - "rtvFormat": "DXGI_FORMAT_R16G16B16A16_FLOAT" - } - ], - "GL_ALPHA32F_EXT": [ - { - "texFormat": "DXGI_FORMAT_R32G32B32A32_FLOAT", - "srvFormat": "DXGI_FORMAT_R32G32B32A32_FLOAT", - "rtvFormat": "DXGI_FORMAT_R32G32B32A32_FLOAT" - } - ], - "GL_ALPHA8_EXT": [ - { - "texFormat": "DXGI_FORMAT_A8_UNORM", - "srvFormat": "DXGI_FORMAT_A8_UNORM", - "rtvFormat": "DXGI_FORMAT_A8_UNORM", - "requirementsFcn": "OnlyFL10Plus" - }, - { - "texFormat": "DXGI_FORMAT_R8G8B8A8_UNORM", - "srvFormat": "DXGI_FORMAT_R8G8B8A8_UNORM", - "rtvFormat": "DXGI_FORMAT_R8G8B8A8_UNORM", - "requirementsFcn": "OnlyFL9_3" - } - ], - "GL_BGR5_A1_ANGLEX": [ - { - "texFormat": "DXGI_FORMAT_B8G8R8A8_UNORM", - "srvFormat": "DXGI_FORMAT_B8G8R8A8_UNORM", - "rtvFormat": "DXGI_FORMAT_B8G8R8A8_UNORM" - } - ], - "GL_BGRA4_ANGLEX": [ - { - "texFormat": "DXGI_FORMAT_B8G8R8A8_UNORM", - "srvFormat": "DXGI_FORMAT_B8G8R8A8_UNORM", - "rtvFormat": "DXGI_FORMAT_B8G8R8A8_UNORM" - } - ], - "GL_BGRA8_EXT": [ - { - "texFormat": "DXGI_FORMAT_B8G8R8A8_UNORM", - "srvFormat": "DXGI_FORMAT_B8G8R8A8_UNORM", - "rtvFormat": "DXGI_FORMAT_B8G8R8A8_UNORM" - } - ], - "GL_BGRA_EXT": [ - { - "texFormat": "DXGI_FORMAT_B8G8R8A8_UNORM", - "srvFormat": "DXGI_FORMAT_B8G8R8A8_UNORM", - "rtvFormat": "DXGI_FORMAT_B8G8R8A8_UNORM" - } - ], - "GL_COMPRESSED_R11_EAC": [ - { - "texFormat": "DXGI_FORMAT_R8_UNORM", - "srvFormat": "DXGI_FORMAT_R8_UNORM", - "requirementsFcn": "OnlyFL10Plus" - } - ], - "GL_COMPRESSED_RG11_EAC": [ - { - "texFormat": "DXGI_FORMAT_R8G8_UNORM", - "srvFormat": "DXGI_FORMAT_R8G8_UNORM", - "requirementsFcn": "OnlyFL10Plus" - } - ], - "GL_COMPRESSED_RGB8_ETC2": [ - { - "texFormat": "DXGI_FORMAT_R8G8B8A8_UNORM", - "srvFormat": "DXGI_FORMAT_R8G8B8A8_UNORM", - "requirementsFcn": "OnlyFL10Plus" - } - ], - "GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2": [ - { - "texFormat": "DXGI_FORMAT_R8G8B8A8_UNORM", - "srvFormat": "DXGI_FORMAT_R8G8B8A8_UNORM", - "requirementsFcn": "OnlyFL10Plus" - } - ], - "GL_COMPRESSED_RGBA8_ETC2_EAC": [ - { - "texFormat": "DXGI_FORMAT_R8G8B8A8_UNORM", - "srvFormat": "DXGI_FORMAT_R8G8B8A8_UNORM", - "requirementsFcn": "OnlyFL10Plus" - } - ], - "GL_COMPRESSED_RGBA_S3TC_DXT1_EXT": [ - { - "texFormat": "DXGI_FORMAT_BC1_UNORM", - "srvFormat": "DXGI_FORMAT_BC1_UNORM" - } - ], - "GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE": [ - { - "texFormat": "DXGI_FORMAT_BC2_UNORM", - "srvFormat": "DXGI_FORMAT_BC2_UNORM" - } - ], - "GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE": [ - { - "texFormat": "DXGI_FORMAT_BC3_UNORM", - "srvFormat": "DXGI_FORMAT_BC3_UNORM" - } - ], - "GL_COMPRESSED_RGB_S3TC_DXT1_EXT": [ - { - "texFormat": "DXGI_FORMAT_BC1_UNORM", - "srvFormat": "DXGI_FORMAT_BC1_UNORM" - } - ], - "GL_COMPRESSED_SIGNED_R11_EAC": [ - { - "texFormat": "DXGI_FORMAT_R8_SNORM", - "srvFormat": "DXGI_FORMAT_R8_SNORM", - "requirementsFcn": "OnlyFL10Plus" - } - ], - "GL_COMPRESSED_SIGNED_RG11_EAC": [ - { - "texFormat": "DXGI_FORMAT_R8G8_SNORM", - "srvFormat": "DXGI_FORMAT_R8G8_SNORM", - "requirementsFcn": "OnlyFL10Plus" - } - ], - "GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC": [ - { - "texFormat": "DXGI_FORMAT_R8G8B8A8_UNORM_SRGB", - "srvFormat": "DXGI_FORMAT_R8G8B8A8_UNORM_SRGB", - "requirementsFcn": "OnlyFL10Plus" - } - ], - "GL_COMPRESSED_SRGB8_ETC2": [ - { - "texFormat": "DXGI_FORMAT_R8G8B8A8_UNORM_SRGB", - "srvFormat": "DXGI_FORMAT_R8G8B8A8_UNORM_SRGB", - "requirementsFcn": "OnlyFL10Plus" - } - ], - "GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2": [ - { - "texFormat": "DXGI_FORMAT_R8G8B8A8_UNORM_SRGB", - "srvFormat": "DXGI_FORMAT_R8G8B8A8_UNORM_SRGB", - "requirementsFcn": "OnlyFL10Plus" - } - ], - "GL_DEPTH24_STENCIL8": [ - { + "NONE": { + }, + "A8_UNORM": { + "texFormat": "DXGI_FORMAT_A8_UNORM", + "srvFormat": "DXGI_FORMAT_A8_UNORM", + "rtvFormat": "DXGI_FORMAT_A8_UNORM", + "channels": "a", + "componentType": "unorm", + "bits": { "alpha": 8 }, + "supportTest": "OnlyFL10Plus(deviceCaps)", + "fallbackFormat": "R8G8B8A8_UNORM" + }, + "R8G8B8A8_UNORM": { + "texFormat": "DXGI_FORMAT_R8G8B8A8_UNORM", + "srvFormat": "DXGI_FORMAT_R8G8B8A8_UNORM", + "rtvFormat": "DXGI_FORMAT_R8G8B8A8_UNORM", + "channels": "rgba", + "componentType": "unorm", + "bits": { "red": 8, "green": 8, "blue": 8, "alpha": 8 }, + "glInternalFormat": "GL_RGBA8" + }, + "R16G16B16A16_UNORM": { + "texFormat": "DXGI_FORMAT_R16G16B16A16_UNORM", + "srvFormat": "DXGI_FORMAT_R16G16B16A16_UNORM", + "rtvFormat": "DXGI_FORMAT_R16G16B16A16_UNORM", + "channels": "rgba", + "componentType": "unorm", + "bits": { "red": 16, "green": 16, "blue": 16, "alpha": 16 }, + "glInternalFormat": "GL_RGBA16_EXT" + }, + "R16G16B16A16_FLOAT": { + "texFormat": "DXGI_FORMAT_R16G16B16A16_FLOAT", + "srvFormat": "DXGI_FORMAT_R16G16B16A16_FLOAT", + "rtvFormat": "DXGI_FORMAT_R16G16B16A16_FLOAT", + "channels": "rgba", + "componentType": "float", + "bits": { "red": 16, "green": 16, "blue": 16, "alpha": 16 }, + "glInternalFormat": "GL_RGBA16F" + }, + "R32G32B32A32_FLOAT": { + "texFormat": "DXGI_FORMAT_R32G32B32A32_FLOAT", + "srvFormat": "DXGI_FORMAT_R32G32B32A32_FLOAT", + "rtvFormat": "DXGI_FORMAT_R32G32B32A32_FLOAT", + "channels": "rgba", + "componentType": "float", + "bits": { "red": 32, "green": 32, "blue": 32, "alpha": 32 }, + "glInternalFormat": "GL_RGBA32F" + }, + "B8G8R8A8_UNORM": { + "texFormat": "DXGI_FORMAT_B8G8R8A8_UNORM", + "srvFormat": "DXGI_FORMAT_B8G8R8A8_UNORM", + "rtvFormat": "DXGI_FORMAT_B8G8R8A8_UNORM", + "channels": "bgra", + "componentType": "unorm", + "bits": { "red": 8, "green": 8, "blue": 8, "alpha": 8 }, + "glInternalFormat": "GL_BGRA8_EXT" + }, + "B8G8R8A8_UNORM_SRGB": { + "texFormat": "DXGI_FORMAT_B8G8R8A8_UNORM_SRGB", + "srvFormat": "DXGI_FORMAT_B8G8R8A8_UNORM_SRGB", + "rtvFormat": "DXGI_FORMAT_B8G8R8A8_UNORM_SRGB", + "channels": "bgra", + "componentType": "unorm", + "bits": {"red": 8, "green": 8, "blue": 8,"alpha": 8}, + "siwzzleFormat": "GL_RGBA8" + }, + "BC1_RGBA_UNORM_BLOCK": { + "texFormat": "DXGI_FORMAT_BC1_UNORM", + "srvFormat": "DXGI_FORMAT_BC1_UNORM", + "channels": "rgba", + "componentType": "unorm", + "swizzleFormat": "GL_RGBA8" + }, + "BC1_RGB_UNORM_BLOCK": { + "texFormat": "DXGI_FORMAT_BC1_UNORM", + "srvFormat": "DXGI_FORMAT_BC1_UNORM", + "channels": "rgba", + "componentType": "unorm", + "swizzleFormat": "GL_RGBA8" + }, + "BC2_RGBA_UNORM_BLOCK": { + "texFormat": "DXGI_FORMAT_BC2_UNORM", + "srvFormat": "DXGI_FORMAT_BC2_UNORM", + "channels": "rgba", + "componentType": "unorm", + "swizzleFormat": "GL_RGBA8" + }, + "BC3_RGBA_UNORM_BLOCK": { + "texFormat": "DXGI_FORMAT_BC3_UNORM", + "srvFormat": "DXGI_FORMAT_BC3_UNORM", + "channels": "rgba", + "componentType": "unorm", + "swizzleFormat": "GL_RGBA8" + }, + "BC1_RGBA_UNORM_SRGB_BLOCK": { + "texFormat": "DXGI_FORMAT_BC1_UNORM_SRGB", + "srvFormat": "DXGI_FORMAT_BC1_UNORM_SRGB", + "channels": "rgba", + "componentType": "unorm", + "swizzleFormat": "GL_RGBA8" + }, + "BC1_RGB_UNORM_SRGB_BLOCK": { + "texFormat": "DXGI_FORMAT_BC1_UNORM_SRGB", + "srvFormat": "DXGI_FORMAT_BC1_UNORM_SRGB", + "channels": "rgba", + "componentType": "unorm", + "swizzleFormat": "GL_RGBA8" + }, + "BC2_RGBA_UNORM_SRGB_BLOCK": { + "texFormat": "DXGI_FORMAT_BC2_UNORM_SRGB", + "srvFormat": "DXGI_FORMAT_BC2_UNORM_SRGB", + "channels": "rgba", + "componentType": "unorm", + "swizzleFormat": "GL_RGBA8" + }, + "BC3_RGBA_UNORM_SRGB_BLOCK": { + "texFormat": "DXGI_FORMAT_BC3_UNORM_SRGB", + "srvFormat": "DXGI_FORMAT_BC3_UNORM_SRGB", + "channels": "rgba", + "componentType": "unorm", + "swizzleFormat": "GL_RGBA8" + }, + "D24_UNORM_S8_UINT": { + "FL10Plus": { "texFormat": "DXGI_FORMAT_R24G8_TYPELESS", - "srvFormat": "DXGI_FORMAT_R24_UNORM_X8_TYPELESS", - "dsvFormat": "DXGI_FORMAT_D24_UNORM_S8_UINT", - "requirementsFcn": "OnlyFL10Plus" + "srvFormat": "DXGI_FORMAT_R24_UNORM_X8_TYPELESS" }, - { - "texFormat": "DXGI_FORMAT_D24_UNORM_S8_UINT", - "dsvFormat": "DXGI_FORMAT_D24_UNORM_S8_UINT", - "requirementsFcn": "OnlyFL9_3" - } - ], - "GL_DEPTH32F_STENCIL8": [ - { - "texFormat": "DXGI_FORMAT_R32G8X24_TYPELESS", - "srvFormat": "DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS", - "dsvFormat": "DXGI_FORMAT_D32_FLOAT_S8X24_UINT", - "requirementsFcn": "OnlyFL10Plus" + "FL9_3": { + "texFormat": "DXGI_FORMAT_D24_UNORM_S8_UINT" }, - { - "requirementsFcn": "OnlyFL9_3" - } - ], - "GL_DEPTH_COMPONENT16": [ - { + "dsvFormat": "DXGI_FORMAT_D24_UNORM_S8_UINT", + "channels": "ds", + "bits": { "depth": 24, "stencil": 8 }, + "glInternalFormat": "GL_DEPTH24_STENCIL8_OES" + }, + "D32_FLOAT_S8X24_UINT": { + "texFormat": "DXGI_FORMAT_R32G8X24_TYPELESS", + "srvFormat": "DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS", + "dsvFormat": "DXGI_FORMAT_D32_FLOAT_S8X24_UINT", + "channels": "ds", + "bits": { "depth": 32, "stencil": 8 }, + "glInternalFormat": "GL_DEPTH32F_STENCIL8" + }, + "D16_UNORM": { + "FL10Plus": { "texFormat": "DXGI_FORMAT_R16_TYPELESS", - "srvFormat": "DXGI_FORMAT_R16_UNORM", - "dsvFormat": "DXGI_FORMAT_D16_UNORM", - "requirementsFcn": "OnlyFL10Plus" - }, - { - "texFormat": "DXGI_FORMAT_D16_UNORM", - "dsvFormat": "DXGI_FORMAT_D16_UNORM", - "requirementsFcn": "OnlyFL9_3" - } - ], - "GL_DEPTH_COMPONENT24": [ - { - "texFormat": "DXGI_FORMAT_R24G8_TYPELESS", - "srvFormat": "DXGI_FORMAT_R24_UNORM_X8_TYPELESS", - "dsvFormat": "DXGI_FORMAT_D24_UNORM_S8_UINT", - "requirementsFcn": "OnlyFL10Plus" - }, - { - "texFormat": "DXGI_FORMAT_D24_UNORM_S8_UINT", - "dsvFormat": "DXGI_FORMAT_D24_UNORM_S8_UINT", - "requirementsFcn": "OnlyFL9_3" - } - ], - "GL_DEPTH_COMPONENT32F": [ - { - "texFormat": "DXGI_FORMAT_R32_TYPELESS", - "srvFormat": "DXGI_FORMAT_R32_FLOAT", - "dsvFormat": "DXGI_FORMAT_D32_FLOAT", - "requirementsFcn": "OnlyFL10Plus" + "srvFormat": "DXGI_FORMAT_R16_UNORM" }, - { - "requirementsFcn": "OnlyFL9_3" - } - ], - "GL_DEPTH_COMPONENT32_OES": [ - { - "texFormat": "DXGI_FORMAT_R24G8_TYPELESS", - "srvFormat": "DXGI_FORMAT_R24_UNORM_X8_TYPELESS", - "dsvFormat": "DXGI_FORMAT_D24_UNORM_S8_UINT", - "requirementsFcn": "OnlyFL10Plus" - } - ], - "GL_ETC1_RGB8_OES": [ - { - "texFormat": "DXGI_FORMAT_R8G8B8A8_UNORM", - "srvFormat": "DXGI_FORMAT_R8G8B8A8_UNORM" - } - ], - "GL_ETC1_RGB8_LOSSY_DECODE_ANGLE": [ - { - "texFormat": "DXGI_FORMAT_BC1_UNORM", - "srvFormat": "DXGI_FORMAT_BC1_UNORM" - } - ], - "GL_LUMINANCE": [ - { - "texFormat": "DXGI_FORMAT_R8G8B8A8_UNORM", - "srvFormat": "DXGI_FORMAT_R8G8B8A8_UNORM", - "rtvFormat": "DXGI_FORMAT_R8G8B8A8_UNORM" - } - ], - "GL_LUMINANCE16F_EXT": [ - { - "texFormat": "DXGI_FORMAT_R16G16B16A16_FLOAT", - "srvFormat": "DXGI_FORMAT_R16G16B16A16_FLOAT", - "rtvFormat": "DXGI_FORMAT_R16G16B16A16_FLOAT" - } - ], - "GL_LUMINANCE32F_EXT": [ - { - "texFormat": "DXGI_FORMAT_R32G32B32A32_FLOAT", - "srvFormat": "DXGI_FORMAT_R32G32B32A32_FLOAT", - "rtvFormat": "DXGI_FORMAT_R32G32B32A32_FLOAT" - } - ], - "GL_LUMINANCE8_ALPHA8_EXT": [ - { - "texFormat": "DXGI_FORMAT_R8G8B8A8_UNORM", - "srvFormat": "DXGI_FORMAT_R8G8B8A8_UNORM", - "rtvFormat": "DXGI_FORMAT_R8G8B8A8_UNORM" - } - ], - "GL_LUMINANCE8_EXT": [ - { - "texFormat": "DXGI_FORMAT_R8G8B8A8_UNORM", - "srvFormat": "DXGI_FORMAT_R8G8B8A8_UNORM", - "rtvFormat": "DXGI_FORMAT_R8G8B8A8_UNORM" - } - ], - "GL_LUMINANCE_ALPHA": [ - { - "texFormat": "DXGI_FORMAT_R8G8B8A8_UNORM", - "srvFormat": "DXGI_FORMAT_R8G8B8A8_UNORM", - "rtvFormat": "DXGI_FORMAT_R8G8B8A8_UNORM" - } - ], - "GL_LUMINANCE_ALPHA16F_EXT": [ - { - "texFormat": "DXGI_FORMAT_R16G16B16A16_FLOAT", - "srvFormat": "DXGI_FORMAT_R16G16B16A16_FLOAT", - "rtvFormat": "DXGI_FORMAT_R16G16B16A16_FLOAT" - } - ], - "GL_LUMINANCE_ALPHA32F_EXT": [ - { - "texFormat": "DXGI_FORMAT_R32G32B32A32_FLOAT", - "srvFormat": "DXGI_FORMAT_R32G32B32A32_FLOAT", - "rtvFormat": "DXGI_FORMAT_R32G32B32A32_FLOAT" - } - ], - "GL_NONE": [ - { - } - ], - "GL_R11F_G11F_B10F": [ - { - "texFormat": "DXGI_FORMAT_R11G11B10_FLOAT", - "srvFormat": "DXGI_FORMAT_R11G11B10_FLOAT", - "rtvFormat": "DXGI_FORMAT_R11G11B10_FLOAT" - } - ], - "GL_R16F": [ - { - "texFormat": "DXGI_FORMAT_R16_FLOAT", - "srvFormat": "DXGI_FORMAT_R16_FLOAT", - "rtvFormat": "DXGI_FORMAT_R16_FLOAT" - } - ], - "GL_R16I": [ - { - "texFormat": "DXGI_FORMAT_R16_SINT", - "srvFormat": "DXGI_FORMAT_R16_SINT", - "rtvFormat": "DXGI_FORMAT_R16_SINT" - } - ], - "GL_R16UI": [ - { - "texFormat": "DXGI_FORMAT_R16_UINT", - "srvFormat": "DXGI_FORMAT_R16_UINT", - "rtvFormat": "DXGI_FORMAT_R16_UINT" - } - ], - "GL_R32F": [ - { - "texFormat": "DXGI_FORMAT_R32_FLOAT", - "srvFormat": "DXGI_FORMAT_R32_FLOAT", - "rtvFormat": "DXGI_FORMAT_R32_FLOAT" - } - ], - "GL_R32I": [ - { - "texFormat": "DXGI_FORMAT_R32_SINT", - "srvFormat": "DXGI_FORMAT_R32_SINT", - "rtvFormat": "DXGI_FORMAT_R32_SINT" - } - ], - "GL_R32UI": [ - { - "texFormat": "DXGI_FORMAT_R32_UINT", - "srvFormat": "DXGI_FORMAT_R32_UINT", - "rtvFormat": "DXGI_FORMAT_R32_UINT" - } - ], - "GL_R8": [ - { - "texFormat": "DXGI_FORMAT_R8_UNORM", - "srvFormat": "DXGI_FORMAT_R8_UNORM", - "rtvFormat": "DXGI_FORMAT_R8_UNORM" - } - ], - "GL_R8I": [ - { - "texFormat": "DXGI_FORMAT_R8_SINT", - "srvFormat": "DXGI_FORMAT_R8_SINT", - "rtvFormat": "DXGI_FORMAT_R8_SINT" - } - ], - "GL_R8UI": [ - { - "texFormat": "DXGI_FORMAT_R8_UINT", - "srvFormat": "DXGI_FORMAT_R8_UINT", - "rtvFormat": "DXGI_FORMAT_R8_UINT" - } - ], - "GL_R8_SNORM": [ - { - "texFormat": "DXGI_FORMAT_R8_SNORM", - "srvFormat": "DXGI_FORMAT_R8_SNORM" - } - ], - "GL_RG16F": [ - { - "texFormat": "DXGI_FORMAT_R16G16_FLOAT", - "srvFormat": "DXGI_FORMAT_R16G16_FLOAT", - "rtvFormat": "DXGI_FORMAT_R16G16_FLOAT" - } - ], - "GL_RG16I": [ - { - "texFormat": "DXGI_FORMAT_R16G16_SINT", - "srvFormat": "DXGI_FORMAT_R16G16_SINT", - "rtvFormat": "DXGI_FORMAT_R16G16_SINT" - } - ], - "GL_RG16UI": [ - { - "texFormat": "DXGI_FORMAT_R16G16_UINT", - "srvFormat": "DXGI_FORMAT_R16G16_UINT", - "rtvFormat": "DXGI_FORMAT_R16G16_UINT" - } - ], - "GL_RG32F": [ - { - "texFormat": "DXGI_FORMAT_R32G32_FLOAT", - "srvFormat": "DXGI_FORMAT_R32G32_FLOAT", - "rtvFormat": "DXGI_FORMAT_R32G32_FLOAT" - } - ], - "GL_RG32I": [ - { - "texFormat": "DXGI_FORMAT_R32G32_SINT", - "srvFormat": "DXGI_FORMAT_R32G32_SINT", - "rtvFormat": "DXGI_FORMAT_R32G32_SINT" - } - ], - "GL_RG32UI": [ - { - "texFormat": "DXGI_FORMAT_R32G32_UINT", - "srvFormat": "DXGI_FORMAT_R32G32_UINT", - "rtvFormat": "DXGI_FORMAT_R32G32_UINT" - } - ], - "GL_RG8": [ - { - "texFormat": "DXGI_FORMAT_R8G8_UNORM", - "srvFormat": "DXGI_FORMAT_R8G8_UNORM", - "rtvFormat": "DXGI_FORMAT_R8G8_UNORM" - } - ], - "GL_RG8I": [ - { - "texFormat": "DXGI_FORMAT_R8G8_SINT", - "srvFormat": "DXGI_FORMAT_R8G8_SINT", - "rtvFormat": "DXGI_FORMAT_R8G8_SINT" - } - ], - "GL_RG8UI": [ - { - "texFormat": "DXGI_FORMAT_R8G8_UINT", - "srvFormat": "DXGI_FORMAT_R8G8_UINT", - "rtvFormat": "DXGI_FORMAT_R8G8_UINT" - } - ], - "GL_RG8_SNORM": [ - { - "texFormat": "DXGI_FORMAT_R8G8_SNORM", - "srvFormat": "DXGI_FORMAT_R8G8_SNORM" - } - ], - "GL_RGB": [ - { - "texFormat": "DXGI_FORMAT_R8G8B8A8_UNORM", - "srvFormat": "DXGI_FORMAT_R8G8B8A8_UNORM", - "rtvFormat": "DXGI_FORMAT_R8G8B8A8_UNORM" - } - ], - "GL_RGB10_A2": [ - { - "texFormat": "DXGI_FORMAT_R10G10B10A2_UNORM", - "srvFormat": "DXGI_FORMAT_R10G10B10A2_UNORM", - "rtvFormat": "DXGI_FORMAT_R10G10B10A2_UNORM" - } - ], - "GL_RGB10_A2UI": [ - { - "texFormat": "DXGI_FORMAT_R10G10B10A2_UINT", - "srvFormat": "DXGI_FORMAT_R10G10B10A2_UINT", - "rtvFormat": "DXGI_FORMAT_R10G10B10A2_UINT" - } - ], - "GL_RGB16F": [ - { - "texFormat": "DXGI_FORMAT_R16G16B16A16_FLOAT", - "srvFormat": "DXGI_FORMAT_R16G16B16A16_FLOAT", - "rtvFormat": "DXGI_FORMAT_R16G16B16A16_FLOAT" - } - ], - "GL_RGB16I": [ - { - "texFormat": "DXGI_FORMAT_R16G16B16A16_SINT", - "srvFormat": "DXGI_FORMAT_R16G16B16A16_SINT", - "rtvFormat": "DXGI_FORMAT_R16G16B16A16_SINT" - } - ], - "GL_RGB16UI": [ - { - "texFormat": "DXGI_FORMAT_R16G16B16A16_UINT", - "srvFormat": "DXGI_FORMAT_R16G16B16A16_UINT", - "rtvFormat": "DXGI_FORMAT_R16G16B16A16_UINT" - } - ], - "GL_RGB32F": [ - { - "texFormat": "DXGI_FORMAT_R32G32B32A32_FLOAT", - "srvFormat": "DXGI_FORMAT_R32G32B32A32_FLOAT", - "rtvFormat": "DXGI_FORMAT_R32G32B32A32_FLOAT" - } - ], - "GL_RGB32I": [ - { - "texFormat": "DXGI_FORMAT_R32G32B32A32_SINT", - "srvFormat": "DXGI_FORMAT_R32G32B32A32_SINT", - "rtvFormat": "DXGI_FORMAT_R32G32B32A32_SINT" - } - ], - "GL_RGB32UI": [ - { - "texFormat": "DXGI_FORMAT_R32G32B32A32_UINT", - "srvFormat": "DXGI_FORMAT_R32G32B32A32_UINT", - "rtvFormat": "DXGI_FORMAT_R32G32B32A32_UINT" - } - ], - "GL_RGB565": [ - { - "texFormat": "DXGI_FORMAT_R8G8B8A8_UNORM", - "srvFormat": "DXGI_FORMAT_R8G8B8A8_UNORM", - "rtvFormat": "DXGI_FORMAT_R8G8B8A8_UNORM", - "requirementsFcn": "SupportsFormat" - }, - { - "texFormat": "DXGI_FORMAT_B5G6R5_UNORM", - "srvFormat": "DXGI_FORMAT_B5G6R5_UNORM", - "rtvFormat": "DXGI_FORMAT_B5G6R5_UNORM", - "requirementsFcn": "SupportsFormat" - } - ], - "GL_RGB5_A1": [ - { - "texFormat": "DXGI_FORMAT_R8G8B8A8_UNORM", - "srvFormat": "DXGI_FORMAT_R8G8B8A8_UNORM", - "rtvFormat": "DXGI_FORMAT_R8G8B8A8_UNORM", - "requirementsFcn": "SupportsFormat" - }, - { - "texFormat": "DXGI_FORMAT_B5G5R5A1_UNORM", - "srvFormat": "DXGI_FORMAT_B5G5R5A1_UNORM", - "rtvFormat": "DXGI_FORMAT_B5G5R5A1_UNORM", - "requirementsFcn": "SupportsFormat" - } - ], - "GL_RGB8": [ - { - "texFormat": "DXGI_FORMAT_R8G8B8A8_UNORM", - "srvFormat": "DXGI_FORMAT_R8G8B8A8_UNORM", - "rtvFormat": "DXGI_FORMAT_R8G8B8A8_UNORM" - } - ], - "GL_RGB8I": [ - { - "texFormat": "DXGI_FORMAT_R8G8B8A8_SINT", - "srvFormat": "DXGI_FORMAT_R8G8B8A8_SINT", - "rtvFormat": "DXGI_FORMAT_R8G8B8A8_SINT" - } - ], - "GL_RGB8UI": [ - { - "texFormat": "DXGI_FORMAT_R8G8B8A8_UINT", - "srvFormat": "DXGI_FORMAT_R8G8B8A8_UINT", - "rtvFormat": "DXGI_FORMAT_R8G8B8A8_UINT" - } - ], - "GL_RGB8_SNORM": [ - { - "texFormat": "DXGI_FORMAT_R8G8B8A8_SNORM", - "srvFormat": "DXGI_FORMAT_R8G8B8A8_SNORM" - } - ], - "GL_RGB9_E5": [ - { - "texFormat": "DXGI_FORMAT_R9G9B9E5_SHAREDEXP", - "srvFormat": "DXGI_FORMAT_R9G9B9E5_SHAREDEXP" - } - ], - "GL_RGBA": [ - { - "texFormat": "DXGI_FORMAT_R8G8B8A8_UNORM", - "srvFormat": "DXGI_FORMAT_R8G8B8A8_UNORM", - "rtvFormat": "DXGI_FORMAT_R8G8B8A8_UNORM" - } - ], - "GL_RGBA16F": [ - { - "texFormat": "DXGI_FORMAT_R16G16B16A16_FLOAT", - "srvFormat": "DXGI_FORMAT_R16G16B16A16_FLOAT", - "rtvFormat": "DXGI_FORMAT_R16G16B16A16_FLOAT" - } - ], - "GL_RGBA16I": [ - { - "texFormat": "DXGI_FORMAT_R16G16B16A16_SINT", - "srvFormat": "DXGI_FORMAT_R16G16B16A16_SINT", - "rtvFormat": "DXGI_FORMAT_R16G16B16A16_SINT" - } - ], - "GL_RGBA16UI": [ - { - "texFormat": "DXGI_FORMAT_R16G16B16A16_UINT", - "srvFormat": "DXGI_FORMAT_R16G16B16A16_UINT", - "rtvFormat": "DXGI_FORMAT_R16G16B16A16_UINT" - } - ], - "GL_RGBA32F": [ - { - "texFormat": "DXGI_FORMAT_R32G32B32A32_FLOAT", - "srvFormat": "DXGI_FORMAT_R32G32B32A32_FLOAT", - "rtvFormat": "DXGI_FORMAT_R32G32B32A32_FLOAT" - } - ], - "GL_RGBA32I": [ - { - "texFormat": "DXGI_FORMAT_R32G32B32A32_SINT", - "srvFormat": "DXGI_FORMAT_R32G32B32A32_SINT", - "rtvFormat": "DXGI_FORMAT_R32G32B32A32_SINT" - } - ], - "GL_RGBA32UI": [ - { - "texFormat": "DXGI_FORMAT_R32G32B32A32_UINT", - "srvFormat": "DXGI_FORMAT_R32G32B32A32_UINT", - "rtvFormat": "DXGI_FORMAT_R32G32B32A32_UINT" - } - ], - "GL_RGBA4": [ - { - "texFormat": "DXGI_FORMAT_R8G8B8A8_UNORM", - "srvFormat": "DXGI_FORMAT_R8G8B8A8_UNORM", - "rtvFormat": "DXGI_FORMAT_R8G8B8A8_UNORM", - "requirementsFcn": "SupportsFormat" - }, - { - "texFormat": "DXGI_FORMAT_B4G4R4A4_UNORM", - "srvFormat": "DXGI_FORMAT_B4G4R4A4_UNORM", - "rtvFormat": "DXGI_FORMAT_B4G4R4A4_UNORM", - "requirementsFcn": "SupportsFormat" - } - ], - "GL_RGBA8": [ - { - "texFormat": "DXGI_FORMAT_R8G8B8A8_UNORM", - "srvFormat": "DXGI_FORMAT_R8G8B8A8_UNORM", - "rtvFormat": "DXGI_FORMAT_R8G8B8A8_UNORM" - } - ], - "GL_RGBA8I": [ - { - "texFormat": "DXGI_FORMAT_R8G8B8A8_SINT", - "srvFormat": "DXGI_FORMAT_R8G8B8A8_SINT", - "rtvFormat": "DXGI_FORMAT_R8G8B8A8_SINT" - } - ], - "GL_RGBA8UI": [ - { - "texFormat": "DXGI_FORMAT_R8G8B8A8_UINT", - "srvFormat": "DXGI_FORMAT_R8G8B8A8_UINT", - "rtvFormat": "DXGI_FORMAT_R8G8B8A8_UINT" - } - ], - "GL_RGBA8_SNORM": [ - { - "texFormat": "DXGI_FORMAT_R8G8B8A8_SNORM", - "srvFormat": "DXGI_FORMAT_R8G8B8A8_SNORM" - } - ], - "GL_SRGB8": [ - { - "texFormat": "DXGI_FORMAT_R8G8B8A8_UNORM_SRGB", - "srvFormat": "DXGI_FORMAT_R8G8B8A8_UNORM_SRGB" - } - ], - "GL_SRGB8_ALPHA8": [ - { - "texFormat": "DXGI_FORMAT_R8G8B8A8_UNORM_SRGB", - "srvFormat": "DXGI_FORMAT_R8G8B8A8_UNORM_SRGB", - "rtvFormat": "DXGI_FORMAT_R8G8B8A8_UNORM_SRGB" - } - ], - "GL_STENCIL_INDEX8": [ - { - "texFormat": "DXGI_FORMAT_R24G8_TYPELESS", - "srvFormat": "DXGI_FORMAT_X24_TYPELESS_G8_UINT", - "dsvFormat": "DXGI_FORMAT_D24_UNORM_S8_UINT", - "requirementsFcn": "OnlyFL10Plus" + "FL9_3": { + "texFormat": "DXGI_FORMAT_D16_UNORM" }, - { - "texFormat": "DXGI_FORMAT_D24_UNORM_S8_UINT", - "dsvFormat": "DXGI_FORMAT_D24_UNORM_S8_UINT", - "requirementsFcn": "OnlyFL9_3" - } - ] + "dsvFormat": "DXGI_FORMAT_D16_UNORM", + "channels": "d", + "componentType": "unorm", + "bits": { "depth": 16 }, + "glInternalFormat": "GL_DEPTH_COMPONENT16" + }, + "D32_FLOAT": { + "texFormat": "DXGI_FORMAT_R32_TYPELESS", + "srvFormat": "DXGI_FORMAT_R32_FLOAT", + "dsvFormat": "DXGI_FORMAT_D32_FLOAT", + "channels": "d", + "componentType": "float", + "bits": { "depth": 32 }, + "glInternalFormat": "GL_DEPTH_COMPONENT32F" + }, + "R11G11B10_FLOAT": { + "texFormat": "DXGI_FORMAT_R11G11B10_FLOAT", + "srvFormat": "DXGI_FORMAT_R11G11B10_FLOAT", + "rtvFormat": "DXGI_FORMAT_R11G11B10_FLOAT", + "channels": "rgb", + "componentType": "float", + "bits": { "red": 11, "green": 11, "blue": 10 }, + "glInternalFormat": "GL_R11F_G11F_B10F" + }, + "R16_FLOAT": { + "texFormat": "DXGI_FORMAT_R16_FLOAT", + "srvFormat": "DXGI_FORMAT_R16_FLOAT", + "rtvFormat": "DXGI_FORMAT_R16_FLOAT", + "channels": "r", + "componentType": "float", + "bits": { "red": 16 }, + "glInternalFormat": "GL_R16F" + }, + "R16_SINT": { + "texFormat": "DXGI_FORMAT_R16_SINT", + "srvFormat": "DXGI_FORMAT_R16_SINT", + "rtvFormat": "DXGI_FORMAT_R16_SINT", + "channels": "r", + "componentType": "int", + "bits": { "red": 16 }, + "glInternalFormat": "GL_R16I" + }, + "R16_UINT": { + "texFormat": "DXGI_FORMAT_R16_UINT", + "srvFormat": "DXGI_FORMAT_R16_UINT", + "rtvFormat": "DXGI_FORMAT_R16_UINT", + "channels": "r", + "componentType": "uint", + "bits": { "red": 16 }, + "glInternalFormat": "GL_R16UI" + }, + "R32_FLOAT": { + "texFormat": "DXGI_FORMAT_R32_FLOAT", + "srvFormat": "DXGI_FORMAT_R32_FLOAT", + "rtvFormat": "DXGI_FORMAT_R32_FLOAT", + "channels": "r", + "componentType": "float", + "bits": { "red": 32 }, + "glInternalFormat": "GL_R32F" + }, + "R32_SINT": { + "texFormat": "DXGI_FORMAT_R32_SINT", + "srvFormat": "DXGI_FORMAT_R32_SINT", + "rtvFormat": "DXGI_FORMAT_R32_SINT", + "channels": "r", + "componentType": "int", + "bits": { "red": 32 }, + "glInternalFormat": "GL_R32I" + }, + "R32_UINT": { + "texFormat": "DXGI_FORMAT_R32_UINT", + "srvFormat": "DXGI_FORMAT_R32_UINT", + "rtvFormat": "DXGI_FORMAT_R32_UINT", + "channels": "r", + "componentType": "uint", + "bits": { "red": 32 }, + "glInternalFormat": "GL_R32UI" + }, + "R8_UNORM": { + "texFormat": "DXGI_FORMAT_R8_UNORM", + "srvFormat": "DXGI_FORMAT_R8_UNORM", + "rtvFormat": "DXGI_FORMAT_R8_UNORM", + "channels": "r", + "componentType": "unorm", + "bits": { "red": 8 }, + "glInternalFormat": "GL_R8" + }, + "R8_SINT": { + "texFormat": "DXGI_FORMAT_R8_SINT", + "srvFormat": "DXGI_FORMAT_R8_SINT", + "rtvFormat": "DXGI_FORMAT_R8_SINT", + "channels": "r", + "componentType": "int", + "bits": { "red": 8 }, + "glInternalFormat": "GL_R8I" + }, + "R8_UINT": { + "texFormat": "DXGI_FORMAT_R8_UINT", + "srvFormat": "DXGI_FORMAT_R8_UINT", + "rtvFormat": "DXGI_FORMAT_R8_UINT", + "channels": "r", + "componentType": "uint", + "bits": { "red": 8 }, + "glInternalFormat": "GL_R8UI" + }, + "R8_SNORM": { + "texFormat": "DXGI_FORMAT_R8_SNORM", + "srvFormat": "DXGI_FORMAT_R8_SNORM", + "channels": "r", + "componentType": "snorm", + "bits": { "red": 8 }, + "glInternalFormat": "GL_R8_SNORM" + }, + "R16G16_FLOAT": { + "texFormat": "DXGI_FORMAT_R16G16_FLOAT", + "srvFormat": "DXGI_FORMAT_R16G16_FLOAT", + "rtvFormat": "DXGI_FORMAT_R16G16_FLOAT", + "channels": "rg", + "componentType": "float", + "bits": { "red": 16, "green": 16 }, + "glInternalFormat": "GL_RG16F" + }, + "R16G16_SINT": { + "texFormat": "DXGI_FORMAT_R16G16_SINT", + "srvFormat": "DXGI_FORMAT_R16G16_SINT", + "rtvFormat": "DXGI_FORMAT_R16G16_SINT", + "channels": "rg", + "componentType": "int", + "bits": { "red": 16, "green": 16 }, + "glInternalFormat": "GL_RG16I" + }, + "R16G16_UINT": { + "texFormat": "DXGI_FORMAT_R16G16_UINT", + "srvFormat": "DXGI_FORMAT_R16G16_UINT", + "rtvFormat": "DXGI_FORMAT_R16G16_UINT", + "channels": "rg", + "componentType": "uint", + "bits": { "red": 16, "green": 16 }, + "glInternalFormat": "GL_RG16UI" + }, + "R32G32_FLOAT": { + "texFormat": "DXGI_FORMAT_R32G32_FLOAT", + "srvFormat": "DXGI_FORMAT_R32G32_FLOAT", + "rtvFormat": "DXGI_FORMAT_R32G32_FLOAT", + "channels": "rg", + "componentType": "float", + "bits": { "red": 32, "green": 32 }, + "glInternalFormat": "GL_RG32F" + }, + "R32G32_SINT": { + "texFormat": "DXGI_FORMAT_R32G32_SINT", + "srvFormat": "DXGI_FORMAT_R32G32_SINT", + "rtvFormat": "DXGI_FORMAT_R32G32_SINT", + "channels": "rg", + "componentType": "int", + "bits": { "red": 32, "green": 32 }, + "glInternalFormat": "GL_RG32I" + }, + "R32G32_UINT": { + "texFormat": "DXGI_FORMAT_R32G32_UINT", + "srvFormat": "DXGI_FORMAT_R32G32_UINT", + "rtvFormat": "DXGI_FORMAT_R32G32_UINT", + "channels": "rg", + "componentType": "uint", + "bits": { "red": 32, "green": 32 }, + "glInternalFormat": "GL_RG32UI" + }, + "R8G8_UNORM": { + "texFormat": "DXGI_FORMAT_R8G8_UNORM", + "srvFormat": "DXGI_FORMAT_R8G8_UNORM", + "rtvFormat": "DXGI_FORMAT_R8G8_UNORM", + "channels": "rg", + "componentType": "unorm", + "bits": { "red": 8, "green": 8 }, + "glInternalFormat": "GL_RG8" + }, + "R8G8_SINT": { + "texFormat": "DXGI_FORMAT_R8G8_SINT", + "srvFormat": "DXGI_FORMAT_R8G8_SINT", + "rtvFormat": "DXGI_FORMAT_R8G8_SINT", + "channels": "rg", + "componentType": "int", + "bits": { "red": 8, "green": 8 }, + "glInternalFormat": "GL_RG8I" + }, + "R8G8_UINT": { + "texFormat": "DXGI_FORMAT_R8G8_UINT", + "srvFormat": "DXGI_FORMAT_R8G8_UINT", + "rtvFormat": "DXGI_FORMAT_R8G8_UINT", + "channels": "rg", + "componentType": "uint", + "bits": { "red": 8, "green": 8 }, + "glInternalFormat": "GL_RG8UI" + }, + "R8G8_SNORM": { + "texFormat": "DXGI_FORMAT_R8G8_SNORM", + "srvFormat": "DXGI_FORMAT_R8G8_SNORM", + "channels": "rg", + "componentType": "snorm", + "bits": { "red": 8, "green": 8 }, + "glInternalFormat": "GL_RG8_SNORM" + }, + "R10G10B10A2_UNORM": { + "texFormat": "DXGI_FORMAT_R10G10B10A2_UNORM", + "srvFormat": "DXGI_FORMAT_R10G10B10A2_UNORM", + "rtvFormat": "DXGI_FORMAT_R10G10B10A2_UNORM", + "channels": "rgba", + "componentType": "unorm", + "bits": { "red": 10, "green": 10, "blue": 10, "alpha": 2 }, + "glInternalFormat": "GL_RGB10_A2" + }, + "R10G10B10A2_UINT": { + "texFormat": "DXGI_FORMAT_R10G10B10A2_UINT", + "srvFormat": "DXGI_FORMAT_R10G10B10A2_UINT", + "rtvFormat": "DXGI_FORMAT_R10G10B10A2_UINT", + "channels": "rgba", + "componentType": "uint", + "bits": { "red": 10, "green": 10, "blue": 10, "alpha": 2 }, + "glInternalFormat": "GL_RGB10_A2UI" + }, + "R16G16B16A16_SINT": { + "texFormat": "DXGI_FORMAT_R16G16B16A16_SINT", + "srvFormat": "DXGI_FORMAT_R16G16B16A16_SINT", + "rtvFormat": "DXGI_FORMAT_R16G16B16A16_SINT", + "channels": "rgba", + "componentType": "int", + "bits": { "red": 16, "green": 16, "blue": 16, "alpha": 16 }, + "glInternalFormat": "GL_RGBA16I" + }, + "R16G16B16A16_UINT": { + "texFormat": "DXGI_FORMAT_R16G16B16A16_UINT", + "srvFormat": "DXGI_FORMAT_R16G16B16A16_UINT", + "rtvFormat": "DXGI_FORMAT_R16G16B16A16_UINT", + "channels": "rgba", + "componentType": "uint", + "bits": { "red": 16, "green": 16, "blue": 16, "alpha": 16 }, + "glInternalFormat": "GL_RGBA16UI" + }, + "R32G32B32A32_SINT": { + "texFormat": "DXGI_FORMAT_R32G32B32A32_SINT", + "srvFormat": "DXGI_FORMAT_R32G32B32A32_SINT", + "rtvFormat": "DXGI_FORMAT_R32G32B32A32_SINT", + "channels": "rgba", + "componentType": "int", + "bits": { "red": 32, "green": 32, "blue": 32, "alpha": 32 }, + "glInternalFormat": "GL_RGBA32I" + }, + "R32G32B32A32_UINT": { + "texFormat": "DXGI_FORMAT_R32G32B32A32_UINT", + "srvFormat": "DXGI_FORMAT_R32G32B32A32_UINT", + "rtvFormat": "DXGI_FORMAT_R32G32B32A32_UINT", + "channels": "rgba", + "componentType": "uint", + "bits": { "red": 32, "green": 32, "blue": 32, "alpha": 32 }, + "glInternalFormat": "GL_RGBA32UI" + }, + "B5G6R5_UNORM": { + "texFormat": "DXGI_FORMAT_B5G6R5_UNORM", + "srvFormat": "DXGI_FORMAT_B5G6R5_UNORM", + "rtvFormat": "DXGI_FORMAT_B5G6R5_UNORM", + "channels": "bgr", + "componentType": "unorm", + "bits": { "red": 5, "green": 6, "blue": 5 }, + "supportTest": "SupportsFormat(DXGI_FORMAT_B5G6R5_UNORM, deviceCaps)", + "fallbackFormat": "R8G8B8A8_UNORM" + }, + "B5G5R5A1_UNORM": { + "texFormat": "DXGI_FORMAT_B5G5R5A1_UNORM", + "srvFormat": "DXGI_FORMAT_B5G5R5A1_UNORM", + "rtvFormat": "DXGI_FORMAT_B5G5R5A1_UNORM", + "channels": "bgra", + "componentType": "unorm", + "bits": { "red": 5, "green": 5, "blue": 5, "alpha": 1 }, + "supportTest": "SupportsFormat(DXGI_FORMAT_B5G5R5A1_UNORM, deviceCaps)", + "fallbackFormat": "R8G8B8A8_UNORM" + }, + "R8G8B8A8_SINT": { + "texFormat": "DXGI_FORMAT_R8G8B8A8_SINT", + "srvFormat": "DXGI_FORMAT_R8G8B8A8_SINT", + "rtvFormat": "DXGI_FORMAT_R8G8B8A8_SINT", + "channels": "rgba", + "componentType": "int", + "bits": { "red": 8, "green": 8, "blue": 8, "alpha": 8 }, + "glInternalFormat": "GL_RGBA8I" + }, + "R8G8B8A8_UINT": { + "texFormat": "DXGI_FORMAT_R8G8B8A8_UINT", + "srvFormat": "DXGI_FORMAT_R8G8B8A8_UINT", + "rtvFormat": "DXGI_FORMAT_R8G8B8A8_UINT", + "channels": "rgba", + "componentType": "uint", + "bits": { "red": 8, "green": 8, "blue": 8, "alpha": 8 }, + "glInternalFormat": "GL_RGBA8UI" + }, + "R8G8B8A8_SNORM": { + "texFormat": "DXGI_FORMAT_R8G8B8A8_SNORM", + "srvFormat": "DXGI_FORMAT_R8G8B8A8_SNORM", + "channels": "rgba", + "componentType": "snorm", + "bits": { "red": 8, "green": 8, "blue": 8, "alpha": 8 }, + "glInternalFormat": "GL_RGBA8_SNORM" + }, + "R9G9B9E5_SHAREDEXP": { + "texFormat": "DXGI_FORMAT_R9G9B9E5_SHAREDEXP", + "srvFormat": "DXGI_FORMAT_R9G9B9E5_SHAREDEXP", + "channels": "rgb", + "componentType": "float", + "bits": { "red": 9, "green": 9, "blue": 9, "shared": 5 } + }, + "B4G4R4A4_UNORM": { + "texFormat": "DXGI_FORMAT_B4G4R4A4_UNORM", + "srvFormat": "DXGI_FORMAT_B4G4R4A4_UNORM", + "rtvFormat": "DXGI_FORMAT_B4G4R4A4_UNORM", + "channels": "bgra", + "componentType": "unorm", + "bits": { "red": 4, "green": 4, "blue": 4, "alpha": 4 }, + "supportTest": "SupportsFormat(DXGI_FORMAT_B4G4R4A4_UNORM, deviceCaps)", + "fallbackFormat": "R8G8B8A8_UNORM" + }, + "R8G8B8A8_UNORM_SRGB": { + "texFormat": "DXGI_FORMAT_R8G8B8A8_UNORM_SRGB", + "srvFormat": "DXGI_FORMAT_R8G8B8A8_UNORM_SRGB", + "rtvFormat": "DXGI_FORMAT_R8G8B8A8_UNORM_SRGB", + "channels": "rgba", + "componentType": "unorm", + "bits": { "red": 8, "green": 8, "blue": 8, "alpha": 8 }, + "glInternalFormat": "GL_SRGB8_ALPHA8" + }, + "R16_UNORM": { + "texFormat": "DXGI_FORMAT_R16_UNORM", + "srvFormat": "DXGI_FORMAT_R16_UNORM", + "rtvFormat": "DXGI_FORMAT_R16_UNORM", + "channels": "r", + "componentType": "unorm", + "bits": { "red": 16 }, + "glInternalFormat": "GL_R16_EXT" + }, + "R16G16_UNORM": { + "texFormat": "DXGI_FORMAT_R16G16_UNORM", + "srvFormat": "DXGI_FORMAT_R16G16_UNORM", + "rtvFormat": "DXGI_FORMAT_R16G16_UNORM", + "channels": "rg", + "componentType": "unorm", + "bits": { "red": 16, "green": 16 }, + "glInternalFormat": "GL_RG16_EXT" + }, + "R16_SNORM": { + "texFormat": "DXGI_FORMAT_R16_SNORM", + "srvFormat": "DXGI_FORMAT_R16_SNORM", + "channels": "r", + "componentType": "snorm", + "bits": { "red": 16 }, + "glInternalFormat": "GL_R16_SNORM_EXT" + }, + "R16G16_SNORM": { + "texFormat": "DXGI_FORMAT_R16G16_SNORM", + "srvFormat": "DXGI_FORMAT_R16G16_SNORM", + "channels": "rg", + "componentType": "snorm", + "bits": { "red": 16, "green": 16 }, + "glInternalFormat": "GL_RG16_SNORM_EXT" + }, + "R16G16B16A16_SNORM": { + "texFormat": "DXGI_FORMAT_R16G16B16A16_SNORM", + "srvFormat": "DXGI_FORMAT_R16G16B16A16_SNORM", + "channels": "rgba", + "componentType": "snorm", + "bits": { "red": 16, "green": 16, "blue": 16, "alpha": 16 }, + "glInternalFormat": "GL_RGBA16_SNORM_EXT" + } } diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/texture_format_map.json b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/texture_format_map.json new file mode 100644 index 0000000000..3ef2355645 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/texture_format_map.json @@ -0,0 +1,78 @@ +{ + "GL_ALPHA16F_EXT": "R16G16B16A16_FLOAT", + "GL_ALPHA32F_EXT": "R32G32B32A32_FLOAT", + "GL_BGR5_A1_ANGLEX": "B8G8R8A8_UNORM", + "GL_BGRA4_ANGLEX": "B8G8R8A8_UNORM", + "GL_BGRA8_SRGB_ANGLEX": "B8G8R8A8_UNORM_SRGB", + "GL_COMPRESSED_R11_EAC": "R8_UNORM", + "GL_COMPRESSED_RG11_EAC": "R8G8_UNORM", + "GL_COMPRESSED_RGB8_ETC2": "R8G8B8A8_UNORM", + "GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2": "R8G8B8A8_UNORM", + "GL_COMPRESSED_RGBA8_ETC2_EAC": "R8G8B8A8_UNORM", + "GL_COMPRESSED_RGBA_ASTC_4x4_KHR": "NONE", + "GL_COMPRESSED_RGBA_ASTC_5x4_KHR": "NONE", + "GL_COMPRESSED_RGBA_ASTC_5x5_KHR": "NONE", + "GL_COMPRESSED_RGBA_ASTC_6x5_KHR": "NONE", + "GL_COMPRESSED_RGBA_ASTC_6x6_KHR": "NONE", + "GL_COMPRESSED_RGBA_ASTC_8x5_KHR": "NONE", + "GL_COMPRESSED_RGBA_ASTC_8x6_KHR": "NONE", + "GL_COMPRESSED_RGBA_ASTC_8x8_KHR": "NONE", + "GL_COMPRESSED_RGBA_ASTC_10x5_KHR": "NONE", + "GL_COMPRESSED_RGBA_ASTC_10x6_KHR": "NONE", + "GL_COMPRESSED_RGBA_ASTC_10x8_KHR": "NONE", + "GL_COMPRESSED_RGBA_ASTC_10x10_KHR": "NONE", + "GL_COMPRESSED_RGBA_ASTC_12x10_KHR": "NONE", + "GL_COMPRESSED_RGBA_ASTC_12x12_KHR": "NONE", + "GL_COMPRESSED_SIGNED_R11_EAC": "R8_SNORM", + "GL_COMPRESSED_SIGNED_RG11_EAC": "R8G8_SNORM", + "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR": "NONE", + "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR": "NONE", + "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR": "NONE", + "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR": "NONE", + "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR": "NONE", + "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR": "NONE", + "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR": "NONE", + "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR": "NONE", + "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR": "NONE", + "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR": "NONE", + "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR": "NONE", + "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR": "NONE", + "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR": "NONE", + "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR": "NONE", + "GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC": "R8G8B8A8_UNORM_SRGB", + "GL_COMPRESSED_SRGB8_ETC2": "R8G8B8A8_UNORM_SRGB", + "GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2": "R8G8B8A8_UNORM_SRGB", + "GL_DEPTH_COMPONENT24": "D24_UNORM_S8_UINT", + "GL_DEPTH_COMPONENT32_OES": "D24_UNORM_S8_UINT", + "GL_ETC1_RGB8_OES": "R8G8B8A8_UNORM", + "GL_ETC1_RGB8_LOSSY_DECODE_ANGLE": "BC1_RGB_UNORM_BLOCK", + "GL_COMPRESSED_RGB8_LOSSY_DECODE_ETC2_ANGLE": "BC1_RGB_UNORM_BLOCK", + "GL_COMPRESSED_SRGB8_LOSSY_DECODE_ETC2_ANGLE": "BC1_RGB_UNORM_SRGB_BLOCK", + "GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE": "BC1_RGBA_UNORM_BLOCK", + "GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE": "BC1_RGBA_UNORM_SRGB_BLOCK", + "GL_LUMINANCE16F_EXT": "R16G16B16A16_FLOAT", + "GL_LUMINANCE32F_EXT": "R32G32B32A32_FLOAT", + "GL_LUMINANCE8_ALPHA8_EXT": "R8G8B8A8_UNORM", + "GL_LUMINANCE8_EXT": "R8G8B8A8_UNORM", + "GL_LUMINANCE_ALPHA16F_EXT": "R16G16B16A16_FLOAT", + "GL_LUMINANCE_ALPHA32F_EXT": "R32G32B32A32_FLOAT", + "GL_RGB": "R8G8B8A8_UNORM", + "GL_RGB16F": "R16G16B16A16_FLOAT", + "GL_RGB16I": "R16G16B16A16_SINT", + "GL_RGB16UI": "R16G16B16A16_UINT", + "GL_RGB565": "B5G6R5_UNORM", + "GL_RGB5_A1": "B5G5R5A1_UNORM", + "GL_RGB8": "R8G8B8A8_UNORM", + "GL_RGB8I": "R8G8B8A8_SINT", + "GL_RGB8UI": "R8G8B8A8_UINT", + "GL_RGB8_SNORM": "R8G8B8A8_SNORM", + "GL_RGBA4": "B4G4R4A4_UNORM", + "GL_SRGB8": "R8G8B8A8_UNORM_SRGB", + "GL_STENCIL_INDEX8": "D24_UNORM_S8_UINT", + "GL_RGB16_EXT": "R16G16B16A16_UNORM", + "GL_RGBA16_EXT": "R16G16B16A16_UNORM", + "GL_RGB16_SNORM_EXT": "R16G16B16A16_SNORM", + "GL_RGB32F": "R32G32B32A32_FLOAT", + "GL_RGB32I": "R32G32B32A32_SINT", + "GL_RGB32UI": "R32G32B32A32_UINT" +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/texture_format_table.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/texture_format_table.cpp new file mode 100644 index 0000000000..a9dfec56b8 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/texture_format_table.cpp @@ -0,0 +1,35 @@ +// +// Copyright 2016 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 routines for the D3D11 texture format table. + +#include "libANGLE/renderer/d3d/d3d11/texture_format_table.h" + +#include "libANGLE/renderer/load_functions_table.h" + +namespace rx +{ + +namespace d3d11 +{ + +const Format &Format::getSwizzleFormat(const Renderer11DeviceCaps &deviceCaps) const +{ + return (swizzleFormat == internalFormat ? *this : Format::Get(swizzleFormat, deviceCaps)); +} + +LoadFunctionMap Format::getLoadFunctions() const +{ + return GetLoadFunctionsMap(internalFormat, formatID); +} + +const angle::Format &Format::format() const +{ + return angle::Format::Get(formatID); +} + +} // namespace d3d11 + +} // namespace rx diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/texture_format_table.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/texture_format_table.h index 1606a28a73..3efcb81adb 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/texture_format_table.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/texture_format_table.h @@ -12,50 +12,91 @@ #include +#include "common/angleutils.h" #include "common/platform.h" +#include "libANGLE/renderer/Format.h" +#include "libANGLE/renderer/renderer_utils.h" #include "libANGLE/renderer/d3d/formatutilsD3D.h" -#include "libANGLE/renderer/d3d/d3d11/Renderer11.h" namespace rx { -namespace d3d11 -{ +struct Renderer11DeviceCaps; -struct LoadImageFunctionInfo +namespace d3d11 { - LoadImageFunctionInfo() : loadFunction(nullptr), requiresConversion(false) {} - LoadImageFunctionInfo(LoadImageFunction loadFunction, bool requiresConversion) - : loadFunction(loadFunction), requiresConversion(requiresConversion) - { - } - - LoadImageFunction loadFunction; - bool requiresConversion; -}; -struct TextureFormat +// For sized GL internal formats, there are several possible corresponding D3D11 formats depending +// on device capabilities. +// This structure allows querying for the DXGI texture formats to use for textures, SRVs, RTVs and +// DSVs given a GL internal format. +struct Format final : private angle::NonCopyable { - TextureFormat(); + constexpr Format(); + constexpr Format(GLenum internalFormat, + angle::Format::ID formatID, + DXGI_FORMAT texFormat, + DXGI_FORMAT srvFormat, + DXGI_FORMAT rtvFormat, + DXGI_FORMAT dsvFormat, + DXGI_FORMAT blitSRVFormat, + GLenum swizzleFormat, + InitializeTextureDataFunction internalFormatInitializer); + + static const Format &Get(GLenum internalFormat, const Renderer11DeviceCaps &deviceCaps); + + const Format &getSwizzleFormat(const Renderer11DeviceCaps &deviceCaps) const; + LoadFunctionMap getLoadFunctions() const; + const angle::Format &format() const; + + GLenum internalFormat; + angle::Format::ID formatID; DXGI_FORMAT texFormat; DXGI_FORMAT srvFormat; DXGI_FORMAT rtvFormat; DXGI_FORMAT dsvFormat; - DXGI_FORMAT renderFormat; - DXGI_FORMAT swizzleTexFormat; - DXGI_FORMAT swizzleSRVFormat; - DXGI_FORMAT swizzleRTVFormat; + DXGI_FORMAT blitSRVFormat; - InitializeTextureDataFunction dataInitializerFunction; - typedef std::map LoadFunctionMap; + GLenum swizzleFormat; - LoadFunctionMap loadFunctions; + InitializeTextureDataFunction dataInitializerFunction; }; -const TextureFormat &GetTextureFormatInfo(GLenum internalformat, - const Renderer11DeviceCaps &renderer11DeviceCaps); +constexpr Format::Format() + : internalFormat(GL_NONE), + formatID(angle::Format::ID::NONE), + texFormat(DXGI_FORMAT_UNKNOWN), + srvFormat(DXGI_FORMAT_UNKNOWN), + rtvFormat(DXGI_FORMAT_UNKNOWN), + dsvFormat(DXGI_FORMAT_UNKNOWN), + blitSRVFormat(DXGI_FORMAT_UNKNOWN), + swizzleFormat(GL_NONE), + dataInitializerFunction(nullptr) +{ +} + +constexpr Format::Format(GLenum internalFormat, + angle::Format::ID formatID, + DXGI_FORMAT texFormat, + DXGI_FORMAT srvFormat, + DXGI_FORMAT rtvFormat, + DXGI_FORMAT dsvFormat, + DXGI_FORMAT blitSRVFormat, + GLenum swizzleFormat, + InitializeTextureDataFunction internalFormatInitializer) + : internalFormat(internalFormat), + formatID(formatID), + texFormat(texFormat), + srvFormat(srvFormat), + rtvFormat(rtvFormat), + dsvFormat(dsvFormat), + blitSRVFormat(blitSRVFormat), + swizzleFormat(swizzleFormat), + dataInitializerFunction(internalFormatInitializer) +{ +} } // namespace d3d11 diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/texture_format_table_autogen.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/texture_format_table_autogen.cpp index 0b214c9756..3c1c2bcd50 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/texture_format_table_autogen.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/texture_format_table_autogen.cpp @@ -1,7 +1,7 @@ // GENERATED FILE - DO NOT EDIT. // Generated by gen_texture_format_table.py using data from texture_format_data.json // -// Copyright 2015 The ANGLE Project Authors. All rights reserved. +// Copyright 2017 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. // @@ -11,12 +11,15 @@ #include "libANGLE/renderer/d3d/d3d11/texture_format_table.h" +#include "image_util/copyimage.h" +#include "image_util/generatemip.h" +#include "image_util/loadimage.h" + #include "libANGLE/renderer/d3d/d3d11/formatutils11.h" -#include "libANGLE/renderer/d3d/d3d11/internal_format_initializer_table.h" -#include "libANGLE/renderer/d3d/d3d11/load_functions_table.h" #include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h" -#include "libANGLE/renderer/d3d/d3d11/swizzle_format_info.h" -#include "libANGLE/renderer/d3d/loadimage.h" +#include "libANGLE/renderer/d3d/d3d11/texture_format_table_utils.h" + +using namespace angle; namespace rx { @@ -24,1756 +27,1899 @@ namespace rx namespace d3d11 { -namespace -{ - -typedef bool (*FormatSupportFunction)(const Renderer11DeviceCaps &); - -bool AnyDevice(const Renderer11DeviceCaps &deviceCaps) -{ - return true; -} - -bool OnlyFL10Plus(const Renderer11DeviceCaps &deviceCaps) -{ - return (deviceCaps.featureLevel >= D3D_FEATURE_LEVEL_10_0); -} - -bool OnlyFL9_3(const Renderer11DeviceCaps &deviceCaps) -{ - return (deviceCaps.featureLevel == D3D_FEATURE_LEVEL_9_3); -} - -template -bool SupportsFormat(const Renderer11DeviceCaps &deviceCaps) -{ - // Must support texture, SRV and RTV support - UINT mustSupport = D3D11_FORMAT_SUPPORT_TEXTURE2D | D3D11_FORMAT_SUPPORT_TEXTURECUBE | - D3D11_FORMAT_SUPPORT_SHADER_SAMPLE | D3D11_FORMAT_SUPPORT_MIP | - D3D11_FORMAT_SUPPORT_RENDER_TARGET; - - if (d3d11_gl::GetMaximumClientVersion(deviceCaps.featureLevel) > 2) - { - mustSupport |= D3D11_FORMAT_SUPPORT_TEXTURE3D; - } - - bool fullSupport = false; - if (format == DXGI_FORMAT_B5G6R5_UNORM) - { - // All hardware that supports DXGI_FORMAT_B5G6R5_UNORM should support autogen mipmaps, but - // check anyway. - mustSupport |= D3D11_FORMAT_SUPPORT_MIP_AUTOGEN; - fullSupport = ((deviceCaps.B5G6R5support & mustSupport) == mustSupport); - } - else if (format == DXGI_FORMAT_B4G4R4A4_UNORM) - { - fullSupport = ((deviceCaps.B4G4R4A4support & mustSupport) == mustSupport); - } - else if (format == DXGI_FORMAT_B5G5R5A1_UNORM) - { - fullSupport = ((deviceCaps.B5G5R5A1support & mustSupport) == mustSupport); - } - else - { - UNREACHABLE(); - return false; - } - - // This 'SupportsFormat' function is used by individual entries in the D3D11 Format Map below, - // which maps GL formats to DXGI formats. - if (requireSupport) - { - // This means that ANGLE would like to use the entry in the map if the inputted DXGI format - // *IS* supported. - // e.g. the entry might map GL_RGB5_A1 to DXGI_FORMAT_B5G5R5A1, which should only be used if - // DXGI_FORMAT_B5G5R5A1 is supported. - // In this case, we should only return 'true' if the format *IS* supported. - return fullSupport; - } - else - { - // This means that ANGLE would like to use the entry in the map if the inputted DXGI format - // *ISN'T* supported. - // This might be a fallback entry. e.g. for ANGLE to use DXGI_FORMAT_R8G8B8A8_UNORM if - // DXGI_FORMAT_B5G5R5A1 isn't supported. - // In this case, we should only return 'true' if the format *ISN'T* supported. - return !fullSupport; - } -} - -// End Format Support Functions - -// For sized GL internal formats, there are several possible corresponding D3D11 formats depending -// on device capabilities. -// This function allows querying for the DXGI texture formats to use for textures, SRVs, RTVs and -// DSVs given a GL internal format. -const TextureFormat GetD3D11FormatInfo(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); - - const SwizzleFormatInfo &swizzleInfo = - GetSwizzleFormatInfo(maxBits, formatInfo.componentType); - 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 - info.dataInitializerFunction = GetInternalFormatInitializer(internalFormat, texFormat); - // Gather all the load functions for this internal format - info.loadFunctions = GetLoadFunctionsMap(internalFormat, texFormat); - - ASSERT(info.loadFunctions.size() != 0 || internalFormat == GL_NONE); - - return info; -} - -} // namespace - -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() -{ -} - -const TextureFormat &GetTextureFormatInfo(GLenum internalFormat, - const Renderer11DeviceCaps &renderer11DeviceCaps) +// static +const Format &Format::Get(GLenum internalFormat, const Renderer11DeviceCaps &deviceCaps) { // clang-format off switch (internalFormat) { - case GL_ALPHA: - { - if (OnlyFL10Plus(renderer11DeviceCaps)) - { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_A8_UNORM, - DXGI_FORMAT_A8_UNORM, - DXGI_FORMAT_A8_UNORM, - DXGI_FORMAT_UNKNOWN); - return textureFormat; - } - else if (OnlyFL9_3(renderer11DeviceCaps)) - { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_R8G8B8A8_UNORM, - DXGI_FORMAT_R8G8B8A8_UNORM, - DXGI_FORMAT_R8G8B8A8_UNORM, - DXGI_FORMAT_UNKNOWN); - return textureFormat; - } - else - { - break; - } - } case GL_ALPHA16F_EXT: { - if (AnyDevice(renderer11DeviceCaps)) - { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_R16G16B16A16_FLOAT, - DXGI_FORMAT_R16G16B16A16_FLOAT, - DXGI_FORMAT_R16G16B16A16_FLOAT, - DXGI_FORMAT_UNKNOWN); - return textureFormat; - } - else - { - break; - } + static constexpr Format info(GL_ALPHA16F_EXT, + angle::Format::ID::R16G16B16A16_FLOAT, + DXGI_FORMAT_R16G16B16A16_FLOAT, + DXGI_FORMAT_R16G16B16A16_FLOAT, + DXGI_FORMAT_R16G16B16A16_FLOAT, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R16G16B16A16_FLOAT, + GL_RGBA16F, + nullptr); + return info; } case GL_ALPHA32F_EXT: { - if (AnyDevice(renderer11DeviceCaps)) - { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_R32G32B32A32_FLOAT, - DXGI_FORMAT_R32G32B32A32_FLOAT, - DXGI_FORMAT_R32G32B32A32_FLOAT, - DXGI_FORMAT_UNKNOWN); - return textureFormat; - } - else - { - break; - } + static constexpr Format info(GL_ALPHA32F_EXT, + angle::Format::ID::R32G32B32A32_FLOAT, + DXGI_FORMAT_R32G32B32A32_FLOAT, + DXGI_FORMAT_R32G32B32A32_FLOAT, + DXGI_FORMAT_R32G32B32A32_FLOAT, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R32G32B32A32_FLOAT, + GL_RGBA32F, + nullptr); + return info; } case GL_ALPHA8_EXT: { - if (OnlyFL10Plus(renderer11DeviceCaps)) - { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_A8_UNORM, - DXGI_FORMAT_A8_UNORM, - DXGI_FORMAT_A8_UNORM, - DXGI_FORMAT_UNKNOWN); - return textureFormat; - } - else if (OnlyFL9_3(renderer11DeviceCaps)) + if (OnlyFL10Plus(deviceCaps)) { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_R8G8B8A8_UNORM, - DXGI_FORMAT_R8G8B8A8_UNORM, - DXGI_FORMAT_R8G8B8A8_UNORM, - DXGI_FORMAT_UNKNOWN); - return textureFormat; + static constexpr Format info(GL_ALPHA8_EXT, + angle::Format::ID::A8_UNORM, + DXGI_FORMAT_A8_UNORM, + DXGI_FORMAT_A8_UNORM, + DXGI_FORMAT_A8_UNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_A8_UNORM, + GL_RGBA8, + nullptr); + return info; } else { - break; + static constexpr Format info(GL_ALPHA8_EXT, + angle::Format::ID::R8G8B8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R8G8B8A8_UNORM, + GL_RGBA8, + nullptr); + return info; } } - case GL_BGR5_A1_ANGLEX: + case GL_BGR565_ANGLEX: { - if (AnyDevice(renderer11DeviceCaps)) + if (SupportsFormat(DXGI_FORMAT_B5G6R5_UNORM, deviceCaps)) { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_B8G8R8A8_UNORM, - DXGI_FORMAT_B8G8R8A8_UNORM, - DXGI_FORMAT_B8G8R8A8_UNORM, - DXGI_FORMAT_UNKNOWN); - return textureFormat; + static constexpr Format info(GL_BGR565_ANGLEX, + angle::Format::ID::B5G6R5_UNORM, + DXGI_FORMAT_B5G6R5_UNORM, + DXGI_FORMAT_B5G6R5_UNORM, + DXGI_FORMAT_B5G6R5_UNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_B5G6R5_UNORM, + GL_RGBA8, + nullptr); + return info; } else { - break; + static constexpr Format info(GL_BGR565_ANGLEX, + angle::Format::ID::R8G8B8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R8G8B8A8_UNORM, + GL_RGBA8, + nullptr); + return info; } } - case GL_BGRA4_ANGLEX: + case GL_BGR5_A1_ANGLEX: { - if (AnyDevice(renderer11DeviceCaps)) - { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_B8G8R8A8_UNORM, - DXGI_FORMAT_B8G8R8A8_UNORM, - DXGI_FORMAT_B8G8R8A8_UNORM, - DXGI_FORMAT_UNKNOWN); - return textureFormat; - } - else - { - break; - } + static constexpr Format info(GL_BGR5_A1_ANGLEX, + angle::Format::ID::B8G8R8A8_UNORM, + DXGI_FORMAT_B8G8R8A8_UNORM, + DXGI_FORMAT_B8G8R8A8_UNORM, + DXGI_FORMAT_B8G8R8A8_UNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_B8G8R8A8_UNORM, + GL_BGRA8_EXT, + nullptr); + return info; } - case GL_BGRA8_EXT: + case GL_BGRA4_ANGLEX: { - if (AnyDevice(renderer11DeviceCaps)) - { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_B8G8R8A8_UNORM, - DXGI_FORMAT_B8G8R8A8_UNORM, - DXGI_FORMAT_B8G8R8A8_UNORM, - DXGI_FORMAT_UNKNOWN); - return textureFormat; - } - else - { - break; - } + static constexpr Format info(GL_BGRA4_ANGLEX, + angle::Format::ID::B8G8R8A8_UNORM, + DXGI_FORMAT_B8G8R8A8_UNORM, + DXGI_FORMAT_B8G8R8A8_UNORM, + DXGI_FORMAT_B8G8R8A8_UNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_B8G8R8A8_UNORM, + GL_BGRA8_EXT, + nullptr); + return info; } - case GL_BGRA_EXT: + case GL_BGRA8_EXT: { - if (AnyDevice(renderer11DeviceCaps)) - { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_B8G8R8A8_UNORM, - DXGI_FORMAT_B8G8R8A8_UNORM, - DXGI_FORMAT_B8G8R8A8_UNORM, - DXGI_FORMAT_UNKNOWN); - return textureFormat; - } - else - { - break; - } + static constexpr Format info(GL_BGRA8_EXT, + angle::Format::ID::B8G8R8A8_UNORM, + DXGI_FORMAT_B8G8R8A8_UNORM, + DXGI_FORMAT_B8G8R8A8_UNORM, + DXGI_FORMAT_B8G8R8A8_UNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_B8G8R8A8_UNORM, + GL_BGRA8_EXT, + nullptr); + return info; + } + case GL_BGRA8_SRGB_ANGLEX: + { + static constexpr Format info(GL_BGRA8_SRGB_ANGLEX, + angle::Format::ID::B8G8R8A8_UNORM_SRGB, + DXGI_FORMAT_B8G8R8A8_UNORM_SRGB, + DXGI_FORMAT_B8G8R8A8_UNORM_SRGB, + DXGI_FORMAT_B8G8R8A8_UNORM_SRGB, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_B8G8R8A8_UNORM_SRGB, + GL_BGRA8_SRGB_ANGLEX, + nullptr); + return info; } case GL_COMPRESSED_R11_EAC: { - if (OnlyFL10Plus(renderer11DeviceCaps)) - { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_R8_UNORM, - DXGI_FORMAT_R8_UNORM, - DXGI_FORMAT_UNKNOWN, - DXGI_FORMAT_UNKNOWN); - return textureFormat; - } - else - { - break; - } + static constexpr Format info(GL_COMPRESSED_R11_EAC, + angle::Format::ID::R8_UNORM, + DXGI_FORMAT_R8_UNORM, + DXGI_FORMAT_R8_UNORM, + DXGI_FORMAT_R8_UNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R8_UNORM, + GL_RGBA8, + nullptr); + return info; } case GL_COMPRESSED_RG11_EAC: { - if (OnlyFL10Plus(renderer11DeviceCaps)) - { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_R8G8_UNORM, - DXGI_FORMAT_R8G8_UNORM, - DXGI_FORMAT_UNKNOWN, - DXGI_FORMAT_UNKNOWN); - return textureFormat; - } - else - { - break; - } + static constexpr Format info(GL_COMPRESSED_RG11_EAC, + angle::Format::ID::R8G8_UNORM, + DXGI_FORMAT_R8G8_UNORM, + DXGI_FORMAT_R8G8_UNORM, + DXGI_FORMAT_R8G8_UNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R8G8_UNORM, + GL_RGBA8, + nullptr); + return info; } case GL_COMPRESSED_RGB8_ETC2: { - if (OnlyFL10Plus(renderer11DeviceCaps)) - { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_R8G8B8A8_UNORM, - DXGI_FORMAT_R8G8B8A8_UNORM, - DXGI_FORMAT_UNKNOWN, - DXGI_FORMAT_UNKNOWN); - return textureFormat; - } - else - { - break; - } + static constexpr Format info(GL_COMPRESSED_RGB8_ETC2, + angle::Format::ID::R8G8B8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R8G8B8A8_UNORM, + GL_RGBA8, + Initialize4ComponentData); + return info; + } + case GL_COMPRESSED_RGB8_LOSSY_DECODE_ETC2_ANGLE: + { + static constexpr Format info(GL_COMPRESSED_RGB8_LOSSY_DECODE_ETC2_ANGLE, + angle::Format::ID::BC1_RGB_UNORM_BLOCK, + DXGI_FORMAT_BC1_UNORM, + DXGI_FORMAT_BC1_UNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_BC1_UNORM, + GL_RGBA8, + nullptr); + return info; } case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2: { - if (OnlyFL10Plus(renderer11DeviceCaps)) - { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_R8G8B8A8_UNORM, - DXGI_FORMAT_R8G8B8A8_UNORM, - DXGI_FORMAT_UNKNOWN, - DXGI_FORMAT_UNKNOWN); - return textureFormat; - } - else - { - break; - } + static constexpr Format info(GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2, + angle::Format::ID::R8G8B8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R8G8B8A8_UNORM, + GL_RGBA8, + Initialize4ComponentData); + return info; + } + case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE: + { + static constexpr Format info(GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE, + angle::Format::ID::BC1_RGBA_UNORM_BLOCK, + DXGI_FORMAT_BC1_UNORM, + DXGI_FORMAT_BC1_UNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_BC1_UNORM, + GL_RGBA8, + nullptr); + return info; } case GL_COMPRESSED_RGBA8_ETC2_EAC: { - if (OnlyFL10Plus(renderer11DeviceCaps)) - { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_R8G8B8A8_UNORM, - DXGI_FORMAT_R8G8B8A8_UNORM, - DXGI_FORMAT_UNKNOWN, - DXGI_FORMAT_UNKNOWN); - return textureFormat; - } - else - { - break; - } + static constexpr Format info(GL_COMPRESSED_RGBA8_ETC2_EAC, + angle::Format::ID::R8G8B8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R8G8B8A8_UNORM, + GL_RGBA8, + nullptr); + return info; + } + case GL_COMPRESSED_RGBA_ASTC_10x10_KHR: + { + static constexpr Format info(GL_COMPRESSED_RGBA_ASTC_10x10_KHR, + angle::Format::ID::NONE, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + GL_NONE, + nullptr); + return info; + } + case GL_COMPRESSED_RGBA_ASTC_10x5_KHR: + { + static constexpr Format info(GL_COMPRESSED_RGBA_ASTC_10x5_KHR, + angle::Format::ID::NONE, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + GL_NONE, + nullptr); + return info; + } + case GL_COMPRESSED_RGBA_ASTC_10x6_KHR: + { + static constexpr Format info(GL_COMPRESSED_RGBA_ASTC_10x6_KHR, + angle::Format::ID::NONE, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + GL_NONE, + nullptr); + return info; + } + case GL_COMPRESSED_RGBA_ASTC_10x8_KHR: + { + static constexpr Format info(GL_COMPRESSED_RGBA_ASTC_10x8_KHR, + angle::Format::ID::NONE, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + GL_NONE, + nullptr); + return info; + } + case GL_COMPRESSED_RGBA_ASTC_12x10_KHR: + { + static constexpr Format info(GL_COMPRESSED_RGBA_ASTC_12x10_KHR, + angle::Format::ID::NONE, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + GL_NONE, + nullptr); + return info; + } + case GL_COMPRESSED_RGBA_ASTC_12x12_KHR: + { + static constexpr Format info(GL_COMPRESSED_RGBA_ASTC_12x12_KHR, + angle::Format::ID::NONE, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + GL_NONE, + nullptr); + return info; + } + case GL_COMPRESSED_RGBA_ASTC_4x4_KHR: + { + static constexpr Format info(GL_COMPRESSED_RGBA_ASTC_4x4_KHR, + angle::Format::ID::NONE, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + GL_NONE, + nullptr); + return info; + } + case GL_COMPRESSED_RGBA_ASTC_5x4_KHR: + { + static constexpr Format info(GL_COMPRESSED_RGBA_ASTC_5x4_KHR, + angle::Format::ID::NONE, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + GL_NONE, + nullptr); + return info; + } + case GL_COMPRESSED_RGBA_ASTC_5x5_KHR: + { + static constexpr Format info(GL_COMPRESSED_RGBA_ASTC_5x5_KHR, + angle::Format::ID::NONE, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + GL_NONE, + nullptr); + return info; + } + case GL_COMPRESSED_RGBA_ASTC_6x5_KHR: + { + static constexpr Format info(GL_COMPRESSED_RGBA_ASTC_6x5_KHR, + angle::Format::ID::NONE, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + GL_NONE, + nullptr); + return info; + } + case GL_COMPRESSED_RGBA_ASTC_6x6_KHR: + { + static constexpr Format info(GL_COMPRESSED_RGBA_ASTC_6x6_KHR, + angle::Format::ID::NONE, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + GL_NONE, + nullptr); + return info; + } + case GL_COMPRESSED_RGBA_ASTC_8x5_KHR: + { + static constexpr Format info(GL_COMPRESSED_RGBA_ASTC_8x5_KHR, + angle::Format::ID::NONE, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + GL_NONE, + nullptr); + return info; + } + case GL_COMPRESSED_RGBA_ASTC_8x6_KHR: + { + static constexpr Format info(GL_COMPRESSED_RGBA_ASTC_8x6_KHR, + angle::Format::ID::NONE, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + GL_NONE, + nullptr); + return info; + } + case GL_COMPRESSED_RGBA_ASTC_8x8_KHR: + { + static constexpr Format info(GL_COMPRESSED_RGBA_ASTC_8x8_KHR, + angle::Format::ID::NONE, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + GL_NONE, + nullptr); + return info; } case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: { - if (AnyDevice(renderer11DeviceCaps)) - { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_BC1_UNORM, - DXGI_FORMAT_BC1_UNORM, - DXGI_FORMAT_UNKNOWN, - DXGI_FORMAT_UNKNOWN); - return textureFormat; - } - else - { - break; - } + static constexpr Format info(GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, + angle::Format::ID::BC1_RGBA_UNORM_BLOCK, + DXGI_FORMAT_BC1_UNORM, + DXGI_FORMAT_BC1_UNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_BC1_UNORM, + GL_RGBA8, + nullptr); + return info; } case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: { - if (AnyDevice(renderer11DeviceCaps)) - { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_BC2_UNORM, - DXGI_FORMAT_BC2_UNORM, - DXGI_FORMAT_UNKNOWN, - DXGI_FORMAT_UNKNOWN); - return textureFormat; - } - else - { - break; - } + static constexpr Format info(GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE, + angle::Format::ID::BC2_RGBA_UNORM_BLOCK, + DXGI_FORMAT_BC2_UNORM, + DXGI_FORMAT_BC2_UNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_BC2_UNORM, + GL_RGBA8, + nullptr); + return info; } case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: { - if (AnyDevice(renderer11DeviceCaps)) - { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_BC3_UNORM, - DXGI_FORMAT_BC3_UNORM, - DXGI_FORMAT_UNKNOWN, - DXGI_FORMAT_UNKNOWN); - return textureFormat; - } - else - { - break; - } + static constexpr Format info(GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE, + angle::Format::ID::BC3_RGBA_UNORM_BLOCK, + DXGI_FORMAT_BC3_UNORM, + DXGI_FORMAT_BC3_UNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_BC3_UNORM, + GL_RGBA8, + nullptr); + return info; } case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: { - if (AnyDevice(renderer11DeviceCaps)) - { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_BC1_UNORM, - DXGI_FORMAT_BC1_UNORM, - DXGI_FORMAT_UNKNOWN, - DXGI_FORMAT_UNKNOWN); - return textureFormat; - } - else - { - break; - } + static constexpr Format info(GL_COMPRESSED_RGB_S3TC_DXT1_EXT, + angle::Format::ID::BC1_RGB_UNORM_BLOCK, + DXGI_FORMAT_BC1_UNORM, + DXGI_FORMAT_BC1_UNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_BC1_UNORM, + GL_RGBA8, + nullptr); + return info; } case GL_COMPRESSED_SIGNED_R11_EAC: { - if (OnlyFL10Plus(renderer11DeviceCaps)) - { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_R8_SNORM, - DXGI_FORMAT_R8_SNORM, - DXGI_FORMAT_UNKNOWN, - DXGI_FORMAT_UNKNOWN); - return textureFormat; - } - else - { - break; - } + static constexpr Format info(GL_COMPRESSED_SIGNED_R11_EAC, + angle::Format::ID::R8_SNORM, + DXGI_FORMAT_R8_SNORM, + DXGI_FORMAT_R8_SNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R8_SNORM, + GL_RGBA8_SNORM, + nullptr); + return info; } case GL_COMPRESSED_SIGNED_RG11_EAC: { - if (OnlyFL10Plus(renderer11DeviceCaps)) - { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_R8G8_SNORM, - DXGI_FORMAT_R8G8_SNORM, - DXGI_FORMAT_UNKNOWN, - DXGI_FORMAT_UNKNOWN); - return textureFormat; - } - else - { - break; - } + static constexpr Format info(GL_COMPRESSED_SIGNED_RG11_EAC, + angle::Format::ID::R8G8_SNORM, + DXGI_FORMAT_R8G8_SNORM, + DXGI_FORMAT_R8G8_SNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R8G8_SNORM, + GL_RGBA8_SNORM, + nullptr); + return info; + } + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR: + { + static constexpr Format info(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR, + angle::Format::ID::NONE, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + GL_NONE, + nullptr); + return info; + } + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR: + { + static constexpr Format info(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR, + angle::Format::ID::NONE, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + GL_NONE, + nullptr); + return info; + } + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR: + { + static constexpr Format info(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR, + angle::Format::ID::NONE, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + GL_NONE, + nullptr); + return info; + } + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR: + { + static constexpr Format info(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR, + angle::Format::ID::NONE, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + GL_NONE, + nullptr); + return info; + } + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR: + { + static constexpr Format info(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR, + angle::Format::ID::NONE, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + GL_NONE, + nullptr); + return info; + } + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR: + { + static constexpr Format info(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR, + angle::Format::ID::NONE, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + GL_NONE, + nullptr); + return info; + } + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR: + { + static constexpr Format info(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR, + angle::Format::ID::NONE, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + GL_NONE, + nullptr); + return info; + } + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR: + { + static constexpr Format info(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR, + angle::Format::ID::NONE, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + GL_NONE, + nullptr); + return info; + } + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR: + { + static constexpr Format info(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR, + angle::Format::ID::NONE, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + GL_NONE, + nullptr); + return info; + } + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR: + { + static constexpr Format info(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR, + angle::Format::ID::NONE, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + GL_NONE, + nullptr); + return info; + } + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR: + { + static constexpr Format info(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR, + angle::Format::ID::NONE, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + GL_NONE, + nullptr); + return info; + } + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR: + { + static constexpr Format info(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR, + angle::Format::ID::NONE, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + GL_NONE, + nullptr); + return info; + } + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR: + { + static constexpr Format info(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR, + angle::Format::ID::NONE, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + GL_NONE, + nullptr); + return info; + } + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR: + { + static constexpr Format info(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR, + angle::Format::ID::NONE, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + GL_NONE, + nullptr); + return info; } case GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC: { - if (OnlyFL10Plus(renderer11DeviceCaps)) - { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, - DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, - DXGI_FORMAT_UNKNOWN, - DXGI_FORMAT_UNKNOWN); - return textureFormat; - } - else - { - break; - } + static constexpr Format info(GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC, + angle::Format::ID::R8G8B8A8_UNORM_SRGB, + DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, + DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, + DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, + GL_SRGB8_ALPHA8, + nullptr); + return info; } case GL_COMPRESSED_SRGB8_ETC2: { - if (OnlyFL10Plus(renderer11DeviceCaps)) - { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, - DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, - DXGI_FORMAT_UNKNOWN, - DXGI_FORMAT_UNKNOWN); - return textureFormat; - } - else - { - break; - } + static constexpr Format info(GL_COMPRESSED_SRGB8_ETC2, + angle::Format::ID::R8G8B8A8_UNORM_SRGB, + DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, + DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, + DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, + GL_SRGB8_ALPHA8, + Initialize4ComponentData); + return info; + } + case GL_COMPRESSED_SRGB8_LOSSY_DECODE_ETC2_ANGLE: + { + static constexpr Format info(GL_COMPRESSED_SRGB8_LOSSY_DECODE_ETC2_ANGLE, + angle::Format::ID::BC1_RGB_UNORM_SRGB_BLOCK, + DXGI_FORMAT_BC1_UNORM_SRGB, + DXGI_FORMAT_BC1_UNORM_SRGB, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_BC1_UNORM_SRGB, + GL_RGBA8, + nullptr); + return info; } case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2: { - if (OnlyFL10Plus(renderer11DeviceCaps)) - { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, - DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, - DXGI_FORMAT_UNKNOWN, - DXGI_FORMAT_UNKNOWN); - return textureFormat; - } - else - { - break; - } + static constexpr Format info(GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2, + angle::Format::ID::R8G8B8A8_UNORM_SRGB, + DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, + DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, + DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, + GL_SRGB8_ALPHA8, + nullptr); + return info; + } + case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE: + { + static constexpr Format info(GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE, + angle::Format::ID::BC1_RGBA_UNORM_SRGB_BLOCK, + DXGI_FORMAT_BC1_UNORM_SRGB, + DXGI_FORMAT_BC1_UNORM_SRGB, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_BC1_UNORM_SRGB, + GL_RGBA8, + nullptr); + return info; + } + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT: + { + static constexpr Format info(GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT, + angle::Format::ID::BC1_RGBA_UNORM_SRGB_BLOCK, + DXGI_FORMAT_BC1_UNORM_SRGB, + DXGI_FORMAT_BC1_UNORM_SRGB, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_BC1_UNORM_SRGB, + GL_RGBA8, + nullptr); + return info; + } + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT: + { + static constexpr Format info(GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT, + angle::Format::ID::BC2_RGBA_UNORM_SRGB_BLOCK, + DXGI_FORMAT_BC2_UNORM_SRGB, + DXGI_FORMAT_BC2_UNORM_SRGB, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_BC2_UNORM_SRGB, + GL_RGBA8, + nullptr); + return info; + } + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT: + { + static constexpr Format info(GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, + angle::Format::ID::BC3_RGBA_UNORM_SRGB_BLOCK, + DXGI_FORMAT_BC3_UNORM_SRGB, + DXGI_FORMAT_BC3_UNORM_SRGB, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_BC3_UNORM_SRGB, + GL_RGBA8, + nullptr); + return info; + } + case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT: + { + static constexpr Format info(GL_COMPRESSED_SRGB_S3TC_DXT1_EXT, + angle::Format::ID::BC1_RGB_UNORM_SRGB_BLOCK, + DXGI_FORMAT_BC1_UNORM_SRGB, + DXGI_FORMAT_BC1_UNORM_SRGB, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_BC1_UNORM_SRGB, + GL_RGBA8, + nullptr); + return info; } case GL_DEPTH24_STENCIL8: { - if (OnlyFL9_3(renderer11DeviceCaps)) - { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_D24_UNORM_S8_UINT, - DXGI_FORMAT_UNKNOWN, - DXGI_FORMAT_UNKNOWN, - DXGI_FORMAT_D24_UNORM_S8_UINT); - return textureFormat; - } - else if (OnlyFL10Plus(renderer11DeviceCaps)) + if (OnlyFL10Plus(deviceCaps)) { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_R24G8_TYPELESS, - DXGI_FORMAT_R24_UNORM_X8_TYPELESS, - DXGI_FORMAT_UNKNOWN, - DXGI_FORMAT_D24_UNORM_S8_UINT); - return textureFormat; + static constexpr Format info(GL_DEPTH24_STENCIL8, + angle::Format::ID::D24_UNORM_S8_UINT, + DXGI_FORMAT_R24G8_TYPELESS, + DXGI_FORMAT_R24_UNORM_X8_TYPELESS, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_D24_UNORM_S8_UINT, + DXGI_FORMAT_R24_UNORM_X8_TYPELESS, + GL_RGBA32F, + nullptr); + return info; } else { - break; + static constexpr Format info(GL_DEPTH24_STENCIL8, + angle::Format::ID::D24_UNORM_S8_UINT, + DXGI_FORMAT_D24_UNORM_S8_UINT, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_D24_UNORM_S8_UINT, + DXGI_FORMAT_UNKNOWN, + GL_RGBA32F, + nullptr); + return info; } } case GL_DEPTH32F_STENCIL8: { - if (OnlyFL9_3(renderer11DeviceCaps)) - { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_UNKNOWN, - DXGI_FORMAT_UNKNOWN, - DXGI_FORMAT_UNKNOWN, - DXGI_FORMAT_UNKNOWN); - return textureFormat; - } - else if (OnlyFL10Plus(renderer11DeviceCaps)) - { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_R32G8X24_TYPELESS, - DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS, - DXGI_FORMAT_UNKNOWN, - DXGI_FORMAT_D32_FLOAT_S8X24_UINT); - return textureFormat; - } - else - { - break; - } + static constexpr Format info(GL_DEPTH32F_STENCIL8, + angle::Format::ID::D32_FLOAT_S8X24_UINT, + DXGI_FORMAT_R32G8X24_TYPELESS, + DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_D32_FLOAT_S8X24_UINT, + DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS, + GL_RGBA32F, + nullptr); + return info; } case GL_DEPTH_COMPONENT16: { - if (OnlyFL9_3(renderer11DeviceCaps)) + if (OnlyFL10Plus(deviceCaps)) { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_D16_UNORM, - DXGI_FORMAT_UNKNOWN, - DXGI_FORMAT_UNKNOWN, - DXGI_FORMAT_D16_UNORM); - return textureFormat; - } - else if (OnlyFL10Plus(renderer11DeviceCaps)) - { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_R16_TYPELESS, - DXGI_FORMAT_R16_UNORM, - DXGI_FORMAT_UNKNOWN, - DXGI_FORMAT_D16_UNORM); - return textureFormat; + static constexpr Format info(GL_DEPTH_COMPONENT16, + angle::Format::ID::D16_UNORM, + DXGI_FORMAT_R16_TYPELESS, + DXGI_FORMAT_R16_UNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_D16_UNORM, + DXGI_FORMAT_R16_UNORM, + GL_RGBA16_EXT, + nullptr); + return info; } else { - break; + static constexpr Format info(GL_DEPTH_COMPONENT16, + angle::Format::ID::D16_UNORM, + DXGI_FORMAT_D16_UNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_D16_UNORM, + DXGI_FORMAT_UNKNOWN, + GL_RGBA16_EXT, + nullptr); + return info; } } case GL_DEPTH_COMPONENT24: { - if (OnlyFL9_3(renderer11DeviceCaps)) - { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_D24_UNORM_S8_UINT, - DXGI_FORMAT_UNKNOWN, - DXGI_FORMAT_UNKNOWN, - DXGI_FORMAT_D24_UNORM_S8_UINT); - return textureFormat; - } - else if (OnlyFL10Plus(renderer11DeviceCaps)) + if (OnlyFL10Plus(deviceCaps)) { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_R24G8_TYPELESS, - DXGI_FORMAT_R24_UNORM_X8_TYPELESS, - DXGI_FORMAT_UNKNOWN, - DXGI_FORMAT_D24_UNORM_S8_UINT); - return textureFormat; + static constexpr Format info(GL_DEPTH_COMPONENT24, + angle::Format::ID::D24_UNORM_S8_UINT, + DXGI_FORMAT_R24G8_TYPELESS, + DXGI_FORMAT_R24_UNORM_X8_TYPELESS, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_D24_UNORM_S8_UINT, + DXGI_FORMAT_R24_UNORM_X8_TYPELESS, + GL_RGBA32F, + nullptr); + return info; } else { - break; + static constexpr Format info(GL_DEPTH_COMPONENT24, + angle::Format::ID::D24_UNORM_S8_UINT, + DXGI_FORMAT_D24_UNORM_S8_UINT, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_D24_UNORM_S8_UINT, + DXGI_FORMAT_UNKNOWN, + GL_RGBA32F, + nullptr); + return info; } } case GL_DEPTH_COMPONENT32F: { - if (OnlyFL9_3(renderer11DeviceCaps)) - { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_UNKNOWN, - DXGI_FORMAT_UNKNOWN, - DXGI_FORMAT_UNKNOWN, - DXGI_FORMAT_UNKNOWN); - return textureFormat; - } - else if (OnlyFL10Plus(renderer11DeviceCaps)) - { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_R32_TYPELESS, - DXGI_FORMAT_R32_FLOAT, - DXGI_FORMAT_UNKNOWN, - DXGI_FORMAT_D32_FLOAT); - return textureFormat; - } - else - { - break; - } + static constexpr Format info(GL_DEPTH_COMPONENT32F, + angle::Format::ID::D32_FLOAT, + DXGI_FORMAT_R32_TYPELESS, + DXGI_FORMAT_R32_FLOAT, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_D32_FLOAT, + DXGI_FORMAT_R32_FLOAT, + GL_RGBA32F, + nullptr); + return info; } case GL_DEPTH_COMPONENT32_OES: { - if (OnlyFL10Plus(renderer11DeviceCaps)) + if (OnlyFL10Plus(deviceCaps)) { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_R24G8_TYPELESS, - DXGI_FORMAT_R24_UNORM_X8_TYPELESS, - DXGI_FORMAT_UNKNOWN, - DXGI_FORMAT_D24_UNORM_S8_UINT); - return textureFormat; + static constexpr Format info(GL_DEPTH_COMPONENT32_OES, + angle::Format::ID::D24_UNORM_S8_UINT, + DXGI_FORMAT_R24G8_TYPELESS, + DXGI_FORMAT_R24_UNORM_X8_TYPELESS, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_D24_UNORM_S8_UINT, + DXGI_FORMAT_R24_UNORM_X8_TYPELESS, + GL_RGBA32F, + nullptr); + return info; } else { - break; + static constexpr Format info(GL_DEPTH_COMPONENT32_OES, + angle::Format::ID::D24_UNORM_S8_UINT, + DXGI_FORMAT_D24_UNORM_S8_UINT, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_D24_UNORM_S8_UINT, + DXGI_FORMAT_UNKNOWN, + GL_RGBA32F, + nullptr); + return info; } } case GL_ETC1_RGB8_LOSSY_DECODE_ANGLE: { - if (AnyDevice(renderer11DeviceCaps)) - { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_BC1_UNORM, - DXGI_FORMAT_BC1_UNORM, - DXGI_FORMAT_UNKNOWN, - DXGI_FORMAT_UNKNOWN); - return textureFormat; - } - else - { - break; - } + static constexpr Format info(GL_ETC1_RGB8_LOSSY_DECODE_ANGLE, + angle::Format::ID::BC1_RGB_UNORM_BLOCK, + DXGI_FORMAT_BC1_UNORM, + DXGI_FORMAT_BC1_UNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_BC1_UNORM, + GL_RGBA8, + nullptr); + return info; } case GL_ETC1_RGB8_OES: { - if (AnyDevice(renderer11DeviceCaps)) - { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_R8G8B8A8_UNORM, - DXGI_FORMAT_R8G8B8A8_UNORM, - DXGI_FORMAT_UNKNOWN, - DXGI_FORMAT_UNKNOWN); - return textureFormat; - } - else - { - break; - } - } - case GL_LUMINANCE: - { - if (AnyDevice(renderer11DeviceCaps)) - { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_R8G8B8A8_UNORM, - DXGI_FORMAT_R8G8B8A8_UNORM, - DXGI_FORMAT_R8G8B8A8_UNORM, - DXGI_FORMAT_UNKNOWN); - return textureFormat; - } - else - { - break; - } + static constexpr Format info(GL_ETC1_RGB8_OES, + angle::Format::ID::R8G8B8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R8G8B8A8_UNORM, + GL_RGBA8, + Initialize4ComponentData); + return info; } case GL_LUMINANCE16F_EXT: { - if (AnyDevice(renderer11DeviceCaps)) - { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_R16G16B16A16_FLOAT, - DXGI_FORMAT_R16G16B16A16_FLOAT, - DXGI_FORMAT_R16G16B16A16_FLOAT, - DXGI_FORMAT_UNKNOWN); - return textureFormat; - } - else - { - break; - } + static constexpr Format info(GL_LUMINANCE16F_EXT, + angle::Format::ID::R16G16B16A16_FLOAT, + DXGI_FORMAT_R16G16B16A16_FLOAT, + DXGI_FORMAT_R16G16B16A16_FLOAT, + DXGI_FORMAT_R16G16B16A16_FLOAT, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R16G16B16A16_FLOAT, + GL_RGBA16F, + Initialize4ComponentData); + return info; } case GL_LUMINANCE32F_EXT: { - if (AnyDevice(renderer11DeviceCaps)) - { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_R32G32B32A32_FLOAT, - DXGI_FORMAT_R32G32B32A32_FLOAT, - DXGI_FORMAT_R32G32B32A32_FLOAT, - DXGI_FORMAT_UNKNOWN); - return textureFormat; - } - else - { - break; - } + static constexpr Format info(GL_LUMINANCE32F_EXT, + angle::Format::ID::R32G32B32A32_FLOAT, + DXGI_FORMAT_R32G32B32A32_FLOAT, + DXGI_FORMAT_R32G32B32A32_FLOAT, + DXGI_FORMAT_R32G32B32A32_FLOAT, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R32G32B32A32_FLOAT, + GL_RGBA32F, + Initialize4ComponentData); + return info; } case GL_LUMINANCE8_ALPHA8_EXT: { - if (AnyDevice(renderer11DeviceCaps)) - { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_R8G8B8A8_UNORM, - DXGI_FORMAT_R8G8B8A8_UNORM, - DXGI_FORMAT_R8G8B8A8_UNORM, - DXGI_FORMAT_UNKNOWN); - return textureFormat; - } - else - { - break; - } + static constexpr Format info(GL_LUMINANCE8_ALPHA8_EXT, + angle::Format::ID::R8G8B8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R8G8B8A8_UNORM, + GL_RGBA8, + nullptr); + return info; } case GL_LUMINANCE8_EXT: { - if (AnyDevice(renderer11DeviceCaps)) - { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_R8G8B8A8_UNORM, - DXGI_FORMAT_R8G8B8A8_UNORM, - DXGI_FORMAT_R8G8B8A8_UNORM, - DXGI_FORMAT_UNKNOWN); - return textureFormat; - } - else - { - break; - } - } - case GL_LUMINANCE_ALPHA: - { - if (AnyDevice(renderer11DeviceCaps)) - { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_R8G8B8A8_UNORM, - DXGI_FORMAT_R8G8B8A8_UNORM, - DXGI_FORMAT_R8G8B8A8_UNORM, - DXGI_FORMAT_UNKNOWN); - return textureFormat; - } - else - { - break; - } + static constexpr Format info(GL_LUMINANCE8_EXT, + angle::Format::ID::R8G8B8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R8G8B8A8_UNORM, + GL_RGBA8, + Initialize4ComponentData); + return info; } case GL_LUMINANCE_ALPHA16F_EXT: { - if (AnyDevice(renderer11DeviceCaps)) - { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_R16G16B16A16_FLOAT, - DXGI_FORMAT_R16G16B16A16_FLOAT, - DXGI_FORMAT_R16G16B16A16_FLOAT, - DXGI_FORMAT_UNKNOWN); - return textureFormat; - } - else - { - break; - } + static constexpr Format info(GL_LUMINANCE_ALPHA16F_EXT, + angle::Format::ID::R16G16B16A16_FLOAT, + DXGI_FORMAT_R16G16B16A16_FLOAT, + DXGI_FORMAT_R16G16B16A16_FLOAT, + DXGI_FORMAT_R16G16B16A16_FLOAT, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R16G16B16A16_FLOAT, + GL_RGBA16F, + nullptr); + return info; } case GL_LUMINANCE_ALPHA32F_EXT: { - if (AnyDevice(renderer11DeviceCaps)) - { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_R32G32B32A32_FLOAT, - DXGI_FORMAT_R32G32B32A32_FLOAT, - DXGI_FORMAT_R32G32B32A32_FLOAT, - DXGI_FORMAT_UNKNOWN); - return textureFormat; - } - else - { - break; - } + static constexpr Format info(GL_LUMINANCE_ALPHA32F_EXT, + angle::Format::ID::R32G32B32A32_FLOAT, + DXGI_FORMAT_R32G32B32A32_FLOAT, + DXGI_FORMAT_R32G32B32A32_FLOAT, + DXGI_FORMAT_R32G32B32A32_FLOAT, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R32G32B32A32_FLOAT, + GL_RGBA32F, + nullptr); + return info; } case GL_NONE: { - if (AnyDevice(renderer11DeviceCaps)) - { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_UNKNOWN, - DXGI_FORMAT_UNKNOWN, - DXGI_FORMAT_UNKNOWN, - DXGI_FORMAT_UNKNOWN); - return textureFormat; - } - else - { - break; - } + static constexpr Format info(GL_NONE, + angle::Format::ID::NONE, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + GL_NONE, + nullptr); + return info; } case GL_R11F_G11F_B10F: { - if (AnyDevice(renderer11DeviceCaps)) - { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_R11G11B10_FLOAT, - DXGI_FORMAT_R11G11B10_FLOAT, - DXGI_FORMAT_R11G11B10_FLOAT, - DXGI_FORMAT_UNKNOWN); - return textureFormat; - } - else - { - break; - } + static constexpr Format info(GL_R11F_G11F_B10F, + angle::Format::ID::R11G11B10_FLOAT, + DXGI_FORMAT_R11G11B10_FLOAT, + DXGI_FORMAT_R11G11B10_FLOAT, + DXGI_FORMAT_R11G11B10_FLOAT, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R11G11B10_FLOAT, + GL_RGBA16F_EXT, + nullptr); + return info; } case GL_R16F: { - if (AnyDevice(renderer11DeviceCaps)) - { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_R16_FLOAT, - DXGI_FORMAT_R16_FLOAT, - DXGI_FORMAT_R16_FLOAT, - DXGI_FORMAT_UNKNOWN); - return textureFormat; - } - else - { - break; - } + static constexpr Format info(GL_R16F, + angle::Format::ID::R16_FLOAT, + DXGI_FORMAT_R16_FLOAT, + DXGI_FORMAT_R16_FLOAT, + DXGI_FORMAT_R16_FLOAT, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R16_FLOAT, + GL_RGBA16F_EXT, + nullptr); + return info; } case GL_R16I: { - if (AnyDevice(renderer11DeviceCaps)) - { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_R16_SINT, - DXGI_FORMAT_R16_SINT, - DXGI_FORMAT_R16_SINT, - DXGI_FORMAT_UNKNOWN); - return textureFormat; - } - else - { - break; - } + static constexpr Format info(GL_R16I, + angle::Format::ID::R16_SINT, + DXGI_FORMAT_R16_SINT, + DXGI_FORMAT_R16_SINT, + DXGI_FORMAT_R16_SINT, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R16_SINT, + GL_RGBA16I, + nullptr); + return info; } case GL_R16UI: { - if (AnyDevice(renderer11DeviceCaps)) - { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_R16_UINT, - DXGI_FORMAT_R16_UINT, - DXGI_FORMAT_R16_UINT, - DXGI_FORMAT_UNKNOWN); - return textureFormat; - } - else - { - break; - } + static constexpr Format info(GL_R16UI, + angle::Format::ID::R16_UINT, + DXGI_FORMAT_R16_UINT, + DXGI_FORMAT_R16_UINT, + DXGI_FORMAT_R16_UINT, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R16_UINT, + GL_RGBA16I, + nullptr); + return info; + } + case GL_R16_EXT: + { + static constexpr Format info(GL_R16_EXT, + angle::Format::ID::R16_UNORM, + DXGI_FORMAT_R16_UNORM, + DXGI_FORMAT_R16_UNORM, + DXGI_FORMAT_R16_UNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R16_UNORM, + GL_RGBA16_EXT, + nullptr); + return info; + } + case GL_R16_SNORM_EXT: + { + static constexpr Format info(GL_R16_SNORM_EXT, + angle::Format::ID::R16_SNORM, + DXGI_FORMAT_R16_SNORM, + DXGI_FORMAT_R16_SNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R16_SNORM, + GL_RGBA16_SNORM_EXT, + nullptr); + return info; } case GL_R32F: { - if (AnyDevice(renderer11DeviceCaps)) - { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_R32_FLOAT, - DXGI_FORMAT_R32_FLOAT, - DXGI_FORMAT_R32_FLOAT, - DXGI_FORMAT_UNKNOWN); - return textureFormat; - } - else - { - break; - } + static constexpr Format info(GL_R32F, + angle::Format::ID::R32_FLOAT, + DXGI_FORMAT_R32_FLOAT, + DXGI_FORMAT_R32_FLOAT, + DXGI_FORMAT_R32_FLOAT, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R32_FLOAT, + GL_RGBA32F, + nullptr); + return info; } case GL_R32I: { - if (AnyDevice(renderer11DeviceCaps)) - { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_R32_SINT, - DXGI_FORMAT_R32_SINT, - DXGI_FORMAT_R32_SINT, - DXGI_FORMAT_UNKNOWN); - return textureFormat; - } - else - { - break; - } + static constexpr Format info(GL_R32I, + angle::Format::ID::R32_SINT, + DXGI_FORMAT_R32_SINT, + DXGI_FORMAT_R32_SINT, + DXGI_FORMAT_R32_SINT, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R32_SINT, + GL_RGBA32I, + nullptr); + return info; } case GL_R32UI: { - if (AnyDevice(renderer11DeviceCaps)) - { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_R32_UINT, - DXGI_FORMAT_R32_UINT, - DXGI_FORMAT_R32_UINT, - DXGI_FORMAT_UNKNOWN); - return textureFormat; - } - else - { - break; - } + static constexpr Format info(GL_R32UI, + angle::Format::ID::R32_UINT, + DXGI_FORMAT_R32_UINT, + DXGI_FORMAT_R32_UINT, + DXGI_FORMAT_R32_UINT, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R32_UINT, + GL_RGBA32I, + nullptr); + return info; } case GL_R8: { - if (AnyDevice(renderer11DeviceCaps)) - { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_R8_UNORM, - DXGI_FORMAT_R8_UNORM, - DXGI_FORMAT_R8_UNORM, - DXGI_FORMAT_UNKNOWN); - return textureFormat; - } - else - { - break; - } + static constexpr Format info(GL_R8, + angle::Format::ID::R8_UNORM, + DXGI_FORMAT_R8_UNORM, + DXGI_FORMAT_R8_UNORM, + DXGI_FORMAT_R8_UNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R8_UNORM, + GL_RGBA8, + nullptr); + return info; } case GL_R8I: { - if (AnyDevice(renderer11DeviceCaps)) - { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_R8_SINT, - DXGI_FORMAT_R8_SINT, - DXGI_FORMAT_R8_SINT, - DXGI_FORMAT_UNKNOWN); - return textureFormat; - } - else - { - break; - } + static constexpr Format info(GL_R8I, + angle::Format::ID::R8_SINT, + DXGI_FORMAT_R8_SINT, + DXGI_FORMAT_R8_SINT, + DXGI_FORMAT_R8_SINT, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R8_SINT, + GL_RGBA8I, + nullptr); + return info; } case GL_R8UI: { - if (AnyDevice(renderer11DeviceCaps)) - { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_R8_UINT, - DXGI_FORMAT_R8_UINT, - DXGI_FORMAT_R8_UINT, - DXGI_FORMAT_UNKNOWN); - return textureFormat; - } - else - { - break; - } + static constexpr Format info(GL_R8UI, + angle::Format::ID::R8_UINT, + DXGI_FORMAT_R8_UINT, + DXGI_FORMAT_R8_UINT, + DXGI_FORMAT_R8_UINT, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R8_UINT, + GL_RGBA8I, + nullptr); + return info; } case GL_R8_SNORM: { - if (AnyDevice(renderer11DeviceCaps)) - { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_R8_SNORM, - DXGI_FORMAT_R8_SNORM, - DXGI_FORMAT_UNKNOWN, - DXGI_FORMAT_UNKNOWN); - return textureFormat; - } - else - { - break; - } + static constexpr Format info(GL_R8_SNORM, + angle::Format::ID::R8_SNORM, + DXGI_FORMAT_R8_SNORM, + DXGI_FORMAT_R8_SNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R8_SNORM, + GL_RGBA8_SNORM, + nullptr); + return info; } case GL_RG16F: { - if (AnyDevice(renderer11DeviceCaps)) - { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_R16G16_FLOAT, - DXGI_FORMAT_R16G16_FLOAT, - DXGI_FORMAT_R16G16_FLOAT, - DXGI_FORMAT_UNKNOWN); - return textureFormat; - } - else - { - break; - } + static constexpr Format info(GL_RG16F, + angle::Format::ID::R16G16_FLOAT, + DXGI_FORMAT_R16G16_FLOAT, + DXGI_FORMAT_R16G16_FLOAT, + DXGI_FORMAT_R16G16_FLOAT, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R16G16_FLOAT, + GL_RGBA16F_EXT, + nullptr); + return info; } case GL_RG16I: { - if (AnyDevice(renderer11DeviceCaps)) - { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_R16G16_SINT, - DXGI_FORMAT_R16G16_SINT, - DXGI_FORMAT_R16G16_SINT, - DXGI_FORMAT_UNKNOWN); - return textureFormat; - } - else - { - break; - } + static constexpr Format info(GL_RG16I, + angle::Format::ID::R16G16_SINT, + DXGI_FORMAT_R16G16_SINT, + DXGI_FORMAT_R16G16_SINT, + DXGI_FORMAT_R16G16_SINT, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R16G16_SINT, + GL_RGBA16I, + nullptr); + return info; } case GL_RG16UI: { - if (AnyDevice(renderer11DeviceCaps)) - { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_R16G16_UINT, - DXGI_FORMAT_R16G16_UINT, - DXGI_FORMAT_R16G16_UINT, - DXGI_FORMAT_UNKNOWN); - return textureFormat; - } - else - { - break; - } + static constexpr Format info(GL_RG16UI, + angle::Format::ID::R16G16_UINT, + DXGI_FORMAT_R16G16_UINT, + DXGI_FORMAT_R16G16_UINT, + DXGI_FORMAT_R16G16_UINT, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R16G16_UINT, + GL_RGBA16I, + nullptr); + return info; + } + case GL_RG16_EXT: + { + static constexpr Format info(GL_RG16_EXT, + angle::Format::ID::R16G16_UNORM, + DXGI_FORMAT_R16G16_UNORM, + DXGI_FORMAT_R16G16_UNORM, + DXGI_FORMAT_R16G16_UNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R16G16_UNORM, + GL_RGBA16_EXT, + nullptr); + return info; + } + case GL_RG16_SNORM_EXT: + { + static constexpr Format info(GL_RG16_SNORM_EXT, + angle::Format::ID::R16G16_SNORM, + DXGI_FORMAT_R16G16_SNORM, + DXGI_FORMAT_R16G16_SNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R16G16_SNORM, + GL_RGBA16_SNORM_EXT, + nullptr); + return info; } case GL_RG32F: { - if (AnyDevice(renderer11DeviceCaps)) - { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_R32G32_FLOAT, - DXGI_FORMAT_R32G32_FLOAT, - DXGI_FORMAT_R32G32_FLOAT, - DXGI_FORMAT_UNKNOWN); - return textureFormat; - } - else - { - break; - } + static constexpr Format info(GL_RG32F, + angle::Format::ID::R32G32_FLOAT, + DXGI_FORMAT_R32G32_FLOAT, + DXGI_FORMAT_R32G32_FLOAT, + DXGI_FORMAT_R32G32_FLOAT, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R32G32_FLOAT, + GL_RGBA32F, + nullptr); + return info; } case GL_RG32I: { - if (AnyDevice(renderer11DeviceCaps)) - { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_R32G32_SINT, - DXGI_FORMAT_R32G32_SINT, - DXGI_FORMAT_R32G32_SINT, - DXGI_FORMAT_UNKNOWN); - return textureFormat; - } - else - { - break; - } + static constexpr Format info(GL_RG32I, + angle::Format::ID::R32G32_SINT, + DXGI_FORMAT_R32G32_SINT, + DXGI_FORMAT_R32G32_SINT, + DXGI_FORMAT_R32G32_SINT, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R32G32_SINT, + GL_RGBA32I, + nullptr); + return info; } case GL_RG32UI: { - if (AnyDevice(renderer11DeviceCaps)) - { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_R32G32_UINT, - DXGI_FORMAT_R32G32_UINT, - DXGI_FORMAT_R32G32_UINT, - DXGI_FORMAT_UNKNOWN); - return textureFormat; - } - else - { - break; - } + static constexpr Format info(GL_RG32UI, + angle::Format::ID::R32G32_UINT, + DXGI_FORMAT_R32G32_UINT, + DXGI_FORMAT_R32G32_UINT, + DXGI_FORMAT_R32G32_UINT, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R32G32_UINT, + GL_RGBA32I, + nullptr); + return info; } case GL_RG8: { - if (AnyDevice(renderer11DeviceCaps)) - { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_R8G8_UNORM, - DXGI_FORMAT_R8G8_UNORM, - DXGI_FORMAT_R8G8_UNORM, - DXGI_FORMAT_UNKNOWN); - return textureFormat; - } - else - { - break; - } + static constexpr Format info(GL_RG8, + angle::Format::ID::R8G8_UNORM, + DXGI_FORMAT_R8G8_UNORM, + DXGI_FORMAT_R8G8_UNORM, + DXGI_FORMAT_R8G8_UNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R8G8_UNORM, + GL_RGBA8, + nullptr); + return info; } case GL_RG8I: { - if (AnyDevice(renderer11DeviceCaps)) - { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_R8G8_SINT, - DXGI_FORMAT_R8G8_SINT, - DXGI_FORMAT_R8G8_SINT, - DXGI_FORMAT_UNKNOWN); - return textureFormat; - } - else - { - break; - } + static constexpr Format info(GL_RG8I, + angle::Format::ID::R8G8_SINT, + DXGI_FORMAT_R8G8_SINT, + DXGI_FORMAT_R8G8_SINT, + DXGI_FORMAT_R8G8_SINT, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R8G8_SINT, + GL_RGBA8I, + nullptr); + return info; } case GL_RG8UI: { - if (AnyDevice(renderer11DeviceCaps)) - { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_R8G8_UINT, - DXGI_FORMAT_R8G8_UINT, - DXGI_FORMAT_R8G8_UINT, - DXGI_FORMAT_UNKNOWN); - return textureFormat; - } - else - { - break; - } + static constexpr Format info(GL_RG8UI, + angle::Format::ID::R8G8_UINT, + DXGI_FORMAT_R8G8_UINT, + DXGI_FORMAT_R8G8_UINT, + DXGI_FORMAT_R8G8_UINT, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R8G8_UINT, + GL_RGBA8I, + nullptr); + return info; } case GL_RG8_SNORM: { - if (AnyDevice(renderer11DeviceCaps)) - { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_R8G8_SNORM, - DXGI_FORMAT_R8G8_SNORM, - DXGI_FORMAT_UNKNOWN, - DXGI_FORMAT_UNKNOWN); - return textureFormat; - } - else - { - break; - } + static constexpr Format info(GL_RG8_SNORM, + angle::Format::ID::R8G8_SNORM, + DXGI_FORMAT_R8G8_SNORM, + DXGI_FORMAT_R8G8_SNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R8G8_SNORM, + GL_RGBA8_SNORM, + nullptr); + return info; } case GL_RGB: { - if (AnyDevice(renderer11DeviceCaps)) - { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_R8G8B8A8_UNORM, - DXGI_FORMAT_R8G8B8A8_UNORM, - DXGI_FORMAT_R8G8B8A8_UNORM, - DXGI_FORMAT_UNKNOWN); - return textureFormat; - } - else - { - break; - } + static constexpr Format info(GL_RGB, + angle::Format::ID::R8G8B8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R8G8B8A8_UNORM, + GL_RGBA8, + Initialize4ComponentData); + return info; } case GL_RGB10_A2: { - if (AnyDevice(renderer11DeviceCaps)) - { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_R10G10B10A2_UNORM, - DXGI_FORMAT_R10G10B10A2_UNORM, - DXGI_FORMAT_R10G10B10A2_UNORM, - DXGI_FORMAT_UNKNOWN); - return textureFormat; - } - else - { - break; - } + static constexpr Format info(GL_RGB10_A2, + angle::Format::ID::R10G10B10A2_UNORM, + DXGI_FORMAT_R10G10B10A2_UNORM, + DXGI_FORMAT_R10G10B10A2_UNORM, + DXGI_FORMAT_R10G10B10A2_UNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R10G10B10A2_UNORM, + GL_RGBA16_EXT, + nullptr); + return info; } case GL_RGB10_A2UI: { - if (AnyDevice(renderer11DeviceCaps)) - { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_R10G10B10A2_UINT, - DXGI_FORMAT_R10G10B10A2_UINT, - DXGI_FORMAT_R10G10B10A2_UINT, - DXGI_FORMAT_UNKNOWN); - return textureFormat; - } - else - { - break; - } + static constexpr Format info(GL_RGB10_A2UI, + angle::Format::ID::R10G10B10A2_UINT, + DXGI_FORMAT_R10G10B10A2_UINT, + DXGI_FORMAT_R10G10B10A2_UINT, + DXGI_FORMAT_R10G10B10A2_UINT, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R10G10B10A2_UINT, + GL_RGBA16I, + nullptr); + return info; } case GL_RGB16F: { - if (AnyDevice(renderer11DeviceCaps)) - { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_R16G16B16A16_FLOAT, - DXGI_FORMAT_R16G16B16A16_FLOAT, - DXGI_FORMAT_R16G16B16A16_FLOAT, - DXGI_FORMAT_UNKNOWN); - return textureFormat; - } - else - { - break; - } + static constexpr Format info(GL_RGB16F, + angle::Format::ID::R16G16B16A16_FLOAT, + DXGI_FORMAT_R16G16B16A16_FLOAT, + DXGI_FORMAT_R16G16B16A16_FLOAT, + DXGI_FORMAT_R16G16B16A16_FLOAT, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R16G16B16A16_FLOAT, + GL_RGBA16F, + Initialize4ComponentData); + return info; } case GL_RGB16I: { - if (AnyDevice(renderer11DeviceCaps)) - { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_R16G16B16A16_SINT, - DXGI_FORMAT_R16G16B16A16_SINT, - DXGI_FORMAT_R16G16B16A16_SINT, - DXGI_FORMAT_UNKNOWN); - return textureFormat; - } - else - { - break; - } + static constexpr Format info(GL_RGB16I, + angle::Format::ID::R16G16B16A16_SINT, + DXGI_FORMAT_R16G16B16A16_SINT, + DXGI_FORMAT_R16G16B16A16_SINT, + DXGI_FORMAT_R16G16B16A16_SINT, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R16G16B16A16_SINT, + GL_RGBA16I, + Initialize4ComponentData); + return info; } case GL_RGB16UI: { - if (AnyDevice(renderer11DeviceCaps)) - { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_R16G16B16A16_UINT, - DXGI_FORMAT_R16G16B16A16_UINT, - DXGI_FORMAT_R16G16B16A16_UINT, - DXGI_FORMAT_UNKNOWN); - return textureFormat; - } - else - { - break; - } + static constexpr Format info(GL_RGB16UI, + angle::Format::ID::R16G16B16A16_UINT, + DXGI_FORMAT_R16G16B16A16_UINT, + DXGI_FORMAT_R16G16B16A16_UINT, + DXGI_FORMAT_R16G16B16A16_UINT, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R16G16B16A16_UINT, + GL_RGBA16UI, + Initialize4ComponentData); + return info; + } + case GL_RGB16_EXT: + { + static constexpr Format info(GL_RGB16_EXT, + angle::Format::ID::R16G16B16A16_UNORM, + DXGI_FORMAT_R16G16B16A16_UNORM, + DXGI_FORMAT_R16G16B16A16_UNORM, + DXGI_FORMAT_R16G16B16A16_UNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R16G16B16A16_UNORM, + GL_RGBA16_EXT, + Initialize4ComponentData); + return info; + } + case GL_RGB16_SNORM_EXT: + { + static constexpr Format info(GL_RGB16_SNORM_EXT, + angle::Format::ID::R16G16B16A16_SNORM, + DXGI_FORMAT_R16G16B16A16_SNORM, + DXGI_FORMAT_R16G16B16A16_SNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R16G16B16A16_SNORM, + GL_RGBA16_SNORM_EXT, + Initialize4ComponentData); + return info; } case GL_RGB32F: { - if (AnyDevice(renderer11DeviceCaps)) - { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_R32G32B32A32_FLOAT, - DXGI_FORMAT_R32G32B32A32_FLOAT, - DXGI_FORMAT_R32G32B32A32_FLOAT, - DXGI_FORMAT_UNKNOWN); - return textureFormat; - } - else - { - break; - } + static constexpr Format info(GL_RGB32F, + angle::Format::ID::R32G32B32A32_FLOAT, + DXGI_FORMAT_R32G32B32A32_FLOAT, + DXGI_FORMAT_R32G32B32A32_FLOAT, + DXGI_FORMAT_R32G32B32A32_FLOAT, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R32G32B32A32_FLOAT, + GL_RGBA32F, + Initialize4ComponentData); + return info; } case GL_RGB32I: { - if (AnyDevice(renderer11DeviceCaps)) - { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_R32G32B32A32_SINT, - DXGI_FORMAT_R32G32B32A32_SINT, - DXGI_FORMAT_R32G32B32A32_SINT, - DXGI_FORMAT_UNKNOWN); - return textureFormat; - } - else - { - break; - } + static constexpr Format info(GL_RGB32I, + angle::Format::ID::R32G32B32A32_SINT, + DXGI_FORMAT_R32G32B32A32_SINT, + DXGI_FORMAT_R32G32B32A32_SINT, + DXGI_FORMAT_R32G32B32A32_SINT, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R32G32B32A32_SINT, + GL_RGBA32I, + Initialize4ComponentData); + return info; } case GL_RGB32UI: { - if (AnyDevice(renderer11DeviceCaps)) - { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_R32G32B32A32_UINT, - DXGI_FORMAT_R32G32B32A32_UINT, - DXGI_FORMAT_R32G32B32A32_UINT, - DXGI_FORMAT_UNKNOWN); - return textureFormat; - } - else - { - break; - } + static constexpr Format info(GL_RGB32UI, + angle::Format::ID::R32G32B32A32_UINT, + DXGI_FORMAT_R32G32B32A32_UINT, + DXGI_FORMAT_R32G32B32A32_UINT, + DXGI_FORMAT_R32G32B32A32_UINT, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R32G32B32A32_UINT, + GL_RGBA32UI, + Initialize4ComponentData); + return info; } case GL_RGB565: { - if (SupportsFormat(renderer11DeviceCaps)) + if (SupportsFormat(DXGI_FORMAT_B5G6R5_UNORM, deviceCaps)) { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_R8G8B8A8_UNORM, - DXGI_FORMAT_R8G8B8A8_UNORM, - DXGI_FORMAT_R8G8B8A8_UNORM, - DXGI_FORMAT_UNKNOWN); - return textureFormat; - } - else if (SupportsFormat(renderer11DeviceCaps)) - { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_B5G6R5_UNORM, - DXGI_FORMAT_B5G6R5_UNORM, - DXGI_FORMAT_B5G6R5_UNORM, - DXGI_FORMAT_UNKNOWN); - return textureFormat; + static constexpr Format info(GL_RGB565, + angle::Format::ID::B5G6R5_UNORM, + DXGI_FORMAT_B5G6R5_UNORM, + DXGI_FORMAT_B5G6R5_UNORM, + DXGI_FORMAT_B5G6R5_UNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_B5G6R5_UNORM, + GL_RGBA8, + nullptr); + return info; } else { - break; + static constexpr Format info(GL_RGB565, + angle::Format::ID::R8G8B8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R8G8B8A8_UNORM, + GL_RGBA8, + Initialize4ComponentData); + return info; } } case GL_RGB5_A1: { - if (SupportsFormat(renderer11DeviceCaps)) - { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_R8G8B8A8_UNORM, - DXGI_FORMAT_R8G8B8A8_UNORM, - DXGI_FORMAT_R8G8B8A8_UNORM, - DXGI_FORMAT_UNKNOWN); - return textureFormat; - } - else if (SupportsFormat(renderer11DeviceCaps)) + if (SupportsFormat(DXGI_FORMAT_B5G5R5A1_UNORM, deviceCaps)) { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_B5G5R5A1_UNORM, - DXGI_FORMAT_B5G5R5A1_UNORM, - DXGI_FORMAT_B5G5R5A1_UNORM, - DXGI_FORMAT_UNKNOWN); - return textureFormat; + static constexpr Format info(GL_RGB5_A1, + angle::Format::ID::B5G5R5A1_UNORM, + DXGI_FORMAT_B5G5R5A1_UNORM, + DXGI_FORMAT_B5G5R5A1_UNORM, + DXGI_FORMAT_B5G5R5A1_UNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_B5G5R5A1_UNORM, + GL_RGBA8, + nullptr); + return info; } else { - break; + static constexpr Format info(GL_RGB5_A1, + angle::Format::ID::R8G8B8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R8G8B8A8_UNORM, + GL_RGBA8, + nullptr); + return info; } } case GL_RGB8: { - if (AnyDevice(renderer11DeviceCaps)) - { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_R8G8B8A8_UNORM, - DXGI_FORMAT_R8G8B8A8_UNORM, - DXGI_FORMAT_R8G8B8A8_UNORM, - DXGI_FORMAT_UNKNOWN); - return textureFormat; - } - else - { - break; - } + static constexpr Format info(GL_RGB8, + angle::Format::ID::R8G8B8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R8G8B8A8_UNORM, + GL_RGBA8, + Initialize4ComponentData); + return info; } case GL_RGB8I: { - if (AnyDevice(renderer11DeviceCaps)) - { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_R8G8B8A8_SINT, - DXGI_FORMAT_R8G8B8A8_SINT, - DXGI_FORMAT_R8G8B8A8_SINT, - DXGI_FORMAT_UNKNOWN); - return textureFormat; - } - else - { - break; - } + static constexpr Format info(GL_RGB8I, + angle::Format::ID::R8G8B8A8_SINT, + DXGI_FORMAT_R8G8B8A8_SINT, + DXGI_FORMAT_R8G8B8A8_SINT, + DXGI_FORMAT_R8G8B8A8_SINT, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R8G8B8A8_SINT, + GL_RGBA8I, + Initialize4ComponentData); + return info; } case GL_RGB8UI: { - if (AnyDevice(renderer11DeviceCaps)) - { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_R8G8B8A8_UINT, - DXGI_FORMAT_R8G8B8A8_UINT, - DXGI_FORMAT_R8G8B8A8_UINT, - DXGI_FORMAT_UNKNOWN); - return textureFormat; - } - else - { - break; - } + static constexpr Format info(GL_RGB8UI, + angle::Format::ID::R8G8B8A8_UINT, + DXGI_FORMAT_R8G8B8A8_UINT, + DXGI_FORMAT_R8G8B8A8_UINT, + DXGI_FORMAT_R8G8B8A8_UINT, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R8G8B8A8_UINT, + GL_RGBA8UI, + Initialize4ComponentData); + return info; } case GL_RGB8_SNORM: { - if (AnyDevice(renderer11DeviceCaps)) - { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_R8G8B8A8_SNORM, - DXGI_FORMAT_R8G8B8A8_SNORM, - DXGI_FORMAT_UNKNOWN, - DXGI_FORMAT_UNKNOWN); - return textureFormat; - } - else - { - break; - } + static constexpr Format info(GL_RGB8_SNORM, + angle::Format::ID::R8G8B8A8_SNORM, + DXGI_FORMAT_R8G8B8A8_SNORM, + DXGI_FORMAT_R8G8B8A8_SNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R8G8B8A8_SNORM, + GL_RGBA8_SNORM, + Initialize4ComponentData); + return info; } case GL_RGB9_E5: { - if (AnyDevice(renderer11DeviceCaps)) - { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_R9G9B9E5_SHAREDEXP, - DXGI_FORMAT_R9G9B9E5_SHAREDEXP, - DXGI_FORMAT_UNKNOWN, - DXGI_FORMAT_UNKNOWN); - return textureFormat; - } - else - { - break; - } + static constexpr Format info(GL_RGB9_E5, + angle::Format::ID::R9G9B9E5_SHAREDEXP, + DXGI_FORMAT_R9G9B9E5_SHAREDEXP, + DXGI_FORMAT_R9G9B9E5_SHAREDEXP, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R9G9B9E5_SHAREDEXP, + GL_RGBA16F_EXT, + nullptr); + return info; } case GL_RGBA: { - if (AnyDevice(renderer11DeviceCaps)) - { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_R8G8B8A8_UNORM, - DXGI_FORMAT_R8G8B8A8_UNORM, - DXGI_FORMAT_R8G8B8A8_UNORM, - DXGI_FORMAT_UNKNOWN); - return textureFormat; - } - else - { - break; - } + static constexpr Format info(GL_RGBA, + angle::Format::ID::R8G8B8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R8G8B8A8_UNORM, + GL_RGBA8, + nullptr); + return info; } case GL_RGBA16F: { - if (AnyDevice(renderer11DeviceCaps)) - { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_R16G16B16A16_FLOAT, - DXGI_FORMAT_R16G16B16A16_FLOAT, - DXGI_FORMAT_R16G16B16A16_FLOAT, - DXGI_FORMAT_UNKNOWN); - return textureFormat; - } - else - { - break; - } + static constexpr Format info(GL_RGBA16F, + angle::Format::ID::R16G16B16A16_FLOAT, + DXGI_FORMAT_R16G16B16A16_FLOAT, + DXGI_FORMAT_R16G16B16A16_FLOAT, + DXGI_FORMAT_R16G16B16A16_FLOAT, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R16G16B16A16_FLOAT, + GL_RGBA16F, + nullptr); + return info; } case GL_RGBA16I: { - if (AnyDevice(renderer11DeviceCaps)) - { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_R16G16B16A16_SINT, - DXGI_FORMAT_R16G16B16A16_SINT, - DXGI_FORMAT_R16G16B16A16_SINT, - DXGI_FORMAT_UNKNOWN); - return textureFormat; - } - else - { - break; - } + static constexpr Format info(GL_RGBA16I, + angle::Format::ID::R16G16B16A16_SINT, + DXGI_FORMAT_R16G16B16A16_SINT, + DXGI_FORMAT_R16G16B16A16_SINT, + DXGI_FORMAT_R16G16B16A16_SINT, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R16G16B16A16_SINT, + GL_RGBA16I, + nullptr); + return info; } case GL_RGBA16UI: { - if (AnyDevice(renderer11DeviceCaps)) - { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_R16G16B16A16_UINT, - DXGI_FORMAT_R16G16B16A16_UINT, - DXGI_FORMAT_R16G16B16A16_UINT, - DXGI_FORMAT_UNKNOWN); - return textureFormat; - } - else - { - break; - } + static constexpr Format info(GL_RGBA16UI, + angle::Format::ID::R16G16B16A16_UINT, + DXGI_FORMAT_R16G16B16A16_UINT, + DXGI_FORMAT_R16G16B16A16_UINT, + DXGI_FORMAT_R16G16B16A16_UINT, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R16G16B16A16_UINT, + GL_RGBA16UI, + nullptr); + return info; + } + case GL_RGBA16_EXT: + { + static constexpr Format info(GL_RGBA16_EXT, + angle::Format::ID::R16G16B16A16_UNORM, + DXGI_FORMAT_R16G16B16A16_UNORM, + DXGI_FORMAT_R16G16B16A16_UNORM, + DXGI_FORMAT_R16G16B16A16_UNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R16G16B16A16_UNORM, + GL_RGBA16_EXT, + nullptr); + return info; + } + case GL_RGBA16_SNORM_EXT: + { + static constexpr Format info(GL_RGBA16_SNORM_EXT, + angle::Format::ID::R16G16B16A16_SNORM, + DXGI_FORMAT_R16G16B16A16_SNORM, + DXGI_FORMAT_R16G16B16A16_SNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R16G16B16A16_SNORM, + GL_RGBA16_SNORM_EXT, + nullptr); + return info; } case GL_RGBA32F: { - if (AnyDevice(renderer11DeviceCaps)) - { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_R32G32B32A32_FLOAT, - DXGI_FORMAT_R32G32B32A32_FLOAT, - DXGI_FORMAT_R32G32B32A32_FLOAT, - DXGI_FORMAT_UNKNOWN); - return textureFormat; - } - else - { - break; - } + static constexpr Format info(GL_RGBA32F, + angle::Format::ID::R32G32B32A32_FLOAT, + DXGI_FORMAT_R32G32B32A32_FLOAT, + DXGI_FORMAT_R32G32B32A32_FLOAT, + DXGI_FORMAT_R32G32B32A32_FLOAT, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R32G32B32A32_FLOAT, + GL_RGBA32F, + nullptr); + return info; } case GL_RGBA32I: { - if (AnyDevice(renderer11DeviceCaps)) - { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_R32G32B32A32_SINT, - DXGI_FORMAT_R32G32B32A32_SINT, - DXGI_FORMAT_R32G32B32A32_SINT, - DXGI_FORMAT_UNKNOWN); - return textureFormat; - } - else - { - break; - } + static constexpr Format info(GL_RGBA32I, + angle::Format::ID::R32G32B32A32_SINT, + DXGI_FORMAT_R32G32B32A32_SINT, + DXGI_FORMAT_R32G32B32A32_SINT, + DXGI_FORMAT_R32G32B32A32_SINT, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R32G32B32A32_SINT, + GL_RGBA32I, + nullptr); + return info; } case GL_RGBA32UI: { - if (AnyDevice(renderer11DeviceCaps)) - { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_R32G32B32A32_UINT, - DXGI_FORMAT_R32G32B32A32_UINT, - DXGI_FORMAT_R32G32B32A32_UINT, - DXGI_FORMAT_UNKNOWN); - return textureFormat; - } - else - { - break; - } + static constexpr Format info(GL_RGBA32UI, + angle::Format::ID::R32G32B32A32_UINT, + DXGI_FORMAT_R32G32B32A32_UINT, + DXGI_FORMAT_R32G32B32A32_UINT, + DXGI_FORMAT_R32G32B32A32_UINT, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R32G32B32A32_UINT, + GL_RGBA32UI, + nullptr); + return info; } case GL_RGBA4: { - if (SupportsFormat(renderer11DeviceCaps)) + if (SupportsFormat(DXGI_FORMAT_B4G4R4A4_UNORM, deviceCaps)) { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_R8G8B8A8_UNORM, - DXGI_FORMAT_R8G8B8A8_UNORM, - DXGI_FORMAT_R8G8B8A8_UNORM, - DXGI_FORMAT_UNKNOWN); - return textureFormat; - } - else if (SupportsFormat(renderer11DeviceCaps)) - { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_B4G4R4A4_UNORM, - DXGI_FORMAT_B4G4R4A4_UNORM, - DXGI_FORMAT_B4G4R4A4_UNORM, - DXGI_FORMAT_UNKNOWN); - return textureFormat; + static constexpr Format info(GL_RGBA4, + angle::Format::ID::B4G4R4A4_UNORM, + DXGI_FORMAT_B4G4R4A4_UNORM, + DXGI_FORMAT_B4G4R4A4_UNORM, + DXGI_FORMAT_B4G4R4A4_UNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_B4G4R4A4_UNORM, + GL_RGBA4, + nullptr); + return info; } else { - break; + static constexpr Format info(GL_RGBA4, + angle::Format::ID::R8G8B8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R8G8B8A8_UNORM, + GL_RGBA8, + nullptr); + return info; } } case GL_RGBA8: { - if (AnyDevice(renderer11DeviceCaps)) - { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_R8G8B8A8_UNORM, - DXGI_FORMAT_R8G8B8A8_UNORM, - DXGI_FORMAT_R8G8B8A8_UNORM, - DXGI_FORMAT_UNKNOWN); - return textureFormat; - } - else - { - break; - } + static constexpr Format info(GL_RGBA8, + angle::Format::ID::R8G8B8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R8G8B8A8_UNORM, + GL_RGBA8, + nullptr); + return info; } case GL_RGBA8I: { - if (AnyDevice(renderer11DeviceCaps)) - { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_R8G8B8A8_SINT, - DXGI_FORMAT_R8G8B8A8_SINT, - DXGI_FORMAT_R8G8B8A8_SINT, - DXGI_FORMAT_UNKNOWN); - return textureFormat; - } - else - { - break; - } + static constexpr Format info(GL_RGBA8I, + angle::Format::ID::R8G8B8A8_SINT, + DXGI_FORMAT_R8G8B8A8_SINT, + DXGI_FORMAT_R8G8B8A8_SINT, + DXGI_FORMAT_R8G8B8A8_SINT, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R8G8B8A8_SINT, + GL_RGBA8I, + nullptr); + return info; } case GL_RGBA8UI: { - if (AnyDevice(renderer11DeviceCaps)) - { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_R8G8B8A8_UINT, - DXGI_FORMAT_R8G8B8A8_UINT, - DXGI_FORMAT_R8G8B8A8_UINT, - DXGI_FORMAT_UNKNOWN); - return textureFormat; - } - else - { - break; - } + static constexpr Format info(GL_RGBA8UI, + angle::Format::ID::R8G8B8A8_UINT, + DXGI_FORMAT_R8G8B8A8_UINT, + DXGI_FORMAT_R8G8B8A8_UINT, + DXGI_FORMAT_R8G8B8A8_UINT, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R8G8B8A8_UINT, + GL_RGBA8UI, + nullptr); + return info; } case GL_RGBA8_SNORM: { - if (AnyDevice(renderer11DeviceCaps)) - { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_R8G8B8A8_SNORM, - DXGI_FORMAT_R8G8B8A8_SNORM, - DXGI_FORMAT_UNKNOWN, - DXGI_FORMAT_UNKNOWN); - return textureFormat; - } - else - { - break; - } + static constexpr Format info(GL_RGBA8_SNORM, + angle::Format::ID::R8G8B8A8_SNORM, + DXGI_FORMAT_R8G8B8A8_SNORM, + DXGI_FORMAT_R8G8B8A8_SNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R8G8B8A8_SNORM, + GL_RGBA8_SNORM, + nullptr); + return info; } case GL_SRGB8: { - if (AnyDevice(renderer11DeviceCaps)) - { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, - DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, - DXGI_FORMAT_UNKNOWN, - DXGI_FORMAT_UNKNOWN); - return textureFormat; - } - else - { - break; - } + static constexpr Format info(GL_SRGB8, + angle::Format::ID::R8G8B8A8_UNORM_SRGB, + DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, + DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, + DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, + GL_SRGB8_ALPHA8, + Initialize4ComponentData); + return info; } case GL_SRGB8_ALPHA8: { - if (AnyDevice(renderer11DeviceCaps)) - { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, - DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, - DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, - DXGI_FORMAT_UNKNOWN); - return textureFormat; - } - else - { - break; - } + static constexpr Format info(GL_SRGB8_ALPHA8, + angle::Format::ID::R8G8B8A8_UNORM_SRGB, + DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, + DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, + DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, + GL_SRGB8_ALPHA8, + nullptr); + return info; } case GL_STENCIL_INDEX8: { - if (OnlyFL9_3(renderer11DeviceCaps)) + if (OnlyFL10Plus(deviceCaps)) { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_D24_UNORM_S8_UINT, - DXGI_FORMAT_UNKNOWN, - DXGI_FORMAT_UNKNOWN, - DXGI_FORMAT_D24_UNORM_S8_UINT); - return textureFormat; - } - else if (OnlyFL10Plus(renderer11DeviceCaps)) - { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_R24G8_TYPELESS, - DXGI_FORMAT_X24_TYPELESS_G8_UINT, - DXGI_FORMAT_UNKNOWN, - DXGI_FORMAT_D24_UNORM_S8_UINT); - return textureFormat; + static constexpr Format info(GL_STENCIL_INDEX8, + angle::Format::ID::D24_UNORM_S8_UINT, + DXGI_FORMAT_R24G8_TYPELESS, + DXGI_FORMAT_R24_UNORM_X8_TYPELESS, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_D24_UNORM_S8_UINT, + DXGI_FORMAT_R24_UNORM_X8_TYPELESS, + GL_RGBA32F, + nullptr); + return info; } else { - break; + static constexpr Format info(GL_STENCIL_INDEX8, + angle::Format::ID::D24_UNORM_S8_UINT, + DXGI_FORMAT_D24_UNORM_S8_UINT, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_D24_UNORM_S8_UINT, + DXGI_FORMAT_UNKNOWN, + GL_RGBA32F, + nullptr); + return info; } } @@ -1782,9 +1928,10 @@ const TextureFormat &GetTextureFormatInfo(GLenum internalFormat, } // clang-format on - static const TextureFormat defaultInfo; + UNREACHABLE(); + static constexpr Format defaultInfo; return defaultInfo; -} // GetTextureFormatInfo +} } // namespace d3d11 diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/texture_format_table_utils.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/texture_format_table_utils.h new file mode 100644 index 0000000000..d5351ff882 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/texture_format_table_utils.h @@ -0,0 +1,85 @@ +// +// Copyright 2016 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 routines for the D3D11 texture format table. + +#ifndef LIBANGLE_RENDERER_D3D_D3D11_TEXTURE_FORMAT_TABLE_UTILS_H_ +#define LIBANGLE_RENDERER_D3D_D3D11_TEXTURE_FORMAT_TABLE_UTILS_H_ + +#include "libANGLE/renderer/d3d/d3d11/Renderer11.h" + +namespace rx +{ + +namespace d3d11 +{ + +using FormatSupportFunction = bool (*)(const Renderer11DeviceCaps &); + +inline bool OnlyFL10Plus(const Renderer11DeviceCaps &deviceCaps) +{ + return (deviceCaps.featureLevel >= D3D_FEATURE_LEVEL_10_0); +} + +inline bool OnlyFL9_3(const Renderer11DeviceCaps &deviceCaps) +{ + return (deviceCaps.featureLevel == D3D_FEATURE_LEVEL_9_3); +} + +inline bool SupportsFormat(DXGI_FORMAT format, const Renderer11DeviceCaps &deviceCaps) +{ + // Must support texture, SRV and RTV support + UINT mustSupport = D3D11_FORMAT_SUPPORT_TEXTURE2D | D3D11_FORMAT_SUPPORT_TEXTURECUBE | + D3D11_FORMAT_SUPPORT_SHADER_SAMPLE | D3D11_FORMAT_SUPPORT_MIP | + D3D11_FORMAT_SUPPORT_RENDER_TARGET; + UINT minimumRequiredSamples = 0; + + if (d3d11_gl::GetMaximumClientVersion(deviceCaps.featureLevel).major > 2) + { + mustSupport |= D3D11_FORMAT_SUPPORT_TEXTURE3D; + + // RGBA4, RGB5A1 and RGB565 are all required multisampled renderbuffer formats in ES3 and + // need to support a minimum of 4 samples. + minimumRequiredSamples = 4; + } + + bool fullSupport = false; + if (format == DXGI_FORMAT_B5G6R5_UNORM) + { + // All hardware that supports DXGI_FORMAT_B5G6R5_UNORM should support autogen mipmaps, but + // check anyway. + mustSupport |= D3D11_FORMAT_SUPPORT_MIP_AUTOGEN; + fullSupport = ((deviceCaps.B5G6R5support & mustSupport) == mustSupport) && + deviceCaps.B5G6R5maxSamples >= minimumRequiredSamples; + } + else if (format == DXGI_FORMAT_B4G4R4A4_UNORM) + { + fullSupport = ((deviceCaps.B4G4R4A4support & mustSupport) == mustSupport) && + deviceCaps.B4G4R4A4maxSamples >= minimumRequiredSamples; + } + else if (format == DXGI_FORMAT_B5G5R5A1_UNORM) + { + fullSupport = ((deviceCaps.B5G5R5A1support & mustSupport) == mustSupport) && + deviceCaps.B5G5R5A1maxSamples >= minimumRequiredSamples; + } + else + { + UNREACHABLE(); + return false; + } + + // This means that ANGLE would like to use the entry in the map if the inputted DXGI format + // *IS* supported. + // e.g. the entry might map GL_RGB5_A1 to DXGI_FORMAT_B5G5R5A1, which should only be used if + // DXGI_FORMAT_B5G5R5A1 is supported. + // In this case, we should only return 'true' if the format *IS* supported. + return fullSupport; +} + +} // namespace d3d11 + +} // namespace rx + +#endif // LIBANGLE_RENDERER_D3D_D3D11_TEXTURE_FORMAT_TABLE_UTILS_H_ 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 deleted file mode 100644 index da6460b136..0000000000 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/win32/NativeWindow.cpp +++ /dev/null @@ -1,220 +0,0 @@ -// -// 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 "libANGLE/renderer/d3d/d3d11/renderer11_utils.h" - -#include "common/debug.h" - -#include -#if !defined(__MINGW32__) -#include -#endif - -namespace rx -{ - -NativeWindow::NativeWindow(EGLNativeWindowType window, - const egl::Config *config, - bool directComposition) - : mWindow(window), - mDirectComposition(directComposition), - mDevice(nullptr), - mCompositionTarget(nullptr), - mVisual(nullptr), - mConfig(config) -{ -} - -NativeWindow::~NativeWindow() -{ -#if !defined(__MINGW32__) - SafeRelease(mCompositionTarget); - SafeRelease(mDevice); - SafeRelease(mVisual); -#endif -} - -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; -} - -#if defined(ANGLE_ENABLE_D3D11) -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; - } - -#if !defined(__MINGW32__) - if (mDirectComposition) - { - HMODULE dcomp = ::GetModuleHandle(TEXT("dcomp.dll")); - if (!dcomp) - { - return E_INVALIDARG; - } - - typedef HRESULT(WINAPI * PFN_DCOMPOSITION_CREATE_DEVICE)( - IDXGIDevice * dxgiDevice, REFIID iid, void **dcompositionDevice); - PFN_DCOMPOSITION_CREATE_DEVICE createDComp = - reinterpret_cast( - GetProcAddress(dcomp, "DCompositionCreateDevice")); - if (!createDComp) - { - return E_INVALIDARG; - } - - if (!mDevice) - { - IDXGIDevice *dxgiDevice = d3d11::DynamicCastComObject(device); - HRESULT result = createDComp(dxgiDevice, __uuidof(IDCompositionDevice), - reinterpret_cast(&mDevice)); - SafeRelease(dxgiDevice); - - if (FAILED(result)) - { - return result; - } - } - - if (!mCompositionTarget) - { - HRESULT result = mDevice->CreateTargetForHwnd(mWindow, TRUE, &mCompositionTarget); - if (FAILED(result)) - { - return result; - } - } - - if (!mVisual) - { - HRESULT result = mDevice->CreateVisual(&mVisual); - if (FAILED(result)) - { - return result; - } - } - - IDXGIFactory2 *factory2 = d3d11::DynamicCastComObject(factory); - 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 | DXGI_USAGE_SHADER_INPUT; - swapChainDesc.BufferCount = 2; - swapChainDesc.Scaling = DXGI_SCALING_STRETCH; - swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; - swapChainDesc.AlphaMode = - mConfig->alphaSize == 0 ? DXGI_ALPHA_MODE_IGNORE : DXGI_ALPHA_MODE_PREMULTIPLIED; - swapChainDesc.Flags = 0; - IDXGISwapChain1 *swapChain1 = nullptr; - HRESULT result = - factory2->CreateSwapChainForComposition(device, &swapChainDesc, nullptr, &swapChain1); - if (SUCCEEDED(result)) - { - *swapChain = static_cast(swapChain1); - } - mVisual->SetContent(swapChain1); - mCompositionTarget->SetRoot(mVisual); - SafeRelease(factory2); - return result; - } - - // Use IDXGIFactory2::CreateSwapChainForHwnd if DXGI 1.2 is available to create a DXGI_SWAP_EFFECT_SEQUENTIAL swap chain. - IDXGIFactory2 *factory2 = d3d11::DynamicCastComObject(factory); - if (factory2 != nullptr) - { - 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_SHADER_INPUT | DXGI_USAGE_BACK_BUFFER; - swapChainDesc.BufferCount = 1; - swapChainDesc.Scaling = DXGI_SCALING_STRETCH; - swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_SEQUENTIAL; - swapChainDesc.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED; - swapChainDesc.Flags = 0; - IDXGISwapChain1 *swapChain1 = nullptr; - HRESULT result = factory2->CreateSwapChainForHwnd(device, mWindow, &swapChainDesc, nullptr, nullptr, &swapChain1); - if (SUCCEEDED(result)) - { - const HRESULT makeWindowAssociationResult = factory->MakeWindowAssociation(mWindow, DXGI_MWA_NO_ALT_ENTER); - UNUSED_VARIABLE(makeWindowAssociationResult); - *swapChain = static_cast(swapChain1); - } - SafeRelease(factory2); - return result; - } -#endif // !__MINGW32__ - - DXGI_SWAP_CHAIN_DESC swapChainDesc = {}; - 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_SHADER_INPUT | 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; - - const HRESULT result = factory->CreateSwapChain(device, &swapChainDesc, swapChain); - if (SUCCEEDED(result)) - { - const HRESULT makeWindowAssociationResult = factory->MakeWindowAssociation(mWindow, DXGI_MWA_NO_ALT_ENTER); - UNUSED_VARIABLE(makeWindowAssociationResult); - } - return result; -} -#endif - -void NativeWindow::commitChange() -{ -#if !defined(__MINGW32__) - if (mDevice) - { - mDevice->Commit(); - } -#endif -} -} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/win32/NativeWindow11Win32.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/win32/NativeWindow11Win32.cpp new file mode 100644 index 0000000000..5394e3d3e7 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/win32/NativeWindow11Win32.cpp @@ -0,0 +1,217 @@ +// +// Copyright (c) 2016 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. +// + +// NativeWindow11Win32.cpp: Implementation of NativeWindow11 using win32 window APIs. + +#include "libANGLE/renderer/d3d/d3d11/win32/NativeWindow11Win32.h" +#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h" + +#include "common/debug.h" + +#include +#include + +namespace rx +{ + +NativeWindow11Win32::NativeWindow11Win32(EGLNativeWindowType window, + bool hasAlpha, + bool directComposition) + : NativeWindow11(window), + mDirectComposition(directComposition), + mHasAlpha(hasAlpha), + mDevice(nullptr), + mCompositionTarget(nullptr), + mVisual(nullptr) +{ +} + +NativeWindow11Win32::~NativeWindow11Win32() +{ + SafeRelease(mCompositionTarget); + SafeRelease(mDevice); + SafeRelease(mVisual); +} + +bool NativeWindow11Win32::initialize() +{ + return true; +} + +bool NativeWindow11Win32::getClientRect(LPRECT rect) const +{ + return GetClientRect(getNativeWindow(), rect) == TRUE; +} + +bool NativeWindow11Win32::isIconic() const +{ + return IsIconic(getNativeWindow()) == TRUE; +} + +HRESULT NativeWindow11Win32::createSwapChain(ID3D11Device *device, + IDXGIFactory *factory, + DXGI_FORMAT format, + UINT width, + UINT height, + UINT samples, + IDXGISwapChain **swapChain) +{ + if (device == nullptr || factory == nullptr || swapChain == nullptr || width == 0 || + height == 0) + { + return E_INVALIDARG; + } + + if (mDirectComposition) + { + HMODULE dcomp = ::GetModuleHandle(TEXT("dcomp.dll")); + if (!dcomp) + { + return E_INVALIDARG; + } + + typedef HRESULT(WINAPI * PFN_DCOMPOSITION_CREATE_DEVICE)( + IDXGIDevice * dxgiDevice, REFIID iid, void **dcompositionDevice); + PFN_DCOMPOSITION_CREATE_DEVICE createDComp = + reinterpret_cast( + GetProcAddress(dcomp, "DCompositionCreateDevice")); + if (!createDComp) + { + return E_INVALIDARG; + } + + if (!mDevice) + { + IDXGIDevice *dxgiDevice = d3d11::DynamicCastComObject(device); + HRESULT result = createDComp(dxgiDevice, __uuidof(IDCompositionDevice), + reinterpret_cast(&mDevice)); + SafeRelease(dxgiDevice); + + if (FAILED(result)) + { + return result; + } + } + + if (!mCompositionTarget) + { + HRESULT result = + mDevice->CreateTargetForHwnd(getNativeWindow(), TRUE, &mCompositionTarget); + if (FAILED(result)) + { + return result; + } + } + + if (!mVisual) + { + HRESULT result = mDevice->CreateVisual(&mVisual); + if (FAILED(result)) + { + return result; + } + } + + IDXGIFactory2 *factory2 = d3d11::DynamicCastComObject(factory); + 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 | DXGI_USAGE_SHADER_INPUT; + swapChainDesc.BufferCount = 2; + swapChainDesc.Scaling = DXGI_SCALING_STRETCH; + swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; + swapChainDesc.AlphaMode = + mHasAlpha ? DXGI_ALPHA_MODE_PREMULTIPLIED : DXGI_ALPHA_MODE_IGNORE; + swapChainDesc.Flags = 0; + IDXGISwapChain1 *swapChain1 = nullptr; + HRESULT result = + factory2->CreateSwapChainForComposition(device, &swapChainDesc, nullptr, &swapChain1); + if (SUCCEEDED(result)) + { + *swapChain = static_cast(swapChain1); + } + mVisual->SetContent(swapChain1); + mCompositionTarget->SetRoot(mVisual); + SafeRelease(factory2); + return result; + } + + // Use IDXGIFactory2::CreateSwapChainForHwnd if DXGI 1.2 is available to create a + // DXGI_SWAP_EFFECT_SEQUENTIAL swap chain. + IDXGIFactory2 *factory2 = d3d11::DynamicCastComObject(factory); + if (factory2 != nullptr) + { + DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {0}; + swapChainDesc.Width = width; + swapChainDesc.Height = height; + swapChainDesc.Format = format; + swapChainDesc.Stereo = FALSE; + swapChainDesc.SampleDesc.Count = samples; + swapChainDesc.SampleDesc.Quality = 0; + swapChainDesc.BufferUsage = + DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_SHADER_INPUT | DXGI_USAGE_BACK_BUFFER; + swapChainDesc.BufferCount = 1; + swapChainDesc.Scaling = DXGI_SCALING_STRETCH; + swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_SEQUENTIAL; + swapChainDesc.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED; + swapChainDesc.Flags = 0; + IDXGISwapChain1 *swapChain1 = nullptr; + HRESULT result = factory2->CreateSwapChainForHwnd(device, getNativeWindow(), &swapChainDesc, + nullptr, nullptr, &swapChain1); + if (SUCCEEDED(result)) + { + factory2->MakeWindowAssociation(getNativeWindow(), DXGI_MWA_NO_ALT_ENTER); + *swapChain = static_cast(swapChain1); + } + SafeRelease(factory2); + return result; + } + + DXGI_SWAP_CHAIN_DESC swapChainDesc = {}; + 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_SHADER_INPUT | DXGI_USAGE_BACK_BUFFER; + swapChainDesc.Flags = 0; + swapChainDesc.OutputWindow = getNativeWindow(); + swapChainDesc.SampleDesc.Count = samples; + swapChainDesc.SampleDesc.Quality = 0; + swapChainDesc.Windowed = TRUE; + swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; + + HRESULT result = factory->CreateSwapChain(device, &swapChainDesc, swapChain); + if (SUCCEEDED(result)) + { + factory->MakeWindowAssociation(getNativeWindow(), DXGI_MWA_NO_ALT_ENTER); + } + return result; +} + +void NativeWindow11Win32::commitChange() +{ + if (mDevice) + { + mDevice->Commit(); + } +} + +// static +bool NativeWindow11Win32::IsValidNativeWindow(EGLNativeWindowType window) +{ + return IsWindow(window) == TRUE; +} +} // namespace rx diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/win32/NativeWindow11Win32.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/win32/NativeWindow11Win32.h new file mode 100644 index 0000000000..baeba6a347 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/win32/NativeWindow11Win32.h @@ -0,0 +1,53 @@ +// +// Copyright (c) 2016 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. +// + +// NativeWindow11Win32.h: Implementation of NativeWindow11 using win32 window APIs. + +#ifndef LIBANGLE_RENDERER_D3D_D3D11_WIN32_NATIVEWINDOW11WIN32_H_ +#define LIBANGLE_RENDERER_D3D_D3D11_WIN32_NATIVEWINDOW11WIN32_H_ + +#include "libANGLE/renderer/d3d/d3d11/NativeWindow11.h" + +typedef interface IDCompositionDevice IDCompositionDevice; +typedef interface IDCompositionTarget IDCompositionTarget; +typedef interface IDCompositionVisual IDCompositionVisual; + +namespace rx +{ + +class NativeWindow11Win32 : public NativeWindow11 +{ + public: + NativeWindow11Win32(EGLNativeWindowType window, bool hasAlpha, bool directComposition); + ~NativeWindow11Win32() override; + + bool initialize() override; + bool getClientRect(LPRECT rect) const override; + bool isIconic() const override; + + HRESULT createSwapChain(ID3D11Device *device, + IDXGIFactory *factory, + DXGI_FORMAT format, + UINT width, + UINT height, + UINT samples, + IDXGISwapChain **swapChain) override; + + void commitChange() override; + + static bool IsValidNativeWindow(EGLNativeWindowType window); + + private: + bool mDirectComposition; + bool mHasAlpha; + IDCompositionDevice *mDevice; + IDCompositionTarget *mCompositionTarget; + IDCompositionVisual *mVisual; +}; + +} // namespace rx + +#endif // LIBANGLE_RENDERER_D3D_D3D11_WIN32_NATIVEWINDOW11WIN32_H_ 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 index f401db614b..1ef90e7b09 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow.cpp @@ -8,6 +8,8 @@ #include "libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow.h" +#include + using namespace ABI::Windows::Foundation::Collections; namespace rx @@ -19,7 +21,6 @@ CoreWindowNativeWindow::~CoreWindowNativeWindow() bool CoreWindowNativeWindow::initialize(EGLNativeWindowType window, IPropertySet *propertySet) { - mOrientationChangedEventToken.value = 0; ComPtr props = propertySet; ComPtr win = window; SIZE swapChainSize = {}; @@ -63,7 +64,8 @@ bool CoreWindowNativeWindow::initialize(EGLNativeWindowType window, IPropertySet // A EGLRenderSurfaceSizeProperty and a EGLRenderResolutionScaleProperty can't both be specified if (mSwapChainScaleSpecified && mSwapChainSizeSpecified) { - ERR("It is invalid to specify both an EGLRenderSurfaceSizeProperty and a EGLRenderResolutionScaleProperty."); + ERR() << "It is invalid to specify both an EGLRenderSurfaceSizeProperty and a " + "EGLRenderResolutionScaleProperty."; return false; } } @@ -87,26 +89,16 @@ bool CoreWindowNativeWindow::initialize(EGLNativeWindowType window, IPropertySet } else { - SIZE coreWindowSize; + Size coreWindowSize; result = GetCoreWindowSizeInPixels(mCoreWindow, &coreWindowSize); if (SUCCEEDED(result)) { - mClientRect = { 0, 0, static_cast(coreWindowSize.cx * mSwapChainScale), static_cast(coreWindowSize.cy * mSwapChainScale) }; + mClientRect = clientRect(coreWindowSize); } } } - 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; @@ -126,16 +118,6 @@ bool CoreWindowNativeWindow::registerForSizeChangeEvents() 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); - orientationChangedHandler->Invoke(mDisplayInformation.Get(), nullptr); - } -#endif - if (SUCCEEDED(result)) { return true; @@ -150,34 +132,26 @@ void CoreWindowNativeWindow::unregisterForSizeChangeEvents() { (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, + IDXGIFactory2 *factory, DXGI_FORMAT format, unsigned int width, unsigned int height, bool containsAlpha, - DXGISwapChain **swapChain) + IDXGISwapChain1 **swapChain) { - if (device == NULL || factory == NULL || swapChain == NULL || width == 0 || height == 0) + if (device == nullptr || factory == nullptr || swapChain == nullptr || width == 0 || + height == 0) { return E_INVALIDARG; } DXGI_SWAP_CHAIN_DESC1 swapChainDesc = { 0 }; - swapChainDesc.Width = mRotationFlags ? height : width; - swapChainDesc.Height = mRotationFlags ? width : height; + swapChainDesc.Width = width; + swapChainDesc.Height = height; swapChainDesc.Format = format; swapChainDesc.Stereo = FALSE; swapChainDesc.SampleDesc.Count = 1; @@ -195,17 +169,6 @@ HRESULT CoreWindowNativeWindow::createSwapChain(ID3D11Device *device, 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); } @@ -222,14 +185,16 @@ HRESULT CoreWindowNativeWindow::createSwapChain(ID3D11Device *device, return result; } -inline HRESULT CoreWindowNativeWindow::scaleSwapChain(const Size &windowSize, const RECT &clientRect) +inline HRESULT CoreWindowNativeWindow::scaleSwapChain(const Size &windowSize, + const RECT &clientRect) { // We don't need to do any additional work to scale CoreWindow swapchains. // Using DXGI_SCALING_STRETCH to create the swapchain above does all the necessary work. return S_OK; } -HRESULT GetCoreWindowSizeInPixels(const ComPtr& coreWindow, SIZE *windowSize) +HRESULT GetCoreWindowSizeInPixels(const ComPtr &coreWindow, + Size *windowSize) { ABI::Windows::Foundation::Rect bounds; HRESULT result = coreWindow->get_Bounds(&bounds); 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 index fc1cd124a1..21855c2c3b 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow.h @@ -12,10 +12,10 @@ #include "libANGLE/renderer/d3d/d3d11/winrt/InspectableNativeWindow.h" #include -#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 { @@ -26,12 +26,12 @@ class CoreWindowNativeWindow : public InspectableNativeWindow, public std::enabl bool initialize(EGLNativeWindowType window, IPropertySet *propertySet) override; HRESULT createSwapChain(ID3D11Device *device, - DXGIFactory *factory, + IDXGIFactory2 *factory, DXGI_FORMAT format, unsigned int width, unsigned int height, bool containsAlpha, - DXGISwapChain **swapChain) override; + IDXGISwapChain1 **swapChain) override; protected: HRESULT scaleSwapChain(const Size &windowSize, const RECT &clientRect) override; @@ -42,13 +42,11 @@ class CoreWindowNativeWindow : public InspectableNativeWindow, public std::enabl private: ComPtr mCoreWindow; ComPtr> mPropertyMap; - ComPtr mDisplayInformation; - EventRegistrationToken mOrientationChangedEventToken; }; [uuid(7F924F66-EBAE-40E5-A10B-B8F35E245190)] class CoreWindowSizeChangedHandler : - public Microsoft::WRL::RuntimeClass, IWindowSizeChangedEventHandler, IDisplayOrientationEventHandler> + public Microsoft::WRL::RuntimeClass, IWindowSizeChangedEventHandler> { public: CoreWindowSizeChangedHandler() { } @@ -72,47 +70,21 @@ class CoreWindowSizeChangedHandler : ABI::Windows::Foundation::Size windowSize; if (SUCCEEDED(sizeChangedEventArgs->get_Size(&windowSize))) { - host->setNewClientSize(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, SIZE *windowSize); +HRESULT GetCoreWindowSizeInPixels(const ComPtr &coreWindow, + Size *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 index aacfadd2f0..1bd796e58f 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/InspectableNativeWindow.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/InspectableNativeWindow.cpp @@ -11,108 +11,6 @@ namespace rx { -NativeWindow::NativeWindow(EGLNativeWindowType window, - const egl::Config *config, - bool directComposition) -{ - mWindow = window; - mConfig = config; -} - -NativeWindow::~NativeWindow() -{ -} - -void NativeWindow::commitChange() -{ -} - -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) - { - bool containsAlpha = (mConfig->alphaSize > 0); - return mImpl->createSwapChain(device, factory, format, width, height, containsAlpha, - swapChain); - } - - return E_UNEXPECTED; -} bool IsCoreWindow(EGLNativeWindowType window, ComPtr *coreWindow) { @@ -127,7 +25,7 @@ bool IsCoreWindow(EGLNativeWindowType window, ComPtr> &propertyMap, const wchar_t *propertyName, @@ -381,7 +268,13 @@ HRESULT GetOptionalSinglePropertyValue(const ComPtr(ConvertDipsToPixels(size.Width)), + static_cast(ConvertDipsToPixels(size.Height))}; +} + +float GetLogicalDpi() { ComPtr displayProperties; float dpi = 96.0f; @@ -396,7 +289,7 @@ static float GetLogicalDpi() return dpi; } -long ConvertDipsToPixels(float dips) +float 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/InspectableNativeWindow.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/InspectableNativeWindow.h index 2d58f1c00a..d81c3e5fb9 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/InspectableNativeWindow.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/InspectableNativeWindow.h @@ -10,14 +10,18 @@ #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/debug.h" #include "common/platform.h" #include "angle_windowsstore.h" +#include + +#include #include #include +#include +#include using namespace Microsoft::WRL; using namespace Microsoft::WRL::Wrappers; @@ -26,7 +30,8 @@ using namespace ABI::Windows::Foundation::Collections; namespace rx { -long ConvertDipsToPixels(float dips); +float ConvertDipsToPixels(float dips); +float GetLogicalDpi(); class InspectableNativeWindow { @@ -35,24 +40,25 @@ class InspectableNativeWindow mSupportsSwapChainResize(true), mSwapChainSizeSpecified(false), mSwapChainScaleSpecified(false), - mSwapChainScale(1.0f), mClientRectChanged(false), mClientRect({0,0,0,0}), - mNewClientRect({0,0,0,0}), - mRotationFlags(NativeWindow::RotateNone) + mNewClientRect({0,0,0,0}) { mSizeChangedEventToken.value = 0; + mSwapChainScale = 96.0f / GetLogicalDpi(); + if (mSwapChainScale != 1.0f) + mSwapChainScaleSpecified = true; } virtual ~InspectableNativeWindow(){} virtual bool initialize(EGLNativeWindowType window, IPropertySet *propertySet) = 0; virtual HRESULT createSwapChain(ID3D11Device *device, - DXGIFactory *factory, + IDXGIFactory2 *factory, DXGI_FORMAT format, unsigned int width, unsigned int height, bool containsAlpha, - DXGISwapChain **swapChain) = 0; + IDXGISwapChain1 **swapChain) = 0; bool getClientRect(RECT *rect) { @@ -77,8 +83,7 @@ class InspectableNativeWindow // If the swapchain size was specified then we should ignore this call too if (!mSwapChainSizeSpecified) { - // We don't have to check if a swapchain scale was specified here; the default value is 1.0f which will have no effect. - mNewClientRect = { 0, 0, ConvertDipsToPixels(newWindowSize.Width), ConvertDipsToPixels(newWindowSize.Height) }; + mNewClientRect = clientRect(newWindowSize); mClientRectChanged = true; // If a scale was specified, then now is the time to apply the scale matrix for the new swapchain size and window size @@ -97,18 +102,9 @@ class InspectableNativeWindow } } - NativeWindow::RotationFlags rotationFlags() const - { - return mRotationFlags; - } - - void setRotationFlags(NativeWindow::RotationFlags flags) - { - mRotationFlags = flags; - } - protected: virtual HRESULT scaleSwapChain(const Size &windowSize, const RECT &clientRect) = 0; + RECT clientRect(const Size &size); bool mSupportsSwapChainResize; // Support for IDXGISwapChain::ResizeBuffers method bool mSwapChainSizeSpecified; // If an EGLRenderSurfaceSizeProperty was specified @@ -117,12 +113,10 @@ class InspectableNativeWindow 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); diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/NativeWindow11WinRT.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/NativeWindow11WinRT.cpp new file mode 100644 index 0000000000..655b23be83 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/NativeWindow11WinRT.cpp @@ -0,0 +1,126 @@ +// +// Copyright (c) 2016 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. +// + +// NativeWindow11WinRT.cpp: NativeWindow base class for managing IInspectable native window types. + +#include "libANGLE/renderer/d3d/d3d11/winrt/NativeWindow11WinRT.h" + +#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h" +#include "libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow.h" +#include "libANGLE/renderer/d3d/d3d11/winrt/InspectableNativeWindow.h" +#include "libANGLE/renderer/d3d/d3d11/winrt/SwapChainPanelNativeWindow.h" + +using namespace Microsoft::WRL; +using namespace Microsoft::WRL::Wrappers; + +namespace rx +{ +NativeWindow11WinRT::NativeWindow11WinRT(EGLNativeWindowType window, bool hasAlpha) + : NativeWindow11(window), mHasAlpha(hasAlpha) +{ +} + +bool NativeWindow11WinRT::initialize() +{ + EGLNativeWindowType window = getNativeWindow(); + + // 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(window, &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. + window = eglNativeWindow.Get(); + } + + ComPtr coreWindow; + ComPtr swapChainPanel; + if (IsCoreWindow(window, &coreWindow)) + { + mImpl = std::make_shared(); + if (mImpl) + { + return mImpl->initialize(window, propertySet.Get()); + } + } + else if (IsSwapChainPanel(window, &swapChainPanel)) + { + mImpl = std::make_shared(); + if (mImpl) + { + return mImpl->initialize(window, propertySet.Get()); + } + } + else + { + ERR() << "Invalid IInspectable EGLNativeWindowType detected. Valid IInspectables include " + "ICoreWindow, ISwapChainPanel and IPropertySet"; + } + + return false; +} + +bool NativeWindow11WinRT::getClientRect(LPRECT rect) const +{ + if (mImpl) + { + return mImpl->getClientRect(rect); + } + + return false; +} + +bool NativeWindow11WinRT::isIconic() const +{ + return false; +} + +HRESULT NativeWindow11WinRT::createSwapChain(ID3D11Device *device, + IDXGIFactory *factory, + DXGI_FORMAT format, + UINT width, + UINT height, + UINT samples, + IDXGISwapChain **swapChain) +{ + if (mImpl) + { + IDXGIFactory2 *factory2 = d3d11::DynamicCastComObject(factory); + IDXGISwapChain1 *swapChain1 = nullptr; + HRESULT result = + mImpl->createSwapChain(device, factory2, format, width, height, mHasAlpha, &swapChain1); + SafeRelease(factory2); + *swapChain = static_cast(swapChain1); + return result; + } + + return E_UNEXPECTED; +} + +void NativeWindow11WinRT::commitChange() +{ +} + +// static +bool NativeWindow11WinRT::IsValidNativeWindow(EGLNativeWindowType window) +{ + // A Valid EGLNativeWindowType IInspectable can only be: + // + // ICoreWindow + // ISwapChainPanel + // IPropertySet + // + // Anything else will be rejected as an invalid IInspectable. + return IsCoreWindow(window) || IsSwapChainPanel(window) || IsEGLConfiguredPropertySet(window); +} + +} // namespace rx diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/NativeWindow11WinRT.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/NativeWindow11WinRT.h new file mode 100644 index 0000000000..c4ac997a55 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/NativeWindow11WinRT.h @@ -0,0 +1,51 @@ +// +// Copyright (c) 2016 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. +// + +// NativeWindow11WinRT.h: NativeWindow base class for managing IInspectable native window types. + +#ifndef LIBANGLE_RENDERER_D3D_D3D11_WINRT_NATIVEWINDOW11WINRT_H_ +#define LIBANGLE_RENDERER_D3D_D3D11_WINRT_NATIVEWINDOW11WINRT_H_ + +#include "libANGLE/renderer/d3d/d3d11/NativeWindow11.h" + +#include +#include +#include +#include + +namespace rx +{ +class InspectableNativeWindow; + +class NativeWindow11WinRT : public NativeWindow11 +{ + public: + NativeWindow11WinRT(EGLNativeWindowType window, bool hasAlpha); + + bool initialize() override; + bool getClientRect(LPRECT rect) const override; + bool isIconic() const override; + + HRESULT createSwapChain(ID3D11Device *device, + IDXGIFactory *factory, + DXGI_FORMAT format, + UINT width, + UINT height, + UINT samples, + IDXGISwapChain **swapChain) override; + + void commitChange() override; + + static bool IsValidNativeWindow(EGLNativeWindowType window); + + private: + bool mHasAlpha; + std::shared_ptr mImpl; +}; + +} // namespace rx + +#endif // LIBANGLE_RENDERER_D3D_D3D11_WINRT_NATIVEWINDOW11WINRT_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 index 548b4602fd..3425fad95d 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/SwapChainPanelNativeWindow.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/SwapChainPanelNativeWindow.cpp @@ -49,7 +49,8 @@ HRESULT RunOnUIThread(CODE &&code, const ComPtr &dispatcher) } else { - Event waitEvent(CreateEventEx(NULL, NULL, CREATE_EVENT_MANUAL_RESET, EVENT_ALL_ACCESS)); + Event waitEvent( + CreateEventEx(nullptr, nullptr, CREATE_EVENT_MANUAL_RESET, EVENT_ALL_ACCESS)); if (!waitEvent.IsValid()) { return E_FAIL; @@ -78,7 +79,8 @@ HRESULT RunOnUIThread(CODE &&code, const ComPtr &dispatcher) // unrecoverable state (probably deadlocked). We therefore terminate the application // entirely. This also prevents stack corruption if the async operation is eventually // run. - ERR("Timeout waiting for async action on UI thread. The UI thread might be blocked."); + ERR() + << "Timeout waiting for async action on UI thread. The UI thread might be blocked."; std::terminate(); return E_FAIL; } @@ -132,7 +134,8 @@ bool SwapChainPanelNativeWindow::initialize(EGLNativeWindowType window, IPropert // A EGLRenderSurfaceSizeProperty and a EGLRenderResolutionScaleProperty can't both be specified if (mSwapChainScaleSpecified && mSwapChainSizeSpecified) { - ERR("It is invalid to specify both an EGLRenderSurfaceSizeProperty and a EGLRenderResolutionScaleProperty."); + ERR() << "It is invalid to specify both an EGLRenderSurfaceSizeProperty and a " + "EGLRenderResolutionScaleProperty."; return false; } } @@ -169,17 +172,14 @@ bool SwapChainPanelNativeWindow::initialize(EGLNativeWindowType window, IPropert } else { - SIZE swapChainPanelSize; + Size swapChainPanelSize; result = GetSwapChainPanelSize(mSwapChainPanel, mSwapChainPanelDispatcher, - &swapChainPanelSize, &mSwapChainScale); - if (mSwapChainScale != 1.0f) - mSwapChainScaleSpecified = true; + &swapChainPanelSize); if (SUCCEEDED(result)) { // Update the client rect to account for any swapchain scale factor - mClientRect = { 0, 0, static_cast(ConvertDipsToPixels(swapChainPanelSize.cx * mSwapChainScale)), - static_cast(ConvertDipsToPixels(swapChainPanelSize.cy * mSwapChainScale)) }; + mClientRect = clientRect(swapChainPanelSize); } } } @@ -241,14 +241,15 @@ void SwapChainPanelNativeWindow::unregisterForSizeChangeEvents() } HRESULT SwapChainPanelNativeWindow::createSwapChain(ID3D11Device *device, - DXGIFactory *factory, + IDXGIFactory2 *factory, DXGI_FORMAT format, unsigned int width, unsigned int height, bool containsAlpha, - DXGISwapChain **swapChain) + IDXGISwapChain1 **swapChain) { - if (device == NULL || factory == NULL || swapChain == NULL || width == 0 || height == 0) + if (device == nullptr || factory == nullptr || swapChain == nullptr || width == 0 || + height == 0) { return E_INVALIDARG; } @@ -272,6 +273,7 @@ HRESULT SwapChainPanelNativeWindow::createSwapChain(ID3D11Device *device, ComPtr newSwapChain; ComPtr swapChainPanelNative; + Size currentPanelSize = {}; HRESULT result = factory->CreateSwapChainForComposition(device, &swapChainDesc, nullptr, newSwapChain.ReleaseAndGetAddressOf()); @@ -306,14 +308,14 @@ HRESULT SwapChainPanelNativeWindow::createSwapChain(ID3D11Device *device, { if (mSwapChainSizeSpecified || mSwapChainScaleSpecified) { - ComPtr uiElement; - result = mSwapChainPanel.As(&uiElement); - ASSERT(SUCCEEDED(result)); - - Size currentSize; - result = uiElement->get_RenderSize(¤tSize); - ASSERT(SUCCEEDED(result)); - result = scaleSwapChain(currentSize, mClientRect); + result = GetSwapChainPanelSize(mSwapChainPanel, mSwapChainPanelDispatcher, + ¤tPanelSize); + + // Scale the swapchain to fit inside the contents of the panel. + if (SUCCEEDED(result)) + { + result = scaleSwapChain(currentPanelSize, mClientRect); + } } } @@ -342,31 +344,14 @@ HRESULT SwapChainPanelNativeWindow::scaleSwapChain(const Size &windowSize, const HRESULT GetSwapChainPanelSize( const ComPtr &swapChainPanel, const ComPtr &dispatcher, - SIZE *windowSize, float *scaleFactor) + Size *windowSize) { ComPtr uiElement; - Size renderSize = {0, 0}; HRESULT result = swapChainPanel.As(&uiElement); if (SUCCEEDED(result)) { result = RunOnUIThread( - [uiElement, &renderSize] - { - return uiElement->get_RenderSize(&renderSize); - }, - dispatcher); - } - - if (SUCCEEDED(result)) - { - long width = ConvertDipsToPixels(renderSize.Width); - long height = ConvertDipsToPixels(renderSize.Height); - *windowSize = { width, height }; - - if (scaleFactor) - { - *scaleFactor = renderSize.Width / width; - } + [uiElement, windowSize] { return uiElement->get_RenderSize(windowSize); }, dispatcher); } 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 index 09d87ad523..f9a2fc0e4b 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/SwapChainPanelNativeWindow.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/SwapChainPanelNativeWindow.h @@ -11,6 +11,8 @@ #include "libANGLE/renderer/d3d/d3d11/winrt/InspectableNativeWindow.h" +#include + namespace rx { class SwapChainPanelNativeWindow : public InspectableNativeWindow, public std::enable_shared_from_this @@ -20,12 +22,12 @@ class SwapChainPanelNativeWindow : public InspectableNativeWindow, public std::e bool initialize(EGLNativeWindowType window, IPropertySet *propertySet) override; HRESULT createSwapChain(ID3D11Device *device, - DXGIFactory *factory, + IDXGIFactory2 *factory, DXGI_FORMAT format, unsigned int width, unsigned int height, bool containsAlpha, - DXGISwapChain **swapChain) override; + IDXGISwapChain1 **swapChain) override; protected: HRESULT scaleSwapChain(const Size &windowSize, const RECT &clientRect) override; @@ -37,7 +39,7 @@ class SwapChainPanelNativeWindow : public InspectableNativeWindow, public std::e ComPtr mSwapChainPanel; ComPtr mSwapChainPanelDispatcher; ComPtr> mPropertyMap; - ComPtr mSwapChain; + ComPtr mSwapChain; }; [uuid(8ACBD974-8187-4508-AD80-AEC77F93CF36)] @@ -86,6 +88,6 @@ class SwapChainPanelSizeChangedHandler : HRESULT GetSwapChainPanelSize( const ComPtr &swapChainPanel, const ComPtr &dispatcher, - SIZE *windowSize, float *scaleFactor); + Size *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 index 2ac8ee3a29..36f2bd0db8 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Blit9.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Blit9.cpp @@ -7,6 +7,8 @@ // Blit9.cpp: Surface copy utility class. #include "libANGLE/renderer/d3d/d3d9/Blit9.h" + +#include "libANGLE/renderer/d3d/TextureD3D.h" #include "libANGLE/renderer/d3d/d3d9/renderer9_utils.h" #include "libANGLE/renderer/d3d/d3d9/formatutils9.h" #include "libANGLE/renderer/d3d/d3d9/TextureStorage9.h" @@ -20,27 +22,34 @@ 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/luminancepremultps.h" +#include "libANGLE/renderer/d3d/d3d9/shaders/compiled/luminanceunmultps.h" #include "libANGLE/renderer/d3d/d3d9/shaders/compiled/componentmaskps.h" +#include "libANGLE/renderer/d3d/d3d9/shaders/compiled/componentmaskpremultps.h" +#include "libANGLE/renderer/d3d/d3d9/shaders/compiled/componentmaskunmultps.h" -const BYTE* const g_shaderCode[] = -{ +const BYTE *const g_shaderCode[] = { g_vs20_standardvs, - g_vs20_flipyvs, g_ps20_passthroughps, g_ps20_luminanceps, - g_ps20_componentmaskps + g_ps20_luminancepremultps, + g_ps20_luminanceunmultps, + g_ps20_componentmaskps, + g_ps20_componentmaskpremultps, + g_ps20_componentmaskunmultps, }; -const size_t g_shaderSize[] = -{ +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) + sizeof(g_ps20_luminancepremultps), + sizeof(g_ps20_luminanceunmultps), + sizeof(g_ps20_componentmaskps), + sizeof(g_ps20_componentmaskpremultps), + sizeof(g_ps20_componentmaskunmultps), }; } @@ -50,11 +59,11 @@ namespace rx Blit9::Blit9(Renderer9 *renderer) : mRenderer(renderer), mGeometryLoaded(false), - mQuadVertexBuffer(NULL), - mQuadVertexDeclaration(NULL), - mSavedStateBlock(NULL), - mSavedRenderTarget(NULL), - mSavedDepthStencil(NULL) + mQuadVertexBuffer(nullptr), + mQuadVertexDeclaration(nullptr), + mSavedStateBlock(nullptr), + mSavedRenderTarget(nullptr), + mSavedDepthStencil(nullptr) { memset(mCompiledShaders, 0, sizeof(mCompiledShaders)); } @@ -75,7 +84,7 @@ gl::Error Blit9::initialize() { if (mGeometryLoaded) { - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } static const float quad[] = @@ -88,22 +97,25 @@ gl::Error Blit9::initialize() IDirect3DDevice9 *device = mRenderer->getDevice(); - HRESULT result = device->CreateVertexBuffer(sizeof(quad), D3DUSAGE_WRITEONLY, 0, D3DPOOL_DEFAULT, &mQuadVertexBuffer, NULL); + HRESULT result = device->CreateVertexBuffer(sizeof(quad), D3DUSAGE_WRITEONLY, 0, + D3DPOOL_DEFAULT, &mQuadVertexBuffer, nullptr); 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); + return gl::OutOfMemory() << "Failed to create internal blit vertex shader, " + << gl::FmtHR(result); } - void *lockPtr = NULL; + void *lockPtr = nullptr; result = mQuadVertexBuffer->Lock(0, 0, &lockPtr, 0); - if (FAILED(result) || lockPtr == NULL) + if (FAILED(result) || lockPtr == nullptr) { 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); + return gl::OutOfMemory() << "Failed to lock internal blit vertex shader, " + << gl::FmtHR(result); } memcpy(lockPtr, quad, sizeof(quad)); @@ -121,11 +133,12 @@ gl::Error Blit9::initialize() { 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); + return gl::OutOfMemory() << "Failed to lock internal blit vertex declaration, " + << gl::FmtHR(result); } mGeometryLoaded = true; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } template @@ -137,7 +150,7 @@ gl::Error Blit9::setShader(ShaderId source, const char *profile, D3DShaderType *shader = nullptr; - if (mCompiledShaders[source] != NULL) + if (mCompiledShaders[source] != nullptr) { shader = static_cast(mCompiledShaders[source]); } @@ -145,23 +158,17 @@ gl::Error Blit9::setShader(ShaderId source, const char *profile, { 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; - } - + ANGLE_TRY((mRenderer->*createShader)(reinterpret_cast(shaderCode), shaderSize, &shader)); 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::OutOfMemory() << "Failed to set shader for blit operation, " << gl::FmtHR(hr); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } gl::Error Blit9::setVertexShader(ShaderId shader) @@ -188,20 +195,20 @@ RECT Blit9::getSurfaceRect(IDirect3DSurface9 *surface) const return rect; } +gl::Extents Blit9::getSurfaceSize(IDirect3DSurface9 *surface) const +{ + D3DSURFACE_DESC desc; + surface->GetDesc(&desc); + + return gl::Extents(desc.Width, desc.Height, 1); +} + gl::Error Blit9::boxFilter(IDirect3DSurface9 *source, IDirect3DSurface9 *dest) { - gl::Error error = initialize(); - if (error.isError()) - { - return error; - } + ANGLE_TRY(initialize()); - IDirect3DTexture9 *texture = NULL; - error = copySurfaceToTexture(source, getSurfaceRect(source), &texture); - if (error.isError()) - { - return error; - } + IDirect3DBaseTexture9 *texture = nullptr; + ANGLE_TRY(copySurfaceToTexture(source, getSurfaceRect(source), &texture)); IDirect3DDevice9 *device = mRenderer->getDevice(); @@ -210,14 +217,15 @@ gl::Error Blit9::boxFilter(IDirect3DSurface9 *source, IDirect3DSurface9 *dest) device->SetTexture(0, texture); device->SetRenderTarget(0, dest); - setVertexShader(SHADER_VS_STANDARD); - setPixelShader(SHADER_PS_PASSTHROUGH); + ANGLE_TRY(setVertexShader(SHADER_VS_STANDARD)); + ANGLE_TRY(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)); + setViewportAndShaderConstants(getSurfaceRect(source), getSurfaceSize(source), + getSurfaceRect(dest), false); render(); @@ -225,34 +233,32 @@ gl::Error Blit9::boxFilter(IDirect3DSurface9 *source, IDirect3DSurface9 *dest) restoreState(); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error Blit9::copy2D(const gl::Framebuffer *framebuffer, const RECT &sourceRect, GLenum destFormat, const gl::Offset &destOffset, TextureStorage *storage, GLint level) +gl::Error Blit9::copy2D(const gl::Context *context, + 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; - } + ANGLE_TRY(initialize()); const gl::FramebufferAttachment *colorbuffer = framebuffer->getColorbuffer(0); ASSERT(colorbuffer); RenderTarget9 *renderTarget9 = nullptr; - error = colorbuffer->getRenderTarget(&renderTarget9); - if (error.isError()) - { - return error; - } + ANGLE_TRY(colorbuffer->getRenderTarget(context, &renderTarget9)); ASSERT(renderTarget9); IDirect3DSurface9 *source = renderTarget9->getSurface(); ASSERT(source); - IDirect3DSurface9 *destSurface = NULL; + IDirect3DSurface9 *destSurface = nullptr; TextureStorage9 *storage9 = GetAs(storage); - error = storage9->getSurfaceLevel(GL_TEXTURE_2D, level, true, &destSurface); + gl::Error error = storage9->getSurfaceLevel(context, GL_TEXTURE_2D, level, true, &destSurface); if (error.isError()) { SafeRelease(source); @@ -260,7 +266,8 @@ gl::Error Blit9::copy2D(const gl::Framebuffer *framebuffer, const RECT &sourceRe } ASSERT(destSurface); - gl::Error result = copy(source, sourceRect, destFormat, destOffset, destSurface); + gl::Error result = + copy(source, nullptr, sourceRect, destFormat, destOffset, destSurface, false, false, false); SafeRelease(destSurface); SafeRelease(source); @@ -268,7 +275,14 @@ gl::Error Blit9::copy2D(const gl::Framebuffer *framebuffer, const RECT &sourceRe 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 Blit9::copyCube(const gl::Context *context, + 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()) @@ -280,7 +294,7 @@ gl::Error Blit9::copyCube(const gl::Framebuffer *framebuffer, const RECT &source ASSERT(colorbuffer); RenderTarget9 *renderTarget9 = nullptr; - error = colorbuffer->getRenderTarget(&renderTarget9); + error = colorbuffer->getRenderTarget(context, &renderTarget9); if (error.isError()) { return error; @@ -290,9 +304,9 @@ gl::Error Blit9::copyCube(const gl::Framebuffer *framebuffer, const RECT &source IDirect3DSurface9 *source = renderTarget9->getSurface(); ASSERT(source); - IDirect3DSurface9 *destSurface = NULL; + IDirect3DSurface9 *destSurface = nullptr; TextureStorage9 *storage9 = GetAs(storage); - error = storage9->getSurfaceLevel(target, level, true, &destSurface); + error = storage9->getSurfaceLevel(context, target, level, true, &destSurface); if (error.isError()) { SafeRelease(source); @@ -300,7 +314,8 @@ gl::Error Blit9::copyCube(const gl::Framebuffer *framebuffer, const RECT &source } ASSERT(destSurface); - gl::Error result = copy(source, sourceRect, destFormat, destOffset, destSurface); + gl::Error result = + copy(source, nullptr, sourceRect, destFormat, destOffset, destSurface, false, false, false); SafeRelease(destSurface); SafeRelease(source); @@ -308,9 +323,69 @@ gl::Error Blit9::copyCube(const gl::Framebuffer *framebuffer, const RECT &source return result; } -gl::Error Blit9::copy(IDirect3DSurface9 *source, const RECT &sourceRect, GLenum destFormat, const gl::Offset &destOffset, IDirect3DSurface9 *dest) +gl::Error Blit9::copyTexture(const gl::Context *context, + const gl::Texture *source, + GLint sourceLevel, + const RECT &sourceRect, + GLenum destFormat, + const gl::Offset &destOffset, + TextureStorage *storage, + GLenum destTarget, + GLint destLevel, + bool flipY, + bool premultiplyAlpha, + bool unmultiplyAlpha) +{ + ANGLE_TRY(initialize()); + + const TextureD3D *sourceD3D = GetImplAs(source); + + TextureStorage *sourceStorage = nullptr; + ANGLE_TRY(const_cast(sourceD3D)->getNativeTexture(context, &sourceStorage)); + + TextureStorage9_2D *sourceStorage9 = GetAs(sourceStorage); + ASSERT(sourceStorage9); + + TextureStorage9 *destStorage9 = GetAs(storage); + ASSERT(destStorage9); + + ASSERT(sourceLevel == 0); + IDirect3DBaseTexture9 *sourceTexture = nullptr; + ANGLE_TRY(sourceStorage9->getBaseTexture(context, &sourceTexture)); + + IDirect3DSurface9 *sourceSurface = nullptr; + ANGLE_TRY( + sourceStorage9->getSurfaceLevel(context, GL_TEXTURE_2D, sourceLevel, true, &sourceSurface)); + + IDirect3DSurface9 *destSurface = nullptr; + gl::Error error = + destStorage9->getSurfaceLevel(context, destTarget, destLevel, true, &destSurface); + if (error.isError()) + { + SafeRelease(sourceSurface); + return error; + } + + error = copy(sourceSurface, sourceTexture, sourceRect, destFormat, destOffset, destSurface, + flipY, premultiplyAlpha, unmultiplyAlpha); + + SafeRelease(sourceSurface); + SafeRelease(destSurface); + + return error; +} + +gl::Error Blit9::copy(IDirect3DSurface9 *source, + IDirect3DBaseTexture9 *sourceTexture, + const RECT &sourceRect, + GLenum destFormat, + const gl::Offset &destOffset, + IDirect3DSurface9 *dest, + bool flipY, + bool premultiplyAlpha, + bool unmultiplyAlpha) { - ASSERT(source != NULL && dest != NULL); + ASSERT(source != nullptr && dest != nullptr); IDirect3DDevice9 *device = mRenderer->getDevice(); @@ -319,8 +394,10 @@ gl::Error Blit9::copy(IDirect3DSurface9 *source, const RECT &sourceRect, GLenum source->GetDesc(&sourceDesc); dest->GetDesc(&destDesc); - if (sourceDesc.Format == destDesc.Format && destDesc.Usage & D3DUSAGE_RENDERTARGET && - d3d9_gl::IsFormatChannelEquivalent(destDesc.Format, destFormat)) // Can use StretchRect + // Check if it's possible to use StetchRect + if (sourceDesc.Format == destDesc.Format && (destDesc.Usage & D3DUSAGE_RENDERTARGET) && + d3d9_gl::IsFormatChannelEquivalent(destDesc.Format, destFormat) && !flipY && + premultiplyAlpha == unmultiplyAlpha) { 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); @@ -328,85 +405,135 @@ gl::Error Blit9::copy(IDirect3DSurface9 *source, const RECT &sourceRect, GLenum 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::OutOfMemory() + << "Failed to blit between textures, StretchRect " << gl::FmtHR(result); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } else { - return formatConvert(source, sourceRect, destFormat, destOffset, dest); - } -} + IDirect3DBaseTexture9 *texture = sourceTexture; + RECT adjustedSourceRect = sourceRect; + gl::Extents sourceSize(sourceDesc.Width, sourceDesc.Height, 1); -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; - } + if (texture == nullptr) + { + ANGLE_TRY(copySurfaceToTexture(source, sourceRect, &texture)); + + // copySurfaceToTexture only copies in the sourceRect area of the source surface. + // Adjust sourceRect so that it is now covering the entire source texture + adjustedSourceRect.left = 0; + adjustedSourceRect.right = sourceRect.right - sourceRect.left; + adjustedSourceRect.top = 0; + adjustedSourceRect.bottom = sourceRect.bottom - sourceRect.top; + + sourceSize.width = sourceRect.right - sourceRect.left; + sourceSize.height = sourceRect.bottom - sourceRect.top; + } + else + { + texture->AddRef(); + } + + gl::Error error = formatConvert(texture, adjustedSourceRect, sourceSize, destFormat, + destOffset, dest, flipY, premultiplyAlpha, unmultiplyAlpha); + + SafeRelease(texture); - IDirect3DTexture9 *texture = NULL; - error = copySurfaceToTexture(source, sourceRect, &texture); - if (error.isError()) - { return error; } +} + +gl::Error Blit9::formatConvert(IDirect3DBaseTexture9 *source, + const RECT &sourceRect, + const gl::Extents &sourceSize, + GLenum destFormat, + const gl::Offset &destOffset, + IDirect3DSurface9 *dest, + bool flipY, + bool premultiplyAlpha, + bool unmultiplyAlpha) +{ + ANGLE_TRY(initialize()); IDirect3DDevice9 *device = mRenderer->getDevice(); saveState(); - device->SetTexture(0, texture); + device->SetTexture(0, source); device->SetRenderTarget(0, dest); - setViewport(sourceRect, destOffset); + RECT destRect; + destRect.left = destOffset.x; + destRect.right = destOffset.x + (sourceRect.right - sourceRect.left); + destRect.top = destOffset.y; + destRect.bottom = destOffset.y + (sourceRect.bottom - sourceRect.top); + + setViewportAndShaderConstants(sourceRect, sourceSize, destRect, flipY); setCommonBlitState(); - error = setFormatConvertShaders(destFormat); + gl::Error error = setFormatConvertShaders(destFormat, flipY, premultiplyAlpha, unmultiplyAlpha); if (!error.isError()) { render(); } - SafeRelease(texture); - restoreState(); return error; } -gl::Error Blit9::setFormatConvertShaders(GLenum destFormat) +gl::Error Blit9::setFormatConvertShaders(GLenum destFormat, + bool flipY, + bool premultiplyAlpha, + bool unmultiplyAlpha) { - gl::Error error = setVertexShader(SHADER_VS_STANDARD); - if (error.isError()) - { - return error; - } + ANGLE_TRY(setVertexShader(SHADER_VS_STANDARD)); 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; + if (premultiplyAlpha == unmultiplyAlpha) + { + ANGLE_TRY(setPixelShader(SHADER_PS_COMPONENTMASK)); + } + else if (premultiplyAlpha) + { + ANGLE_TRY(setPixelShader(SHADER_PS_COMPONENTMASK_PREMULTIPLY_ALPHA)); + } + else + { + ASSERT(unmultiplyAlpha); + ANGLE_TRY(setPixelShader(SHADER_PS_COMPONENTMASK_UNMULTIPLY_ALPHA)); + } + break; case GL_LUMINANCE: case GL_LUMINANCE_ALPHA: - error = setPixelShader(SHADER_PS_LUMINANCE); - break; - } - - if (error.isError()) - { - return error; + if (premultiplyAlpha == unmultiplyAlpha) + { + ANGLE_TRY(setPixelShader(SHADER_PS_LUMINANCE)); + } + else if (premultiplyAlpha) + { + ANGLE_TRY(setPixelShader(SHADER_PS_LUMINANCE_PREMULTIPLY_ALPHA)); + } + else + { + ASSERT(unmultiplyAlpha); + ANGLE_TRY(setPixelShader(SHADER_PS_LUMINANCE_UNMULTIPLY_ALPHA)); + } + break; + + default: + UNREACHABLE(); } enum { X = 0, Y = 1, Z = 2, W = 3 }; @@ -502,10 +629,12 @@ gl::Error Blit9::setFormatConvertShaders(GLenum destFormat) mRenderer->getDevice()->SetPixelShaderConstantF(0, psConst, 2); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error Blit9::copySurfaceToTexture(IDirect3DSurface9 *surface, const RECT &sourceRect, IDirect3DTexture9 **outTexture) +gl::Error Blit9::copySurfaceToTexture(IDirect3DSurface9 *surface, + const RECT &sourceRect, + IDirect3DBaseTexture9 **outTexture) { ASSERT(surface); @@ -516,12 +645,15 @@ gl::Error Blit9::copySurfaceToTexture(IDirect3DSurface9 *surface, const RECT &so // 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); + HRESULT result = device->CreateTexture( + sourceRect.right - sourceRect.left, sourceRect.bottom - sourceRect.top, 1, + D3DUSAGE_RENDERTARGET, sourceDesc.Format, D3DPOOL_DEFAULT, &texture, nullptr); 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); + return gl::OutOfMemory() << "Failed to allocate internal texture for blit, " + << gl::FmtHR(result); } IDirect3DSurface9 *textureSurface; @@ -531,11 +663,12 @@ gl::Error Blit9::copySurfaceToTexture(IDirect3DSurface9 *surface, const RECT &so { 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); + return gl::OutOfMemory() << "Failed to query surface of internal blit texture, " + << gl::FmtHR(result); } mRenderer->endScene(); - result = device->StretchRect(surface, &sourceRect, textureSurface, NULL, D3DTEXF_NONE); + result = device->StretchRect(surface, &sourceRect, textureSurface, nullptr, D3DTEXF_NONE); SafeRelease(textureSurface); @@ -543,35 +676,50 @@ gl::Error Blit9::copySurfaceToTexture(IDirect3DSurface9 *surface, const RECT &so { 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); + return gl::OutOfMemory() << "Failed to copy between internal blit textures, " + << gl::FmtHR(result); } *outTexture = texture; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -void Blit9::setViewport(const RECT &sourceRect, const gl::Offset &offset) +void Blit9::setViewportAndShaderConstants(const RECT &sourceRect, + const gl::Extents &sourceSize, + const RECT &destRect, + bool flipY) { 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.X = destRect.left; + vp.Y = destRect.top; + vp.Width = destRect.right - destRect.left; + vp.Height = destRect.bottom - destRect.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); + float vertexConstants[8] = { + // halfPixelAdjust + -1.0f / vp.Width, 1.0f / vp.Height, 0, 0, + // texcoordOffset + static_cast(sourceRect.left) / sourceSize.width, + static_cast(flipY ? sourceRect.bottom : sourceRect.top) / sourceSize.height, + static_cast(sourceRect.right - sourceRect.left) / sourceSize.width, + static_cast(flipY ? sourceRect.top - sourceRect.bottom + : sourceRect.bottom - sourceRect.top) / + sourceSize.height, + }; + + device->SetVertexShaderConstantF(0, vertexConstants, 2); } void Blit9::setCommonBlitState() { IDirect3DDevice9 *device = mRenderer->getDevice(); - device->SetDepthStencilSurface(NULL); + device->SetDepthStencilSurface(nullptr); device->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID); device->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE); @@ -617,7 +765,7 @@ void Blit9::saveState() device->GetDepthStencilSurface(&mSavedDepthStencil); device->GetRenderTarget(0, &mSavedRenderTarget); - if (mSavedStateBlock == NULL) + if (mSavedStateBlock == nullptr) { hr = device->BeginStateBlock(); ASSERT(SUCCEEDED(hr) || hr == D3DERR_OUTOFVIDEOMEMORY || hr == E_OUTOFMEMORY); @@ -626,9 +774,9 @@ void Blit9::saveState() static const float dummyConst[8] = { 0 }; - device->SetVertexShader(NULL); + device->SetVertexShader(nullptr); device->SetVertexShaderConstantF(0, dummyConst, 2); - device->SetPixelShader(NULL); + device->SetPixelShader(nullptr); device->SetPixelShaderConstantF(0, dummyConst, 2); D3DVIEWPORT9 dummyVp; @@ -641,7 +789,7 @@ void Blit9::saveState() device->SetViewport(&dummyVp); - device->SetTexture(0, NULL); + device->SetTexture(0, nullptr); device->SetStreamSource(0, mQuadVertexBuffer, 0, 0); @@ -651,9 +799,9 @@ void Blit9::saveState() ASSERT(SUCCEEDED(hr) || hr == D3DERR_OUTOFVIDEOMEMORY || hr == E_OUTOFMEMORY); } - ASSERT(mSavedStateBlock != NULL); + ASSERT(mSavedStateBlock != nullptr); - if (mSavedStateBlock != NULL) + if (mSavedStateBlock != nullptr) { hr = mSavedStateBlock->Capture(); ASSERT(SUCCEEDED(hr)); @@ -670,9 +818,9 @@ void Blit9::restoreState() device->SetRenderTarget(0, mSavedRenderTarget); SafeRelease(mSavedRenderTarget); - ASSERT(mSavedStateBlock != NULL); + ASSERT(mSavedStateBlock != nullptr); - if (mSavedStateBlock != NULL) + if (mSavedStateBlock != nullptr) { 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 index 586abd2580..026874f8ae 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Blit9.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Blit9.h @@ -16,7 +16,10 @@ namespace gl { +class Context; class Framebuffer; +class Texture; +struct Extents; struct Offset; } @@ -35,13 +38,33 @@ class Blit9 : angle::NonCopyable // 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); + gl::Error copy2D(const gl::Context *context, + const gl::Framebuffer *framebuffer, + const RECT &sourceRect, + GLenum destFormat, + const gl::Offset &destOffset, + TextureStorage *storage, + GLint level); + gl::Error copyCube(const gl::Context *context, + const gl::Framebuffer *framebuffer, + const RECT &sourceRect, + GLenum destFormat, + const gl::Offset &destOffset, + TextureStorage *storage, + GLenum target, + GLint level); + gl::Error copyTexture(const gl::Context *context, + const gl::Texture *source, + GLint sourceLevel, + const RECT &sourceRect, + GLenum destFormat, + const gl::Offset &destOffset, + TextureStorage *storage, + GLenum destTarget, + GLint destLevel, + bool flipY, + bool premultiplyAlpha, + bool unmultiplyAlpha); // 2x2 box filter sample from source to dest. // Requires that source is RGB(A) and dest has the same format as source. @@ -54,23 +77,56 @@ class Blit9 : angle::NonCopyable 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); + // Copy from source texture 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(IDirect3DBaseTexture9 *source, + const RECT &sourceRect, + const gl::Extents &sourceSize, + GLenum destFormat, + const gl::Offset &destOffset, + IDirect3DSurface9 *dest, + bool flipY, + bool premultiplyAlpha, + bool unmultiplyAlpha); + gl::Error setFormatConvertShaders(GLenum destFormat, + bool flipY, + bool premultiplyAlpha, + bool unmultiplyAlpha); + + gl::Error copy(IDirect3DSurface9 *source, + IDirect3DBaseTexture9 *sourceTexture, + const RECT &sourceRect, + GLenum destFormat, + const gl::Offset &destOffset, + IDirect3DSurface9 *dest, + bool flipY, + bool premultiplyAlpha, + bool unmultiplyAlpha); + gl::Error copySurfaceToTexture(IDirect3DSurface9 *surface, + const RECT &sourceRect, + IDirect3DBaseTexture9 **outTexture); + void setViewportAndShaderConstants(const RECT &sourceRect, + const gl::Extents &sourceSize, + const RECT &destRect, + bool flipY); void setCommonBlitState(); RECT getSurfaceRect(IDirect3DSurface9 *surface) const; + gl::Extents getSurfaceSize(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_LUMINANCE_PREMULTIPLY_ALPHA, + SHADER_PS_LUMINANCE_UNMULTIPLY_ALPHA, SHADER_PS_COMPONENTMASK, - SHADER_COUNT + SHADER_PS_COMPONENTMASK_PREMULTIPLY_ALPHA, + SHADER_PS_COMPONENTMASK_UNMULTIPLY_ALPHA, + SHADER_COUNT, }; // This actually contains IDirect3DVertexShader9 or IDirect3DPixelShader9 casted to IUnknown. diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Buffer9.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Buffer9.cpp index 804b6971ce..dc308e7752 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Buffer9.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Buffer9.cpp @@ -12,23 +12,37 @@ namespace rx { -Buffer9::Buffer9(Renderer9 *renderer) - : BufferD3D(renderer), - mSize(0) -{} +Buffer9::Buffer9(const gl::BufferState &state, Renderer9 *renderer) + : BufferD3D(state, renderer), mSize(0) +{ +} Buffer9::~Buffer9() { mSize = 0; } -gl::Error Buffer9::setData(const void* data, size_t size, GLenum usage) +size_t Buffer9::getSize() const +{ + return mSize; +} + +bool Buffer9::supportsDirectBinding() const +{ + return false; +} + +gl::Error Buffer9::setData(const gl::Context *context, + gl::BufferBinding /*target*/, + const void *data, + size_t size, + gl::BufferUsage usage) { if (size > mMemory.size()) { if (!mMemory.resize(size)) { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to resize internal buffer."); + return gl::OutOfMemory() << "Failed to resize internal buffer."; } } @@ -38,25 +52,30 @@ gl::Error Buffer9::setData(const void* data, size_t size, GLenum usage) memcpy(mMemory.data(), data, size); } - invalidateStaticData(D3D_BUFFER_INVALIDATE_WHOLE_CACHE); + updateD3DBufferUsage(context, usage); - updateD3DBufferUsage(usage); - return gl::Error(GL_NO_ERROR); + invalidateStaticData(context); + + return gl::NoError(); } -gl::Error Buffer9::getData(const uint8_t **outData) +gl::Error Buffer9::getData(const gl::Context *context, const uint8_t **outData) { *outData = mMemory.data(); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error Buffer9::setSubData(const void* data, size_t size, size_t offset) +gl::Error Buffer9::setSubData(const gl::Context *context, + gl::BufferBinding /*target*/, + 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."); + return gl::OutOfMemory() << "Failed to resize internal buffer."; } } @@ -66,46 +85,55 @@ gl::Error Buffer9::setSubData(const void* data, size_t size, size_t offset) memcpy(mMemory.data() + offset, data, size); } - invalidateStaticData(D3D_BUFFER_INVALIDATE_WHOLE_CACHE); + invalidateStaticData(context); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error Buffer9::copySubData(BufferImpl* source, GLintptr sourceOffset, GLintptr destOffset, GLsizeiptr size) +gl::Error Buffer9::copySubData(const gl::Context *context, + BufferImpl *source, + GLintptr sourceOffset, + GLintptr destOffset, + GLsizeiptr size) { // Note: this method is currently unreachable - Buffer9* sourceBuffer = GetAs(source); + Buffer9 *sourceBuffer = GetAs(source); ASSERT(sourceBuffer); memcpy(mMemory.data() + destOffset, sourceBuffer->mMemory.data() + sourceOffset, size); - invalidateStaticData(D3D_BUFFER_INVALIDATE_WHOLE_CACHE); + invalidateStaticData(context); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } // We do not support buffer mapping in D3D9 -gl::Error Buffer9::map(GLenum access, GLvoid **mapPtr) +gl::Error Buffer9::map(const gl::Context *context, GLenum access, void **mapPtr) { UNREACHABLE(); - return gl::Error(GL_INVALID_OPERATION); + return gl::InternalError(); } -gl::Error Buffer9::mapRange(size_t offset, size_t length, GLbitfield access, GLvoid **mapPtr) +gl::Error Buffer9::mapRange(const gl::Context *context, + size_t offset, + size_t length, + GLbitfield access, + void **mapPtr) { UNREACHABLE(); - return gl::Error(GL_INVALID_OPERATION); + return gl::InternalError(); } -gl::Error Buffer9::unmap(GLboolean *result) +gl::Error Buffer9::unmap(const gl::Context *context, GLboolean *result) { UNREACHABLE(); - return gl::Error(GL_INVALID_OPERATION); + return gl::InternalError(); } -void Buffer9::markTransformFeedbackUsage() +gl::Error Buffer9::markTransformFeedbackUsage(const gl::Context *context) { UNREACHABLE(); + return gl::InternalError(); } -} +} // namespace rx diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Buffer9.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Buffer9.h index 44a524ba28..960b2a2474 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Buffer9.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Buffer9.h @@ -20,28 +20,44 @@ class Renderer9; class Buffer9 : public BufferD3D { public: - Buffer9(Renderer9 *renderer); - virtual ~Buffer9(); + Buffer9(const gl::BufferState &state, Renderer9 *renderer); + ~Buffer9() override; // BufferD3D implementation - virtual size_t getSize() const { return mSize; } - virtual bool supportsDirectBinding() const { return false; } - gl::Error getData(const uint8_t **outData) override; + size_t getSize() const override; + bool supportsDirectBinding() const override; + gl::Error getData(const gl::Context *context, const uint8_t **outData) override; // BufferImpl implementation - virtual gl::Error setData(const void* data, size_t size, GLenum usage); - 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(GLenum access, GLvoid **mapPtr); - virtual gl::Error mapRange(size_t offset, size_t length, GLbitfield access, GLvoid **mapPtr); - virtual gl::Error unmap(GLboolean *result); - virtual void markTransformFeedbackUsage(); + gl::Error setData(const gl::Context *context, + gl::BufferBinding target, + const void *data, + size_t size, + gl::BufferUsage usage) override; + gl::Error setSubData(const gl::Context *context, + gl::BufferBinding target, + const void *data, + size_t size, + size_t offset) override; + gl::Error copySubData(const gl::Context *context, + BufferImpl *source, + GLintptr sourceOffset, + GLintptr destOffset, + GLsizeiptr size) override; + gl::Error map(const gl::Context *context, GLenum access, void **mapPtr) override; + gl::Error mapRange(const gl::Context *context, + size_t offset, + size_t length, + GLbitfield access, + void **mapPtr) override; + gl::Error unmap(const gl::Context *context, GLboolean *result) override; + gl::Error markTransformFeedbackUsage(const gl::Context *context) override; private: - MemoryBuffer mMemory; + angle::MemoryBuffer mMemory; size_t mSize; }; -} +} // namespace rx -#endif // LIBANGLE_RENDERER_D3D_D3D9_BUFFER9_H_ +#endif // LIBANGLE_RENDERER_D3D_D3D9_BUFFER9_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Context9.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Context9.cpp new file mode 100644 index 0000000000..1b9874cc20 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Context9.cpp @@ -0,0 +1,303 @@ +// +// Copyright 2016 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. +// +// Context9: +// D3D9-specific functionality associated with a GL Context. +// + +#include "libANGLE/renderer/d3d/d3d9/Context9.h" + +#include "common/string_utils.h" +#include "libANGLE/renderer/d3d/CompilerD3D.h" +#include "libANGLE/renderer/d3d/ProgramD3D.h" +#include "libANGLE/renderer/d3d/RenderbufferD3D.h" +#include "libANGLE/renderer/d3d/SamplerD3D.h" +#include "libANGLE/renderer/d3d/ShaderD3D.h" +#include "libANGLE/renderer/d3d/TextureD3D.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/Query9.h" +#include "libANGLE/renderer/d3d/d3d9/Renderer9.h" +#include "libANGLE/renderer/d3d/d3d9/StateManager9.h" +#include "libANGLE/renderer/d3d/d3d9/VertexArray9.h" + +namespace rx +{ + +Context9::Context9(const gl::ContextState &state, Renderer9 *renderer) + : ContextImpl(state), mRenderer(renderer) +{ +} + +Context9::~Context9() +{ +} + +gl::Error Context9::initialize() +{ + return gl::NoError(); +} + +CompilerImpl *Context9::createCompiler() +{ + return new CompilerD3D(SH_HLSL_3_0_OUTPUT); +} + +ShaderImpl *Context9::createShader(const gl::ShaderState &data) +{ + return new ShaderD3D(data, mRenderer->getWorkarounds(), mRenderer->getNativeExtensions()); +} + +ProgramImpl *Context9::createProgram(const gl::ProgramState &data) +{ + return new ProgramD3D(data, mRenderer); +} + +FramebufferImpl *Context9::createFramebuffer(const gl::FramebufferState &data) +{ + return new Framebuffer9(data, mRenderer); +} + +TextureImpl *Context9::createTexture(const gl::TextureState &state) +{ + switch (state.getTarget()) + { + case GL_TEXTURE_2D: + return new TextureD3D_2D(state, mRenderer); + case GL_TEXTURE_CUBE_MAP: + return new TextureD3D_Cube(state, mRenderer); + case GL_TEXTURE_EXTERNAL_OES: + return new TextureD3D_External(state, mRenderer); + default: + UNREACHABLE(); + } + return nullptr; +} + +RenderbufferImpl *Context9::createRenderbuffer() +{ + return new RenderbufferD3D(mRenderer); +} + +BufferImpl *Context9::createBuffer(const gl::BufferState &state) +{ + return new Buffer9(state, mRenderer); +} + +VertexArrayImpl *Context9::createVertexArray(const gl::VertexArrayState &data) +{ + return new VertexArray9(data); +} + +QueryImpl *Context9::createQuery(GLenum type) +{ + return new Query9(mRenderer, type); +} + +FenceNVImpl *Context9::createFenceNV() +{ + return new FenceNV9(mRenderer); +} + +SyncImpl *Context9::createSync() +{ + // D3D9 doesn't support ES 3.0 and its sync objects. + UNREACHABLE(); + return nullptr; +} + +TransformFeedbackImpl *Context9::createTransformFeedback(const gl::TransformFeedbackState &state) +{ + UNREACHABLE(); + return nullptr; +} + +SamplerImpl *Context9::createSampler(const gl::SamplerState &state) +{ + return new SamplerD3D(state); +} + +ProgramPipelineImpl *Context9::createProgramPipeline(const gl::ProgramPipelineState &data) +{ + UNREACHABLE(); + return nullptr; +} + +std::vector Context9::createPaths(GLsizei) +{ + return std::vector(); +} + +gl::Error Context9::flush(const gl::Context *context) +{ + return mRenderer->flush(); +} + +gl::Error Context9::finish(const gl::Context *context) +{ + return mRenderer->finish(); +} + +gl::Error Context9::drawArrays(const gl::Context *context, GLenum mode, GLint first, GLsizei count) +{ + return mRenderer->genericDrawArrays(context, mode, first, count, 0); +} + +gl::Error Context9::drawArraysInstanced(const gl::Context *context, + GLenum mode, + GLint first, + GLsizei count, + GLsizei instanceCount) +{ + return mRenderer->genericDrawArrays(context, mode, first, count, instanceCount); +} + +gl::Error Context9::drawElements(const gl::Context *context, + GLenum mode, + GLsizei count, + GLenum type, + const void *indices) +{ + return mRenderer->genericDrawElements(context, mode, count, type, indices, 0); +} + +gl::Error Context9::drawElementsInstanced(const gl::Context *context, + GLenum mode, + GLsizei count, + GLenum type, + const void *indices, + GLsizei instances) +{ + return mRenderer->genericDrawElements(context, mode, count, type, indices, instances); +} + +gl::Error Context9::drawRangeElements(const gl::Context *context, + GLenum mode, + GLuint start, + GLuint end, + GLsizei count, + GLenum type, + const void *indices) +{ + return mRenderer->genericDrawElements(context, mode, count, type, indices, 0); +} + +gl::Error Context9::drawArraysIndirect(const gl::Context *context, + GLenum mode, + const void *indirect) +{ + UNREACHABLE(); + return gl::InternalError() << "D3D9 doesn't support ES 3.1 DrawArraysIndirect API"; +} + +gl::Error Context9::drawElementsIndirect(const gl::Context *context, + GLenum mode, + GLenum type, + const void *indirect) +{ + UNREACHABLE(); + return gl::InternalError() << "D3D9 doesn't support ES 3.1 DrawElementsIndirect API"; +} + +GLenum Context9::getResetStatus() +{ + return mRenderer->getResetStatus(); +} + +std::string Context9::getVendorString() const +{ + return mRenderer->getVendorString(); +} + +std::string Context9::getRendererDescription() const +{ + return mRenderer->getRendererDescription(); +} + +void Context9::insertEventMarker(GLsizei length, const char *marker) +{ + auto optionalString = angle::WidenString(static_cast(length), marker); + if (optionalString.valid()) + { + mRenderer->getAnnotator()->setMarker(optionalString.value().data()); + } +} + +void Context9::pushGroupMarker(GLsizei length, const char *marker) +{ + auto optionalString = angle::WidenString(static_cast(length), marker); + if (optionalString.valid()) + { + mRenderer->getAnnotator()->beginEvent(optionalString.value().data()); + } +} + +void Context9::popGroupMarker() +{ + mRenderer->getAnnotator()->endEvent(); +} + +void Context9::pushDebugGroup(GLenum source, GLuint id, GLsizei length, const char *message) +{ + // Fall through to the EXT_debug_marker functions + pushGroupMarker(length, message); +} + +void Context9::popDebugGroup() +{ + // Fall through to the EXT_debug_marker functions + popGroupMarker(); +} + +void Context9::syncState(const gl::Context *context, const gl::State::DirtyBits &dirtyBits) +{ + mRenderer->getStateManager()->syncState(mState.getState(), dirtyBits); +} + +GLint Context9::getGPUDisjoint() +{ + return mRenderer->getGPUDisjoint(); +} + +GLint64 Context9::getTimestamp() +{ + return mRenderer->getTimestamp(); +} + +void Context9::onMakeCurrent(const gl::Context *context) +{ +} + +const gl::Caps &Context9::getNativeCaps() const +{ + return mRenderer->getNativeCaps(); +} + +const gl::TextureCapsMap &Context9::getNativeTextureCaps() const +{ + return mRenderer->getNativeTextureCaps(); +} + +const gl::Extensions &Context9::getNativeExtensions() const +{ + return mRenderer->getNativeExtensions(); +} + +const gl::Limitations &Context9::getNativeLimitations() const +{ + return mRenderer->getNativeLimitations(); +} + +gl::Error Context9::dispatchCompute(const gl::Context *context, + GLuint numGroupsX, + GLuint numGroupsY, + GLuint numGroupsZ) +{ + UNREACHABLE(); + return gl::InternalError() << "D3D9 doesn't support ES 3.1 DispatchCompute API"; +} + +} // namespace rx diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Context9.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Context9.h new file mode 100644 index 0000000000..d681bfde89 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Context9.h @@ -0,0 +1,151 @@ +// +// Copyright 2016 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. +// +// Context9: +// D3D9-specific functionality associated with a GL Context. +// + +#ifndef LIBANGLE_RENDERER_D3D_D3D9_CONTEXT9_H_ +#define LIBANGLE_RENDERER_D3D_D3D9_CONTEXT9_H_ + +#include "libANGLE/renderer/ContextImpl.h" + +namespace rx +{ +class Renderer9; + +class Context9 : public ContextImpl +{ + public: + Context9(const gl::ContextState &state, Renderer9 *renderer); + ~Context9() override; + + gl::Error initialize() override; + + // Shader creation + CompilerImpl *createCompiler() override; + ShaderImpl *createShader(const gl::ShaderState &data) override; + ProgramImpl *createProgram(const gl::ProgramState &data) override; + + // Framebuffer creation + FramebufferImpl *createFramebuffer(const gl::FramebufferState &data) override; + + // Texture creation + TextureImpl *createTexture(const gl::TextureState &state) override; + + // Renderbuffer creation + RenderbufferImpl *createRenderbuffer() override; + + // Buffer creation + BufferImpl *createBuffer(const gl::BufferState &state) override; + + // Vertex Array creation + VertexArrayImpl *createVertexArray(const gl::VertexArrayState &data) override; + + // Query and Fence creation + QueryImpl *createQuery(GLenum type) override; + FenceNVImpl *createFenceNV() override; + SyncImpl *createSync() override; + + // Transform Feedback creation + TransformFeedbackImpl *createTransformFeedback( + const gl::TransformFeedbackState &state) override; + + // Sampler object creation + SamplerImpl *createSampler(const gl::SamplerState &state) override; + + // Program Pipeline object creation + ProgramPipelineImpl *createProgramPipeline(const gl::ProgramPipelineState &data) override; + + // Path object creation + std::vector createPaths(GLsizei) override; + + // Flush and finish. + gl::Error flush(const gl::Context *context) override; + gl::Error finish(const gl::Context *context) override; + + // Drawing methods. + gl::Error drawArrays(const gl::Context *context, + GLenum mode, + GLint first, + GLsizei count) override; + gl::Error drawArraysInstanced(const gl::Context *context, + GLenum mode, + GLint first, + GLsizei count, + GLsizei instanceCount) override; + + gl::Error drawElements(const gl::Context *context, + GLenum mode, + GLsizei count, + GLenum type, + const void *indices) override; + gl::Error drawElementsInstanced(const gl::Context *context, + GLenum mode, + GLsizei count, + GLenum type, + const void *indices, + GLsizei instances) override; + gl::Error drawRangeElements(const gl::Context *context, + GLenum mode, + GLuint start, + GLuint end, + GLsizei count, + GLenum type, + const void *indices) override; + gl::Error drawArraysIndirect(const gl::Context *context, + GLenum mode, + const void *indirect) override; + gl::Error drawElementsIndirect(const gl::Context *context, + GLenum mode, + GLenum type, + const void *indirect) override; + + // Device loss + GLenum getResetStatus() override; + + // Vendor and description strings. + std::string getVendorString() const override; + std::string getRendererDescription() const override; + + // EXT_debug_marker + void insertEventMarker(GLsizei length, const char *marker) override; + void pushGroupMarker(GLsizei length, const char *marker) override; + void popGroupMarker() override; + + // KHR_debug + void pushDebugGroup(GLenum source, GLuint id, GLsizei length, const char *message) override; + void popDebugGroup() override; + + // State sync with dirty bits. + void syncState(const gl::Context *context, const gl::State::DirtyBits &dirtyBits) override; + + // Disjoint timer queries + GLint getGPUDisjoint() override; + GLint64 getTimestamp() override; + + // Context switching + void onMakeCurrent(const gl::Context *context) override; + + // Caps queries + const gl::Caps &getNativeCaps() const override; + const gl::TextureCapsMap &getNativeTextureCaps() const override; + const gl::Extensions &getNativeExtensions() const override; + const gl::Limitations &getNativeLimitations() const override; + + gl::Error dispatchCompute(const gl::Context *context, + GLuint numGroupsX, + GLuint numGroupsY, + GLuint numGroupsZ) override; + + Renderer9 *getRenderer() const { return mRenderer; } + + private: + Renderer9 *mRenderer; +}; + +} // namespace rx + +#endif // LIBANGLE_RENDERER_D3D_D3D9_CONTEXT9_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/DebugAnnotator9.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/DebugAnnotator9.h index 54e3bb9490..b28008335f 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/DebugAnnotator9.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/DebugAnnotator9.h @@ -9,12 +9,12 @@ #ifndef LIBANGLE_RENDERER_D3D_D3D9_DEBUGANNOTATOR9_H_ #define LIBANGLE_RENDERER_D3D_D3D9_DEBUGANNOTATOR9_H_ -#include "common/debug.h" +#include "libANGLE/LoggingAnnotator.h" namespace rx { -class DebugAnnotator9 : public gl::DebugAnnotator +class DebugAnnotator9 : public angle::LoggingAnnotator { public: DebugAnnotator9() {} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Fence9.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Fence9.cpp index 3300681277..bff3881655 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Fence9.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Fence9.cpp @@ -13,10 +13,7 @@ namespace rx { -FenceNV9::FenceNV9(Renderer9 *renderer) - : FenceNVImpl(), - mRenderer(renderer), - mQuery(NULL) +FenceNV9::FenceNV9(Renderer9 *renderer) : FenceNVImpl(), mRenderer(renderer), mQuery(nullptr) { } @@ -41,10 +38,10 @@ gl::Error FenceNV9::set(GLenum condition) { 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::OutOfMemory() << "Failed to end event query, " << gl::FmtHR(result); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } gl::Error FenceNV9::test(GLboolean *outFinished) @@ -66,7 +63,7 @@ gl::Error FenceNV9::finish() Sleep(0); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } gl::Error FenceNV9::testHelper(bool flushCommandBuffer, GLboolean *outFinished) @@ -74,21 +71,21 @@ gl::Error FenceNV9::testHelper(bool flushCommandBuffer, GLboolean *outFinished) ASSERT(mQuery); DWORD getDataFlags = (flushCommandBuffer ? D3DGETDATA_FLUSH : 0); - HRESULT result = mQuery->GetData(NULL, 0, getDataFlags); + HRESULT result = mQuery->GetData(nullptr, 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."); + return gl::OutOfMemory() << "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); + return gl::OutOfMemory() << "Failed to get query data, " << gl::FmtHR(result); } ASSERT(result == S_OK || result == S_FALSE); *outFinished = ((result == S_OK) ? GL_TRUE : GL_FALSE); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } } diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Fence9.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Fence9.h index 200ac68d27..de0ff20774 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Fence9.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Fence9.h @@ -10,7 +10,7 @@ #define LIBANGLE_RENDERER_D3D_D3D9_FENCE9_H_ #include "libANGLE/renderer/FenceNVImpl.h" -#include "libANGLE/renderer/FenceSyncImpl.h" +#include "libANGLE/renderer/SyncImpl.h" namespace rx { diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Framebuffer9.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Framebuffer9.cpp index 9c269a8565..dff12e03f8 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Framebuffer9.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Framebuffer9.cpp @@ -7,21 +7,25 @@ // 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/Context.h" #include "libANGLE/Framebuffer.h" #include "libANGLE/FramebufferAttachment.h" #include "libANGLE/Texture.h" +#include "libANGLE/formatutils.h" +#include "libANGLE/renderer/ContextImpl.h" +#include "libANGLE/renderer/d3d/TextureD3D.h" +#include "libANGLE/renderer/d3d/d3d9/RenderTarget9.h" +#include "libANGLE/renderer/d3d/d3d9/Renderer9.h" +#include "libANGLE/renderer/d3d/d3d9/TextureStorage9.h" +#include "libANGLE/renderer/d3d/d3d9/formatutils9.h" +#include "libANGLE/renderer/d3d/d3d9/renderer9_utils.h" +#include "libANGLE/renderer/renderer_utils.h" namespace rx { -Framebuffer9::Framebuffer9(const gl::Framebuffer::Data &data, Renderer9 *renderer) +Framebuffer9::Framebuffer9(const gl::FramebufferState &data, Renderer9 *renderer) : FramebufferD3D(data, renderer), mRenderer(renderer) { ASSERT(mRenderer != nullptr); @@ -31,66 +35,61 @@ Framebuffer9::~Framebuffer9() { } -gl::Error Framebuffer9::discard(size_t, const GLenum *) +gl::Error Framebuffer9::discard(const gl::Context *context, size_t, const GLenum *) { // Extension not implemented in D3D9 renderer UNREACHABLE(); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error Framebuffer9::invalidate(size_t, const GLenum *) +gl::Error Framebuffer9::invalidate(const gl::Context *context, size_t, const GLenum *) { // Shouldn't ever reach here in D3D9 UNREACHABLE(); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error Framebuffer9::invalidateSub(size_t, const GLenum *, const gl::Rectangle &) +gl::Error Framebuffer9::invalidateSub(const gl::Context *context, + size_t, + const GLenum *, + const gl::Rectangle &) { // Shouldn't ever reach here in D3D9 UNREACHABLE(); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error Framebuffer9::clear(const gl::Data &data, const ClearParameters &clearParams) +gl::Error Framebuffer9::clearImpl(const gl::Context *context, const ClearParameters &clearParams) { - const gl::FramebufferAttachment *colorAttachment = mData.getColorAttachment(0); - const gl::FramebufferAttachment *depthStencilAttachment = mData.getDepthOrStencilAttachment(); + const gl::FramebufferAttachment *colorAttachment = mState.getColorAttachment(0); + const gl::FramebufferAttachment *depthStencilAttachment = mState.getDepthOrStencilAttachment(); - gl::Error error = mRenderer->applyRenderTarget(colorAttachment, depthStencilAttachment); - if (error.isError()) - { - return error; - } + ANGLE_TRY(mRenderer->applyRenderTarget(context, colorAttachment, depthStencilAttachment)); - float nearZ = data.state->getNearPlane(); - float farZ = data.state->getFarPlane(); - mRenderer->setViewport(data.caps, data.state->getViewport(), nearZ, farZ, GL_TRIANGLES, - data.state->getRasterizerState().frontFace, true); + const gl::State &glState = context->getGLState(); + float nearZ = glState.getNearPlane(); + float farZ = glState.getFarPlane(); + mRenderer->setViewport(glState.getViewport(), nearZ, farZ, GL_TRIANGLES, + glState.getRasterizerState().frontFace, true); - mRenderer->setScissorRectangle(data.state->getScissor(), data.state->isScissorTestEnabled()); + mRenderer->setScissorRectangle(glState.getScissor(), glState.isScissorTestEnabled()); - return mRenderer->clear(clearParams, colorAttachment, depthStencilAttachment); + return mRenderer->clear(context, clearParams, colorAttachment, depthStencilAttachment); } -gl::Error Framebuffer9::readPixelsImpl(const gl::Rectangle &area, +gl::Error Framebuffer9::readPixelsImpl(const gl::Context *context, + const gl::Rectangle &area, GLenum format, GLenum type, size_t outputPitch, const gl::PixelPackState &pack, - uint8_t *pixels) const + uint8_t *pixels) { - ASSERT(pack.pixelBuffer.get() == nullptr); - - const gl::FramebufferAttachment *colorbuffer = mData.getColorAttachment(0); + const gl::FramebufferAttachment *colorbuffer = mState.getColorAttachment(0); ASSERT(colorbuffer); RenderTarget9 *renderTarget = nullptr; - gl::Error error = colorbuffer->getRenderTarget(&renderTarget); - if (error.isError()) - { - return error; - } + ANGLE_TRY(colorbuffer->getRenderTarget(context, &renderTarget)); ASSERT(renderTarget); IDirect3DSurface9 *surface = renderTarget->getSurface(); @@ -103,7 +102,8 @@ gl::Error Framebuffer9::readPixelsImpl(const gl::Rectangle &area, { 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."); + return gl::OutOfMemory() + << "ReadPixels is unimplemented for multisampled framebuffer attachments."; } IDirect3DDevice9 *device = mRenderer->getDevice(); @@ -135,7 +135,7 @@ gl::Error Framebuffer9::readPixelsImpl(const gl::Rectangle &area, { ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); SafeRelease(surface); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate internal texture for ReadPixels."); + return gl::OutOfMemory() << "Failed to allocate internal texture for ReadPixels."; } } @@ -157,13 +157,13 @@ gl::Error Framebuffer9::readPixelsImpl(const gl::Rectangle &area, UNREACHABLE(); } - return gl::Error(GL_OUT_OF_MEMORY, "Failed to read internal render target data."); + return gl::OutOfMemory() << "Failed to read internal render target data."; } if (directToPixels) { SafeRelease(systemSurface); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } RECT rect; @@ -180,85 +180,42 @@ gl::Error Framebuffer9::readPixelsImpl(const gl::Rectangle &area, UNREACHABLE(); SafeRelease(systemSurface); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock internal render target."); + return gl::OutOfMemory() << "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; - } + uint8_t *source = reinterpret_cast(lock.pBits); + int 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; + gl::FormatType formatType(format, type); - fastCopyFunc(src, dest); - } - } - } - else - { - ColorReadFunction colorReadFunction = sourceD3DFormatInfo.colorReadFunction; - ColorWriteFunction colorWriteFunction = GetColorWriteFunction(format, type); + PackPixelsParams packParams; + packParams.area.x = rect.left; + packParams.area.y = rect.top; + packParams.area.width = rect.right - rect.left; + packParams.area.height = rect.bottom - rect.top; + packParams.format = format; + packParams.type = type; + packParams.outputPitch = static_cast(outputPitch); + packParams.pack = pack; - 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); - } - } - } - } + PackPixels(packParams, d3dFormatInfo.info(), inputPitch, source, pixels); systemSurface->UnlockRect(); SafeRelease(systemSurface); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -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) +gl::Error Framebuffer9::blitImpl(const gl::Context *context, + 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); @@ -273,18 +230,18 @@ gl::Error Framebuffer9::blit(const gl::Rectangle &sourceArea, const gl::Rectangl ASSERT(readBuffer); RenderTarget9 *readRenderTarget = nullptr; - gl::Error error = readBuffer->getRenderTarget(&readRenderTarget); + gl::Error error = readBuffer->getRenderTarget(context, &readRenderTarget); if (error.isError()) { return error; } ASSERT(readRenderTarget); - const gl::FramebufferAttachment *drawBuffer = mData.getColorAttachment(0); + const gl::FramebufferAttachment *drawBuffer = mState.getColorAttachment(0); ASSERT(drawBuffer); RenderTarget9 *drawRenderTarget = nullptr; - error = drawBuffer->getRenderTarget(&drawRenderTarget); + error = drawBuffer->getRenderTarget(context, &drawRenderTarget); if (error.isError()) { return error; @@ -389,7 +346,7 @@ gl::Error Framebuffer9::blit(const gl::Rectangle &sourceArea, const gl::Rectangl if (FAILED(result)) { - return gl::Error(GL_OUT_OF_MEMORY, "Internal blit failed, StretchRect returned 0x%X.", result); + return gl::OutOfMemory() << "Internal blit failed, StretchRect " << gl::FmtHR(result); } } @@ -399,18 +356,18 @@ gl::Error Framebuffer9::blit(const gl::Rectangle &sourceArea, const gl::Rectangl ASSERT(readBuffer); RenderTarget9 *readDepthStencil = nullptr; - gl::Error error = readBuffer->getRenderTarget(&readDepthStencil); + gl::Error error = readBuffer->getRenderTarget(context, &readDepthStencil); if (error.isError()) { return error; } ASSERT(readDepthStencil); - const gl::FramebufferAttachment *drawBuffer = mData.getDepthOrStencilAttachment(); + const gl::FramebufferAttachment *drawBuffer = mState.getDepthOrStencilAttachment(); ASSERT(drawBuffer); RenderTarget9 *drawDepthStencil = nullptr; - error = drawBuffer->getRenderTarget(&drawDepthStencil); + error = drawBuffer->getRenderTarget(context, &drawDepthStencil); if (error.isError()) { return error; @@ -431,18 +388,24 @@ gl::Error Framebuffer9::blit(const gl::Rectangle &sourceArea, const gl::Rectangl if (FAILED(result)) { - return gl::Error(GL_OUT_OF_MEMORY, "Internal blit failed, StretchRect returned 0x%X.", result); + return gl::OutOfMemory() << "Internal blit failed, StretchRect " << gl::FmtHR(result); } } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } GLenum Framebuffer9::getRenderTargetImplementationFormat(RenderTargetD3D *renderTarget) const { RenderTarget9 *renderTarget9 = GetAs(renderTarget); const d3d9::D3DFormat &d3dFormatInfo = d3d9::GetD3DFormatInfo(renderTarget9->getD3DFormat()); - return d3dFormatInfo.internalFormat; + return d3dFormatInfo.info().glInternalFormat; } +gl::Error Framebuffer9::getSamplePosition(size_t index, GLfloat *xy) const +{ + UNREACHABLE(); + return gl::InternalError() << "getSamplePosition is unsupported to d3d9."; } + +} // namespace rx diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Framebuffer9.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Framebuffer9.h index fe12079ae0..d2b46435ee 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Framebuffer9.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Framebuffer9.h @@ -18,26 +18,40 @@ class Renderer9; class Framebuffer9 : public FramebufferD3D { public: - Framebuffer9(const gl::Framebuffer::Data &data, Renderer9 *renderer); - virtual ~Framebuffer9(); + Framebuffer9(const gl::FramebufferState &data, Renderer9 *renderer); + ~Framebuffer9() override; - gl::Error discard(size_t count, const GLenum *attachments) 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 discard(const gl::Context *context, size_t count, const GLenum *attachments) override; + gl::Error invalidate(const gl::Context *context, + size_t count, + const GLenum *attachments) override; + gl::Error invalidateSub(const gl::Context *context, + size_t count, + const GLenum *attachments, + const gl::Rectangle &area) override; + + gl::Error getSamplePosition(size_t index, GLfloat *xy) const override; private: - gl::Error clear(const gl::Data &data, const ClearParameters &clearParams) override; + gl::Error clearImpl(const gl::Context *context, const ClearParameters &clearParams) override; - gl::Error readPixelsImpl(const gl::Rectangle &area, + gl::Error readPixelsImpl(const gl::Context *context, + 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; + uint8_t *pixels) override; + + gl::Error blitImpl(const gl::Context *context, + 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; diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Image9.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Image9.cpp index fec7e3e19d..179629b362 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Image9.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Image9.cpp @@ -24,8 +24,8 @@ namespace rx Image9::Image9(Renderer9 *renderer) { - mSurface = NULL; - mRenderer = NULL; + mSurface = nullptr; + mRenderer = nullptr; mD3DPool = D3DPOOL_SYSTEMMEM; mD3DFormat = D3DFMT_UNKNOWN; @@ -45,7 +45,9 @@ gl::Error Image9::generateMip(IDirect3DSurface9 *destSurface, IDirect3DSurface9 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); + return gl::OutOfMemory() + << "Failed to query the source surface description for mipmap generation, " + << gl::FmtHR(result); } D3DSURFACE_DESC sourceDesc; @@ -53,7 +55,9 @@ gl::Error Image9::generateMip(IDirect3DSurface9 *destSurface, IDirect3DSurface9 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); + return gl::OutOfMemory() + << "Failed to query the destination surface description for mipmap generation, " + << gl::FmtHR(result); } ASSERT(sourceDesc.Format == destDesc.Format); @@ -61,23 +65,25 @@ gl::Error Image9::generateMip(IDirect3DSurface9 *destSurface, IDirect3DSurface9 ASSERT(sourceDesc.Height == 1 || sourceDesc.Height / 2 == destDesc.Height); const d3d9::D3DFormat &d3dFormatInfo = d3d9::GetD3DFormatInfo(sourceDesc.Format); - ASSERT(d3dFormatInfo.mipGenerationFunction != NULL); + ASSERT(d3dFormatInfo.info().mipGenerationFunction != nullptr); D3DLOCKED_RECT sourceLocked = {0}; - result = sourceSurface->LockRect(&sourceLocked, NULL, D3DLOCK_READONLY); + result = sourceSurface->LockRect(&sourceLocked, nullptr, 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); + return gl::OutOfMemory() << "Failed to lock the source surface for mipmap generation, " + << gl::FmtHR(result); } D3DLOCKED_RECT destLocked = {0}; - result = destSurface->LockRect(&destLocked, NULL, 0); + result = destSurface->LockRect(&destLocked, nullptr, 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); + return gl::OutOfMemory() << "Failed to lock the destination surface for mipmap generation, " + << gl::FmtHR(result); } const uint8_t *sourceData = reinterpret_cast(sourceLocked.pBits); @@ -85,40 +91,29 @@ gl::Error Image9::generateMip(IDirect3DSurface9 *destSurface, IDirect3DSurface9 ASSERT(sourceData && destData); - d3dFormatInfo.mipGenerationFunction(sourceDesc.Width, sourceDesc.Height, 1, sourceData, sourceLocked.Pitch, 0, - destData, destLocked.Pitch, 0); + d3dFormatInfo.info().mipGenerationFunction(sourceDesc.Width, sourceDesc.Height, 1, sourceData, + sourceLocked.Pitch, 0, destData, destLocked.Pitch, + 0); destSurface->UnlockRect(); sourceSurface->UnlockRect(); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } gl::Error Image9::generateMipmap(Image9 *dest, Image9 *source) { - IDirect3DSurface9 *sourceSurface = NULL; - gl::Error error = source->getSurface(&sourceSurface); - if (error.isError()) - { - return error; - } + IDirect3DSurface9 *sourceSurface = nullptr; + ANGLE_TRY(source->getSurface(&sourceSurface)); - IDirect3DSurface9 *destSurface = NULL; - error = dest->getSurface(&destSurface); - if (error.isError()) - { - return error; - } + IDirect3DSurface9 *destSurface = nullptr; + ANGLE_TRY(dest->getSurface(&destSurface)); - error = generateMip(destSurface, sourceSurface); - if (error.isError()) - { - return error; - } + ANGLE_TRY(generateMip(destSurface, sourceSurface)); dest->markDirty(); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } gl::Error Image9::copyLockableSurfaces(IDirect3DSurface9 *dest, IDirect3DSurface9 *source) @@ -128,17 +123,17 @@ gl::Error Image9::copyLockableSurfaces(IDirect3DSurface9 *dest, IDirect3DSurface HRESULT result; - result = source->LockRect(&sourceLock, NULL, 0); + result = source->LockRect(&sourceLock, nullptr, 0); if (FAILED(result)) { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock source surface for copy, result: 0x%X.", result); + return gl::OutOfMemory() << "Failed to lock source surface for copy, " << gl::FmtHR(result); } - result = dest->LockRect(&destLock, NULL, 0); + result = dest->LockRect(&destLock, nullptr, 0); if (FAILED(result)) { source->UnlockRect(); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock source surface for copy, result: 0x%X.", result); + return gl::OutOfMemory() << "Failed to lock source surface for copy, " << gl::FmtHR(result); } ASSERT(sourceLock.pBits && destLock.pBits); @@ -161,7 +156,85 @@ gl::Error Image9::copyLockableSurfaces(IDirect3DSurface9 *dest, IDirect3DSurface source->UnlockRect(); dest->UnlockRect(); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); +} + +// static +gl::Error Image9::CopyImage(const gl::Context *context, + Image9 *dest, + Image9 *source, + const gl::Rectangle &sourceRect, + const gl::Offset &destOffset, + bool unpackFlipY, + bool unpackPremultiplyAlpha, + bool unpackUnmultiplyAlpha) +{ + IDirect3DSurface9 *sourceSurface = nullptr; + ANGLE_TRY(source->getSurface(&sourceSurface)); + + IDirect3DSurface9 *destSurface = nullptr; + ANGLE_TRY(dest->getSurface(&destSurface)); + + D3DSURFACE_DESC destDesc; + HRESULT result = destSurface->GetDesc(&destDesc); + ASSERT(SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::OutOfMemory() + << "Failed to query the source surface description for mipmap generation, " + << gl::FmtHR(result); + } + const d3d9::D3DFormat &destD3DFormatInfo = d3d9::GetD3DFormatInfo(destDesc.Format); + + D3DSURFACE_DESC sourceDesc; + result = sourceSurface->GetDesc(&sourceDesc); + ASSERT(SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::OutOfMemory() + << "Failed to query the destination surface description for mipmap generation, " + << gl::FmtHR(result); + } + const d3d9::D3DFormat &sourceD3DFormatInfo = d3d9::GetD3DFormatInfo(sourceDesc.Format); + + D3DLOCKED_RECT sourceLocked = {0}; + result = sourceSurface->LockRect(&sourceLocked, nullptr, D3DLOCK_READONLY); + ASSERT(SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::OutOfMemory() << "Failed to lock the source surface for CopyImage, " + << gl::FmtHR(result); + } + + D3DLOCKED_RECT destLocked = {0}; + result = destSurface->LockRect(&destLocked, nullptr, 0); + ASSERT(SUCCEEDED(result)); + if (FAILED(result)) + { + sourceSurface->UnlockRect(); + return gl::OutOfMemory() << "Failed to lock the destination surface for CopyImage, " + << gl::FmtHR(result); + } + + const uint8_t *sourceData = reinterpret_cast(sourceLocked.pBits) + + sourceRect.x * sourceD3DFormatInfo.pixelBytes + + sourceRect.y * sourceLocked.Pitch; + uint8_t *destData = reinterpret_cast(destLocked.pBits) + + destOffset.x * destD3DFormatInfo.pixelBytes + + destOffset.y * destLocked.Pitch; + ASSERT(sourceData && destData); + + CopyImageCHROMIUM(sourceData, sourceLocked.Pitch, sourceD3DFormatInfo.pixelBytes, + sourceD3DFormatInfo.info().colorReadFunction, destData, destLocked.Pitch, + destD3DFormatInfo.pixelBytes, destD3DFormatInfo.info().colorWriteFunction, + gl::GetUnsizedFormat(dest->getInternalFormat()), + destD3DFormatInfo.info().componentType, sourceRect.width, sourceRect.height, + unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha); + + destSurface->UnlockRect(); + sourceSurface->UnlockRect(); + + return gl::NoError(); } bool Image9::redefine(GLenum target, GLenum internalformat, const gl::Extents &size, bool forceRelease) @@ -189,7 +262,7 @@ bool Image9::redefine(GLenum target, GLenum internalformat, const gl::Extents &s mRenderable = (d3d9FormatInfo.renderFormat != D3DFMT_UNKNOWN); SafeRelease(mSurface); - mDirty = (d3d9FormatInfo.dataInitializerFunction != NULL); + mDirty = (d3d9FormatInfo.dataInitializerFunction != nullptr); return true; } @@ -201,11 +274,11 @@ gl::Error Image9::createSurface() { if (mSurface) { - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } - IDirect3DTexture9 *newTexture = NULL; - IDirect3DSurface9 *newSurface = NULL; + IDirect3DTexture9 *newTexture = nullptr; + IDirect3DSurface9 *newSurface = nullptr; const D3DPOOL poolToUse = D3DPOOL_SYSTEMMEM; const D3DFORMAT d3dFormat = getD3DFormat(); @@ -218,20 +291,20 @@ gl::Error Image9::createSurface() IDirect3DDevice9 *device = mRenderer->getDevice(); - HRESULT result = device->CreateTexture(requestWidth, requestHeight, levelToFetch + 1, 0, d3dFormat, - poolToUse, &newTexture, NULL); + HRESULT result = device->CreateTexture(requestWidth, requestHeight, levelToFetch + 1, 0, + d3dFormat, poolToUse, &newTexture, nullptr); 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); + return gl::OutOfMemory() << "Failed to create image surface, " << gl::FmtHR(result); } newTexture->GetSurfaceLevel(levelToFetch, &newSurface); SafeRelease(newTexture); const d3d9::TextureFormat &d3dFormatInfo = d3d9::GetTextureFormatInfo(mInternalFormat); - if (d3dFormatInfo.dataInitializerFunction != NULL) + if (d3dFormatInfo.dataInitializerFunction != nullptr) { RECT entireRect; entireRect.left = 0; @@ -244,7 +317,7 @@ gl::Error Image9::createSurface() ASSERT(SUCCEEDED(result)); if (FAILED(result)) { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock image surface, result: 0x%X.", result); + return gl::OutOfMemory() << "Failed to lock image surface, " << gl::FmtHR(result); } d3dFormatInfo.dataInitializerFunction(mWidth, mHeight, 1, reinterpret_cast(lockedRect.pBits), @@ -254,7 +327,7 @@ gl::Error Image9::createSurface() ASSERT(SUCCEEDED(result)); if (FAILED(result)) { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to unlock image surface, result: 0x%X.", result); + return gl::OutOfMemory() << "Failed to unlock image surface, " << gl::FmtHR(result); } } } @@ -263,7 +336,7 @@ gl::Error Image9::createSurface() mDirty = false; mD3DPool = poolToUse; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } gl::Error Image9::lock(D3DLOCKED_RECT *lockedRect, const RECT &rect) @@ -280,13 +353,13 @@ gl::Error Image9::lock(D3DLOCKED_RECT *lockedRect, const RECT &rect) ASSERT(SUCCEEDED(result)); if (FAILED(result)) { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock image surface, result: 0x%X.", result); + return gl::OutOfMemory() << "Failed to lock image surface, " << gl::FmtHR(result); } mDirty = true; } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } void Image9::unlock() @@ -294,7 +367,6 @@ void Image9::unlock() if (mSurface) { HRESULT result = mSurface->UnlockRect(); - UNUSED_ASSERTION_VARIABLE(result); ASSERT(SUCCEEDED(result)); } } @@ -312,7 +384,9 @@ 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; + return (mSurface || + d3d9::GetTextureFormatInfo(mInternalFormat).dataInitializerFunction != nullptr) && + mDirty; } gl::Error Image9::getSurface(IDirect3DSurface9 **outSurface) @@ -324,14 +398,16 @@ gl::Error Image9::getSurface(IDirect3DSurface9 **outSurface) } *outSurface = mSurface; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error Image9::setManagedSurface2D(TextureStorage *storage, int level) +gl::Error Image9::setManagedSurface2D(const gl::Context *context, + TextureStorage *storage, + int level) { - IDirect3DSurface9 *surface = NULL; + IDirect3DSurface9 *surface = nullptr; TextureStorage9 *storage9 = GetAs(storage); - gl::Error error = storage9->getSurfaceLevel(GL_TEXTURE_2D, level, false, &surface); + gl::Error error = storage9->getSurfaceLevel(context, GL_TEXTURE_2D, level, false, &surface); if (error.isError()) { return error; @@ -339,12 +415,15 @@ gl::Error Image9::setManagedSurface2D(TextureStorage *storage, int level) return setManagedSurface(surface); } -gl::Error Image9::setManagedSurfaceCube(TextureStorage *storage, int face, int level) +gl::Error Image9::setManagedSurfaceCube(const gl::Context *context, + TextureStorage *storage, + int face, + int level) { - IDirect3DSurface9 *surface = NULL; + IDirect3DSurface9 *surface = nullptr; TextureStorage9 *storage9 = GetAs(storage); - gl::Error error = - storage9->getSurfaceLevel(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level, false, &surface); + gl::Error error = storage9->getSurfaceLevel(context, GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, + level, false, &surface); if (error.isError()) { return error; @@ -374,10 +453,13 @@ gl::Error Image9::setManagedSurface(IDirect3DSurface9 *surface) mD3DPool = desc.Pool; } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error Image9::copyToStorage(TextureStorage *storage, const gl::ImageIndex &index, const gl::Box ®ion) +gl::Error Image9::copyToStorage(const gl::Context *context, + TextureStorage *storage, + const gl::ImageIndex &index, + const gl::Box ®ion) { gl::Error error = createSurface(); if (error.isError()) @@ -387,11 +469,12 @@ gl::Error Image9::copyToStorage(TextureStorage *storage, const gl::ImageIndex &i TextureStorage9 *storage9 = GetAs(storage); - IDirect3DSurface9 *destSurface = NULL; + IDirect3DSurface9 *destSurface = nullptr; if (index.type == GL_TEXTURE_2D) { - error = storage9->getSurfaceLevel(GL_TEXTURE_2D, index.mipIndex, true, &destSurface); + error = + storage9->getSurfaceLevel(context, GL_TEXTURE_2D, index.mipIndex, true, &destSurface); if (error.isError()) { return error; @@ -400,7 +483,7 @@ gl::Error Image9::copyToStorage(TextureStorage *storage, const gl::ImageIndex &i else { ASSERT(gl::IsCubeMapTextureTarget(index.type)); - error = storage9->getSurfaceLevel(index.type, index.mipIndex, true, &destSurface); + error = storage9->getSurfaceLevel(context, index.type, index.mipIndex, true, &destSurface); if (error.isError()) { return error; @@ -417,7 +500,7 @@ gl::Error Image9::copyToSurface(IDirect3DSurface9 *destSurface, const gl::Box &a ASSERT(area.width > 0 && area.height > 0 && area.depth == 1); ASSERT(destSurface); - IDirect3DSurface9 *sourceSurface = NULL; + IDirect3DSurface9 *sourceSurface = nullptr; gl::Error error = getSurface(&sourceSurface); if (error.isError()) { @@ -442,19 +525,22 @@ gl::Error Image9::copyToSurface(IDirect3DSurface9 *destSurface, const gl::Box &a sourceSurface->GetDesc(&desc); IDirect3DSurface9 *surf = 0; - HRESULT result = device->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format, D3DPOOL_SYSTEMMEM, &surf, NULL); + HRESULT result = device->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format, + D3DPOOL_SYSTEMMEM, &surf, nullptr); if (FAILED(result)) { - return gl::Error(GL_OUT_OF_MEMORY, "Internal CreateOffscreenPlainSurface call failed, result: 0x%X.", result); + return gl::OutOfMemory() + << "Internal CreateOffscreenPlainSurface call failed, " << gl::FmtHR(result); } - copyLockableSurfaces(surf, sourceSurface); + auto err = copyLockableSurfaces(surf, sourceSurface); result = device->UpdateSurface(surf, &rect, destSurface, &point); SafeRelease(surf); + ANGLE_TRY(err); ASSERT(SUCCEEDED(result)); if (FAILED(result)) { - return gl::Error(GL_OUT_OF_MEMORY, "Internal UpdateSurface call failed, result: 0x%X.", result); + return gl::OutOfMemory() << "Internal UpdateSurface call failed, " << gl::FmtHR(result); } } else @@ -464,27 +550,36 @@ gl::Error Image9::copyToSurface(IDirect3DSurface9 *destSurface, const gl::Box &a ASSERT(SUCCEEDED(result)); if (FAILED(result)) { - return gl::Error(GL_OUT_OF_MEMORY, "Internal UpdateSurface call failed, result: 0x%X.", result); + return gl::OutOfMemory() << "Internal UpdateSurface call failed, " << gl::FmtHR(result); } } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } // 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) +gl::Error Image9::loadData(const gl::Context *context, + const gl::Box &area, + const gl::PixelUnpackState &unpack, + GLenum type, + const void *input, + bool applySkipImages) { // 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); - GLsizei inputSkipBytes = formatInfo.computeSkipPixels(inputRowPitch, 0, unpack.skipImages, - unpack.skipRows, unpack.skipPixels); + const gl::InternalFormat &formatInfo = gl::GetSizedInternalFormatInfo(mInternalFormat); + GLuint inputRowPitch = 0; + ANGLE_TRY_RESULT( + formatInfo.computeRowPitch(type, area.width, unpack.alignment, unpack.rowLength), + inputRowPitch); + ASSERT(!applySkipImages); + ASSERT(unpack.skipPixels == 0); + ASSERT(unpack.skipRows == 0); const d3d9::TextureFormat &d3dFormatInfo = d3d9::GetTextureFormatInfo(mInternalFormat); - ASSERT(d3dFormatInfo.loadFunction != NULL); + ASSERT(d3dFormatInfo.loadFunction != nullptr); RECT lockRect = { @@ -500,31 +595,34 @@ gl::Error Image9::loadData(const gl::Box &area, const gl::PixelUnpackState &unpa } d3dFormatInfo.loadFunction(area.width, area.height, area.depth, - reinterpret_cast(input) + inputSkipBytes, - inputRowPitch, 0, reinterpret_cast(locked.pBits), - locked.Pitch, 0); + reinterpret_cast(input), inputRowPitch, 0, + reinterpret_cast(locked.pBits), locked.Pitch, 0); unlock(); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error Image9::loadCompressedData(const gl::Box &area, const void *input) +gl::Error Image9::loadCompressedData(const gl::Context *context, + 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, 0); + const gl::InternalFormat &formatInfo = gl::GetSizedInternalFormatInfo(mInternalFormat); + GLsizei inputRowPitch = 0; + ANGLE_TRY_RESULT(formatInfo.computeRowPitch(GL_UNSIGNED_BYTE, area.width, 1, 0), inputRowPitch); + GLsizei inputDepthPitch = 0; + ANGLE_TRY_RESULT(formatInfo.computeDepthPitch(area.height, 0, inputDepthPitch), + inputDepthPitch); 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); + ASSERT(d3d9FormatInfo.loadFunction != nullptr); RECT lockRect = { @@ -545,7 +643,7 @@ gl::Error Image9::loadCompressedData(const gl::Box &area, const void *input) unlock(); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } // This implements glCopyTex[Sub]Image2D for non-renderable internal texture formats and incomplete textures @@ -565,16 +663,19 @@ gl::Error Image9::copyFromRTInternal(const gl::Offset &destOffset, IDirect3DDevice9 *device = mRenderer->getDevice(); - IDirect3DSurface9 *renderTargetData = NULL; + IDirect3DSurface9 *renderTargetData = nullptr; D3DSURFACE_DESC description; surface->GetDesc(&description); - HRESULT result = device->CreateOffscreenPlainSurface(description.Width, description.Height, description.Format, D3DPOOL_SYSTEMMEM, &renderTargetData, NULL); + HRESULT result = device->CreateOffscreenPlainSurface(description.Width, description.Height, + description.Format, D3DPOOL_SYSTEMMEM, + &renderTargetData, nullptr); if (FAILED(result)) { SafeRelease(surface); - return gl::Error(GL_OUT_OF_MEMORY, "Could not create matching destination surface, result: 0x%X.", result); + return gl::OutOfMemory() << "Could not create matching destination surface, " + << gl::FmtHR(result); } result = device->GetRenderTargetData(surface, renderTargetData); @@ -583,7 +684,8 @@ gl::Error Image9::copyFromRTInternal(const gl::Offset &destOffset, { SafeRelease(renderTargetData); SafeRelease(surface); - return gl::Error(GL_OUT_OF_MEMORY, "GetRenderTargetData unexpectedly failed, result: 0x%X.", result); + return gl::OutOfMemory() << "GetRenderTargetData unexpectedly failed, " + << gl::FmtHR(result); } int width = sourceArea.width; @@ -599,7 +701,9 @@ gl::Error Image9::copyFromRTInternal(const gl::Offset &destOffset, { 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); + return gl::OutOfMemory() + << "Failed to lock the source surface (rectangle might be invalid), " + << gl::FmtHR(result); } D3DLOCKED_RECT destLock = {0}; @@ -776,13 +880,15 @@ gl::Error Image9::copyFromRTInternal(const gl::Offset &destOffset, SafeRelease(surface); mDirty = true; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error Image9::copyFromTexStorage(const gl::ImageIndex &imageIndex, TextureStorage *source) +gl::Error Image9::copyFromTexStorage(const gl::Context *context, + const gl::ImageIndex &imageIndex, + TextureStorage *source) { RenderTargetD3D *renderTarget = nullptr; - gl::Error error = source->getRenderTarget(imageIndex, &renderTarget); + gl::Error error = source->getRenderTarget(context, imageIndex, &renderTarget); if (error.isError()) { return error; @@ -792,15 +898,16 @@ gl::Error Image9::copyFromTexStorage(const gl::ImageIndex &imageIndex, TextureSt return copyFromRTInternal(gl::Offset(), sourceArea, renderTarget); } -gl::Error Image9::copyFromFramebuffer(const gl::Offset &destOffset, +gl::Error Image9::copyFromFramebuffer(const gl::Context *context, + const gl::Offset &destOffset, const gl::Rectangle &sourceArea, const gl::Framebuffer *source) { const gl::FramebufferAttachment *srcAttachment = source->getReadColorbuffer(); ASSERT(srcAttachment); - RenderTargetD3D *renderTarget = NULL; - gl::Error error = srcAttachment->getRenderTarget(&renderTarget); + RenderTargetD3D *renderTarget = nullptr; + gl::Error error = srcAttachment->getRenderTarget(context, &renderTarget); if (error.isError()) { return error; diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Image9.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Image9.h index 91448cc849..01c60dc4fb 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Image9.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Image9.h @@ -26,27 +26,53 @@ class Image9 : public ImageD3D { public: Image9(Renderer9 *renderer); - ~Image9(); + ~Image9() override; static gl::Error generateMipmap(Image9 *dest, Image9 *source); static gl::Error generateMip(IDirect3DSurface9 *destSurface, IDirect3DSurface9 *sourceSurface); static gl::Error copyLockableSurfaces(IDirect3DSurface9 *dest, IDirect3DSurface9 *source); + static gl::Error CopyImage(const gl::Context *context, + Image9 *dest, + Image9 *source, + const gl::Rectangle &sourceRect, + const gl::Offset &destOffset, + bool unpackFlipY, + bool unpackPremultiplyAlpha, + bool unpackUnmultiplyAlpha); 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); - - gl::Error copyFromTexStorage(const gl::ImageIndex &imageIndex, TextureStorage *source) override; - gl::Error copyFromFramebuffer(const gl::Offset &destOffset, + bool isDirty() const override; + + gl::Error setManagedSurface2D(const gl::Context *context, + TextureStorage *storage, + int level) override; + gl::Error setManagedSurfaceCube(const gl::Context *context, + TextureStorage *storage, + int face, + int level) override; + gl::Error copyToStorage(const gl::Context *context, + TextureStorage *storage, + const gl::ImageIndex &index, + const gl::Box ®ion) override; + + gl::Error loadData(const gl::Context *context, + const gl::Box &area, + const gl::PixelUnpackState &unpack, + GLenum type, + const void *input, + bool applySkipImages) override; + gl::Error loadCompressedData(const gl::Context *context, + const gl::Box &area, + const void *input) override; + + gl::Error copyFromTexStorage(const gl::Context *context, + const gl::ImageIndex &imageIndex, + TextureStorage *source) override; + gl::Error copyFromFramebuffer(const gl::Context *context, + const gl::Offset &destOffset, const gl::Rectangle &sourceArea, const gl::Framebuffer *source) override; diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/IndexBuffer9.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/IndexBuffer9.cpp index 97c7f72136..df86331766 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/IndexBuffer9.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/IndexBuffer9.cpp @@ -14,7 +14,7 @@ namespace rx IndexBuffer9::IndexBuffer9(Renderer9 *const renderer) : mRenderer(renderer) { - mIndexBuffer = NULL; + mIndexBuffer = nullptr; mBufferSize = 0; mIndexType = 0; mDynamic = false; @@ -40,7 +40,7 @@ gl::Error IndexBuffer9::initialize(unsigned int bufferSize, GLenum indexType, bo } else if (indexType == GL_UNSIGNED_INT) { - ASSERT(mRenderer->getRendererExtensions().elementIndexUint); + ASSERT(mRenderer->getNativeExtensions().elementIndexUint); format = D3DFMT_INDEX32; } else UNREACHABLE(); @@ -54,7 +54,8 @@ gl::Error IndexBuffer9::initialize(unsigned int bufferSize, GLenum indexType, bo 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); + return gl::OutOfMemory() + << "Failed to allocate internal index buffer of size " << bufferSize; } } @@ -62,43 +63,43 @@ gl::Error IndexBuffer9::initialize(unsigned int bufferSize, GLenum indexType, bo mIndexType = indexType; mDynamic = dynamic; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } 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."); + return gl::OutOfMemory() << "Internal index buffer is not initialized."; } DWORD lockFlags = mDynamic ? D3DLOCK_NOOVERWRITE : 0; - void *mapPtr = NULL; + void *mapPtr = nullptr; 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); + return gl::OutOfMemory() << "Failed to lock internal index buffer, " << gl::FmtHR(result); } *outMappedMemory = mapPtr; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } gl::Error IndexBuffer9::unmapBuffer() { if (!mIndexBuffer) { - return gl::Error(GL_OUT_OF_MEMORY, "Internal index buffer is not initialized."); + return gl::OutOfMemory() << "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::OutOfMemory() << "Failed to unlock internal index buffer, " << gl::FmtHR(result); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } GLenum IndexBuffer9::getIndexType() const @@ -119,7 +120,7 @@ gl::Error IndexBuffer9::setSize(unsigned int bufferSize, GLenum indexType) } else { - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } } @@ -127,7 +128,7 @@ gl::Error IndexBuffer9::discard() { if (!mIndexBuffer) { - return gl::Error(GL_OUT_OF_MEMORY, "Internal index buffer is not initialized."); + return gl::OutOfMemory() << "Internal index buffer is not initialized."; } void *dummy; @@ -136,16 +137,16 @@ gl::Error IndexBuffer9::discard() 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); + return gl::OutOfMemory() << "Failed to lock internal index buffer, " << gl::FmtHR(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::OutOfMemory() << "Failed to unlock internal index buffer, " << gl::FmtHR(result); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } D3DFORMAT IndexBuffer9::getIndexFormat() const diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/IndexBuffer9.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/IndexBuffer9.h index ba03ba703f..5921d2a859 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/IndexBuffer9.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/IndexBuffer9.h @@ -19,18 +19,18 @@ class IndexBuffer9 : public IndexBuffer { public: explicit IndexBuffer9(Renderer9 *const renderer); - virtual ~IndexBuffer9(); + ~IndexBuffer9() override; - virtual gl::Error initialize(unsigned int bufferSize, GLenum indexType, bool dynamic); + gl::Error initialize(unsigned int bufferSize, GLenum indexType, bool dynamic) override; - virtual gl::Error mapBuffer(unsigned int offset, unsigned int size, void** outMappedMemory); - virtual gl::Error unmapBuffer(); + gl::Error mapBuffer(unsigned int offset, unsigned int size, void **outMappedMemory) override; + gl::Error unmapBuffer() override; - virtual GLenum getIndexType() const; - virtual unsigned int getBufferSize() const; - virtual gl::Error setSize(unsigned int bufferSize, GLenum indexType); + GLenum getIndexType() const override; + unsigned int getBufferSize() const override; + gl::Error setSize(unsigned int bufferSize, GLenum indexType) override; - virtual gl::Error discard(); + gl::Error discard() override; D3DFORMAT getIndexFormat() const; IDirect3DIndexBuffer9 *getBuffer() const; diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/NativeWindow9.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/NativeWindow9.cpp new file mode 100644 index 0000000000..388b8aa168 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/NativeWindow9.cpp @@ -0,0 +1,39 @@ +// +// Copyright (c) 2016 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. +// + +// NativeWindow9.cpp: Defines NativeWindow9, a class for managing and +// performing operations on an EGLNativeWindowType for the D3D9 renderer. + +#include "libANGLE/renderer/d3d/d3d9/NativeWindow9.h" + +namespace rx +{ +NativeWindow9::NativeWindow9(EGLNativeWindowType window) : NativeWindowD3D(window) +{ +} + +bool NativeWindow9::initialize() +{ + return true; +} + +bool NativeWindow9::getClientRect(LPRECT rect) const +{ + return GetClientRect(getNativeWindow(), rect) == TRUE; +} + +bool NativeWindow9::isIconic() const +{ + return IsIconic(getNativeWindow()) == TRUE; +} + +// static +bool NativeWindow9::IsValidNativeWindow(EGLNativeWindowType window) +{ + return IsWindow(window) == TRUE; +} + +} // namespace rx diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/NativeWindow9.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/NativeWindow9.h new file mode 100644 index 0000000000..a56b08dc81 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/NativeWindow9.h @@ -0,0 +1,35 @@ +// +// Copyright (c) 2016 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. +// + +// NativeWindow9.h: Defines NativeWindow9, a class for managing and +// performing operations on an EGLNativeWindowType for the D3D9 renderer. + +#ifndef LIBANGLE_RENDERER_D3D_D3D9_NATIVEWINDOW9_H_ +#define LIBANGLE_RENDERER_D3D_D3D9_NATIVEWINDOW9_H_ + +#include "common/debug.h" +#include "common/platform.h" + +#include "libANGLE/renderer/d3d/NativeWindowD3D.h" + +namespace rx +{ + +class NativeWindow9 : public NativeWindowD3D +{ + public: + explicit NativeWindow9(EGLNativeWindowType window); + + bool initialize() override; + bool getClientRect(LPRECT rect) const override; + bool isIconic() const override; + + static bool IsValidNativeWindow(EGLNativeWindowType window); +}; + +} // namespace rx + +#endif // LIBANGLE_RENDERER_D3D_D3D9_NATIVEWINDOW9_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 index c826abf81c..4ba053e6bd 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Query9.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Query9.cpp @@ -19,7 +19,7 @@ Query9::Query9(Renderer9 *renderer, GLenum type) mResult(GL_FALSE), mQueryFinished(false), mRenderer(renderer), - mQuery(NULL) + mQuery(nullptr) { } @@ -30,23 +30,27 @@ Query9::~Query9() gl::Error Query9::begin() { - if (mQuery == NULL) + D3DQUERYTYPE d3dQueryType = gl_d3d9::ConvertQueryType(getType()); + if (mQuery == nullptr) { - HRESULT result = mRenderer->getDevice()->CreateQuery(D3DQUERYTYPE_OCCLUSION, &mQuery); + HRESULT result = mRenderer->getDevice()->CreateQuery(d3dQueryType, &mQuery); if (FAILED(result)) { - return gl::Error(GL_OUT_OF_MEMORY, "Internal query creation failed, result: 0x%X.", result); + return gl::OutOfMemory() << "Internal query creation failed, " << gl::FmtHR(result); } } - HRESULT result = mQuery->Issue(D3DISSUE_BEGIN); - ASSERT(SUCCEEDED(result)); - if (FAILED(result)) + if (d3dQueryType != D3DQUERYTYPE_EVENT) { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to begin internal query, result: 0x%X.", result); + HRESULT result = mQuery->Issue(D3DISSUE_BEGIN); + ASSERT(SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::OutOfMemory() << "Failed to begin internal query, " << gl::FmtHR(result); + } } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } gl::Error Query9::end() @@ -57,19 +61,19 @@ gl::Error Query9::end() ASSERT(SUCCEEDED(result)); if (FAILED(result)) { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to end internal query, result: 0x%X.", result); + return gl::OutOfMemory() << "Failed to end internal query, " << gl::FmtHR(result); } mQueryFinished = false; mResult = GL_FALSE; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } gl::Error Query9::queryCounter() { UNIMPLEMENTED(); - return gl::Error(GL_INVALID_OPERATION, "Unimplemented"); + return gl::InternalError() << "Unimplemented"; } template @@ -91,7 +95,7 @@ gl::Error Query9::getResultBase(T *params) ASSERT(mQueryFinished); *params = static_cast(mResult); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } gl::Error Query9::getResult(GLint *params) @@ -124,7 +128,7 @@ gl::Error Query9::isResultAvailable(bool *available) *available = mQueryFinished; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } gl::Error Query9::testQuery() @@ -133,38 +137,52 @@ gl::Error Query9::testQuery() { ASSERT(mQuery); - DWORD numPixels = 0; - - HRESULT hres = mQuery->GetData(&numPixels, sizeof(DWORD), D3DGETDATA_FLUSH); - if (hres == S_OK) + HRESULT result = S_OK; + switch (getType()) { - mQueryFinished = true; + case GL_ANY_SAMPLES_PASSED_EXT: + case GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT: + { + DWORD numPixels = 0; + result = mQuery->GetData(&numPixels, sizeof(numPixels), D3DGETDATA_FLUSH); + if (result == S_OK) + { + mQueryFinished = true; + mResult = (numPixels > 0) ? GL_TRUE : GL_FALSE; + } + break; + } - switch (getType()) + case GL_COMMANDS_COMPLETED_CHROMIUM: { - case GL_ANY_SAMPLES_PASSED_EXT: - case GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT: - mResult = (numPixels > 0) ? GL_TRUE : GL_FALSE; + BOOL completed = FALSE; + result = mQuery->GetData(&completed, sizeof(completed), D3DGETDATA_FLUSH); + if (result == S_OK) + { + mQueryFinished = true; + mResult = (completed == TRUE) ? GL_TRUE : GL_FALSE; + } break; + } - default: + default: UNREACHABLE(); break; - } } - else if (d3d9::isDeviceLostError(hres)) + + if (d3d9::isDeviceLostError(result)) { mRenderer->notifyDeviceLost(); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to test get query result, device is lost."); + return gl::OutOfMemory() << "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::OutOfMemory() << "Failed to test get query result, device is lost."; } } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } } diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Query9.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Query9.h index 9d17711a00..6c7c22f096 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Query9.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Query9.h @@ -19,16 +19,16 @@ class Query9 : public QueryImpl { public: Query9(Renderer9 *renderer, GLenum type); - virtual ~Query9(); - - virtual gl::Error begin(); - virtual gl::Error end(); - virtual gl::Error queryCounter(); - virtual gl::Error getResult(GLint *params); - virtual gl::Error getResult(GLuint *params); - virtual gl::Error getResult(GLint64 *params); - virtual gl::Error getResult(GLuint64 *params); - virtual gl::Error isResultAvailable(bool *available); + ~Query9() override; + + gl::Error begin() override; + gl::Error end() override; + gl::Error queryCounter() override; + gl::Error getResult(GLint *params) override; + gl::Error getResult(GLuint *params) override; + gl::Error getResult(GLint64 *params) override; + gl::Error getResult(GLuint64 *params) override; + gl::Error isResultAvailable(bool *available) override; private: gl::Error testQuery(); diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/RenderTarget9.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/RenderTarget9.cpp index 419bff1f63..3e54c27f43 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/RenderTarget9.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/RenderTarget9.cpp @@ -130,7 +130,8 @@ GLsizei SurfaceRenderTarget9::getDepth() const GLenum SurfaceRenderTarget9::getInternalFormat() const { - return (mDepth ? mSwapChain->GetDepthBufferInternalFormat() : mSwapChain->GetRenderTargetInternalFormat()); + return (mDepth ? mSwapChain->getDepthBufferInternalFormat() + : mSwapChain->getRenderTargetInternalFormat()); } GLsizei SurfaceRenderTarget9::getSamples() const diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/RenderTarget9.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/RenderTarget9.h index f19c54de7b..bb3b5a4ee4 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/RenderTarget9.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/RenderTarget9.h @@ -21,7 +21,7 @@ class RenderTarget9 : public RenderTargetD3D { public: RenderTarget9() { } - virtual ~RenderTarget9() { } + ~RenderTarget9() override {} // Retrieve the texture that backs this render target, may be null for swap chain render // targets. virtual IDirect3DBaseTexture9 *getTexture() const = 0; @@ -43,7 +43,7 @@ class TextureRenderTarget9 : public RenderTarget9 GLsizei height, GLsizei depth, GLsizei samples); - virtual ~TextureRenderTarget9(); + ~TextureRenderTarget9() override; GLsizei getWidth() const override; GLsizei getHeight() const override; @@ -74,7 +74,7 @@ class SurfaceRenderTarget9 : public RenderTarget9 { public: SurfaceRenderTarget9(SwapChain9 *swapChain, bool depth); - virtual ~SurfaceRenderTarget9(); + ~SurfaceRenderTarget9() override; GLsizei getWidth() const override; GLsizei getHeight() const override; diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Renderer9.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Renderer9.cpp index 6bb975b0e4..75c6298868 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Renderer9.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Renderer9.cpp @@ -8,51 +8,51 @@ #include "libANGLE/renderer/d3d/d3d9/Renderer9.h" -#include #include +#include #include "common/utilities.h" -#include "libANGLE/angletypes.h" #include "libANGLE/Buffer.h" +#include "libANGLE/Context.h" #include "libANGLE/Display.h" -#include "libANGLE/features.h" -#include "libANGLE/formatutils.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/DeviceD3D.h" +#include "libANGLE/renderer/d3d/FramebufferD3D.h" +#include "libANGLE/renderer/d3d/IndexDataManager.h" +#include "libANGLE/renderer/d3d/ProgramD3D.h" +#include "libANGLE/renderer/d3d/RenderbufferD3D.h" +#include "libANGLE/renderer/d3d/ShaderD3D.h" +#include "libANGLE/renderer/d3d/SurfaceD3D.h" +#include "libANGLE/renderer/d3d/TextureD3D.h" #include "libANGLE/renderer/d3d/d3d9/Blit9.h" #include "libANGLE/renderer/d3d/d3d9/Buffer9.h" +#include "libANGLE/renderer/d3d/d3d9/Context9.h" #include "libANGLE/renderer/d3d/d3d9/Fence9.h" -#include "libANGLE/renderer/d3d/d3d9/formatutils9.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/NativeWindow9.h" #include "libANGLE/renderer/d3d/d3d9/Query9.h" -#include "libANGLE/renderer/d3d/d3d9/renderer9_utils.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/CompilerD3D.h" -#include "libANGLE/renderer/d3d/DeviceD3D.h" -#include "libANGLE/renderer/d3d/FramebufferD3D.h" -#include "libANGLE/renderer/d3d/IndexDataManager.h" -#include "libANGLE/renderer/d3d/ProgramD3D.h" -#include "libANGLE/renderer/d3d/RenderbufferD3D.h" -#include "libANGLE/renderer/d3d/ShaderD3D.h" -#include "libANGLE/renderer/d3d/SurfaceD3D.h" -#include "libANGLE/renderer/d3d/TextureD3D.h" -#include "libANGLE/renderer/d3d/TransformFeedbackD3D.h" -#include "libANGLE/State.h" -#include "libANGLE/Surface.h" -#include "libANGLE/Texture.h" +#include "libANGLE/renderer/d3d/d3d9/formatutils9.h" +#include "libANGLE/renderer/d3d/d3d9/renderer9_utils.h" #include "third_party/trace_event/trace_event.h" - - #if !defined(ANGLE_COMPILE_OPTIMIZATION_LEVEL) #define ANGLE_COMPILE_OPTIMIZATION_LEVEL D3DCOMPILE_OPTIMIZATION_LEVEL3 #endif @@ -69,69 +69,69 @@ 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_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), mStateManager(this) { - mD3d9Module = NULL; + mD3d9Module = nullptr; - mD3d9 = NULL; - mD3d9Ex = NULL; - mDevice = NULL; - mDeviceEx = NULL; - mDeviceWindow = NULL; - mBlit = NULL; + mD3d9 = nullptr; + mD3d9Ex = nullptr; + mDevice = nullptr; + mDeviceEx = nullptr; + mDeviceWindow = nullptr; + mBlit = nullptr; 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); + EGLint requestedDeviceType = static_cast(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_HARDWARE_ANGLE: + mDeviceType = D3DDEVTYPE_HAL; + break; - case EGL_PLATFORM_ANGLE_DEVICE_TYPE_REFERENCE_ANGLE: - mDeviceType = D3DDEVTYPE_REF; - 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; + case EGL_PLATFORM_ANGLE_DEVICE_TYPE_NULL_ANGLE: + mDeviceType = D3DDEVTYPE_NULLREF; + break; - default: - UNREACHABLE(); + default: + UNREACHABLE(); } - mMaskedClearSavedState = NULL; + mMaskedClearSavedState = nullptr; - mVertexDataManager = NULL; - mIndexDataManager = NULL; - mLineLoopIB = NULL; - mCountingIB = NULL; + mVertexDataManager = nullptr; + mIndexDataManager = nullptr; + mLineLoopIB = nullptr; + mCountingIB = nullptr; 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; + mNullColorbufferCache[i].width = 0; + mNullColorbufferCache[i].height = 0; + mNullColorbufferCache[i].buffer = nullptr; } - mAppliedVertexShader = NULL; - mAppliedPixelShader = NULL; + mAppliedVertexShader = nullptr; + mAppliedPixelShader = nullptr; mAppliedProgramSerial = 0; - initializeDebugAnnotator(); + gl::InitializeDebugAnnotations(&mAnnotator); mEGLDevice = nullptr; } @@ -154,6 +154,10 @@ void Renderer9::release() { RendererD3D::cleanup(); + gl::UninitializeDebugAnnotations(); + + mTranslatedAttribCache.clear(); + releaseDeviceResources(); SafeDelete(mEGLDevice); @@ -167,10 +171,10 @@ void Renderer9::release() if (mDeviceWindow) { DestroyWindow(mDeviceWindow); - mDeviceWindow = NULL; + mDeviceWindow = nullptr; } - mD3d9Module = NULL; + mD3d9Module = nullptr; } egl::Error Renderer9::initialize() @@ -178,22 +182,25 @@ egl::Error Renderer9::initialize() TRACE_EVENT0("gpu.angle", "GetModuleHandle_d3d9"); mD3d9Module = GetModuleHandle(TEXT("d3d9.dll")); - if (mD3d9Module == NULL) + if (mD3d9Module == nullptr) { - return egl::Error(EGL_NOT_INITIALIZED, D3D9_INIT_MISSING_DEP, "No D3D9 module found."); + return egl::EglNotInitialized(D3D9_INIT_MISSING_DEP) << "No D3D9 module found."; } - typedef HRESULT (WINAPI *Direct3DCreate9ExFunc)(UINT, IDirect3D9Ex**); - Direct3DCreate9ExFunc Direct3DCreate9ExPtr = reinterpret_cast(GetProcAddress(mD3d9Module, "Direct3DCreate9Ex")); + 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))) + // 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.angle", "D3d9Ex_QueryInterface"); ASSERT(mD3d9Ex); - mD3d9Ex->QueryInterface(IID_IDirect3D9, reinterpret_cast(&mD3d9)); + mD3d9Ex->QueryInterface(__uuidof(IDirect3D9), reinterpret_cast(&mD3d9)); ASSERT(mD3d9); } else @@ -204,12 +211,13 @@ egl::Error Renderer9::initialize() if (!mD3d9) { - return egl::Error(EGL_NOT_INITIALIZED, D3D9_INIT_MISSING_DEP, "Could not create D3D9 device."); + return egl::EglNotInitialized(D3D9_INIT_MISSING_DEP) << "Could not create D3D9 device."; } if (mDisplay->getNativeDisplayId() != nullptr) { - // UNIMPLEMENTED(); // FIXME: Determine which adapter index the device context corresponds to + // UNIMPLEMENTED(); // FIXME: Determine which adapter index the device context + // corresponds to } HRESULT result; @@ -226,13 +234,14 @@ egl::Error Renderer9::initialize() } else if (result == D3DERR_NOTAVAILABLE) { - Sleep(100); // Give the driver some time to initialize/recover + 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 + 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); + return egl::EglNotInitialized(D3D9_INIT_OTHER_ERROR) + << "Failed to get device caps, " << gl::FmtHR(result); } } } @@ -245,18 +254,17 @@ egl::Error Renderer9::initialize() 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); + return egl::EglNotInitialized(D3D9_INIT_UNSUPPORTED_VERSION) + << "Renderer does not support PS " << minShaderModel << ".0, aborting!"; } - // 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. + // 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."); + return egl::EglNotInitialized(D3D9_INIT_UNSUPPORTED_STRETCHRECT) + << "Renderer does not support StretctRect from textures."; } { @@ -265,43 +273,52 @@ egl::Error Renderer9::initialize() } static const TCHAR windowName[] = TEXT("AngleHiddenWindow"); - static const TCHAR className[] = TEXT("STATIC"); + static const TCHAR className[] = TEXT("STATIC"); { TRACE_EVENT0("gpu.angle", "CreateWindowEx"); - mDeviceWindow = CreateWindowEx(WS_EX_NOACTIVATE, className, windowName, WS_DISABLED | WS_POPUP, 0, 0, 1, 1, HWND_MESSAGE, NULL, GetModuleHandle(NULL), NULL); + mDeviceWindow = + CreateWindowEx(WS_EX_NOACTIVATE, className, windowName, WS_DISABLED | WS_POPUP, 0, 0, 1, + 1, HWND_MESSAGE, nullptr, GetModuleHandle(nullptr), nullptr); } D3DPRESENT_PARAMETERS presentParameters = getDefaultPresentParameters(); - DWORD behaviorFlags = D3DCREATE_FPU_PRESERVE | D3DCREATE_NOWINDOWCHANGES | D3DCREATE_MULTITHREADED; + DWORD behaviorFlags = + D3DCREATE_FPU_PRESERVE | D3DCREATE_NOWINDOWCHANGES | D3DCREATE_MULTITHREADED; { TRACE_EVENT0("gpu.angle", "D3d9_CreateDevice"); - result = mD3d9->CreateDevice(mAdapter, mDeviceType, mDeviceWindow, behaviorFlags | D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE, &presentParameters, &mDevice); + 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"); + return egl::EglBadAlloc(D3D9_INIT_OUT_OF_MEMORY) + << "CreateDevice failed: device lost of out of memory"; } if (FAILED(result)) { TRACE_EVENT0("gpu.angle", "D3d9_CreateDevice2"); - result = mD3d9->CreateDevice(mAdapter, mDeviceType, mDeviceWindow, behaviorFlags | D3DCREATE_SOFTWARE_VERTEXPROCESSING, &presentParameters, &mDevice); + 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"); + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || + result == D3DERR_NOTAVAILABLE || result == D3DERR_DEVICELOST); + return egl::EglBadAlloc(D3D9_INIT_OUT_OF_MEMORY) + << "CreateDevice2 failed: device lost, not available, or of out of memory"; } } if (mD3d9Ex) { TRACE_EVENT0("gpu.angle", "mDevice_QueryInterface"); - result = mDevice->QueryInterface(IID_IDirect3DDevice9Ex, (void**)&mDeviceEx); + result = mDevice->QueryInterface(__uuidof(IDirect3DDevice9Ex), (void **)&mDeviceEx); ASSERT(SUCCEEDED(result)); } @@ -318,18 +335,19 @@ egl::Error Renderer9::initialize() // 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)); + SUCCEEDED(mD3d9->CheckDeviceFormat( + mAdapter, mDeviceType, currentDisplayMode.Format, + D3DUSAGE_QUERY_VERTEXTEXTURE, D3DRTYPE_TEXTURE, D3DFMT_R16F)); - initializeDevice(); + ANGLE_TRY(initializeDevice()); - return egl::Error(EGL_SUCCESS); + return egl::NoError(); } // 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() +egl::Error Renderer9::initializeDevice() { // Permanent non-default states mDevice->SetRenderState(D3DRS_POINTSPRITEENABLE, TRUE); @@ -337,14 +355,14 @@ void Renderer9::initializeDevice() if (mDeviceCaps.PixelShaderVersion >= D3DPS_VERSION(3, 0)) { - mDevice->SetRenderState(D3DRS_POINTSIZE_MAX, (DWORD&)mDeviceCaps.MaxPointSize); + mDevice->SetRenderState(D3DRS_POINTSIZE_MAX, (DWORD &)mDeviceCaps.MaxPointSize); } else { - mDevice->SetRenderState(D3DRS_POINTSIZE_MAX, 0x3F800000); // 1.0f + mDevice->SetRenderState(D3DRS_POINTSIZE_MAX, 0x3F800000); // 1.0f } - const gl::Caps &rendererCaps = getRendererCaps(); + const gl::Caps &rendererCaps = getNativeCaps(); mCurVertexSamplerStates.resize(rendererCaps.maxVertexTextureImageUnits); mCurPixelSamplerStates.resize(rendererCaps.maxTextureImageUnits); @@ -358,50 +376,55 @@ void Renderer9::initializeDevice() ASSERT(!mBlit); mBlit = new Blit9(this); - mBlit->initialize(); + ANGLE_TRY(mBlit->initialize()); ASSERT(!mVertexDataManager && !mIndexDataManager); mVertexDataManager = new VertexDataManager(this); - mIndexDataManager = new IndexDataManager(this, getRendererClass()); + mIndexDataManager = new IndexDataManager(this); + + if (mVertexDataManager->initialize().isError()) + { + return egl::EglBadAlloc() << "Error initializing VertexDataManager"; + } + + mTranslatedAttribCache.resize(getNativeCaps().maxVertexAttributes); + + mStateManager.initialize(); - // TODO(jmadill): use context caps, and place in common D3D location - mTranslatedAttribCache.resize(getRendererCaps().maxVertexAttributes); + return egl::NoError(); } 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. + // 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.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; + 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 +egl::ConfigSet Renderer9::generateConfigs() { - static const GLenum colorBufferFormats[] = - { - GL_BGR5_A1_ANGLEX, - GL_BGRA8_EXT, - GL_RGB565, + static const GLenum colorBufferFormats[] = { + GL_BGR5_A1_ANGLEX, GL_BGRA8_EXT, GL_RGB565, }; - static const GLenum depthStencilBufferFormats[] = - { + static const GLenum depthStencilBufferFormats[] = { GL_NONE, GL_DEPTH_COMPONENT32_OES, GL_DEPTH24_STENCIL8_OES, @@ -409,8 +432,8 @@ egl::ConfigSet Renderer9::generateConfigs() const GL_DEPTH_COMPONENT16, }; - const gl::Caps &rendererCaps = getRendererCaps(); - const gl::TextureCapsMap &rendererTextureCaps = getRendererTextureCaps(); + const gl::Caps &rendererCaps = getNativeCaps(); + const gl::TextureCapsMap &rendererTextureCaps = getNativeTextureCaps(); D3DDISPLAYMODE currentDisplayMode; mD3d9->GetAdapterDisplayMode(mAdapter, ¤tDisplayMode); @@ -449,56 +472,72 @@ egl::ConfigSet Renderer9::generateConfigs() const for (size_t formatIndex = 0; formatIndex < ArraySize(colorBufferFormats); formatIndex++) { GLenum colorBufferInternalFormat = colorBufferFormats[formatIndex]; - const gl::TextureCaps &colorBufferFormatCaps = rendererTextureCaps.get(colorBufferInternalFormat); + const gl::TextureCaps &colorBufferFormatCaps = + rendererTextureCaps.get(colorBufferInternalFormat); if (colorBufferFormatCaps.renderable) { - for (size_t depthStencilIndex = 0; depthStencilIndex < ArraySize(depthStencilBufferFormats); depthStencilIndex++) + 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) + 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); + const gl::InternalFormat &colorBufferFormatInfo = + gl::GetSizedInternalFormatInfo(colorBufferInternalFormat); + const gl::InternalFormat &depthStencilBufferFormatInfo = + gl::GetSizedInternalFormatInfo(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.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.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.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.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.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; + config.transparentBlueValue = 0; + config.colorComponentType = gl_egl::GLComponentTypeToEGLColorComponentType( + colorBufferFormatInfo.componentType); configs.add(config); } @@ -519,13 +558,12 @@ void Renderer9::generateDisplayExtensions(egl::DisplayExtensions *outExtensions) outExtensions->d3dShareHandleClientBuffer = true; outExtensions->surfaceD3DTexture2DShareHandle = true; } + outExtensions->d3dTextureClientBuffer = true; outExtensions->querySurfacePointer = true; outExtensions->windowFixedSize = true; outExtensions->postSubBuffer = true; - outExtensions->createContext = true; outExtensions->deviceQuery = true; - outExtensions->createContextNoError = true; outExtensions->image = true; outExtensions->imageBase = true; @@ -533,6 +571,14 @@ void Renderer9::generateDisplayExtensions(egl::DisplayExtensions *outExtensions) outExtensions->glRenderbufferImage = true; outExtensions->flexibleSurfaceCompatibility = true; + + // Contexts are virtualized so textures can be shared globally + outExtensions->displayTextureShareGroup = true; + + // D3D9 can be used without an output surface + outExtensions->surfacelessContext = true; + + outExtensions->robustResourceInitialization = true; } void Renderer9::startScene() @@ -540,7 +586,8 @@ void Renderer9::startScene() if (!mSceneStarted) { long result = mDevice->BeginScene(); - if (SUCCEEDED(result)) { + if (SUCCEEDED(result)) + { // This is defensive checking against the device being // lost at unexpected times. mSceneStarted = true; @@ -561,8 +608,8 @@ void Renderer9::endScene() gl::Error Renderer9::flush() { - IDirect3DQuery9* query = NULL; - gl::Error error = allocateEventQuery(&query); + IDirect3DQuery9 *query = nullptr; + gl::Error error = allocateEventQuery(&query); if (error.isError()) { return error; @@ -572,11 +619,11 @@ gl::Error Renderer9::flush() 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); + return gl::OutOfMemory() << "Failed to issue event query, " << gl::FmtHR(result); } // Grab the query data once - result = query->GetData(NULL, 0, D3DGETDATA_FLUSH); + result = query->GetData(nullptr, 0, D3DGETDATA_FLUSH); freeEventQuery(query); if (FAILED(result)) { @@ -585,16 +632,16 @@ gl::Error Renderer9::flush() notifyDeviceLost(); } - return gl::Error(GL_OUT_OF_MEMORY, "Failed to get event query data, result: 0x%X.", result); + return gl::OutOfMemory() << "Failed to get event query data, " << gl::FmtHR(result); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } gl::Error Renderer9::finish() { - IDirect3DQuery9* query = NULL; - gl::Error error = allocateEventQuery(&query); + IDirect3DQuery9 *query = nullptr; + gl::Error error = allocateEventQuery(&query); if (error.isError()) { return error; @@ -604,11 +651,11 @@ gl::Error Renderer9::finish() 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); + return gl::OutOfMemory() << "Failed to issue event query, " << gl::FmtHR(result); } // Grab the query data once - result = query->GetData(NULL, 0, D3DGETDATA_FLUSH); + result = query->GetData(nullptr, 0, D3DGETDATA_FLUSH); if (FAILED(result)) { if (d3d9::isDeviceLostError(result)) @@ -617,7 +664,7 @@ gl::Error Renderer9::finish() } freeEventQuery(query); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to get event query data, result: 0x%X.", result); + return gl::OutOfMemory() << "Failed to get event query data, " << gl::FmtHR(result); } // Loop until the query completes @@ -626,7 +673,7 @@ gl::Error Renderer9::finish() // Keep polling, but allow other threads to do something useful first ScheduleYield(); - result = query->GetData(NULL, 0, D3DGETDATA_FLUSH); + result = query->GetData(nullptr, 0, D3DGETDATA_FLUSH); // explicitly check for device loss // some drivers seem to return S_FALSE even if the device is lost @@ -644,34 +691,146 @@ gl::Error Renderer9::finish() } freeEventQuery(query); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to get event query data, result: 0x%X.", result); + return gl::OutOfMemory() << "Failed to get event query data, " << gl::FmtHR(result); } - } freeEventQuery(query); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); +} + +bool Renderer9::isValidNativeWindow(EGLNativeWindowType window) const +{ + return NativeWindow9::IsValidNativeWindow(window); +} + +NativeWindowD3D *Renderer9::createNativeWindow(EGLNativeWindowType window, + const egl::Config *, + const egl::AttributeMap &) const +{ + return new NativeWindow9(window); } -SwapChainD3D *Renderer9::createSwapChain(NativeWindow nativeWindow, +SwapChainD3D *Renderer9::createSwapChain(NativeWindowD3D *nativeWindow, HANDLE shareHandle, + IUnknown *d3dTexture, GLenum backBufferFormat, GLenum depthBufferFormat, - EGLint orientation) + EGLint orientation, + EGLint samples) { - return new SwapChain9(this, nativeWindow, shareHandle, backBufferFormat, depthBufferFormat, - orientation); + return new SwapChain9(this, GetAs(nativeWindow), shareHandle, d3dTexture, + backBufferFormat, depthBufferFormat, orientation); } -CompilerImpl *Renderer9::createCompiler() +egl::Error Renderer9::getD3DTextureInfo(const egl::Config *config, + IUnknown *d3dTexture, + EGLint *width, + EGLint *height, + GLenum *fboFormat) const { - return new CompilerD3D(SH_HLSL_3_0_OUTPUT); + IDirect3DTexture9 *texture = nullptr; + if (FAILED(d3dTexture->QueryInterface(&texture))) + { + return egl::EglBadParameter() << "Client buffer is not a IDirect3DTexture9"; + } + + IDirect3DDevice9 *textureDevice = nullptr; + texture->GetDevice(&textureDevice); + if (textureDevice != mDevice) + { + SafeRelease(texture); + return egl::EglBadParameter() << "Texture's device does not match."; + } + SafeRelease(textureDevice); + + D3DSURFACE_DESC desc; + texture->GetLevelDesc(0, &desc); + SafeRelease(texture); + + if (width) + { + *width = static_cast(desc.Width); + } + if (height) + { + *height = static_cast(desc.Height); + } + + // From table egl.restrictions in EGL_ANGLE_d3d_texture_client_buffer. + switch (desc.Format) + { + case D3DFMT_R8G8B8: + case D3DFMT_A8R8G8B8: + case D3DFMT_A16B16G16R16F: + case D3DFMT_A32B32G32R32F: + break; + + default: + return egl::EglBadParameter() + << "Unknown client buffer texture format: " << desc.Format; + } + + if (fboFormat) + { + const auto &d3dFormatInfo = d3d9::GetD3DFormatInfo(desc.Format); + ASSERT(d3dFormatInfo.info().id != angle::Format::ID::NONE); + *fboFormat = d3dFormatInfo.info().fboImplementationInternalFormat; + } + + return egl::NoError(); +} + +egl::Error Renderer9::validateShareHandle(const egl::Config *config, + HANDLE shareHandle, + const egl::AttributeMap &attribs) const +{ + if (shareHandle == nullptr) + { + return egl::EglBadParameter() << "NULL share handle."; + } + + EGLint width = attribs.getAsInt(EGL_WIDTH, 0); + EGLint height = attribs.getAsInt(EGL_HEIGHT, 0); + ASSERT(width != 0 && height != 0); + + const d3d9::TextureFormat &backBufferd3dFormatInfo = + d3d9::GetTextureFormatInfo(config->renderTargetFormat); + + IDirect3DTexture9 *texture = nullptr; + HRESULT result = mDevice->CreateTexture(width, height, 1, D3DUSAGE_RENDERTARGET, + backBufferd3dFormatInfo.texFormat, D3DPOOL_DEFAULT, + &texture, &shareHandle); + if (FAILED(result)) + { + return egl::EglBadParameter() << "Failed to open share handle, " << gl::FmtHR(result); + } + + DWORD levelCount = texture->GetLevelCount(); + + D3DSURFACE_DESC desc; + texture->GetLevelDesc(0, &desc); + SafeRelease(texture); + + if (levelCount != 1 || desc.Width != static_cast(width) || + desc.Height != static_cast(height) || + desc.Format != backBufferd3dFormatInfo.texFormat) + { + return egl::EglBadParameter() << "Invalid texture parameters in share handle texture."; + } + + return egl::NoError(); +} + +ContextImpl *Renderer9::createContext(const gl::ContextState &state) +{ + return new Context9(state, this); } void *Renderer9::getD3DDevice() { - return reinterpret_cast(mDevice); + return reinterpret_cast(mDevice); } gl::Error Renderer9::allocateEventQuery(IDirect3DQuery9 **outQuery) @@ -682,7 +841,7 @@ gl::Error Renderer9::allocateEventQuery(IDirect3DQuery9 **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); + return gl::OutOfMemory() << "Failed to allocate event query, " << gl::FmtHR(result); } } else @@ -691,10 +850,10 @@ gl::Error Renderer9::allocateEventQuery(IDirect3DQuery9 **outQuery) mEventQueryPool.pop_back(); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -void Renderer9::freeEventQuery(IDirect3DQuery9* query) +void Renderer9::freeEventQuery(IDirect3DQuery9 *query) { if (mEventQueryPool.size() > 1000) { @@ -706,20 +865,26 @@ void Renderer9::freeEventQuery(IDirect3DQuery9* query) } } -gl::Error Renderer9::createVertexShader(const DWORD *function, size_t length, IDirect3DVertexShader9 **outShader) +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) +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) +HRESULT Renderer9::createVertexBuffer(UINT Length, + DWORD Usage, + IDirect3DVertexBuffer9 **ppVertexBuffer) { D3DPOOL Pool = getBufferPool(Usage); - return mDevice->CreateVertexBuffer(Length, Usage, 0, Pool, ppVertexBuffer, NULL); + return mDevice->CreateVertexBuffer(Length, Usage, 0, Pool, ppVertexBuffer, nullptr); } VertexBuffer *Renderer9::createVertexBuffer() @@ -727,10 +892,13 @@ VertexBuffer *Renderer9::createVertexBuffer() return new VertexBuffer9(this); } -HRESULT Renderer9::createIndexBuffer(UINT Length, DWORD Usage, D3DFORMAT Format, IDirect3DIndexBuffer9 **ppIndexBuffer) +HRESULT Renderer9::createIndexBuffer(UINT Length, + DWORD Usage, + D3DFORMAT Format, + IDirect3DIndexBuffer9 **ppIndexBuffer) { D3DPOOL Pool = getBufferPool(Usage); - return mDevice->CreateIndexBuffer(Length, Usage, Format, Pool, ppIndexBuffer, NULL); + return mDevice->CreateIndexBuffer(Length, Usage, Format, Pool, ppIndexBuffer, nullptr); } IndexBuffer *Renderer9::createIndexBuffer() @@ -738,36 +906,13 @@ IndexBuffer *Renderer9::createIndexBuffer() return new IndexBuffer9(this); } -BufferImpl *Renderer9::createBuffer() -{ - return new Buffer9(this); -} - -VertexArrayImpl *Renderer9::createVertexArray(const gl::VertexArray::Data &data) -{ - return new VertexArray9(data); -} - -QueryImpl *Renderer9::createQuery(GLenum type) -{ - return new Query9(this, type); -} - -FenceNVImpl *Renderer9::createFenceNV() -{ - return new FenceNV9(this); -} - -FenceSyncImpl *Renderer9::createFenceSync() +StreamProducerImpl *Renderer9::createStreamProducerD3DTextureNV12( + egl::Stream::ConsumerType consumerType, + const egl::AttributeMap &attribs) { - // Renderer9 doesn't support ES 3.0 and its sync objects. + // Streams are not supported under D3D9 UNREACHABLE(); - return NULL; -} - -TransformFeedbackImpl* Renderer9::createTransformFeedback() -{ - return new TransformFeedbackD3D(); + return nullptr; } bool Renderer9::supportsFastCopyBufferToTexture(GLenum internalFormat) const @@ -776,22 +921,24 @@ bool Renderer9::supportsFastCopyBufferToTexture(GLenum internalFormat) const return false; } -gl::Error Renderer9::fastCopyBufferToTexture(const gl::PixelUnpackState &unpack, unsigned int offset, RenderTargetD3D *destRenderTarget, - GLenum destinationFormat, GLenum sourcePixelsType, const gl::Box &destArea) +gl::Error Renderer9::fastCopyBufferToTexture(const gl::Context *context, + 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); + return gl::InternalError(); } -gl::Error Renderer9::setSamplerState(gl::SamplerType type, int index, gl::Texture *texture, const gl::SamplerState &samplerState) +gl::Error Renderer9::setSamplerState(const gl::Context *context, + gl::SamplerType type, + int index, + gl::Texture *texture, + const gl::SamplerState &samplerState) { CurSamplerState &appliedSampler = (type == gl::SAMPLER_PIXEL) ? mCurPixelSamplerStates[index] : mCurVertexSamplerStates[index]; @@ -800,11 +947,7 @@ gl::Error Renderer9::setSamplerState(gl::SamplerType type, int index, gl::Textur TextureD3D *textureD3D = GetImplAs(texture); TextureStorage *storage = nullptr; - gl::Error error = textureD3D->getNativeTexture(&storage); - if (error.isError()) - { - return error; - } + ANGLE_TRY(textureD3D->getNativeTexture(context, &storage)); // Storage should exist, texture should be complete ASSERT(storage); @@ -815,12 +958,16 @@ gl::Error Renderer9::setSamplerState(gl::SamplerType type, int index, gl::Textur memcmp(&samplerState, &appliedSampler, sizeof(gl::SamplerState)) != 0) { int d3dSamplerOffset = (type == gl::SAMPLER_PIXEL) ? 0 : D3DVERTEXTEXTURESAMPLER0; - int d3dSampler = index + d3dSamplerOffset; + int d3dSampler = index + d3dSamplerOffset; - mDevice->SetSamplerState(d3dSampler, D3DSAMP_ADDRESSU, gl_d3d9::ConvertTextureWrap(samplerState.wrapS)); - mDevice->SetSamplerState(d3dSampler, D3DSAMP_ADDRESSV, gl_d3d9::ConvertTextureWrap(samplerState.wrapT)); + 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)); + mDevice->SetSamplerState( + d3dSampler, D3DSAMP_MAGFILTER, + gl_d3d9::ConvertMagFilter(samplerState.magFilter, samplerState.maxAnisotropy)); D3DTEXTUREFILTERTYPE d3dMinFilter, d3dMipFilter; float lodBias; @@ -830,52 +977,50 @@ gl::Error Renderer9::setSamplerState(gl::SamplerType type, int index, gl::Textur mDevice->SetSamplerState(d3dSampler, D3DSAMP_MIPFILTER, d3dMipFilter); mDevice->SetSamplerState(d3dSampler, D3DSAMP_MAXMIPLEVEL, baseLevel); mDevice->SetSamplerState(d3dSampler, D3DSAMP_MIPMAPLODBIAS, static_cast(lodBias)); - if (getRendererExtensions().textureFilterAnisotropic) + if (getNativeExtensions().textureFilterAnisotropic) { - mDevice->SetSamplerState(d3dSampler, D3DSAMP_MAXANISOTROPY, (DWORD)samplerState.maxAnisotropy); + DWORD maxAnisotropy = + std::min(mDeviceCaps.MaxAnisotropy, static_cast(samplerState.maxAnisotropy)); + mDevice->SetSamplerState(d3dSampler, D3DSAMP_MAXANISOTROPY, maxAnisotropy); } } - appliedSampler.forceSet = false; + appliedSampler.forceSet = false; appliedSampler.samplerState = samplerState; - appliedSampler.baseLevel = baseLevel; + appliedSampler.baseLevel = baseLevel; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error Renderer9::setTexture(gl::SamplerType type, int index, gl::Texture *texture) +gl::Error Renderer9::setTexture(const gl::Context *context, + gl::SamplerType type, + int index, + gl::Texture *texture) { - int d3dSamplerOffset = (type == gl::SAMPLER_PIXEL) ? 0 : D3DVERTEXTEXTURESAMPLER0; - int d3dSampler = index + d3dSamplerOffset; - IDirect3DBaseTexture9 *d3dTexture = NULL; - bool forceSetTexture = false; + int d3dSamplerOffset = (type == gl::SAMPLER_PIXEL) ? 0 : D3DVERTEXTEXTURESAMPLER0; + int d3dSampler = index + d3dSamplerOffset; + IDirect3DBaseTexture9 *d3dTexture = nullptr; + bool forceSetTexture = false; - std::vector &appliedTextures = (type == gl::SAMPLER_PIXEL) ? mCurPixelTextures : mCurVertexTextures; + std::vector &appliedTextures = + (type == gl::SAMPLER_PIXEL) ? mCurPixelTextures : mCurVertexTextures; if (texture) { TextureD3D *textureImpl = GetImplAs(texture); TextureStorage *texStorage = nullptr; - gl::Error error = textureImpl->getNativeTexture(&texStorage); - if (error.isError()) - { - return error; - } + ANGLE_TRY(textureImpl->getNativeTexture(context, &texStorage)); // Texture should be complete and have a storage ASSERT(texStorage); TextureStorage9 *storage9 = GetAs(texStorage); - error = storage9->getBaseTexture(&d3dTexture); - if (error.isError()) - { - return error; - } + ANGLE_TRY(storage9->getBaseTexture(context, &d3dTexture)); // 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); + ASSERT(d3dTexture != nullptr); forceSetTexture = textureImpl->hasDirtyImages(); textureImpl->resetDirty(); @@ -888,60 +1033,50 @@ gl::Error Renderer9::setTexture(gl::SamplerType type, int index, gl::Texture *te appliedTextures[index] = reinterpret_cast(d3dTexture); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error Renderer9::setUniformBuffers(const gl::Data &/*data*/, - const std::vector &/*vertexUniformBuffers*/, - const std::vector &/*fragmentUniformBuffers*/) +gl::Error Renderer9::updateState(const gl::Context *context, GLenum drawMode) { - // No effect in ES2/D3D9 - return gl::Error(GL_NO_ERROR); -} + const auto &glState = context->getGLState(); -void Renderer9::syncState(const gl::State &state, const gl::State::DirtyBits &bitmask) -{ - mStateManager.syncState(state, bitmask); -} - -gl::Error Renderer9::updateState(const gl::Data &data, GLenum drawMode) -{ // Applies the render target surface, depth stencil surface, viewport rectangle and // scissor rectangle to the renderer - const gl::Framebuffer *framebufferObject = data.state->getDrawFramebuffer(); - ASSERT(framebufferObject && framebufferObject->checkStatus(data) == GL_FRAMEBUFFER_COMPLETE); + gl::Framebuffer *framebuffer = glState.getDrawFramebuffer(); + ASSERT(framebuffer && !framebuffer->hasAnyDirtyBit() && framebuffer->cachedComplete()); - gl::Error error = applyRenderTarget(framebufferObject); - if (error.isError()) - { - return error; - } + ANGLE_TRY(applyRenderTarget(context, framebuffer)); // Setting viewport state - setViewport(data.caps, data.state->getViewport(), data.state->getNearPlane(), - data.state->getFarPlane(), drawMode, data.state->getRasterizerState().frontFace, - false); + setViewport(glState.getViewport(), glState.getNearPlane(), glState.getFarPlane(), drawMode, + glState.getRasterizerState().frontFace, false); // Setting scissors state - setScissorRectangle(data.state->getScissor(), data.state->isScissorTestEnabled()); + setScissorRectangle(glState.getScissor(), glState.isScissorTestEnabled()); // Setting blend, depth stencil, and rasterizer states - int samples = framebufferObject->getSamples(data); - gl::RasterizerState rasterizer = data.state->getRasterizerState(); + // Since framebuffer->getSamples will return the original samples which may be different with + // the sample counts that we set in render target view, here we use renderTarget->getSamples to + // get the actual samples. + GLsizei samples = 0; + const gl::FramebufferAttachment *firstColorAttachment = framebuffer->getFirstColorbuffer(); + if (firstColorAttachment) + { + ASSERT(firstColorAttachment->isAttached()); + RenderTarget9 *renderTarget = nullptr; + ANGLE_TRY(firstColorAttachment->getRenderTarget(context, &renderTarget)); + samples = renderTarget->getSamples(); + } + gl::RasterizerState rasterizer = glState.getRasterizerState(); rasterizer.pointDrawMode = (drawMode == GL_POINTS); rasterizer.multiSample = (samples != 0); - unsigned int mask = GetBlendSampleMask(data, samples); - error = setBlendDepthRasterStates(data, mask); - - if (error.isError()) - { - return error; - } + unsigned int mask = GetBlendSampleMask(glState, samples); + ANGLE_TRY(setBlendDepthRasterStates(context, mask)); mStateManager.resetDirtyBits(); - return error; + return gl::NoError(); } void Renderer9::setScissorRectangle(const gl::Rectangle &scissor, bool enabled) @@ -949,71 +1084,85 @@ void Renderer9::setScissorRectangle(const gl::Rectangle &scissor, bool enabled) mStateManager.setScissorState(scissor, enabled); } -gl::Error Renderer9::setBlendDepthRasterStates(const gl::Data &glData, GLenum drawMode) +gl::Error Renderer9::setBlendDepthRasterStates(const gl::Context *context, GLenum drawMode) { - int samples = glData.state->getDrawFramebuffer()->getSamples(glData); - gl::RasterizerState rasterizer = glData.state->getRasterizerState(); + const auto &glState = context->getGLState(); + gl::Framebuffer *drawFramebuffer = glState.getDrawFramebuffer(); + ASSERT(!drawFramebuffer->hasAnyDirtyBit()); + // Since framebuffer->getSamples will return the original samples which may be different with + // the sample counts that we set in render target view, here we use renderTarget->getSamples to + // get the actual samples. + GLsizei samples = 0; + const gl::FramebufferAttachment *firstColorAttachment = drawFramebuffer->getFirstColorbuffer(); + if (firstColorAttachment) + { + ASSERT(firstColorAttachment->isAttached()); + RenderTarget9 *renderTarget = nullptr; + ANGLE_TRY(firstColorAttachment->getRenderTarget(context, &renderTarget)); + samples = renderTarget->getSamples(); + } + gl::RasterizerState rasterizer = glState.getRasterizerState(); rasterizer.pointDrawMode = (drawMode == GL_POINTS); rasterizer.multiSample = (samples != 0); - unsigned int mask = GetBlendSampleMask(glData, samples); - return mStateManager.setBlendDepthRasterStates(*glData.state, mask); + unsigned int mask = GetBlendSampleMask(glState, samples); + return mStateManager.setBlendDepthRasterStates(glState, mask); } -void Renderer9::setViewport(const gl::Caps *caps, - const gl::Rectangle &viewport, +void Renderer9::setViewport(const gl::Rectangle &viewport, float zNear, float zFar, GLenum drawMode, GLenum frontFace, bool ignoreViewport) { - mStateManager.setViewportState(caps, viewport, zNear, zFar, drawMode, frontFace, - ignoreViewport); + mStateManager.setViewportState(viewport, zNear, zFar, drawMode, frontFace, ignoreViewport); } 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; + 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) +gl::Error Renderer9::getNullColorbuffer(const gl::Context *context, + const gl::FramebufferAttachment *depthbuffer, + const gl::FramebufferAttachment **outColorBuffer) { ASSERT(depthbuffer); @@ -1022,25 +1171,28 @@ gl::Error Renderer9::getNullColorbuffer(const gl::FramebufferAttachment *depthbu // search cached nullcolorbuffers for (int i = 0; i < NUM_NULL_COLORBUFFER_CACHE_ENTRIES; i++) { - if (mNullColorbufferCache[i].buffer != NULL && + if (mNullColorbufferCache[i].buffer != nullptr && mNullColorbufferCache[i].width == size.width && mNullColorbufferCache[i].height == size.height) { mNullColorbufferCache[i].lruCount = ++mMaxNullColorbufferLRU; - *outColorBuffer = mNullColorbufferCache[i].buffer; - return gl::Error(GL_NO_ERROR); + *outColorBuffer = mNullColorbufferCache[i].buffer; + return gl::NoError(); } } - gl::Renderbuffer *nullRenderbuffer = new gl::Renderbuffer(createRenderbuffer(), 0); - gl::Error error = nullRenderbuffer->setStorage(GL_NONE, size.width, size.height); + auto *implFactory = context->getImplementation(); + + gl::Renderbuffer *nullRenderbuffer = new gl::Renderbuffer(implFactory->createRenderbuffer(), 0); + gl::Error error = nullRenderbuffer->setStorage(context, GL_NONE, size.width, size.height); if (error.isError()) { SafeDelete(nullRenderbuffer); return error; } - gl::FramebufferAttachment *nullbuffer = new gl::FramebufferAttachment(GL_RENDERBUFFER, GL_NONE, gl::ImageIndex::MakeInvalid(), nullRenderbuffer); + gl::FramebufferAttachment *nullbuffer = new gl::FramebufferAttachment( + context, GL_RENDERBUFFER, GL_NONE, gl::ImageIndex::MakeInvalid(), nullRenderbuffer); // add nullbuffer to the cache NullColorbufferCacheEntry *oldest = &mNullColorbufferCache[0]; @@ -1053,46 +1205,38 @@ gl::Error Renderer9::getNullColorbuffer(const gl::FramebufferAttachment *depthbu } delete oldest->buffer; - oldest->buffer = nullbuffer; + oldest->buffer = nullbuffer; oldest->lruCount = ++mMaxNullColorbufferLRU; oldest->width = size.width; oldest->height = size.height; *outColorBuffer = nullbuffer; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error Renderer9::applyRenderTarget(const gl::FramebufferAttachment *colorAttachment, +gl::Error Renderer9::applyRenderTarget(const gl::Context *context, + const gl::FramebufferAttachment *colorAttachment, const gl::FramebufferAttachment *depthStencilAttachment) { const gl::FramebufferAttachment *renderAttachment = colorAttachment; - gl::Error error(GL_NO_ERROR); // 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 (renderAttachment == nullptr) { - error = getNullColorbuffer(depthStencilAttachment, &renderAttachment); - if (error.isError()) - { - return error; - } + ANGLE_TRY(getNullColorbuffer(context, depthStencilAttachment, &renderAttachment)); } ASSERT(renderAttachment != nullptr); - size_t renderTargetWidth = 0; - size_t renderTargetHeight = 0; + size_t renderTargetWidth = 0; + size_t renderTargetHeight = 0; D3DFORMAT renderTargetFormat = D3DFMT_UNKNOWN; RenderTarget9 *renderTarget = nullptr; - error = renderAttachment->getRenderTarget(&renderTarget); - if (error.isError()) - { - return error; - } + ANGLE_TRY(renderAttachment->getRenderTarget(context, &renderTarget)); ASSERT(renderTarget); - bool renderTargetChanged = false; + bool renderTargetChanged = false; unsigned int renderTargetSerial = renderTarget->getSerial(); if (renderTargetSerial != mAppliedRenderTargetSerial) { @@ -1103,24 +1247,20 @@ gl::Error Renderer9::applyRenderTarget(const gl::FramebufferAttachment *colorAtt mDevice->SetRenderTarget(0, renderTargetSurface); SafeRelease(renderTargetSurface); - renderTargetWidth = renderTarget->getWidth(); + renderTargetWidth = renderTarget->getWidth(); renderTargetHeight = renderTarget->getHeight(); renderTargetFormat = renderTarget->getD3DFormat(); mAppliedRenderTargetSerial = renderTargetSerial; - renderTargetChanged = true; + renderTargetChanged = true; } RenderTarget9 *depthStencilRenderTarget = nullptr; - unsigned int depthStencilSerial = 0; + unsigned int depthStencilSerial = 0; if (depthStencilAttachment != nullptr) { - error = depthStencilAttachment->getRenderTarget(&depthStencilRenderTarget); - if (error.isError()) - { - return error; - } + ANGLE_TRY(depthStencilAttachment->getRenderTarget(context, &depthStencilRenderTarget)); ASSERT(depthStencilRenderTarget); depthStencilSerial = depthStencilRenderTarget->getSerial(); @@ -1128,7 +1268,7 @@ gl::Error Renderer9::applyRenderTarget(const gl::FramebufferAttachment *colorAtt if (depthStencilSerial != mAppliedDepthStencilSerial || !mDepthStencilInitialized) { - unsigned int depthSize = 0; + unsigned int depthSize = 0; unsigned int stencilSize = 0; // Apply the depth stencil on the device @@ -1140,19 +1280,19 @@ gl::Error Renderer9::applyRenderTarget(const gl::FramebufferAttachment *colorAtt mDevice->SetDepthStencilSurface(depthStencilSurface); SafeRelease(depthStencilSurface); - depthSize = depthStencilAttachment->getDepthSize(); + depthSize = depthStencilAttachment->getDepthSize(); stencilSize = depthStencilAttachment->getStencilSize(); } else { - mDevice->SetDepthStencilSurface(NULL); + mDevice->SetDepthStencilSurface(nullptr); } mStateManager.updateDepthSizeIfChanged(mDepthStencilInitialized, depthSize); mStateManager.updateStencilSizeIfChanged(mDepthStencilInitialized, stencilSize); mAppliedDepthStencilSerial = depthStencilSerial; - mDepthStencilInitialized = true; + mDepthStencilInitialized = true; } if (renderTargetChanged || !mRenderTargetDescInitialized) @@ -1163,83 +1303,84 @@ gl::Error Renderer9::applyRenderTarget(const gl::FramebufferAttachment *colorAtt mRenderTargetDescInitialized = true; } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error Renderer9::applyRenderTarget(const gl::Framebuffer *framebuffer) +gl::Error Renderer9::applyRenderTarget(const gl::Context *context, + const gl::Framebuffer *framebuffer) { - return applyRenderTarget(framebuffer->getColorbuffer(0), framebuffer->getDepthOrStencilbuffer()); + return applyRenderTarget(context, framebuffer->getColorbuffer(0), + framebuffer->getDepthOrStencilbuffer()); } -gl::Error Renderer9::applyVertexBuffer(const gl::State &state, +gl::Error Renderer9::applyVertexBuffer(const gl::Context *context, GLenum mode, GLint first, GLsizei count, GLsizei instances, TranslatedIndexData * /*indexInfo*/) { - gl::Error error = mVertexDataManager->prepareVertexData(state, first, count, &mTranslatedAttribCache, instances); + const gl::State &state = context->getGLState(); + gl::Error error = mVertexDataManager->prepareVertexData(context, first, count, + &mTranslatedAttribCache, instances); if (error.isError()) { return error; } - return mVertexDeclarationCache.applyDeclaration(mDevice, mTranslatedAttribCache, state.getProgram(), instances, &mRepeatDraw); + return mVertexDeclarationCache.applyDeclaration( + mDevice, mTranslatedAttribCache, state.getProgram(), first, instances, &mRepeatDraw); } // Applies the indices and element array bindings to the Direct3D 9 device -gl::Error Renderer9::applyIndexBuffer(const gl::Data &data, - const GLvoid *indices, +gl::Error Renderer9::applyIndexBuffer(const gl::Context *context, + const void *indices, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo) { - gl::VertexArray *vao = data.state->getVertexArray(); + gl::VertexArray *vao = context->getGLState().getVertexArray(); gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get(); - gl::Error error = mIndexDataManager->prepareIndexData(type, count, elementArrayBuffer, indices, - indexInfo, false); - if (error.isError()) - { - return error; - } + const auto &lazyIndexRange = context->getParams(); + + GLenum dstType = GetIndexTranslationDestType(type, lazyIndexRange, false); + + ANGLE_TRY(mIndexDataManager->prepareIndexData(context, type, dstType, count, elementArrayBuffer, + indices, indexInfo)); // Directly binding the storage buffer is not supported for d3d9 - ASSERT(indexInfo->storage == NULL); + ASSERT(indexInfo->storage == nullptr); if (indexInfo->serial != mAppliedIBSerial) { - IndexBuffer9* indexBuffer = GetAs(indexInfo->indexBuffer); + IndexBuffer9 *indexBuffer = GetAs(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()); + return gl::NoError(); } -gl::Error Renderer9::drawArraysImpl(const gl::Data &data, +gl::Error Renderer9::drawArraysImpl(const gl::Context *context, GLenum mode, + GLint startVertex, GLsizei count, GLsizei instances) { - ASSERT(!data.state->isTransformFeedbackActiveUnpaused()); + ASSERT(!context->getGLState().isTransformFeedbackActiveUnpaused()); startScene(); if (mode == GL_LINE_LOOP) { - return drawLineLoop(count, GL_NONE, NULL, 0, NULL); + return drawLineLoop(context, count, GL_NONE, nullptr, 0, nullptr); } else if (instances > 0) { - StaticIndexBufferInterface *countingIB = NULL; - gl::Error error = getCountingIB(count, &countingIB); + StaticIndexBufferInterface *countingIB = nullptr; + gl::Error error = getCountingIB(count, &countingIB); if (error.isError()) { return error; @@ -1258,60 +1399,73 @@ gl::Error Renderer9::drawArraysImpl(const gl::Data &data, mDevice->DrawIndexedPrimitive(mPrimitiveType, 0, 0, count, 0, mPrimitiveCount); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } - else // Regular case + else // Regular case { mDevice->DrawPrimitive(mPrimitiveType, 0, mPrimitiveCount); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } } -gl::Error Renderer9::drawElementsImpl(const gl::Data &data, - const TranslatedIndexData &indexInfo, +gl::Error Renderer9::drawElementsImpl(const gl::Context *context, GLenum mode, GLsizei count, GLenum type, - const GLvoid *indices, - GLsizei /*instances*/) + const void *indices, + GLsizei instances) { + TranslatedIndexData indexInfo; + + ANGLE_TRY(applyIndexBuffer(context, indices, count, mode, type, &indexInfo)); + + const auto &lazyIndexRange = context->getParams(); + const gl::IndexRange &indexRange = lazyIndexRange.getIndexRange().value(); + size_t vertexCount = indexRange.vertexCount(); + ANGLE_TRY(applyVertexBuffer(context, mode, static_cast(indexRange.start), + static_cast(vertexCount), instances, &indexInfo)); + startScene(); - int minIndex = static_cast(indexInfo.indexRange.start); + int minIndex = static_cast(indexRange.start); - gl::VertexArray *vao = data.state->getVertexArray(); + gl::VertexArray *vao = context->getGLState().getVertexArray(); gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get(); if (mode == GL_POINTS) { - return drawIndexedPoints(count, type, indices, minIndex, elementArrayBuffer); + return drawIndexedPoints(context, count, type, indices, minIndex, elementArrayBuffer); } else if (mode == GL_LINE_LOOP) { - return drawLineLoop(count, type, indices, minIndex, elementArrayBuffer); + return drawLineLoop(context, count, type, indices, minIndex, elementArrayBuffer); } else { - size_t vertexCount = indexInfo.indexRange.vertexCount(); for (int i = 0; i < mRepeatDraw; i++) { mDevice->DrawIndexedPrimitive(mPrimitiveType, -minIndex, minIndex, static_cast(vertexCount), indexInfo.startIndex, mPrimitiveCount); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } } -gl::Error Renderer9::drawLineLoop(GLsizei count, GLenum type, const GLvoid *indices, int minIndex, gl::Buffer *elementArrayBuffer) +gl::Error Renderer9::drawLineLoop(const gl::Context *context, + GLsizei count, + GLenum type, + const void *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); + BufferD3D *storage = GetImplAs(elementArrayBuffer); + intptr_t offset = reinterpret_cast(indices); + const uint8_t *bufferData = nullptr; + gl::Error error = storage->getData(context, &bufferData); if (error.isError()) { return error; @@ -1321,12 +1475,13 @@ gl::Error Renderer9::drawLineLoop(GLsizei count, GLenum type, const GLvoid *indi unsigned int startIndex = 0; - if (getRendererExtensions().elementIndexUint) + if (getNativeExtensions().elementIndexUint) { if (!mLineLoopIB) { mLineLoopIB = new StreamingIndexBufferInterface(this); - gl::Error error = mLineLoopIB->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_INT); + gl::Error error = + mLineLoopIB->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_INT); if (error.isError()) { SafeDelete(mLineLoopIB); @@ -1337,60 +1492,64 @@ gl::Error Renderer9::drawLineLoop(GLsizei count, GLenum type, const GLvoid *indi // Checked by Renderer9::applyPrimitiveType ASSERT(count >= 0); - if (static_cast(count) + 1 > (std::numeric_limits::max() / sizeof(unsigned int))) + 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."); + return gl::OutOfMemory() << "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); + 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; + void *mappedMemory = nullptr; unsigned int offset = 0; - error = mLineLoopIB->mapBuffer(spaceNeeded, &mappedMemory, &offset); + error = mLineLoopIB->mapBuffer(spaceNeeded, &mappedMemory, &offset); if (error.isError()) { return error; } - startIndex = static_cast(offset) / 4; - unsigned int *data = reinterpret_cast(mappedMemory); + 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(); + 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(); @@ -1404,7 +1563,8 @@ gl::Error Renderer9::drawLineLoop(GLsizei count, GLenum type, const GLvoid *indi if (!mLineLoopIB) { mLineLoopIB = new StreamingIndexBufferInterface(this); - gl::Error error = mLineLoopIB->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_SHORT); + gl::Error error = + mLineLoopIB->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_SHORT); if (error.isError()) { SafeDelete(mLineLoopIB); @@ -1415,19 +1575,22 @@ gl::Error Renderer9::drawLineLoop(GLsizei count, GLenum type, const GLvoid *indi // Checked by Renderer9::applyPrimitiveType ASSERT(count >= 0); - if (static_cast(count) + 1 > (std::numeric_limits::max() / sizeof(unsigned short))) + 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."); + return gl::OutOfMemory() << "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); + 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; + void *mappedMemory = nullptr; unsigned int offset; error = mLineLoopIB->mapBuffer(spaceNeeded, &mappedMemory, &offset); if (error.isError()) @@ -1435,40 +1598,41 @@ gl::Error Renderer9::drawLineLoop(GLsizei count, GLenum type, const GLvoid *indi return error; } - startIndex = static_cast(offset) / 2; - unsigned short *data = reinterpret_cast(mappedMemory); + 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] = static_cast(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(static_cast(indices)[i]); - } - data[count] = static_cast(static_cast(indices)[0]); - break; - default: UNREACHABLE(); + case GL_NONE: // Non-indexed draw + for (int i = 0; i < count; i++) + { + data[i] = static_cast(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(static_cast(indices)[i]); + } + data[count] = static_cast(static_cast(indices)[0]); + break; + default: + UNREACHABLE(); } error = mLineLoopIB->unmapBuffer(); @@ -1488,22 +1652,31 @@ gl::Error Renderer9::drawLineLoop(GLsizei count, GLenum type, const GLvoid *indi mDevice->DrawIndexedPrimitive(D3DPT_LINESTRIP, -minIndex, minIndex, count, startIndex, count); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } template -static gl::Error drawPoints(IDirect3DDevice9* device, GLsizei count, const GLvoid *indices, int minIndex) +static gl::Error drawPoints(IDirect3DDevice9 *device, + GLsizei count, + const void *indices, + int minIndex) { for (int i = 0; i < count; i++) { - unsigned int indexValue = static_cast(static_cast(indices)[i]) - minIndex; + unsigned int indexValue = + static_cast(static_cast(indices)[i]) - minIndex; device->DrawPrimitive(D3DPT_POINTLIST, indexValue, 1); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error Renderer9::drawIndexedPoints(GLsizei count, GLenum type, const GLvoid *indices, int minIndex, gl::Buffer *elementArrayBuffer) +gl::Error Renderer9::drawIndexedPoints(const gl::Context *context, + GLsizei count, + GLenum type, + const void *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. @@ -1511,10 +1684,10 @@ gl::Error Renderer9::drawIndexedPoints(GLsizei count, GLenum type, const GLvoid if (elementArrayBuffer) { BufferD3D *storage = GetImplAs(elementArrayBuffer); - intptr_t offset = reinterpret_cast(indices); + intptr_t offset = reinterpret_cast(indices); - const uint8_t *bufferData = NULL; - gl::Error error = storage->getData(&bufferData); + const uint8_t *bufferData = nullptr; + gl::Error error = storage->getData(context, &bufferData); if (error.isError()) { return error; @@ -1525,17 +1698,22 @@ gl::Error Renderer9::drawIndexedPoints(GLsizei count, GLenum type, const GLvoid 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); + 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::InternalError(); } } 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 + if (count <= 65536) // 16-bit indices { const unsigned int spaceNeeded = static_cast(count) * sizeof(unsigned short); @@ -1543,29 +1721,21 @@ gl::Error Renderer9::getCountingIB(size_t count, StaticIndexBufferInterface **ou { SafeDelete(mCountingIB); mCountingIB = new StaticIndexBufferInterface(this); - mCountingIB->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_SHORT); + ANGLE_TRY(mCountingIB->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_SHORT)); - void *mappedMemory = NULL; - gl::Error error = mCountingIB->mapBuffer(spaceNeeded, &mappedMemory, NULL); - if (error.isError()) - { - return error; - } + void *mappedMemory = nullptr; + ANGLE_TRY(mCountingIB->mapBuffer(spaceNeeded, &mappedMemory, nullptr)); - unsigned short *data = reinterpret_cast(mappedMemory); + unsigned short *data = reinterpret_cast(mappedMemory); for (size_t i = 0; i < count; i++) { data[i] = static_cast(i); } - error = mCountingIB->unmapBuffer(); - if (error.isError()) - { - return error; - } + ANGLE_TRY(mCountingIB->unmapBuffer()); } } - else if (getRendererExtensions().elementIndexUint) + else if (getNativeExtensions().elementIndexUint) { const unsigned int spaceNeeded = static_cast(count) * sizeof(unsigned int); @@ -1573,59 +1743,53 @@ gl::Error Renderer9::getCountingIB(size_t count, StaticIndexBufferInterface **ou { SafeDelete(mCountingIB); mCountingIB = new StaticIndexBufferInterface(this); - mCountingIB->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_INT); + ANGLE_TRY(mCountingIB->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_INT)); - void *mappedMemory = NULL; - gl::Error error = mCountingIB->mapBuffer(spaceNeeded, &mappedMemory, NULL); - if (error.isError()) - { - return error; - } + void *mappedMemory = nullptr; + ANGLE_TRY(mCountingIB->mapBuffer(spaceNeeded, &mappedMemory, nullptr)); - unsigned int *data = reinterpret_cast(mappedMemory); + unsigned int *data = reinterpret_cast(mappedMemory); for (unsigned int i = 0; i < count; i++) { data[i] = i; } - error = mCountingIB->unmapBuffer(); - if (error.isError()) - { - return error; - } + ANGLE_TRY(mCountingIB->unmapBuffer()); } } else { - return gl::Error(GL_OUT_OF_MEMORY, "Could not create a counting index buffer for glDrawArraysInstanced."); + return gl::OutOfMemory() + << "Could not create a counting index buffer for glDrawArraysInstanced."; } *outIB = mCountingIB; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error Renderer9::applyShadersImpl(const gl::Data &data, GLenum /*drawMode*/) +gl::Error Renderer9::applyShaders(const gl::Context *context, GLenum drawMode) { - ProgramD3D *programD3D = GetImplAs(data.state->getProgram()); - const auto &inputLayout = programD3D->getCachedInputLayout(); + const gl::State &state = context->getContextState().getState(); + // This method is called single-threaded. + ANGLE_TRY(ensureHLSLCompilerInitialized()); - ShaderExecutableD3D *vertexExe = NULL; - gl::Error error = programD3D->getVertexExecutableForInputLayout(inputLayout, &vertexExe, nullptr); - if (error.isError()) - { - return error; - } + ProgramD3D *programD3D = GetImplAs(state.getProgram()); + VertexArray9 *vao = GetImplAs(state.getVertexArray()); + programD3D->updateCachedInputLayout(vao->getCurrentStateSerial(), state); - const gl::Framebuffer *drawFramebuffer = data.state->getDrawFramebuffer(); - ShaderExecutableD3D *pixelExe = NULL; - error = programD3D->getPixelExecutableForFramebuffer(drawFramebuffer, &pixelExe); - if (error.isError()) - { - return error; - } + ShaderExecutableD3D *vertexExe = nullptr; + ANGLE_TRY(programD3D->getVertexExecutableForCachedInputLayout(&vertexExe, nullptr)); + + const gl::Framebuffer *drawFramebuffer = state.getDrawFramebuffer(); + programD3D->updateCachedOutputLayout(context, drawFramebuffer); + + ShaderExecutableD3D *pixelExe = nullptr; + ANGLE_TRY(programD3D->getPixelExecutableForCachedOutputLayout(&pixelExe, nullptr)); - IDirect3DVertexShader9 *vertexShader = (vertexExe ? GetAs(vertexExe)->getVertexShader() : nullptr); - IDirect3DPixelShader9 *pixelShader = (pixelExe ? GetAs(pixelExe)->getPixelShader() : nullptr); + IDirect3DVertexShader9 *vertexShader = + (vertexExe ? GetAs(vertexExe)->getVertexShader() : nullptr); + IDirect3DPixelShader9 *pixelShader = + (pixelExe ? GetAs(pixelExe)->getPixelShader() : nullptr); if (vertexShader != mAppliedVertexShader) { @@ -1652,25 +1816,39 @@ gl::Error Renderer9::applyShadersImpl(const gl::Data &data, GLenum /*drawMode*/) mAppliedProgramSerial = programSerial; } - return gl::Error(GL_NO_ERROR); + ANGLE_TRY(applyUniforms(programD3D)); + + // Driver uniforms + mStateManager.setShaderConstants(); + + return gl::NoError(); } -gl::Error Renderer9::applyUniforms(const ProgramD3D &programD3D, - GLenum /*drawMode*/, - const std::vector &uniformArray) +gl::Error Renderer9::applyUniforms(ProgramD3D *programD3D) { + // Skip updates if we're not dirty. Note that D3D9 cannot have compute. + if (!programD3D->areVertexUniformsDirty() && !programD3D->areFragmentUniformsDirty()) + { + return gl::NoError(); + } + + const auto &uniformArray = programD3D->getD3DUniforms(); + for (const D3DUniform *targetUniform : uniformArray) { - if (!targetUniform->dirty) + // Built-in uniforms must be skipped. + if (!targetUniform->isReferencedByFragmentShader() && + !targetUniform->isReferencedByVertexShader()) continue; - GLfloat *f = (GLfloat *)targetUniform->data; - GLint *i = (GLint *)targetUniform->data; + const GLfloat *f = reinterpret_cast(targetUniform->firstNonNullData()); + const GLint *i = reinterpret_cast(targetUniform->firstNonNullData()); - switch (targetUniform->type) + switch (targetUniform->typeInfo.type) { case GL_SAMPLER_2D: case GL_SAMPLER_CUBE: + case GL_SAMPLER_EXTERNAL_OES: break; case GL_BOOL: case GL_BOOL_VEC2: @@ -1698,22 +1876,22 @@ gl::Error Renderer9::applyUniforms(const ProgramD3D &programD3D, } } - // Driver uniforms - mStateManager.setShaderConstants(); - - return gl::Error(GL_NO_ERROR); + programD3D->markUniformsClean(); + return gl::NoError(); } void Renderer9::applyUniformnfv(const D3DUniform *targetUniform, const GLfloat *v) { if (targetUniform->isReferencedByFragmentShader()) { - mDevice->SetPixelShaderConstantF(targetUniform->psRegisterIndex, v, targetUniform->registerCount); + mDevice->SetPixelShaderConstantF(targetUniform->psRegisterIndex, v, + targetUniform->registerCount); } if (targetUniform->isReferencedByVertexShader()) { - mDevice->SetVertexShaderConstantF(targetUniform->vsRegisterIndex, v, targetUniform->registerCount); + mDevice->SetVertexShaderConstantF(targetUniform->vsRegisterIndex, v, + targetUniform->registerCount); } } @@ -1730,7 +1908,7 @@ void Renderer9::applyUniformniv(const D3DUniform *targetUniform, const GLint *v) vector[i][3] = (GLfloat)v[4 * i + 3]; } - applyUniformnfv(targetUniform, (GLfloat*)vector); + applyUniformnfv(targetUniform, (GLfloat *)vector); } void Renderer9::applyUniformnbv(const D3DUniform *targetUniform, const GLint *v) @@ -1746,18 +1924,19 @@ void Renderer9::applyUniformnbv(const D3DUniform *targetUniform, const GLint *v) vector[i][3] = (v[4 * i + 3] == GL_FALSE) ? 0.0f : 1.0f; } - applyUniformnfv(targetUniform, (GLfloat*)vector); + applyUniformnfv(targetUniform, (GLfloat *)vector); } -gl::Error Renderer9::clear(const ClearParameters &clearParams, +gl::Error Renderer9::clear(const gl::Context *context, + const ClearParameters &clearParams, const gl::FramebufferAttachment *colorBuffer, const gl::FramebufferAttachment *depthStencilBuffer) { - if (clearParams.colorClearType != GL_FLOAT) + if (clearParams.colorType != GL_FLOAT) { // Clearing buffers with non-float values is not supported by Renderer9 and ES 2.0 UNREACHABLE(); - return gl::Error(GL_INVALID_OPERATION); + return gl::InternalError(); } bool clearColor = clearParams.clearColor[0]; @@ -1765,14 +1944,15 @@ gl::Error Renderer9::clear(const ClearParameters &clearParams, { if (clearParams.clearColor[i] != clearColor) { - // Clearing individual buffers other than buffer zero is not supported by Renderer9 and ES 2.0 + // Clearing individual buffers other than buffer zero is not supported by Renderer9 and + // ES 2.0 UNREACHABLE(); - return gl::Error(GL_INVALID_OPERATION); + return gl::InternalError(); } } - float depth = gl::clamp01(clearParams.depthClearValue); - DWORD stencil = clearParams.stencilClearValue & 0x000000FF; + float depth = gl::clamp01(clearParams.depthValue); + DWORD stencil = clearParams.stencilValue & 0x000000FF; unsigned int stencilUnmasked = 0x0; if (clearParams.clearStencil && depthStencilBuffer->getStencilSize() > 0) @@ -1780,7 +1960,7 @@ gl::Error Renderer9::clear(const ClearParameters &clearParams, ASSERT(depthStencilBuffer != nullptr); RenderTargetD3D *stencilRenderTarget = nullptr; - gl::Error error = depthStencilBuffer->getRenderTarget(&stencilRenderTarget); + gl::Error error = depthStencilBuffer->getRenderTarget(context, &stencilRenderTarget); if (error.isError()) { return error; @@ -1789,21 +1969,23 @@ gl::Error Renderer9::clear(const ClearParameters &clearParams, RenderTarget9 *stencilRenderTarget9 = GetAs(stencilRenderTarget); ASSERT(stencilRenderTarget9); - const d3d9::D3DFormat &d3dFormatInfo = d3d9::GetD3DFormatInfo(stencilRenderTarget9->getD3DFormat()); + const d3d9::D3DFormat &d3dFormatInfo = + d3d9::GetD3DFormatInfo(stencilRenderTarget9->getD3DFormat()); stencilUnmasked = (0x1 << d3dFormatInfo.stencilBits) - 1; } - const bool needMaskedStencilClear = clearParams.clearStencil && - (clearParams.stencilWriteMask & stencilUnmasked) != stencilUnmasked; + const bool needMaskedStencilClear = + clearParams.clearStencil && + (clearParams.stencilWriteMask & stencilUnmasked) != stencilUnmasked; bool needMaskedColorClear = false; - D3DCOLOR color = D3DCOLOR_ARGB(255, 0, 0, 0); + D3DCOLOR color = D3DCOLOR_ARGB(255, 0, 0, 0); if (clearColor) { ASSERT(colorBuffer != nullptr); - RenderTargetD3D *colorRenderTarget = NULL; - gl::Error error = colorBuffer->getRenderTarget(&colorRenderTarget); + RenderTargetD3D *colorRenderTarget = nullptr; + gl::Error error = colorBuffer->getRenderTarget(context, &colorRenderTarget); if (error.isError()) { return error; @@ -1812,17 +1994,27 @@ gl::Error Renderer9::clear(const ClearParameters &clearParams, RenderTarget9 *colorRenderTarget9 = GetAs(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) || + const gl::InternalFormat &formatInfo = *colorBuffer->getFormat().info; + const d3d9::D3DFormat &d3dFormatInfo = + d3d9::GetD3DFormatInfo(colorRenderTarget9->getD3DFormat()); + + color = + D3DCOLOR_ARGB(gl::unorm<8>((formatInfo.alphaBits == 0 && d3dFormatInfo.alphaBits > 0) + ? 1.0f + : clearParams.colorF.alpha), + gl::unorm<8>((formatInfo.redBits == 0 && d3dFormatInfo.redBits > 0) + ? 0.0f + : clearParams.colorF.red), + gl::unorm<8>((formatInfo.greenBits == 0 && d3dFormatInfo.greenBits > 0) + ? 0.0f + : clearParams.colorF.green), + gl::unorm<8>((formatInfo.blueBits == 0 && d3dFormatInfo.blueBits > 0) + ? 0.0f + : clearParams.colorF.blue)); + + if ((formatInfo.redBits > 0 && !clearParams.colorMaskRed) || (formatInfo.greenBits > 0 && !clearParams.colorMaskGreen) || - (formatInfo.blueBits > 0 && !clearParams.colorMaskBlue) || + (formatInfo.blueBits > 0 && !clearParams.colorMaskBlue) || (formatInfo.alphaBits > 0 && !clearParams.colorMaskAlpha)) { needMaskedColorClear = true; @@ -1835,7 +2027,7 @@ gl::Error Renderer9::clear(const ClearParameters &clearParams, // 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) + if (mMaskedClearSavedState == nullptr) { hr = mDevice->BeginStateBlock(); ASSERT(SUCCEEDED(hr) || hr == D3DERR_OUTOFVIDEOMEMORY || hr == E_OUTOFMEMORY); @@ -1850,10 +2042,10 @@ gl::Error Renderer9::clear(const ClearParameters &clearParams, mDevice->SetRenderState(D3DRS_CLIPPLANEENABLE, 0); mDevice->SetRenderState(D3DRS_COLORWRITEENABLE, 0); mDevice->SetRenderState(D3DRS_STENCILENABLE, FALSE); - mDevice->SetPixelShader(NULL); - mDevice->SetVertexShader(NULL); + mDevice->SetPixelShader(nullptr); + mDevice->SetVertexShader(nullptr); mDevice->SetFVF(D3DFVF_XYZRHW | D3DFVF_DIFFUSE); - mDevice->SetStreamSource(0, NULL, 0, 0); + mDevice->SetStreamSource(0, nullptr, 0, 0); mDevice->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, TRUE); mDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1); mDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TFACTOR); @@ -1862,7 +2054,7 @@ gl::Error Renderer9::clear(const ClearParameters &clearParams, mDevice->SetRenderState(D3DRS_TEXTUREFACTOR, color); mDevice->SetRenderState(D3DRS_MULTISAMPLEMASK, 0xFFFFFFFF); - for(int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) + for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) { mDevice->SetStreamSourceFreq(i, 1); } @@ -1871,9 +2063,9 @@ gl::Error Renderer9::clear(const ClearParameters &clearParams, ASSERT(SUCCEEDED(hr) || hr == D3DERR_OUTOFVIDEOMEMORY || hr == E_OUTOFMEMORY); } - ASSERT(mMaskedClearSavedState != NULL); + ASSERT(mMaskedClearSavedState != nullptr); - if (mMaskedClearSavedState != NULL) + if (mMaskedClearSavedState != nullptr) { hr = mMaskedClearSavedState->Capture(); ASSERT(SUCCEEDED(hr)); @@ -1890,11 +2082,10 @@ gl::Error Renderer9::clear(const ClearParameters &clearParams, if (clearColor) { - mDevice->SetRenderState(D3DRS_COLORWRITEENABLE, - gl_d3d9::ConvertColorMask(clearParams.colorMaskRed, - clearParams.colorMaskGreen, - clearParams.colorMaskBlue, - clearParams.colorMaskAlpha)); + mDevice->SetRenderState( + D3DRS_COLORWRITEENABLE, + gl_d3d9::ConvertColorMask(clearParams.colorMaskRed, clearParams.colorMaskGreen, + clearParams.colorMaskBlue, clearParams.colorMaskAlpha)); } else { @@ -1917,8 +2108,8 @@ gl::Error Renderer9::clear(const ClearParameters &clearParams, mDevice->SetRenderState(D3DRS_STENCILENABLE, FALSE); } - mDevice->SetPixelShader(NULL); - mDevice->SetVertexShader(NULL); + mDevice->SetPixelShader(nullptr); + mDevice->SetVertexShader(nullptr); mDevice->SetFVF(D3DFVF_XYZRHW); mDevice->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, TRUE); mDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1); @@ -1928,7 +2119,7 @@ gl::Error Renderer9::clear(const ClearParameters &clearParams, mDevice->SetRenderState(D3DRS_TEXTUREFACTOR, color); mDevice->SetRenderState(D3DRS_MULTISAMPLEMASK, 0xFFFFFFFF); - for(int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) + for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) { mDevice->SetStreamSourceFreq(i, 1); } @@ -1936,7 +2127,7 @@ gl::Error Renderer9::clear(const ClearParameters &clearParams, int renderTargetWidth = mStateManager.getRenderTargetWidth(); int renderTargetHeight = mStateManager.getRenderTargetHeight(); - float quad[4][4]; // A quadrilateral covering the target, aligned to match the edges + float quad[4][4]; // A quadrilateral covering the target, aligned to match the edges quad[0][0] = -0.5f; quad[0][1] = renderTargetHeight - 0.5f; quad[0][2] = 0.0f; @@ -1964,10 +2155,10 @@ gl::Error Renderer9::clear(const ClearParameters &clearParams, { mDevice->SetRenderState(D3DRS_ZENABLE, TRUE); mDevice->SetRenderState(D3DRS_ZWRITEENABLE, TRUE); - mDevice->Clear(0, NULL, D3DCLEAR_ZBUFFER, color, depth, stencil); + mDevice->Clear(0, nullptr, D3DCLEAR_ZBUFFER, color, depth, stencil); } - if (mMaskedClearSavedState != NULL) + if (mMaskedClearSavedState != nullptr) { mMaskedClearSavedState->Apply(); } @@ -1988,17 +2179,17 @@ gl::Error Renderer9::clear(const ClearParameters &clearParams, dxClearFlags |= D3DCLEAR_STENCIL; } - mDevice->Clear(0, NULL, dxClearFlags, color, depth, stencil); + mDevice->Clear(0, nullptr, dxClearFlags, color, depth, stencil); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } void Renderer9::markAllStateDirty() { - mAppliedRenderTargetSerial = 0; - mAppliedDepthStencilSerial = 0; - mDepthStencilInitialized = false; + mAppliedRenderTargetSerial = 0; + mAppliedDepthStencilSerial = 0; + mDepthStencilInitialized = false; mRenderTargetDescInitialized = false; mStateManager.forceSetRasterState(); @@ -2021,9 +2212,9 @@ void Renderer9::markAllStateDirty() mCurPixelTextures[i] = angle::DirtyPointer; } - mAppliedIBSerial = 0; - mAppliedVertexShader = NULL; - mAppliedPixelShader = NULL; + mAppliedIBSerial = 0; + mAppliedVertexShader = nullptr; + mAppliedPixelShader = nullptr; mAppliedProgramSerial = 0; mStateManager.forceSetDXUniformsState(); @@ -2051,6 +2242,10 @@ void Renderer9::releaseDeviceResources() for (int i = 0; i < NUM_NULL_COLORBUFFER_CACHE_ENTRIES; i++) { + if (mNullColorbufferCache[i].buffer) + { + mNullColorbufferCache[i].buffer->detach(mDisplay->getProxyContext()); + } SafeDelete(mNullColorbufferCache[i].buffer); } } @@ -2059,19 +2254,7 @@ void Renderer9::releaseDeviceResources() 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; + return FAILED(status); } HRESULT Renderer9::getDeviceStatusCode() @@ -2080,7 +2263,7 @@ HRESULT Renderer9::getDeviceStatusCode() if (mDeviceEx) { - status = mDeviceEx->CheckDeviceState(NULL); + status = mDeviceEx->CheckDeviceState(nullptr); } else if (mDevice) { @@ -2096,16 +2279,16 @@ bool Renderer9::testDeviceResettable() // 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; + case D3DERR_DEVICENOTRESET: + case D3DERR_DEVICEHUNG: + return true; + case D3DERR_DEVICELOST: + return (mDeviceEx != nullptr); + case D3DERR_DEVICEREMOVED: + ASSERT(mDeviceEx != nullptr); + return isRemovedDeviceResettable(); + default: + return false; } } @@ -2115,12 +2298,12 @@ bool Renderer9::resetDevice() D3DPRESENT_PARAMETERS presentParameters = getDefaultPresentParameters(); - HRESULT result = D3D_OK; - bool lost = testDeviceLost(); + 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); + ASSERT(mDeviceEx != nullptr || !removedDevice); for (int attempts = 3; lost && attempts > 0; attempts--) { @@ -2134,16 +2317,16 @@ bool Renderer9::resetDevice() } else if (mDeviceEx) { - Sleep(500); // Give the graphics driver some CPU time - result = mDeviceEx->ResetEx(&presentParameters, NULL); - lost = testDeviceLost(); + Sleep(500); // Give the graphics driver some CPU time + result = mDeviceEx->ResetEx(&presentParameters, nullptr); + lost = testDeviceLost(); } else { result = mDevice->TestCooperativeLevel(); while (result == D3DERR_DEVICELOST) { - Sleep(100); // Give the graphics driver some CPU time + Sleep(100); // Give the graphics driver some CPU time result = mDevice->TestCooperativeLevel(); } @@ -2157,13 +2340,13 @@ bool Renderer9::resetDevice() if (FAILED(result)) { - ERR("Reset/ResetEx failed multiple times: 0x%08X", result); + ERR() << "Reset/ResetEx failed multiple times, " << gl::FmtHR(result); return false; } if (removedDevice && lost) { - ERR("Device lost reset failed multiple times"); + ERR() << "Device lost reset failed multiple times"; return false; } @@ -2171,11 +2354,12 @@ bool Renderer9::resetDevice() if (!removedDevice) { // reset device defaults - initializeDevice(); + if (initializeDevice().isError()) + { + return false; + } } - mDeviceLost = false; - return true; } @@ -2184,15 +2368,16 @@ 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")); + IDirect3D9Ex *d3d9Ex = nullptr; + 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); + success = SUCCEEDED(result); } SafeRelease(d3d9Ex); @@ -2232,20 +2417,22 @@ std::string Renderer9::getRendererDescription() const 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); + 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(); } DeviceIdentifier Renderer9::getAdapterIdentifier() const { - DeviceIdentifier deviceIdentifier = { 0 }; - deviceIdentifier.VendorId = static_cast(mAdapterIdentifier.VendorId); - deviceIdentifier.DeviceId = static_cast(mAdapterIdentifier.DeviceId); - deviceIdentifier.SubSysId = static_cast(mAdapterIdentifier.SubSysId); - deviceIdentifier.Revision = static_cast(mAdapterIdentifier.Revision); - deviceIdentifier.FeatureLevel = 0; + DeviceIdentifier deviceIdentifier = {0}; + deviceIdentifier.VendorId = static_cast(mAdapterIdentifier.VendorId); + deviceIdentifier.DeviceId = static_cast(mAdapterIdentifier.DeviceId); + deviceIdentifier.SubSysId = static_cast(mAdapterIdentifier.SubSysId); + deviceIdentifier.Revision = static_cast(mAdapterIdentifier.Revision); + deviceIdentifier.FeatureLevel = 0; return deviceIdentifier; } @@ -2260,20 +2447,10 @@ unsigned int Renderer9::getReservedFragmentUniformVectors() const return d3d9_gl::GetReservedFragmentUniformVectors(); } -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(); + return (mD3d9Ex != nullptr) && !gl::DebugAnnotationsActive(); } int Renderer9::getMajorShaderModel() const @@ -2298,7 +2475,7 @@ DWORD Renderer9::getCapsDeclTypes() const D3DPOOL Renderer9::getBufferPool(DWORD usage) const { - if (mD3d9Ex != NULL) + if (mD3d9Ex != nullptr) { return D3DPOOL_DEFAULT; } @@ -2313,66 +2490,126 @@ D3DPOOL Renderer9::getBufferPool(DWORD usage) const 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) +gl::Error Renderer9::copyImage2D(const gl::Context *context, + 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.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); + return mBlit->copy2D(context, 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) +gl::Error Renderer9::copyImageCube(const gl::Context *context, + 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.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); + return mBlit->copyCube(context, 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) +gl::Error Renderer9::copyImage3D(const gl::Context *context, + 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); + return gl::InternalError(); } -gl::Error Renderer9::copyImage2DArray(const gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, - const gl::Offset &destOffset, TextureStorage *storage, GLint level) +gl::Error Renderer9::copyImage2DArray(const gl::Context *context, + 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); + return gl::InternalError(); +} + +gl::Error Renderer9::copyTexture(const gl::Context *context, + const gl::Texture *source, + GLint sourceLevel, + const gl::Rectangle &sourceRect, + GLenum destFormat, + const gl::Offset &destOffset, + TextureStorage *storage, + GLenum destTarget, + GLint destLevel, + bool unpackFlipY, + bool unpackPremultiplyAlpha, + bool unpackUnmultiplyAlpha) +{ + RECT rect; + rect.left = sourceRect.x; + rect.top = sourceRect.y; + rect.right = sourceRect.x + sourceRect.width; + rect.bottom = sourceRect.y + sourceRect.height; + + return mBlit->copyTexture(context, source, sourceLevel, rect, destFormat, destOffset, storage, + destTarget, destLevel, unpackFlipY, unpackPremultiplyAlpha, + unpackUnmultiplyAlpha); } -gl::Error Renderer9::createRenderTarget(int width, int height, GLenum format, GLsizei samples, RenderTargetD3D **outRT) +gl::Error Renderer9::copyCompressedTexture(const gl::Context *context, + const gl::Texture *source, + GLint sourceLevel, + TextureStorage *storage, + GLint destLevel) +{ + UNIMPLEMENTED(); + return gl::InternalError(); +} + +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); + const gl::TextureCaps &textureCaps = getNativeTextureCaps().get(format); + GLuint supportedSamples = textureCaps.getNearestSamples(samples); IDirect3DTexture9 *texture = nullptr; - IDirect3DSurface9 *renderTarget = NULL; + IDirect3DSurface9 *renderTarget = nullptr; if (width > 0 && height > 0) { bool requiresInitialization = false; - HRESULT result = D3DERR_INVALIDCALL; + HRESULT result = D3DERR_INVALIDCALL; - const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format); + const gl::InternalFormat &formatInfo = gl::GetSizedInternalFormatInfo(format); if (formatInfo.depthBits > 0 || formatInfo.stencilBits > 0) { - result = mDevice->CreateDepthStencilSurface(width, height, d3d9FormatInfo.renderFormat, - gl_d3d9::GetMultisampleType(supportedSamples), - 0, FALSE, &renderTarget, NULL); + result = mDevice->CreateDepthStencilSurface( + width, height, d3d9FormatInfo.renderFormat, + gl_d3d9::GetMultisampleType(supportedSamples), 0, FALSE, &renderTarget, nullptr); } else { @@ -2398,25 +2635,25 @@ gl::Error Renderer9::createRenderTarget(int width, int height, GLenum format, GL 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); + return gl::OutOfMemory() << "Failed to create render target, " << gl::FmtHR(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; + // 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 = nullptr; mDevice->GetRenderTarget(0, &prevRenderTarget); mDevice->SetRenderTarget(0, renderTarget); - mDevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_RGBA(0, 0, 0, 255), 0.0f, 0); + mDevice->Clear(0, nullptr, D3DCLEAR_TARGET, D3DCOLOR_RGBA(0, 0, 0, 255), 0.0f, 0); mDevice->SetRenderTarget(0, prevRenderTarget); } } *outRT = new TextureRenderTarget9(texture, 0, renderTarget, format, width, height, 1, supportedSamples); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } gl::Error Renderer9::createRenderTargetCopy(RenderTargetD3D *source, RenderTargetD3D **outRT) @@ -2424,7 +2661,7 @@ gl::Error Renderer9::createRenderTargetCopy(RenderTargetD3D *source, RenderTarge ASSERT(source != nullptr); RenderTargetD3D *newRT = nullptr; - gl::Error error = createRenderTarget(source->getWidth(), source->getHeight(), + gl::Error error = createRenderTarget(source->getWidth(), source->getHeight(), source->getInternalFormat(), source->getSamples(), &newRT); if (error.isError()) { @@ -2439,31 +2676,16 @@ gl::Error Renderer9::createRenderTargetCopy(RenderTargetD3D *source, RenderTarge if (FAILED(result)) { ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to copy render target, result: 0x%X.", result); + return gl::OutOfMemory() << "Failed to copy render target, " << gl::FmtHR(result); } *outRT = newRT; - return gl::Error(GL_NO_ERROR); -} - -FramebufferImpl *Renderer9::createFramebuffer(const gl::Framebuffer::Data &data) -{ - return new Framebuffer9(data, this); -} - -ShaderImpl *Renderer9::createShader(const gl::Shader::Data &data) -{ - return new ShaderD3D(data); + return gl::NoError(); } -ProgramImpl *Renderer9::createProgram(const gl::Program::Data &data) -{ - return new ProgramD3D(data, this); -} - -gl::Error Renderer9::loadExecutable(const void *function, +gl::Error Renderer9::loadExecutable(const uint8_t *function, size_t length, - ShaderType type, + gl::ShaderType type, const std::vector &streamOutVaryings, bool separatedOutputBuffers, ShaderExecutableD3D **outExecutable) @@ -2473,10 +2695,10 @@ gl::Error Renderer9::loadExecutable(const void *function, switch (type) { - case SHADER_VERTEX: + case gl::SHADER_VERTEX: { - IDirect3DVertexShader9 *vshader = NULL; - gl::Error error = createVertexShader((DWORD*)function, length, &vshader); + IDirect3DVertexShader9 *vshader = nullptr; + gl::Error error = createVertexShader((DWORD *)function, length, &vshader); if (error.isError()) { return error; @@ -2484,10 +2706,10 @@ gl::Error Renderer9::loadExecutable(const void *function, *outExecutable = new ShaderExecutable9(function, length, vshader); } break; - case SHADER_PIXEL: + case gl::SHADER_FRAGMENT: { - IDirect3DPixelShader9 *pshader = NULL; - gl::Error error = createPixelShader((DWORD*)function, length, &pshader); + IDirect3DPixelShader9 *pshader = nullptr; + gl::Error error = createPixelShader((DWORD *)function, length, &pshader); if (error.isError()) { return error; @@ -2495,41 +2717,45 @@ gl::Error Renderer9::loadExecutable(const void *function, *outExecutable = new ShaderExecutable9(function, length, pshader); } break; - default: - UNREACHABLE(); - return gl::Error(GL_INVALID_OPERATION); + default: + UNREACHABLE(); + return gl::InternalError(); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } gl::Error Renderer9::compileToExecutable(gl::InfoLog &infoLog, const std::string &shaderHLSL, - ShaderType type, + gl::ShaderType type, const std::vector &streamOutVaryings, bool separatedOutputBuffers, - const D3DCompilerWorkarounds &workarounds, + const angle::CompilerWorkaroundsD3D &workarounds, ShaderExecutableD3D **outExectuable) { // Transform feedback is not supported in ES2 or D3D9 ASSERT(streamOutVaryings.empty()); - const char *profileType = NULL; + std::stringstream profileStream; + switch (type) { - case SHADER_VERTEX: - profileType = "vs"; - break; - case SHADER_PIXEL: - profileType = "ps"; - break; - default: - UNREACHABLE(); - return gl::Error(GL_INVALID_OPERATION); + case gl::SHADER_VERTEX: + profileStream << "vs"; + break; + case gl::SHADER_FRAGMENT: + profileStream << "ps"; + break; + default: + UNREACHABLE(); + return gl::InternalError(); } - unsigned int profileMajorVersion = (getMajorShaderModel() >= 3) ? 3 : 2; - unsigned int profileMinorVersion = 0; - std::string profile = FormatString("%s_%u_%u", profileType, profileMajorVersion, profileMinorVersion); + + profileStream << "_" << ((getMajorShaderModel() >= 3) ? 3 : 2); + profileStream << "_" + << "0"; + + std::string profile = profileStream.str(); UINT flags = ANGLE_COMPILE_OPTIMIZATION_LEVEL; @@ -2551,31 +2777,35 @@ gl::Error Renderer9::compileToExecutable(gl::InfoLog &infoLog, 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. + // 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, "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; + ID3DBlob *binary = nullptr; std::string debugInfo; - gl::Error error = mCompiler.compileToBinary(infoLog, shaderHLSL, profile, configs, NULL, &binary, &debugInfo); + gl::Error error = mCompiler.compileToBinary(infoLog, shaderHLSL, profile, configs, nullptr, + &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. + // 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); + *outExectuable = nullptr; + return gl::NoError(); } - error = loadExecutable(binary->GetBufferPointer(), binary->GetBufferSize(), type, - streamOutVaryings, separatedOutputBuffers, outExectuable); + error = loadExecutable(reinterpret_cast(binary->GetBufferPointer()), + binary->GetBufferSize(), type, streamOutVaryings, separatedOutputBuffers, + outExectuable); SafeRelease(binary); if (error.isError()) @@ -2588,7 +2818,12 @@ gl::Error Renderer9::compileToExecutable(gl::InfoLog &infoLog, (*outExectuable)->appendDebugInfo(debugInfo); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); +} + +gl::Error Renderer9::ensureHLSLCompilerInitialized() +{ + return mCompiler.ensureInitialized(); } UniformStorageD3D *Renderer9::createUniformStorage(size_t storageSize) @@ -2603,7 +2838,7 @@ gl::Error Renderer9::boxFilter(IDirect3DSurface9 *source, IDirect3DSurface9 *des D3DPOOL Renderer9::getTexturePool(DWORD usage) const { - if (mD3d9Ex != NULL) + if (mD3d9Ex != nullptr) { return D3DPOOL_DEFAULT; } @@ -2618,7 +2853,9 @@ D3DPOOL Renderer9::getTexturePool(DWORD usage) const return D3DPOOL_DEFAULT; } -gl::Error Renderer9::copyToRenderTarget(IDirect3DSurface9 *dest, IDirect3DSurface9 *source, bool fromManaged) +gl::Error Renderer9::copyToRenderTarget(IDirect3DSurface9 *dest, + IDirect3DSurface9 *source, + bool fromManaged) { ASSERT(source && dest); @@ -2630,28 +2867,34 @@ gl::Error Renderer9::copyToRenderTarget(IDirect3DSurface9 *dest, IDirect3DSurfac source->GetDesc(&desc); IDirect3DSurface9 *surf = 0; - result = mDevice->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format, D3DPOOL_SYSTEMMEM, &surf, NULL); + result = mDevice->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format, + D3DPOOL_SYSTEMMEM, &surf, nullptr); if (SUCCEEDED(result)) { - Image9::copyLockableSurfaces(surf, source); - result = mDevice->UpdateSurface(surf, NULL, dest, NULL); + ANGLE_TRY(Image9::copyLockableSurfaces(surf, source)); + result = mDevice->UpdateSurface(surf, nullptr, dest, nullptr); SafeRelease(surf); } } else { endScene(); - result = mDevice->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE); + result = mDevice->StretchRect(source, nullptr, dest, nullptr, 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::OutOfMemory() << "Failed to blit internal texture, " << gl::FmtHR(result); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); +} + +RendererClass Renderer9::getRendererClass() const +{ + return RENDERER_D3D9; } ImageD3D *Renderer9::createImage() @@ -2659,18 +2902,34 @@ ImageD3D *Renderer9::createImage() return new Image9(this); } -gl::Error Renderer9::generateMipmap(ImageD3D *dest, ImageD3D *src) +gl::Error Renderer9::generateMipmap(const gl::Context *context, ImageD3D *dest, ImageD3D *src) { Image9 *src9 = GetAs(src); Image9 *dst9 = GetAs(dest); return Image9::generateMipmap(dst9, src9); } -gl::Error Renderer9::generateMipmapsUsingD3D(TextureStorage *storage, - const gl::TextureState &textureState) +gl::Error Renderer9::generateMipmapUsingD3D(const gl::Context *context, + TextureStorage *storage, + const gl::TextureState &textureState) { UNREACHABLE(); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); +} + +gl::Error Renderer9::copyImage(const gl::Context *context, + ImageD3D *dest, + ImageD3D *source, + const gl::Rectangle &sourceRect, + const gl::Offset &destOffset, + bool unpackFlipY, + bool unpackPremultiplyAlpha, + bool unpackUnmultiplyAlpha) +{ + Image9 *dest9 = GetAs(dest); + Image9 *src9 = GetAs(source); + return Image9::CopyImage(context, dest9, src9, sourceRect, destOffset, unpackFlipY, + unpackPremultiplyAlpha, unpackUnmultiplyAlpha); } TextureStorage *Renderer9::createTextureStorage2D(SwapChainD3D *swapChain) @@ -2679,59 +2938,83 @@ TextureStorage *Renderer9::createTextureStorage2D(SwapChainD3D *swapChain) return new TextureStorage9_2D(this, swapChain9); } -TextureStorage *Renderer9::createTextureStorageEGLImage(EGLImageD3D *eglImage) +TextureStorage *Renderer9::createTextureStorageEGLImage(EGLImageD3D *eglImage, + RenderTargetD3D *renderTargetD3D) +{ + return new TextureStorage9_EGLImage(this, eglImage, GetAs(renderTargetD3D)); +} + +TextureStorage *Renderer9::createTextureStorageExternal( + egl::Stream *stream, + const egl::Stream::GLTextureDescription &desc) { - return new TextureStorage9_EGLImage(this, eglImage); + UNIMPLEMENTED(); + return nullptr; } -TextureStorage *Renderer9::createTextureStorage2D(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels, bool hintLevelZeroOnly) +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) +TextureStorage *Renderer9::createTextureStorageCube(GLenum internalformat, + bool renderTarget, + int size, + int levels, + bool hintLevelZeroOnly) { - return new TextureStorage9_Cube(this, internalformat, renderTarget, size, levels, 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) +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; + return nullptr; } -TextureStorage *Renderer9::createTextureStorage2DArray(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth, int levels) +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; + return nullptr; } -TextureImpl *Renderer9::createTexture(GLenum target) +TextureStorage *Renderer9::createTextureStorage2DMultisample(GLenum internalformat, + GLsizei width, + GLsizei height, + int levels, + int samples, + bool fixedSampleLocations) { - switch(target) - { - case GL_TEXTURE_2D: return new TextureD3D_2D(this); - case GL_TEXTURE_CUBE_MAP: return new TextureD3D_Cube(this); - default: UNREACHABLE(); - } + // 2D multisampled textures are not supported by the D3D9 backend. + 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; + adapterLuid->LowPart = 0; if (mD3d9Ex) { @@ -2752,6 +3035,40 @@ GLenum Renderer9::getVertexComponentType(gl::VertexFormatType vertexFormatType) return d3d9::GetVertexFormatInfo(getCapsDeclTypes(), vertexFormatType).componentType; } +gl::ErrorOrResult Renderer9::getVertexSpaceRequired(const gl::VertexAttribute &attrib, + const gl::VertexBinding &binding, + GLsizei count, + GLsizei instances) const +{ + if (!attrib.enabled) + { + return 16u; + } + + gl::VertexFormatType vertexFormatType = gl::GetVertexFormatType(attrib, GL_FLOAT); + const d3d9::VertexFormat &d3d9VertexInfo = + d3d9::GetVertexFormatInfo(getCapsDeclTypes(), vertexFormatType); + + unsigned int elementCount = 0; + const unsigned int divisor = binding.getDivisor(); + if (instances == 0 || divisor == 0) + { + elementCount = static_cast(count); + } + else + { + // Round up to divisor, if possible + elementCount = UnsignedCeilDivide(static_cast(instances), divisor); + } + + if (d3d9VertexInfo.outputElementSize > std::numeric_limits::max() / elementCount) + { + return gl::OutOfMemory() << "New vertex buffer size would result in an overflow."; + } + + return static_cast(d3d9VertexInfo.outputElementSize) * elementCount; +} + void Renderer9::generateCaps(gl::Caps *outCaps, gl::TextureCapsMap *outTextureCaps, gl::Extensions *outExtensions, @@ -2761,31 +3078,11 @@ void Renderer9::generateCaps(gl::Caps *outCaps, outExtensions, outLimitations); } -WorkaroundsD3D Renderer9::generateWorkarounds() const +angle::WorkaroundsD3D Renderer9::generateWorkarounds() const { return d3d9::GenerateWorkarounds(); } -void Renderer9::createAnnotator() -{ - mAnnotator = new DebugAnnotator9(); -} - -gl::Error Renderer9::clearTextures(gl::SamplerType samplerType, size_t rangeStart, size_t rangeEnd) -{ - // TODO(jmadill): faster way? - for (size_t samplerIndex = rangeStart; samplerIndex < rangeEnd; samplerIndex++) - { - gl::Error error = setTexture(samplerType, static_cast(samplerIndex), nullptr); - if (error.isError()) - { - return error; - } - } - - return gl::Error(GL_NO_ERROR); -} - egl::Error Renderer9::getEGLDevice(DeviceImpl **device) { if (mEGLDevice == nullptr) @@ -2803,14 +3100,211 @@ egl::Error Renderer9::getEGLDevice(DeviceImpl **device) } *device = static_cast(mEGLDevice); - return egl::Error(EGL_SUCCESS); + return egl::NoError(); } Renderer9::CurSamplerState::CurSamplerState() - : forceSet(true), - baseLevel(std::numeric_limits::max()), - samplerState() + : forceSet(true), baseLevel(std::numeric_limits::max()), samplerState() +{ +} + +gl::Error Renderer9::genericDrawElements(const gl::Context *context, + GLenum mode, + GLsizei count, + GLenum type, + const void *indices, + GLsizei instances) +{ + const auto &data = context->getContextState(); + gl::Program *program = context->getGLState().getProgram(); + ASSERT(program != nullptr); + ProgramD3D *programD3D = GetImplAs(program); + bool usesPointSize = programD3D->usesPointSize(); + + programD3D->updateSamplerMapping(); + + if (!applyPrimitiveType(mode, count, usesPointSize)) + { + return gl::NoError(); + } + + ANGLE_TRY(updateState(context, mode)); + ANGLE_TRY(applyTextures(context)); + ANGLE_TRY(applyShaders(context, mode)); + + if (!skipDraw(data.getState(), mode)) + { + ANGLE_TRY(drawElementsImpl(context, mode, count, type, indices, instances)); + } + + return gl::NoError(); +} + +gl::Error Renderer9::genericDrawArrays(const gl::Context *context, + GLenum mode, + GLint first, + GLsizei count, + GLsizei instances) +{ + gl::Program *program = context->getGLState().getProgram(); + ASSERT(program != nullptr); + ProgramD3D *programD3D = GetImplAs(program); + bool usesPointSize = programD3D->usesPointSize(); + + programD3D->updateSamplerMapping(); + + if (!applyPrimitiveType(mode, count, usesPointSize)) + { + return gl::NoError(); + } + + ANGLE_TRY(updateState(context, mode)); + ANGLE_TRY(applyVertexBuffer(context, mode, first, count, instances, nullptr)); + ANGLE_TRY(applyTextures(context)); + ANGLE_TRY(applyShaders(context, mode)); + + if (!skipDraw(context->getGLState(), mode)) + { + ANGLE_TRY(drawArraysImpl(context, mode, first, count, instances)); + } + + return gl::NoError(); +} + +FramebufferImpl *Renderer9::createDefaultFramebuffer(const gl::FramebufferState &state) { + return new Framebuffer9(state, this); } +gl::Version Renderer9::getMaxSupportedESVersion() const +{ + return gl::Version(2, 0); +} + +gl::Error Renderer9::clearRenderTarget(RenderTargetD3D *renderTarget, + const gl::ColorF &clearColorValue, + const float clearDepthValue, + const unsigned int clearStencilValue) +{ + D3DCOLOR color = + D3DCOLOR_ARGB(gl::unorm<8>(clearColorValue.alpha), gl::unorm<8>(clearColorValue.red), + gl::unorm<8>(clearColorValue.green), gl::unorm<8>(clearColorValue.blue)); + float depth = clearDepthValue; + DWORD stencil = clearStencilValue & 0x000000FF; + + unsigned int renderTargetSerial = renderTarget->getSerial(); + RenderTarget9 *renderTarget9 = GetAs(renderTarget); + IDirect3DSurface9 *renderTargetSurface = renderTarget9->getSurface(); + ASSERT(renderTargetSurface); + + DWORD dxClearFlags = 0; + + const gl::InternalFormat &internalFormatInfo = + gl::GetSizedInternalFormatInfo(renderTarget->getInternalFormat()); + if (internalFormatInfo.depthBits > 0 || internalFormatInfo.stencilBits > 0) + { + dxClearFlags = D3DCLEAR_ZBUFFER | D3DCLEAR_STENCIL; + if (mAppliedDepthStencilSerial != renderTargetSerial) + { + mDevice->SetDepthStencilSurface(renderTargetSurface); + } + } + else + { + dxClearFlags = D3DCLEAR_TARGET; + if (mAppliedRenderTargetSerial != renderTargetSerial) + { + mDevice->SetRenderTarget(0, renderTargetSurface); + } + } + SafeRelease(renderTargetSurface); + + D3DVIEWPORT9 viewport; + viewport.X = 0; + viewport.Y = 0; + viewport.Width = renderTarget->getWidth(); + viewport.Height = renderTarget->getHeight(); + mDevice->SetViewport(&viewport); + + mDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE); + + mDevice->Clear(0, nullptr, dxClearFlags, color, depth, stencil); + + markAllStateDirty(); + + return gl::NoError(); } + +bool Renderer9::canSelectViewInVertexShader() const +{ + return false; +} + +// 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). +// Sampler mapping needs to be up-to-date on the program object before this is called. +gl::Error Renderer9::applyTextures(const gl::Context *context, gl::SamplerType shaderType) +{ + const auto &glState = context->getGLState(); + const auto &caps = context->getCaps(); + ProgramD3D *programD3D = GetImplAs(glState.getProgram()); + + ASSERT(!programD3D->isSamplerMappingDirty()); + + // TODO(jmadill): Use the Program's sampler bindings. + const auto &completeTextures = glState.getCompleteTextureCache(); + + unsigned int samplerRange = programD3D->getUsedSamplerRange(shaderType); + for (unsigned int samplerIndex = 0; samplerIndex < samplerRange; samplerIndex++) + { + GLint textureUnit = programD3D->getSamplerMapping(shaderType, samplerIndex, caps); + ASSERT(textureUnit != -1); + gl::Texture *texture = completeTextures[textureUnit]; + + // A nullptr texture indicates incomplete. + if (texture) + { + gl::Sampler *samplerObject = glState.getSampler(textureUnit); + + const gl::SamplerState &samplerState = + samplerObject ? samplerObject->getSamplerState() : texture->getSamplerState(); + + ANGLE_TRY(setSamplerState(context, shaderType, samplerIndex, texture, samplerState)); + ANGLE_TRY(setTexture(context, shaderType, samplerIndex, texture)); + } + else + { + GLenum textureType = programD3D->getSamplerTextureType(shaderType, samplerIndex); + + // Texture is not sampler complete or it is in use by the framebuffer. Bind the + // incomplete texture. + gl::Texture *incompleteTexture = nullptr; + ANGLE_TRY(getIncompleteTexture(context, textureType, &incompleteTexture)); + ANGLE_TRY(setSamplerState(context, shaderType, samplerIndex, incompleteTexture, + incompleteTexture->getSamplerState())); + ANGLE_TRY(setTexture(context, shaderType, samplerIndex, incompleteTexture)); + } + } + + // Set all the remaining textures to NULL + size_t samplerCount = (shaderType == gl::SAMPLER_PIXEL) ? caps.maxTextureImageUnits + : caps.maxVertexTextureImageUnits; + + // TODO(jmadill): faster way? + for (size_t samplerIndex = samplerRange; samplerIndex < samplerCount; samplerIndex++) + { + ANGLE_TRY(setTexture(context, shaderType, static_cast(samplerIndex), nullptr)); + } + + return gl::NoError(); +} + +gl::Error Renderer9::applyTextures(const gl::Context *context) +{ + ANGLE_TRY(applyTextures(context, gl::SAMPLER_VERTEX)); + ANGLE_TRY(applyTextures(context, gl::SAMPLER_PIXEL)); + return gl::NoError(); +} + +} // namespace rx diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Renderer9.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Renderer9.h index a0dfecb02e..9ddee45f0f 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Renderer9.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Renderer9.h @@ -12,12 +12,13 @@ #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/RendererD3D.h" #include "libANGLE/renderer/d3d/d3d9/DebugAnnotator9.h" #include "libANGLE/renderer/d3d/d3d9/ShaderCache.h" -#include "libANGLE/renderer/d3d/d3d9/VertexDeclarationCache.h" #include "libANGLE/renderer/d3d/d3d9/StateManager9.h" +#include "libANGLE/renderer/d3d/d3d9/VertexDeclarationCache.h" +#include "libANGLE/renderer/driver_utils.h" namespace gl { @@ -32,6 +33,7 @@ class AttributeMap; namespace rx { class Blit9; +class Context9; class IndexDataManager; class ProgramD3D; class StreamingIndexBufferInterface; @@ -65,184 +67,270 @@ class Renderer9 : public RendererD3D { public: explicit Renderer9(egl::Display *display); - virtual ~Renderer9(); + ~Renderer9() override; egl::Error initialize() override; - virtual bool resetDevice(); + bool resetDevice() override; - egl::ConfigSet generateConfigs() const override; + egl::ConfigSet generateConfigs() override; void generateDisplayExtensions(egl::DisplayExtensions *outExtensions) const override; void startScene(); void endScene(); - gl::Error flush() override; - gl::Error finish() override; + gl::Error flush(); + gl::Error finish(); - SwapChainD3D *createSwapChain(NativeWindow nativeWindow, + bool isValidNativeWindow(EGLNativeWindowType window) const override; + NativeWindowD3D *createNativeWindow(EGLNativeWindowType window, + const egl::Config *config, + const egl::AttributeMap &attribs) const override; + + SwapChainD3D *createSwapChain(NativeWindowD3D *nativeWindow, HANDLE shareHandle, + IUnknown *d3dTexture, GLenum backBufferFormat, GLenum depthBufferFormat, - EGLint orientation) override; - - CompilerImpl *createCompiler() override; + EGLint orientation, + EGLint samples) override; + egl::Error getD3DTextureInfo(const egl::Config *configuration, + IUnknown *d3dTexture, + EGLint *width, + EGLint *height, + GLenum *fboFormat) const override; + egl::Error validateShareHandle(const egl::Config *config, + HANDLE shareHandle, + const egl::AttributeMap &attribs) const override; + + ContextImpl *createContext(const gl::ContextState &state) override; gl::Error allocateEventQuery(IDirect3DQuery9 **outQuery); - void freeEventQuery(IDirect3DQuery9* query); + 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); + 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 std::vector &vertexUniformBuffers, - const std::vector &fragmentUniformBuffers) override; - - gl::Error updateState(const gl::Data &data, GLenum drawMode) override; + HRESULT createIndexBuffer(UINT Length, + DWORD Usage, + D3DFORMAT Format, + IDirect3DIndexBuffer9 **ppIndexBuffer); + gl::Error setSamplerState(const gl::Context *context, + gl::SamplerType type, + int index, + gl::Texture *texture, + const gl::SamplerState &sampler); + gl::Error setTexture(const gl::Context *context, + gl::SamplerType type, + int index, + gl::Texture *texture); + + gl::Error updateState(const gl::Context *context, GLenum drawMode); void setScissorRectangle(const gl::Rectangle &scissor, bool enabled); - void setViewport(const gl::Caps *caps, - const gl::Rectangle &viewport, + 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 *colorAttachment, + gl::Error applyRenderTarget(const gl::Context *context, const gl::Framebuffer *frameBuffer); + gl::Error applyRenderTarget(const gl::Context *context, + const gl::FramebufferAttachment *colorAttachment, const gl::FramebufferAttachment *depthStencilAttachment); - gl::Error applyUniforms(const ProgramD3D &programD3D, - GLenum drawMode, - const std::vector &uniformArray) override; - 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, - TranslatedIndexData *indexInfo); - gl::Error applyIndexBuffer(const gl::Data &data, - const GLvoid *indices, + gl::Error applyUniforms(ProgramD3D *programD3D); + bool applyPrimitiveType(GLenum primitiveType, GLsizei elementCount, bool usesPointSize); + gl::Error applyVertexBuffer(const gl::Context *context, + GLenum mode, + GLint first, + GLsizei count, + GLsizei instances, + TranslatedIndexData *indexInfo); + gl::Error applyIndexBuffer(const gl::Context *context, + const void *indices, GLsizei count, GLenum mode, GLenum type, - TranslatedIndexData *indexInfo) override; + TranslatedIndexData *indexInfo); - void applyTransformFeedbackBuffers(const gl::State &state) override; - - gl::Error clear(const ClearParameters &clearParams, + gl::Error clear(const gl::Context *context, + const ClearParameters &clearParams, const gl::FramebufferAttachment *colorBuffer, const gl::FramebufferAttachment *depthStencilBuffer); - virtual void markAllStateDirty(); + void markAllStateDirty(); // lost device bool testDeviceLost() override; bool testDeviceResettable() override; VendorID getVendorId() const; - std::string getRendererDescription() const override; + std::string getRendererDescription() const; DeviceIdentifier getAdapterIdentifier() const override; IDirect3DDevice9 *getDevice() { return mDevice; } void *getD3DDevice() override; - virtual unsigned int getReservedVertexUniformVectors() const; - virtual unsigned int getReservedFragmentUniformVectors() const; - virtual unsigned int getReservedVertexUniformBuffers() const; - virtual unsigned int getReservedFragmentUniformBuffers() const; + unsigned int getReservedVertexUniformVectors() const; + unsigned int getReservedFragmentUniformVectors() const; bool getShareHandleSupport() const; - virtual int getMajorShaderModel() const; + int getMajorShaderModel() const override; 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); + gl::Error copyImage2D(const gl::Context *context, + const gl::Framebuffer *framebuffer, + const gl::Rectangle &sourceRect, + GLenum destFormat, + const gl::Offset &destOffset, + TextureStorage *storage, + GLint level) override; + gl::Error copyImageCube(const gl::Context *context, + const gl::Framebuffer *framebuffer, + const gl::Rectangle &sourceRect, + GLenum destFormat, + const gl::Offset &destOffset, + TextureStorage *storage, + GLenum target, + GLint level) override; + gl::Error copyImage3D(const gl::Context *context, + const gl::Framebuffer *framebuffer, + const gl::Rectangle &sourceRect, + GLenum destFormat, + const gl::Offset &destOffset, + TextureStorage *storage, + GLint level) override; + gl::Error copyImage2DArray(const gl::Context *context, + const gl::Framebuffer *framebuffer, + const gl::Rectangle &sourceRect, + GLenum destFormat, + const gl::Offset &destOffset, + TextureStorage *storage, + GLint level) override; + + gl::Error copyTexture(const gl::Context *context, + const gl::Texture *source, + GLint sourceLevel, + const gl::Rectangle &sourceRect, + GLenum destFormat, + const gl::Offset &destOffset, + TextureStorage *storage, + GLenum destTarget, + GLint destLevel, + bool unpackFlipY, + bool unpackPremultiplyAlpha, + bool unpackUnmultiplyAlpha) override; + gl::Error copyCompressedTexture(const gl::Context *context, + const gl::Texture *source, + GLint sourceLevel, + TextureStorage *storage, + GLint destLevel) override; // RenderTarget creation - virtual gl::Error createRenderTarget(int width, int height, GLenum format, GLsizei samples, RenderTargetD3D **outRT); + gl::Error createRenderTarget(int width, + int height, + GLenum format, + GLsizei samples, + RenderTargetD3D **outRT) override; gl::Error createRenderTargetCopy(RenderTargetD3D *source, RenderTargetD3D **outRT) override; - // Framebuffer creation - FramebufferImpl *createFramebuffer(const gl::Framebuffer::Data &data) override; - - // Shader creation - ShaderImpl *createShader(const gl::Shader::Data &data) override; - ProgramImpl *createProgram(const gl::Program::Data &data) override; - // Shader operations - gl::Error loadExecutable(const void *function, + gl::Error loadExecutable(const uint8_t *function, size_t length, - ShaderType type, + gl::ShaderType type, const std::vector &streamOutVaryings, bool separatedOutputBuffers, ShaderExecutableD3D **outExecutable) override; gl::Error compileToExecutable(gl::InfoLog &infoLog, const std::string &shaderHLSL, - ShaderType type, + gl::ShaderType type, const std::vector &streamOutVaryings, bool separatedOutputBuffers, - const D3DCompilerWorkarounds &workarounds, + const angle::CompilerWorkaroundsD3D &workarounds, ShaderExecutableD3D **outExectuable) override; + gl::Error ensureHLSLCompilerInitialized() override; + UniformStorageD3D *createUniformStorage(size_t storageSize) override; // Image operations - virtual ImageD3D *createImage(); - gl::Error generateMipmap(ImageD3D *dest, ImageD3D *source) override; - gl::Error generateMipmapsUsingD3D(TextureStorage *storage, - const gl::TextureState &textureState) override; - virtual TextureStorage *createTextureStorage2D(SwapChainD3D *swapChain); - TextureStorage *createTextureStorageEGLImage(EGLImageD3D *eglImage) override; - 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(); + ImageD3D *createImage() override; + gl::Error generateMipmap(const gl::Context *context, ImageD3D *dest, ImageD3D *source) override; + gl::Error generateMipmapUsingD3D(const gl::Context *context, + TextureStorage *storage, + const gl::TextureState &textureState) override; + gl::Error copyImage(const gl::Context *context, + ImageD3D *dest, + ImageD3D *source, + const gl::Rectangle &sourceRect, + const gl::Offset &destOffset, + bool unpackFlipY, + bool unpackPremultiplyAlpha, + bool unpackUnmultiplyAlpha) override; + TextureStorage *createTextureStorage2D(SwapChainD3D *swapChain) override; + TextureStorage *createTextureStorageEGLImage(EGLImageD3D *eglImage, + RenderTargetD3D *renderTargetD3D) override; + TextureStorage *createTextureStorageExternal( + egl::Stream *stream, + const egl::Stream::GLTextureDescription &desc) override; + TextureStorage *createTextureStorage2D(GLenum internalformat, + bool renderTarget, + GLsizei width, + GLsizei height, + int levels, + bool hintLevelZeroOnly) override; + TextureStorage *createTextureStorageCube(GLenum internalformat, + bool renderTarget, + int size, + int levels, + bool hintLevelZeroOnly) override; + TextureStorage *createTextureStorage3D(GLenum internalformat, + bool renderTarget, + GLsizei width, + GLsizei height, + GLsizei depth, + int levels) override; + TextureStorage *createTextureStorage2DArray(GLenum internalformat, + bool renderTarget, + GLsizei width, + GLsizei height, + GLsizei depth, + int levels) override; + + TextureStorage *createTextureStorage2DMultisample(GLenum internalformat, + GLsizei width, + GLsizei height, + int levels, + int samples, + bool fixedSampleLocations) override; // Buffer creation - virtual BufferImpl *createBuffer(); - virtual VertexBuffer *createVertexBuffer(); - virtual IndexBuffer *createIndexBuffer(); + VertexBuffer *createVertexBuffer() override; + IndexBuffer *createIndexBuffer() override; - // Vertex Array creation - VertexArrayImpl *createVertexArray(const gl::VertexArray::Data &data) override; - - // Query and Fence creation - virtual QueryImpl *createQuery(GLenum type); - virtual FenceNVImpl *createFenceNV(); - virtual FenceSyncImpl *createFenceSync(); - - // Transform Feedback creation - virtual TransformFeedbackImpl* createTransformFeedback(); + // Stream Creation + StreamProducerImpl *createStreamProducerD3DTextureNV12( + egl::Stream::ConsumerType consumerType, + const egl::AttributeMap &attribs) override; // 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 syncState(const gl::State &state, const gl::State::DirtyBits &bitmask) override; + bool supportsFastCopyBufferToTexture(GLenum internalFormat) const override; + gl::Error fastCopyBufferToTexture(const gl::Context *context, + const gl::PixelUnpackState &unpack, + unsigned int offset, + RenderTargetD3D *destRenderTarget, + GLenum destinationFormat, + GLenum sourcePixelsType, + const gl::Box &destArea) override; // D3D9-renderer specific methods gl::Error boxFilter(IDirect3DSurface9 *source, IDirect3DSurface9 *dest); @@ -250,42 +338,82 @@ class Renderer9 : public RendererD3D D3DPOOL getTexturePool(DWORD usage) const; bool getLUID(LUID *adapterLuid) const override; - VertexConversionType getVertexConversionType(gl::VertexFormatType vertexFormatType) const override; + VertexConversionType getVertexConversionType( + gl::VertexFormatType vertexFormatType) const override; GLenum getVertexComponentType(gl::VertexFormatType vertexFormatType) const override; - gl::Error copyToRenderTarget(IDirect3DSurface9 *dest, IDirect3DSurface9 *source, bool fromManaged); + // Warning: you should ensure binding really matches attrib.bindingIndex before using this + // function. + gl::ErrorOrResult getVertexSpaceRequired(const gl::VertexAttribute &attrib, + const gl::VertexBinding &binding, + GLsizei count, + GLsizei instances) const override; - RendererClass getRendererClass() const override { return RENDERER_D3D9; } + gl::Error copyToRenderTarget(IDirect3DSurface9 *dest, + IDirect3DSurface9 *source, + bool fromManaged); + + RendererClass getRendererClass() const override; D3DDEVTYPE getD3D9DeviceType() const { return mDeviceType; } egl::Error getEGLDevice(DeviceImpl **device) override; - protected: - void createAnnotator() override; - gl::Error clearTextures(gl::SamplerType samplerType, size_t rangeStart, size_t rangeEnd) override; - gl::Error applyShadersImpl(const gl::Data &data, GLenum drawMode) override; + StateManager9 *getStateManager() { return &mStateManager; } + + gl::Error genericDrawArrays(const gl::Context *context, + GLenum mode, + GLint first, + GLsizei count, + GLsizei instances); + + gl::Error genericDrawElements(const gl::Context *context, + GLenum mode, + GLsizei count, + GLenum type, + const void *indices, + GLsizei instances); + + // Necessary hack for default framebuffers in D3D. + FramebufferImpl *createDefaultFramebuffer(const gl::FramebufferState &state) override; + + DebugAnnotator9 *getAnnotator() { return &mAnnotator; } + + gl::Version getMaxSupportedESVersion() const override; + + gl::Error clearRenderTarget(RenderTargetD3D *renderTarget, + const gl::ColorF &clearColorValue, + const float clearDepthValue, + const unsigned int clearStencilValue) override; + + bool canSelectViewInVertexShader() const override; private: - gl::Error drawArraysImpl(const gl::Data &data, + gl::Error drawArraysImpl(const gl::Context *context, GLenum mode, + GLint startVertex, GLsizei count, - GLsizei instances) override; - gl::Error drawElementsImpl(const gl::Data &data, - const TranslatedIndexData &indexInfo, + GLsizei instances); + gl::Error drawElementsImpl(const gl::Context *context, GLenum mode, GLsizei count, GLenum type, - const GLvoid *indices, - GLsizei instances) override; + const void *indices, + GLsizei instances); - void generateCaps(gl::Caps *outCaps, gl::TextureCapsMap *outTextureCaps, + gl::Error applyShaders(const gl::Context *context, GLenum drawMode); + + gl::Error applyTextures(const gl::Context *context); + gl::Error applyTextures(const gl::Context *context, gl::SamplerType shaderType); + + void generateCaps(gl::Caps *outCaps, + gl::TextureCapsMap *outTextureCaps, gl::Extensions *outExtensions, gl::Limitations *outLimitations) const override; - WorkaroundsD3D generateWorkarounds() const override; + angle::WorkaroundsD3D generateWorkarounds() const override; - gl::Error setBlendDepthRasterStates(const gl::Data &glData, GLenum drawMode); + gl::Error setBlendDepthRasterStates(const gl::Context *context, GLenum drawMode); void release(); @@ -293,18 +421,30 @@ class Renderer9 : public RendererD3D void applyUniformniv(const D3DUniform *targetUniform, const GLint *v); void applyUniformnbv(const D3DUniform *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 drawLineLoop(const gl::Context *context, + GLsizei count, + GLenum type, + const void *indices, + int minIndex, + gl::Buffer *elementArrayBuffer); + gl::Error drawIndexedPoints(const gl::Context *context, + GLsizei count, + GLenum type, + const void *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); + gl::Error getNullColorbuffer(const gl::Context *context, + const gl::FramebufferAttachment *depthbuffer, + const gl::FramebufferAttachment **outColorBuffer); D3DPOOL getBufferPool(DWORD usage) const; HMODULE mD3d9Module; - void initializeDevice(); + egl::Error initializeDevice(); D3DPRESENT_PARAMETERS getDefaultPresentParameters(); void releaseDeviceResources(); @@ -314,7 +454,7 @@ class Renderer9 : public RendererD3D UINT mAdapter; D3DDEVTYPE mDeviceType; - IDirect3D9 *mD3d9; // Always valid after successful initialization. + 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. @@ -368,7 +508,7 @@ class Renderer9 : public RendererD3D unsigned int mAppliedProgramSerial; // A pool of event queries that are currently unused. - std::vector mEventQueryPool; + std::vector mEventQueryPool; VertexShaderCache mVertexShaderCache; PixelShaderCache mPixelShaderCache; @@ -379,7 +519,10 @@ class Renderer9 : public RendererD3D StreamingIndexBufferInterface *mLineLoopIB; StaticIndexBufferInterface *mCountingIB; - enum { NUM_NULL_COLORBUFFER_CACHE_ENTRIES = 12 }; + enum + { + NUM_NULL_COLORBUFFER_CACHE_ENTRIES = 12 + }; struct NullColorbufferCacheEntry { UINT lruCount; @@ -390,7 +533,11 @@ class Renderer9 : public RendererD3D UINT mMaxNullColorbufferLRU; DeviceD3D *mEGLDevice; + std::vector mTranslatedAttribCache; + + DebugAnnotator9 mAnnotator; }; -} -#endif // LIBANGLE_RENDERER_D3D_D3D9_RENDERER9_H_ +} // namespace rx + +#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 index cf831c62fa..399770dd8d 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/ShaderCache.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/ShaderCache.h @@ -24,9 +24,7 @@ template class ShaderCache : angle::NonCopyable { public: - ShaderCache() : mDevice(NULL) - { - } + ShaderCache() : mDevice(nullptr) {} ~ShaderCache() { @@ -47,14 +45,14 @@ class ShaderCache : angle::NonCopyable { it->second->AddRef(); *outShaderObject = it->second; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } 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); + return gl::OutOfMemory() << "Failed to create shader, " << gl::FmtHR(result); } // Random eviction policy. @@ -68,7 +66,7 @@ class ShaderCache : angle::NonCopyable mMap[key] = shader; *outShaderObject = shader; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } void clear() diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/ShaderExecutable9.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/ShaderExecutable9.cpp index 28a486056b..362c6c60a3 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/ShaderExecutable9.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/ShaderExecutable9.cpp @@ -18,14 +18,14 @@ ShaderExecutable9::ShaderExecutable9(const void *function, size_t length, IDirec : ShaderExecutableD3D(function, length) { mPixelExecutable = executable; - mVertexExecutable = NULL; + mVertexExecutable = nullptr; } ShaderExecutable9::ShaderExecutable9(const void *function, size_t length, IDirect3DVertexShader9 *executable) : ShaderExecutableD3D(function, length) { mVertexExecutable = executable; - mPixelExecutable = NULL; + mPixelExecutable = nullptr; } ShaderExecutable9::~ShaderExecutable9() @@ -44,4 +44,4 @@ 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 index 382a68c820..0b6b87947e 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/ShaderExecutable9.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/ShaderExecutable9.h @@ -20,7 +20,7 @@ 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(); + ~ShaderExecutable9() override; IDirect3DPixelShader9 *getPixelShader() const; IDirect3DVertexShader9 *getVertexShader() const; diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/StateManager9.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/StateManager9.cpp index c4c600aedb..a3bdc14efb 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/StateManager9.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/StateManager9.cpp @@ -7,7 +7,7 @@ // StateManager9.cpp: Defines a class for caching D3D9 state #include "libANGLE/renderer/d3d/d3d9/StateManager9.h" -#include "common/BitSetIterator.h" +#include "common/bitset_utils.h" #include "common/utilities.h" #include "libANGLE/formatutils.h" #include "libANGLE/renderer/d3d/d3d9/renderer9_utils.h" @@ -18,7 +18,8 @@ namespace rx { StateManager9::StateManager9(Renderer9 *renderer9) - : mCurBlendState(), + : mUsingZeroColorMaskWorkaround(false), + mCurBlendState(), mCurBlendColor(0, 0, 0, 0), mCurSampleMask(0), mCurRasterState(), @@ -67,6 +68,11 @@ StateManager9::~StateManager9() { } +void StateManager9::initialize() +{ + mUsingZeroColorMaskWorkaround = IsAMD(mRenderer9->getVendorId()); +} + void StateManager9::forceSetBlendState() { mDirtyBits |= mBlendStateDirtyBits; @@ -114,7 +120,7 @@ void StateManager9::syncState(const gl::State &state, const gl::State::DirtyBits return; } - for (auto dirtyBit : angle::IterateBitSet(dirtyBits)) + for (auto dirtyBit : dirtyBits) { switch (dirtyBit) { @@ -125,6 +131,12 @@ void StateManager9::syncState(const gl::State &state, const gl::State::DirtyBits // BlendColor and funcs and equations has to be set if blend is enabled mDirtyBits.set(DIRTY_BIT_BLEND_COLOR); mDirtyBits.set(DIRTY_BIT_BLEND_FUNCS_EQUATIONS); + + // The color mask may have to be updated if the blend state changes + if (mUsingZeroColorMaskWorkaround) + { + mDirtyBits.set(DIRTY_BIT_COLOR_MASK); + } } break; case gl::State::DIRTY_BIT_BLEND_FUNCS: @@ -138,6 +150,12 @@ void StateManager9::syncState(const gl::State &state, const gl::State::DirtyBits mDirtyBits.set(DIRTY_BIT_BLEND_FUNCS_EQUATIONS); // BlendColor depends on the values of blend funcs mDirtyBits.set(DIRTY_BIT_BLEND_COLOR); + + // The color mask may have to be updated if the blend funcs change + if (mUsingZeroColorMaskWorkaround) + { + mDirtyBits.set(DIRTY_BIT_COLOR_MASK); + } } break; } @@ -148,6 +166,12 @@ void StateManager9::syncState(const gl::State &state, const gl::State::DirtyBits blendState.blendEquationAlpha != mCurBlendState.blendEquationAlpha) { mDirtyBits.set(DIRTY_BIT_BLEND_FUNCS_EQUATIONS); + + // The color mask may have to be updated if the blend funcs change + if (mUsingZeroColorMaskWorkaround) + { + mDirtyBits.set(DIRTY_BIT_COLOR_MASK); + } } break; } @@ -167,6 +191,14 @@ void StateManager9::syncState(const gl::State &state, const gl::State::DirtyBits blendState.colorMaskAlpha != mCurBlendState.colorMaskAlpha) { mDirtyBits.set(DIRTY_BIT_COLOR_MASK); + + // The color mask can cause the blend state to get out of sync when using the + // zero color mask workaround + if (mUsingZeroColorMaskWorkaround) + { + mDirtyBits.set(DIRTY_BIT_BLEND_ENABLED); + mDirtyBits.set(DIRTY_BIT_BLEND_FUNCS_EQUATIONS); + } } break; } @@ -364,7 +396,7 @@ gl::Error StateManager9::setBlendDepthRasterStates(const gl::State &glState, mCurFrontFaceCCW = frontFaceCCW; } - for (auto dirtyBit : angle::IterateBitSet(mDirtyBits)) + for (auto dirtyBit : mDirtyBits) { switch (dirtyBit) { @@ -438,11 +470,10 @@ gl::Error StateManager9::setBlendDepthRasterStates(const gl::State &glState, setSampleMask(sampleMask); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -void StateManager9::setViewportState(const gl::Caps *caps, - const gl::Rectangle &viewport, +void StateManager9::setViewportState(const gl::Rectangle &viewport, float zNear, float zFar, GLenum drawMode, @@ -698,6 +729,7 @@ void StateManager9::setStencilTestEnabled(bool stencilTestEnabled) if (stencilTestEnabled && mCurStencilSize > 0) { mRenderer9->getDevice()->SetRenderState(D3DRS_STENCILENABLE, TRUE); + mRenderer9->getDevice()->SetRenderState(D3DRS_TWOSIDEDSTENCILMODE, TRUE); } else { @@ -718,7 +750,7 @@ void StateManager9::setSampleAlphaToCoverage(bool enabled) { if (enabled) { - FIXME("Sample alpha to coverage is unimplemented."); + UNREACHABLE(); } } @@ -800,42 +832,52 @@ void StateManager9::setColorMask(const gl::Framebuffer *framebuffer, bool alpha) { // Set the color mask - bool zeroColorMaskAllowed = mRenderer9->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::FramebufferAttachment *attachment = framebuffer->getFirstColorbuffer(); - GLenum internalFormat = attachment ? attachment->getInternalFormat() : GL_NONE; - - const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat); + const auto *attachment = framebuffer->getFirstColorbuffer(); + const auto &format = attachment ? attachment->getFormat() : gl::Format::Invalid(); DWORD colorMask = gl_d3d9::ConvertColorMask( - formatInfo.redBits > 0 && red, formatInfo.greenBits > 0 && green, - formatInfo.blueBits > 0 && blue, formatInfo.alphaBits > 0 && alpha); - - if (colorMask == 0 && !zeroColorMaskAllowed) + format.info->redBits > 0 && red, format.info->greenBits > 0 && green, + format.info->blueBits > 0 && blue, format.info->alphaBits > 0 && alpha); + + // 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://anglebug.com/169 + if (colorMask == 0 && mUsingZeroColorMaskWorkaround) { IDirect3DDevice9 *device = mRenderer9->getDevice(); // Enable green channel, but set blending so nothing will be drawn. device->SetRenderState(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_GREEN); + device->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ZERO); device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE); device->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD); + + mCurBlendState.colorMaskRed = false; + mCurBlendState.colorMaskGreen = true; + mCurBlendState.colorMaskBlue = false; + mCurBlendState.colorMaskAlpha = false; + + mCurBlendState.blend = true; + mCurBlendState.sourceBlendRGB = GL_ZERO; + mCurBlendState.sourceBlendAlpha = GL_ZERO; + mCurBlendState.destBlendRGB = GL_ONE; + mCurBlendState.destBlendAlpha = GL_ONE; + mCurBlendState.blendEquationRGB = GL_FUNC_ADD; + mCurBlendState.blendEquationAlpha = GL_FUNC_ADD; } else { mRenderer9->getDevice()->SetRenderState(D3DRS_COLORWRITEENABLE, colorMask); - } - mCurBlendState.colorMaskRed = red; - mCurBlendState.colorMaskGreen = green; - mCurBlendState.colorMaskBlue = blue; - mCurBlendState.colorMaskAlpha = alpha; + mCurBlendState.colorMaskRed = red; + mCurBlendState.colorMaskGreen = green; + mCurBlendState.colorMaskBlue = blue; + mCurBlendState.colorMaskAlpha = alpha; + } } void StateManager9::setSampleMask(unsigned int sampleMask) @@ -848,7 +890,7 @@ void StateManager9::setSampleMask(unsigned int sampleMask) mCurSampleMask = sampleMask; } -void StateManager9::setCullMode(bool cullFace, GLenum cullMode, GLenum frontFace) +void StateManager9::setCullMode(bool cullFace, gl::CullFaceMode cullMode, GLenum frontFace) { if (cullFace) { diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/StateManager9.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/StateManager9.h index d8c1eb9812..63ce17cb1e 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/StateManager9.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/StateManager9.h @@ -10,7 +10,7 @@ #define LIBANGLE_RENDERER_D3D9_STATEMANAGER9_H_ #include "libANGLE/angletypes.h" -#include "libANGLE/Data.h" +#include "libANGLE/ContextState.h" #include "libANGLE/State.h" #include "libANGLE/renderer/d3d/RendererD3D.h" @@ -39,12 +39,13 @@ class StateManager9 final : angle::NonCopyable StateManager9(Renderer9 *renderer9); ~StateManager9(); + void initialize(); + void syncState(const gl::State &state, const gl::State::DirtyBits &dirtyBits); gl::Error setBlendDepthRasterStates(const gl::State &glState, unsigned int sampleMask); void setScissorState(const gl::Rectangle &scissor, bool enabled); - void setViewportState(const gl::Caps *caps, - const gl::Rectangle &viewport, + void setViewportState(const gl::Rectangle &viewport, float zNear, float zFar, GLenum drawMode, @@ -85,7 +86,7 @@ class StateManager9 final : angle::NonCopyable void setSampleMask(unsigned int sampleMask); // Current raster state functions - void setCullMode(bool cullFace, GLenum cullMode, GLenum frontFace); + void setCullMode(bool cullFace, gl::CullFaceMode cullMode, GLenum frontFace); void setDepthBias(bool polygonOffsetFill, GLfloat polygonOffsetFactor, GLfloat polygonOffsetUnits); @@ -154,7 +155,9 @@ class StateManager9 final : angle::NonCopyable DIRTY_BIT_MAX }; - typedef std::bitset DirtyBits; + using DirtyBits = angle::BitSet; + + bool mUsingZeroColorMaskWorkaround; // Currently applied blend state gl::BlendState mCurBlendState; diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/SwapChain9.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/SwapChain9.cpp index be6a9c424c..bc81aa18ec 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/SwapChain9.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/SwapChain9.cpp @@ -7,25 +7,29 @@ // 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/features.h" #include "libANGLE/renderer/d3d/d3d9/formatutils9.h" +#include "libANGLE/renderer/d3d/d3d9/NativeWindow9.h" #include "libANGLE/renderer/d3d/d3d9/Renderer9.h" -#include "libANGLE/features.h" +#include "libANGLE/renderer/d3d/d3d9/renderer9_utils.h" namespace rx { SwapChain9::SwapChain9(Renderer9 *renderer, - NativeWindow nativeWindow, + NativeWindow9 *nativeWindow, HANDLE shareHandle, + IUnknown *d3dTexture, GLenum backBufferFormat, GLenum depthBufferFormat, EGLint orientation) - : SwapChainD3D(nativeWindow, shareHandle, backBufferFormat, depthBufferFormat), + : SwapChainD3D(shareHandle, d3dTexture, backBufferFormat, depthBufferFormat), mRenderer(renderer), mWidth(-1), mHeight(-1), mSwapInterval(-1), + mNativeWindow(nativeWindow), mSwapChain(nullptr), mBackBuffer(nullptr), mRenderTarget(nullptr), @@ -50,9 +54,9 @@ void SwapChain9::release() SafeRelease(mRenderTarget); SafeRelease(mOffscreenTexture); - if (mNativeWindow.getNativeWindow()) + if (mNativeWindow->getNativeWindow()) { - mShareHandle = NULL; + mShareHandle = nullptr; } } @@ -75,17 +79,20 @@ static DWORD convertInterval(EGLint interval) #endif } -EGLint SwapChain9::resize(int backbufferWidth, int backbufferHeight) +EGLint SwapChain9::resize(const gl::Context *context, int backbufferWidth, int backbufferHeight) { // D3D9 does not support resizing swap chains without recreating them - return reset(backbufferWidth, backbufferHeight, mSwapInterval); + return reset(context, backbufferWidth, backbufferHeight, mSwapInterval); } -EGLint SwapChain9::reset(int backbufferWidth, int backbufferHeight, EGLint swapInterval) +EGLint SwapChain9::reset(const gl::Context *context, + int backbufferWidth, + int backbufferHeight, + EGLint swapInterval) { IDirect3DDevice9 *device = mRenderer->getDevice(); - if (device == NULL) + if (device == nullptr) { return EGL_BAD_ACCESS; } @@ -103,28 +110,37 @@ EGLint SwapChain9::reset(int backbufferWidth, int backbufferHeight, EGLint swapI SafeRelease(mOffscreenTexture); SafeRelease(mDepthStencil); - HANDLE *pShareHandle = NULL; - if (!mNativeWindow.getNativeWindow() && mRenderer->getShareHandleSupport()) + const d3d9::TextureFormat &backBufferd3dFormatInfo = + d3d9::GetTextureFormatInfo(mOffscreenRenderTargetFormat); + if (mD3DTexture != nullptr) { - pShareHandle = &mShareHandle; + result = mD3DTexture->QueryInterface(&mOffscreenTexture); + ASSERT(SUCCEEDED(result)); } - - const d3d9::TextureFormat &backBufferd3dFormatInfo = d3d9::GetTextureFormatInfo(mOffscreenRenderTargetFormat); - result = device->CreateTexture(backbufferWidth, backbufferHeight, 1, D3DUSAGE_RENDERTARGET, - backBufferd3dFormatInfo.texFormat, D3DPOOL_DEFAULT, &mOffscreenTexture, - pShareHandle); - if (FAILED(result)) + else { - ERR("Could not create offscreen texture: %08lX", result); - release(); - - if (d3d9::isDeviceLostError(result)) + HANDLE *pShareHandle = nullptr; + if (!mNativeWindow->getNativeWindow() && mRenderer->getShareHandleSupport()) { - return EGL_CONTEXT_LOST; + pShareHandle = &mShareHandle; } - else + + result = device->CreateTexture(backbufferWidth, backbufferHeight, 1, D3DUSAGE_RENDERTARGET, + backBufferd3dFormatInfo.texFormat, D3DPOOL_DEFAULT, + &mOffscreenTexture, pShareHandle); + if (FAILED(result)) { - return EGL_BAD_ALLOC; + ERR() << "Could not create offscreen texture, " << gl::FmtHR(result); + release(); + + if (d3d9::isDeviceLostError(result)) + { + return EGL_CONTEXT_LOST; + } + else + { + return EGL_BAD_ALLOC; + } } } @@ -163,7 +179,7 @@ EGLint SwapChain9::reset(int backbufferWidth, int backbufferHeight, EGLint swapI // Don't create a swapchain for NULLREF devices D3DDEVTYPE deviceType = mRenderer->getD3D9DeviceType(); - EGLNativeWindowType window = mNativeWindow.getNativeWindow(); + EGLNativeWindowType window = mNativeWindow->getNativeWindow(); if (window && deviceType != D3DDEVTYPE_NULLREF) { D3DPRESENT_PARAMETERS presentParameters = {0}; @@ -189,7 +205,7 @@ EGLint SwapChain9::reset(int backbufferWidth, int backbufferHeight, EGLint swapI // // 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) + if (IsIntel(mRenderer->getVendorId())) { presentParameters.BackBufferWidth = (presentParameters.BackBufferWidth + 63) / 64 * 64; } @@ -200,7 +216,8 @@ EGLint SwapChain9::reset(int backbufferWidth, int backbufferHeight, EGLint swapI { 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); + ERR() << "Could not create additional swap chains or offscreen surfaces, " + << gl::FmtHR(result); release(); if (d3d9::isDeviceLostError(result)) @@ -215,20 +232,21 @@ EGLint SwapChain9::reset(int backbufferWidth, int backbufferHeight, EGLint swapI result = mSwapChain->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &mBackBuffer); ASSERT(SUCCEEDED(result)); - InvalidateRect(window, NULL, FALSE); + InvalidateRect(window, nullptr, FALSE); } if (mDepthBufferFormat != GL_NONE) { - result = device->CreateDepthStencilSurface(backbufferWidth, backbufferHeight, - depthBufferd3dFormatInfo.renderFormat, - D3DMULTISAMPLE_NONE, 0, FALSE, &mDepthStencil, NULL); + result = device->CreateDepthStencilSurface( + backbufferWidth, backbufferHeight, depthBufferd3dFormatInfo.renderFormat, + D3DMULTISAMPLE_NONE, 0, FALSE, &mDepthStencil, nullptr); 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); + ERR() << "Could not create depthstencil surface for new swap chain, " + << gl::FmtHR(result); release(); if (d3d9::isDeviceLostError(result)) @@ -250,7 +268,11 @@ EGLint SwapChain9::reset(int backbufferWidth, int backbufferHeight, EGLint swapI } // parameters should be validated/clamped by caller -EGLint SwapChain9::swapRect(EGLint x, EGLint y, EGLint width, EGLint height) +EGLint SwapChain9::swapRect(const gl::Context *context, + EGLint x, + EGLint y, + EGLint width, + EGLint height) { if (!mSwapChain) { @@ -270,11 +292,11 @@ EGLint SwapChain9::swapRect(EGLint x, EGLint y, EGLint width, EGLint height) 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->SetPixelShader(nullptr); + device->SetVertexShader(nullptr); device->SetRenderTarget(0, mBackBuffer); - device->SetDepthStencilSurface(NULL); + device->SetDepthStencilSurface(nullptr); device->SetTexture(0, mOffscreenTexture); device->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1); @@ -313,7 +335,7 @@ EGLint SwapChain9::swapRect(EGLint x, EGLint y, EGLint width, EGLint height) device->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, quad, 6 * sizeof(float)); mRenderer->endScene(); - device->SetTexture(0, NULL); + device->SetTexture(0, nullptr); RECT rect = { @@ -321,7 +343,7 @@ EGLint SwapChain9::swapRect(EGLint x, EGLint y, EGLint width, EGLint height) static_cast(x + width), static_cast(mHeight - y) }; - HRESULT result = mSwapChain->Present(&rect, &rect, NULL, NULL, 0); + HRESULT result = mSwapChain->Present(&rect, &rect, nullptr, nullptr, 0); mRenderer->markAllStateDirty(); @@ -333,7 +355,7 @@ EGLint SwapChain9::swapRect(EGLint x, EGLint y, EGLint width, EGLint height) // 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) + if (result == static_cast(0x88760873)) { return EGL_BAD_MATCH; } @@ -395,6 +417,12 @@ void *SwapChain9::getKeyedMutex() return nullptr; } +egl::Error SwapChain9::getSyncValues(EGLuint64KHR *ust, EGLuint64KHR *msc, EGLuint64KHR *sbc) +{ + UNREACHABLE(); + return egl::EglBadSurface(); +} + void SwapChain9::recreate() { if (!mSwapChain) @@ -403,7 +431,7 @@ void SwapChain9::recreate() } IDirect3DDevice9 *device = mRenderer->getDevice(); - if (device == NULL) + if (device == nullptr) { return; } @@ -412,7 +440,7 @@ void SwapChain9::recreate() HRESULT result = mSwapChain->GetPresentParameters(&presentParameters); ASSERT(SUCCEEDED(result)); - IDirect3DSwapChain9* newSwapChain = NULL; + IDirect3DSwapChain9 *newSwapChain = nullptr; result = device->CreateAdditionalSwapChain(&presentParameters, &newSwapChain); if (FAILED(result)) { @@ -427,4 +455,13 @@ void SwapChain9::recreate() ASSERT(SUCCEEDED(result)); } +RenderTargetD3D *SwapChain9::getColorRenderTarget() +{ + return &mColorRenderTarget; +} + +RenderTargetD3D *SwapChain9::getDepthStencilRenderTarget() +{ + return &mDepthStencilRenderTarget; +} } diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/SwapChain9.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/SwapChain9.h index 55a700c2d6..5753637c47 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/SwapChain9.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/SwapChain9.h @@ -15,26 +15,36 @@ namespace rx { +class NativeWindow9; class Renderer9; class SwapChain9 : public SwapChainD3D { public: SwapChain9(Renderer9 *renderer, - NativeWindow nativeWindow, + NativeWindow9 *nativeWindow, HANDLE shareHandle, + IUnknown *d3dTexture, GLenum backBufferFormat, GLenum depthBufferFormat, EGLint orientation); - virtual ~SwapChain9(); + ~SwapChain9() override; - 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(); + EGLint resize(const gl::Context *context, EGLint backbufferWidth, EGLint backbufferHeight) + override; + EGLint reset(const gl::Context *context, + EGLint backbufferWidth, + EGLint backbufferHeight, + EGLint swapInterval) override; + EGLint swapRect(const gl::Context *context, + EGLint x, + EGLint y, + EGLint width, + EGLint height) override; + void recreate() override; - RenderTargetD3D *getColorRenderTarget() override { return &mColorRenderTarget; } - RenderTargetD3D *getDepthStencilRenderTarget() override { return &mDepthStencilRenderTarget; } + RenderTargetD3D *getColorRenderTarget() override; + RenderTargetD3D *getDepthStencilRenderTarget() override; virtual IDirect3DSurface9 *getRenderTarget(); virtual IDirect3DSurface9 *getDepthStencil(); @@ -45,6 +55,8 @@ class SwapChain9 : public SwapChainD3D void *getKeyedMutex() override; + egl::Error getSyncValues(EGLuint64KHR *ust, EGLuint64KHR *msc, EGLuint64KHR *sbc) override; + private: void release(); @@ -53,6 +65,8 @@ class SwapChain9 : public SwapChainD3D EGLint mHeight; EGLint mSwapInterval; + NativeWindow9 *mNativeWindow; + IDirect3DSwapChain9 *mSwapChain; IDirect3DSurface9 *mBackBuffer; IDirect3DSurface9 *mRenderTarget; diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/TextureStorage9.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/TextureStorage9.cpp index b28d5076b5..6404af6bba 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/TextureStorage9.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/TextureStorage9.cpp @@ -43,7 +43,7 @@ DWORD TextureStorage9::GetTextureUsage(GLenum internalformat, bool renderTarget) { DWORD d3dusage = 0; - const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat); + const gl::InternalFormat &formatInfo = gl::GetSizedInternalFormatInfo(internalformat); const d3d9::TextureFormat &d3dFormatInfo = d3d9::GetTextureFormatInfo(internalformat); if (formatInfo.depthBits > 0 || formatInfo.stencilBits > 0) { @@ -93,11 +93,16 @@ int TextureStorage9::getLevelCount() const return static_cast(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) +gl::Error TextureStorage9::setData(const gl::Context *context, + 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); + return gl::InternalError(); } TextureStorage9_2D::TextureStorage9_2D(Renderer9 *renderer, SwapChain9 *swapchain) @@ -107,7 +112,7 @@ TextureStorage9_2D::TextureStorage9_2D(Renderer9 *renderer, SwapChain9 *swapchai mTexture = surfaceTexture; mMipLevels = surfaceTexture->GetLevelCount(); - mInternalFormat = swapchain->GetRenderTargetInternalFormat(); + mInternalFormat = swapchain->getRenderTargetInternalFormat(); D3DSURFACE_DESC surfaceDesc; surfaceTexture->GetLevelDesc(0, &surfaceDesc); @@ -121,7 +126,7 @@ TextureStorage9_2D::TextureStorage9_2D(Renderer9 *renderer, SwapChain9 *swapchai TextureStorage9_2D::TextureStorage9_2D(Renderer9 *renderer, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels) : TextureStorage9(renderer, GetTextureUsage(internalformat, renderTarget)) { - mTexture = NULL; + mTexture = nullptr; mInternalFormat = internalformat; @@ -139,7 +144,7 @@ TextureStorage9_2D::TextureStorage9_2D(Renderer9 *renderer, GLenum internalforma TextureStorage9_2D::~TextureStorage9_2D() { SafeRelease(mTexture); - for (auto &renderTarget : mRenderTargets) + for (RenderTargetD3D *renderTarget : mRenderTargets) { SafeDelete(renderTarget); } @@ -147,16 +152,16 @@ TextureStorage9_2D::~TextureStorage9_2D() // Increments refcount on surface. // caller must Release() the returned surface -gl::Error TextureStorage9_2D::getSurfaceLevel(GLenum target, +gl::Error TextureStorage9_2D::getSurfaceLevel(const gl::Context *context, + GLenum target, int level, bool dirty, IDirect3DSurface9 **outSurface) { ASSERT(target == GL_TEXTURE_2D); - UNUSED_ASSERTION_VARIABLE(target); - IDirect3DBaseTexture9 *baseTexture = NULL; - gl::Error error = getBaseTexture(&baseTexture); + IDirect3DBaseTexture9 *baseTexture = nullptr; + gl::Error error = getBaseTexture(context, &baseTexture); if (error.isError()) { return error; @@ -169,33 +174,36 @@ gl::Error TextureStorage9_2D::getSurfaceLevel(GLenum target, 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); + return gl::OutOfMemory() << "Failed to get the surface from a texture, " + << gl::FmtHR(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); + texture->AddDirtyRect(nullptr); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureStorage9_2D::getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT) +gl::Error TextureStorage9_2D::getRenderTarget(const gl::Context *context, + const gl::ImageIndex &index, + RenderTargetD3D **outRT) { ASSERT(index.mipIndex < getLevelCount()); if (!mRenderTargets[index.mipIndex] && isRenderTarget()) { - IDirect3DBaseTexture9 *baseTexture = NULL; - gl::Error error = getBaseTexture(&baseTexture); + IDirect3DBaseTexture9 *baseTexture = nullptr; + gl::Error error = getBaseTexture(context, &baseTexture); if (error.isError()) { return error; } - IDirect3DSurface9 *surface = NULL; - error = getSurfaceLevel(GL_TEXTURE_2D, index.mipIndex, false, &surface); + IDirect3DSurface9 *surface = nullptr; + error = getSurfaceLevel(context, GL_TEXTURE_2D, index.mipIndex, false, &surface); if (error.isError()) { return error; @@ -213,20 +221,22 @@ gl::Error TextureStorage9_2D::getRenderTarget(const gl::ImageIndex &index, Rende ASSERT(outRT); *outRT = mRenderTargets[index.mipIndex]; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureStorage9_2D::generateMipmap(const gl::ImageIndex &sourceIndex, const gl::ImageIndex &destIndex) +gl::Error TextureStorage9_2D::generateMipmap(const gl::Context *context, + const gl::ImageIndex &sourceIndex, + const gl::ImageIndex &destIndex) { - IDirect3DSurface9 *upper = NULL; - gl::Error error = getSurfaceLevel(GL_TEXTURE_2D, sourceIndex.mipIndex, false, &upper); + IDirect3DSurface9 *upper = nullptr; + gl::Error error = getSurfaceLevel(context, GL_TEXTURE_2D, sourceIndex.mipIndex, false, &upper); if (error.isError()) { return error; } - IDirect3DSurface9 *lower = NULL; - error = getSurfaceLevel(GL_TEXTURE_2D, destIndex.mipIndex, true, &lower); + IDirect3DSurface9 *lower = nullptr; + error = getSurfaceLevel(context, GL_TEXTURE_2D, destIndex.mipIndex, true, &lower); if (error.isError()) { SafeRelease(upper); @@ -242,32 +252,34 @@ gl::Error TextureStorage9_2D::generateMipmap(const gl::ImageIndex &sourceIndex, return error; } -gl::Error TextureStorage9_2D::getBaseTexture(IDirect3DBaseTexture9 **outTexture) +gl::Error TextureStorage9_2D::getBaseTexture(const gl::Context *context, + 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) + if (mTexture == nullptr && mTextureWidth > 0 && mTextureHeight > 0) { ASSERT(mMipLevels > 0); IDirect3DDevice9 *device = mRenderer->getDevice(); - HRESULT result = device->CreateTexture(static_cast(mTextureWidth), + HRESULT result = device->CreateTexture(static_cast(mTextureWidth), static_cast(mTextureHeight), static_cast(mMipLevels), getUsage(), - mTextureFormat, getPool(), &mTexture, NULL); + mTextureFormat, getPool(), &mTexture, nullptr); 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); + return gl::OutOfMemory() + << "Failed to create 2D storage texture, " << gl::FmtHR(result); } } *outTexture = mTexture; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureStorage9_2D::copyToStorage(TextureStorage *destStorage) +gl::Error TextureStorage9_2D::copyToStorage(const gl::Context *context, TextureStorage *destStorage) { ASSERT(destStorage); @@ -276,15 +288,15 @@ gl::Error TextureStorage9_2D::copyToStorage(TextureStorage *destStorage) int levels = getLevelCount(); for (int i = 0; i < levels; ++i) { - IDirect3DSurface9 *srcSurf = NULL; - gl::Error error = getSurfaceLevel(GL_TEXTURE_2D, i, false, &srcSurf); + IDirect3DSurface9 *srcSurf = nullptr; + gl::Error error = getSurfaceLevel(context, GL_TEXTURE_2D, i, false, &srcSurf); if (error.isError()) { return error; } - IDirect3DSurface9 *dstSurf = NULL; - error = dest9->getSurfaceLevel(GL_TEXTURE_2D, i, true, &dstSurf); + IDirect3DSurface9 *dstSurf = nullptr; + error = dest9->getSurfaceLevel(context, GL_TEXTURE_2D, i, true, &dstSurf); if (error.isError()) { SafeRelease(srcSurf); @@ -302,17 +314,14 @@ gl::Error TextureStorage9_2D::copyToStorage(TextureStorage *destStorage) } } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -TextureStorage9_EGLImage::TextureStorage9_EGLImage(Renderer9 *renderer, EGLImageD3D *image) +TextureStorage9_EGLImage::TextureStorage9_EGLImage(Renderer9 *renderer, + EGLImageD3D *image, + RenderTarget9 *renderTarget9) : TextureStorage9(renderer, D3DUSAGE_RENDERTARGET), mImage(image) { - RenderTargetD3D *renderTargetD3D = nullptr; - mImage->getRenderTarget(&renderTargetD3D); - - RenderTarget9 *renderTarget9 = GetAs(renderTargetD3D); - mInternalFormat = renderTarget9->getInternalFormat(); mTextureFormat = renderTarget9->getD3DFormat(); mTextureWidth = renderTarget9->getWidth(); @@ -325,18 +334,17 @@ TextureStorage9_EGLImage::~TextureStorage9_EGLImage() { } -gl::Error TextureStorage9_EGLImage::getSurfaceLevel(GLenum target, +gl::Error TextureStorage9_EGLImage::getSurfaceLevel(const gl::Context *context, + GLenum target, int level, bool, IDirect3DSurface9 **outSurface) { ASSERT(target == GL_TEXTURE_2D); ASSERT(level == 0); - UNUSED_ASSERTION_VARIABLE(target); - UNUSED_ASSERTION_VARIABLE(level); RenderTargetD3D *renderTargetD3D = nullptr; - gl::Error error = mImage->getRenderTarget(&renderTargetD3D); + gl::Error error = mImage->getRenderTarget(context, &renderTargetD3D); if (error.isError()) { return error; @@ -345,23 +353,24 @@ gl::Error TextureStorage9_EGLImage::getSurfaceLevel(GLenum target, RenderTarget9 *renderTarget9 = GetAs(renderTargetD3D); *outSurface = renderTarget9->getSurface(); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureStorage9_EGLImage::getRenderTarget(const gl::ImageIndex &index, +gl::Error TextureStorage9_EGLImage::getRenderTarget(const gl::Context *context, + const gl::ImageIndex &index, RenderTargetD3D **outRT) { ASSERT(!index.hasLayer()); ASSERT(index.mipIndex == 0); - UNUSED_ASSERTION_VARIABLE(index); - return mImage->getRenderTarget(outRT); + return mImage->getRenderTarget(context, outRT); } -gl::Error TextureStorage9_EGLImage::getBaseTexture(IDirect3DBaseTexture9 **outTexture) +gl::Error TextureStorage9_EGLImage::getBaseTexture(const gl::Context *context, + IDirect3DBaseTexture9 **outTexture) { RenderTargetD3D *renderTargetD3D = nullptr; - gl::Error error = mImage->getRenderTarget(&renderTargetD3D); + gl::Error error = mImage->getRenderTarget(context, &renderTargetD3D); if (error.isError()) { return error; @@ -371,16 +380,19 @@ gl::Error TextureStorage9_EGLImage::getBaseTexture(IDirect3DBaseTexture9 **outTe *outTexture = renderTarget9->getTexture(); ASSERT(*outTexture != nullptr); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureStorage9_EGLImage::generateMipmap(const gl::ImageIndex &, const gl::ImageIndex &) +gl::Error TextureStorage9_EGLImage::generateMipmap(const gl::Context *context, + const gl::ImageIndex &, + const gl::ImageIndex &) { UNREACHABLE(); - return gl::Error(GL_INVALID_OPERATION); + return gl::InternalError(); } -gl::Error TextureStorage9_EGLImage::copyToStorage(TextureStorage *destStorage) +gl::Error TextureStorage9_EGLImage::copyToStorage(const gl::Context *context, + TextureStorage *destStorage) { ASSERT(destStorage); ASSERT(getLevelCount() == 1); @@ -388,7 +400,7 @@ gl::Error TextureStorage9_EGLImage::copyToStorage(TextureStorage *destStorage) TextureStorage9 *dest9 = GetAs(destStorage); IDirect3DBaseTexture9 *destBaseTexture9 = nullptr; - gl::Error error = dest9->getBaseTexture(&destBaseTexture9); + gl::Error error = dest9->getBaseTexture(context, &destBaseTexture9); if (error.isError()) { return error; @@ -400,12 +412,12 @@ gl::Error TextureStorage9_EGLImage::copyToStorage(TextureStorage *destStorage) HRESULT result = destTexture9->GetSurfaceLevel(destStorage->getTopLevel(), &destSurface); if (FAILED(result)) { - return gl::Error(GL_OUT_OF_MEMORY, - "Failed to get the surface from a texture, result: 0x%X.", result); + return gl::OutOfMemory() << "Failed to get the surface from a texture, " + << gl::FmtHR(result); } RenderTargetD3D *sourceRenderTarget = nullptr; - error = mImage->getRenderTarget(&sourceRenderTarget); + error = mImage->getRenderTarget(context, &sourceRenderTarget); if (error.isError()) { SafeRelease(destSurface); @@ -427,16 +439,16 @@ gl::Error TextureStorage9_EGLImage::copyToStorage(TextureStorage *destStorage) } SafeRelease(destSurface); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } 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) + mTexture = nullptr; + for (size_t i = 0; i < gl::CUBE_FACE_COUNT; ++i) { - mRenderTarget[i] = NULL; + mRenderTarget[i] = nullptr; } mInternalFormat = internalformat; @@ -455,7 +467,7 @@ TextureStorage9_Cube::~TextureStorage9_Cube() { SafeRelease(mTexture); - for (int i = 0; i < CUBE_FACE_COUNT; ++i) + for (size_t i = 0; i < gl::CUBE_FACE_COUNT; ++i) { SafeDelete(mRenderTarget[i]); } @@ -463,13 +475,14 @@ TextureStorage9_Cube::~TextureStorage9_Cube() // Increments refcount on surface. // caller must Release() the returned surface -gl::Error TextureStorage9_Cube::getSurfaceLevel(GLenum target, +gl::Error TextureStorage9_Cube::getSurfaceLevel(const gl::Context *context, + GLenum target, int level, bool dirty, IDirect3DSurface9 **outSurface) { - IDirect3DBaseTexture9 *baseTexture = NULL; - gl::Error error = getBaseTexture(&baseTexture); + IDirect3DBaseTexture9 *baseTexture = nullptr; + gl::Error error = getBaseTexture(context, &baseTexture); if (error.isError()) { return error; @@ -483,35 +496,38 @@ gl::Error TextureStorage9_Cube::getSurfaceLevel(GLenum target, 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); + return gl::OutOfMemory() << "Failed to get the surface from a texture, " + << gl::FmtHR(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); + texture->AddDirtyRect(face, nullptr); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureStorage9_Cube::getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT) +gl::Error TextureStorage9_Cube::getRenderTarget(const gl::Context *context, + const gl::ImageIndex &index, + RenderTargetD3D **outRT) { ASSERT(outRT); ASSERT(index.mipIndex == 0); - ASSERT(index.layerIndex >= 0 && index.layerIndex < CUBE_FACE_COUNT); + ASSERT(index.layerIndex >= 0 && static_cast(index.layerIndex) < gl::CUBE_FACE_COUNT); - if (mRenderTarget[index.layerIndex] == NULL && isRenderTarget()) + if (mRenderTarget[index.layerIndex] == nullptr && isRenderTarget()) { - IDirect3DBaseTexture9 *baseTexture = NULL; - gl::Error error = getBaseTexture(&baseTexture); + IDirect3DBaseTexture9 *baseTexture = nullptr; + gl::Error error = getBaseTexture(context, &baseTexture); if (error.isError()) { return error; } - IDirect3DSurface9 *surface = NULL; - error = getSurfaceLevel(GL_TEXTURE_CUBE_MAP_POSITIVE_X + index.layerIndex, + IDirect3DSurface9 *surface = nullptr; + error = getSurfaceLevel(context, GL_TEXTURE_CUBE_MAP_POSITIVE_X + index.layerIndex, mTopLevel + index.mipIndex, false, &surface); if (error.isError()) { @@ -525,20 +541,23 @@ gl::Error TextureStorage9_Cube::getRenderTarget(const gl::ImageIndex &index, Ren } *outRT = mRenderTarget[index.layerIndex]; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureStorage9_Cube::generateMipmap(const gl::ImageIndex &sourceIndex, const gl::ImageIndex &destIndex) +gl::Error TextureStorage9_Cube::generateMipmap(const gl::Context *context, + const gl::ImageIndex &sourceIndex, + const gl::ImageIndex &destIndex) { - IDirect3DSurface9 *upper = NULL; - gl::Error error = getSurfaceLevel(sourceIndex.type, sourceIndex.mipIndex, false, &upper); + IDirect3DSurface9 *upper = nullptr; + gl::Error error = + getSurfaceLevel(context, sourceIndex.type, sourceIndex.mipIndex, false, &upper); if (error.isError()) { return error; } - IDirect3DSurface9 *lower = NULL; - error = getSurfaceLevel(destIndex.type, destIndex.mipIndex, true, &lower); + IDirect3DSurface9 *lower = nullptr; + error = getSurfaceLevel(context, destIndex.type, destIndex.mipIndex, true, &lower); if (error.isError()) { SafeRelease(upper); @@ -554,52 +573,56 @@ gl::Error TextureStorage9_Cube::generateMipmap(const gl::ImageIndex &sourceIndex return error; } -gl::Error TextureStorage9_Cube::getBaseTexture(IDirect3DBaseTexture9 **outTexture) +gl::Error TextureStorage9_Cube::getBaseTexture(const gl::Context *context, + 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) + if (mTexture == nullptr && mTextureWidth > 0 && mTextureHeight > 0) { ASSERT(mMipLevels > 0); ASSERT(mTextureWidth == mTextureHeight); IDirect3DDevice9 *device = mRenderer->getDevice(); - HRESULT result = device->CreateCubeTexture( + HRESULT result = device->CreateCubeTexture( static_cast(mTextureWidth), static_cast(mMipLevels), - getUsage(), mTextureFormat, getPool(), &mTexture, NULL); + getUsage(), mTextureFormat, getPool(), &mTexture, nullptr); 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); + return gl::OutOfMemory() + << "Failed to create cube storage texture, " << gl::FmtHR(result); } } *outTexture = mTexture; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureStorage9_Cube::copyToStorage(TextureStorage *destStorage) +gl::Error TextureStorage9_Cube::copyToStorage(const gl::Context *context, + TextureStorage *destStorage) { ASSERT(destStorage); TextureStorage9_Cube *dest9 = GetAs(destStorage); int levels = getLevelCount(); - for (int f = 0; f < CUBE_FACE_COUNT; f++) + for (int f = 0; f < static_cast(gl::CUBE_FACE_COUNT); f++) { for (int i = 0; i < levels; i++) { - IDirect3DSurface9 *srcSurf = NULL; + IDirect3DSurface9 *srcSurf = nullptr; gl::Error error = - getSurfaceLevel(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i, false, &srcSurf); + getSurfaceLevel(context, GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i, false, &srcSurf); if (error.isError()) { return error; } - IDirect3DSurface9 *dstSurf = NULL; - error = dest9->getSurfaceLevel(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i, true, &dstSurf); + IDirect3DSurface9 *dstSurf = nullptr; + error = dest9->getSurfaceLevel(context, GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i, true, + &dstSurf); if (error.isError()) { SafeRelease(srcSurf); @@ -618,7 +641,7 @@ gl::Error TextureStorage9_Cube::copyToStorage(TextureStorage *destStorage) } } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } } diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/TextureStorage9.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/TextureStorage9.h index 50e63a6f14..2f51901931 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/TextureStorage9.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/TextureStorage9.h @@ -25,28 +25,34 @@ class RenderTarget9; class TextureStorage9 : public TextureStorage { public: - virtual ~TextureStorage9(); + ~TextureStorage9() override; static DWORD GetTextureUsage(GLenum internalformat, bool renderTarget); D3DPOOL getPool() const; DWORD getUsage() const; - virtual gl::Error getSurfaceLevel(GLenum target, + virtual gl::Error getSurfaceLevel(const gl::Context *context, + GLenum target, int level, bool dirty, IDirect3DSurface9 **outSurface) = 0; - virtual gl::Error getBaseTexture(IDirect3DBaseTexture9 **outTexture) = 0; - virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT) = 0; + virtual gl::Error getBaseTexture(const gl::Context *context, + IDirect3DBaseTexture9 **outTexture) = 0; - virtual int getTopLevel() const; - virtual bool isRenderTarget() const; - virtual bool isManaged() const; + int getTopLevel() const override; + bool isRenderTarget() const override; + bool isManaged() const override; bool supportsNativeMipmapFunction() const override; - virtual int getLevelCount() const; + int getLevelCount() const override; - virtual gl::Error setData(const gl::ImageIndex &index, ImageD3D *image, const gl::Box *destBox, GLenum type, - const gl::PixelUnpackState &unpack, const uint8_t *pixelData); + gl::Error setData(const gl::Context *context, + const gl::ImageIndex &index, + ImageD3D *image, + const gl::Box *destBox, + GLenum type, + const gl::PixelUnpackState &unpack, + const uint8_t *pixelData) override; protected: int mTopLevel; @@ -70,16 +76,22 @@ 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(); + ~TextureStorage9_2D() override; - gl::Error getSurfaceLevel(GLenum target, + gl::Error getSurfaceLevel(const gl::Context *context, + GLenum target, int level, bool dirty, IDirect3DSurface9 **outSurface) override; - 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); + gl::Error getRenderTarget(const gl::Context *context, + const gl::ImageIndex &index, + RenderTargetD3D **outRT) override; + gl::Error getBaseTexture(const gl::Context *context, + IDirect3DBaseTexture9 **outTexture) override; + gl::Error generateMipmap(const gl::Context *context, + const gl::ImageIndex &sourceIndex, + const gl::ImageIndex &destIndex) override; + gl::Error copyToStorage(const gl::Context *context, TextureStorage *destStorage) override; private: IDirect3DTexture9 *mTexture; @@ -89,18 +101,23 @@ class TextureStorage9_2D : public TextureStorage9 class TextureStorage9_EGLImage final : public TextureStorage9 { public: - TextureStorage9_EGLImage(Renderer9 *renderer, EGLImageD3D *image); + TextureStorage9_EGLImage(Renderer9 *renderer, EGLImageD3D *image, RenderTarget9 *renderTarget9); ~TextureStorage9_EGLImage() override; - gl::Error getSurfaceLevel(GLenum target, + gl::Error getSurfaceLevel(const gl::Context *context, + GLenum target, int level, bool dirty, IDirect3DSurface9 **outSurface) override; - gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT) override; - gl::Error getBaseTexture(IDirect3DBaseTexture9 **outTexture) override; - gl::Error generateMipmap(const gl::ImageIndex &sourceIndex, + gl::Error getRenderTarget(const gl::Context *context, + const gl::ImageIndex &index, + RenderTargetD3D **outRT) override; + gl::Error getBaseTexture(const gl::Context *context, + IDirect3DBaseTexture9 **outTexture) override; + gl::Error generateMipmap(const gl::Context *context, + const gl::ImageIndex &sourceIndex, const gl::ImageIndex &destIndex) override; - gl::Error copyToStorage(TextureStorage *destStorage) override; + gl::Error copyToStorage(const gl::Context *context, TextureStorage *destStorage) override; private: EGLImageD3D *mImage; @@ -110,25 +127,28 @@ class TextureStorage9_Cube : public TextureStorage9 { public: TextureStorage9_Cube(Renderer9 *renderer, GLenum internalformat, bool renderTarget, int size, int levels, bool hintLevelZeroOnly); - virtual ~TextureStorage9_Cube(); + ~TextureStorage9_Cube() override; - gl::Error getSurfaceLevel(GLenum target, + gl::Error getSurfaceLevel(const gl::Context *context, + GLenum target, int level, bool dirty, IDirect3DSurface9 **outSurface) override; - 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); + gl::Error getRenderTarget(const gl::Context *context, + const gl::ImageIndex &index, + RenderTargetD3D **outRT) override; + gl::Error getBaseTexture(const gl::Context *context, + IDirect3DBaseTexture9 **outTexture) override; + gl::Error generateMipmap(const gl::Context *context, + const gl::ImageIndex &sourceIndex, + const gl::ImageIndex &destIndex) override; + gl::Error copyToStorage(const gl::Context *context, TextureStorage *destStorage) override; private: - static const size_t CUBE_FACE_COUNT = 6; - IDirect3DCubeTexture9 *mTexture; - RenderTarget9 *mRenderTarget[CUBE_FACE_COUNT]; + RenderTarget9 *mRenderTarget[gl::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 index 992201737f..0f4410b8de 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/VertexArray9.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/VertexArray9.h @@ -9,7 +9,9 @@ #ifndef LIBANGLE_RENDERER_D3D_D3D9_VERTEXARRAY9_H_ #define LIBANGLE_RENDERER_D3D_D3D9_VERTEXARRAY9_H_ +#include "libANGLE/Context.h" #include "libANGLE/renderer/VertexArrayImpl.h" +#include "libANGLE/renderer/d3d/d3d9/Context9.h" #include "libANGLE/renderer/d3d/d3d9/Renderer9.h" namespace rx @@ -19,14 +21,26 @@ class Renderer9; class VertexArray9 : public VertexArrayImpl { public: - VertexArray9(const gl::VertexArray::Data &data) - : VertexArrayImpl(data) - { - } + VertexArray9(const gl::VertexArrayState &data) : VertexArrayImpl(data) {} - virtual ~VertexArray9() { } + void syncState(const gl::Context *context, + const gl::VertexArray::DirtyBits &dirtyBits) override; + + ~VertexArray9() override {} + + Serial getCurrentStateSerial() const { return mCurrentStateSerial; } + + private: + Serial mCurrentStateSerial; }; +inline void VertexArray9::syncState(const gl::Context *context, + const gl::VertexArray::DirtyBits &dirtyBits) +{ + ASSERT(dirtyBits.any()); + Renderer9 *renderer = GetImplAs(context)->getRenderer(); + mCurrentStateSerial = renderer->generateSerial(); +} } #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 index bfdf137126..c0b80a847c 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/VertexBuffer9.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/VertexBuffer9.cpp @@ -19,7 +19,7 @@ namespace rx VertexBuffer9::VertexBuffer9(Renderer9 *renderer) : mRenderer(renderer) { - mVertexBuffer = NULL; + mVertexBuffer = nullptr; mBufferSize = 0; mDynamicUsage = false; } @@ -47,16 +47,18 @@ gl::Error VertexBuffer9::initialize(unsigned int size, bool dynamicUsage) if (FAILED(result)) { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate internal vertex buffer of size, %lu.", size); + return gl::OutOfMemory() + << "Failed to allocate internal vertex buffer of size " << size; } } mBufferSize = size; mDynamicUsage = dynamicUsage; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } gl::Error VertexBuffer9::storeVertexAttributes(const gl::VertexAttribute &attrib, + const gl::VertexBinding &binding, GLenum currentValueType, GLint start, GLsizei count, @@ -66,32 +68,33 @@ gl::Error VertexBuffer9::storeVertexAttributes(const gl::VertexAttribute &attrib { if (!mVertexBuffer) { - return gl::Error(GL_OUT_OF_MEMORY, "Internal vertex buffer is not initialized."); + return gl::OutOfMemory() << "Internal vertex buffer is not initialized."; } - int inputStride = static_cast(gl::ComputeVertexAttributeStride(attrib)); + int inputStride = static_cast(gl::ComputeVertexAttributeStride(attrib, binding)); int elementSize = static_cast(gl::ComputeVertexAttributeTypeSize(attrib)); DWORD lockFlags = mDynamicUsage ? D3DLOCK_NOOVERWRITE : 0; - uint8_t *mapPtr = NULL; + uint8_t *mapPtr = nullptr; - unsigned int mapSize; - gl::Error error = spaceRequired(attrib, count, instances, &mapSize); - if (error.isError()) + auto errorOrMapSize = mRenderer->getVertexSpaceRequired(attrib, binding, count, instances); + if (errorOrMapSize.isError()) { - return error; + return errorOrMapSize.getError(); } + unsigned int mapSize = errorOrMapSize.getResult(); + 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); + return gl::OutOfMemory() << "Failed to lock internal vertex buffer, " << gl::FmtHR(result); } const uint8_t *input = sourceData; - if (instances == 0 || attrib.divisor == 0) + if (instances == 0 || binding.getDivisor() == 0) { input += inputStride * start; } @@ -112,13 +115,7 @@ gl::Error VertexBuffer9::storeVertexAttributes(const gl::VertexAttribute &attrib 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); + return gl::NoError(); } unsigned int VertexBuffer9::getBufferSize() const @@ -134,7 +131,7 @@ gl::Error VertexBuffer9::setBufferSize(unsigned int size) } else { - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } } @@ -142,7 +139,7 @@ gl::Error VertexBuffer9::discard() { if (!mVertexBuffer) { - return gl::Error(GL_OUT_OF_MEMORY, "Internal vertex buffer is not initialized."); + return gl::OutOfMemory() << "Internal vertex buffer is not initialized."; } void *dummy; @@ -151,65 +148,22 @@ gl::Error VertexBuffer9::discard() 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); + return gl::OutOfMemory() << "Failed to lock internal buffer for discarding, " + << gl::FmtHR(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::OutOfMemory() << "Failed to unlock internal buffer for discarding, " + << gl::FmtHR(result); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } 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::VertexFormatType vertexFormatType = gl::GetVertexFormatType(attrib, GL_FLOAT); - const d3d9::VertexFormat &d3d9VertexInfo = d3d9::GetVertexFormatInfo(mRenderer->getCapsDeclTypes(), vertexFormatType); - - if (attrib.enabled) - { - unsigned int elementCount = 0; - if (instances == 0 || attrib.divisor == 0) - { - elementCount = static_cast(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 = - static_cast(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); - } -} - -} +} // namespace rx diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/VertexBuffer9.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/VertexBuffer9.h index 64271cbe2a..983616f4e4 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/VertexBuffer9.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/VertexBuffer9.h @@ -19,11 +19,13 @@ class VertexBuffer9 : public VertexBuffer { public: explicit VertexBuffer9(Renderer9 *renderer); - virtual ~VertexBuffer9(); - virtual gl::Error initialize(unsigned int size, bool dynamicUsage); + gl::Error initialize(unsigned int size, bool dynamicUsage) override; + // Warning: you should ensure binding really matches attrib.bindingIndex before using this + // function. gl::Error storeVertexAttributes(const gl::VertexAttribute &attrib, + const gl::VertexBinding &binding, GLenum currentValueType, GLint start, GLsizei count, @@ -31,23 +33,19 @@ class VertexBuffer9 : public VertexBuffer unsigned int offset, const uint8_t *sourceData) override; - 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(); + unsigned int getBufferSize() const override; + gl::Error setBufferSize(unsigned int size) override; + gl::Error discard() override; IDirect3DVertexBuffer9 *getBuffer() const; private: + ~VertexBuffer9() override; 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; }; } diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/VertexDeclarationCache.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/VertexDeclarationCache.cpp index a23ab4a290..abadf5c0b5 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/VertexDeclarationCache.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/VertexDeclarationCache.cpp @@ -21,7 +21,7 @@ VertexDeclarationCache::VertexDeclarationCache() : mMaxLru(0) { for (int i = 0; i < NUM_VERTEX_DECL_CACHE_ENTRIES; i++) { - mVertexDeclCache[i].vertexDeclaration = NULL; + mVertexDeclCache[i].vertexDeclaration = nullptr; mVertexDeclCache[i].lruCount = 0; } @@ -30,7 +30,7 @@ VertexDeclarationCache::VertexDeclarationCache() : mMaxLru(0) mAppliedVBs[i].serial = 0; } - mLastSetVDecl = NULL; + mLastSetVDecl = nullptr; mInstancingEnabled = true; } @@ -42,11 +42,13 @@ VertexDeclarationCache::~VertexDeclarationCache() } } -gl::Error VertexDeclarationCache::applyDeclaration(IDirect3DDevice9 *device, - const std::vector &attributes, - gl::Program *program, - GLsizei instances, - GLsizei *repeatDraw) +gl::Error VertexDeclarationCache::applyDeclaration( + IDirect3DDevice9 *device, + const std::vector &attributes, + gl::Program *program, + GLint start, + GLsizei instances, + GLsizei *repeatDraw) { ASSERT(gl::MAX_VERTEX_ATTRIBS >= attributes.size()); @@ -102,14 +104,14 @@ gl::Error VertexDeclarationCache::applyDeclaration(IDirect3DDevice9 *device, D3DVERTEXELEMENT9 *element = &elements[0]; ProgramD3D *programD3D = GetImplAs(program); - const auto &semanticIndexes = programD3D->getSemanticIndexes(); + const auto &semanticIndexes = programD3D->getAttribLocationToD3DSemantics(); for (size_t i = 0; i < attributes.size(); i++) { if (attributes[i].active) { // Directly binding the storage buffer is not supported for d3d9 - ASSERT(attributes[i].storage == NULL); + ASSERT(attributes[i].storage == nullptr); int stream = static_cast(i); @@ -147,19 +149,24 @@ gl::Error VertexDeclarationCache::applyDeclaration(IDirect3DDevice9 *device, } } - VertexBuffer9 *vertexBuffer = GetAs(attributes[i].vertexBuffer); + VertexBuffer9 *vertexBuffer = GetAs(attributes[i].vertexBuffer.get()); + + unsigned int offset = 0; + ANGLE_TRY_RESULT(attributes[i].computeOffset(start), offset); if (mAppliedVBs[stream].serial != attributes[i].serial || mAppliedVBs[stream].stride != attributes[i].stride || - mAppliedVBs[stream].offset != attributes[i].offset) + mAppliedVBs[stream].offset != offset) { - device->SetStreamSource(stream, vertexBuffer->getBuffer(), attributes[i].offset, attributes[i].stride); + device->SetStreamSource(stream, vertexBuffer->getBuffer(), offset, + attributes[i].stride); mAppliedVBs[stream].serial = attributes[i].serial; mAppliedVBs[stream].stride = attributes[i].stride; - mAppliedVBs[stream].offset = attributes[i].offset; + mAppliedVBs[stream].offset = offset; } - gl::VertexFormatType vertexformatType = gl::GetVertexFormatType(*attributes[i].attribute, GL_FLOAT); + gl::VertexFormatType vertexformatType = + gl::GetVertexFormatType(*attributes[i].attribute, GL_FLOAT); const d3d9::VertexFormat &d3d9VertexInfo = d3d9::GetVertexFormatInfo(caps.DeclTypes, vertexformatType); element->Stream = static_cast(stream); @@ -200,7 +207,7 @@ gl::Error VertexDeclarationCache::applyDeclaration(IDirect3DDevice9 *device, mLastSetVDecl = entry->vertexDeclaration; } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } } @@ -214,7 +221,7 @@ gl::Error VertexDeclarationCache::applyDeclaration(IDirect3DDevice9 *device, } } - if (lastCache->vertexDeclaration != NULL) + if (lastCache->vertexDeclaration != nullptr) { SafeRelease(lastCache->vertexDeclaration); // mLastSetVDecl is set to the replacement, so we don't have to worry @@ -225,14 +232,15 @@ gl::Error VertexDeclarationCache::applyDeclaration(IDirect3DDevice9 *device, 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); + return gl::OutOfMemory() << "Failed to create internal vertex declaration, " + << gl::FmtHR(result); } device->SetVertexDeclaration(lastCache->vertexDeclaration); mLastSetVDecl = lastCache->vertexDeclaration; lastCache->lruCount = ++mMaxLru; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } void VertexDeclarationCache::markStateDirty() @@ -242,7 +250,7 @@ void VertexDeclarationCache::markStateDirty() mAppliedVBs[i].serial = 0; } - mLastSetVDecl = NULL; + mLastSetVDecl = nullptr; 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 index bad4de4d6b..7bd7cabae4 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/VertexDeclarationCache.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/VertexDeclarationCache.h @@ -30,6 +30,7 @@ class VertexDeclarationCache gl::Error applyDeclaration(IDirect3DDevice9 *device, const std::vector &attributes, gl::Program *program, + GLint start, GLsizei instances, GLsizei *repeatDraw); diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/formatutils9.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/formatutils9.cpp index b672a60e3c..d10fa1ee87 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/formatutils9.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/formatutils9.cpp @@ -7,12 +7,16 @@ // 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 "image_util/copyimage.h" +#include "image_util/generatemip.h" +#include "image_util/loadimage.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" + +using namespace angle; namespace rx { @@ -20,35 +24,8 @@ 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; -} +constexpr D3DFORMAT D3DFMT_INTZ = ((D3DFORMAT)(MAKEFOURCC('I', 'N', 'T', 'Z'))); +constexpr D3DFORMAT D3DFMT_NULL = ((D3DFORMAT)(MAKEFOURCC('N', 'U', 'L', 'L'))); // A map to determine the pixel size and mip generation function of a given D3D format typedef std::map D3D9FormatInfoMap; @@ -64,109 +41,188 @@ D3DFormat::D3DFormat() luminanceBits(0), depthBits(0), stencilBits(0), - internalFormat(GL_NONE), - mipGenerationFunction(NULL), - colorReadFunction(NULL), - fastCopyFunctions() + formatID(angle::Format::ID::NONE) { } -ColorCopyFunction D3DFormat::getFastCopyFunction(GLenum format, GLenum type) const +D3DFormat::D3DFormat(GLuint bits, + GLuint blockWidth, + GLuint blockHeight, + GLuint redBits, + GLuint greenBits, + GLuint blueBits, + GLuint alphaBits, + GLuint lumBits, + GLuint depthBits, + GLuint stencilBits, + Format::ID formatID) + : pixelBytes(bits / 8), + blockWidth(blockWidth), + blockHeight(blockHeight), + redBits(redBits), + greenBits(greenBits), + blueBits(blueBits), + alphaBits(alphaBits), + luminanceBits(lumBits), + depthBits(depthBits), + stencilBits(stencilBits), + formatID(formatID) { - 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) +const D3DFormat &GetD3DFormatInfo(D3DFORMAT format) { - 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++) + if (format == D3DFMT_NULL) { - info.fastCopyFunctions.insert(std::make_pair(std::make_pair(i->second.destFormat, i->second.destType), i->second.copyFunction)); + static const D3DFormat info(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Format::ID::NONE); + return info; } - 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()) + if (format == D3DFMT_INTZ) { - return iter->second; + static const D3DFormat info(32, 1, 1, 0, 0, 0, 0, 0, 24, 8, Format::ID::D24_UNORM_S8_UINT); + return info; } - else + + switch (format) { - static const D3DFormat defaultInfo; - return defaultInfo; - } -} + case D3DFMT_UNKNOWN: + { + static const D3DFormat info(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Format::ID::NONE); + return info; + } + case D3DFMT_L8: + { + static const D3DFormat info(8, 1, 1, 0, 0, 0, 0, 8, 0, 0, Format::ID::L8_UNORM); + return info; + } + case D3DFMT_A8: + { + static const D3DFormat info(8, 1, 1, 0, 0, 0, 8, 0, 0, 0, Format::ID::A8_UNORM); + return info; + } + case D3DFMT_A8L8: + { + static const D3DFormat info(16, 1, 1, 0, 0, 0, 8, 8, 0, 0, Format::ID::L8A8_UNORM); + return info; + } + case D3DFMT_A4R4G4B4: + { + static const D3DFormat info(16, 1, 1, 4, 4, 4, 4, 0, 0, 0, Format::ID::B4G4R4A4_UNORM); + return info; + } + case D3DFMT_A1R5G5B5: + { + static const D3DFormat info(16, 1, 1, 5, 5, 5, 1, 0, 0, 0, Format::ID::B5G5R5A1_UNORM); + return info; + } + case D3DFMT_R5G6B5: + { + static const D3DFormat info(16, 1, 1, 5, 6, 5, 0, 0, 0, 0, Format::ID::R5G6B5_UNORM); + return info; + } + case D3DFMT_X8R8G8B8: + { + static const D3DFormat info(32, 1, 1, 8, 8, 8, 0, 0, 0, 0, Format::ID::B8G8R8X8_UNORM); + return info; + } + case D3DFMT_A8R8G8B8: + { + static const D3DFormat info(32, 1, 1, 8, 8, 8, 8, 0, 0, 0, Format::ID::B8G8R8A8_UNORM); + return info; + } + + case D3DFMT_R16F: + { + static const D3DFormat info(16, 1, 1, 16, 0, 0, 0, 0, 0, 0, Format::ID::R16_FLOAT); + return info; + } + case D3DFMT_G16R16F: + { + static const D3DFormat info(32, 1, 1, 16, 16, 0, 0, 0, 0, 0, Format::ID::R16G16_FLOAT); + return info; + } + case D3DFMT_A16B16G16R16F: + { + static const D3DFormat info(64, 1, 1, 16, 16, 16, 16, 0, 0, 0, + Format::ID::R16G16B16A16_FLOAT); + return info; + } + case D3DFMT_R32F: + { + static const D3DFormat info(32, 1, 1, 32, 0, 0, 0, 0, 0, 0, Format::ID::R32_FLOAT); + return info; + } + case D3DFMT_G32R32F: + { + static const D3DFormat info(64, 1, 1, 32, 32, 0, 0, 0, 0, 0, Format::ID::R32G32_FLOAT); + return info; + } + case D3DFMT_A32B32G32R32F: + { + static const D3DFormat info(128, 1, 1, 32, 32, 32, 32, 0, 0, 0, + Format::ID::R32G32B32A32_FLOAT); + return info; + } + + case D3DFMT_D16: + { + static const D3DFormat info(16, 1, 1, 0, 0, 0, 0, 0, 16, 0, Format::ID::D16_UNORM); + return info; + } + case D3DFMT_D24S8: + { + static const D3DFormat info(32, 1, 1, 0, 0, 0, 0, 0, 24, 8, + Format::ID::D24_UNORM_S8_UINT); + return info; + } + case D3DFMT_D24X8: + { + static const D3DFormat info(32, 1, 1, 0, 0, 0, 0, 0, 24, 0, Format::ID::D16_UNORM); + return info; + } + case D3DFMT_D32: + { + static const D3DFormat info(32, 1, 1, 0, 0, 0, 0, 0, 32, 0, Format::ID::D32_UNORM); + return info; + } + + case D3DFMT_DXT1: + { + static const D3DFormat info(64, 4, 4, 0, 0, 0, 0, 0, 0, 0, + Format::ID::BC1_RGBA_UNORM_BLOCK); + return info; + } + case D3DFMT_DXT3: + { + static const D3DFormat info(128, 4, 4, 0, 0, 0, 0, 0, 0, 0, + Format::ID::BC2_RGBA_UNORM_BLOCK); + return info; + } + case D3DFMT_DXT5: + { + static const D3DFormat info(128, 4, 4, 0, 0, 0, 0, 0, 0, 0, + Format::ID::BC3_RGBA_UNORM_BLOCK); + return info; + } + + default: + { + static const D3DFormat defaultInfo; + return defaultInfo; + } + } +} typedef std::pair InternalFormatInitialzerPair; typedef std::map InternalFormatInitialzerMap; static InternalFormatInitialzerMap BuildInternalFormatInitialzerMap() { + using namespace angle; // For image initialization functions + InternalFormatInitialzerMap map; map.insert(InternalFormatInitialzerPair(GL_RGB16F, Initialize4ComponentData)); @@ -175,28 +231,6 @@ static InternalFormatInitialzerMap BuildInternalFormatInitialzerMap() 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) @@ -210,7 +244,7 @@ typedef std::map D3D9FormatMap; TextureFormat::TextureFormat() : texFormat(D3DFMT_UNKNOWN), renderFormat(D3DFMT_UNKNOWN), - dataInitializerFunction(NULL), + dataInitializerFunction(nullptr), loadFunction(UnreachableLoad) { } @@ -224,7 +258,8 @@ static inline void InsertD3D9FormatInfo(D3D9FormatMap *map, GLenum internalForma static const InternalFormatInitialzerMap dataInitializationMap = BuildInternalFormatInitialzerMap(); InternalFormatInitialzerMap::const_iterator dataInitIter = dataInitializationMap.find(internalFormat); - info.dataInitializerFunction = (dataInitIter != dataInitializationMap.end()) ? dataInitIter->second : NULL; + info.dataInitializerFunction = + (dataInitIter != dataInitializationMap.end()) ? dataInitIter->second : nullptr; info.loadFunction = loadFunction; @@ -233,8 +268,11 @@ static inline void InsertD3D9FormatInfo(D3D9FormatMap *map, GLenum internalForma static D3D9FormatMap BuildD3D9FormatMap() { + using namespace angle; // For image loading functions + D3D9FormatMap map; + // clang-format off // | Internal format | Texture format | Render format | Load function | InsertD3D9FormatInfo(&map, GL_NONE, D3DFMT_NULL, D3DFMT_NULL, UnreachableLoad ); @@ -268,11 +306,11 @@ static D3D9FormatMap BuildD3D9FormatMap() 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_ALPHA8_EXT, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, LoadA8ToBGRA8 ); 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_RGBA8_OES, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, LoadRGBA8ToBGRA8 ); 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 ); @@ -291,6 +329,7 @@ static D3D9FormatMap BuildD3D9FormatMap() // 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 ); + // clang-format on return map; } @@ -503,7 +542,7 @@ public: VertexFormat::VertexFormat() : conversionType(VERTEX_CONVERT_NONE), outputElementSize(0), - copyFunction(NULL), + copyFunction(nullptr), nativeFormat(D3DDECLTYPE_UNUSED), componentType(GL_NONE) { diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/formatutils9.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/formatutils9.h index c55010760d..1bef320b53 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/formatutils9.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/formatutils9.h @@ -15,6 +15,8 @@ #include "common/platform.h" #include "libANGLE/angletypes.h" #include "libANGLE/formatutils.h" +#include "libANGLE/renderer/Format.h" +#include "libANGLE/renderer/renderer_utils.h" #include "libANGLE/renderer/d3d/formatutilsD3D.h" namespace rx @@ -25,11 +27,22 @@ class Renderer9; namespace d3d9 { -typedef std::map, ColorCopyFunction> FastCopyFunctionMap; - struct D3DFormat { D3DFormat(); + D3DFormat(GLuint pixelBytes, + GLuint blockWidth, + GLuint blockHeight, + GLuint redBits, + GLuint greenBits, + GLuint blueBits, + GLuint alphaBits, + GLuint luminanceBits, + GLuint depthBits, + GLuint stencilBits, + angle::Format::ID formatID); + + const angle::Format &info() const { return angle::Format::Get(formatID); } GLuint pixelBytes; GLuint blockWidth; @@ -44,14 +57,9 @@ struct D3DFormat GLuint depthBits; GLuint stencilBits; - GLenum internalFormat; - - MipGenerationFunction mipGenerationFunction; - ColorReadFunction colorReadFunction; - - FastCopyFunctionMap fastCopyFunctions; - ColorCopyFunction getFastCopyFunction(GLenum format, GLenum type) const; + angle::Format::ID formatID; }; + const D3DFormat &GetD3DFormatInfo(D3DFORMAT format); struct VertexFormat 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 index 8622dc4d13..fd451a6e51 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/renderer9_utils.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/renderer9_utils.cpp @@ -17,7 +17,9 @@ #include "libANGLE/renderer/d3d/d3d9/formatutils9.h" #include "libANGLE/renderer/d3d/d3d9/RenderTarget9.h" #include "libANGLE/renderer/d3d/FramebufferD3D.h" -#include "libANGLE/renderer/d3d/WorkaroundsD3D.h" +#include "libANGLE/renderer/driver_utils.h" +#include "platform/Platform.h" +#include "platform/WorkaroundsD3D.h" #include "third_party/systeminfo/SystemInfo.h" @@ -133,21 +135,22 @@ D3DTEXTUREADDRESS ConvertTextureWrap(GLenum wrap) return d3dWrap; } -D3DCULL ConvertCullMode(GLenum cullFace, GLenum frontFace) +D3DCULL ConvertCullMode(gl::CullFaceMode 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(); + case gl::CullFaceMode::Front: + cull = (frontFace == GL_CCW ? D3DCULL_CW : D3DCULL_CCW); + break; + case gl::CullFaceMode::Back: + cull = (frontFace == GL_CCW ? D3DCULL_CCW : D3DCULL_CW); + break; + case gl::CullFaceMode::FrontAndBack: + cull = D3DCULL_NONE; // culling will be handled during draw + break; + default: + UNREACHABLE(); } return cull; @@ -264,6 +267,21 @@ void ConvertMinFilter(GLenum minFilter, D3DTEXTUREFILTERTYPE *d3dMinFilter, D3DT } } +D3DQUERYTYPE ConvertQueryType(GLenum queryType) +{ + switch (queryType) + { + case GL_ANY_SAMPLES_PASSED_EXT: + case GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT: + return D3DQUERYTYPE_OCCLUSION; + case GL_COMMANDS_COMPLETED_CHROMIUM: + return D3DQUERYTYPE_EVENT; + default: + UNREACHABLE(); + return static_cast(0); + } +} + D3DMULTISAMPLE_TYPE GetMultisampleType(GLuint samples) { return (samples > 1) ? static_cast(samples) : D3DMULTISAMPLE_NONE; @@ -291,8 +309,8 @@ GLsizei GetSamplesCount(D3DMULTISAMPLE_TYPE type) bool IsFormatChannelEquivalent(D3DFORMAT d3dformat, GLenum format) { - GLenum internalFormat = d3d9::GetD3DFormatInfo(d3dformat).internalFormat; - GLenum convertedFormat = gl::GetInternalFormatInfo(internalFormat).format; + GLenum internalFormat = d3d9::GetD3DFormatInfo(d3dformat).info().glInternalFormat; + GLenum convertedFormat = gl::GetSizedInternalFormatInfo(internalFormat).format; return convertedFormat == format; } @@ -302,7 +320,7 @@ static gl::TextureCaps GenerateTextureFormatCaps(GLenum internalFormat, IDirect3 gl::TextureCaps textureCaps; const d3d9::TextureFormat &d3dFormatInfo = d3d9::GetTextureFormatInfo(internalFormat); - const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat); + const gl::InternalFormat &formatInfo = gl::GetSizedInternalFormatInfo(internalFormat); if (d3dFormatInfo.texFormat != D3DFMT_UNKNOWN) { @@ -333,7 +351,8 @@ static gl::TextureCaps GenerateTextureFormatCaps(GLenum internalFormat, IDirect3 { D3DMULTISAMPLE_TYPE multisampleType = D3DMULTISAMPLE_TYPE(i); - HRESULT result = d3d9->CheckDeviceMultiSampleType(adapter, deviceType, d3dFormatInfo.renderFormat, TRUE, multisampleType, NULL); + HRESULT result = d3d9->CheckDeviceMultiSampleType( + adapter, deviceType, d3dFormatInfo.renderFormat, TRUE, multisampleType, nullptr); if (SUCCEEDED(result)) { textureCaps.sampleCounts.insert(i); @@ -364,18 +383,17 @@ void GenerateCaps(IDirect3D9 *d3d9, 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) + for (GLenum internalFormat : gl::GetAllSizedInternalFormats()) { - gl::TextureCaps textureCaps = GenerateTextureFormatCaps(*internalFormat, d3d9, deviceType, adapter, - currentDisplayMode.Format); - textureCapsMap->insert(*internalFormat, textureCaps); + 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) + if (gl::GetSizedInternalFormatInfo(internalFormat).compressed) { - caps->compressedTextureFormats.push_back(*internalFormat); + caps->compressedTextureFormats.push_back(internalFormat); } } @@ -444,6 +462,8 @@ void GenerateCaps(IDirect3D9 *d3d9, // Vertex shader limits caps->maxVertexAttributes = 16; + // Vertex Attrib Binding not supported. + caps->maxVertexAttribBindings = caps->maxVertexAttributes; const size_t MAX_VERTEX_CONSTANT_VECTORS_D3D9 = 256; caps->maxVertexUniformVectors = @@ -525,12 +545,12 @@ void GenerateCaps(IDirect3D9 *d3d9, { // 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); + !(deviceCaps.TextureCaps & D3DPTEXTURECAPS_CUBEMAP_POW2) && + !(deviceCaps.TextureCaps & D3DPTEXTURECAPS_NONPOW2CONDITIONAL) && + !(!isWindowsVistaOrGreater() && IsAMD(adapterId.VendorId)); // Disable depth texture support on AMD cards (See ANGLE issue 839) - if (adapterId.VendorId == VENDOR_ID_AMD) + if (IsAMD(adapterId.VendorId)) { extensions->depthTextures = false; } @@ -548,18 +568,21 @@ void GenerateCaps(IDirect3D9 *d3d9, extensions->maxTextureAnisotropy = static_cast(deviceCaps.MaxAnisotropy); // Check occlusion query support by trying to create one - IDirect3DQuery9 *occlusionQuery = NULL; + IDirect3DQuery9 *occlusionQuery = nullptr; extensions->occlusionQueryBoolean = SUCCEEDED(device->CreateQuery(D3DQUERYTYPE_OCCLUSION, &occlusionQuery)) && occlusionQuery; SafeRelease(occlusionQuery); // Check event query support by trying to create one - IDirect3DQuery9 *eventQuery = NULL; + IDirect3DQuery9 *eventQuery = nullptr; extensions->fence = SUCCEEDED(device->CreateQuery(D3DQUERYTYPE_EVENT, &eventQuery)) && eventQuery; SafeRelease(eventQuery); - extensions->timerQuery = false; // Unimplemented extensions->disjointTimerQuery = false; extensions->robustness = true; + // It seems that only DirectX 10 and higher enforce the well-defined behavior of always + // returning zero values when out-of-bounds reads. See + // https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_robustness.txt + extensions->robustBufferAccessBehavior = false; extensions->blendMinMax = true; extensions->framebufferBlit = true; extensions->framebufferMultisample = true; @@ -575,10 +598,11 @@ void GenerateCaps(IDirect3D9 *d3d9, extensions->colorBufferFloat = false; extensions->debugMarker = true; extensions->eglImage = true; + extensions->eglImageExternal = true; extensions->unpackSubimage = true; extensions->packSubimage = true; - extensions->vertexArrayObject = true; - extensions->noError = true; + extensions->syncQuery = extensions->fence; + extensions->copyTexture = true; // D3D9 has no concept of separate masks and refs for front and back faces in the depth stencil // state. @@ -625,15 +649,23 @@ void MakeValidSize(bool isImage, D3DFORMAT format, GLsizei *requestWidth, GLsize *levelOffset = upsampleCount; } -WorkaroundsD3D GenerateWorkarounds() +angle::WorkaroundsD3D GenerateWorkarounds() { - WorkaroundsD3D workarounds; + angle::WorkaroundsD3D workarounds; workarounds.mrtPerfWorkaround = true; workarounds.setDataFasterThanImageUpload = false; workarounds.useInstancedPointSpriteEmulation = false; + + // TODO(jmadill): Disable workaround when we have a fixed compiler DLL. + workarounds.expandIntegerPowExpressions = true; + + // Call platform hooks for testing overrides. + auto *platform = ANGLEPlatformCurrent(); + platform->overrideWorkaroundsD3D(platform, &workarounds); + return workarounds; } -} +} // namespace d3d9 -} +} // namespace rx 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 index aa494adb62..5b65b8910a 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/renderer9_utils.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/renderer9_utils.h @@ -10,9 +10,10 @@ #ifndef LIBANGLE_RENDERER_D3D_D3D9_RENDERER9UTILS_H_ #define LIBANGLE_RENDERER_D3D_D3D9_RENDERER9UTILS_H_ -#include "libANGLE/angletypes.h" +#include "common/Color.h" #include "libANGLE/Caps.h" #include "libANGLE/Error.h" +#include "platform/WorkaroundsD3D.h" namespace gl { @@ -22,7 +23,6 @@ class FramebufferAttachment; namespace rx { class RenderTarget9; -struct WorkaroundsD3D; namespace gl_d3d9 { @@ -33,12 +33,13 @@ D3DBLEND ConvertBlendFunc(GLenum blend); D3DBLENDOP ConvertBlendOp(GLenum blendOp); D3DSTENCILOP ConvertStencilOp(GLenum stencilOp); D3DTEXTUREADDRESS ConvertTextureWrap(GLenum wrap); -D3DCULL ConvertCullMode(GLenum cullFace, GLenum frontFace); +D3DCULL ConvertCullMode(gl::CullFaceMode 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 *d3dLodBias, float maxAnisotropy, size_t baseLevel); +D3DQUERYTYPE ConvertQueryType(GLenum queryType); D3DMULTISAMPLE_TYPE GetMultisampleType(GLuint samples); @@ -86,9 +87,9 @@ inline bool isDeviceLostError(HRESULT errorCode) } } -WorkaroundsD3D GenerateWorkarounds(); +angle::WorkaroundsD3D GenerateWorkarounds(); } -} +} // namespace d3d9 #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 index dc357d0fa6..ecc593cc78 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/shaders/Blit.ps +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/shaders/Blit.ps @@ -24,6 +24,23 @@ float4 luminanceps(float4 texcoord : TEXCOORD0) : COLOR return (tex2D(tex, texcoord.xy).xw * mult.xw + add.xw).xxxy; }; +float4 luminancepremultps(float4 texcoord : TEXCOORD0) : COLOR +{ + float4 luma = tex2D(tex, texcoord.xy).xxxw; + luma.rgb *= luma.a; + return luma * mult + add; +}; + +float4 luminanceunmultps(float4 texcoord : TEXCOORD0) : COLOR +{ + float4 luma = tex2D(tex, texcoord.xy).xxxw; + if (luma.a > 0.0f) + { + luma.rgb /= luma.a; + } + return luma * mult + add; +}; + // 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 @@ -31,3 +48,20 @@ float4 componentmaskps(float4 texcoord : TEXCOORD0) : COLOR { return tex2D(tex, texcoord.xy) * mult + add; }; + +float4 componentmaskpremultps(float4 texcoord : TEXCOORD0) : COLOR +{ + float4 color = tex2D(tex, texcoord.xy); + color.rgb *= color.a; + return color * mult + add; +}; + +float4 componentmaskunmultps(float4 texcoord : TEXCOORD0) : COLOR +{ + float4 color = tex2D(tex, texcoord.xy); + if (color.a > 0.0f) + { + color.rgb /= color.a; + } + return color * 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 index 3a36980b93..c68395a69c 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/shaders/Blit.vs +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/shaders/Blit.vs @@ -11,6 +11,7 @@ struct VS_OUTPUT }; uniform float4 halfPixelSize : c0; +uniform float4 texcoordOffset : c1; // Standard Vertex Shader // Input 0 is the homogenous position. @@ -22,22 +23,7 @@ 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); + Out.texcoord = ((position * float4(0.5, -0.5, 1.0, 1.0) + float4(0.5, 0.5, 0, 0)) * float4(texcoordOffset.zw, 1.0, 1.0)) + float4(texcoordOffset.xy, 0, 0); return Out; }; diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/formatutilsD3D.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/formatutilsD3D.cpp deleted file mode 100644 index e1c955eb06..0000000000 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/formatutilsD3D.cpp +++ /dev/null @@ -1,147 +0,0 @@ -// -// 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 index 6dd59ca94b..a245a0432f 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/formatutilsD3D.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/formatutilsD3D.h @@ -15,24 +15,15 @@ #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); +#include -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); +namespace gl +{ +struct FormatType; +} +namespace rx +{ typedef void (*VertexCopyFunction)(const uint8_t *input, size_t stride, size_t count, uint8_t *output); enum VertexConversionType @@ -42,9 +33,6 @@ enum VertexConversionType VERTEX_CONVERT_GPU = 2, VERTEX_CONVERT_BOTH = 3 }; - -ColorWriteFunction GetColorWriteFunction(GLenum format, GLenum type); - -} +} // namespace rx #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 deleted file mode 100644 index 398ef26b30..0000000000 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/generatemip.h +++ /dev/null @@ -1,28 +0,0 @@ -// -// 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 deleted file mode 100644 index 265783641e..0000000000 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/generatemip.inl +++ /dev/null @@ -1,266 +0,0 @@ -// -// 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 deleted file mode 100644 index 76f1830e64..0000000000 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/imageformats.h +++ /dev/null @@ -1,1999 +0,0 @@ -// -// 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 -{ - // OpenGL ES 2.0.25 spec Section 3.6.2: "Components are packed with the first component in the most significant - // bits of the bitfield, and successive component occupying progressively less significant locations" - 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 A1R5G5B5 -{ - unsigned short ARGB; - - static void readColor(gl::ColorF *dst, const A1R5G5B5 *src) - { - dst->alpha = gl::normalizedToFloat<1>(gl::getShiftedData<1, 15>(src->ARGB)); - dst->red = gl::normalizedToFloat<5>(gl::getShiftedData<5, 10>(src->ARGB)); - dst->green = gl::normalizedToFloat<5>(gl::getShiftedData<5, 5>(src->ARGB)); - dst->blue = gl::normalizedToFloat<5>(gl::getShiftedData<5, 0>(src->ARGB)); - } - - static void writeColor(A1R5G5B5 *dst, const gl::ColorF *src) - { - dst->ARGB = 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(A1R5G5B5 *dst, const A1R5G5B5 *src1, const A1R5G5B5 *src2) - { - dst->ARGB = gl::shiftData<1, 15>(gl::average(gl::getShiftedData<1, 15>(src1->ARGB), gl::getShiftedData<1, 15>(src2->ARGB))) | - gl::shiftData<5, 10>(gl::average(gl::getShiftedData<5, 10>(src1->ARGB), gl::getShiftedData<5, 10>(src2->ARGB))) | - gl::shiftData<5, 5>(gl::average(gl::getShiftedData<5, 5>(src1->ARGB), gl::getShiftedData<5, 5>(src2->ARGB))) | - gl::shiftData<5, 0>(gl::average(gl::getShiftedData<5, 0>(src1->ARGB), gl::getShiftedData<5, 0>(src2->ARGB))); - } -}; - -struct R5G5B5A1 -{ - // OpenGL ES 2.0.25 spec Section 3.6.2: "Components are packed with the first component in the most significant - // bits of the bitfield, and successive component occupying progressively less significant locations" - unsigned short RGBA; - - static void readColor(gl::ColorF *dst, const R5G5B5A1 *src) - { - dst->red = gl::normalizedToFloat<5>(gl::getShiftedData<5, 11>(src->RGBA)); - dst->green = gl::normalizedToFloat<5>(gl::getShiftedData<5, 6>(src->RGBA)); - dst->blue = gl::normalizedToFloat<5>(gl::getShiftedData<5, 1>(src->RGBA)); - dst->alpha = gl::normalizedToFloat<1>(gl::getShiftedData<1, 0>(src->RGBA)); - } - - static void writeColor(R5G5B5A1 *dst, const gl::ColorF *src) - { - dst->RGBA = gl::shiftData<5, 11>(gl::floatToNormalized<5, unsigned short>(src->red)) | - gl::shiftData<5, 6>(gl::floatToNormalized<5, unsigned short>(src->green)) | - gl::shiftData<5, 1>(gl::floatToNormalized<5, unsigned short>(src->blue)) | - gl::shiftData<1, 0>(gl::floatToNormalized<1, unsigned short>(src->alpha)); - } - - static void average(R5G5B5A1 *dst, const R5G5B5A1 *src1, const R5G5B5A1 *src2) - { - dst->RGBA = gl::shiftData<5, 11>(gl::average(gl::getShiftedData<5, 11>(src1->RGBA), gl::getShiftedData<5, 11>(src2->RGBA))) | - gl::shiftData<5, 6>(gl::average(gl::getShiftedData<5, 6>(src1->RGBA), gl::getShiftedData<5, 6>(src2->RGBA))) | - gl::shiftData<5, 1>(gl::average(gl::getShiftedData<5, 1>(src1->RGBA), gl::getShiftedData<5, 1>(src2->RGBA))) | - gl::shiftData<1, 0>(gl::average(gl::getShiftedData<1, 0>(src1->RGBA), gl::getShiftedData<1, 0>(src2->RGBA))); - } -}; - -struct R4G4B4A4 -{ - // OpenGL ES 2.0.25 spec Section 3.6.2: "Components are packed with the first component in the most significant - // bits of the bitfield, and successive component occupying progressively less significant locations" - unsigned short RGBA; - - static void readColor(gl::ColorF *dst, const R4G4B4A4 *src) - { - dst->red = gl::normalizedToFloat<4>(gl::getShiftedData<4, 12>(src->RGBA)); - dst->green = gl::normalizedToFloat<4>(gl::getShiftedData<4, 8>(src->RGBA)); - dst->blue = gl::normalizedToFloat<4>(gl::getShiftedData<4, 4>(src->RGBA)); - dst->alpha = gl::normalizedToFloat<4>(gl::getShiftedData<4, 0>(src->RGBA)); - } - - static void writeColor(R4G4B4A4 *dst, const gl::ColorF *src) - { - dst->RGBA = gl::shiftData<4, 12>(gl::floatToNormalized<4, unsigned short>(src->red)) | - gl::shiftData<4, 8>(gl::floatToNormalized<4, unsigned short>(src->green)) | - gl::shiftData<4, 4>(gl::floatToNormalized<4, unsigned short>(src->blue)) | - gl::shiftData<4, 0>(gl::floatToNormalized<4, unsigned short>(src->alpha)); - } - - static void average(R4G4B4A4 *dst, const R4G4B4A4 *src1, const R4G4B4A4 *src2) - { - dst->RGBA = gl::shiftData<4, 12>(gl::average(gl::getShiftedData<4, 12>(src1->RGBA), gl::getShiftedData<4, 12>(src2->RGBA))) | - gl::shiftData<4, 8>(gl::average(gl::getShiftedData<4, 8>(src1->RGBA), gl::getShiftedData<4, 8>(src2->RGBA))) | - gl::shiftData<4, 4>(gl::average(gl::getShiftedData<4, 4>(src1->RGBA), gl::getShiftedData<4, 4>(src2->RGBA))) | - gl::shiftData<4, 0>(gl::average(gl::getShiftedData<4, 0>(src1->RGBA), gl::getShiftedData<4, 0>(src2->RGBA))); - } -}; - -struct A4R4G4B4 -{ - unsigned short ARGB; - - static void readColor(gl::ColorF *dst, const A4R4G4B4 *src) - { - dst->alpha = gl::normalizedToFloat<4>(gl::getShiftedData<4, 12>(src->ARGB)); - dst->red = gl::normalizedToFloat<4>(gl::getShiftedData<4, 8>(src->ARGB)); - dst->green = gl::normalizedToFloat<4>(gl::getShiftedData<4, 4>(src->ARGB)); - dst->blue = gl::normalizedToFloat<4>(gl::getShiftedData<4, 0>(src->ARGB)); - } - - static void writeColor(A4R4G4B4 *dst, const gl::ColorF *src) - { - dst->ARGB = gl::shiftData<4, 12>(gl::floatToNormalized<4, unsigned short>(src->alpha)) | - gl::shiftData<4, 8>(gl::floatToNormalized<4, unsigned short>(src->red)) | - gl::shiftData<4, 4>(gl::floatToNormalized<4, unsigned short>(src->green)) | - gl::shiftData<4, 0>(gl::floatToNormalized<4, unsigned short>(src->blue)); - } - - static void average(A4R4G4B4 *dst, const A4R4G4B4 *src1, const A4R4G4B4 *src2) - { - dst->ARGB = gl::shiftData<4, 12>(gl::average(gl::getShiftedData<4, 12>(src1->ARGB), gl::getShiftedData<4, 12>(src2->ARGB))) | - gl::shiftData<4, 8>(gl::average(gl::getShiftedData<4, 8>(src1->ARGB), gl::getShiftedData<4, 8>(src2->ARGB))) | - gl::shiftData<4, 4>(gl::average(gl::getShiftedData<4, 4>(src1->ARGB), gl::getShiftedData<4, 4>(src2->ARGB))) | - gl::shiftData<4, 0>(gl::average(gl::getShiftedData<4, 0>(src1->ARGB), gl::getShiftedData<4, 0>(src2->ARGB))); - } -}; - -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 = static_cast(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 = static_cast(gl::average(src1->R, src2->R)); - dst->G = static_cast(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 = static_cast(gl::average(src1->R, src2->R)); - dst->G = static_cast(gl::average(src1->G, src2->G)); - dst->B = static_cast(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 = static_cast(gl::average(src1->R, src2->R)); - dst->G = static_cast(gl::average(src1->G, src2->G)); - dst->B = static_cast(gl::average(src1->B, src2->B)); - dst->A = static_cast(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 deleted file mode 100644 index b9b9e5e4ab..0000000000 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/loadimage.cpp +++ /dev/null @@ -1,697 +0,0 @@ -// -// 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] = static_cast(((rgb & 0x001F) << 3) | ((rgb & 0x001F) >> 2)); - dest[4 * x + 1] = static_cast(((rgb & 0x07E0) >> 3) | ((rgb & 0x07E0) >> 9)); - dest[4 * x + 2] = static_cast(((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] = static_cast(((rgb & 0xF800) >> 8) | ((rgb & 0xF800) >> 13)); - dest[4 * x + 1] = static_cast(((rgb & 0x07E0) >> 3) | ((rgb & 0x07E0) >> 9)); - dest[4 * x + 2] = static_cast(((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 LoadRGBA4ToARGB4(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[x] = ANGLE_ROTR16(source[x], 4); - } - } - } -} - -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] = static_cast(((rgba & 0x00F0) << 0) | ((rgba & 0x00F0) >> 4)); - dest[4 * x + 1] = static_cast(((rgba & 0x0F00) >> 4) | ((rgba & 0x0F00) >> 8)); - dest[4 * x + 2] = static_cast(((rgba & 0xF000) >> 8) | ((rgba & 0xF000) >> 12)); - dest[4 * x + 3] = static_cast(((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] = static_cast(((rgba & 0xF000) >> 8) | ((rgba & 0xF000) >> 12)); - dest[4 * x + 1] = static_cast(((rgba & 0x0F00) >> 4) | ((rgba & 0x0F00) >> 8)); - dest[4 * x + 2] = static_cast(((rgba & 0x00F0) << 0) | ((rgba & 0x00F0) >> 4)); - dest[4 * x + 3] = static_cast(((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] = static_cast(((bgra & 0xF000) >> 8) | ((bgra & 0xF000) >> 12)); - dest[4 * x + 1] = static_cast(((bgra & 0x0F00) >> 4) | ((bgra & 0x0F00) >> 8)); - dest[4 * x + 2] = static_cast(((bgra & 0x00F0) << 0) | ((bgra & 0x00F0) >> 4)); - dest[4 * x + 3] = static_cast(((bgra & 0x000F) << 4) | ((bgra & 0x000F) >> 0)); - } - } - } -} - -void LoadRGB5A1ToA1RGB5(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[x] = ANGLE_ROTR16(source[x], 1); - } - } - } -} - -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] = static_cast(((rgba & 0x003E) << 2) | ((rgba & 0x003E) >> 3)); - dest[4 * x + 1] = static_cast(((rgba & 0x07C0) >> 3) | ((rgba & 0x07C0) >> 8)); - dest[4 * x + 2] = static_cast(((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13)); - dest[4 * x + 3] = static_cast((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] = static_cast(((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13)); - dest[4 * x + 1] = static_cast(((rgba & 0x07C0) >> 3) | ((rgba & 0x07C0) >> 8)); - dest[4 * x + 2] = static_cast(((rgba & 0x003E) << 2) | ((rgba & 0x003E) >> 3)); - dest[4 * x + 3] = static_cast((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] = static_cast(((bgra & 0xF800) >> 8) | ((bgra & 0xF800) >> 13)); - dest[4 * x + 1] = static_cast(((bgra & 0x07C0) >> 3) | ((bgra & 0x07C0) >> 8)); - dest[4 * x + 2] = static_cast(((bgra & 0x003E) << 2) | ((bgra & 0x003E) >> 3)); - dest[4 * x + 3] = static_cast((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] = static_cast((rgba & 0x000003FF) >> 2); - dest[4 * x + 1] = static_cast((rgba & 0x000FFC00) >> 12); - dest[4 * x + 2] = static_cast((rgba & 0x3FF00000) >> 22); - dest[4 * x + 3] = static_cast(((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 deleted file mode 100644 index 6c5118365e..0000000000 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/loadimage.h +++ /dev/null @@ -1,201 +0,0 @@ -// -// 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 LoadRGBA4ToARGB4(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 LoadRGB5A1ToA1RGB5(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 deleted file mode 100644 index 920e667db1..0000000000 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/loadimage.inl +++ /dev/null @@ -1,156 +0,0 @@ -// -// 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 deleted file mode 100644 index c87d35c82b..0000000000 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/loadimageSSE2.cpp +++ /dev/null @@ -1,125 +0,0 @@ -// -// 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/renderer/d3d/loadimage_etc.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/loadimage_etc.cpp deleted file mode 100644 index 26a3b32ce0..0000000000 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/loadimage_etc.cpp +++ /dev/null @@ -1,1435 +0,0 @@ -// -// 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_etc.cpp: Decodes ETC and EAC encoded textures. - -#include "libANGLE/renderer/d3d/loadimage_etc.h" - -#include "libANGLE/renderer/d3d/loadimage.h" -#include "libANGLE/renderer/d3d/imageformats.h" - -namespace rx -{ -namespace -{ -// Table 3.17.2 sorted according to table 3.17.3 -// clang-format off -static const int intensityModifierDefault[][4] = -{ - { 2, 8, -2, -8 }, - { 5, 17, -5, -17 }, - { 9, 29, -9, -29 }, - { 13, 42, -13, -42 }, - { 18, 60, -18, -60 }, - { 24, 80, -24, -80 }, - { 33, 106, -33, -106 }, - { 47, 183, -47, -183 }, -}; -// clang-format on - -// Table C.12, intensity modifier for non opaque punchthrough alpha -// clang-format off -static const int intensityModifierNonOpaque[][4] = -{ - { 0, 8, 0, -8 }, - { 0, 17, 0, -17 }, - { 0, 29, 0, -29 }, - { 0, 42, 0, -42 }, - { 0, 60, 0, -60 }, - { 0, 80, 0, -80 }, - { 0, 106, 0, -106 }, - { 0, 183, 0, -183 }, -}; -// clang-format on - -// Table C.7, mapping from pixel index values to modifier value orders -// clang-format off -static const int valueMappingTable[] = -{ - 2, 3, 1, 0 -}; -// clang-format on - -struct ETC2Block -{ - // Decodes unsigned single or dual channel block to bytes - void decodeAsSingleChannel(uint8_t *dest, - size_t x, - size_t y, - size_t w, - size_t h, - size_t destPixelStride, - size_t destRowPitch, - bool isSigned) const - { - for (size_t j = 0; j < 4 && (y + j) < h; j++) - { - uint8_t *row = dest + (j * destRowPitch); - for (size_t i = 0; i < 4 && (x + i) < w; i++) - { - uint8_t *pixel = row + (i * destPixelStride); - if (isSigned) - { - *pixel = clampSByte(getSingleChannel(i, j, isSigned)); - } - else - { - *pixel = clampByte(getSingleChannel(i, j, isSigned)); - } - } - } - } - - // Decodes RGB block to rgba8 - void decodeAsRGB(uint8_t *dest, - size_t x, - size_t y, - size_t w, - size_t h, - size_t destRowPitch, - const uint8_t alphaValues[4][4], - bool punchThroughAlpha) const - { - bool opaqueBit = u.idht.mode.idm.diffbit; - bool nonOpaquePunchThroughAlpha = punchThroughAlpha && !opaqueBit; - // Select mode - if (u.idht.mode.idm.diffbit || punchThroughAlpha) - { - const auto &block = u.idht.mode.idm.colors.diff; - int r = (block.R + block.dR); - int g = (block.G + block.dG); - int b = (block.B + block.dB); - if (r < 0 || r > 31) - { - decodeTBlock(dest, x, y, w, h, destRowPitch, alphaValues, - nonOpaquePunchThroughAlpha); - } - else if (g < 0 || g > 31) - { - decodeHBlock(dest, x, y, w, h, destRowPitch, alphaValues, - nonOpaquePunchThroughAlpha); - } - else if (b < 0 || b > 31) - { - decodePlanarBlock(dest, x, y, w, h, destRowPitch, alphaValues); - } - else - { - decodeDifferentialBlock(dest, x, y, w, h, destRowPitch, alphaValues, - nonOpaquePunchThroughAlpha); - } - } - else - { - decodeIndividualBlock(dest, x, y, w, h, destRowPitch, alphaValues, - nonOpaquePunchThroughAlpha); - } - } - - // Transcodes RGB block to BC1 - void transcodeAsBC1(uint8_t *dest, - size_t x, - size_t y, - size_t w, - size_t h, - const uint8_t alphaValues[4][4], - bool punchThroughAlpha) const - { - bool opaqueBit = u.idht.mode.idm.diffbit; - bool nonOpaquePunchThroughAlpha = punchThroughAlpha && !opaqueBit; - // Select mode - if (u.idht.mode.idm.diffbit || punchThroughAlpha) - { - const auto &block = u.idht.mode.idm.colors.diff; - int r = (block.R + block.dR); - int g = (block.G + block.dG); - int b = (block.B + block.dB); - if (r < 0 || r > 31) - { - transcodeTBlockToBC1(dest, x, y, w, h, alphaValues, nonOpaquePunchThroughAlpha); - } - else if (g < 0 || g > 31) - { - transcodeHBlockToBC1(dest, x, y, w, h, alphaValues, nonOpaquePunchThroughAlpha); - } - else if (b < 0 || b > 31) - { - transcodePlanarBlockToBC1(dest, x, y, w, h, alphaValues); - } - else - { - transcodeDifferentialBlockToBC1(dest, x, y, w, h, alphaValues, - nonOpaquePunchThroughAlpha); - } - } - else - { - transcodeIndividualBlockToBC1(dest, x, y, w, h, alphaValues, - nonOpaquePunchThroughAlpha); - } - } - - private: - union - { - // Individual, differential, H and T modes - struct - { - union - { - // Individual and differential modes - struct - { - union - { - struct // Individual colors - { - unsigned char R2 : 4; - unsigned char R1 : 4; - unsigned char G2 : 4; - unsigned char G1 : 4; - unsigned char B2 : 4; - unsigned char B1 : 4; - } indiv; - struct // Differential colors - { - signed char dR : 3; - unsigned char R : 5; - signed char dG : 3; - unsigned char G : 5; - signed char dB : 3; - unsigned char B : 5; - } diff; - } colors; - bool flipbit : 1; - bool diffbit : 1; - unsigned char cw2 : 3; - unsigned char cw1 : 3; - } idm; - // T mode - struct - { - // Byte 1 - unsigned char TR1b : 2; - unsigned char TdummyB : 1; - unsigned char TR1a : 2; - unsigned char TdummyA : 3; - // Byte 2 - unsigned char TB1 : 4; - unsigned char TG1 : 4; - // Byte 3 - unsigned char TG2 : 4; - unsigned char TR2 : 4; - // Byte 4 - unsigned char Tdb : 1; - bool Tflipbit : 1; - unsigned char Tda : 2; - unsigned char TB2 : 4; - } tm; - // H mode - struct - { - // Byte 1 - unsigned char HG1a : 3; - unsigned char HR1 : 4; - unsigned char HdummyA : 1; - // Byte 2 - unsigned char HB1b : 2; - unsigned char HdummyC : 1; - unsigned char HB1a : 1; - unsigned char HG1b : 1; - unsigned char HdummyB : 3; - // Byte 3 - unsigned char HG2a : 3; - unsigned char HR2 : 4; - unsigned char HB1c : 1; - // Byte 4 - unsigned char Hdb : 1; - bool Hflipbit : 1; - unsigned char Hda : 1; - unsigned char HB2 : 4; - unsigned char HG2b : 1; - } hm; - } mode; - unsigned char pixelIndexMSB[2]; - unsigned char pixelIndexLSB[2]; - } idht; - // planar mode - struct - { - // Byte 1 - unsigned char GO1 : 1; - unsigned char RO : 6; - unsigned char PdummyA : 1; - // Byte 2 - unsigned char BO1 : 1; - unsigned char GO2 : 6; - unsigned char PdummyB : 1; - // Byte 3 - unsigned char BO3a : 2; - unsigned char PdummyD : 1; - unsigned char BO2 : 2; - unsigned char PdummyC : 3; - // Byte 4 - unsigned char RH2 : 1; - bool Pflipbit : 1; - unsigned char RH1 : 5; - unsigned char BO3b : 1; - // Byte 5 - unsigned char BHa : 1; - unsigned char GH : 7; - // Byte 6 - unsigned char RVa : 3; - unsigned char BHb : 5; - // Byte 7 - unsigned char GVa : 5; - unsigned char RVb : 3; - // Byte 8 - unsigned char BV : 6; - unsigned char GVb : 2; - } pblk; - // Single channel block - struct - { - union - { - unsigned char us; - signed char s; - } base_codeword; - unsigned char table_index : 4; - unsigned char multiplier : 4; - unsigned char mc1 : 2; - unsigned char mb : 3; - unsigned char ma : 3; - unsigned char mf1 : 1; - unsigned char me : 3; - unsigned char md : 3; - unsigned char mc2 : 1; - unsigned char mh : 3; - unsigned char mg : 3; - unsigned char mf2 : 2; - unsigned char mk1 : 2; - unsigned char mj : 3; - unsigned char mi : 3; - unsigned char mn1 : 1; - unsigned char mm : 3; - unsigned char ml : 3; - unsigned char mk2 : 1; - unsigned char mp : 3; - unsigned char mo : 3; - unsigned char mn2 : 2; - } scblk; - } u; - - static unsigned char clampByte(int value) - { - return static_cast(gl::clamp(value, 0, 255)); - } - - static signed char clampSByte(int value) - { - return static_cast(gl::clamp(value, -128, 127)); - } - - static R8G8B8A8 createRGBA(int red, int green, int blue, int alpha) - { - R8G8B8A8 rgba; - rgba.R = clampByte(red); - rgba.G = clampByte(green); - rgba.B = clampByte(blue); - rgba.A = clampByte(alpha); - return rgba; - } - - static R8G8B8A8 createRGBA(int red, int green, int blue) - { - return createRGBA(red, green, blue, 255); - } - - static int extend_4to8bits(int x) { return (x << 4) | x; } - static int extend_5to8bits(int x) { return (x << 3) | (x >> 2); } - static int extend_6to8bits(int x) { return (x << 2) | (x >> 4); } - static int extend_7to8bits(int x) { return (x << 1) | (x >> 6); } - - void decodeIndividualBlock(uint8_t *dest, - size_t x, - size_t y, - size_t w, - size_t h, - size_t destRowPitch, - const uint8_t alphaValues[4][4], - bool nonOpaquePunchThroughAlpha) const - { - const auto &block = u.idht.mode.idm.colors.indiv; - int r1 = extend_4to8bits(block.R1); - int g1 = extend_4to8bits(block.G1); - int b1 = extend_4to8bits(block.B1); - int r2 = extend_4to8bits(block.R2); - int g2 = extend_4to8bits(block.G2); - int b2 = extend_4to8bits(block.B2); - decodeIndividualOrDifferentialBlock(dest, x, y, w, h, destRowPitch, r1, g1, b1, r2, g2, b2, - alphaValues, nonOpaquePunchThroughAlpha); - } - - void decodeDifferentialBlock(uint8_t *dest, - size_t x, - size_t y, - size_t w, - size_t h, - size_t destRowPitch, - const uint8_t alphaValues[4][4], - bool nonOpaquePunchThroughAlpha) const - { - const auto &block = u.idht.mode.idm.colors.diff; - int b1 = extend_5to8bits(block.B); - int g1 = extend_5to8bits(block.G); - int r1 = extend_5to8bits(block.R); - int r2 = extend_5to8bits(block.R + block.dR); - int g2 = extend_5to8bits(block.G + block.dG); - int b2 = extend_5to8bits(block.B + block.dB); - decodeIndividualOrDifferentialBlock(dest, x, y, w, h, destRowPitch, r1, g1, b1, r2, g2, b2, - alphaValues, nonOpaquePunchThroughAlpha); - } - - void decodeIndividualOrDifferentialBlock(uint8_t *dest, - size_t x, - size_t y, - size_t w, - size_t h, - size_t destRowPitch, - int r1, - int g1, - int b1, - int r2, - int g2, - int b2, - const uint8_t alphaValues[4][4], - bool nonOpaquePunchThroughAlpha) const - { - const auto intensityModifier = - nonOpaquePunchThroughAlpha ? intensityModifierNonOpaque : intensityModifierDefault; - - R8G8B8A8 subblockColors0[4]; - R8G8B8A8 subblockColors1[4]; - for (size_t modifierIdx = 0; modifierIdx < 4; modifierIdx++) - { - const int i1 = intensityModifier[u.idht.mode.idm.cw1][modifierIdx]; - subblockColors0[modifierIdx] = createRGBA(r1 + i1, g1 + i1, b1 + i1); - - const int i2 = intensityModifier[u.idht.mode.idm.cw2][modifierIdx]; - subblockColors1[modifierIdx] = createRGBA(r2 + i2, g2 + i2, b2 + i2); - } - - if (u.idht.mode.idm.flipbit) - { - uint8_t *curPixel = dest; - for (size_t j = 0; j < 2 && (y + j) < h; j++) - { - R8G8B8A8 *row = reinterpret_cast(curPixel); - for (size_t i = 0; i < 4 && (x + i) < w; i++) - { - row[i] = subblockColors0[getIndex(i, j)]; - row[i].A = alphaValues[j][i]; - } - curPixel += destRowPitch; - } - for (size_t j = 2; j < 4 && (y + j) < h; j++) - { - R8G8B8A8 *row = reinterpret_cast(curPixel); - for (size_t i = 0; i < 4 && (x + i) < w; i++) - { - row[i] = subblockColors1[getIndex(i, j)]; - row[i].A = alphaValues[j][i]; - } - curPixel += destRowPitch; - } - } - else - { - uint8_t *curPixel = dest; - for (size_t j = 0; j < 4 && (y + j) < h; j++) - { - R8G8B8A8 *row = reinterpret_cast(curPixel); - for (size_t i = 0; i < 2 && (x + i) < w; i++) - { - row[i] = subblockColors0[getIndex(i, j)]; - row[i].A = alphaValues[j][i]; - } - for (size_t i = 2; i < 4 && (x + i) < w; i++) - { - row[i] = subblockColors1[getIndex(i, j)]; - row[i].A = alphaValues[j][i]; - } - curPixel += destRowPitch; - } - } - if (nonOpaquePunchThroughAlpha) - { - decodePunchThroughAlphaBlock(dest, x, y, w, h, destRowPitch); - } - } - - void decodeTBlock(uint8_t *dest, - size_t x, - size_t y, - size_t w, - size_t h, - size_t destRowPitch, - const uint8_t alphaValues[4][4], - bool nonOpaquePunchThroughAlpha) const - { - // Table C.8, distance index for T and H modes - const auto &block = u.idht.mode.tm; - - int r1 = extend_4to8bits(block.TR1a << 2 | block.TR1b); - int g1 = extend_4to8bits(block.TG1); - int b1 = extend_4to8bits(block.TB1); - int r2 = extend_4to8bits(block.TR2); - int g2 = extend_4to8bits(block.TG2); - int b2 = extend_4to8bits(block.TB2); - - static int distance[8] = {3, 6, 11, 16, 23, 32, 41, 64}; - const int d = distance[block.Tda << 1 | block.Tdb]; - - const R8G8B8A8 paintColors[4] = { - createRGBA(r1, g1, b1), createRGBA(r2 + d, g2 + d, b2 + d), createRGBA(r2, g2, b2), - createRGBA(r2 - d, g2 - d, b2 - d), - }; - - uint8_t *curPixel = dest; - for (size_t j = 0; j < 4 && (y + j) < h; j++) - { - R8G8B8A8 *row = reinterpret_cast(curPixel); - for (size_t i = 0; i < 4 && (x + i) < w; i++) - { - row[i] = paintColors[getIndex(i, j)]; - row[i].A = alphaValues[j][i]; - } - curPixel += destRowPitch; - } - - if (nonOpaquePunchThroughAlpha) - { - decodePunchThroughAlphaBlock(dest, x, y, w, h, destRowPitch); - } - } - - void decodeHBlock(uint8_t *dest, - size_t x, - size_t y, - size_t w, - size_t h, - size_t destRowPitch, - const uint8_t alphaValues[4][4], - bool nonOpaquePunchThroughAlpha) const - { - // Table C.8, distance index for T and H modes - const auto &block = u.idht.mode.hm; - - int r1 = extend_4to8bits(block.HR1); - int g1 = extend_4to8bits(block.HG1a << 1 | block.HG1b); - int b1 = extend_4to8bits(block.HB1a << 3 | block.HB1b << 1 | block.HB1c); - int r2 = extend_4to8bits(block.HR2); - int g2 = extend_4to8bits(block.HG2a << 1 | block.HG2b); - int b2 = extend_4to8bits(block.HB2); - - static const int distance[8] = {3, 6, 11, 16, 23, 32, 41, 64}; - const int d = distance[(block.Hda << 2) | (block.Hdb << 1) | - ((r1 << 16 | g1 << 8 | b1) >= (r2 << 16 | g2 << 8 | b2) ? 1 : 0)]; - - const R8G8B8A8 paintColors[4] = { - createRGBA(r1 + d, g1 + d, b1 + d), createRGBA(r1 - d, g1 - d, b1 - d), - createRGBA(r2 + d, g2 + d, b2 + d), createRGBA(r2 - d, g2 - d, b2 - d), - }; - - uint8_t *curPixel = dest; - for (size_t j = 0; j < 4 && (y + j) < h; j++) - { - R8G8B8A8 *row = reinterpret_cast(curPixel); - for (size_t i = 0; i < 4 && (x + i) < w; i++) - { - row[i] = paintColors[getIndex(i, j)]; - row[i].A = alphaValues[j][i]; - } - curPixel += destRowPitch; - } - - if (nonOpaquePunchThroughAlpha) - { - decodePunchThroughAlphaBlock(dest, x, y, w, h, destRowPitch); - } - } - - void decodePlanarBlock(uint8_t *dest, - size_t x, - size_t y, - size_t w, - size_t h, - size_t pitch, - const uint8_t alphaValues[4][4]) const - { - int ro = extend_6to8bits(u.pblk.RO); - int go = extend_7to8bits(u.pblk.GO1 << 6 | u.pblk.GO2); - int bo = - extend_6to8bits(u.pblk.BO1 << 5 | u.pblk.BO2 << 3 | u.pblk.BO3a << 1 | u.pblk.BO3b); - int rh = extend_6to8bits(u.pblk.RH1 << 1 | u.pblk.RH2); - int gh = extend_7to8bits(u.pblk.GH); - int bh = extend_6to8bits(u.pblk.BHa << 5 | u.pblk.BHb); - int rv = extend_6to8bits(u.pblk.RVa << 3 | u.pblk.RVb); - int gv = extend_7to8bits(u.pblk.GVa << 2 | u.pblk.GVb); - int bv = extend_6to8bits(u.pblk.BV); - - uint8_t *curPixel = dest; - for (size_t j = 0; j < 4 && (y + j) < h; j++) - { - R8G8B8A8 *row = reinterpret_cast(curPixel); - - int ry = static_cast(j) * (rv - ro) + 2; - int gy = static_cast(j) * (gv - go) + 2; - int by = static_cast(j) * (bv - bo) + 2; - for (size_t i = 0; i < 4 && (x + i) < w; i++) - { - row[i] = createRGBA(((static_cast(i) * (rh - ro) + ry) >> 2) + ro, - ((static_cast(i) * (gh - go) + gy) >> 2) + go, - ((static_cast(i) * (bh - bo) + by) >> 2) + bo, - alphaValues[j][i]); - } - curPixel += pitch; - } - } - - // Index for individual, differential, H and T modes - size_t getIndex(size_t x, size_t y) const - { - size_t bitIndex = x * 4 + y; - size_t bitOffset = bitIndex & 7; - size_t lsb = (u.idht.pixelIndexLSB[1 - (bitIndex >> 3)] >> bitOffset) & 1; - size_t msb = (u.idht.pixelIndexMSB[1 - (bitIndex >> 3)] >> bitOffset) & 1; - return (msb << 1) | lsb; - } - - void decodePunchThroughAlphaBlock(uint8_t *dest, - size_t x, - size_t y, - size_t w, - size_t h, - size_t destRowPitch) const - { - uint8_t *curPixel = dest; - for (size_t j = 0; j < 4 && (y + j) < h; j++) - { - R8G8B8A8 *row = reinterpret_cast(curPixel); - for (size_t i = 0; i < 4 && (x + i) < w; i++) - { - if (getIndex(i, j) == 2) // msb == 1 && lsb == 0 - { - row[i] = createRGBA(0, 0, 0, 0); - } - } - curPixel += destRowPitch; - } - } - - uint16_t RGB8ToRGB565(const R8G8B8A8 &rgba) const - { - return (static_cast(rgba.R >> 3) << 11) | - (static_cast(rgba.G >> 2) << 5) | - (static_cast(rgba.B >> 3) << 0); - } - - uint32_t matchBC1Bits(const R8G8B8A8 *rgba, - const R8G8B8A8 &minColor, - const R8G8B8A8 &maxColor, - bool opaque) const - { - // Project each pixel on the (maxColor, minColor) line to decide which - // BC1 code to assign to it. - - uint8_t decodedColors[2][3] = {{maxColor.R, maxColor.G, maxColor.B}, - {minColor.R, minColor.G, minColor.B}}; - - int direction[3]; - for (int ch = 0; ch < 3; ch++) - { - direction[ch] = decodedColors[0][ch] - decodedColors[1][ch]; - } - - int stops[2]; - for (int i = 0; i < 2; i++) - { - stops[i] = decodedColors[i][0] * direction[0] + decodedColors[i][1] * direction[1] + - decodedColors[i][2] * direction[2]; - } - - uint32_t bits = 0; - if (opaque) - { - for (int i = 15; i >= 0; i--) - { - // In opaque mode, the code is from 0 to 3. - - bits <<= 2; - const int dot = - rgba[i].R * direction[0] + rgba[i].G * direction[1] + rgba[i].B * direction[2]; - const int factor = gl::clamp( - static_cast( - (static_cast(dot - stops[1]) / (stops[0] - stops[1])) * 3 + 0.5f), - 0, 3); - switch (factor) - { - case 0: - bits |= 1; - break; - case 1: - bits |= 3; - break; - case 2: - bits |= 2; - break; - case 3: - default: - bits |= 0; - break; - } - } - } - else - { - for (int i = 15; i >= 0; i--) - { - // In non-opaque mode, 3 is for tranparent pixels. - - bits <<= 2; - if (0 == rgba[i].A) - { - bits |= 3; - } - else - { - const int dot = rgba[i].R * direction[0] + rgba[i].G * direction[1] + - rgba[i].B * direction[2]; - const int factor = gl::clamp( - static_cast( - (static_cast(dot - stops[1]) / (stops[0] - stops[1])) * 2 + - 0.5f), - 0, 2); - switch (factor) - { - case 0: - bits |= 0; - break; - case 1: - bits |= 2; - break; - case 2: - default: - bits |= 1; - break; - } - } - } - } - - return bits; - } - - void packBC1(void *bc1, - const R8G8B8A8 *rgba, - R8G8B8A8 &minColor, - R8G8B8A8 &maxColor, - bool opaque) const - { - uint32_t bits; - uint16_t max16 = RGB8ToRGB565(maxColor); - uint16_t min16 = RGB8ToRGB565(minColor); - if (max16 != min16) - { - // Find the best BC1 code for each pixel - bits = matchBC1Bits(rgba, minColor, maxColor, opaque); - } - else - { - // Same colors, BC1 index 0 is the color in both opaque and transparent mode - bits = 0; - // BC1 index 3 is transparent - if (!opaque) - { - for (int i = 0; i < 16; i++) - { - if (0 == rgba[i].A) - { - bits |= (3 << (i * 2)); - } - } - } - } - - if (max16 < min16) - { - std::swap(max16, min16); - - uint32_t xorMask = 0; - if (opaque) - { - // In opaque mode switching the two colors is doing the - // following code swaps: 0 <-> 1 and 2 <-> 3. This is - // equivalent to flipping the first bit of each code - // (5 = 0b0101) - xorMask = 0x55555555; - } - else - { - // In transparent mode switching the colors is doing the - // following code swap: 0 <-> 1. 0xA selects the second bit of - // each code, bits >> 1 selects the first bit of the code when - // the seconds bit is set (case 2 and 3). We invert all the - // non-selected bits, that is the first bit when the code is - // 0 or 1. - xorMask = ~((bits >> 1) | 0xAAAAAAAA); - } - bits ^= xorMask; - } - - struct BC1Block - { - uint16_t color0; - uint16_t color1; - uint32_t bits; - }; - - // Encode the opaqueness in the order of the two BC1 colors - BC1Block *dest = reinterpret_cast(bc1); - if (opaque) - { - dest->color0 = max16; - dest->color1 = min16; - } - else - { - dest->color0 = min16; - dest->color1 = max16; - } - dest->bits = bits; - } - - void transcodeIndividualBlockToBC1(uint8_t *dest, - size_t x, - size_t y, - size_t w, - size_t h, - const uint8_t alphaValues[4][4], - bool nonOpaquePunchThroughAlpha) const - { - const auto &block = u.idht.mode.idm.colors.indiv; - int r1 = extend_4to8bits(block.R1); - int g1 = extend_4to8bits(block.G1); - int b1 = extend_4to8bits(block.B1); - int r2 = extend_4to8bits(block.R2); - int g2 = extend_4to8bits(block.G2); - int b2 = extend_4to8bits(block.B2); - transcodeIndividualOrDifferentialBlockToBC1(dest, x, y, w, h, r1, g1, b1, r2, g2, b2, - alphaValues, nonOpaquePunchThroughAlpha); - } - - void transcodeDifferentialBlockToBC1(uint8_t *dest, - size_t x, - size_t y, - size_t w, - size_t h, - const uint8_t alphaValues[4][4], - bool nonOpaquePunchThroughAlpha) const - { - const auto &block = u.idht.mode.idm.colors.diff; - int b1 = extend_5to8bits(block.B); - int g1 = extend_5to8bits(block.G); - int r1 = extend_5to8bits(block.R); - int r2 = extend_5to8bits(block.R + block.dR); - int g2 = extend_5to8bits(block.G + block.dG); - int b2 = extend_5to8bits(block.B + block.dB); - transcodeIndividualOrDifferentialBlockToBC1(dest, x, y, w, h, r1, g1, b1, r2, g2, b2, - alphaValues, nonOpaquePunchThroughAlpha); - } - - void decodeSubblock(R8G8B8A8 *rgbaBlock, - size_t pixelRange[2][2], - size_t x, - size_t y, - size_t w, - size_t h, - const uint8_t alphaValues[4][4], - bool flipbit, - size_t subblockIdx, - const R8G8B8A8 subblockColors[2][4]) const - { - size_t dxBegin = 0; - size_t dxEnd = 4; - size_t dyBegin = subblockIdx * 2; - size_t dyEnd = dyBegin + 2; - if (!flipbit) - { - std::swap(dxBegin, dyBegin); - std::swap(dxEnd, dyEnd); - } - - for (size_t j = dyBegin; j < dyEnd && (y + j) < h; j++) - { - R8G8B8A8 *row = &rgbaBlock[j * 4]; - for (size_t i = dxBegin; i < dxEnd && (x + i) < w; i++) - { - const size_t pixelIndex = getIndex(i, j); - if (valueMappingTable[pixelIndex] < valueMappingTable[pixelRange[subblockIdx][0]]) - { - pixelRange[subblockIdx][0] = pixelIndex; - } - if (valueMappingTable[pixelIndex] > valueMappingTable[pixelRange[subblockIdx][1]]) - { - pixelRange[subblockIdx][1] = pixelIndex; - } - - row[i] = subblockColors[subblockIdx][pixelIndex]; - row[i].A = alphaValues[j][i]; - } - } - } - - void transcodeIndividualOrDifferentialBlockToBC1(uint8_t *dest, - size_t x, - size_t y, - size_t w, - size_t h, - int r1, - int g1, - int b1, - int r2, - int g2, - int b2, - const uint8_t alphaValues[4][4], - bool nonOpaquePunchThroughAlpha) const - { - // A BC1 block has 2 endpoints, pixels is encoded as linear - // interpolations of them. A ETC1/ETC2 individual or differential block - // has 2 subblocks. Each subblock has one color and a modifier. We - // compute the max intensity and min intensity pixel values to use as - // our two BC1 endpoints and then map pixels to BC1 by projecting on the - // line between the two endpoints and choosing the right fraction. - // - // In the future, we have 2 potential improvements to this algorithm. - // 1. We don't actually need to decode ETC blocks to RGBs. Instead, - // the subblock colors and pixel indices alreay contains enough - // information for transcode. A direct mapping would be more - // efficient here. - // 2. Currently the BC1 endpoints come from the max and min intensity - // of ETC colors. A principal component analysis (PCA) on them might - // give us better quality results, with limited costs - - const auto intensityModifier = - nonOpaquePunchThroughAlpha ? intensityModifierNonOpaque : intensityModifierDefault; - - // Compute the colors that pixels can have in each subblock both for - // the decoding of the RGBA data and BC1 encoding - R8G8B8A8 subblockColors[2][4]; - for (size_t modifierIdx = 0; modifierIdx < 4; modifierIdx++) - { - const int i1 = intensityModifier[u.idht.mode.idm.cw1][modifierIdx]; - subblockColors[0][modifierIdx] = createRGBA(r1 + i1, g1 + i1, b1 + i1); - - const int i2 = intensityModifier[u.idht.mode.idm.cw2][modifierIdx]; - subblockColors[1][modifierIdx] = createRGBA(r2 + i2, g2 + i2, b2 + i2); - } - - // 1 and 3 are the argmax and argmin of valueMappingTable - size_t pixelRange[2][2] = {{1, 3}, {1, 3}}; - R8G8B8A8 rgbaBlock[16]; - // Decode the block in rgbaBlock and store the inverse valueTableMapping - // of {min(modifier index), max(modifier index)} - for (size_t blockIdx = 0; blockIdx < 2; blockIdx++) - { - decodeSubblock(rgbaBlock, pixelRange, x, y, w, h, alphaValues, u.idht.mode.idm.flipbit, - blockIdx, subblockColors); - } - if (nonOpaquePunchThroughAlpha) - { - decodePunchThroughAlphaBlock(reinterpret_cast(rgbaBlock), x, y, w, h, - sizeof(R8G8B8A8) * 4); - } - - // Get the "min" and "max" pixel colors that have been used. - R8G8B8A8 minColor; - const R8G8B8A8 &minColor0 = subblockColors[0][pixelRange[0][0]]; - const R8G8B8A8 &minColor1 = subblockColors[1][pixelRange[1][0]]; - if (minColor0.R + minColor0.G + minColor0.B < minColor1.R + minColor1.G + minColor1.B) - { - minColor = minColor0; - } - else - { - minColor = minColor1; - } - - R8G8B8A8 maxColor; - const R8G8B8A8 &maxColor0 = subblockColors[0][pixelRange[0][1]]; - const R8G8B8A8 &maxColor1 = subblockColors[1][pixelRange[1][1]]; - if (maxColor0.R + maxColor0.G + maxColor0.B < maxColor1.R + maxColor1.G + maxColor1.B) - { - maxColor = maxColor1; - } - else - { - maxColor = maxColor0; - } - - packBC1(dest, rgbaBlock, minColor, maxColor, !nonOpaquePunchThroughAlpha); - } - - void transcodeTBlockToBC1(uint8_t *dest, - size_t x, - size_t y, - size_t w, - size_t h, - const uint8_t alphaValues[4][4], - bool nonOpaquePunchThroughAlpha) const - { - // TODO (mgong): Will be implemented soon - UNIMPLEMENTED(); - } - - void transcodeHBlockToBC1(uint8_t *dest, - size_t x, - size_t y, - size_t w, - size_t h, - const uint8_t alphaValues[4][4], - bool nonOpaquePunchThroughAlpha) const - { - // TODO (mgong): Will be implemented soon - UNIMPLEMENTED(); - } - - void transcodePlanarBlockToBC1(uint8_t *dest, - size_t x, - size_t y, - size_t w, - size_t h, - const uint8_t alphaValues[4][4]) const - { - // TODO (mgong): Will be implemented soon - UNIMPLEMENTED(); - } - - // Single channel utility functions - int getSingleChannel(size_t x, size_t y, bool isSigned) const - { - int codeword = isSigned ? u.scblk.base_codeword.s : u.scblk.base_codeword.us; - return codeword + getSingleChannelModifier(x, y) * u.scblk.multiplier; - } - - int getSingleChannelIndex(size_t x, size_t y) const - { - ASSERT(x < 4 && y < 4); - - // clang-format off - switch (x * 4 + y) - { - case 0: return u.scblk.ma; - case 1: return u.scblk.mb; - case 2: return u.scblk.mc1 << 1 | u.scblk.mc2; - case 3: return u.scblk.md; - case 4: return u.scblk.me; - case 5: return u.scblk.mf1 << 2 | u.scblk.mf2; - case 6: return u.scblk.mg; - case 7: return u.scblk.mh; - case 8: return u.scblk.mi; - case 9: return u.scblk.mj; - case 10: return u.scblk.mk1 << 1 | u.scblk.mk2; - case 11: return u.scblk.ml; - case 12: return u.scblk.mm; - case 13: return u.scblk.mn1 << 2 | u.scblk.mn2; - case 14: return u.scblk.mo; - case 15: return u.scblk.mp; - default: UNREACHABLE(); return 0; - } - // clang-format on - } - - int getSingleChannelModifier(size_t x, size_t y) const - { - // clang-format off - static const int modifierTable[16][8] = - { - { -3, -6, -9, -15, 2, 5, 8, 14 }, - { -3, -7, -10, -13, 2, 6, 9, 12 }, - { -2, -5, -8, -13, 1, 4, 7, 12 }, - { -2, -4, -6, -13, 1, 3, 5, 12 }, - { -3, -6, -8, -12, 2, 5, 7, 11 }, - { -3, -7, -9, -11, 2, 6, 8, 10 }, - { -4, -7, -8, -11, 3, 6, 7, 10 }, - { -3, -5, -8, -11, 2, 4, 7, 10 }, - { -2, -6, -8, -10, 1, 5, 7, 9 }, - { -2, -5, -8, -10, 1, 4, 7, 9 }, - { -2, -4, -8, -10, 1, 3, 7, 9 }, - { -2, -5, -7, -10, 1, 4, 6, 9 }, - { -3, -4, -7, -10, 2, 3, 6, 9 }, - { -1, -2, -3, -10, 0, 1, 2, 9 }, - { -4, -6, -8, -9, 3, 5, 7, 8 }, - { -3, -5, -7, -9, 2, 4, 6, 8 } - }; - // clang-format on - - return modifierTable[u.scblk.table_index][getSingleChannelIndex(x, y)]; - } -}; - -// clang-format off -static const uint8_t DefaultETCAlphaValues[4][4] = -{ - { 255, 255, 255, 255 }, - { 255, 255, 255, 255 }, - { 255, 255, 255, 255 }, - { 255, 255, 255, 255 }, -}; -// clang-format on - -void LoadR11EACToR8(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, - bool isSigned) -{ - for (size_t z = 0; z < depth; z++) - { - for (size_t y = 0; y < height; y += 4) - { - const ETC2Block *sourceRow = - OffsetDataPointer(input, y / 4, z, inputRowPitch, inputDepthPitch); - uint8_t *destRow = - OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); - - for (size_t x = 0; x < width; x += 4) - { - const ETC2Block *sourceBlock = sourceRow + (x / 4); - uint8_t *destPixels = destRow + x; - - sourceBlock->decodeAsSingleChannel(destPixels, x, y, width, height, 1, - outputRowPitch, isSigned); - } - } - } -} - -void LoadRG11EACToRG8(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, - bool isSigned) -{ - for (size_t z = 0; z < depth; z++) - { - for (size_t y = 0; y < height; y += 4) - { - const ETC2Block *sourceRow = - OffsetDataPointer(input, y / 4, z, inputRowPitch, inputDepthPitch); - uint8_t *destRow = - OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); - - for (size_t x = 0; x < width; x += 4) - { - uint8_t *destPixelsRed = destRow + (x * 2); - const ETC2Block *sourceBlockRed = sourceRow + (x / 2); - sourceBlockRed->decodeAsSingleChannel(destPixelsRed, x, y, width, height, 2, - outputRowPitch, isSigned); - - uint8_t *destPixelsGreen = destPixelsRed + 1; - const ETC2Block *sourceBlockGreen = sourceBlockRed + 1; - sourceBlockGreen->decodeAsSingleChannel(destPixelsGreen, x, y, width, height, 2, - outputRowPitch, isSigned); - } - } - } -} - -void LoadETC2RGB8ToRGBA8(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, - bool punchthroughAlpha) -{ - for (size_t z = 0; z < depth; z++) - { - for (size_t y = 0; y < height; y += 4) - { - const ETC2Block *sourceRow = - OffsetDataPointer(input, y / 4, z, inputRowPitch, inputDepthPitch); - uint8_t *destRow = - OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); - - for (size_t x = 0; x < width; x += 4) - { - const ETC2Block *sourceBlock = sourceRow + (x / 4); - uint8_t *destPixels = destRow + (x * 4); - - sourceBlock->decodeAsRGB(destPixels, x, y, width, height, outputRowPitch, - DefaultETCAlphaValues, punchthroughAlpha); - } - } - } -} - -void LoadETC2RGB8ToBC1(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, - bool punchthroughAlpha) -{ - for (size_t z = 0; z < depth; z++) - { - for (size_t y = 0; y < height; y += 4) - { - const ETC2Block *sourceRow = - OffsetDataPointer(input, y / 4, z, inputRowPitch, inputDepthPitch); - uint8_t *destRow = - OffsetDataPointer(output, y / 4, z, outputRowPitch, outputDepthPitch); - - for (size_t x = 0; x < width; x += 4) - { - const ETC2Block *sourceBlock = sourceRow + (x / 4); - uint8_t *destPixels = destRow + (x * 2); - - sourceBlock->transcodeAsBC1(destPixels, x, y, width, height, DefaultETCAlphaValues, - punchthroughAlpha); - } - } - } -} - -void LoadETC2RGBA8ToRGBA8(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, - bool srgb) -{ - uint8_t decodedAlphaValues[4][4]; - - for (size_t z = 0; z < depth; z++) - { - for (size_t y = 0; y < height; y += 4) - { - const ETC2Block *sourceRow = - OffsetDataPointer(input, y / 4, z, inputRowPitch, inputDepthPitch); - uint8_t *destRow = - OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); - - for (size_t x = 0; x < width; x += 4) - { - const ETC2Block *sourceBlockAlpha = sourceRow + (x / 2); - sourceBlockAlpha->decodeAsSingleChannel( - reinterpret_cast(decodedAlphaValues), x, y, width, height, 1, 4, - false); - - uint8_t *destPixels = destRow + (x * 4); - const ETC2Block *sourceBlockRGB = sourceBlockAlpha + 1; - sourceBlockRGB->decodeAsRGB(destPixels, x, y, width, height, outputRowPitch, - decodedAlphaValues, false); - } - } - } -} - -} // anonymous namespace - -void LoadETC1RGB8ToRGBA8(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) -{ - LoadETC2RGB8ToRGBA8(width, height, depth, input, inputRowPitch, inputDepthPitch, output, - outputRowPitch, outputDepthPitch, false); -} - -void LoadETC1RGB8ToBC1(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) -{ - LoadETC2RGB8ToBC1(width, height, depth, input, inputRowPitch, inputDepthPitch, output, - outputRowPitch, outputDepthPitch, false); -} - -void LoadEACR11ToR8(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) -{ - LoadR11EACToR8(width, height, depth, input, inputRowPitch, inputDepthPitch, output, - outputRowPitch, outputDepthPitch, false); -} - -void LoadEACR11SToR8(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) -{ - LoadR11EACToR8(width, height, depth, input, inputRowPitch, inputDepthPitch, output, - outputRowPitch, outputDepthPitch, true); -} - -void LoadEACRG11ToRG8(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) -{ - LoadRG11EACToRG8(width, height, depth, input, inputRowPitch, inputDepthPitch, output, - outputRowPitch, outputDepthPitch, false); -} - -void LoadEACRG11SToRG8(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) -{ - LoadRG11EACToRG8(width, height, depth, input, inputRowPitch, inputDepthPitch, output, - outputRowPitch, outputDepthPitch, true); -} - -void LoadETC2RGB8ToRGBA8(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) -{ - LoadETC2RGB8ToRGBA8(width, height, depth, input, inputRowPitch, inputDepthPitch, output, - outputRowPitch, outputDepthPitch, false); -} - -void LoadETC2SRGB8ToRGBA8(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) -{ - LoadETC2RGB8ToRGBA8(width, height, depth, input, inputRowPitch, inputDepthPitch, output, - outputRowPitch, outputDepthPitch, false); -} - -void LoadETC2RGB8A1ToRGBA8(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) -{ - LoadETC2RGB8ToRGBA8(width, height, depth, input, inputRowPitch, inputDepthPitch, output, - outputRowPitch, outputDepthPitch, true); -} - -void LoadETC2SRGB8A1ToRGBA8(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) -{ - LoadETC2RGB8ToRGBA8(width, height, depth, input, inputRowPitch, inputDepthPitch, output, - outputRowPitch, outputDepthPitch, true); -} - -void LoadETC2RGBA8ToRGBA8(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) -{ - LoadETC2RGBA8ToRGBA8(width, height, depth, input, inputRowPitch, inputDepthPitch, output, - outputRowPitch, outputDepthPitch, false); -} - -void LoadETC2SRGBA8ToSRGBA8(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) -{ - LoadETC2RGBA8ToRGBA8(width, height, depth, input, inputRowPitch, inputDepthPitch, output, - outputRowPitch, outputDepthPitch, true); -} - -} // namespace rx diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/loadimage_etc.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/loadimage_etc.h deleted file mode 100644 index dc64e0461b..0000000000 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/loadimage_etc.h +++ /dev/null @@ -1,140 +0,0 @@ -// -// 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_etc.h: Decodes ETC and EAC encoded textures. - -#ifndef LIBANGLE_RENDERER_D3D_LOADIMAGE_ETC_H_ -#define LIBANGLE_RENDERER_D3D_LOADIMAGE_ETC_H_ - -#include "libANGLE/angletypes.h" - -#include - -namespace rx -{ - -void LoadETC1RGB8ToRGBA8(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 LoadETC1RGB8ToBC1(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 LoadEACR11ToR8(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 LoadEACR11SToR8(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 LoadEACRG11ToRG8(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 LoadEACRG11SToRG8(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 LoadETC2RGB8ToRGBA8(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 LoadETC2SRGB8ToRGBA8(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 LoadETC2RGB8A1ToRGBA8(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 LoadETC2SRGB8A1ToRGBA8(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 LoadETC2RGBA8ToRGBA8(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 LoadETC2SRGBA8ToSRGBA8(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); -} - -#endif // LIBANGLE_RENDERER_D3D_LOADIMAGE_ETC_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/driver_utils.cpp b/src/3rdparty/angle/src/libANGLE/renderer/driver_utils.cpp new file mode 100644 index 0000000000..d97b8e7c22 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/driver_utils.cpp @@ -0,0 +1,120 @@ +// +// Copyright (c) 2016 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. +// + +// driver_utils.h : provides more information about current driver. + +#include + +#include "libANGLE/renderer/driver_utils.h" + +namespace rx +{ +// Intel +// Referenced from https://cgit.freedesktop.org/vaapi/intel-driver/tree/src/i965_pciids.h +namespace +{ +// gen7 +const uint32_t Haswell[] = { + 0x0402, 0x0406, 0x040A, 0x040B, 0x040E, 0x0C02, 0x0C06, 0x0C0A, 0x0C0B, 0x0C0E, + 0x0A02, 0x0A06, 0x0A0A, 0x0A0B, 0x0A0E, 0x0D02, 0x0D06, 0x0D0A, 0x0D0B, 0x0D0E, // hsw_gt1 + 0x0412, 0x0416, 0x041A, 0x041B, 0x041E, 0x0C12, 0x0C16, 0x0C1A, 0x0C1B, 0x0C1E, + 0x0A12, 0x0A16, 0x0A1A, 0x0A1B, 0x0A1E, 0x0D12, 0x0D16, 0x0D1A, 0x0D1B, 0x0D1E, // hsw_gt2 + 0x0422, 0x0426, 0x042A, 0x042B, 0x042E, 0x0C22, 0x0C26, 0x0C2A, 0x0C2B, 0x0C2E, + 0x0A22, 0x0A26, 0x0A2A, 0x0A2B, 0x0A2E, 0x0D22, 0x0D26, 0x0D2A, 0x0D2B, 0x0D2E // hsw_gt3 +}; + +// gen8 +const uint32_t Broadwell[] = {0x1602, 0x1606, 0x160A, 0x160B, 0x160D, 0x160E, + 0x1612, 0x1616, 0x161A, 0x161B, 0x161D, 0x161E, + 0x1622, 0x1626, 0x162A, 0x162B, 0x162D, 0x162E}; + +const uint32_t CherryView[] = {0x22B0, 0x22B1, 0x22B2, 0x22B3}; + +// gen9 +const uint32_t Skylake[] = {0x1902, 0x1906, 0x190A, 0x190B, 0x190E, 0x1912, 0x1913, 0x1915, 0x1916, + 0x1917, 0x191A, 0x191B, 0x191D, 0x191E, 0x1921, 0x1923, 0x1926, 0x1927, + 0x192A, 0x192B, 0x192D, 0x1932, 0x193A, 0x193B, 0x193D}; + +const uint32_t Broxton[] = {0x0A84, 0x1A84, 0x1A85, 0x5A84, 0x5A85}; + +// gen9p5 +const uint32_t Kabylake[] = {0x5916, 0x5913, 0x5906, 0x5926, 0x5921, 0x5915, 0x590E, + 0x591E, 0x5912, 0x5917, 0x5902, 0x591B, 0x593B, 0x590B, + 0x591A, 0x590A, 0x591D, 0x5908, 0x5923, 0x5927}; + +} // anonymous namespace + +IntelDriverVersion::IntelDriverVersion(uint16_t lastPart) : mVersionPart(lastPart) +{ +} + +bool IntelDriverVersion::operator==(const IntelDriverVersion &version) +{ + return mVersionPart == version.mVersionPart; +} + +bool IntelDriverVersion::operator!=(const IntelDriverVersion &version) +{ + return !(*this == version); +} + +bool IntelDriverVersion::operator<(const IntelDriverVersion &version) +{ + // See http://www.intel.com/content/www/us/en/support/graphics-drivers/000005654.html to + // understand the Intel graphics driver version number on Windows. + // mVersionPart1 changes with OS version. mVersionPart2 changes with DirectX version. + // mVersionPart3 stands for release year. mVersionPart4 is driver specific unique version + // number. + // For example: Intel driver version '20.19.15.4539' + // 20 -> windows 10 driver + // 19 -> DirectX 12 first version(12.0) supported + // 15 -> Driver released in 2015 + // 4539 -> Driver specific unique version number + // For linux, Intel graphics driver version is the mesa version. The version number has three + // parts: major revision, minor revision, release number. So, for linux, we need to compare + // three parts. + // Currently, it's only used in windows. So, checking the last part is enough. Once it's needed + // in other platforms, it's easy to be extended. + return mVersionPart < version.mVersionPart; +} + +bool IntelDriverVersion::operator>=(const IntelDriverVersion &version) +{ + return !(*this < version); +} + +bool IsHaswell(uint32_t DeviceId) +{ + return std::find(std::begin(Haswell), std::end(Haswell), DeviceId) != std::end(Haswell); +} + +bool IsBroadwell(uint32_t DeviceId) +{ + return std::find(std::begin(Broadwell), std::end(Broadwell), DeviceId) != std::end(Broadwell); +} + +bool IsCherryView(uint32_t DeviceId) +{ + return std::find(std::begin(CherryView), std::end(CherryView), DeviceId) != + std::end(CherryView); +} + +bool IsSkylake(uint32_t DeviceId) +{ + return std::find(std::begin(Skylake), std::end(Skylake), DeviceId) != std::end(Skylake); +} + +bool IsBroxton(uint32_t DeviceId) +{ + return std::find(std::begin(Broxton), std::end(Broxton), DeviceId) != std::end(Broxton); +} + +bool IsKabylake(uint32_t DeviceId) +{ + return std::find(std::begin(Kabylake), std::end(Kabylake), DeviceId) != std::end(Kabylake); +} + +} // namespace rx \ No newline at end of file diff --git a/src/3rdparty/angle/src/libANGLE/renderer/driver_utils.h b/src/3rdparty/angle/src/libANGLE/renderer/driver_utils.h new file mode 100644 index 0000000000..62bdc502fc --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/driver_utils.h @@ -0,0 +1,73 @@ +// +// Copyright (c) 2016 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. +// + +// driver_utils.h : provides more information about current driver. + +#ifndef LIBANGLE_RENDERER_DRIVER_UTILS_H_ +#define LIBANGLE_RENDERER_DRIVER_UTILS_H_ + +#include "libANGLE/angletypes.h" + +namespace rx +{ + +enum VendorID : uint32_t +{ + VENDOR_ID_UNKNOWN = 0x0, + VENDOR_ID_AMD = 0x1002, + VENDOR_ID_INTEL = 0x8086, + VENDOR_ID_NVIDIA = 0x10DE, + // This is Qualcomm PCI Vendor ID. + // Android doesn't have a PCI bus, but all we need is a unique id. + VENDOR_ID_QUALCOMM = 0x5143, +}; + +inline bool IsAMD(uint32_t vendor_id) +{ + return vendor_id == VENDOR_ID_AMD; +} + +inline bool IsIntel(uint32_t vendor_id) +{ + return vendor_id == VENDOR_ID_INTEL; +} + +inline bool IsNvidia(uint32_t vendor_id) +{ + return vendor_id == VENDOR_ID_NVIDIA; +} + +inline bool IsQualcomm(uint32_t vendor_id) +{ + return vendor_id == VENDOR_ID_QUALCOMM; +} + +// Intel +class IntelDriverVersion +{ + public: + // Currently, We only provide the constructor with one parameter. It mainly used in Intel + // version number on windows. If you want to use this class on other platforms, it's easy to + // be extended. + IntelDriverVersion(uint16_t lastPart); + bool operator==(const IntelDriverVersion &); + bool operator!=(const IntelDriverVersion &); + bool operator<(const IntelDriverVersion &); + bool operator>=(const IntelDriverVersion &); + + private: + uint16_t mVersionPart; +}; + +bool IsHaswell(uint32_t DeviceId); +bool IsBroadwell(uint32_t DeviceId); +bool IsCherryView(uint32_t DeviceId); +bool IsSkylake(uint32_t DeviceId); +bool IsBroxton(uint32_t DeviceId); +bool IsKabylake(uint32_t DeviceId); + +} // namespace rx +#endif // LIBANGLE_RENDERER_DRIVER_UTILS_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/load_functions_data.json b/src/3rdparty/angle/src/libANGLE/renderer/load_functions_data.json new file mode 100644 index 0000000000..198274998c --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/load_functions_data.json @@ -0,0 +1,602 @@ +{ + "GL_RG8_SNORM": { + "R8G8_SNORM": { + "GL_BYTE": "LoadToNative" + } + }, + "GL_SRGB8": { + "R8G8B8A8_UNORM_SRGB": { + "GL_UNSIGNED_BYTE": "LoadToNative3To4" + } + }, + "GL_RGBA8I": { + "R8G8B8A8_SINT": { + "GL_BYTE": "LoadToNative" + } + }, + "GL_R8_SNORM": { + "R8_SNORM": { + "GL_BYTE": "LoadToNative" + } + }, + "GL_RGBA8_SNORM": { + "R8G8B8A8_SNORM": { + "GL_BYTE": "LoadToNative" + } + }, + "GL_R16I": { + "R16_SINT": { + "GL_SHORT": "LoadToNative" + } + }, + "GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC": { + "R8G8B8A8_UNORM_SRGB": { + "GL_UNSIGNED_BYTE": "LoadETC2SRGBA8ToSRGBA8" + } + }, + "GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2": { + "R8G8B8A8_UNORM": { + "GL_UNSIGNED_BYTE": "LoadETC2RGB8A1ToRGBA8" + } + }, + "GL_RGB32UI": { + "R32G32B32A32_UINT": { + "GL_UNSIGNED_INT": "LoadToNative3To4" + } + }, + "GL_ALPHA32F_EXT": { + "NONE": { + "GL_FLOAT": "LoadA32FToRGBA32F" + } + }, + "GL_R16UI": { + "R16_UINT": { + "GL_UNSIGNED_SHORT": "LoadToNative" + } + }, + "GL_RGB9_E5": { + "R9G9B9E5_SHAREDEXP": { + "GL_HALF_FLOAT": "LoadRGB16FToRGB9E5", + "GL_UNSIGNED_INT_5_9_9_9_REV": "LoadToNative", + "GL_FLOAT": "LoadRGB32FToRGB9E5", + "GL_HALF_FLOAT_OES": "LoadRGB16FToRGB9E5" + } + }, + "GL_COMPRESSED_R11_EAC": { + "R8_UNORM": { + "GL_UNSIGNED_BYTE": "LoadEACR11ToR8" + } + }, + "GL_RGBA32UI": { + "R32G32B32A32_UINT": { + "GL_UNSIGNED_INT": "LoadToNative" + } + }, + "GL_RG8UI": { + "R8G8_UINT": { + "GL_UNSIGNED_BYTE": "LoadToNative" + } + }, + "GL_LUMINANCE32F_EXT": { + "NONE": { + "GL_FLOAT": "LoadL32FToRGBA32F" + } + }, + "GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2": { + "R8G8B8A8_UNORM_SRGB": { + "GL_UNSIGNED_BYTE": "LoadETC2SRGB8A1ToRGBA8" + } + }, + "GL_R16F": { + "R16_FLOAT": { + "GL_HALF_FLOAT": "LoadToNative", + "GL_FLOAT": "Load32FTo16F<1>", + "GL_HALF_FLOAT_OES": "LoadToNative" + } + }, + "GL_RGBA8UI": { + "R8G8B8A8_UINT": { + "GL_UNSIGNED_BYTE": "LoadToNative" + } + }, + "GL_BGRA4_ANGLEX": { + "NONE": { + "GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT": "LoadRGBA4ToRGBA8", + "GL_UNSIGNED_BYTE": "LoadToNative" + } + }, + "GL_RGBA16F": { + "R16G16B16A16_FLOAT": { + "GL_HALF_FLOAT": "LoadToNative", + "GL_FLOAT": "Load32FTo16F<4>", + "GL_HALF_FLOAT_OES": "LoadToNative" + } + }, + "GL_LUMINANCE8_EXT": { + "NONE": { + "GL_UNSIGNED_BYTE": "LoadL8ToRGBA8" + } + }, + "GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE": { + "NONE": { + "GL_UNSIGNED_BYTE": "LoadCompressedToNative<4, 4, 16>" + } + }, + "GL_RGB": { + "NONE": { + "GL_UNSIGNED_BYTE": "UnreachableLoadFunction", + "GL_UNSIGNED_SHORT_5_6_5": "UnreachableLoadFunction" + } + }, + "GL_RGB5_A1": { + "R8G8B8A8_UNORM": { + "GL_UNSIGNED_INT_2_10_10_10_REV": "LoadRGB10A2ToRGBA8", + "GL_UNSIGNED_BYTE": "LoadToNative", + "GL_UNSIGNED_SHORT_5_5_5_1": "LoadRGB5A1ToRGBA8" + }, + "B5G5R5A1_UNORM": { + "GL_UNSIGNED_INT_2_10_10_10_REV": "LoadRGB10A2ToBGR5A1", + "GL_UNSIGNED_BYTE": "LoadRGBA8ToBGR5A1", + "GL_UNSIGNED_SHORT_5_5_5_1": "LoadRGB5A1ToA1RGB5" + } + }, + "GL_RGB16UI": { + "R16G16B16A16_UINT": { + "GL_UNSIGNED_SHORT": "LoadToNative3To4" + } + }, + "GL_BGRA_EXT": { + "NONE": { + "GL_UNSIGNED_BYTE": "UnreachableLoadFunction" + } + }, + "GL_COMPRESSED_RGB8_ETC2": { + "R8G8B8A8_UNORM": { + "GL_UNSIGNED_BYTE": "LoadETC2RGB8ToRGBA8" + } + }, + "GL_RGBA32F": { + "R32G32B32A32_FLOAT": { + "GL_FLOAT": "LoadToNative" + } + }, + "GL_RGBA32I": { + "R32G32B32A32_SINT": { + "GL_INT": "LoadToNative" + } + }, + "GL_LUMINANCE8_ALPHA8_EXT": { + "NONE": { + "GL_UNSIGNED_BYTE": "LoadLA8ToRGBA8" + } + }, + "GL_RG8": { + "R8G8_UNORM": { + "GL_UNSIGNED_BYTE": "LoadToNative" + } + }, + "GL_RGB10_A2": { + "R10G10B10A2_UNORM": { + "GL_UNSIGNED_INT_2_10_10_10_REV": "LoadToNative" + } + }, + "GL_COMPRESSED_SIGNED_RG11_EAC": { + "R8G8_SNORM": { + "GL_UNSIGNED_BYTE": "LoadEACRG11SToRG8" + } + }, + "GL_DEPTH_COMPONENT16": { + "D16_UNORM": { + "GL_UNSIGNED_INT": "LoadR32ToR16", + "GL_UNSIGNED_SHORT": "LoadToNative" + } + }, + "GL_RGB32I": { + "R32G32B32A32_SINT": { + "GL_INT": "LoadToNative3To4" + } + }, + "GL_R8": { + "R8_UNORM": { + "GL_UNSIGNED_BYTE": "LoadToNative" + } + }, + "GL_RGB32F": { + "R32G32B32A32_FLOAT": { + "GL_FLOAT": "LoadToNative3To4" + } + }, + "GL_R11F_G11F_B10F": { + "R11G11B10_FLOAT": { + "GL_UNSIGNED_INT_10F_11F_11F_REV": "LoadToNative", + "GL_HALF_FLOAT": "LoadRGB16FToRG11B10F", + "GL_FLOAT": "LoadRGB32FToRG11B10F", + "GL_HALF_FLOAT_OES": "LoadRGB16FToRG11B10F" + } + }, + "GL_RGB8": { + "R8G8B8A8_UNORM": { + "GL_UNSIGNED_BYTE": "LoadToNative3To4" + } + }, + "GL_LUMINANCE_ALPHA": { + "R16G16B16A16_FLOAT": { + "GL_HALF_FLOAT": "LoadLA16FToRGBA16F", + "GL_HALF_FLOAT_OES": "LoadLA16FToRGBA16F" + }, + "NONE": { + "GL_UNSIGNED_BYTE": "UnreachableLoadFunction" + }, + "R32G32B32A32_FLOAT": { + "GL_FLOAT": "LoadLA32FToRGBA32F" + } + }, + "GL_RGBA16I": { + "R16G16B16A16_SINT": { + "GL_SHORT": "LoadToNative" + } + }, + "GL_R8I": { + "R8_SINT": { + "GL_BYTE": "LoadToNative" + } + }, + "GL_RGB8_SNORM": { + "R8G8B8A8_SNORM": { + "GL_BYTE": "LoadToNative3To4" + } + }, + "GL_RG32F": { + "R32G32_FLOAT": { + "GL_FLOAT": "LoadToNative" + } + }, + "GL_DEPTH_COMPONENT32F": { + "D32_FLOAT": { + "GL_FLOAT": "LoadD32FToD32F" + } + }, + "GL_RG32I": { + "R32G32_SINT": { + "GL_INT": "LoadToNative" + } + }, + "GL_ALPHA8_EXT": { + "A8_UNORM": { + "GL_UNSIGNED_BYTE": "LoadToNative" + }, + "R8G8B8A8_UNORM": { + "GL_UNSIGNED_BYTE": "LoadA8ToRGBA8" + } + }, + "GL_RG32UI": { + "R32G32_UINT": { + "GL_UNSIGNED_INT": "LoadToNative" + } + }, + "GL_RGBA16UI": { + "R16G16B16A16_UINT": { + "GL_UNSIGNED_SHORT": "LoadToNative" + } + }, + "GL_COMPRESSED_RGBA8_ETC2_EAC": { + "R8G8B8A8_UNORM": { + "GL_UNSIGNED_BYTE": "LoadETC2RGBA8ToRGBA8" + } + }, + "GL_RGB8I": { + "R8G8B8A8_SINT": { + "GL_BYTE": "LoadToNative3To4" + } + }, + "GL_COMPRESSED_SRGB8_ETC2": { + "R8G8B8A8_UNORM_SRGB": { + "GL_UNSIGNED_BYTE": "LoadETC2SRGB8ToRGBA8" + } + }, + "GL_DEPTH32F_STENCIL8": { + "D32_FLOAT_S8X24_UINT": { + "GL_FLOAT_32_UNSIGNED_INT_24_8_REV": "LoadD32FS8X24ToD32FS8X24" + } + }, + "GL_RG8I": { + "R8G8_SINT": { + "GL_BYTE": "LoadToNative" + } + }, + "GL_R32UI": { + "R32_UINT": { + "GL_UNSIGNED_INT": "LoadToNative" + } + }, + "GL_BGR5_A1_ANGLEX": { + "NONE": { + "GL_UNSIGNED_BYTE": "LoadToNative", + "GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT": "LoadRGB5A1ToRGBA8" + } + }, + "GL_BGR565_ANGLEX": { + "B5G6R5_UNORM": { + "GL_UNSIGNED_SHORT_5_6_5": "LoadRGB565ToBGR565", + "GL_UNSIGNED_BYTE": "LoadToNative" + } + }, + "GL_COMPRESSED_RG11_EAC": { + "R8G8_UNORM": { + "GL_UNSIGNED_BYTE": "LoadEACRG11ToRG8" + } + }, + "GL_SRGB8_ALPHA8": { + "R8G8B8A8_UNORM_SRGB": { + "GL_UNSIGNED_BYTE": "LoadToNative" + } + }, + "GL_LUMINANCE_ALPHA16F_EXT": { + "NONE": { + "GL_HALF_FLOAT": "LoadLA16FToRGBA16F", + "GL_HALF_FLOAT_OES": "LoadLA16FToRGBA16F" + } + }, + "GL_RGBA": { + "NONE": { + "GL_UNSIGNED_BYTE": "UnreachableLoadFunction", + "GL_UNSIGNED_SHORT_4_4_4_4": "UnreachableLoadFunction", + "GL_UNSIGNED_SHORT_5_5_5_1": "UnreachableLoadFunction" + } + }, + "GL_DEPTH24_STENCIL8": { + "D24_UNORM_S8_UINT": { + "GL_UNSIGNED_INT_24_8": "LoadR32ToR24G8" + } + }, + "GL_RGB16I": { + "R16G16B16A16_SINT": { + "GL_SHORT": "LoadToNative3To4" + } + }, + "GL_R8UI": { + "R8_UINT": { + "GL_UNSIGNED_BYTE": "LoadToNative" + } + }, + "GL_ALPHA": { + "R16G16B16A16_FLOAT": { + "GL_HALF_FLOAT": "LoadA16FToRGBA16F", + "GL_HALF_FLOAT_OES": "LoadA16FToRGBA16F" + }, + "NONE": { + "GL_UNSIGNED_BYTE": "UnreachableLoadFunction" + }, + "R32G32B32A32_FLOAT": { + "GL_FLOAT": "LoadA32FToRGBA32F" + } + }, + "GL_RGB16F": { + "R16G16B16A16_FLOAT": { + "GL_HALF_FLOAT": "LoadToNative3To4", + "GL_FLOAT": "LoadRGB32FToRGBA16F", + "GL_HALF_FLOAT_OES": "LoadToNative3To4" + } + }, + "GL_COMPRESSED_SIGNED_R11_EAC": { + "R8_SNORM": { + "GL_UNSIGNED_BYTE": "LoadEACR11SToR8" + } + }, + "GL_COMPRESSED_RGB_S3TC_DXT1_EXT": { + "NONE": { + "GL_UNSIGNED_BYTE": "LoadCompressedToNative<4, 4, 8>" + } + }, + "GL_COMPRESSED_RGBA_S3TC_DXT1_EXT": { + "NONE": { + "GL_UNSIGNED_BYTE": "LoadCompressedToNative<4, 4, 8>" + } + }, + "GL_STENCIL_INDEX8": { + "NONE": { + "GL_UNSIGNED_BYTE": "UnimplementedLoadFunction" + } + }, + "GL_LUMINANCE_ALPHA32F_EXT": { + "NONE": { + "GL_FLOAT": "LoadLA32FToRGBA32F" + } + }, + "GL_RGB8UI": { + "R8G8B8A8_UINT": { + "GL_UNSIGNED_BYTE": "LoadToNative3To4" + } + }, + "GL_DEPTH_COMPONENT24": { + "D24_UNORM_S8_UINT": { + "GL_UNSIGNED_INT": "LoadR32ToR24G8" + } + }, + "GL_R32I": { + "R32_SINT": { + "GL_INT": "LoadToNative" + } + }, + "GL_DEPTH_COMPONENT32_OES": { + "NONE": { + "GL_UNSIGNED_INT": "LoadR32ToR24G8" + } + }, + "GL_R32F": { + "R32_FLOAT": { + "GL_FLOAT": "LoadToNative" + } + }, + "GL_RG16F": { + "R16G16_FLOAT": { + "GL_HALF_FLOAT": "LoadToNative", + "GL_FLOAT": "Load32FTo16F<2>", + "GL_HALF_FLOAT_OES": "LoadToNative" + } + }, + "GL_RGB565": { + "R8G8B8A8_UNORM": { + "GL_UNSIGNED_BYTE": "LoadToNative3To4", + "GL_UNSIGNED_SHORT_5_6_5": "LoadR5G6B5ToRGBA8" + }, + "B5G6R5_UNORM": { + "GL_UNSIGNED_BYTE": "LoadRGB8ToBGR565", + "GL_UNSIGNED_SHORT_5_6_5": "LoadToNative" + } + }, + "GL_LUMINANCE16F_EXT": { + "NONE": { + "GL_HALF_FLOAT": "LoadL16FToRGBA16F", + "GL_HALF_FLOAT_OES": "LoadL16FToRGBA16F" + } + }, + "GL_RG16UI": { + "R16G16_UINT": { + "GL_UNSIGNED_SHORT": "LoadToNative" + } + }, + "GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE": { + "NONE": { + "GL_UNSIGNED_BYTE": "LoadCompressedToNative<4, 4, 16>" + } + }, + "GL_RG16I": { + "R16G16_SINT": { + "GL_SHORT": "LoadToNative" + } + }, + "GL_BGRA8_EXT": { + "NONE": { + "GL_UNSIGNED_BYTE": "LoadToNative" + } + }, + "GL_ALPHA16F_EXT": { + "NONE": { + "GL_HALF_FLOAT": "LoadA16FToRGBA16F", + "GL_HALF_FLOAT_OES": "LoadA16FToRGBA16F" + } + }, + "GL_RGBA4": { + "R8G8B8A8_UNORM": { + "GL_UNSIGNED_BYTE": "LoadToNative", + "GL_UNSIGNED_SHORT_4_4_4_4": "LoadRGBA4ToRGBA8" + }, + "B4G4R4A4_UNORM": { + "GL_UNSIGNED_BYTE": "LoadRGBA8ToBGRA4", + "GL_UNSIGNED_SHORT_4_4_4_4": "LoadRGBA4ToARGB4" + } + }, + "GL_RGBA8": { + "R8G8B8A8_UNORM": { + "GL_UNSIGNED_BYTE": "LoadToNative" + } + }, + "GL_LUMINANCE": { + "R16G16B16A16_FLOAT": { + "GL_HALF_FLOAT": "LoadL16FToRGBA16F", + "GL_HALF_FLOAT_OES": "LoadL16FToRGBA16F" + }, + "NONE": { + "GL_UNSIGNED_BYTE": "UnreachableLoadFunction" + }, + "R32G32B32A32_FLOAT": { + "GL_FLOAT": "LoadL32FToRGBA32F" + } + }, + "GL_RGB10_A2UI": { + "R10G10B10A2_UINT": { + "GL_UNSIGNED_INT_2_10_10_10_REV": "LoadToNative" + } + }, + "GL_ETC1_RGB8_OES": { + "R8G8B8A8_UNORM": { + "GL_UNSIGNED_BYTE": "LoadETC1RGB8ToRGBA8" + } + }, + "GL_ETC1_RGB8_LOSSY_DECODE_ANGLE": { + "BC1_RGB_UNORM_BLOCK": { + "GL_UNSIGNED_BYTE": "LoadETC1RGB8ToBC1" + } + }, + "GL_COMPRESSED_RGB8_LOSSY_DECODE_ETC2_ANGLE": { + "BC1_RGB_UNORM_BLOCK": { + "GL_UNSIGNED_BYTE": "LoadETC2RGB8ToBC1" + } + }, + "GL_COMPRESSED_SRGB8_LOSSY_DECODE_ETC2_ANGLE": { + "BC1_RGB_UNORM_SRGB_BLOCK": { + "GL_UNSIGNED_BYTE": "LoadETC2SRGB8ToBC1" + } + }, + "GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE": { + "BC1_RGBA_UNORM_BLOCK": { + "GL_UNSIGNED_BYTE": "LoadETC2RGB8A1ToBC1" + } + }, + "GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE": { + "BC1_RGBA_UNORM_SRGB_BLOCK": { + "GL_UNSIGNED_BYTE": "LoadETC2SRGB8A1ToBC1" + } + }, + "GL_R16_EXT": { + "R16_UNORM": { + "GL_UNSIGNED_SHORT": "LoadToNative" + } + }, + "GL_RG16_EXT": { + "R16G16_UNORM": { + "GL_UNSIGNED_SHORT": "LoadToNative" + } + }, + "GL_RGB16_EXT": { + "R16G16B16A16_UNORM": { + "GL_UNSIGNED_SHORT": "LoadToNative3To4" + } + }, + "GL_RGBA16_EXT": { + "R16G16B16A16_UNORM": { + "GL_UNSIGNED_SHORT": "LoadToNative" + } + }, + "GL_R16_SNORM_EXT": { + "R16_SNORM": { + "GL_SHORT": "LoadToNative" + } + }, + "GL_RG16_SNORM_EXT": { + "R16G16_SNORM": { + "GL_SHORT": "LoadToNative" + } + }, + "GL_RGB16_SNORM_EXT": { + "R16G16B16A16_SNORM": { + "GL_SHORT": "LoadToNative3To4" + } + }, + "GL_RGBA16_SNORM_EXT": { + "R16G16B16A16_SNORM": { + "GL_SHORT": "LoadToNative" + } + }, + "GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT": { + "NONE": { + "GL_UNSIGNED_BYTE": "LoadCompressedToNative<4, 4, 16>" + } + }, + "GL_COMPRESSED_SRGB_S3TC_DXT1_EXT": { + "NONE": { + "GL_UNSIGNED_BYTE": "LoadCompressedToNative<4, 4, 8>" + } + }, + "GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT": { + "NONE": { + "GL_UNSIGNED_BYTE": "LoadCompressedToNative<4, 4, 8>" + } + }, + "GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT": { + "NONE": { + "GL_UNSIGNED_BYTE": "LoadCompressedToNative<4, 4, 16>" + } + } +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/load_functions_table.h b/src/3rdparty/angle/src/libANGLE/renderer/load_functions_table.h new file mode 100644 index 0000000000..f3da31c100 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/load_functions_table.h @@ -0,0 +1,22 @@ +// +// 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. +// +// load_functions_table: +// Contains load functions table depending on internal format and ANGLE format. +// + +#ifndef LIBANGLE_RENDERER_LOADFUNCTIONSTABLE_H_ +#define LIBANGLE_RENDERER_LOADFUNCTIONSTABLE_H_ + +#include "libANGLE/renderer/Format.h" + +namespace angle +{ + +rx::LoadFunctionMap GetLoadFunctionsMap(GLenum internalFormat, Format::ID angleFormat); + +} // namespace angle + +#endif // LIBANGLE_RENDERER_LOADFUNCTIONSTABLE_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/load_functions_table_autogen.cpp b/src/3rdparty/angle/src/libANGLE/renderer/load_functions_table_autogen.cpp new file mode 100644 index 0000000000..ed9fe2864c --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/load_functions_table_autogen.cpp @@ -0,0 +1,2459 @@ +// GENERATED FILE - DO NOT EDIT. +// Generated by gen_load_functions_table.py using data from load_functions_data.json +// +// Copyright 2016 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. +// +// load_functions_table: +// Contains the GetLoadFunctionsMap for texture_format_util.h +// + +#include "libANGLE/renderer/load_functions_table.h" + +#include "image_util/copyimage.h" +#include "image_util/generatemip.h" +#include "image_util/loadimage.h" + +using namespace rx; + +namespace angle +{ + +namespace +{ + +// ES3 image loading functions vary based on: +// - the GL internal format (supplied to glTex*Image*D) +// - the GL data type given (supplied to glTex*Image*D) +// - the target DXGI_FORMAT that the image will be loaded into (which is chosen based on the D3D +// device's capabilities) +// This map type determines which loading function to use, based on these three parameters. +// Source formats and types are taken from Tables 3.2 and 3.3 of the ES 3 spec. +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(); +} + +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(); +} + +LoadImageFunctionInfo ALPHA_to_R16G16B16A16_FLOAT(GLenum type) +{ + switch (type) + { + case GL_HALF_FLOAT: + return LoadImageFunctionInfo(LoadA16FToRGBA16F, true); + case GL_HALF_FLOAT_OES: + return LoadImageFunctionInfo(LoadA16FToRGBA16F, true); + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo ALPHA_to_R32G32B32A32_FLOAT(GLenum type) +{ + switch (type) + { + case GL_FLOAT: + return LoadImageFunctionInfo(LoadA32FToRGBA32F, true); + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo ALPHA_to_default(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo ALPHA16F_EXT_to_default(GLenum type) +{ + switch (type) + { + case GL_HALF_FLOAT: + return LoadImageFunctionInfo(LoadA16FToRGBA16F, true); + case GL_HALF_FLOAT_OES: + return LoadImageFunctionInfo(LoadA16FToRGBA16F, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo ALPHA32F_EXT_to_default(GLenum type) +{ + switch (type) + { + case GL_FLOAT: + return LoadImageFunctionInfo(LoadA32FToRGBA32F, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo ALPHA8_EXT_to_A8_UNORM(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(LoadToNative, false); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo ALPHA8_EXT_to_R8G8B8A8_UNORM(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(LoadA8ToRGBA8, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo BGR565_ANGLEX_to_B5G6R5_UNORM(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(LoadToNative, false); + case GL_UNSIGNED_SHORT_5_6_5: + return LoadImageFunctionInfo(LoadRGB565ToBGR565, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo BGR5_A1_ANGLEX_to_default(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(LoadToNative, false); + case GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT: + return LoadImageFunctionInfo(LoadRGB5A1ToRGBA8, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo BGRA4_ANGLEX_to_default(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(LoadToNative, false); + case GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT: + return LoadImageFunctionInfo(LoadRGBA4ToRGBA8, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo BGRA8_EXT_to_default(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(LoadToNative, false); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo BGRA_EXT_to_default(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo COMPRESSED_R11_EAC_to_R8_UNORM(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(LoadEACR11ToR8, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo COMPRESSED_RG11_EAC_to_R8G8_UNORM(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(LoadEACRG11ToRG8, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo COMPRESSED_RGB8_ETC2_to_R8G8B8A8_UNORM(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(LoadETC2RGB8ToRGBA8, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo COMPRESSED_RGB8_LOSSY_DECODE_ETC2_ANGLE_to_BC1_RGB_UNORM_BLOCK(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(LoadETC2RGB8ToBC1, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2_to_R8G8B8A8_UNORM(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(LoadETC2RGB8A1ToRGBA8, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo +COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE_to_BC1_RGBA_UNORM_BLOCK(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(LoadETC2RGB8A1ToBC1, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo COMPRESSED_RGBA8_ETC2_EAC_to_R8G8B8A8_UNORM(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(LoadETC2RGBA8ToRGBA8, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo COMPRESSED_RGBA_S3TC_DXT1_EXT_to_default(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(LoadCompressedToNative<4, 4, 8>, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo COMPRESSED_RGBA_S3TC_DXT3_ANGLE_to_default(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(LoadCompressedToNative<4, 4, 16>, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo COMPRESSED_RGBA_S3TC_DXT5_ANGLE_to_default(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(LoadCompressedToNative<4, 4, 16>, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo COMPRESSED_RGB_S3TC_DXT1_EXT_to_default(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(LoadCompressedToNative<4, 4, 8>, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo COMPRESSED_SIGNED_R11_EAC_to_R8_SNORM(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(LoadEACR11SToR8, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo COMPRESSED_SIGNED_RG11_EAC_to_R8G8_SNORM(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(LoadEACRG11SToRG8, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo COMPRESSED_SRGB8_ALPHA8_ETC2_EAC_to_R8G8B8A8_UNORM_SRGB(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(LoadETC2SRGBA8ToSRGBA8, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo COMPRESSED_SRGB8_ETC2_to_R8G8B8A8_UNORM_SRGB(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(LoadETC2SRGB8ToRGBA8, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo COMPRESSED_SRGB8_LOSSY_DECODE_ETC2_ANGLE_to_BC1_RGB_UNORM_SRGB_BLOCK( + GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(LoadETC2SRGB8ToBC1, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2_to_R8G8B8A8_UNORM_SRGB(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(LoadETC2SRGB8A1ToRGBA8, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo +COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE_to_BC1_RGBA_UNORM_SRGB_BLOCK( + GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(LoadETC2SRGB8A1ToBC1, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT_to_default(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(LoadCompressedToNative<4, 4, 8>, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT_to_default(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(LoadCompressedToNative<4, 4, 16>, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT_to_default(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(LoadCompressedToNative<4, 4, 16>, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo COMPRESSED_SRGB_S3TC_DXT1_EXT_to_default(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(LoadCompressedToNative<4, 4, 8>, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo DEPTH24_STENCIL8_to_D24_UNORM_S8_UINT(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_INT_24_8: + return LoadImageFunctionInfo(LoadR32ToR24G8, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo DEPTH32F_STENCIL8_to_D32_FLOAT_S8X24_UINT(GLenum type) +{ + switch (type) + { + case GL_FLOAT_32_UNSIGNED_INT_24_8_REV: + return LoadImageFunctionInfo(LoadD32FS8X24ToD32FS8X24, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo DEPTH_COMPONENT16_to_D16_UNORM(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_INT: + return LoadImageFunctionInfo(LoadR32ToR16, true); + case GL_UNSIGNED_SHORT: + return LoadImageFunctionInfo(LoadToNative, false); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo DEPTH_COMPONENT24_to_D24_UNORM_S8_UINT(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_INT: + return LoadImageFunctionInfo(LoadR32ToR24G8, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo DEPTH_COMPONENT32F_to_D32_FLOAT(GLenum type) +{ + switch (type) + { + case GL_FLOAT: + return LoadImageFunctionInfo(LoadD32FToD32F, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo DEPTH_COMPONENT32_OES_to_default(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_INT: + return LoadImageFunctionInfo(LoadR32ToR24G8, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo ETC1_RGB8_LOSSY_DECODE_ANGLE_to_BC1_RGB_UNORM_BLOCK(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(LoadETC1RGB8ToBC1, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo ETC1_RGB8_OES_to_R8G8B8A8_UNORM(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(LoadETC1RGB8ToRGBA8, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo LUMINANCE_to_R16G16B16A16_FLOAT(GLenum type) +{ + switch (type) + { + case GL_HALF_FLOAT: + return LoadImageFunctionInfo(LoadL16FToRGBA16F, true); + case GL_HALF_FLOAT_OES: + return LoadImageFunctionInfo(LoadL16FToRGBA16F, true); + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo LUMINANCE_to_R32G32B32A32_FLOAT(GLenum type) +{ + switch (type) + { + case GL_FLOAT: + return LoadImageFunctionInfo(LoadL32FToRGBA32F, true); + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo LUMINANCE_to_default(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo LUMINANCE16F_EXT_to_default(GLenum type) +{ + switch (type) + { + case GL_HALF_FLOAT: + return LoadImageFunctionInfo(LoadL16FToRGBA16F, true); + case GL_HALF_FLOAT_OES: + return LoadImageFunctionInfo(LoadL16FToRGBA16F, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo LUMINANCE32F_EXT_to_default(GLenum type) +{ + switch (type) + { + case GL_FLOAT: + return LoadImageFunctionInfo(LoadL32FToRGBA32F, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo LUMINANCE8_ALPHA8_EXT_to_default(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(LoadLA8ToRGBA8, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo LUMINANCE8_EXT_to_default(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(LoadL8ToRGBA8, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo LUMINANCE_ALPHA_to_R16G16B16A16_FLOAT(GLenum type) +{ + switch (type) + { + case GL_HALF_FLOAT: + return LoadImageFunctionInfo(LoadLA16FToRGBA16F, true); + case GL_HALF_FLOAT_OES: + return LoadImageFunctionInfo(LoadLA16FToRGBA16F, true); + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo LUMINANCE_ALPHA_to_R32G32B32A32_FLOAT(GLenum type) +{ + switch (type) + { + case GL_FLOAT: + return LoadImageFunctionInfo(LoadLA32FToRGBA32F, true); + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo LUMINANCE_ALPHA_to_default(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo LUMINANCE_ALPHA16F_EXT_to_default(GLenum type) +{ + switch (type) + { + case GL_HALF_FLOAT: + return LoadImageFunctionInfo(LoadLA16FToRGBA16F, true); + case GL_HALF_FLOAT_OES: + return LoadImageFunctionInfo(LoadLA16FToRGBA16F, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo LUMINANCE_ALPHA32F_EXT_to_default(GLenum type) +{ + switch (type) + { + case GL_FLOAT: + return LoadImageFunctionInfo(LoadLA32FToRGBA32F, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo R11F_G11F_B10F_to_R11G11B10_FLOAT(GLenum type) +{ + switch (type) + { + case GL_FLOAT: + return LoadImageFunctionInfo(LoadRGB32FToRG11B10F, true); + case GL_HALF_FLOAT: + return LoadImageFunctionInfo(LoadRGB16FToRG11B10F, true); + case GL_HALF_FLOAT_OES: + return LoadImageFunctionInfo(LoadRGB16FToRG11B10F, true); + case GL_UNSIGNED_INT_10F_11F_11F_REV: + return LoadImageFunctionInfo(LoadToNative, false); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo R16F_to_R16_FLOAT(GLenum type) +{ + switch (type) + { + case GL_FLOAT: + return LoadImageFunctionInfo(Load32FTo16F<1>, true); + case GL_HALF_FLOAT: + return LoadImageFunctionInfo(LoadToNative, false); + case GL_HALF_FLOAT_OES: + return LoadImageFunctionInfo(LoadToNative, false); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo R16I_to_R16_SINT(GLenum type) +{ + switch (type) + { + case GL_SHORT: + return LoadImageFunctionInfo(LoadToNative, false); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo R16UI_to_R16_UINT(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_SHORT: + return LoadImageFunctionInfo(LoadToNative, false); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo R16_EXT_to_R16_UNORM(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_SHORT: + return LoadImageFunctionInfo(LoadToNative, false); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo R16_SNORM_EXT_to_R16_SNORM(GLenum type) +{ + switch (type) + { + case GL_SHORT: + return LoadImageFunctionInfo(LoadToNative, false); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo R32F_to_R32_FLOAT(GLenum type) +{ + switch (type) + { + case GL_FLOAT: + return LoadImageFunctionInfo(LoadToNative, false); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo R32I_to_R32_SINT(GLenum type) +{ + switch (type) + { + case GL_INT: + return LoadImageFunctionInfo(LoadToNative, false); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo R32UI_to_R32_UINT(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_INT: + return LoadImageFunctionInfo(LoadToNative, false); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo R8_to_R8_UNORM(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(LoadToNative, false); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo R8I_to_R8_SINT(GLenum type) +{ + switch (type) + { + case GL_BYTE: + return LoadImageFunctionInfo(LoadToNative, false); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo R8UI_to_R8_UINT(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(LoadToNative, false); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo R8_SNORM_to_R8_SNORM(GLenum type) +{ + switch (type) + { + case GL_BYTE: + return LoadImageFunctionInfo(LoadToNative, false); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo RG16F_to_R16G16_FLOAT(GLenum type) +{ + switch (type) + { + case GL_FLOAT: + return LoadImageFunctionInfo(Load32FTo16F<2>, true); + case GL_HALF_FLOAT: + return LoadImageFunctionInfo(LoadToNative, false); + case GL_HALF_FLOAT_OES: + return LoadImageFunctionInfo(LoadToNative, false); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo RG16I_to_R16G16_SINT(GLenum type) +{ + switch (type) + { + case GL_SHORT: + return LoadImageFunctionInfo(LoadToNative, false); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo RG16UI_to_R16G16_UINT(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_SHORT: + return LoadImageFunctionInfo(LoadToNative, false); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo RG16_EXT_to_R16G16_UNORM(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_SHORT: + return LoadImageFunctionInfo(LoadToNative, false); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo RG16_SNORM_EXT_to_R16G16_SNORM(GLenum type) +{ + switch (type) + { + case GL_SHORT: + return LoadImageFunctionInfo(LoadToNative, false); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo RG32F_to_R32G32_FLOAT(GLenum type) +{ + switch (type) + { + case GL_FLOAT: + return LoadImageFunctionInfo(LoadToNative, false); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo RG32I_to_R32G32_SINT(GLenum type) +{ + switch (type) + { + case GL_INT: + return LoadImageFunctionInfo(LoadToNative, false); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo RG32UI_to_R32G32_UINT(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_INT: + return LoadImageFunctionInfo(LoadToNative, false); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo RG8_to_R8G8_UNORM(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(LoadToNative, false); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo RG8I_to_R8G8_SINT(GLenum type) +{ + switch (type) + { + case GL_BYTE: + return LoadImageFunctionInfo(LoadToNative, false); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo RG8UI_to_R8G8_UINT(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(LoadToNative, false); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo RG8_SNORM_to_R8G8_SNORM(GLenum type) +{ + switch (type) + { + case GL_BYTE: + return LoadImageFunctionInfo(LoadToNative, false); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo RGB_to_default(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + case GL_UNSIGNED_SHORT_5_6_5: + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo RGB10_A2_to_R10G10B10A2_UNORM(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_INT_2_10_10_10_REV: + return LoadImageFunctionInfo(LoadToNative, false); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo RGB10_A2UI_to_R10G10B10A2_UINT(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_INT_2_10_10_10_REV: + return LoadImageFunctionInfo(LoadToNative, false); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo RGB16F_to_R16G16B16A16_FLOAT(GLenum type) +{ + switch (type) + { + case GL_FLOAT: + return LoadImageFunctionInfo(LoadRGB32FToRGBA16F, true); + case GL_HALF_FLOAT: + return LoadImageFunctionInfo(LoadToNative3To4, true); + case GL_HALF_FLOAT_OES: + return LoadImageFunctionInfo(LoadToNative3To4, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo RGB16I_to_R16G16B16A16_SINT(GLenum type) +{ + switch (type) + { + case GL_SHORT: + return LoadImageFunctionInfo(LoadToNative3To4, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo RGB16UI_to_R16G16B16A16_UINT(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_SHORT: + return LoadImageFunctionInfo(LoadToNative3To4, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo RGB16_EXT_to_R16G16B16A16_UNORM(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_SHORT: + return LoadImageFunctionInfo(LoadToNative3To4, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo RGB16_SNORM_EXT_to_R16G16B16A16_SNORM(GLenum type) +{ + switch (type) + { + case GL_SHORT: + return LoadImageFunctionInfo(LoadToNative3To4, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo RGB32F_to_R32G32B32A32_FLOAT(GLenum type) +{ + switch (type) + { + case GL_FLOAT: + return LoadImageFunctionInfo(LoadToNative3To4, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo RGB32I_to_R32G32B32A32_SINT(GLenum type) +{ + switch (type) + { + case GL_INT: + return LoadImageFunctionInfo(LoadToNative3To4, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo RGB32UI_to_R32G32B32A32_UINT(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_INT: + return LoadImageFunctionInfo(LoadToNative3To4, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo RGB565_to_B5G6R5_UNORM(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(LoadRGB8ToBGR565, true); + case GL_UNSIGNED_SHORT_5_6_5: + return LoadImageFunctionInfo(LoadToNative, false); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo RGB565_to_R8G8B8A8_UNORM(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(LoadToNative3To4, true); + case GL_UNSIGNED_SHORT_5_6_5: + return LoadImageFunctionInfo(LoadR5G6B5ToRGBA8, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo RGB5_A1_to_B5G5R5A1_UNORM(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(LoadRGBA8ToBGR5A1, true); + case GL_UNSIGNED_INT_2_10_10_10_REV: + return LoadImageFunctionInfo(LoadRGB10A2ToBGR5A1, true); + case GL_UNSIGNED_SHORT_5_5_5_1: + return LoadImageFunctionInfo(LoadRGB5A1ToA1RGB5, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo RGB5_A1_to_R8G8B8A8_UNORM(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(LoadToNative, false); + case GL_UNSIGNED_INT_2_10_10_10_REV: + return LoadImageFunctionInfo(LoadRGB10A2ToRGBA8, true); + case GL_UNSIGNED_SHORT_5_5_5_1: + return LoadImageFunctionInfo(LoadRGB5A1ToRGBA8, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo RGB8_to_R8G8B8A8_UNORM(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(LoadToNative3To4, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo RGB8I_to_R8G8B8A8_SINT(GLenum type) +{ + switch (type) + { + case GL_BYTE: + return LoadImageFunctionInfo(LoadToNative3To4, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo RGB8UI_to_R8G8B8A8_UINT(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(LoadToNative3To4, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo RGB8_SNORM_to_R8G8B8A8_SNORM(GLenum type) +{ + switch (type) + { + case GL_BYTE: + return LoadImageFunctionInfo(LoadToNative3To4, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo RGB9_E5_to_R9G9B9E5_SHAREDEXP(GLenum type) +{ + switch (type) + { + case GL_FLOAT: + return LoadImageFunctionInfo(LoadRGB32FToRGB9E5, true); + case GL_HALF_FLOAT: + return LoadImageFunctionInfo(LoadRGB16FToRGB9E5, true); + case GL_HALF_FLOAT_OES: + return LoadImageFunctionInfo(LoadRGB16FToRGB9E5, true); + case GL_UNSIGNED_INT_5_9_9_9_REV: + return LoadImageFunctionInfo(LoadToNative, false); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo RGBA_to_default(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + case GL_UNSIGNED_SHORT_4_4_4_4: + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + case GL_UNSIGNED_SHORT_5_5_5_1: + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo RGBA16F_to_R16G16B16A16_FLOAT(GLenum type) +{ + switch (type) + { + case GL_FLOAT: + return LoadImageFunctionInfo(Load32FTo16F<4>, true); + case GL_HALF_FLOAT: + return LoadImageFunctionInfo(LoadToNative, false); + case GL_HALF_FLOAT_OES: + return LoadImageFunctionInfo(LoadToNative, false); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo RGBA16I_to_R16G16B16A16_SINT(GLenum type) +{ + switch (type) + { + case GL_SHORT: + return LoadImageFunctionInfo(LoadToNative, false); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo RGBA16UI_to_R16G16B16A16_UINT(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_SHORT: + return LoadImageFunctionInfo(LoadToNative, false); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo RGBA16_EXT_to_R16G16B16A16_UNORM(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_SHORT: + return LoadImageFunctionInfo(LoadToNative, false); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo RGBA16_SNORM_EXT_to_R16G16B16A16_SNORM(GLenum type) +{ + switch (type) + { + case GL_SHORT: + return LoadImageFunctionInfo(LoadToNative, false); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo RGBA32F_to_R32G32B32A32_FLOAT(GLenum type) +{ + switch (type) + { + case GL_FLOAT: + return LoadImageFunctionInfo(LoadToNative, false); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo RGBA32I_to_R32G32B32A32_SINT(GLenum type) +{ + switch (type) + { + case GL_INT: + return LoadImageFunctionInfo(LoadToNative, false); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo RGBA32UI_to_R32G32B32A32_UINT(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_INT: + return LoadImageFunctionInfo(LoadToNative, false); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo RGBA4_to_B4G4R4A4_UNORM(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(LoadRGBA8ToBGRA4, true); + case GL_UNSIGNED_SHORT_4_4_4_4: + return LoadImageFunctionInfo(LoadRGBA4ToARGB4, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo RGBA4_to_R8G8B8A8_UNORM(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(LoadToNative, false); + case GL_UNSIGNED_SHORT_4_4_4_4: + return LoadImageFunctionInfo(LoadRGBA4ToRGBA8, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo RGBA8_to_R8G8B8A8_UNORM(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(LoadToNative, false); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo RGBA8I_to_R8G8B8A8_SINT(GLenum type) +{ + switch (type) + { + case GL_BYTE: + return LoadImageFunctionInfo(LoadToNative, false); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo RGBA8UI_to_R8G8B8A8_UINT(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(LoadToNative, false); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo RGBA8_SNORM_to_R8G8B8A8_SNORM(GLenum type) +{ + switch (type) + { + case GL_BYTE: + return LoadImageFunctionInfo(LoadToNative, false); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo SRGB8_to_R8G8B8A8_UNORM_SRGB(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(LoadToNative3To4, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo SRGB8_ALPHA8_to_R8G8B8A8_UNORM_SRGB(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(LoadToNative, false); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo STENCIL_INDEX8_to_default(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(UnimplementedLoadFunction, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +} // namespace + +LoadFunctionMap GetLoadFunctionsMap(GLenum internalFormat, Format::ID angleFormat) +{ + // clang-format off + switch (internalFormat) + { + case GL_ALPHA: + { + switch (angleFormat) + { + case Format::ID::R16G16B16A16_FLOAT: + return ALPHA_to_R16G16B16A16_FLOAT; + case Format::ID::R32G32B32A32_FLOAT: + return ALPHA_to_R32G32B32A32_FLOAT; + default: + return ALPHA_to_default; + } + } + case GL_ALPHA16F_EXT: + return ALPHA16F_EXT_to_default; + case GL_ALPHA32F_EXT: + return ALPHA32F_EXT_to_default; + case GL_ALPHA8_EXT: + { + switch (angleFormat) + { + case Format::ID::A8_UNORM: + return ALPHA8_EXT_to_A8_UNORM; + case Format::ID::R8G8B8A8_UNORM: + return ALPHA8_EXT_to_R8G8B8A8_UNORM; + default: + break; + } + } + case GL_BGR565_ANGLEX: + { + switch (angleFormat) + { + case Format::ID::B5G6R5_UNORM: + return BGR565_ANGLEX_to_B5G6R5_UNORM; + default: + break; + } + } + case GL_BGR5_A1_ANGLEX: + return BGR5_A1_ANGLEX_to_default; + case GL_BGRA4_ANGLEX: + return BGRA4_ANGLEX_to_default; + case GL_BGRA8_EXT: + return BGRA8_EXT_to_default; + case GL_BGRA_EXT: + return BGRA_EXT_to_default; + case GL_COMPRESSED_R11_EAC: + { + switch (angleFormat) + { + case Format::ID::R8_UNORM: + return COMPRESSED_R11_EAC_to_R8_UNORM; + default: + break; + } + } + case GL_COMPRESSED_RG11_EAC: + { + switch (angleFormat) + { + case Format::ID::R8G8_UNORM: + return COMPRESSED_RG11_EAC_to_R8G8_UNORM; + default: + break; + } + } + case GL_COMPRESSED_RGB8_ETC2: + { + switch (angleFormat) + { + case Format::ID::R8G8B8A8_UNORM: + return COMPRESSED_RGB8_ETC2_to_R8G8B8A8_UNORM; + default: + break; + } + } + case GL_COMPRESSED_RGB8_LOSSY_DECODE_ETC2_ANGLE: + { + switch (angleFormat) + { + case Format::ID::BC1_RGB_UNORM_BLOCK: + return COMPRESSED_RGB8_LOSSY_DECODE_ETC2_ANGLE_to_BC1_RGB_UNORM_BLOCK; + default: + break; + } + } + case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2: + { + switch (angleFormat) + { + case Format::ID::R8G8B8A8_UNORM: + return COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2_to_R8G8B8A8_UNORM; + default: + break; + } + } + case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE: + { + switch (angleFormat) + { + case Format::ID::BC1_RGBA_UNORM_BLOCK: + return COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE_to_BC1_RGBA_UNORM_BLOCK; + default: + break; + } + } + case GL_COMPRESSED_RGBA8_ETC2_EAC: + { + switch (angleFormat) + { + case Format::ID::R8G8B8A8_UNORM: + return COMPRESSED_RGBA8_ETC2_EAC_to_R8G8B8A8_UNORM; + default: + break; + } + } + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: + return COMPRESSED_RGBA_S3TC_DXT1_EXT_to_default; + case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: + return COMPRESSED_RGBA_S3TC_DXT3_ANGLE_to_default; + case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: + return COMPRESSED_RGBA_S3TC_DXT5_ANGLE_to_default; + case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: + return COMPRESSED_RGB_S3TC_DXT1_EXT_to_default; + case GL_COMPRESSED_SIGNED_R11_EAC: + { + switch (angleFormat) + { + case Format::ID::R8_SNORM: + return COMPRESSED_SIGNED_R11_EAC_to_R8_SNORM; + default: + break; + } + } + case GL_COMPRESSED_SIGNED_RG11_EAC: + { + switch (angleFormat) + { + case Format::ID::R8G8_SNORM: + return COMPRESSED_SIGNED_RG11_EAC_to_R8G8_SNORM; + default: + break; + } + } + case GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC: + { + switch (angleFormat) + { + case Format::ID::R8G8B8A8_UNORM_SRGB: + return COMPRESSED_SRGB8_ALPHA8_ETC2_EAC_to_R8G8B8A8_UNORM_SRGB; + default: + break; + } + } + case GL_COMPRESSED_SRGB8_ETC2: + { + switch (angleFormat) + { + case Format::ID::R8G8B8A8_UNORM_SRGB: + return COMPRESSED_SRGB8_ETC2_to_R8G8B8A8_UNORM_SRGB; + default: + break; + } + } + case GL_COMPRESSED_SRGB8_LOSSY_DECODE_ETC2_ANGLE: + { + switch (angleFormat) + { + case Format::ID::BC1_RGB_UNORM_SRGB_BLOCK: + return COMPRESSED_SRGB8_LOSSY_DECODE_ETC2_ANGLE_to_BC1_RGB_UNORM_SRGB_BLOCK; + default: + break; + } + } + case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2: + { + switch (angleFormat) + { + case Format::ID::R8G8B8A8_UNORM_SRGB: + return COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2_to_R8G8B8A8_UNORM_SRGB; + default: + break; + } + } + case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE: + { + switch (angleFormat) + { + case Format::ID::BC1_RGBA_UNORM_SRGB_BLOCK: + return COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE_to_BC1_RGBA_UNORM_SRGB_BLOCK; + default: + break; + } + } + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT: + return COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT_to_default; + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT: + return COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT_to_default; + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT: + return COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT_to_default; + case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT: + return COMPRESSED_SRGB_S3TC_DXT1_EXT_to_default; + case GL_DEPTH24_STENCIL8: + { + switch (angleFormat) + { + case Format::ID::D24_UNORM_S8_UINT: + return DEPTH24_STENCIL8_to_D24_UNORM_S8_UINT; + default: + break; + } + } + case GL_DEPTH32F_STENCIL8: + { + switch (angleFormat) + { + case Format::ID::D32_FLOAT_S8X24_UINT: + return DEPTH32F_STENCIL8_to_D32_FLOAT_S8X24_UINT; + default: + break; + } + } + case GL_DEPTH_COMPONENT16: + { + switch (angleFormat) + { + case Format::ID::D16_UNORM: + return DEPTH_COMPONENT16_to_D16_UNORM; + default: + break; + } + } + case GL_DEPTH_COMPONENT24: + { + switch (angleFormat) + { + case Format::ID::D24_UNORM_S8_UINT: + return DEPTH_COMPONENT24_to_D24_UNORM_S8_UINT; + default: + break; + } + } + case GL_DEPTH_COMPONENT32F: + { + switch (angleFormat) + { + case Format::ID::D32_FLOAT: + return DEPTH_COMPONENT32F_to_D32_FLOAT; + default: + break; + } + } + case GL_DEPTH_COMPONENT32_OES: + return DEPTH_COMPONENT32_OES_to_default; + case GL_ETC1_RGB8_LOSSY_DECODE_ANGLE: + { + switch (angleFormat) + { + case Format::ID::BC1_RGB_UNORM_BLOCK: + return ETC1_RGB8_LOSSY_DECODE_ANGLE_to_BC1_RGB_UNORM_BLOCK; + default: + break; + } + } + case GL_ETC1_RGB8_OES: + { + switch (angleFormat) + { + case Format::ID::R8G8B8A8_UNORM: + return ETC1_RGB8_OES_to_R8G8B8A8_UNORM; + default: + break; + } + } + case GL_LUMINANCE: + { + switch (angleFormat) + { + case Format::ID::R16G16B16A16_FLOAT: + return LUMINANCE_to_R16G16B16A16_FLOAT; + case Format::ID::R32G32B32A32_FLOAT: + return LUMINANCE_to_R32G32B32A32_FLOAT; + default: + return LUMINANCE_to_default; + } + } + case GL_LUMINANCE16F_EXT: + return LUMINANCE16F_EXT_to_default; + case GL_LUMINANCE32F_EXT: + return LUMINANCE32F_EXT_to_default; + case GL_LUMINANCE8_ALPHA8_EXT: + return LUMINANCE8_ALPHA8_EXT_to_default; + case GL_LUMINANCE8_EXT: + return LUMINANCE8_EXT_to_default; + case GL_LUMINANCE_ALPHA: + { + switch (angleFormat) + { + case Format::ID::R16G16B16A16_FLOAT: + return LUMINANCE_ALPHA_to_R16G16B16A16_FLOAT; + case Format::ID::R32G32B32A32_FLOAT: + return LUMINANCE_ALPHA_to_R32G32B32A32_FLOAT; + default: + return LUMINANCE_ALPHA_to_default; + } + } + case GL_LUMINANCE_ALPHA16F_EXT: + return LUMINANCE_ALPHA16F_EXT_to_default; + case GL_LUMINANCE_ALPHA32F_EXT: + return LUMINANCE_ALPHA32F_EXT_to_default; + case GL_R11F_G11F_B10F: + { + switch (angleFormat) + { + case Format::ID::R11G11B10_FLOAT: + return R11F_G11F_B10F_to_R11G11B10_FLOAT; + default: + break; + } + } + case GL_R16F: + { + switch (angleFormat) + { + case Format::ID::R16_FLOAT: + return R16F_to_R16_FLOAT; + default: + break; + } + } + case GL_R16I: + { + switch (angleFormat) + { + case Format::ID::R16_SINT: + return R16I_to_R16_SINT; + default: + break; + } + } + case GL_R16UI: + { + switch (angleFormat) + { + case Format::ID::R16_UINT: + return R16UI_to_R16_UINT; + default: + break; + } + } + case GL_R16_EXT: + { + switch (angleFormat) + { + case Format::ID::R16_UNORM: + return R16_EXT_to_R16_UNORM; + default: + break; + } + } + case GL_R16_SNORM_EXT: + { + switch (angleFormat) + { + case Format::ID::R16_SNORM: + return R16_SNORM_EXT_to_R16_SNORM; + default: + break; + } + } + case GL_R32F: + { + switch (angleFormat) + { + case Format::ID::R32_FLOAT: + return R32F_to_R32_FLOAT; + default: + break; + } + } + case GL_R32I: + { + switch (angleFormat) + { + case Format::ID::R32_SINT: + return R32I_to_R32_SINT; + default: + break; + } + } + case GL_R32UI: + { + switch (angleFormat) + { + case Format::ID::R32_UINT: + return R32UI_to_R32_UINT; + default: + break; + } + } + case GL_R8: + { + switch (angleFormat) + { + case Format::ID::R8_UNORM: + return R8_to_R8_UNORM; + default: + break; + } + } + case GL_R8I: + { + switch (angleFormat) + { + case Format::ID::R8_SINT: + return R8I_to_R8_SINT; + default: + break; + } + } + case GL_R8UI: + { + switch (angleFormat) + { + case Format::ID::R8_UINT: + return R8UI_to_R8_UINT; + default: + break; + } + } + case GL_R8_SNORM: + { + switch (angleFormat) + { + case Format::ID::R8_SNORM: + return R8_SNORM_to_R8_SNORM; + default: + break; + } + } + case GL_RG16F: + { + switch (angleFormat) + { + case Format::ID::R16G16_FLOAT: + return RG16F_to_R16G16_FLOAT; + default: + break; + } + } + case GL_RG16I: + { + switch (angleFormat) + { + case Format::ID::R16G16_SINT: + return RG16I_to_R16G16_SINT; + default: + break; + } + } + case GL_RG16UI: + { + switch (angleFormat) + { + case Format::ID::R16G16_UINT: + return RG16UI_to_R16G16_UINT; + default: + break; + } + } + case GL_RG16_EXT: + { + switch (angleFormat) + { + case Format::ID::R16G16_UNORM: + return RG16_EXT_to_R16G16_UNORM; + default: + break; + } + } + case GL_RG16_SNORM_EXT: + { + switch (angleFormat) + { + case Format::ID::R16G16_SNORM: + return RG16_SNORM_EXT_to_R16G16_SNORM; + default: + break; + } + } + case GL_RG32F: + { + switch (angleFormat) + { + case Format::ID::R32G32_FLOAT: + return RG32F_to_R32G32_FLOAT; + default: + break; + } + } + case GL_RG32I: + { + switch (angleFormat) + { + case Format::ID::R32G32_SINT: + return RG32I_to_R32G32_SINT; + default: + break; + } + } + case GL_RG32UI: + { + switch (angleFormat) + { + case Format::ID::R32G32_UINT: + return RG32UI_to_R32G32_UINT; + default: + break; + } + } + case GL_RG8: + { + switch (angleFormat) + { + case Format::ID::R8G8_UNORM: + return RG8_to_R8G8_UNORM; + default: + break; + } + } + case GL_RG8I: + { + switch (angleFormat) + { + case Format::ID::R8G8_SINT: + return RG8I_to_R8G8_SINT; + default: + break; + } + } + case GL_RG8UI: + { + switch (angleFormat) + { + case Format::ID::R8G8_UINT: + return RG8UI_to_R8G8_UINT; + default: + break; + } + } + case GL_RG8_SNORM: + { + switch (angleFormat) + { + case Format::ID::R8G8_SNORM: + return RG8_SNORM_to_R8G8_SNORM; + default: + break; + } + } + case GL_RGB: + return RGB_to_default; + case GL_RGB10_A2: + { + switch (angleFormat) + { + case Format::ID::R10G10B10A2_UNORM: + return RGB10_A2_to_R10G10B10A2_UNORM; + default: + break; + } + } + case GL_RGB10_A2UI: + { + switch (angleFormat) + { + case Format::ID::R10G10B10A2_UINT: + return RGB10_A2UI_to_R10G10B10A2_UINT; + default: + break; + } + } + case GL_RGB16F: + { + switch (angleFormat) + { + case Format::ID::R16G16B16A16_FLOAT: + return RGB16F_to_R16G16B16A16_FLOAT; + default: + break; + } + } + case GL_RGB16I: + { + switch (angleFormat) + { + case Format::ID::R16G16B16A16_SINT: + return RGB16I_to_R16G16B16A16_SINT; + default: + break; + } + } + case GL_RGB16UI: + { + switch (angleFormat) + { + case Format::ID::R16G16B16A16_UINT: + return RGB16UI_to_R16G16B16A16_UINT; + default: + break; + } + } + case GL_RGB16_EXT: + { + switch (angleFormat) + { + case Format::ID::R16G16B16A16_UNORM: + return RGB16_EXT_to_R16G16B16A16_UNORM; + default: + break; + } + } + case GL_RGB16_SNORM_EXT: + { + switch (angleFormat) + { + case Format::ID::R16G16B16A16_SNORM: + return RGB16_SNORM_EXT_to_R16G16B16A16_SNORM; + default: + break; + } + } + case GL_RGB32F: + { + switch (angleFormat) + { + case Format::ID::R32G32B32A32_FLOAT: + return RGB32F_to_R32G32B32A32_FLOAT; + default: + break; + } + } + case GL_RGB32I: + { + switch (angleFormat) + { + case Format::ID::R32G32B32A32_SINT: + return RGB32I_to_R32G32B32A32_SINT; + default: + break; + } + } + case GL_RGB32UI: + { + switch (angleFormat) + { + case Format::ID::R32G32B32A32_UINT: + return RGB32UI_to_R32G32B32A32_UINT; + default: + break; + } + } + case GL_RGB565: + { + switch (angleFormat) + { + case Format::ID::B5G6R5_UNORM: + return RGB565_to_B5G6R5_UNORM; + case Format::ID::R8G8B8A8_UNORM: + return RGB565_to_R8G8B8A8_UNORM; + default: + break; + } + } + case GL_RGB5_A1: + { + switch (angleFormat) + { + case Format::ID::B5G5R5A1_UNORM: + return RGB5_A1_to_B5G5R5A1_UNORM; + case Format::ID::R8G8B8A8_UNORM: + return RGB5_A1_to_R8G8B8A8_UNORM; + default: + break; + } + } + case GL_RGB8: + { + switch (angleFormat) + { + case Format::ID::R8G8B8A8_UNORM: + return RGB8_to_R8G8B8A8_UNORM; + default: + break; + } + } + case GL_RGB8I: + { + switch (angleFormat) + { + case Format::ID::R8G8B8A8_SINT: + return RGB8I_to_R8G8B8A8_SINT; + default: + break; + } + } + case GL_RGB8UI: + { + switch (angleFormat) + { + case Format::ID::R8G8B8A8_UINT: + return RGB8UI_to_R8G8B8A8_UINT; + default: + break; + } + } + case GL_RGB8_SNORM: + { + switch (angleFormat) + { + case Format::ID::R8G8B8A8_SNORM: + return RGB8_SNORM_to_R8G8B8A8_SNORM; + default: + break; + } + } + case GL_RGB9_E5: + { + switch (angleFormat) + { + case Format::ID::R9G9B9E5_SHAREDEXP: + return RGB9_E5_to_R9G9B9E5_SHAREDEXP; + default: + break; + } + } + case GL_RGBA: + return RGBA_to_default; + case GL_RGBA16F: + { + switch (angleFormat) + { + case Format::ID::R16G16B16A16_FLOAT: + return RGBA16F_to_R16G16B16A16_FLOAT; + default: + break; + } + } + case GL_RGBA16I: + { + switch (angleFormat) + { + case Format::ID::R16G16B16A16_SINT: + return RGBA16I_to_R16G16B16A16_SINT; + default: + break; + } + } + case GL_RGBA16UI: + { + switch (angleFormat) + { + case Format::ID::R16G16B16A16_UINT: + return RGBA16UI_to_R16G16B16A16_UINT; + default: + break; + } + } + case GL_RGBA16_EXT: + { + switch (angleFormat) + { + case Format::ID::R16G16B16A16_UNORM: + return RGBA16_EXT_to_R16G16B16A16_UNORM; + default: + break; + } + } + case GL_RGBA16_SNORM_EXT: + { + switch (angleFormat) + { + case Format::ID::R16G16B16A16_SNORM: + return RGBA16_SNORM_EXT_to_R16G16B16A16_SNORM; + default: + break; + } + } + case GL_RGBA32F: + { + switch (angleFormat) + { + case Format::ID::R32G32B32A32_FLOAT: + return RGBA32F_to_R32G32B32A32_FLOAT; + default: + break; + } + } + case GL_RGBA32I: + { + switch (angleFormat) + { + case Format::ID::R32G32B32A32_SINT: + return RGBA32I_to_R32G32B32A32_SINT; + default: + break; + } + } + case GL_RGBA32UI: + { + switch (angleFormat) + { + case Format::ID::R32G32B32A32_UINT: + return RGBA32UI_to_R32G32B32A32_UINT; + default: + break; + } + } + case GL_RGBA4: + { + switch (angleFormat) + { + case Format::ID::B4G4R4A4_UNORM: + return RGBA4_to_B4G4R4A4_UNORM; + case Format::ID::R8G8B8A8_UNORM: + return RGBA4_to_R8G8B8A8_UNORM; + default: + break; + } + } + case GL_RGBA8: + { + switch (angleFormat) + { + case Format::ID::R8G8B8A8_UNORM: + return RGBA8_to_R8G8B8A8_UNORM; + default: + break; + } + } + case GL_RGBA8I: + { + switch (angleFormat) + { + case Format::ID::R8G8B8A8_SINT: + return RGBA8I_to_R8G8B8A8_SINT; + default: + break; + } + } + case GL_RGBA8UI: + { + switch (angleFormat) + { + case Format::ID::R8G8B8A8_UINT: + return RGBA8UI_to_R8G8B8A8_UINT; + default: + break; + } + } + case GL_RGBA8_SNORM: + { + switch (angleFormat) + { + case Format::ID::R8G8B8A8_SNORM: + return RGBA8_SNORM_to_R8G8B8A8_SNORM; + default: + break; + } + } + case GL_SRGB8: + { + switch (angleFormat) + { + case Format::ID::R8G8B8A8_UNORM_SRGB: + return SRGB8_to_R8G8B8A8_UNORM_SRGB; + default: + break; + } + } + case GL_SRGB8_ALPHA8: + { + switch (angleFormat) + { + case Format::ID::R8G8B8A8_UNORM_SRGB: + return SRGB8_ALPHA8_to_R8G8B8A8_UNORM_SRGB; + default: + break; + } + } + case GL_STENCIL_INDEX8: + return STENCIL_INDEX8_to_default; + + default: + { + static LoadFunctionMap emptyLoadFunctionsMap; + return emptyLoadFunctionsMap; + } + } + // clang-format on + +} // GetLoadFunctionsMap + +} // namespace angle diff --git a/src/3rdparty/angle/src/libANGLE/renderer/renderer_utils.cpp b/src/3rdparty/angle/src/libANGLE/renderer/renderer_utils.cpp new file mode 100644 index 0000000000..55471c1d20 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/renderer_utils.cpp @@ -0,0 +1,549 @@ +// +// Copyright 2016 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_utils: +// Helper methods pertaining to most or all back-ends. +// + +#include "libANGLE/renderer/renderer_utils.h" + +#include "image_util/copyimage.h" +#include "image_util/imageformats.h" + +#include "libANGLE/AttributeMap.h" +#include "libANGLE/Context.h" +#include "libANGLE/formatutils.h" +#include "libANGLE/renderer/ContextImpl.h" +#include "libANGLE/renderer/Format.h" + +#include + +namespace rx +{ + +namespace +{ +typedef std::pair FormatWriteFunctionPair; +typedef std::map FormatWriteFunctionMap; + +static inline void InsertFormatWriteFunctionMapping(FormatWriteFunctionMap *map, + GLenum format, + GLenum type, + ColorWriteFunction writeFunc) +{ + map->insert(FormatWriteFunctionPair(gl::FormatType(format, type), writeFunc)); +} + +static FormatWriteFunctionMap BuildFormatWriteFunctionMap() +{ + using namespace angle; // For image writing functions + + FormatWriteFunctionMap map; + + // clang-format off + // | 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, GL_UNSIGNED_SHORT, + WriteColor); + InsertFormatWriteFunctionMapping(&map, GL_RGBA, GL_SHORT, 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, GL_UNSIGNED_SHORT, + WriteColor); + InsertFormatWriteFunctionMapping(&map, GL_RGB, GL_SHORT, 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, GL_UNSIGNED_SHORT, WriteColor); + InsertFormatWriteFunctionMapping(&map, GL_RG, GL_SHORT, 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, GL_UNSIGNED_SHORT, WriteColor); + InsertFormatWriteFunctionMapping(&map, GL_RED, GL_SHORT, 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, nullptr ); + InsertFormatWriteFunctionMapping(&map, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, GL_UNSIGNED_BYTE, nullptr ); + InsertFormatWriteFunctionMapping(&map, GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE, GL_UNSIGNED_BYTE, nullptr ); + InsertFormatWriteFunctionMapping(&map, GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE, GL_UNSIGNED_BYTE, nullptr ); + + InsertFormatWriteFunctionMapping(&map, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, nullptr ); + InsertFormatWriteFunctionMapping(&map, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, nullptr ); + InsertFormatWriteFunctionMapping(&map, GL_DEPTH_COMPONENT, GL_FLOAT, nullptr ); + + InsertFormatWriteFunctionMapping(&map, GL_STENCIL, GL_UNSIGNED_BYTE, nullptr ); + + InsertFormatWriteFunctionMapping(&map, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, nullptr ); + InsertFormatWriteFunctionMapping(&map, GL_DEPTH_STENCIL, GL_FLOAT_32_UNSIGNED_INT_24_8_REV, nullptr ); + // clang-format on + + return map; +} + +void CopyColor(gl::ColorF *color) +{ + // No-op +} + +void PremultiplyAlpha(gl::ColorF *color) +{ + color->red *= color->alpha; + color->green *= color->alpha; + color->blue *= color->alpha; +} + +void UnmultiplyAlpha(gl::ColorF *color) +{ + if (color->alpha != 0.0f) + { + float invAlpha = 1.0f / color->alpha; + color->red *= invAlpha; + color->green *= invAlpha; + color->blue *= invAlpha; + } +} + +void ClipChannelsR(gl::ColorF *color) +{ + color->green = 0.0f; + color->blue = 0.0f; + color->alpha = 1.0f; +} + +void ClipChannelsRG(gl::ColorF *color) +{ + color->blue = 0.0f; + color->alpha = 1.0f; +} + +void ClipChannelsRGB(gl::ColorF *color) +{ + color->alpha = 1.0f; +} + +void ClipChannelsLuminance(gl::ColorF *color) +{ + color->alpha = 1.0f; +} + +void ClipChannelsAlpha(gl::ColorF *color) +{ + color->red = 0.0f; + color->green = 0.0f; + color->blue = 0.0f; +} + +void ClipChannelsNoOp(gl::ColorF *color) +{ +} + +void WriteUintColor(const gl::ColorF &color, + ColorWriteFunction colorWriteFunction, + uint8_t *destPixelData) +{ + gl::ColorUI destColor( + static_cast(color.red * 255), static_cast(color.green * 255), + static_cast(color.blue * 255), static_cast(color.alpha * 255)); + colorWriteFunction(reinterpret_cast(&destColor), destPixelData); +} + +void WriteFloatColor(const gl::ColorF &color, + ColorWriteFunction colorWriteFunction, + uint8_t *destPixelData) +{ + colorWriteFunction(reinterpret_cast(&color), destPixelData); +} + +} // anonymous namespace + +PackPixelsParams::PackPixelsParams() + : format(GL_NONE), type(GL_NONE), outputPitch(0), packBuffer(nullptr), offset(0) +{ +} + +PackPixelsParams::PackPixelsParams(const gl::Rectangle &areaIn, + GLenum formatIn, + GLenum typeIn, + GLuint outputPitchIn, + const gl::PixelPackState &packIn, + gl::Buffer *packBufferIn, + ptrdiff_t offsetIn) + : area(areaIn), + format(formatIn), + type(typeIn), + outputPitch(outputPitchIn), + packBuffer(packBufferIn), + pack(), + offset(offsetIn) +{ + pack.alignment = packIn.alignment; + pack.reverseRowOrder = packIn.reverseRowOrder; +} + +void PackPixels(const PackPixelsParams ¶ms, + const angle::Format &sourceFormat, + int inputPitchIn, + const uint8_t *sourceIn, + uint8_t *destWithoutOffset) +{ + uint8_t *destWithOffset = destWithoutOffset + params.offset; + + const uint8_t *source = sourceIn; + int inputPitch = inputPitchIn; + + if (params.pack.reverseRowOrder) + { + source += inputPitch * (params.area.height - 1); + inputPitch = -inputPitch; + } + + const auto &sourceGLInfo = gl::GetSizedInternalFormatInfo(sourceFormat.glInternalFormat); + + if (sourceGLInfo.format == params.format && sourceGLInfo.type == params.type) + { + // Direct copy possible + for (int y = 0; y < params.area.height; ++y) + { + memcpy(destWithOffset + y * params.outputPitch, source + y * inputPitch, + params.area.width * sourceGLInfo.pixelBytes); + } + return; + } + + ASSERT(sourceGLInfo.sized); + + gl::FormatType formatType(params.format, params.type); + ColorCopyFunction fastCopyFunc = + GetFastCopyFunction(sourceFormat.fastCopyFunctions, formatType); + const auto &destFormatInfo = gl::GetInternalFormatInfo(formatType.format, formatType.type); + + 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 = + destWithOffset + y * params.outputPitch + x * destFormatInfo.pixelBytes; + const uint8_t *src = source + y * inputPitch + x * sourceGLInfo.pixelBytes; + + fastCopyFunc(src, dest); + } + } + return; + } + + ColorWriteFunction colorWriteFunction = GetColorWriteFunction(formatType); + + // Maximum size of any Color type used. + uint8_t temp[16]; + static_assert(sizeof(temp) >= sizeof(gl::ColorF) && sizeof(temp) >= sizeof(gl::ColorUI) && + sizeof(temp) >= sizeof(gl::ColorI), + "Unexpected size of gl::Color struct."); + + const auto &colorReadFunction = sourceFormat.colorReadFunction; + + for (int y = 0; y < params.area.height; ++y) + { + for (int x = 0; x < params.area.width; ++x) + { + uint8_t *dest = destWithOffset + y * params.outputPitch + x * destFormatInfo.pixelBytes; + const uint8_t *src = source + y * inputPitch + x * sourceGLInfo.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); + } + } +} + +ColorWriteFunction GetColorWriteFunction(const gl::FormatType &formatType) +{ + static const FormatWriteFunctionMap formatTypeMap = BuildFormatWriteFunctionMap(); + auto iter = formatTypeMap.find(formatType); + ASSERT(iter != formatTypeMap.end()); + if (iter != formatTypeMap.end()) + { + return iter->second; + } + else + { + return nullptr; + } +} + +ColorCopyFunction GetFastCopyFunction(const FastCopyFunctionMap &fastCopyFunctions, + const gl::FormatType &formatType) +{ + return fastCopyFunctions.get(formatType); +} + +bool FastCopyFunctionMap::has(const gl::FormatType &formatType) const +{ + return (get(formatType) != nullptr); +} + +ColorCopyFunction FastCopyFunctionMap::get(const gl::FormatType &formatType) const +{ + for (size_t index = 0; index < mSize; ++index) + { + if (mData[index].format == formatType.format && mData[index].type == formatType.type) + { + return mData[index].func; + } + } + + return nullptr; +} + +bool ShouldUseDebugLayers(const egl::AttributeMap &attribs) +{ + EGLAttrib debugSetting = + attribs.get(EGL_PLATFORM_ANGLE_DEBUG_LAYERS_ENABLED_ANGLE, EGL_DONT_CARE); + +// Prefer to enable debug layers if compiling in Debug, and disabled in Release. +#if !defined(NDEBUG) + return (debugSetting != EGL_FALSE); +#else + return (debugSetting == EGL_TRUE); +#endif // !defined(NDEBUG) +} + +void CopyImageCHROMIUM(const uint8_t *sourceData, + size_t sourceRowPitch, + size_t sourcePixelBytes, + ColorReadFunction colorReadFunction, + uint8_t *destData, + size_t destRowPitch, + size_t destPixelBytes, + ColorWriteFunction colorWriteFunction, + GLenum destUnsizedFormat, + GLenum destComponentType, + size_t width, + size_t height, + bool unpackFlipY, + bool unpackPremultiplyAlpha, + bool unpackUnmultiplyAlpha) +{ + using ConversionFunction = void (*)(gl::ColorF *); + ConversionFunction conversionFunction = CopyColor; + if (unpackPremultiplyAlpha != unpackUnmultiplyAlpha) + { + if (unpackPremultiplyAlpha) + { + conversionFunction = PremultiplyAlpha; + } + else + { + conversionFunction = UnmultiplyAlpha; + } + } + + auto clipChannelsFunction = ClipChannelsNoOp; + switch (destUnsizedFormat) + { + case GL_RED: + clipChannelsFunction = ClipChannelsR; + break; + case GL_RG: + clipChannelsFunction = ClipChannelsRG; + break; + case GL_RGB: + clipChannelsFunction = ClipChannelsRGB; + break; + case GL_LUMINANCE: + clipChannelsFunction = ClipChannelsLuminance; + break; + case GL_ALPHA: + clipChannelsFunction = ClipChannelsAlpha; + break; + } + + auto writeFunction = (destComponentType == GL_UNSIGNED_INT) ? WriteUintColor : WriteFloatColor; + + for (size_t y = 0; y < height; y++) + { + for (size_t x = 0; x < width; x++) + { + const uint8_t *sourcePixelData = sourceData + y * sourceRowPitch + x * sourcePixelBytes; + + gl::ColorF sourceColor; + colorReadFunction(sourcePixelData, reinterpret_cast(&sourceColor)); + + conversionFunction(&sourceColor); + clipChannelsFunction(&sourceColor); + + size_t destY = 0; + if (unpackFlipY) + { + destY += (height - 1); + destY -= y; + } + else + { + destY += y; + } + + uint8_t *destPixelData = destData + destY * destRowPitch + x * destPixelBytes; + writeFunction(sourceColor, colorWriteFunction, destPixelData); + } + } +} + +// IncompleteTextureSet implementation. +IncompleteTextureSet::IncompleteTextureSet() +{ +} + +IncompleteTextureSet::~IncompleteTextureSet() +{ +} + +void IncompleteTextureSet::onDestroy(const gl::Context *context) +{ + // Clear incomplete textures. + for (auto &incompleteTexture : mIncompleteTextures) + { + ANGLE_SWALLOW_ERR(incompleteTexture.second->onDestroy(context)); + incompleteTexture.second.set(context, nullptr); + } + mIncompleteTextures.clear(); +} + +gl::Error IncompleteTextureSet::getIncompleteTexture( + const gl::Context *context, + GLenum type, + MultisampleTextureInitializer *multisampleInitializer, + gl::Texture **textureOut) +{ + auto iter = mIncompleteTextures.find(type); + if (iter != mIncompleteTextures.end()) + { + *textureOut = iter->second.get(); + return gl::NoError(); + } + + ContextImpl *implFactory = context->getImplementation(); + + const GLubyte color[] = {0, 0, 0, 255}; + const gl::Extents colorSize(1, 1, 1); + gl::PixelUnpackState unpack; + unpack.alignment = 1; + const gl::Box area(0, 0, 0, 1, 1, 1); + + // If a texture is external use a 2D texture for the incomplete texture + GLenum createType = (type == GL_TEXTURE_EXTERNAL_OES) ? GL_TEXTURE_2D : type; + + gl::Texture *tex = new gl::Texture(implFactory, std::numeric_limits::max(), createType); + angle::UniqueObjectPointer t(tex, context); + + if (createType == GL_TEXTURE_2D_MULTISAMPLE) + { + ANGLE_TRY(t->setStorageMultisample(context, createType, 1, GL_RGBA8, colorSize, true)); + } + else + { + ANGLE_TRY(t->setStorage(context, createType, 1, GL_RGBA8, colorSize)); + } + + if (type == GL_TEXTURE_CUBE_MAP) + { + for (GLenum face = GL_TEXTURE_CUBE_MAP_POSITIVE_X; face <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z; + face++) + { + ANGLE_TRY( + t->setSubImage(context, unpack, face, 0, area, GL_RGBA, GL_UNSIGNED_BYTE, color)); + } + } + else if (type == GL_TEXTURE_2D_MULTISAMPLE) + { + // Call a specialized clear function to init a multisample texture. + ANGLE_TRY(multisampleInitializer->initializeMultisampleTextureToBlack(context, t.get())); + } + else + { + ANGLE_TRY( + t->setSubImage(context, unpack, createType, 0, area, GL_RGBA, GL_UNSIGNED_BYTE, color)); + } + + t->syncState(); + + mIncompleteTextures[type].set(context, t.release()); + *textureOut = mIncompleteTextures[type].get(); + return gl::NoError(); +} + +} // namespace rx diff --git a/src/3rdparty/angle/src/libANGLE/renderer/renderer_utils.h b/src/3rdparty/angle/src/libANGLE/renderer/renderer_utils.h new file mode 100644 index 0000000000..5a1cb38a6a --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/renderer_utils.h @@ -0,0 +1,254 @@ +// +// Copyright 2016 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_utils: +// Helper methods pertaining to most or all back-ends. +// + +#ifndef LIBANGLE_RENDERER_RENDERER_UTILS_H_ +#define LIBANGLE_RENDERER_RENDERER_UTILS_H_ + +#include + +#include +#include + +#include "common/angleutils.h" +#include "libANGLE/angletypes.h" + +namespace angle +{ +struct Format; +} // namespace angle + +namespace gl +{ +struct FormatType; +struct InternalFormat; +} // namespace gl + +namespace egl +{ +class AttributeMap; +} // namespace egl + +namespace rx +{ + +class ResourceSerial +{ + public: + constexpr ResourceSerial() : mValue(kDirty) {} + explicit constexpr ResourceSerial(uintptr_t value) : mValue(value) {} + constexpr bool operator==(ResourceSerial other) const { return mValue == other.mValue; } + constexpr bool operator!=(ResourceSerial other) const { return mValue != other.mValue; } + + void dirty() { mValue = kDirty; } + void clear() { mValue = kEmpty; } + + constexpr bool valid() const { return mValue != kEmpty && mValue != kDirty; } + constexpr bool empty() const { return mValue == kEmpty; } + + private: + constexpr static uintptr_t kDirty = std::numeric_limits::max(); + constexpr static uintptr_t kEmpty = 0; + + uintptr_t mValue; +}; + +class SerialFactory; + +class Serial final +{ + public: + constexpr Serial() : mValue(kInvalid) {} + constexpr Serial(const Serial &other) = default; + Serial &operator=(const Serial &other) = default; + + constexpr bool operator==(const Serial &other) const + { + return mValue != kInvalid && mValue == other.mValue; + } + constexpr bool operator!=(const Serial &other) const + { + return mValue == kInvalid || mValue != other.mValue; + } + constexpr bool operator>(const Serial &other) const { return mValue > other.mValue; } + constexpr bool operator>=(const Serial &other) const { return mValue >= other.mValue; } + constexpr bool operator<(const Serial &other) const { return mValue < other.mValue; } + constexpr bool operator<=(const Serial &other) const { return mValue <= other.mValue; } + + private: + friend class SerialFactory; + constexpr explicit Serial(uint64_t value) : mValue(value) {} + uint64_t mValue; + static constexpr uint64_t kInvalid = 0; +}; + +class SerialFactory final : angle::NonCopyable +{ + public: + SerialFactory() : mSerial(1) {} + + Serial generate() + { + ASSERT(mSerial != std::numeric_limits::max()); + return Serial(mSerial++); + } + + private: + uint64_t mSerial; +}; + +using MipGenerationFunction = void (*)(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 (*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); + +class FastCopyFunctionMap +{ + public: + struct Entry + { + GLenum format; + GLenum type; + ColorCopyFunction func; + }; + + constexpr FastCopyFunctionMap() : FastCopyFunctionMap(nullptr, 0) {} + + constexpr FastCopyFunctionMap(const Entry *data, size_t size) : mSize(size), mData(data) {} + + bool has(const gl::FormatType &formatType) const; + ColorCopyFunction get(const gl::FormatType &formatType) const; + + private: + size_t mSize; + const Entry *mData; +}; + +struct PackPixelsParams +{ + PackPixelsParams(); + PackPixelsParams(const gl::Rectangle &area, + GLenum format, + GLenum type, + GLuint outputPitch, + const gl::PixelPackState &pack, + gl::Buffer *packBufferIn, + ptrdiff_t offset); + + gl::Rectangle area; + GLenum format; + GLenum type; + GLuint outputPitch; + gl::Buffer *packBuffer; + gl::PixelPackState pack; + ptrdiff_t offset; +}; + +void PackPixels(const PackPixelsParams ¶ms, + const angle::Format &sourceFormat, + int inputPitch, + const uint8_t *source, + uint8_t *destination); + +ColorWriteFunction GetColorWriteFunction(const gl::FormatType &formatType); +ColorCopyFunction GetFastCopyFunction(const FastCopyFunctionMap &fastCopyFunctions, + const gl::FormatType &formatType); + +using InitializeTextureDataFunction = void (*)(size_t width, + size_t height, + size_t depth, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch); + +using LoadImageFunction = void (*)(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); + +struct LoadImageFunctionInfo +{ + LoadImageFunctionInfo() : loadFunction(nullptr), requiresConversion(false) {} + LoadImageFunctionInfo(LoadImageFunction loadFunction, bool requiresConversion) + : loadFunction(loadFunction), requiresConversion(requiresConversion) + { + } + + LoadImageFunction loadFunction; + bool requiresConversion; +}; + +using LoadFunctionMap = LoadImageFunctionInfo (*)(GLenum); + +bool ShouldUseDebugLayers(const egl::AttributeMap &attribs); + +void CopyImageCHROMIUM(const uint8_t *sourceData, + size_t sourceRowPitch, + size_t sourcePixelBytes, + ColorReadFunction readFunction, + uint8_t *destData, + size_t destRowPitch, + size_t destPixelBytes, + ColorWriteFunction colorWriteFunction, + GLenum destUnsizedFormat, + GLenum destComponentType, + size_t width, + size_t height, + bool unpackFlipY, + bool unpackPremultiplyAlpha, + bool unpackUnmultiplyAlpha); + +// Incomplete textures are 1x1 textures filled with black, used when samplers are incomplete. +// This helper class encapsulates handling incomplete textures. Because the GL back-end +// can take advantage of the driver's incomplete textures, and because clearing multisample +// textures is so difficult, we can keep an instance of this class in the back-end instead +// of moving the logic to the Context front-end. + +// This interface allows us to call-back to init a multisample texture. +class MultisampleTextureInitializer +{ + public: + virtual ~MultisampleTextureInitializer() {} + virtual gl::Error initializeMultisampleTextureToBlack(const gl::Context *context, + gl::Texture *glTexture) = 0; +}; + +class IncompleteTextureSet final : angle::NonCopyable +{ + public: + IncompleteTextureSet(); + ~IncompleteTextureSet(); + + void onDestroy(const gl::Context *context); + + gl::Error getIncompleteTexture(const gl::Context *context, + GLenum type, + MultisampleTextureInitializer *multisampleInitializer, + gl::Texture **textureOut); + + private: + gl::TextureMap mIncompleteTextures; +}; + +} // namespace rx + +#endif // LIBANGLE_RENDERER_RENDERER_UTILS_H_ diff --git a/src/3rdparty/angle/src/libANGLE/signal_utils.h b/src/3rdparty/angle/src/libANGLE/signal_utils.h new file mode 100644 index 0000000000..3dd1332013 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/signal_utils.h @@ -0,0 +1,187 @@ +// +// Copyright 2016 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. +// +// signal_utils: +// Helper classes for tracking dependent state changes between objects. +// These changes are signaled to the dependent class via channels. +// See design document: +// https://docs.google.com/document/d/15Edfotqg6_l1skTEL8ADQudF_oIdNa7i8Po43k6jMd4/ + +#ifndef LIBANGLE_SIGNAL_UTILS_H_ +#define LIBANGLE_SIGNAL_UTILS_H_ + +#include + +#include "common/angleutils.h" +#include "common/debug.h" + +namespace angle +{ + +// Interface that the depending class inherits from. +template +class SignalReceiver +{ + public: + virtual ~SignalReceiver() = default; + virtual void signal(ChannelID channelID, MessageT... message) = 0; +}; + +template +class ChannelBinding; + +// The host class owns the channel. It uses the channel to fire signals to the receiver. +template +class BroadcastChannel final : NonCopyable +{ + public: + BroadcastChannel(); + ~BroadcastChannel(); + + void signal(MessageT... message) const; + + void reset(); + + bool empty() const; + + private: + // Only the ChannelBinding class should add or remove receivers. + friend class ChannelBinding; + void addReceiver(ChannelBinding *receiver); + void removeReceiver(ChannelBinding *receiver); + + std::vector *> mReceivers; +}; + +template +BroadcastChannel::BroadcastChannel() +{ +} + +template +BroadcastChannel::~BroadcastChannel() +{ + reset(); +} + +template +void BroadcastChannel::addReceiver( + ChannelBinding *receiver) +{ + ASSERT(std::find(mReceivers.begin(), mReceivers.end(), receiver) == mReceivers.end()); + mReceivers.push_back(receiver); +} + +template +void BroadcastChannel::removeReceiver( + ChannelBinding *receiver) +{ + auto iter = std::find(mReceivers.begin(), mReceivers.end(), receiver); + ASSERT(iter != mReceivers.end()); + mReceivers.erase(iter); +} + +template +void BroadcastChannel::signal(MessageT... message) const +{ + if (mReceivers.empty()) + return; + + for (const auto *receiver : mReceivers) + { + receiver->signal(message...); + } +} + +template +void BroadcastChannel::reset() +{ + for (auto receiver : mReceivers) + { + receiver->onChannelClosed(); + } + mReceivers.clear(); +} + +template +bool BroadcastChannel::empty() const +{ + return mReceivers.empty(); +} + +// The dependent class keeps bindings to the host's BroadcastChannel. +template +class ChannelBinding final +{ + public: + ChannelBinding(SignalReceiver *receiver, ChannelID channelID); + ~ChannelBinding(); + ChannelBinding(const ChannelBinding &other) = default; + ChannelBinding &operator=(const ChannelBinding &other) = default; + + void bind(BroadcastChannel *channel); + void reset(); + void signal(MessageT... message) const; + void onChannelClosed(); + + private: + BroadcastChannel *mChannel; + SignalReceiver *mReceiver; + ChannelID mChannelID; +}; + +template +ChannelBinding::ChannelBinding( + SignalReceiver *receiver, + ChannelID channelID) + : mChannel(nullptr), mReceiver(receiver), mChannelID(channelID) +{ + ASSERT(receiver); +} + +template +ChannelBinding::~ChannelBinding() +{ + reset(); +} + +template +void ChannelBinding::bind(BroadcastChannel *channel) +{ + ASSERT(mReceiver); + if (mChannel) + { + mChannel->removeReceiver(this); + } + + mChannel = channel; + + if (mChannel) + { + mChannel->addReceiver(this); + } +} + +template +void ChannelBinding::reset() +{ + bind(nullptr); +} + +template +void ChannelBinding::signal(MessageT... message) const +{ + mReceiver->signal(mChannelID, message...); +} + +template +void ChannelBinding::onChannelClosed() +{ + mChannel = nullptr; +} + +} // namespace angle + +#endif // LIBANGLE_SIGNAL_UTILS_H_ diff --git a/src/3rdparty/angle/src/libANGLE/validationEGL.cpp b/src/3rdparty/angle/src/libANGLE/validationEGL.cpp index 903f51b158..13a3a9e280 100644 --- a/src/3rdparty/angle/src/libANGLE/validationEGL.cpp +++ b/src/3rdparty/angle/src/libANGLE/validationEGL.cpp @@ -1,5 +1,5 @@ // -// Copyright (c) 2015 The ANGLE Project Authors. All rights reserved. +// Copyright (c) 2016 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. // @@ -14,10 +14,15 @@ #include "libANGLE/Device.h" #include "libANGLE/Display.h" #include "libANGLE/Image.h" +#include "libANGLE/Stream.h" #include "libANGLE/Surface.h" +#include "libANGLE/Texture.h" +#include "libANGLE/formatutils.h" #include +namespace egl +{ namespace { size_t GetMaximumMipLevel(const gl::Context *context, GLenum target) @@ -30,6 +35,9 @@ size_t GetMaximumMipLevel(const gl::Context *context, GLenum target) case GL_TEXTURE_2D: maxDimension = caps.max2DTextureSize; break; + case GL_TEXTURE_RECTANGLE_ANGLE: + maxDimension = caps.maxRectangleTextureSize; + break; case GL_TEXTURE_CUBE_MAP: maxDimension = caps.maxCubeMapTextureSize; break; @@ -56,7 +64,7 @@ bool TextureHasNonZeroMipLevelsSpecified(const gl::Context *context, const gl::T for (GLenum face = gl::FirstCubeMapTextureTarget; face <= gl::LastCubeMapTextureTarget; face++) { - if (texture->getInternalFormat(face, level) != GL_NONE) + if (texture->getFormat(face, level).valid()) { return true; } @@ -64,7 +72,7 @@ bool TextureHasNonZeroMipLevelsSpecified(const gl::Context *context, const gl::T } else { - if (texture->getInternalFormat(texture->getTarget(), level) != GL_NONE) + if (texture->getFormat(texture->getTarget(), level).valid()) { return true; } @@ -79,7 +87,7 @@ bool CubeTextureHasUnspecifiedLevel0Face(const gl::Texture *texture) ASSERT(texture->getTarget() == GL_TEXTURE_CUBE_MAP); for (GLenum face = gl::FirstCubeMapTextureTarget; face <= gl::LastCubeMapTextureTarget; face++) { - if (texture->getInternalFormat(face, 0) == GL_NONE) + if (!texture->getFormat(face, 0).valid()) { return true; } @@ -87,114 +95,482 @@ bool CubeTextureHasUnspecifiedLevel0Face(const gl::Texture *texture) return false; } + +Error ValidateStreamAttribute(const EGLAttrib attribute, + const EGLAttrib value, + const DisplayExtensions &extensions) +{ + switch (attribute) + { + case EGL_STREAM_STATE_KHR: + case EGL_PRODUCER_FRAME_KHR: + case EGL_CONSUMER_FRAME_KHR: + return EglBadAccess() << "Attempt to initialize readonly parameter"; + case EGL_CONSUMER_LATENCY_USEC_KHR: + // Technically not in spec but a latency < 0 makes no sense so we check it + if (value < 0) + { + return EglBadParameter() << "Latency must be positive"; + } + break; + case EGL_CONSUMER_ACQUIRE_TIMEOUT_USEC_KHR: + if (!extensions.streamConsumerGLTexture) + { + return EglBadAttribute() << "Consumer GL extension not enabled"; + } + // Again not in spec but it should be positive anyways + if (value < 0) + { + return EglBadParameter() << "Timeout must be positive"; + } + break; + default: + return EglBadAttribute() << "Invalid stream attribute"; + } + return NoError(); +} + +Error ValidateCreateImageKHRMipLevelCommon(gl::Context *context, + const gl::Texture *texture, + EGLAttrib level) +{ + // Note that the spec EGL_KHR_create_image spec does not explicitly specify an error + // when the level is outside the base/max level range, but it does mention that the + // level "must be a part of the complete texture object ". It can be argued + // that out-of-range levels are not a part of the complete texture. + const GLuint effectiveBaseLevel = texture->getTextureState().getEffectiveBaseLevel(); + if (level > 0 && + (!texture->isMipmapComplete() || static_cast(level) < effectiveBaseLevel || + static_cast(level) > texture->getTextureState().getMipmapMaxLevel())) + { + return EglBadParameter() << "texture must be complete if level is non-zero."; + } + + if (level == 0 && !texture->isMipmapComplete() && + TextureHasNonZeroMipLevelsSpecified(context, texture)) + { + return EglBadParameter() << "if level is zero and the texture is incomplete, it must " + "have no mip levels specified except zero."; + } + + return NoError(); } -namespace egl +Error ValidateConfigAttribute(const Display *display, EGLAttrib attribute) +{ + switch (attribute) + { + case EGL_BUFFER_SIZE: + case EGL_ALPHA_SIZE: + case EGL_BLUE_SIZE: + case EGL_GREEN_SIZE: + case EGL_RED_SIZE: + case EGL_DEPTH_SIZE: + case EGL_STENCIL_SIZE: + case EGL_CONFIG_CAVEAT: + case EGL_CONFIG_ID: + case EGL_LEVEL: + case EGL_NATIVE_RENDERABLE: + case EGL_NATIVE_VISUAL_ID: + case EGL_NATIVE_VISUAL_TYPE: + case EGL_SAMPLES: + case EGL_SAMPLE_BUFFERS: + case EGL_SURFACE_TYPE: + case EGL_TRANSPARENT_TYPE: + case EGL_TRANSPARENT_BLUE_VALUE: + case EGL_TRANSPARENT_GREEN_VALUE: + case EGL_TRANSPARENT_RED_VALUE: + case EGL_BIND_TO_TEXTURE_RGB: + case EGL_BIND_TO_TEXTURE_RGBA: + case EGL_MIN_SWAP_INTERVAL: + case EGL_MAX_SWAP_INTERVAL: + case EGL_LUMINANCE_SIZE: + case EGL_ALPHA_MASK_SIZE: + case EGL_COLOR_BUFFER_TYPE: + case EGL_RENDERABLE_TYPE: + case EGL_MATCH_NATIVE_PIXMAP: + case EGL_CONFORMANT: + case EGL_MAX_PBUFFER_WIDTH: + case EGL_MAX_PBUFFER_HEIGHT: + case EGL_MAX_PBUFFER_PIXELS: + break; + + case EGL_OPTIMAL_SURFACE_ORIENTATION_ANGLE: + if (!display->getExtensions().surfaceOrientation) + { + return EglBadAttribute() << "EGL_ANGLE_surface_orientation is not enabled."; + } + break; + + case EGL_COLOR_COMPONENT_TYPE_EXT: + if (!display->getExtensions().pixelFormatFloat) + { + return EglBadAttribute() << "EGL_EXT_pixel_format_float is not enabled."; + } + break; + + default: + return EglBadAttribute() << "Unknown attribute."; + } + + return NoError(); +} + +Error ValidateConfigAttributes(const Display *display, const AttributeMap &attributes) +{ + for (const auto &attrib : attributes) + { + ANGLE_TRY(ValidateConfigAttribute(display, attrib.first)); + } + + return NoError(); +} + +Error ValidatePlatformType(const ClientExtensions &clientExtensions, EGLAttrib platformType) +{ + switch (platformType) + { + case EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE: + break; + + case EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE: + case EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE: + if (!clientExtensions.platformANGLED3D) + { + return EglBadAttribute() << "Direct3D platform is unsupported."; + } + break; + + case EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE: + case EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE: + if (!clientExtensions.platformANGLEOpenGL) + { + return EglBadAttribute() << "OpenGL platform is unsupported."; + } + break; + + case EGL_PLATFORM_ANGLE_TYPE_NULL_ANGLE: + if (!clientExtensions.platformANGLENULL) + { + return EglBadAttribute() << "Display type EGL_PLATFORM_ANGLE_TYPE_NULL_ANGLE " + "requires EGL_ANGLE_platform_angle_null."; + } + break; + + case EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE: + if (!clientExtensions.platformANGLEVulkan) + { + return EglBadAttribute() << "Vulkan platform is unsupported."; + } + break; + + default: + return EglBadAttribute() << "Unknown platform type."; + } + + return NoError(); +} + +Error ValidateGetPlatformDisplayCommon(EGLenum platform, + void *native_display, + const AttributeMap &attribMap) { + const ClientExtensions &clientExtensions = Display::GetClientExtensions(); + + switch (platform) + { + case EGL_PLATFORM_ANGLE_ANGLE: + if (!clientExtensions.platformANGLE) + { + return EglBadParameter() << "Platform ANGLE extension is not active"; + } + break; + case EGL_PLATFORM_DEVICE_EXT: + if (!clientExtensions.platformDevice) + { + return EglBadParameter() << "Platform Device extension is not active"; + } + break; + default: + return EglBadConfig() << "Bad platform type."; + } + + if (platform == EGL_PLATFORM_ANGLE_ANGLE) + { + EGLAttrib platformType = EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE; + EGLAttrib deviceType = EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE; + bool enableAutoTrimSpecified = false; + bool deviceTypeSpecified = false; + bool presentPathSpecified = false; + + Optional majorVersion; + Optional minorVersion; + + for (const auto &curAttrib : attribMap) + { + const EGLAttrib value = curAttrib.second; + + switch (curAttrib.first) + { + case EGL_PLATFORM_ANGLE_TYPE_ANGLE: + { + ANGLE_TRY(ValidatePlatformType(clientExtensions, value)); + platformType = value; + break; + } + + case EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE: + if (value != EGL_DONT_CARE) + { + majorVersion = value; + } + break; + + case EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE: + if (value != EGL_DONT_CARE) + { + minorVersion = value; + } + break; + + case EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE: + switch (value) + { + case EGL_TRUE: + case EGL_FALSE: + break; + default: + return EglBadAttribute() << "Invalid automatic trim attribute"; + } + enableAutoTrimSpecified = true; + break; + + case EGL_EXPERIMENTAL_PRESENT_PATH_ANGLE: + if (!clientExtensions.experimentalPresentPath) + { + return EglBadAttribute() + << "EGL_ANGLE_experimental_present_path extension not active"; + } + + switch (value) + { + case EGL_EXPERIMENTAL_PRESENT_PATH_FAST_ANGLE: + case EGL_EXPERIMENTAL_PRESENT_PATH_COPY_ANGLE: + break; + default: + return EglBadAttribute() + << "Invalid value for EGL_EXPERIMENTAL_PRESENT_PATH_ANGLE"; + } + presentPathSpecified = true; + break; + + case EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE: + switch (value) + { + case EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE: + case EGL_PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE: + case EGL_PLATFORM_ANGLE_DEVICE_TYPE_REFERENCE_ANGLE: + deviceTypeSpecified = true; + break; + + case EGL_PLATFORM_ANGLE_DEVICE_TYPE_NULL_ANGLE: + // This is a hidden option, accepted by the OpenGL back-end. + break; + + default: + return EglBadAttribute() << "Invalid value for " + "EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE " + "attrib"; + } + deviceType = value; + break; + + case EGL_PLATFORM_ANGLE_DEBUG_LAYERS_ENABLED_ANGLE: + if (!clientExtensions.platformANGLE) + { + return EglBadAttribute() << "EGL_ANGLE_platform_angle extension not active"; + } + if (value != EGL_TRUE && value != EGL_FALSE && value != EGL_DONT_CARE) + { + return EglBadAttribute() << "EGL_PLATFORM_ANGLE_DEBUG_LAYERS_ENABLED_ANGLE " + "must be EGL_TRUE, EGL_FALSE, or " + "EGL_DONT_CARE."; + } + break; + + default: + break; + } + } + + if (!majorVersion.valid() && minorVersion.valid()) + { + return EglBadAttribute() + << "Must specify major version if you specify a minor version."; + } + + if (deviceType == EGL_PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE && + platformType != EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE) + { + return EglBadAttribute() << "EGL_PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE requires a " + "device type of EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE."; + } + + if (enableAutoTrimSpecified && platformType != EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE) + { + return EglBadAttribute() << "EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE " + "requires a device type of " + "EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE."; + } + + if (presentPathSpecified && platformType != EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE) + { + return EglBadAttribute() << "EGL_EXPERIMENTAL_PRESENT_PATH_ANGLE requires a " + "device type of EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE."; + } + + if (deviceTypeSpecified && platformType != EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE && + platformType != EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE) + { + return EglBadAttribute() << "EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE requires a " + "device type of EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE or " + "EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE."; + } + + if (platformType == EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE) + { + if ((majorVersion.valid() && majorVersion.value() != 1) || + (minorVersion.valid() && minorVersion.value() != 0)) + { + return EglBadAttribute() << "EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE currently " + "only supports Vulkan 1.0."; + } + } + } + else if (platform == EGL_PLATFORM_DEVICE_EXT) + { + Device *eglDevice = reinterpret_cast(native_display); + if (eglDevice == nullptr || !Device::IsValidDevice(eglDevice)) + { + return EglBadAttribute() << "native_display should be a valid EGL device if " + "platform equals EGL_PLATFORM_DEVICE_EXT"; + } + } + else + { + UNREACHABLE(); + } + + return NoError(); +} + +} // namespace Error ValidateDisplay(const Display *display) { if (display == EGL_NO_DISPLAY) { - return Error(EGL_BAD_DISPLAY, "display is EGL_NO_DISPLAY."); + return EglBadDisplay() << "display is EGL_NO_DISPLAY."; } if (!Display::isValidDisplay(display)) { - return Error(EGL_BAD_DISPLAY, "display is not a valid display."); + return EglBadDisplay() << "display is not a valid display."; } if (!display->isInitialized()) { - return Error(EGL_NOT_INITIALIZED, "display is not initialized."); + return EglNotInitialized() << "display is not initialized."; } - return Error(EGL_SUCCESS); + if (display->isDeviceLost()) + { + return EglContextLost() << "display had a context loss"; + } + + return NoError(); } -Error ValidateSurface(const Display *display, Surface *surface) +Error ValidateSurface(const Display *display, const Surface *surface) { - Error error = ValidateDisplay(display); - if (error.isError()) - { - return error; - } + ANGLE_TRY(ValidateDisplay(display)); if (!display->isValidSurface(surface)) { - return Error(EGL_BAD_SURFACE); + return EglBadSurface(); } - return Error(EGL_SUCCESS); + return NoError(); } Error ValidateConfig(const Display *display, const Config *config) { - Error error = ValidateDisplay(display); - if (error.isError()) - { - return error; - } + ANGLE_TRY(ValidateDisplay(display)); if (!display->isValidConfig(config)) { - return Error(EGL_BAD_CONFIG); + return EglBadConfig(); } - return Error(EGL_SUCCESS); + return NoError(); } -Error ValidateContext(const Display *display, gl::Context *context) +Error ValidateContext(const Display *display, const gl::Context *context) { - Error error = ValidateDisplay(display); - if (error.isError()) - { - return error; - } + ANGLE_TRY(ValidateDisplay(display)); if (!display->isValidContext(context)) { - return Error(EGL_BAD_CONTEXT); + return EglBadContext(); } - return Error(EGL_SUCCESS); + return NoError(); } Error ValidateImage(const Display *display, const Image *image) { - Error error = ValidateDisplay(display); - if (error.isError()) + ANGLE_TRY(ValidateDisplay(display)); + + if (!display->isValidImage(image)) { - return error; + return EglBadParameter() << "image is not valid."; } - if (!display->isValidImage(image)) + return NoError(); +} + +Error ValidateStream(const Display *display, const Stream *stream) +{ + ANGLE_TRY(ValidateDisplay(display)); + + const DisplayExtensions &displayExtensions = display->getExtensions(); + if (!displayExtensions.stream) + { + return EglBadAccess() << "Stream extension not active"; + } + + if (stream == EGL_NO_STREAM_KHR || !display->isValidStream(stream)) { - return Error(EGL_BAD_PARAMETER, "image is not valid."); + return EglBadStream() << "Invalid stream"; } - return Error(EGL_SUCCESS); + return NoError(); } Error ValidateCreateContext(Display *display, Config *configuration, gl::Context *shareContext, const AttributeMap& attributes) { - Error error = ValidateConfig(display, configuration); - if (error.isError()) - { - return error; - } + ANGLE_TRY(ValidateConfig(display, configuration)); // Get the requested client version (default is 1) and check it is 2 or 3. - EGLint clientMajorVersion = 1; - EGLint clientMinorVersion = 0; - EGLint contextFlags = 0; + EGLAttrib clientMajorVersion = 1; + EGLAttrib clientMinorVersion = 0; + EGLAttrib 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; + EGLAttrib attribute = attributeIter->first; + EGLAttrib value = attributeIter->second; switch (attribute) { @@ -215,28 +591,27 @@ Error ValidateCreateContext(Display *display, Config *configuration, gl::Context case EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR: // Only valid for OpenGL (non-ES) contexts - return Error(EGL_BAD_ATTRIBUTE); + return EglBadAttribute(); case EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT: if (!display->getExtensions().createContextRobustness) { - return Error(EGL_BAD_ATTRIBUTE); + return EglBadAttribute(); } if (value != EGL_TRUE && value != EGL_FALSE) { - return Error(EGL_BAD_ATTRIBUTE); + return EglBadAttribute(); } - 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 + return EglBadAttribute() << "EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR is not" + << " valid for GLES with EGL 1.4 and KHR_create_context. Use" + << " EXT_create_context_robustness."; case EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT: if (!display->getExtensions().createContextRobustness) { - return Error(EGL_BAD_ATTRIBUTE); + return EglBadAttribute(); } if (value == EGL_LOSE_CONTEXT_ON_RESET_EXT) { @@ -244,34 +619,143 @@ Error ValidateCreateContext(Display *display, Config *configuration, gl::Context } else if (value != EGL_NO_RESET_NOTIFICATION_EXT) { - return Error(EGL_BAD_ATTRIBUTE); + return EglBadAttribute(); } break; case EGL_CONTEXT_OPENGL_NO_ERROR_KHR: if (!display->getExtensions().createContextNoError) { - return Error(EGL_BAD_ATTRIBUTE, "Invalid Context attribute."); + return EglBadAttribute() << "Invalid Context attribute."; + } + if (value != EGL_TRUE && value != EGL_FALSE) + { + return EglBadAttribute() << "Attribute must be EGL_TRUE or EGL_FALSE."; + } + break; + + case EGL_CONTEXT_WEBGL_COMPATIBILITY_ANGLE: + if (!display->getExtensions().createContextWebGLCompatibility) + { + return EglBadAttribute() << "Attribute " + "EGL_CONTEXT_WEBGL_COMPATIBILITY_ANGLE requires " + "EGL_ANGLE_create_context_webgl_compatibility."; + } + if (value != EGL_TRUE && value != EGL_FALSE) + { + return EglBadAttribute() + << "EGL_CONTEXT_WEBGL_COMPATIBILITY_ANGLE must be EGL_TRUE or EGL_FALSE."; + } + break; + + case EGL_CONTEXT_BIND_GENERATES_RESOURCE_CHROMIUM: + if (!display->getExtensions().createContextBindGeneratesResource) + { + return EglBadAttribute() + << "Attribute EGL_CONTEXT_BIND_GENERATES_RESOURCE_CHROMIUM requires " + "EGL_CHROMIUM_create_context_bind_generates_resource."; + } + if (value != EGL_TRUE && value != EGL_FALSE) + { + return EglBadAttribute() << "EGL_CONTEXT_BIND_GENERATES_RESOURCE_CHROMIUM " + "must be EGL_TRUE or EGL_FALSE."; + } + break; + + case EGL_DISPLAY_TEXTURE_SHARE_GROUP_ANGLE: + if (!display->getExtensions().displayTextureShareGroup) + { + return EglBadAttribute() << "Attribute " + "EGL_DISPLAY_TEXTURE_SHARE_GROUP_ANGLE requires " + "EGL_ANGLE_display_texture_share_group."; + } + if (value != EGL_TRUE && value != EGL_FALSE) + { + return EglBadAttribute() + << "EGL_DISPLAY_TEXTURE_SHARE_GROUP_ANGLE must be EGL_TRUE or EGL_FALSE."; + } + if (shareContext && + (shareContext->usingDisplayTextureShareGroup() != (value == EGL_TRUE))) + { + return EglBadAttribute() << "All contexts within a share group must be " + "created with the same value of " + "EGL_DISPLAY_TEXTURE_SHARE_GROUP_ANGLE."; + } + break; + + case EGL_CONTEXT_CLIENT_ARRAYS_ENABLED_ANGLE: + if (!display->getExtensions().createContextClientArrays) + { + return EglBadAttribute() + << "Attribute EGL_CONTEXT_CLIENT_ARRAYS_ENABLED_ANGLE requires " + "EGL_ANGLE_create_context_client_arrays."; + } + if (value != EGL_TRUE && value != EGL_FALSE) + { + return EglBadAttribute() << "EGL_CONTEXT_CLIENT_ARRAYS_ENABLED_ANGLE must " + "be EGL_TRUE or EGL_FALSE."; + } + break; + + case EGL_CONTEXT_PROGRAM_BINARY_CACHE_ENABLED_ANGLE: + if (!display->getExtensions().programCacheControl) + { + return EglBadAttribute() + << "Attribute EGL_CONTEXT_PROGRAM_BINARY_CACHE_ENABLED_ANGLE " + "requires EGL_ANGLE_program_cache_control."; + } + if (value != EGL_TRUE && value != EGL_FALSE) + { + return EglBadAttribute() << "EGL_CONTEXT_PROGRAM_BINARY_CACHE_ENABLED_ANGLE must " + "be EGL_TRUE or EGL_FALSE."; + } + break; + + case EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE: + if (!display->getExtensions().robustResourceInitialization) + { + return EglBadAttribute() << "Attribute EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE " + "requires EGL_ANGLE_robust_resource_initialization."; } if (value != EGL_TRUE && value != EGL_FALSE) { - return Error(EGL_BAD_ATTRIBUTE, "Attribute must be EGL_TRUE or EGL_FALSE."); + return EglBadAttribute() << "EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE must be " + "either EGL_TRUE or EGL_FALSE."; } break; default: - return Error(EGL_BAD_ATTRIBUTE); + return EglBadAttribute() << "Unknown attribute."; } } - if ((clientMajorVersion != 2 && clientMajorVersion != 3) || clientMinorVersion != 0) + switch (clientMajorVersion) { - 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); + case 2: + if (clientMinorVersion != 0) + { + return EglBadConfig(); + } + break; + case 3: + if (clientMinorVersion != 0 && clientMinorVersion != 1) + { + return EglBadConfig(); + } + if (!(configuration->conformant & EGL_OPENGL_ES3_BIT_KHR)) + { + return EglBadConfig(); + } + if (display->getMaxSupportedESVersion() < + gl::Version(static_cast(clientMajorVersion), + static_cast(clientMinorVersion))) + { + return EglBadConfig() << "Requested GLES version is not supported."; + } + break; + default: + return EglBadConfig(); + break; } // Note: EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR does not apply to ES @@ -279,18 +763,7 @@ Error ValidateCreateContext(Display *display, Config *configuration, gl::Context 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); + return EglBadAttribute(); } if (shareContext) @@ -298,43 +771,40 @@ Error ValidateCreateContext(Display *display, Config *configuration, gl::Context // Shared context is invalid or is owned by another display if (!display->isValidContext(shareContext)) { - return Error(EGL_BAD_MATCH); + return EglBadMatch(); } if (shareContext->isResetNotificationEnabled() != resetNotification) { - return Error(EGL_BAD_MATCH); + return EglBadMatch(); } - if (shareContext->getClientVersion() != clientMajorVersion) + if (shareContext->getClientMajorVersion() != clientMajorVersion || + shareContext->getClientMinorVersion() != clientMinorVersion) { - return Error(EGL_BAD_CONTEXT); + return EglBadContext(); } } - return Error(EGL_SUCCESS); + return NoError(); } Error ValidateCreateWindowSurface(Display *display, Config *config, EGLNativeWindowType window, const AttributeMap& attributes) { - Error error = ValidateConfig(display, config); - if (error.isError()) - { - return error; - } + ANGLE_TRY(ValidateConfig(display, config)); if (!display->isValidNativeWindow(window)) { - return Error(EGL_BAD_NATIVE_WINDOW); + return EglBadNativeWindow(); } const DisplayExtensions &displayExtensions = display->getExtensions(); for (AttributeMap::const_iterator attributeIter = attributes.begin(); attributeIter != attributes.end(); attributeIter++) { - EGLint attribute = attributeIter->first; - EGLint value = attributeIter->second; + EGLAttrib attribute = attributeIter->first; + EGLAttrib value = attributeIter->second; switch (attribute) { @@ -344,23 +814,23 @@ Error ValidateCreateWindowSurface(Display *display, Config *config, EGLNativeWin case EGL_BACK_BUFFER: break; case EGL_SINGLE_BUFFER: - return Error(EGL_BAD_MATCH); // Rendering directly to front buffer not supported + return EglBadMatch(); // Rendering directly to front buffer not supported default: - return Error(EGL_BAD_ATTRIBUTE); + return EglBadAttribute(); } break; case EGL_POST_SUB_BUFFER_SUPPORTED_NV: if (!displayExtensions.postSubBuffer) { - return Error(EGL_BAD_ATTRIBUTE); + return EglBadAttribute(); } break; case EGL_FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE: if (!displayExtensions.flexibleSurfaceCompatibility) { - return Error(EGL_BAD_ATTRIBUTE); + return EglBadAttribute(); } break; @@ -368,68 +838,77 @@ Error ValidateCreateWindowSurface(Display *display, Config *config, EGLNativeWin case EGL_HEIGHT: if (!displayExtensions.windowFixedSize) { - return Error(EGL_BAD_ATTRIBUTE); + return EglBadAttribute(); } if (value < 0) { - return Error(EGL_BAD_PARAMETER); + return EglBadParameter(); } break; case EGL_FIXED_SIZE_ANGLE: if (!displayExtensions.windowFixedSize) { - return Error(EGL_BAD_ATTRIBUTE); + return EglBadAttribute(); } break; case EGL_SURFACE_ORIENTATION_ANGLE: if (!displayExtensions.surfaceOrientation) { - return Error(EGL_BAD_ATTRIBUTE, "EGL_ANGLE_surface_orientation is not enabled."); + return EglBadAttribute() << "EGL_ANGLE_surface_orientation is not enabled."; } break; case EGL_VG_COLORSPACE: - return Error(EGL_BAD_MATCH); + return EglBadMatch(); case EGL_VG_ALPHA_FORMAT: - return Error(EGL_BAD_MATCH); + return EglBadMatch(); case EGL_DIRECT_COMPOSITION_ANGLE: if (!displayExtensions.directComposition) { - return Error(EGL_BAD_ATTRIBUTE); + return EglBadAttribute(); + } + break; + + case EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE: + if (!display->getExtensions().robustResourceInitialization) + { + return EglBadAttribute() << "Attribute EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE " + "requires EGL_ANGLE_robust_resource_initialization."; + } + if (value != EGL_TRUE && value != EGL_FALSE) + { + return EglBadAttribute() << "EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE must be " + "either EGL_TRUE or EGL_FALSE."; } break; default: - return Error(EGL_BAD_ATTRIBUTE); + return EglBadAttribute(); } } if (Display::hasExistingWindowSurface(window)) { - return Error(EGL_BAD_ALLOC); + return EglBadAlloc(); } - return Error(EGL_SUCCESS); + return NoError(); } Error ValidateCreatePbufferSurface(Display *display, Config *config, const AttributeMap& attributes) { - Error error = ValidateConfig(display, config); - if (error.isError()) - { - return error; - } + ANGLE_TRY(ValidateConfig(display, config)); const DisplayExtensions &displayExtensions = display->getExtensions(); for (AttributeMap::const_iterator attributeIter = attributes.begin(); attributeIter != attributes.end(); attributeIter++) { - EGLint attribute = attributeIter->first; - EGLint value = attributeIter->second; + EGLAttrib attribute = attributeIter->first; + EGLAttrib value = attributeIter->second; switch (attribute) { @@ -437,7 +916,7 @@ Error ValidateCreatePbufferSurface(Display *display, Config *config, const Attri case EGL_HEIGHT: if (value < 0) { - return Error(EGL_BAD_PARAMETER); + return EglBadParameter(); } break; @@ -452,7 +931,7 @@ Error ValidateCreatePbufferSurface(Display *display, Config *config, const Attri case EGL_TEXTURE_RGBA: break; default: - return Error(EGL_BAD_ATTRIBUTE); + return EglBadAttribute(); } break; @@ -463,7 +942,7 @@ Error ValidateCreatePbufferSurface(Display *display, Config *config, const Attri case EGL_TEXTURE_2D: break; default: - return Error(EGL_BAD_ATTRIBUTE); + return EglBadAttribute(); } break; @@ -479,60 +958,66 @@ Error ValidateCreatePbufferSurface(Display *display, Config *config, const Attri case EGL_FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE: if (!displayExtensions.flexibleSurfaceCompatibility) { - return Error( - EGL_BAD_ATTRIBUTE, - "EGL_FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE cannot be used without " - "EGL_ANGLE_flexible_surface_compatibility support."); + return EglBadAttribute() + << "EGL_FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE cannot be used " + "without EGL_ANGLE_flexible_surface_compatibility support."; + } + break; + + case EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE: + if (!display->getExtensions().robustResourceInitialization) + { + return EglBadAttribute() << "Attribute EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE " + "requires EGL_ANGLE_robust_resource_initialization."; + } + if (value != EGL_TRUE && value != EGL_FALSE) + { + return EglBadAttribute() << "EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE must be " + "either EGL_TRUE or EGL_FALSE."; } break; default: - return Error(EGL_BAD_ATTRIBUTE); + return EglBadAttribute(); } } if (!(config->surfaceType & EGL_PBUFFER_BIT)) { - return Error(EGL_BAD_MATCH); + return EglBadMatch(); } -#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(); - EGLenum textureFormat = attributes.get(EGL_TEXTURE_FORMAT, EGL_NO_TEXTURE); - EGLenum textureTarget = attributes.get(EGL_TEXTURE_TARGET, EGL_NO_TEXTURE); + EGLAttrib textureFormat = attributes.get(EGL_TEXTURE_FORMAT, EGL_NO_TEXTURE); + EGLAttrib 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); + return EglBadMatch(); } if ((textureFormat == EGL_TEXTURE_RGB && config->bindToTextureRGB != EGL_TRUE) || (textureFormat == EGL_TEXTURE_RGBA && config->bindToTextureRGBA != EGL_TRUE)) { - return Error(EGL_BAD_ATTRIBUTE); + return EglBadAttribute(); } - EGLint width = attributes.get(EGL_WIDTH, 0); - EGLint height = attributes.get(EGL_HEIGHT, 0); + EGLint width = static_cast(attributes.get(EGL_WIDTH, 0)); + EGLint height = static_cast(attributes.get(EGL_HEIGHT, 0)); if (textureFormat != EGL_NO_TEXTURE && !caps.textureNPOT && (!gl::isPow2(width) || !gl::isPow2(height))) { - return Error(EGL_BAD_MATCH); + return EglBadMatch(); } -#endif - return Error(EGL_SUCCESS); + return NoError(); } Error ValidateCreatePbufferFromClientBuffer(Display *display, EGLenum buftype, EGLClientBuffer buffer, Config *config, const AttributeMap& attributes) { - Error error = ValidateConfig(display, config); - if (error.isError()) - { - return error; - } + ANGLE_TRY(ValidateConfig(display, config)); const DisplayExtensions &displayExtensions = display->getExtensions(); @@ -541,22 +1026,33 @@ Error ValidateCreatePbufferFromClientBuffer(Display *display, EGLenum buftype, E case EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE: if (!displayExtensions.d3dShareHandleClientBuffer) { - return Error(EGL_BAD_PARAMETER); + return EglBadParameter(); } if (buffer == nullptr) { - return Error(EGL_BAD_PARAMETER); + return EglBadParameter(); } break; + case EGL_D3D_TEXTURE_ANGLE: + if (!displayExtensions.d3dTextureClientBuffer) + { + return EglBadParameter(); + } + if (buffer == nullptr) + { + return EglBadParameter(); + } + break; + default: - return Error(EGL_BAD_PARAMETER); + return EglBadParameter(); } for (AttributeMap::const_iterator attributeIter = attributes.begin(); attributeIter != attributes.end(); attributeIter++) { - EGLint attribute = attributeIter->first; - EGLint value = attributeIter->second; + EGLAttrib attribute = attributeIter->first; + EGLAttrib value = attributeIter->second; switch (attribute) { @@ -564,11 +1060,11 @@ Error ValidateCreatePbufferFromClientBuffer(Display *display, EGLenum buftype, E case EGL_HEIGHT: if (!displayExtensions.d3dShareHandleClientBuffer) { - return Error(EGL_BAD_PARAMETER); + return EglBadParameter(); } if (value < 0) { - return Error(EGL_BAD_PARAMETER); + return EglBadParameter(); } break; @@ -580,7 +1076,7 @@ Error ValidateCreatePbufferFromClientBuffer(Display *display, EGLenum buftype, E case EGL_TEXTURE_RGBA: break; default: - return Error(EGL_BAD_ATTRIBUTE); + return EglBadAttribute(); } break; @@ -591,7 +1087,7 @@ Error ValidateCreatePbufferFromClientBuffer(Display *display, EGLenum buftype, E case EGL_TEXTURE_2D: break; default: - return Error(EGL_BAD_ATTRIBUTE); + return EglBadAttribute(); } break; @@ -601,63 +1097,148 @@ Error ValidateCreatePbufferFromClientBuffer(Display *display, EGLenum buftype, E case EGL_FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE: if (!displayExtensions.flexibleSurfaceCompatibility) { - return Error( - EGL_BAD_ATTRIBUTE, - "EGL_FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE cannot be used without " - "EGL_ANGLE_flexible_surface_compatibility support."); + return EglBadAttribute() + << "EGL_FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE cannot be used " + "without EGL_ANGLE_flexible_surface_compatibility support."; } break; default: - return Error(EGL_BAD_ATTRIBUTE); + return EglBadAttribute(); } } if (!(config->surfaceType & EGL_PBUFFER_BIT)) { - return Error(EGL_BAD_MATCH); + return EglBadMatch(); } - EGLenum textureFormat = attributes.get(EGL_TEXTURE_FORMAT, EGL_NO_TEXTURE); - EGLenum textureTarget = attributes.get(EGL_TEXTURE_TARGET, EGL_NO_TEXTURE); + EGLAttrib textureFormat = attributes.get(EGL_TEXTURE_FORMAT, EGL_NO_TEXTURE); + EGLAttrib 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); + return EglBadMatch(); } if ((textureFormat == EGL_TEXTURE_RGB && config->bindToTextureRGB != EGL_TRUE) || (textureFormat == EGL_TEXTURE_RGBA && config->bindToTextureRGBA != EGL_TRUE)) { - return Error(EGL_BAD_ATTRIBUTE); + return EglBadAttribute(); } if (buftype == EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE) { - EGLint width = attributes.get(EGL_WIDTH, 0); - EGLint height = attributes.get(EGL_HEIGHT, 0); + EGLint width = static_cast(attributes.get(EGL_WIDTH, 0)); + EGLint height = static_cast(attributes.get(EGL_HEIGHT, 0)); if (width == 0 || height == 0) { - return Error(EGL_BAD_ATTRIBUTE); + return EglBadAttribute(); } -// On Windows Store, we know the originating texture came from D3D11, so bypass this check -#if !defined(ANGLE_ENABLE_WINDOWS_STORE) const Caps &caps = display->getCaps(); if (textureFormat != EGL_NO_TEXTURE && !caps.textureNPOT && (!gl::isPow2(width) || !gl::isPow2(height))) { - return Error(EGL_BAD_MATCH); + return EglBadMatch(); } -#endif } - return Error(EGL_SUCCESS); + ANGLE_TRY(display->validateClientBuffer(config, buftype, buffer, attributes)); + + return NoError(); } -Error ValidateCompatibleConfigs(const Display *display, - const Config *config1, - const Surface *surface, +Error ValidateMakeCurrent(Display *display, EGLSurface draw, EGLSurface read, gl::Context *context) +{ + if (context == EGL_NO_CONTEXT && (draw != EGL_NO_SURFACE || read != EGL_NO_SURFACE)) + { + return EglBadMatch() << "If ctx is EGL_NO_CONTEXT, surfaces must be EGL_NO_SURFACE"; + } + + // If ctx is EGL_NO_CONTEXT and either draw or read are not EGL_NO_SURFACE, an EGL_BAD_MATCH + // error is generated. EGL_KHR_surfaceless_context allows both surfaces to be EGL_NO_SURFACE. + if (context != EGL_NO_CONTEXT && (draw == EGL_NO_SURFACE || read == EGL_NO_SURFACE)) + { + if (display->getExtensions().surfacelessContext) + { + if ((draw == EGL_NO_SURFACE) != (read == EGL_NO_SURFACE)) + { + return EglBadMatch() << "If ctx is not EGL_NOT_CONTEXT, draw or read must " + "both be EGL_NO_SURFACE, or both not"; + } + } + else + { + return EglBadMatch() + << "If ctx is not EGL_NO_CONTEXT, surfaces must not be EGL_NO_SURFACE"; + } + } + + // If either of draw or read is a valid surface and the other is EGL_NO_SURFACE, an + // EGL_BAD_MATCH error is generated. + if ((read == EGL_NO_SURFACE) != (draw == EGL_NO_SURFACE)) + { + return EglBadMatch() + << "read and draw must both be valid surfaces, or both be EGL_NO_SURFACE"; + } + + if (display == EGL_NO_DISPLAY || !Display::isValidDisplay(display)) + { + return EglBadDisplay() << "'dpy' not a valid EGLDisplay handle"; + } + + // EGL 1.5 spec: dpy can be uninitialized if all other parameters are null + if (!display->isInitialized() && + (context != EGL_NO_CONTEXT || draw != EGL_NO_SURFACE || read != EGL_NO_SURFACE)) + { + return EglNotInitialized() << "'dpy' not initialized"; + } + + if (context != EGL_NO_CONTEXT) + { + ANGLE_TRY(ValidateContext(display, context)); + } + + if (display->isInitialized() && display->testDeviceLost()) + { + return EglContextLost(); + } + + Surface *drawSurface = static_cast(draw); + if (draw != EGL_NO_SURFACE) + { + ANGLE_TRY(ValidateSurface(display, drawSurface)); + } + + Surface *readSurface = static_cast(read); + if (read != EGL_NO_SURFACE) + { + ANGLE_TRY(ValidateSurface(display, readSurface)); + } + + if (readSurface) + { + ANGLE_TRY(ValidateCompatibleConfigs(display, readSurface->getConfig(), readSurface, + context->getConfig(), readSurface->getType())); + } + + if (draw != read) + { + UNIMPLEMENTED(); // FIXME + + if (drawSurface) + { + ANGLE_TRY(ValidateCompatibleConfigs(display, drawSurface->getConfig(), drawSurface, + context->getConfig(), drawSurface->getType())); + } + } + return NoError(); +} + +Error ValidateCompatibleConfigs(const Display *display, + const Config *config1, + const Surface *surface, const Config *config2, EGLint surfaceType) { @@ -669,7 +1250,7 @@ Error ValidateCompatibleConfigs(const Display *display, bool colorBufferCompat = config1->colorBufferType == config2->colorBufferType; if (!colorBufferCompat) { - return Error(EGL_BAD_MATCH, "Color buffer types are not compatible."); + return EglBadMatch() << "Color buffer types are not compatible."; } bool colorCompat = @@ -678,24 +1259,30 @@ Error ValidateCompatibleConfigs(const Display *display, config1->luminanceSize == config2->luminanceSize; if (!colorCompat) { - return Error(EGL_BAD_MATCH, "Color buffer sizes are not compatible."); + return EglBadMatch() << "Color buffer sizes are not compatible."; + } + + bool componentTypeCompat = config1->colorComponentType == config2->colorComponentType; + if (!componentTypeCompat) + { + return EglBadMatch() << "Color buffer component types are not compatible."; } bool dsCompat = config1->depthSize == config2->depthSize && config1->stencilSize == config2->stencilSize; if (!dsCompat) { - return Error(EGL_BAD_MATCH, "Depth-stencil buffer types are not compatible."); + return EglBadMatch() << "Depth-stencil buffer types are not compatible."; } } bool surfaceTypeCompat = (config1->surfaceType & config2->surfaceType & surfaceType) != 0; if (!surfaceTypeCompat) { - return Error(EGL_BAD_MATCH, "Surface types are not compatible."); + return EglBadMatch() << "Surface types are not compatible."; } - return Error(EGL_SUCCESS); + return NoError(); } Error ValidateCreateImageKHR(const Display *display, @@ -704,11 +1291,7 @@ Error ValidateCreateImageKHR(const Display *display, EGLClientBuffer buffer, const AttributeMap &attributes) { - Error error = ValidateContext(display, context); - if (error.isError()) - { - return error; - } + ANGLE_TRY(ValidateContext(display, context)); const DisplayExtensions &displayExtensions = display->getExtensions(); @@ -717,7 +1300,7 @@ Error ValidateCreateImageKHR(const Display *display, // It is out of spec what happens when calling an extension function when the extension is // not available. // EGL_BAD_DISPLAY seems like a reasonable error. - return Error(EGL_BAD_DISPLAY, "EGL_KHR_image not supported."); + return EglBadDisplay() << "EGL_KHR_image not supported."; } // TODO(geofflang): Complete validation from EGL_KHR_image_base: @@ -727,8 +1310,8 @@ Error ValidateCreateImageKHR(const Display *display, for (AttributeMap::const_iterator attributeIter = attributes.begin(); attributeIter != attributes.end(); attributeIter++) { - EGLint attribute = attributeIter->first; - EGLint value = attributeIter->second; + EGLAttrib attribute = attributeIter->first; + EGLAttrib value = attributeIter->second; switch (attribute) { @@ -740,8 +1323,8 @@ Error ValidateCreateImageKHR(const Display *display, break; default: - return Error(EGL_BAD_PARAMETER, - "EGL_IMAGE_PRESERVED_KHR must be EGL_TRUE or EGL_FALSE."); + return EglBadParameter() + << "EGL_IMAGE_PRESERVED_KHR must be EGL_TRUE or EGL_FALSE."; } break; @@ -749,28 +1332,27 @@ Error ValidateCreateImageKHR(const Display *display, if (!displayExtensions.glTexture2DImage && !displayExtensions.glTextureCubemapImage && !displayExtensions.glTexture3DImage) { - return Error(EGL_BAD_PARAMETER, - "EGL_GL_TEXTURE_LEVEL_KHR cannot be used without " - "KHR_gl_texture_*_image support."); + return EglBadParameter() << "EGL_GL_TEXTURE_LEVEL_KHR cannot be used " + "without KHR_gl_texture_*_image support."; } if (value < 0) { - return Error(EGL_BAD_PARAMETER, "EGL_GL_TEXTURE_LEVEL_KHR cannot be negative."); + return EglBadParameter() << "EGL_GL_TEXTURE_LEVEL_KHR cannot be negative."; } break; case EGL_GL_TEXTURE_ZOFFSET_KHR: if (!displayExtensions.glTexture3DImage) { - return Error(EGL_BAD_PARAMETER, - "EGL_GL_TEXTURE_ZOFFSET_KHR cannot be used without " - "KHR_gl_texture_3D_image support."); + return EglBadParameter() << "EGL_GL_TEXTURE_ZOFFSET_KHR cannot be used " + "without KHR_gl_texture_3D_image support."; } break; default: - return Error(EGL_BAD_PARAMETER, "invalid attribute: 0x%X", attribute); + return EglBadParameter() + << "invalid attribute: 0x" << std::hex << std::uppercase << attribute; } } @@ -780,48 +1362,35 @@ Error ValidateCreateImageKHR(const Display *display, { if (!displayExtensions.glTexture2DImage) { - return Error(EGL_BAD_PARAMETER, "KHR_gl_texture_2D_image not supported."); + return EglBadParameter() << "KHR_gl_texture_2D_image not supported."; } if (buffer == 0) { - return Error(EGL_BAD_PARAMETER, - "buffer cannot reference a 2D texture with the name 0."); + return EglBadParameter() << "buffer cannot reference a 2D texture with the name 0."; } const gl::Texture *texture = context->getTexture(egl_gl::EGLClientBufferToGLObjectHandle(buffer)); if (texture == nullptr || texture->getTarget() != GL_TEXTURE_2D) { - return Error(EGL_BAD_PARAMETER, "target is not a 2D texture."); + return EglBadParameter() << "target is not a 2D texture."; } if (texture->getBoundSurface() != nullptr) { - return Error(EGL_BAD_ACCESS, "texture has a surface bound to it."); + return EglBadAccess() << "texture has a surface bound to it."; } - EGLint level = attributes.get(EGL_GL_TEXTURE_LEVEL_KHR, 0); + EGLAttrib level = attributes.get(EGL_GL_TEXTURE_LEVEL_KHR, 0); if (texture->getWidth(GL_TEXTURE_2D, static_cast(level)) == 0 || texture->getHeight(GL_TEXTURE_2D, static_cast(level)) == 0) { - return Error(EGL_BAD_PARAMETER, - "target 2D texture does not have a valid size at specified level."); - } - - if (level > 0 && (!texture->isMipmapComplete() || - static_cast(level) >= texture->getMipCompleteLevels())) - { - return Error(EGL_BAD_PARAMETER, "texture must be complete if level is non-zero."); + return EglBadParameter() + << "target 2D texture does not have a valid size at specified level."; } - if (level == 0 && !texture->isMipmapComplete() && - TextureHasNonZeroMipLevelsSpecified(context, texture)) - { - return Error(EGL_BAD_PARAMETER, - "if level is zero and the texture is incomplete, it must have no mip " - "levels specified except zero."); - } + ANGLE_TRY(ValidateCreateImageKHRMipLevelCommon(context, texture, level)); } break; @@ -834,57 +1403,44 @@ Error ValidateCreateImageKHR(const Display *display, { if (!displayExtensions.glTextureCubemapImage) { - return Error(EGL_BAD_PARAMETER, "KHR_gl_texture_cubemap_image not supported."); + return EglBadParameter() << "KHR_gl_texture_cubemap_image not supported."; } if (buffer == 0) { - return Error(EGL_BAD_PARAMETER, - "buffer cannot reference a cubemap texture with the name 0."); + return EglBadParameter() + << "buffer cannot reference a cubemap texture with the name 0."; } const gl::Texture *texture = context->getTexture(egl_gl::EGLClientBufferToGLObjectHandle(buffer)); if (texture == nullptr || texture->getTarget() != GL_TEXTURE_CUBE_MAP) { - return Error(EGL_BAD_PARAMETER, "target is not a cubemap texture."); + return EglBadParameter() << "target is not a cubemap texture."; } if (texture->getBoundSurface() != nullptr) { - return Error(EGL_BAD_ACCESS, "texture has a surface bound to it."); + return EglBadAccess() << "texture has a surface bound to it."; } - EGLint level = attributes.get(EGL_GL_TEXTURE_LEVEL_KHR, 0); + EGLAttrib level = attributes.get(EGL_GL_TEXTURE_LEVEL_KHR, 0); GLenum cubeMapFace = egl_gl::EGLCubeMapTargetToGLCubeMapTarget(target); if (texture->getWidth(cubeMapFace, static_cast(level)) == 0 || texture->getHeight(cubeMapFace, static_cast(level)) == 0) { - return Error(EGL_BAD_PARAMETER, - "target cubemap texture does not have a valid size at specified level " - "and face."); - } - - if (level > 0 && (!texture->isMipmapComplete() || - static_cast(level) >= texture->getMipCompleteLevels())) - { - return Error(EGL_BAD_PARAMETER, "texture must be complete if level is non-zero."); + return EglBadParameter() << "target cubemap texture does not have a valid " + "size at specified level and face."; } - if (level == 0 && !texture->isMipmapComplete() && - TextureHasNonZeroMipLevelsSpecified(context, texture)) - { - return Error(EGL_BAD_PARAMETER, - "if level is zero and the texture is incomplete, it must have no mip " - "levels specified except zero."); - } + ANGLE_TRY(ValidateCreateImageKHRMipLevelCommon(context, texture, level)); if (level == 0 && !texture->isMipmapComplete() && CubeTextureHasUnspecifiedLevel0Face(texture)) { - return Error(EGL_BAD_PARAMETER, - "if level is zero and the texture is incomplete, it must have all of " - "its faces specified at level zero."); + return EglBadParameter() << "if level is zero and the texture is incomplete, " + "it must have all of its faces specified at level " + "zero."; } } break; @@ -893,58 +1449,45 @@ Error ValidateCreateImageKHR(const Display *display, { if (!displayExtensions.glTexture3DImage) { - return Error(EGL_BAD_PARAMETER, "KHR_gl_texture_3D_image not supported."); + return EglBadParameter() << "KHR_gl_texture_3D_image not supported."; } if (buffer == 0) { - return Error(EGL_BAD_PARAMETER, - "buffer cannot reference a 3D texture with the name 0."); + return EglBadParameter() << "buffer cannot reference a 3D texture with the name 0."; } const gl::Texture *texture = context->getTexture(egl_gl::EGLClientBufferToGLObjectHandle(buffer)); if (texture == nullptr || texture->getTarget() != GL_TEXTURE_3D) { - return Error(EGL_BAD_PARAMETER, "target is not a 3D texture."); + return EglBadParameter() << "target is not a 3D texture."; } if (texture->getBoundSurface() != nullptr) { - return Error(EGL_BAD_ACCESS, "texture has a surface bound to it."); + return EglBadAccess() << "texture has a surface bound to it."; } - EGLint level = attributes.get(EGL_GL_TEXTURE_LEVEL_KHR, 0); - EGLint zOffset = attributes.get(EGL_GL_TEXTURE_ZOFFSET_KHR, 0); + EGLAttrib level = attributes.get(EGL_GL_TEXTURE_LEVEL_KHR, 0); + EGLAttrib zOffset = attributes.get(EGL_GL_TEXTURE_ZOFFSET_KHR, 0); if (texture->getWidth(GL_TEXTURE_3D, static_cast(level)) == 0 || texture->getHeight(GL_TEXTURE_3D, static_cast(level)) == 0 || texture->getDepth(GL_TEXTURE_3D, static_cast(level)) == 0) { - return Error(EGL_BAD_PARAMETER, - "target 3D texture does not have a valid size at specified level."); + return EglBadParameter() + << "target 3D texture does not have a valid size at specified level."; } if (static_cast(zOffset) >= texture->getDepth(GL_TEXTURE_3D, static_cast(level))) { - return Error(EGL_BAD_PARAMETER, - "target 3D texture does not have enough layers for the specified Z " - "offset at the specified level."); - } - - if (level > 0 && (!texture->isMipmapComplete() || - static_cast(level) >= texture->getMipCompleteLevels())) - { - return Error(EGL_BAD_PARAMETER, "texture must be complete if level is non-zero."); + return EglBadParameter() << "target 3D texture does not have enough layers " + "for the specified Z offset at the specified " + "level."; } - if (level == 0 && !texture->isMipmapComplete() && - TextureHasNonZeroMipLevelsSpecified(context, texture)) - { - return Error(EGL_BAD_PARAMETER, - "if level is zero and the texture is incomplete, it must have no mip " - "levels specified except zero."); - } + ANGLE_TRY(ValidateCreateImageKHRMipLevelCommon(context, texture, level)); } break; @@ -952,75 +1495,71 @@ Error ValidateCreateImageKHR(const Display *display, { if (!displayExtensions.glRenderbufferImage) { - return Error(EGL_BAD_PARAMETER, "KHR_gl_renderbuffer_image not supported."); + return EglBadParameter() << "KHR_gl_renderbuffer_image not supported."; } if (attributes.contains(EGL_GL_TEXTURE_LEVEL_KHR)) { - return Error(EGL_BAD_PARAMETER, - "EGL_GL_TEXTURE_LEVEL_KHR cannot be used in conjunction with a " - "renderbuffer target."); + return EglBadParameter() << "EGL_GL_TEXTURE_LEVEL_KHR cannot be used in " + "conjunction with a renderbuffer target."; } if (buffer == 0) { - return Error(EGL_BAD_PARAMETER, - "buffer cannot reference a renderbuffer with the name 0."); + return EglBadParameter() + << "buffer cannot reference a renderbuffer with the name 0."; } const gl::Renderbuffer *renderbuffer = context->getRenderbuffer(egl_gl::EGLClientBufferToGLObjectHandle(buffer)); if (renderbuffer == nullptr) { - return Error(EGL_BAD_PARAMETER, "target is not a renderbuffer."); + return EglBadParameter() << "target is not a renderbuffer."; } if (renderbuffer->getSamples() > 0) { - return Error(EGL_BAD_PARAMETER, "target renderbuffer cannot be multisampled."); + return EglBadParameter() << "target renderbuffer cannot be multisampled."; } } break; default: - return Error(EGL_BAD_PARAMETER, "invalid target: 0x%X", target); + return EglBadParameter() + << "invalid target: 0x" << std::hex << std::uppercase << target; } - return Error(EGL_SUCCESS); + return NoError(); } Error ValidateDestroyImageKHR(const Display *display, const Image *image) { - Error error = ValidateImage(display, image); - if (error.isError()) - { - return error; - } + ANGLE_TRY(ValidateImage(display, image)); if (!display->getExtensions().imageBase && !display->getExtensions().image) { // It is out of spec what happens when calling an extension function when the extension is // not available. // EGL_BAD_DISPLAY seems like a reasonable error. - return Error(EGL_BAD_DISPLAY); + return EglBadDisplay(); } - return Error(EGL_SUCCESS); + return NoError(); } Error ValidateCreateDeviceANGLE(EGLint device_type, void *native_device, const EGLAttrib *attrib_list) { - const ClientExtensions &clientExtensions = Display::getClientExtensions(); + const ClientExtensions &clientExtensions = Display::GetClientExtensions(); if (!clientExtensions.deviceCreation) { - return Error(EGL_BAD_ACCESS, "Device creation extension not active"); + return EglBadAccess() << "Device creation extension not active"; } if (attrib_list != nullptr && attrib_list[0] != EGL_NONE) { - return Error(EGL_BAD_ATTRIBUTE, "Invalid attrib_list parameter"); + return EglBadAttribute() << "Invalid attrib_list parameter"; } switch (device_type) @@ -1028,35 +1567,935 @@ Error ValidateCreateDeviceANGLE(EGLint device_type, case EGL_D3D11_DEVICE_ANGLE: if (!clientExtensions.deviceCreationD3D11) { - return Error(EGL_BAD_ATTRIBUTE, "D3D11 device creation extension not active"); + return EglBadAttribute() << "D3D11 device creation extension not active"; } break; default: - return Error(EGL_BAD_ATTRIBUTE, "Invalid device_type parameter"); + return EglBadAttribute() << "Invalid device_type parameter"; } - return Error(EGL_SUCCESS); + return NoError(); } Error ValidateReleaseDeviceANGLE(Device *device) { - const ClientExtensions &clientExtensions = Display::getClientExtensions(); + const ClientExtensions &clientExtensions = Display::GetClientExtensions(); if (!clientExtensions.deviceCreation) { - return Error(EGL_BAD_ACCESS, "Device creation extension not active"); + return EglBadAccess() << "Device creation extension not active"; } if (device == EGL_NO_DEVICE_EXT || !Device::IsValidDevice(device)) { - return Error(EGL_BAD_DEVICE_EXT, "Invalid device parameter"); + return EglBadDevice() << "Invalid device parameter"; } Display *owningDisplay = device->getOwningDisplay(); if (owningDisplay != nullptr) { - return Error(EGL_BAD_DEVICE_EXT, "Device must have been created using eglCreateDevice"); + return EglBadDevice() << "Device must have been created using eglCreateDevice"; + } + + return NoError(); +} + +Error ValidateCreateStreamKHR(const Display *display, const AttributeMap &attributes) +{ + ANGLE_TRY(ValidateDisplay(display)); + + const DisplayExtensions &displayExtensions = display->getExtensions(); + if (!displayExtensions.stream) + { + return EglBadAlloc() << "Stream extension not active"; + } + + for (const auto &attributeIter : attributes) + { + EGLAttrib attribute = attributeIter.first; + EGLAttrib value = attributeIter.second; + + ANGLE_TRY(ValidateStreamAttribute(attribute, value, displayExtensions)); + } + + return NoError(); +} + +Error ValidateDestroyStreamKHR(const Display *display, const Stream *stream) +{ + ANGLE_TRY(ValidateStream(display, stream)); + return NoError(); +} + +Error ValidateStreamAttribKHR(const Display *display, + const Stream *stream, + EGLint attribute, + EGLint value) +{ + ANGLE_TRY(ValidateStream(display, stream)); + + if (stream->getState() == EGL_STREAM_STATE_DISCONNECTED_KHR) + { + return EglBadState() << "Bad stream state"; + } + + return ValidateStreamAttribute(attribute, value, display->getExtensions()); +} + +Error ValidateQueryStreamKHR(const Display *display, + const Stream *stream, + EGLenum attribute, + EGLint *value) +{ + ANGLE_TRY(ValidateStream(display, stream)); + + switch (attribute) + { + case EGL_STREAM_STATE_KHR: + case EGL_CONSUMER_LATENCY_USEC_KHR: + break; + case EGL_CONSUMER_ACQUIRE_TIMEOUT_USEC_KHR: + if (!display->getExtensions().streamConsumerGLTexture) + { + return EglBadAttribute() << "Consumer GLTexture extension not active"; + } + break; + default: + return EglBadAttribute() << "Invalid attribute"; + } + + return NoError(); +} + +Error ValidateQueryStreamu64KHR(const Display *display, + const Stream *stream, + EGLenum attribute, + EGLuint64KHR *value) +{ + ANGLE_TRY(ValidateStream(display, stream)); + + switch (attribute) + { + case EGL_CONSUMER_FRAME_KHR: + case EGL_PRODUCER_FRAME_KHR: + break; + default: + return EglBadAttribute() << "Invalid attribute"; + } + + return NoError(); +} + +Error ValidateStreamConsumerGLTextureExternalKHR(const Display *display, + gl::Context *context, + const Stream *stream) +{ + ANGLE_TRY(ValidateDisplay(display)); + ANGLE_TRY(ValidateContext(display, context)); + + const DisplayExtensions &displayExtensions = display->getExtensions(); + if (!displayExtensions.streamConsumerGLTexture) + { + return EglBadAccess() << "Stream consumer extension not active"; } - return Error(EGL_SUCCESS); + if (!context->getExtensions().eglStreamConsumerExternal) + { + return EglBadAccess() << "EGL stream consumer external GL extension not enabled"; + } + + if (stream == EGL_NO_STREAM_KHR || !display->isValidStream(stream)) + { + return EglBadStream() << "Invalid stream"; + } + + if (stream->getState() != EGL_STREAM_STATE_CREATED_KHR) + { + return EglBadState() << "Invalid stream state"; + } + + // Lookup the texture and ensure it is correct + gl::Texture *texture = context->getGLState().getTargetTexture(GL_TEXTURE_EXTERNAL_OES); + if (texture == nullptr || texture->getId() == 0) + { + return EglBadAccess() << "No external texture bound"; + } + + return NoError(); +} + +Error ValidateStreamConsumerAcquireKHR(const Display *display, + gl::Context *context, + const Stream *stream) +{ + ANGLE_TRY(ValidateDisplay(display)); + + const DisplayExtensions &displayExtensions = display->getExtensions(); + if (!displayExtensions.streamConsumerGLTexture) + { + return EglBadAccess() << "Stream consumer extension not active"; + } + + if (stream == EGL_NO_STREAM_KHR || !display->isValidStream(stream)) + { + return EglBadStream() << "Invalid stream"; + } + + if (!context) + { + return EglBadAccess() << "No GL context current to calling thread."; + } + + ANGLE_TRY(ValidateContext(display, context)); + + if (!stream->isConsumerBoundToContext(context)) + { + return EglBadAccess() << "Current GL context not associated with stream consumer"; + } + + if (stream->getConsumerType() != Stream::ConsumerType::GLTextureRGB && + stream->getConsumerType() != Stream::ConsumerType::GLTextureYUV) + { + return EglBadAccess() << "Invalid stream consumer type"; + } + + // Note: technically EGL_STREAM_STATE_EMPTY_KHR is a valid state when the timeout is non-zero. + // However, the timeout is effectively ignored since it has no useful functionality with the + // current producers that are implemented, so we don't allow that state + if (stream->getState() != EGL_STREAM_STATE_NEW_FRAME_AVAILABLE_KHR && + stream->getState() != EGL_STREAM_STATE_OLD_FRAME_AVAILABLE_KHR) + { + return EglBadState() << "Invalid stream state"; + } + + return NoError(); } + +Error ValidateStreamConsumerReleaseKHR(const Display *display, + gl::Context *context, + const Stream *stream) +{ + ANGLE_TRY(ValidateDisplay(display)); + + const DisplayExtensions &displayExtensions = display->getExtensions(); + if (!displayExtensions.streamConsumerGLTexture) + { + return EglBadAccess() << "Stream consumer extension not active"; + } + + if (stream == EGL_NO_STREAM_KHR || !display->isValidStream(stream)) + { + return EglBadStream() << "Invalid stream"; + } + + if (!context) + { + return EglBadAccess() << "No GL context current to calling thread."; + } + + ANGLE_TRY(ValidateContext(display, context)); + + if (!stream->isConsumerBoundToContext(context)) + { + return EglBadAccess() << "Current GL context not associated with stream consumer"; + } + + if (stream->getConsumerType() != Stream::ConsumerType::GLTextureRGB && + stream->getConsumerType() != Stream::ConsumerType::GLTextureYUV) + { + return EglBadAccess() << "Invalid stream consumer type"; + } + + if (stream->getState() != EGL_STREAM_STATE_NEW_FRAME_AVAILABLE_KHR && + stream->getState() != EGL_STREAM_STATE_OLD_FRAME_AVAILABLE_KHR) + { + return EglBadState() << "Invalid stream state"; + } + + return NoError(); } + +Error ValidateStreamConsumerGLTextureExternalAttribsNV(const Display *display, + gl::Context *context, + const Stream *stream, + const AttributeMap &attribs) +{ + ANGLE_TRY(ValidateDisplay(display)); + + const DisplayExtensions &displayExtensions = display->getExtensions(); + if (!displayExtensions.streamConsumerGLTexture) + { + return EglBadAccess() << "Stream consumer extension not active"; + } + + // Although technically not a requirement in spec, the context needs to be checked for support + // for external textures or future logic will cause assertations. This extension is also + // effectively useless without external textures. + if (!context->getExtensions().eglStreamConsumerExternal) + { + return EglBadAccess() << "EGL stream consumer external GL extension not enabled"; + } + + if (stream == EGL_NO_STREAM_KHR || !display->isValidStream(stream)) + { + return EglBadStream() << "Invalid stream"; + } + + if (!context) + { + return EglBadAccess() << "No GL context current to calling thread."; + } + + ANGLE_TRY(ValidateContext(display, context)); + + if (stream->getState() != EGL_STREAM_STATE_CREATED_KHR) + { + return EglBadState() << "Invalid stream state"; + } + + const gl::Caps &glCaps = context->getCaps(); + + EGLAttrib colorBufferType = EGL_RGB_BUFFER; + EGLAttrib planeCount = -1; + EGLAttrib plane[3]; + for (int i = 0; i < 3; i++) + { + plane[i] = -1; + } + for (const auto &attributeIter : attribs) + { + EGLAttrib attribute = attributeIter.first; + EGLAttrib value = attributeIter.second; + + switch (attribute) + { + case EGL_COLOR_BUFFER_TYPE: + if (value != EGL_RGB_BUFFER && value != EGL_YUV_BUFFER_EXT) + { + return EglBadParameter() << "Invalid color buffer type"; + } + colorBufferType = value; + break; + case EGL_YUV_NUMBER_OF_PLANES_EXT: + // planeCount = -1 is a tag for the default plane count so the value must be checked + // to be positive here to ensure future logic doesn't break on invalid negative + // inputs + if (value < 0) + { + return EglBadMatch() << "Invalid plane count"; + } + planeCount = value; + break; + default: + if (attribute >= EGL_YUV_PLANE0_TEXTURE_UNIT_NV && + attribute <= EGL_YUV_PLANE2_TEXTURE_UNIT_NV) + { + if ((value < 0 || + value >= static_cast(glCaps.maxCombinedTextureImageUnits)) && + value != EGL_NONE) + { + return EglBadAccess() << "Invalid texture unit"; + } + plane[attribute - EGL_YUV_PLANE0_TEXTURE_UNIT_NV] = value; + } + else + { + return EglBadAttribute() << "Invalid attribute"; + } + } + } + + if (colorBufferType == EGL_RGB_BUFFER) + { + if (planeCount > 0) + { + return EglBadMatch() << "Plane count must be 0 for RGB buffer"; + } + for (int i = 0; i < 3; i++) + { + if (plane[i] != -1) + { + return EglBadMatch() << "Planes cannot be specified"; + } + } + + // Lookup the texture and ensure it is correct + gl::Texture *texture = context->getGLState().getTargetTexture(GL_TEXTURE_EXTERNAL_OES); + if (texture == nullptr || texture->getId() == 0) + { + return EglBadAccess() << "No external texture bound"; + } + } + else + { + if (planeCount == -1) + { + planeCount = 2; + } + if (planeCount < 1 || planeCount > 3) + { + return EglBadMatch() << "Invalid YUV plane count"; + } + for (EGLAttrib i = planeCount; i < 3; i++) + { + if (plane[i] != -1) + { + return EglBadMatch() << "Invalid plane specified"; + } + } + + // Set to ensure no texture is referenced more than once + std::set textureSet; + for (EGLAttrib i = 0; i < planeCount; i++) + { + if (plane[i] == -1) + { + return EglBadMatch() << "Not all planes specified"; + } + if (plane[i] != EGL_NONE) + { + gl::Texture *texture = context->getGLState().getSamplerTexture( + static_cast(plane[i]), GL_TEXTURE_EXTERNAL_OES); + if (texture == nullptr || texture->getId() == 0) + { + return EglBadAccess() + << "No external texture bound at one or more specified texture units"; + } + if (textureSet.find(texture) != textureSet.end()) + { + return EglBadAccess() << "Multiple planes bound to same texture object"; + } + textureSet.insert(texture); + } + } + } + + return NoError(); +} + +Error ValidateCreateStreamProducerD3DTextureNV12ANGLE(const Display *display, + const Stream *stream, + const AttributeMap &attribs) +{ + ANGLE_TRY(ValidateDisplay(display)); + + const DisplayExtensions &displayExtensions = display->getExtensions(); + if (!displayExtensions.streamProducerD3DTextureNV12) + { + return EglBadAccess() << "Stream producer extension not active"; + } + + ANGLE_TRY(ValidateStream(display, stream)); + + if (!attribs.isEmpty()) + { + return EglBadAttribute() << "Invalid attribute"; + } + + if (stream->getState() != EGL_STREAM_STATE_CONNECTING_KHR) + { + return EglBadState() << "Stream not in connecting state"; + } + + if (stream->getConsumerType() != Stream::ConsumerType::GLTextureYUV || + stream->getPlaneCount() != 2) + { + return EglBadMatch() << "Incompatible stream consumer type"; + } + + return NoError(); +} + +Error ValidateStreamPostD3DTextureNV12ANGLE(const Display *display, + const Stream *stream, + void *texture, + const AttributeMap &attribs) +{ + ANGLE_TRY(ValidateDisplay(display)); + + const DisplayExtensions &displayExtensions = display->getExtensions(); + if (!displayExtensions.streamProducerD3DTextureNV12) + { + return EglBadAccess() << "Stream producer extension not active"; + } + + ANGLE_TRY(ValidateStream(display, stream)); + + for (auto &attributeIter : attribs) + { + EGLAttrib attribute = attributeIter.first; + EGLAttrib value = attributeIter.second; + + switch (attribute) + { + case EGL_D3D_TEXTURE_SUBRESOURCE_ID_ANGLE: + if (value < 0) + { + return EglBadParameter() << "Invalid subresource index"; + } + break; + default: + return EglBadAttribute() << "Invalid attribute"; + } + } + + if (stream->getState() != EGL_STREAM_STATE_EMPTY_KHR && + stream->getState() != EGL_STREAM_STATE_NEW_FRAME_AVAILABLE_KHR && + stream->getState() != EGL_STREAM_STATE_OLD_FRAME_AVAILABLE_KHR) + { + return EglBadState() << "Stream not fully configured"; + } + + if (stream->getProducerType() != Stream::ProducerType::D3D11TextureNV12) + { + return EglBadMatch() << "Incompatible stream producer"; + } + + if (texture == nullptr) + { + return EglBadParameter() << "Texture is null"; + } + + return stream->validateD3D11NV12Texture(texture); +} + +Error ValidateGetSyncValuesCHROMIUM(const Display *display, + const Surface *surface, + const EGLuint64KHR *ust, + const EGLuint64KHR *msc, + const EGLuint64KHR *sbc) +{ + ANGLE_TRY(ValidateDisplay(display)); + + const DisplayExtensions &displayExtensions = display->getExtensions(); + if (!displayExtensions.getSyncValues) + { + return EglBadAccess() << "getSyncValues extension not active"; + } + + if (display->isDeviceLost()) + { + return EglContextLost() << "Context is lost."; + } + + if (surface == EGL_NO_SURFACE) + { + return EglBadSurface() << "getSyncValues surface cannot be EGL_NO_SURFACE"; + } + + if (!surface->directComposition()) + { + return EglBadSurface() << "getSyncValues surface requires Direct Composition to be enabled"; + } + + if (ust == nullptr) + { + return EglBadParameter() << "ust is null"; + } + + if (msc == nullptr) + { + return EglBadParameter() << "msc is null"; + } + + if (sbc == nullptr) + { + return EglBadParameter() << "sbc is null"; + } + + return NoError(); +} + +Error ValidateSwapBuffersWithDamageEXT(const Display *display, + const Surface *surface, + EGLint *rects, + EGLint n_rects) +{ + Error error = ValidateSurface(display, surface); + if (error.isError()) + { + return error; + } + + if (!display->getExtensions().swapBuffersWithDamage) + { + // It is out of spec what happens when calling an extension function when the extension is + // not available. EGL_BAD_DISPLAY seems like a reasonable error. + return EglBadDisplay() << "EGL_EXT_swap_buffers_with_damage is not available."; + } + + if (surface == EGL_NO_SURFACE) + { + return EglBadSurface() << "Swap surface cannot be EGL_NO_SURFACE."; + } + + if (n_rects < 0) + { + return EglBadParameter() << "n_rects cannot be negative."; + } + + if (n_rects > 0 && rects == nullptr) + { + return EglBadParameter() << "n_rects cannot be greater than zero when rects is NULL."; + } + + // TODO(jmadill): Validate Surface is bound to the thread. + + return NoError(); +} + +Error ValidateGetConfigAttrib(const Display *display, const Config *config, EGLint attribute) +{ + ANGLE_TRY(ValidateConfig(display, config)); + ANGLE_TRY(ValidateConfigAttribute(display, static_cast(attribute))); + return NoError(); +} + +Error ValidateChooseConfig(const Display *display, + const AttributeMap &attribs, + EGLint configSize, + EGLint *numConfig) +{ + ANGLE_TRY(ValidateDisplay(display)); + ANGLE_TRY(ValidateConfigAttributes(display, attribs)); + + if (numConfig == nullptr) + { + return EglBadParameter() << "num_config cannot be null."; + } + + return NoError(); +} + +Error ValidateGetConfigs(const Display *display, EGLint configSize, EGLint *numConfig) +{ + ANGLE_TRY(ValidateDisplay(display)); + + if (numConfig == nullptr) + { + return EglBadParameter() << "num_config cannot be null."; + } + + return NoError(); +} + +Error ValidateGetPlatformDisplay(EGLenum platform, + void *native_display, + const EGLAttrib *attrib_list) +{ + const auto &attribMap = AttributeMap::CreateFromAttribArray(attrib_list); + return ValidateGetPlatformDisplayCommon(platform, native_display, attribMap); +} + +Error ValidateGetPlatformDisplayEXT(EGLenum platform, + void *native_display, + const EGLint *attrib_list) +{ + const auto &attribMap = AttributeMap::CreateFromIntArray(attrib_list); + return ValidateGetPlatformDisplayCommon(platform, native_display, attribMap); +} + +Error ValidateProgramCacheGetAttribANGLE(const Display *display, EGLenum attrib) +{ + ANGLE_TRY(ValidateDisplay(display)); + + if (!display->getExtensions().programCacheControl) + { + return EglBadAccess() << "Extension not supported"; + } + + switch (attrib) + { + case EGL_PROGRAM_CACHE_KEY_LENGTH_ANGLE: + case EGL_PROGRAM_CACHE_SIZE_ANGLE: + break; + + default: + return EglBadParameter() << "Invalid program cache attribute."; + } + + return NoError(); +} + +Error ValidateProgramCacheQueryANGLE(const Display *display, + EGLint index, + void *key, + EGLint *keysize, + void *binary, + EGLint *binarysize) +{ + ANGLE_TRY(ValidateDisplay(display)); + + if (!display->getExtensions().programCacheControl) + { + return EglBadAccess() << "Extension not supported"; + } + + if (index < 0 || index >= display->programCacheGetAttrib(EGL_PROGRAM_CACHE_SIZE_ANGLE)) + { + return EglBadParameter() << "Program index out of range."; + } + + if (keysize == nullptr || binarysize == nullptr) + { + return EglBadParameter() << "keysize and binarysize must always be valid pointers."; + } + + if (binary && *keysize != static_cast(gl::kProgramHashLength)) + { + return EglBadParameter() << "Invalid program key size."; + } + + if ((key == nullptr) != (binary == nullptr)) + { + return EglBadParameter() << "key and binary must both be null or both non-null."; + } + + return NoError(); +} + +Error ValidateProgramCachePopulateANGLE(const Display *display, + const void *key, + EGLint keysize, + const void *binary, + EGLint binarysize) +{ + ANGLE_TRY(ValidateDisplay(display)); + + if (!display->getExtensions().programCacheControl) + { + return EglBadAccess() << "Extension not supported"; + } + + if (keysize != static_cast(gl::kProgramHashLength)) + { + return EglBadParameter() << "Invalid program key size."; + } + + if (key == nullptr || binary == nullptr) + { + return EglBadParameter() << "null pointer in arguments."; + } + + // Upper bound for binarysize is arbitrary. + if (binarysize <= 0 || binarysize > egl::kProgramCacheSizeAbsoluteMax) + { + return EglBadParameter() << "binarysize out of valid range."; + } + + return NoError(); +} + +Error ValidateProgramCacheResizeANGLE(const Display *display, EGLint limit, EGLenum mode) +{ + ANGLE_TRY(ValidateDisplay(display)); + + if (!display->getExtensions().programCacheControl) + { + return EglBadAccess() << "Extension not supported"; + } + + if (limit < 0) + { + return EglBadParameter() << "limit must be non-negative."; + } + + switch (mode) + { + case EGL_PROGRAM_CACHE_RESIZE_ANGLE: + case EGL_PROGRAM_CACHE_TRIM_ANGLE: + break; + + default: + return EglBadParameter() << "Invalid cache resize mode."; + } + + return NoError(); +} + +Error ValidateSurfaceAttrib(const Display *display, + const Surface *surface, + EGLint attribute, + EGLint value) +{ + ANGLE_TRY(ValidateDisplay(display)); + ANGLE_TRY(ValidateSurface(display, surface)); + + if (surface == EGL_NO_SURFACE) + { + return EglBadSurface() << "Surface cannot be EGL_NO_SURFACE."; + } + + switch (attribute) + { + case EGL_MIPMAP_LEVEL: + break; + + case EGL_MULTISAMPLE_RESOLVE: + switch (value) + { + case EGL_MULTISAMPLE_RESOLVE_DEFAULT: + break; + + case EGL_MULTISAMPLE_RESOLVE_BOX: + if ((surface->getConfig()->surfaceType & EGL_MULTISAMPLE_RESOLVE_BOX_BIT) == 0) + { + return EglBadMatch() + << "Surface does not support EGL_MULTISAMPLE_RESOLVE_BOX."; + } + break; + + default: + return EglBadAttribute() << "Invalid multisample resolve type."; + } + + case EGL_SWAP_BEHAVIOR: + switch (value) + { + case EGL_BUFFER_PRESERVED: + if ((surface->getConfig()->surfaceType & EGL_SWAP_BEHAVIOR_PRESERVED_BIT) == 0) + { + return EglBadMatch() + << "Surface does not support EGL_SWAP_BEHAVIOR_PRESERVED."; + } + break; + + case EGL_BUFFER_DESTROYED: + break; + + default: + return EglBadAttribute() << "Invalid swap behaviour."; + } + + default: + return EglBadAttribute() << "Invalid surface attribute."; + } + + return NoError(); +} + +Error ValidateQuerySurface(const Display *display, + const Surface *surface, + EGLint attribute, + EGLint *value) +{ + ANGLE_TRY(ValidateDisplay(display)); + ANGLE_TRY(ValidateSurface(display, surface)); + + if (surface == EGL_NO_SURFACE) + { + return EglBadSurface() << "Surface cannot be EGL_NO_SURFACE."; + } + + switch (attribute) + { + case EGL_GL_COLORSPACE: + case EGL_VG_ALPHA_FORMAT: + case EGL_VG_COLORSPACE: + case EGL_CONFIG_ID: + case EGL_HEIGHT: + case EGL_HORIZONTAL_RESOLUTION: + case EGL_LARGEST_PBUFFER: + case EGL_MIPMAP_TEXTURE: + case EGL_MIPMAP_LEVEL: + case EGL_MULTISAMPLE_RESOLVE: + case EGL_PIXEL_ASPECT_RATIO: + case EGL_RENDER_BUFFER: + case EGL_SWAP_BEHAVIOR: + case EGL_TEXTURE_FORMAT: + case EGL_TEXTURE_TARGET: + case EGL_VERTICAL_RESOLUTION: + case EGL_WIDTH: + break; + + case EGL_POST_SUB_BUFFER_SUPPORTED_NV: + if (!display->getExtensions().postSubBuffer) + { + return EglBadAttribute() << "EGL_POST_SUB_BUFFER_SUPPORTED_NV cannot be used " + "without EGL_ANGLE_surface_orientation support."; + } + break; + + case EGL_FIXED_SIZE_ANGLE: + if (!display->getExtensions().windowFixedSize) + { + return EglBadAttribute() << "EGL_FIXED_SIZE_ANGLE cannot be used without " + "EGL_ANGLE_window_fixed_size support."; + } + break; + + case EGL_FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE: + if (!display->getExtensions().flexibleSurfaceCompatibility) + { + return EglBadAttribute() + << "EGL_FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE cannot be " + "used without EGL_ANGLE_flexible_surface_compatibility support."; + } + break; + + case EGL_SURFACE_ORIENTATION_ANGLE: + if (!display->getExtensions().surfaceOrientation) + { + return EglBadAttribute() << "EGL_SURFACE_ORIENTATION_ANGLE cannot be " + "queried without " + "EGL_ANGLE_surface_orientation support."; + } + break; + + case EGL_DIRECT_COMPOSITION_ANGLE: + if (!display->getExtensions().directComposition) + { + return EglBadAttribute() << "EGL_DIRECT_COMPOSITION_ANGLE cannot be " + "used without " + "EGL_ANGLE_direct_composition support."; + } + break; + + case EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE: + if (!display->getExtensions().robustResourceInitialization) + { + return EglBadAttribute() << "EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE cannot be " + "used without EGL_ANGLE_robust_resource_initialization " + "support."; + } + break; + + default: + return EglBadAttribute() << "Invalid surface attribute."; + } + + return NoError(); +} + +Error ValidateQueryContext(const Display *display, + const gl::Context *context, + EGLint attribute, + EGLint *value) +{ + ANGLE_TRY(ValidateDisplay(display)); + ANGLE_TRY(ValidateContext(display, context)); + + switch (attribute) + { + case EGL_CONFIG_ID: + case EGL_CONTEXT_CLIENT_TYPE: + case EGL_CONTEXT_CLIENT_VERSION: + case EGL_RENDER_BUFFER: + break; + + case EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE: + if (!display->getExtensions().robustResourceInitialization) + { + return EglBadAttribute() << "EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE cannot be " + "used without EGL_ANGLE_robust_resource_initialization " + "support."; + } + break; + + default: + return EglBadAttribute() << "Invalid context attribute."; + } + + return NoError(); +} + +} // namespace egl diff --git a/src/3rdparty/angle/src/libANGLE/validationEGL.h b/src/3rdparty/angle/src/libANGLE/validationEGL.h index eaafddc20d..3ab8232c7f 100644 --- a/src/3rdparty/angle/src/libANGLE/validationEGL.h +++ b/src/3rdparty/angle/src/libANGLE/validationEGL.h @@ -12,6 +12,7 @@ #include "libANGLE/Error.h" #include +#include namespace gl { @@ -22,17 +23,19 @@ namespace egl { class AttributeMap; +struct ClientExtensions; struct Config; class Device; class Display; class Image; +class Stream; class Surface; // Object validation Error ValidateDisplay(const Display *display); -Error ValidateSurface(const Display *display, Surface *surface); +Error ValidateSurface(const Display *display, const Surface *surface); Error ValidateConfig(const Display *display, const Config *config); -Error ValidateContext(const Display *display, gl::Context *context); +Error ValidateContext(const Display *display, const gl::Context *context); Error ValidateImage(const Display *display, const Image *image); // Entry point validation @@ -46,6 +49,8 @@ Error ValidateCreatePbufferSurface(Display *display, Config *config, const Attri Error ValidateCreatePbufferFromClientBuffer(Display *display, EGLenum buftype, EGLClientBuffer buffer, Config *config, const AttributeMap& attributes); +Error ValidateMakeCurrent(Display *display, EGLSurface draw, EGLSurface read, gl::Context *context); + Error ValidateCreateImageKHR(const Display *display, gl::Context *context, EGLenum target, @@ -58,12 +63,120 @@ Error ValidateCreateDeviceANGLE(EGLint device_type, const EGLAttrib *attrib_list); Error ValidateReleaseDeviceANGLE(Device *device); +Error ValidateCreateStreamKHR(const Display *display, const AttributeMap &attributes); +Error ValidateDestroyStreamKHR(const Display *display, const Stream *stream); +Error ValidateStreamAttribKHR(const Display *display, + const Stream *stream, + EGLint attribute, + EGLint value); +Error ValidateQueryStreamKHR(const Display *display, + const Stream *stream, + EGLenum attribute, + EGLint *value); +Error ValidateQueryStreamu64KHR(const Display *display, + const Stream *stream, + EGLenum attribute, + EGLuint64KHR *value); +Error ValidateStreamConsumerGLTextureExternalKHR(const Display *display, + gl::Context *context, + const Stream *stream); +Error ValidateStreamConsumerAcquireKHR(const Display *display, + gl::Context *context, + const Stream *stream); +Error ValidateStreamConsumerReleaseKHR(const Display *display, + gl::Context *context, + const Stream *stream); +Error ValidateStreamConsumerGLTextureExternalAttribsNV(const Display *display, + gl::Context *context, + const Stream *stream, + const AttributeMap &attribs); +Error ValidateCreateStreamProducerD3DTextureNV12ANGLE(const Display *display, + const Stream *stream, + const AttributeMap &attribs); +Error ValidateStreamPostD3DTextureNV12ANGLE(const Display *display, + const Stream *stream, + void *texture, + const AttributeMap &attribs); + +Error ValidateGetSyncValuesCHROMIUM(const Display *display, + const Surface *surface, + const EGLuint64KHR *ust, + const EGLuint64KHR *msc, + const EGLuint64KHR *sbc); + +Error ValidateSwapBuffersWithDamageEXT(const Display *display, + const Surface *surface, + EGLint *rects, + EGLint n_rects); + +Error ValidateGetConfigAttrib(const Display *display, const Config *config, EGLint attribute); +Error ValidateChooseConfig(const Display *display, + const AttributeMap &attribs, + EGLint configSize, + EGLint *numConfig); +Error ValidateGetConfigs(const Display *display, EGLint configSize, EGLint *numConfig); + // Other validation Error ValidateCompatibleConfigs(const Display *display, const Config *config1, const Surface *surface, const Config *config2, EGLint surfaceType); -} + +Error ValidateGetPlatformDisplay(EGLenum platform, + void *native_display, + const EGLAttrib *attrib_list); +Error ValidateGetPlatformDisplayEXT(EGLenum platform, + void *native_display, + const EGLint *attrib_list); + +Error ValidateProgramCacheGetAttribANGLE(const Display *display, EGLenum attrib); + +Error ValidateProgramCacheQueryANGLE(const Display *display, + EGLint index, + void *key, + EGLint *keysize, + void *binary, + EGLint *binarysize); + +Error ValidateProgramCachePopulateANGLE(const Display *display, + const void *key, + EGLint keysize, + const void *binary, + EGLint binarysize); + +Error ValidateProgramCacheResizeANGLE(const Display *display, EGLint limit, EGLenum mode); + +Error ValidateSurfaceAttrib(const Display *display, + const Surface *surface, + EGLint attribute, + EGLint value); +Error ValidateQuerySurface(const Display *display, + const Surface *surface, + EGLint attribute, + EGLint *value); +Error ValidateQueryContext(const Display *display, + const gl::Context *context, + EGLint attribute, + EGLint *value); + +} // namespace egl + +#define ANGLE_EGL_TRY(THREAD, EXPR) \ + { \ + auto ANGLE_LOCAL_VAR = (EXPR); \ + if (ANGLE_LOCAL_VAR.isError()) \ + return THREAD->setError(ANGLE_LOCAL_VAR); \ + } + +#define ANGLE_EGL_TRY_RETURN(THREAD, EXPR, RETVAL) \ + { \ + auto ANGLE_LOCAL_VAR = (EXPR); \ + if (ANGLE_LOCAL_VAR.isError()) \ + { \ + THREAD->setError(ANGLE_LOCAL_VAR); \ + return RETVAL; \ + } \ + } #endif // LIBANGLE_VALIDATIONEGL_H_ diff --git a/src/3rdparty/angle/src/libANGLE/validationES.cpp b/src/3rdparty/angle/src/libANGLE/validationES.cpp index 12c76120bd..ae564b7412 100644 --- a/src/3rdparty/angle/src/libANGLE/validationES.cpp +++ b/src/3rdparty/angle/src/libANGLE/validationES.cpp @@ -7,2629 +7,5822 @@ // 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/Display.h" -#include "libANGLE/Texture.h" +#include "libANGLE/ErrorStrings.h" #include "libANGLE/Framebuffer.h" #include "libANGLE/FramebufferAttachment.h" -#include "libANGLE/formatutils.h" #include "libANGLE/Image.h" -#include "libANGLE/Query.h" #include "libANGLE/Program.h" -#include "libANGLE/Uniform.h" +#include "libANGLE/Query.h" +#include "libANGLE/Texture.h" #include "libANGLE/TransformFeedback.h" #include "libANGLE/VertexArray.h" +#include "libANGLE/formatutils.h" +#include "libANGLE/queryconversions.h" +#include "libANGLE/validationES2.h" +#include "libANGLE/validationES3.h" #include "common/mathutil.h" #include "common/utilities.h" +using namespace angle; + namespace gl { -const char *g_ExceedsMaxElementErrorMessage = "Element value exceeds maximum element index."; - namespace { -bool ValidateDrawAttribs(ValidationContext *context, GLint primcount, GLint maxVertex) + +bool ValidateDrawAttribs(ValidationContext *context, + GLint primcount, + GLint maxVertex, + GLint vertexCount) { - const gl::State &state = context->getState(); + const gl::State &state = context->getGLState(); const gl::Program *program = state.getProgram(); + bool webglCompatibility = context->getExtensions().webglCompatibility; + const VertexArray *vao = state.getVertexArray(); const auto &vertexAttribs = vao->getVertexAttributes(); - size_t maxEnabledAttrib = vao->getMaxEnabledAttribute(); + const auto &vertexBindings = vao->getVertexBindings(); + size_t maxEnabledAttrib = vao->getMaxEnabledAttribute(); for (size_t attributeIndex = 0; attributeIndex < maxEnabledAttrib; ++attributeIndex) { const VertexAttribute &attrib = vertexAttribs[attributeIndex]; - if (program->isAttribLocationActive(attributeIndex) && attrib.enabled) + + // No need to range check for disabled attribs. + if (!attrib.enabled) { - gl::Buffer *buffer = attrib.buffer.get(); + continue; + } - if (buffer) + // If we have no buffer, then we either get an error, or there are no more checks to be + // done. + const VertexBinding &binding = vertexBindings[attrib.bindingIndex]; + gl::Buffer *buffer = binding.getBuffer().get(); + if (!buffer) + { + if (webglCompatibility || !state.areClientArraysEnabled()) { - 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); - } - - // If we're drawing zero vertices, we have enough data. - if (maxVertexElement > 0) - { - // Note: Last vertex element does not take the full stride! - GLint64 attribSize = - static_cast(ComputeVertexAttributeTypeSize(attrib)); - GLint64 attribDataSize = (maxVertexElement - 1) * attribStride + attribSize; - - // [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; - } - } + // [WebGL 1.0] Section 6.5 Enabled Vertex Attributes and Range Checking + // If a vertex attribute is enabled as an array via enableVertexAttribArray but + // no buffer is bound to that attribute via bindBuffer and vertexAttribPointer, + // then calls to drawArrays or drawElements will generate an INVALID_OPERATION + // error. + ANGLE_VALIDATION_ERR(context, InvalidOperation(), VertexArrayNoBuffer); + return false; } - else if (attrib.pointer == NULL) + else if (attrib.pointer == nullptr) { // 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.")); + ANGLE_VALIDATION_ERR(context, InvalidOperation(), VertexArrayNoBufferPointer); return false; } + continue; } - } - return true; -} - -} // anonymous namespace + // This needs to come after the check for client arrays as even unused attributes cannot use + // client-side arrays + if (!program->isAttribLocationActive(attributeIndex)) + { + continue; + } -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; + // If we're drawing zero vertices, we have enough data. + if (vertexCount <= 0 || primcount <= 0) + { + continue; + } - case GL_PRIMITIVE_RESTART_FIXED_INDEX: - case GL_RASTERIZER_DISCARD: - return (context->getClientVersion() >= 3); + GLint maxVertexElement = 0; + GLuint divisor = binding.getDivisor(); + if (divisor == 0) + { + maxVertexElement = maxVertex; + } + else + { + maxVertexElement = (primcount - 1) / divisor; + } - case GL_DEBUG_OUTPUT_SYNCHRONOUS: - case GL_DEBUG_OUTPUT: - return context->getExtensions().debug; + // We do manual overflow checks here instead of using safe_math.h because it was + // a bottleneck. Thanks to some properties of GL we know inequalities that can + // help us make the overflow checks faster. + + // The max possible attribSize is 16 for a vector of 4 32 bit values. + constexpr uint64_t kMaxAttribSize = 16; + constexpr uint64_t kIntMax = std::numeric_limits::max(); + constexpr uint64_t kUint64Max = std::numeric_limits::max(); + + // We know attribStride is given as a GLsizei which is typedefed to int. + // We also know an upper bound for attribSize. + static_assert(std::is_same::value, ""); + uint64_t attribStride = ComputeVertexAttributeStride(attrib, binding); + uint64_t attribSize = ComputeVertexAttributeTypeSize(attrib); + ASSERT(attribStride <= kIntMax && attribSize <= kMaxAttribSize); + + // Computing the max offset using uint64_t without attrib.offset is overflow + // safe. Note: Last vertex element does not take the full stride! + static_assert(kIntMax * kIntMax < kUint64Max - kMaxAttribSize, ""); + uint64_t attribDataSizeNoOffset = maxVertexElement * attribStride + attribSize; + + // An overflow can happen when adding the offset, check for it. + uint64_t attribOffset = ComputeVertexAttributeOffset(attrib, binding); + if (attribDataSizeNoOffset > kUint64Max - attribOffset) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), IntegerOverflow); + return false; + } + uint64_t attribDataSizeWithOffset = attribDataSizeNoOffset + attribOffset; - default: - return false; + // [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 (attribDataSizeWithOffset > static_cast(buffer->getSize())) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), InsufficientVertexBufferSize); + return false; + } } -} -bool ValidTextureTarget(const ValidationContext *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; - } + return true; } -bool ValidTexture2DTarget(const ValidationContext *context, GLenum target) +bool ValidReadPixelsTypeEnum(ValidationContext *context, GLenum type) { - switch (target) + switch (type) { - case GL_TEXTURE_2D: - case GL_TEXTURE_CUBE_MAP: - return true; + // Types referenced in Table 3.4 of the ES 2.0.25 spec + case GL_UNSIGNED_BYTE: + case GL_UNSIGNED_SHORT_4_4_4_4: + case GL_UNSIGNED_SHORT_5_5_5_1: + case GL_UNSIGNED_SHORT_5_6_5: + return context->getClientVersion() >= ES_2_0; + + // Types referenced in Table 3.2 of the ES 3.0.5 spec (Except depth stencil) + case GL_BYTE: + case GL_INT: + case GL_SHORT: + case GL_UNSIGNED_INT: + case GL_UNSIGNED_INT_10F_11F_11F_REV: + case GL_UNSIGNED_INT_24_8: + case GL_UNSIGNED_INT_2_10_10_10_REV: + case GL_UNSIGNED_INT_5_9_9_9_REV: + case GL_UNSIGNED_SHORT: + case GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT: + case GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT: + return context->getClientVersion() >= ES_3_0; + + case GL_FLOAT: + return context->getClientVersion() >= ES_3_0 || context->getExtensions().textureFloat || + context->getExtensions().colorBufferHalfFloat; + + case GL_HALF_FLOAT: + return context->getClientVersion() >= ES_3_0 || + context->getExtensions().textureHalfFloat; + + case GL_HALF_FLOAT_OES: + return context->getExtensions().colorBufferHalfFloat; default: return false; } } -bool ValidTexture3DTarget(const ValidationContext *context, GLenum target) +bool ValidReadPixelsFormatEnum(ValidationContext *context, GLenum format) { - switch (target) - { - case GL_TEXTURE_3D: - case GL_TEXTURE_2D_ARRAY: - return (context->getClientVersion() >= 3); + switch (format) + { + // Formats referenced in Table 3.4 of the ES 2.0.25 spec (Except luminance) + case GL_RGBA: + case GL_RGB: + case GL_ALPHA: + return context->getClientVersion() >= ES_2_0; + + // Formats referenced in Table 3.2 of the ES 3.0.5 spec + case GL_RG: + case GL_RED: + case GL_RGBA_INTEGER: + case GL_RGB_INTEGER: + case GL_RG_INTEGER: + case GL_RED_INTEGER: + return context->getClientVersion() >= ES_3_0; + + case GL_SRGB_ALPHA_EXT: + case GL_SRGB_EXT: + return context->getExtensions().sRGB; + + case GL_BGRA_EXT: + return context->getExtensions().readFormatBGRA; 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 ValidationContext *context, GLenum target) +bool ValidReadPixelsFormatType(ValidationContext *context, + GLenum framebufferComponentType, + GLenum format, + GLenum type) { - switch (target) + switch (framebufferComponentType) { - 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; - default: - return false; - } -} + case GL_UNSIGNED_NORMALIZED: + // TODO(geofflang): Don't accept BGRA here. Some chrome internals appear to try to use + // ReadPixels with BGRA even if the extension is not present + return (format == GL_RGBA && type == GL_UNSIGNED_BYTE) || + (context->getExtensions().readFormatBGRA && format == GL_BGRA_EXT && + type == GL_UNSIGNED_BYTE); -bool ValidTexture3DDestinationTarget(const ValidationContext *context, GLenum target) -{ - switch (target) - { - case GL_TEXTURE_3D: - case GL_TEXTURE_2D_ARRAY: - return true; - default: - return false; - } -} + case GL_SIGNED_NORMALIZED: + return (format == GL_RGBA && type == GL_UNSIGNED_BYTE); -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."); + case GL_INT: + return (format == GL_RGBA_INTEGER && type == GL_INT); - switch (target) - { - case GL_FRAMEBUFFER: return true; - case GL_READ_FRAMEBUFFER: return true; - case GL_DRAW_FRAMEBUFFER: return true; - default: return false; + case GL_UNSIGNED_INT: + return (format == GL_RGBA_INTEGER && type == GL_UNSIGNED_INT); + + case GL_FLOAT: + return (format == GL_RGBA && type == GL_FLOAT); + + default: + UNREACHABLE(); + return false; } } -bool ValidBufferTarget(const Context *context, GLenum target) +template +bool ValidateTextureWrapModeValue(Context *context, ParamType *params, bool restrictedWrapModes) { - switch (target) + switch (ConvertToGLenum(params[0])) { - 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 || context->getClientVersion() >= 3); + case GL_CLAMP_TO_EDGE: + break; - case GL_COPY_READ_BUFFER: - case GL_COPY_WRITE_BUFFER: - case GL_TRANSFORM_FEEDBACK_BUFFER: - case GL_UNIFORM_BUFFER: - return (context->getClientVersion() >= 3); + case GL_REPEAT: + case GL_MIRRORED_REPEAT: + if (restrictedWrapModes) + { + // OES_EGL_image_external and ANGLE_texture_rectangle specifies this error. + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidWrapModeTexture); + return false; + } + break; - default: - return false; + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidTextureWrap); + return false; } + + return true; } -bool ValidBufferParameter(const Context *context, GLenum pname) +template +bool ValidateTextureMinFilterValue(Context *context, ParamType *params, bool restrictedMinFilter) { - const Extensions &extensions = context->getExtensions(); - - switch (pname) + switch (ConvertToGLenum(params[0])) { - case GL_BUFFER_USAGE: - case GL_BUFFER_SIZE: - return true; - - case GL_BUFFER_ACCESS_OES: - return extensions.mapBuffer; - - case GL_BUFFER_MAPPED: - static_assert(GL_BUFFER_MAPPED == GL_BUFFER_MAPPED_OES, "GL enums should be equal."); - return (context->getClientVersion() >= 3) || extensions.mapBuffer || extensions.mapBufferRange; + case GL_NEAREST: + case GL_LINEAR: + break; - // GL_BUFFER_MAP_POINTER is a special case, and may only be - // queried with GetBufferPointerv - case GL_BUFFER_ACCESS_FLAGS: - case GL_BUFFER_MAP_OFFSET: - case GL_BUFFER_MAP_LENGTH: - return (context->getClientVersion() >= 3) || extensions.mapBufferRange; + case GL_NEAREST_MIPMAP_NEAREST: + case GL_LINEAR_MIPMAP_NEAREST: + case GL_NEAREST_MIPMAP_LINEAR: + case GL_LINEAR_MIPMAP_LINEAR: + if (restrictedMinFilter) + { + // OES_EGL_image_external specifies this error. + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidFilterTexture); + return false; + } + break; - default: - return false; + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidTextureFilterParam); + return false; } + + return true; } -bool ValidMipLevel(const ValidationContext *context, GLenum target, GLint level) +template +bool ValidateTextureMagFilterValue(Context *context, ParamType *params) { - const auto &caps = context->getCaps(); - size_t maxDimension = 0; - switch (target) + switch (ConvertToGLenum(params[0])) { - case GL_TEXTURE_2D: - maxDimension = caps.max2DTextureSize; + case GL_NEAREST: + case GL_LINEAR: 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 = caps.maxCubeMapTextureSize; - break; - case GL_TEXTURE_3D: - maxDimension = caps.max3DTextureSize; - break; - case GL_TEXTURE_2D_ARRAY: - maxDimension = caps.max2DTextureSize; - break; - default: UNREACHABLE(); + + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidTextureFilterParam); + return false; } - return level <= gl::log2(static_cast(maxDimension)); + return true; } -bool ValidImageSizeParameters(const Context *context, - GLenum target, - GLint level, - GLsizei width, - GLsizei height, - GLsizei depth, - bool isSubImage) +template +bool ValidateTextureCompareModeValue(Context *context, ParamType *params) { - if (level < 0 || width < 0 || height < 0 || depth < 0) - { - return false; - } - - // TexSubImage parameters can be NPOT without textureNPOT extension, - // as long as the destination texture is POT. - if (!isSubImage && !context->getExtensions().textureNPOT && - (level != 0 && (!gl::isPow2(width) || !gl::isPow2(height) || !gl::isPow2(depth)))) + // Acceptable mode parameters from GLES 3.0.2 spec, table 3.17 + switch (ConvertToGLenum(params[0])) { - return false; - } + case GL_NONE: + case GL_COMPARE_REF_TO_TEXTURE: + break; - if (!ValidMipLevel(context, target, level)) - { - return false; + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), UnknownParameter); + return false; } return true; } -bool CompressedTextureFormatRequiresExactSize(GLenum internalFormat) +template +bool ValidateTextureCompareFuncValue(Context *context, ParamType *params) { - // List of compressed format that require that the texture size is smaller than or a multiple of - // the compressed block size. - switch (internalFormat) - { - 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: - case GL_ETC1_RGB8_LOSSY_DECODE_ANGLE: - return true; + // Acceptable function parameters from GLES 3.0.2 spec, table 3.17 + switch (ConvertToGLenum(params[0])) + { + case GL_LEQUAL: + case GL_GEQUAL: + case GL_LESS: + case GL_GREATER: + case GL_EQUAL: + case GL_NOTEQUAL: + case GL_ALWAYS: + case GL_NEVER: + break; default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), UnknownParameter); return false; } + + return true; } -bool ValidCompressedImageSize(const ValidationContext *context, - GLenum internalFormat, - GLsizei width, - GLsizei height) +template +bool ValidateTextureSRGBDecodeValue(Context *context, ParamType *params) { - const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat); - if (!formatInfo.compressed) + if (!context->getExtensions().textureSRGBDecode) { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), ExtensionNotEnabled); return false; } - if (width < 0 || height < 0) + switch (ConvertToGLenum(params[0])) { - return false; - } + case GL_DECODE_EXT: + case GL_SKIP_DECODE_EXT: + break; - if (CompressedTextureFormatRequiresExactSize(internalFormat)) - { - if ((static_cast(width) > formatInfo.compressedBlockWidth && - width % formatInfo.compressedBlockWidth != 0) || - (static_cast(height) > formatInfo.compressedBlockHeight && - height % formatInfo.compressedBlockHeight != 0)) - { + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), UnknownParameter); 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); - case GL_TIME_ELAPSED_EXT: - return context->getExtensions().disjointTimerQuery; - default: - return false; - } -} - -Program *GetValidProgram(Context *context, GLuint id) +bool ValidateFragmentShaderColorBufferTypeMatch(ValidationContext *context) { - // 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." - - Program *validProgram = context->getProgram(id); + const Program *program = context->getGLState().getProgram(); + const Framebuffer *framebuffer = context->getGLState().getDrawFramebuffer(); - if (!validProgram) + const auto &programOutputTypes = program->getOutputVariableTypes(); + for (size_t drawBufferIdx = 0; drawBufferIdx < programOutputTypes.size(); drawBufferIdx++) { - if (context->getShader(id)) - { - context->recordError( - Error(GL_INVALID_OPERATION, "Expected a program name, but found a shader name")); - } - else + GLenum outputType = programOutputTypes[drawBufferIdx]; + GLenum inputType = framebuffer->getDrawbufferWriteType(drawBufferIdx); + if (outputType != GL_NONE && inputType != GL_NONE && inputType != outputType) { - context->recordError(Error(GL_INVALID_VALUE, "Program name is not valid")); + context->handleError(InvalidOperation() << "Fragment shader output type does not " + "match the bound framebuffer attachment " + "type."); + return false; } } - return validProgram; + return true; } -Shader *GetValidShader(Context *context, GLuint id) +bool ValidateVertexShaderAttributeTypeMatch(ValidationContext *context) { - // See ValidProgram for spec details. - - Shader *validShader = context->getShader(id); + const auto &glState = context->getGLState(); + const Program *program = context->getGLState().getProgram(); + const VertexArray *vao = context->getGLState().getVertexArray(); + const auto &vertexAttribs = vao->getVertexAttributes(); + const auto ¤tValues = glState.getVertexAttribCurrentValues(); - if (!validShader) + for (const sh::Attribute &shaderAttribute : program->getAttributes()) { - if (context->getProgram(id)) + // gl_VertexID and gl_InstanceID are active attributes but don't have a bound attribute. + if (shaderAttribute.isBuiltIn()) { - context->recordError( - Error(GL_INVALID_OPERATION, "Expected a shader name, but found a program name")); + continue; } - else + + GLenum shaderInputType = VariableComponentType(shaderAttribute.type); + + const auto &attrib = vertexAttribs[shaderAttribute.location]; + GLenum vertexType = attrib.enabled ? GetVertexAttributeBaseType(attrib) + : currentValues[shaderAttribute.location].Type; + + if (shaderInputType != GL_NONE && vertexType != GL_NONE && shaderInputType != vertexType) { - context->recordError(Error(GL_INVALID_VALUE, "Shader name is invalid")); + context->handleError(InvalidOperation() << "Vertex shader input type does not " + "match the type of the bound vertex " + "attribute."); + return false; } } - return validShader; + return true; } -bool ValidateAttachmentTarget(gl::Context *context, GLenum attachment) +} // anonymous namespace + +bool ValidTextureTarget(const ValidationContext *context, GLenum target) { - if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT) + switch (target) { - const unsigned int colorAttachment = (attachment - GL_COLOR_ATTACHMENT0_EXT); + case GL_TEXTURE_2D: + case GL_TEXTURE_CUBE_MAP: + return true; - 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_TEXTURE_RECTANGLE_ANGLE: + return context->getExtensions().textureRectangle; - case GL_DEPTH_STENCIL_ATTACHMENT: - if (context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } - break; + case GL_TEXTURE_3D: + case GL_TEXTURE_2D_ARRAY: + return (context->getClientMajorVersion() >= 3); - default: - context->recordError(Error(GL_INVALID_ENUM)); + case GL_TEXTURE_2D_MULTISAMPLE: + return (context->getClientVersion() >= Version(3, 1)); + + default: return false; - } } - - return true; } -bool ValidateRenderbufferStorageParametersBase(gl::Context *context, GLenum target, GLsizei samples, - GLenum internalformat, GLsizei width, GLsizei height) +bool ValidTexture2DTarget(const ValidationContext *context, GLenum target) { switch (target) { - case GL_RENDERBUFFER: - break; - default: - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } - + case GL_TEXTURE_2D: + case GL_TEXTURE_CUBE_MAP: + return true; + + case GL_TEXTURE_RECTANGLE_ANGLE: + return context->getExtensions().textureRectangle; + + default: + return false; + } +} + +bool ValidTexture3DTarget(const ValidationContext *context, GLenum target) +{ + switch (target) + { + case GL_TEXTURE_3D: + case GL_TEXTURE_2D_ARRAY: + return (context->getClientMajorVersion() >= 3); + + default: + return false; + } +} + +// Most texture GL calls are not compatible with external textures, so we have a separate validation +// function for use in the GL calls that do +bool ValidTextureExternalTarget(const ValidationContext *context, GLenum target) +{ + return (target == GL_TEXTURE_EXTERNAL_OES) && + (context->getExtensions().eglImageExternal || + context->getExtensions().eglStreamConsumerExternal); +} + +// 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 ValidationContext *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_RECTANGLE_ANGLE: + return context->getExtensions().textureRectangle; + default: + return false; + } +} + +bool ValidateDrawElementsInstancedBase(ValidationContext *context, + GLenum mode, + GLsizei count, + GLenum type, + const GLvoid *indices, + GLsizei primcount) +{ + if (primcount < 0) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), NegativePrimcount); + return false; + } + + if (!ValidateDrawElementsCommon(context, mode, count, type, indices, primcount)) + { + return false; + } + + // No-op zero primitive count + return (primcount > 0); +} + +bool ValidateDrawArraysInstancedBase(Context *context, + GLenum mode, + GLint first, + GLsizei count, + GLsizei primcount) +{ + if (primcount < 0) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), NegativePrimcount); + return false; + } + + if (!ValidateDrawArraysCommon(context, mode, first, count, primcount)) + { + return false; + } + + // No-op if zero primitive count + return (primcount > 0); +} + +bool ValidateDrawInstancedANGLE(ValidationContext *context) +{ + // Verify there is at least one active attribute with a divisor of zero + const State &state = context->getGLState(); + + Program *program = state.getProgram(); + + const auto &attribs = state.getVertexArray()->getVertexAttributes(); + const auto &bindings = state.getVertexArray()->getVertexBindings(); + for (size_t attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++) + { + const VertexAttribute &attrib = attribs[attributeIndex]; + const VertexBinding &binding = bindings[attrib.bindingIndex]; + if (program->isAttribLocationActive(attributeIndex) && binding.getDivisor() == 0) + { + return true; + } + } + + ANGLE_VALIDATION_ERR(context, InvalidOperation(), NoZeroDivisor); + return false; +} + +bool ValidTexture3DDestinationTarget(const ValidationContext *context, GLenum target) +{ + switch (target) + { + case GL_TEXTURE_3D: + case GL_TEXTURE_2D_ARRAY: + return true; + default: + return false; + } +} + +bool ValidTexLevelDestinationTarget(const ValidationContext *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: + case GL_TEXTURE_3D: + case GL_TEXTURE_2D_ARRAY: + case GL_TEXTURE_2D_MULTISAMPLE: + return true; + case GL_TEXTURE_RECTANGLE_ANGLE: + return context->getExtensions().textureRectangle; + default: + return false; + } +} + +bool ValidFramebufferTarget(const ValidationContext *context, 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: + case GL_DRAW_FRAMEBUFFER: + return (context->getExtensions().framebufferBlit || + context->getClientMajorVersion() >= 3); + + default: + return false; + } +} + +bool ValidBufferType(const ValidationContext *context, BufferBinding target) +{ + switch (target) + { + case BufferBinding::ElementArray: + case BufferBinding::Array: + return true; + + case BufferBinding::PixelPack: + case BufferBinding::PixelUnpack: + return (context->getExtensions().pixelBufferObject || + context->getClientMajorVersion() >= 3); + + case BufferBinding::CopyRead: + case BufferBinding::CopyWrite: + case BufferBinding::TransformFeedback: + case BufferBinding::Uniform: + return (context->getClientMajorVersion() >= 3); + + case BufferBinding::AtomicCounter: + case BufferBinding::ShaderStorage: + case BufferBinding::DrawIndirect: + case BufferBinding::DispatchIndirect: + return context->getClientVersion() >= Version(3, 1); + + default: + return false; + } +} + +bool ValidMipLevel(const ValidationContext *context, GLenum target, GLint level) +{ + const auto &caps = context->getCaps(); + size_t maxDimension = 0; + switch (target) + { + case GL_TEXTURE_2D: + maxDimension = caps.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 = caps.maxCubeMapTextureSize; + break; + case GL_TEXTURE_RECTANGLE_ANGLE: + return level == 0; + case GL_TEXTURE_3D: + maxDimension = caps.max3DTextureSize; + break; + case GL_TEXTURE_2D_ARRAY: + maxDimension = caps.max2DTextureSize; + break; + case GL_TEXTURE_2D_MULTISAMPLE: + maxDimension = caps.max2DTextureSize; + break; + default: + UNREACHABLE(); + } + + return level <= gl::log2(static_cast(maxDimension)) && level >= 0; +} + +bool ValidImageSizeParameters(ValidationContext *context, + GLenum target, + GLint level, + GLsizei width, + GLsizei height, + GLsizei depth, + bool isSubImage) +{ + if (width < 0 || height < 0 || depth < 0) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), NegativeSize); + return false; + } + // TexSubImage parameters can be NPOT without textureNPOT extension, + // as long as the destination texture is POT. + bool hasNPOTSupport = + context->getExtensions().textureNPOT || context->getClientVersion() >= Version(3, 0); + if (!isSubImage && !hasNPOTSupport && + (level != 0 && (!gl::isPow2(width) || !gl::isPow2(height) || !gl::isPow2(depth)))) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), TextureNotPow2); + return false; + } + + if (!ValidMipLevel(context, target, level)) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), InvalidMipLevel); + return false; + } + + return true; +} + +bool CompressedTextureFormatRequiresExactSize(GLenum internalFormat) +{ + // List of compressed format that require that the texture size is smaller than or a multiple of + // the compressed block size. + switch (internalFormat) + { + 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: + case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT: + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT: + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT: + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT: + case GL_ETC1_RGB8_LOSSY_DECODE_ANGLE: + case GL_COMPRESSED_RGB8_LOSSY_DECODE_ETC2_ANGLE: + case GL_COMPRESSED_SRGB8_LOSSY_DECODE_ETC2_ANGLE: + case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE: + case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE: + case GL_COMPRESSED_RGBA8_LOSSY_DECODE_ETC2_EAC_ANGLE: + case GL_COMPRESSED_SRGB8_ALPHA8_LOSSY_DECODE_ETC2_EAC_ANGLE: + return true; + + default: + return false; + } +} + +bool ValidCompressedDimension(GLsizei size, GLuint blockSize, bool smallerThanBlockSizeAllowed) +{ + return (smallerThanBlockSizeAllowed && (size > 0) && (blockSize % size == 0)) || + (size % blockSize == 0); +} + +bool ValidCompressedImageSize(const ValidationContext *context, + GLenum internalFormat, + GLint level, + GLsizei width, + GLsizei height) +{ + const gl::InternalFormat &formatInfo = gl::GetSizedInternalFormatInfo(internalFormat); + if (!formatInfo.compressed) + { + return false; + } + + if (width < 0 || height < 0) + { + return false; + } + + if (CompressedTextureFormatRequiresExactSize(internalFormat)) + { + // The ANGLE extensions allow specifying compressed textures with sizes smaller than the + // block size for level 0 but WebGL disallows this. + bool smallerThanBlockSizeAllowed = + level > 0 || !context->getExtensions().webglCompatibility; + + if (!ValidCompressedDimension(width, formatInfo.compressedBlockWidth, + smallerThanBlockSizeAllowed) || + !ValidCompressedDimension(height, formatInfo.compressedBlockHeight, + smallerThanBlockSizeAllowed)) + { + return false; + } + } + + return true; +} + +bool ValidCompressedSubImageSize(const ValidationContext *context, + GLenum internalFormat, + GLint xoffset, + GLint yoffset, + GLsizei width, + GLsizei height, + size_t textureWidth, + size_t textureHeight) +{ + const gl::InternalFormat &formatInfo = gl::GetSizedInternalFormatInfo(internalFormat); + if (!formatInfo.compressed) + { + return false; + } + + if (xoffset < 0 || yoffset < 0 || width < 0 || height < 0) + { + return false; + } + + if (CompressedTextureFormatRequiresExactSize(internalFormat)) + { + if (xoffset % formatInfo.compressedBlockWidth != 0 || + yoffset % formatInfo.compressedBlockHeight != 0) + { + return false; + } + + // Allowed to either have data that is a multiple of block size or is smaller than the block + // size but fills the entire mip + bool fillsEntireMip = xoffset == 0 && yoffset == 0 && + static_cast(width) == textureWidth && + static_cast(height) == textureHeight; + bool sizeMultipleOfBlockSize = (width % formatInfo.compressedBlockWidth) == 0 && + (height % formatInfo.compressedBlockHeight) == 0; + if (!sizeMultipleOfBlockSize && !fillsEntireMip) + { + return false; + } + } + + return true; +} + +bool ValidImageDataSize(ValidationContext *context, + GLenum textureTarget, + GLsizei width, + GLsizei height, + GLsizei depth, + GLenum format, + GLenum type, + const void *pixels, + GLsizei imageSize) +{ + gl::Buffer *pixelUnpackBuffer = + context->getGLState().getTargetBuffer(BufferBinding::PixelUnpack); + if (pixelUnpackBuffer == nullptr && imageSize < 0) + { + // Checks are not required + return true; + } + + // ...the data would be unpacked from the buffer object such that the memory reads required + // would exceed the data store size. + const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format, type); + ASSERT(formatInfo.internalFormat != GL_NONE); + const gl::Extents size(width, height, depth); + const auto &unpack = context->getGLState().getUnpackState(); + + bool targetIs3D = textureTarget == GL_TEXTURE_3D || textureTarget == GL_TEXTURE_2D_ARRAY; + auto endByteOrErr = formatInfo.computePackUnpackEndByte(type, size, unpack, targetIs3D); + if (endByteOrErr.isError()) + { + context->handleError(endByteOrErr.getError()); + return false; + } + + GLuint endByte = endByteOrErr.getResult(); + + if (pixelUnpackBuffer) + { + CheckedNumeric checkedEndByte(endByteOrErr.getResult()); + CheckedNumeric checkedOffset(reinterpret_cast(pixels)); + checkedEndByte += checkedOffset; + + if (!checkedEndByte.IsValid() || + (checkedEndByte.ValueOrDie() > static_cast(pixelUnpackBuffer->getSize()))) + { + // Overflow past the end of the buffer + context->handleError(InvalidOperation()); + return false; + } + } + else + { + ASSERT(imageSize >= 0); + if (pixels == nullptr && imageSize != 0) + { + context->handleError(InvalidOperation() + << "imageSize must be 0 if no texture data is provided."); + return false; + } + + if (pixels != nullptr && endByte > static_cast(imageSize)) + { + context->handleError(InvalidOperation() << "imageSize must be at least " << endByte); + 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 context->getClientMajorVersion() >= 3 || + context->getExtensions().occlusionQueryBoolean; + case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN: + return (context->getClientMajorVersion() >= 3); + case GL_TIME_ELAPSED_EXT: + return context->getExtensions().disjointTimerQuery; + case GL_COMMANDS_COMPLETED_CHROMIUM: + return context->getExtensions().syncQuery; + default: + return false; + } +} + +bool ValidateWebGLVertexAttribPointer(ValidationContext *context, + GLenum type, + GLboolean normalized, + GLsizei stride, + const void *ptr, + bool pureInteger) +{ + ASSERT(context->getExtensions().webglCompatibility); + // WebGL 1.0 [Section 6.11] Vertex Attribute Data Stride + // The WebGL API supports vertex attribute data strides up to 255 bytes. A call to + // vertexAttribPointer will generate an INVALID_VALUE error if the value for the stride + // parameter exceeds 255. + constexpr GLsizei kMaxWebGLStride = 255; + if (stride > kMaxWebGLStride) + { + context->handleError(InvalidValue() + << "Stride is over the maximum stride allowed by WebGL."); + return false; + } + + // WebGL 1.0 [Section 6.4] Buffer Offset and Stride Requirements + // The offset arguments to drawElements and vertexAttribPointer, and the stride argument to + // vertexAttribPointer, must be a multiple of the size of the data type passed to the call, + // or an INVALID_OPERATION error is generated. + VertexFormatType internalType = GetVertexFormatType(type, normalized, 1, pureInteger); + size_t typeSize = GetVertexFormatTypeSize(internalType); + + ASSERT(isPow2(typeSize) && typeSize > 0); + size_t sizeMask = (typeSize - 1); + if ((reinterpret_cast(ptr) & sizeMask) != 0) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), OffsetMustBeMultipleOfType); + return false; + } + + if ((stride & sizeMask) != 0) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), StrideMustBeMultipleOfType); + return false; + } + + return true; +} + +Program *GetValidProgram(ValidationContext *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." + + Program *validProgram = context->getProgram(id); + + if (!validProgram) + { + if (context->getShader(id)) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ExpectedProgramName); + } + else + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), InvalidProgramName); + } + } + + return validProgram; +} + +Shader *GetValidShader(ValidationContext *context, GLuint id) +{ + // See ValidProgram for spec details. + + Shader *validShader = context->getShader(id); + + if (!validShader) + { + if (context->getProgram(id)) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ExpectedShaderName); + } + else + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), InvalidShaderName); + } + } + + return validShader; +} + +bool ValidateAttachmentTarget(gl::Context *context, GLenum attachment) +{ + if (attachment >= GL_COLOR_ATTACHMENT1_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT) + { + if (context->getClientMajorVersion() < 3 && !context->getExtensions().drawBuffers) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidAttachment); + return false; + } + + // Color attachment 0 is validated below because it is always valid + const unsigned int colorAttachment = (attachment - GL_COLOR_ATTACHMENT0_EXT); + if (colorAttachment >= context->getCaps().maxColorAttachments) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), InvalidAttachment); + return false; + } + } + else + { + switch (attachment) + { + case GL_COLOR_ATTACHMENT0: + case GL_DEPTH_ATTACHMENT: + case GL_STENCIL_ATTACHMENT: + break; + + case GL_DEPTH_STENCIL_ATTACHMENT: + if (!context->getExtensions().webglCompatibility && + context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidAttachment); + return false; + } + break; + + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidAttachment); + return false; + } + } + + return true; +} + +bool ValidateRenderbufferStorageParametersBase(ValidationContext *context, + GLenum target, + GLsizei samples, + GLenum internalformat, + GLsizei width, + GLsizei height) +{ + switch (target) + { + case GL_RENDERBUFFER: + break; + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidRenderbufferTarget); + return false; + } + if (width < 0 || height < 0 || samples < 0) { - context->recordError(Error(GL_INVALID_VALUE)); + ANGLE_VALIDATION_ERR(context, InvalidValue(), InvalidRenderbufferWidthHeight); + return false; + } + + // Hack for the special WebGL 1 "DEPTH_STENCIL" internal format. + GLenum convertedInternalFormat = context->getConvertedRenderbufferFormat(internalformat); + + const TextureCaps &formatCaps = context->getTextureCaps().get(convertedInternalFormat); + if (!formatCaps.renderable) + { + context->handleError(InvalidEnum()); + 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::GetSizedInternalFormatInfo(convertedInternalFormat); + if (formatInfo.internalFormat == GL_NONE) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidRenderbufferInternalFormat); + return false; + } + + if (static_cast(std::max(width, height)) > context->getCaps().maxRenderbufferSize) + { + context->handleError(InvalidValue()); + return false; + } + + GLuint handle = context->getGLState().getRenderbufferId(); + if (handle == 0) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), InvalidRenderbufferTarget); + return false; + } + + return true; +} + +bool ValidateFramebufferRenderbufferParameters(gl::Context *context, + GLenum target, + GLenum attachment, + GLenum renderbuffertarget, + GLuint renderbuffer) +{ + if (!ValidFramebufferTarget(context, target)) + { + context->handleError(InvalidEnum()); + return false; + } + + gl::Framebuffer *framebuffer = context->getGLState().getTargetFramebuffer(target); + + ASSERT(framebuffer); + if (framebuffer->id() == 0) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), DefaultFramebufferTarget); + 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)) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), InvalidRenderbufferTarget); + return false; + } + } + + return true; +} + +bool ValidateBlitFramebufferParameters(ValidationContext *context, + GLint srcX0, + GLint srcY0, + GLint srcX1, + GLint srcY1, + GLint dstX0, + GLint dstY0, + GLint dstX1, + GLint dstY1, + GLbitfield mask, + GLenum filter) +{ + switch (filter) + { + case GL_NEAREST: + break; + case GL_LINEAR: + break; + default: + context->handleError(InvalidEnum()); + return false; + } + + if ((mask & ~(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)) != 0) + { + context->handleError(InvalidValue()); + 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; + } + + // 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->handleError(InvalidOperation()); + return false; + } + + const auto &glState = context->getGLState(); + gl::Framebuffer *readFramebuffer = glState.getReadFramebuffer(); + gl::Framebuffer *drawFramebuffer = glState.getDrawFramebuffer(); + + if (!readFramebuffer || !drawFramebuffer) + { + context->handleError(InvalidFramebufferOperation()); + return false; + } + + if (readFramebuffer->id() == drawFramebuffer->id()) + { + context->handleError(InvalidOperation()); + return false; + } + + if (readFramebuffer->checkStatus(context) != GL_FRAMEBUFFER_COMPLETE) + { + context->handleError(InvalidFramebufferOperation()); + return false; + } + + if (drawFramebuffer->checkStatus(context) != GL_FRAMEBUFFER_COMPLETE) + { + context->handleError(InvalidFramebufferOperation()); + return false; + } + + if (drawFramebuffer->getSamples(context) != 0) + { + context->handleError(InvalidOperation()); + return false; + } + + bool sameBounds = srcX0 == dstX0 && srcY0 == dstY0 && srcX1 == dstX1 && srcY1 == dstY1; + + if (mask & GL_COLOR_BUFFER_BIT) + { + const gl::FramebufferAttachment *readColorBuffer = readFramebuffer->getReadColorbuffer(); + const Extensions &extensions = context->getExtensions(); + + if (readColorBuffer) + { + const Format &readFormat = readColorBuffer->getFormat(); + + for (size_t drawbufferIdx = 0; + drawbufferIdx < drawFramebuffer->getDrawbufferStateCount(); ++drawbufferIdx) + { + const FramebufferAttachment *attachment = + drawFramebuffer->getDrawBuffer(drawbufferIdx); + if (attachment) + { + const Format &drawFormat = attachment->getFormat(); + + // 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 + // Changes with EXT_color_buffer_float: + // Case 1) is changed to fixed point OR floating point + GLenum readComponentType = readFormat.info->componentType; + GLenum drawComponentType = drawFormat.info->componentType; + bool readFixedPoint = (readComponentType == GL_UNSIGNED_NORMALIZED || + readComponentType == GL_SIGNED_NORMALIZED); + bool drawFixedPoint = (drawComponentType == GL_UNSIGNED_NORMALIZED || + drawComponentType == GL_SIGNED_NORMALIZED); + + if (extensions.colorBufferFloat) + { + bool readFixedOrFloat = (readFixedPoint || readComponentType == GL_FLOAT); + bool drawFixedOrFloat = (drawFixedPoint || drawComponentType == GL_FLOAT); + + if (readFixedOrFloat != drawFixedOrFloat) + { + context->handleError(InvalidOperation() + << "If the read buffer contains fixed-point or " + "floating-point values, the draw buffer must " + "as well."); + return false; + } + } + else if (readFixedPoint != drawFixedPoint) + { + context->handleError(InvalidOperation() + << "If the read buffer contains fixed-point values, " + "the draw buffer must as well."); + return false; + } + + if (readComponentType == GL_UNSIGNED_INT && + drawComponentType != GL_UNSIGNED_INT) + { + context->handleError(InvalidOperation()); + return false; + } + + if (readComponentType == GL_INT && drawComponentType != GL_INT) + { + context->handleError(InvalidOperation()); + return false; + } + + if (readColorBuffer->getSamples() > 0 && + (!Format::EquivalentForBlit(readFormat, drawFormat) || !sameBounds)) + { + context->handleError(InvalidOperation()); + return false; + } + + if (context->getExtensions().webglCompatibility && + *readColorBuffer == *attachment) + { + context->handleError( + InvalidOperation() + << "Read and write color attachments cannot be the same image."); + return false; + } + } + } + + if ((readFormat.info->componentType == GL_INT || + readFormat.info->componentType == GL_UNSIGNED_INT) && + filter == GL_LINEAR) + { + context->handleError(InvalidOperation()); + return false; + } + } + // WebGL 2.0 BlitFramebuffer when blitting from a missing attachment + // In OpenGL ES it is undefined what happens when an operation tries to blit from a missing + // attachment and WebGL defines it to be an error. We do the check unconditionally as the + // situation is an application error that would lead to a crash in ANGLE. + else if (drawFramebuffer->hasEnabledDrawBuffer()) + { + context->handleError( + InvalidOperation() + << "Attempt to read from a missing color attachment of a complete framebuffer."); + 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]) + { + const gl::FramebufferAttachment *readBuffer = + readFramebuffer->getAttachment(attachments[i]); + const gl::FramebufferAttachment *drawBuffer = + drawFramebuffer->getAttachment(attachments[i]); + + if (readBuffer && drawBuffer) + { + if (!Format::EquivalentForBlit(readBuffer->getFormat(), drawBuffer->getFormat())) + { + context->handleError(InvalidOperation()); + return false; + } + + if (readBuffer->getSamples() > 0 && !sameBounds) + { + context->handleError(InvalidOperation()); + return false; + } + + if (context->getExtensions().webglCompatibility && *readBuffer == *drawBuffer) + { + context->handleError( + InvalidOperation() + << "Read and write depth stencil attachments cannot be the same image."); + return false; + } + } + // WebGL 2.0 BlitFramebuffer when blitting from a missing attachment + else if (drawBuffer) + { + context->handleError(InvalidOperation() << "Attempt to read from a missing " + "depth/stencil attachment of a " + "complete framebuffer."); + return false; + } + } + } + + // ANGLE_multiview, Revision 1: + // Calling BlitFramebuffer will result in an INVALID_FRAMEBUFFER_OPERATION error if the + // multi-view layout of the current draw framebuffer or read framebuffer is not NONE. + if (readFramebuffer->getMultiviewLayout() != GL_NONE) + { + context->handleError(InvalidFramebufferOperation() + << "Attempt to read from a multi-view framebuffer."); + return false; + } + if (drawFramebuffer->getMultiviewLayout() != GL_NONE) + { + context->handleError(InvalidFramebufferOperation() + << "Attempt to write to a multi-view framebuffer."); + return false; + } + + return true; +} + +bool ValidateReadPixelsRobustANGLE(Context *context, + GLint x, + GLint y, + GLsizei width, + GLsizei height, + GLenum format, + GLenum type, + GLsizei bufSize, + GLsizei *length, + GLsizei *columns, + GLsizei *rows, + void *pixels) +{ + if (!ValidateRobustEntryPoint(context, bufSize)) + { + return false; + } + + if (!ValidateReadPixelsBase(context, x, y, width, height, format, type, bufSize, length, + columns, rows, pixels)) + { + return false; + } + + if (!ValidateRobustBufferSize(context, bufSize, *length)) + { + return false; + } + + return true; +} + +bool ValidateReadnPixelsEXT(Context *context, + GLint x, + GLint y, + GLsizei width, + GLsizei height, + GLenum format, + GLenum type, + GLsizei bufSize, + void *pixels) +{ + if (bufSize < 0) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), NegativeBufferSize); + return false; + } + + return ValidateReadPixelsBase(context, x, y, width, height, format, type, bufSize, nullptr, + nullptr, nullptr, pixels); +} + +bool ValidateReadnPixelsRobustANGLE(Context *context, + GLint x, + GLint y, + GLsizei width, + GLsizei height, + GLenum format, + GLenum type, + GLsizei bufSize, + GLsizei *length, + GLsizei *columns, + GLsizei *rows, + void *data) +{ + if (!ValidateRobustEntryPoint(context, bufSize)) + { + return false; + } + + if (!ValidateReadPixelsBase(context, x, y, width, height, format, type, bufSize, length, + columns, rows, data)) + { + return false; + } + + if (!ValidateRobustBufferSize(context, bufSize, *length)) + { + return false; + } + + return true; +} + +bool ValidateGenQueriesEXT(gl::Context *context, GLsizei n, GLuint *ids) +{ + if (!context->getExtensions().occlusionQueryBoolean && + !context->getExtensions().disjointTimerQuery) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), QueryExtensionNotEnabled); + return false; + } + + return ValidateGenOrDelete(context, n); +} + +bool ValidateDeleteQueriesEXT(gl::Context *context, GLsizei n, const GLuint *ids) +{ + if (!context->getExtensions().occlusionQueryBoolean && + !context->getExtensions().disjointTimerQuery) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), QueryExtensionNotEnabled); + return false; + } + + return ValidateGenOrDelete(context, n); +} + +bool ValidateIsQueryEXT(gl::Context *context, GLuint id) +{ + if (!context->getExtensions().occlusionQueryBoolean && + !context->getExtensions().disjointTimerQuery) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), QueryExtensionNotEnabled); + return false; + } + + return true; +} + +bool ValidateBeginQueryBase(gl::Context *context, GLenum target, GLuint id) +{ + if (!ValidQueryType(context, target)) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidQueryType); + return false; + } + + if (id == 0) + { + context->handleError(InvalidOperation() << "Query id is 0"); + 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->getGLState().isQueryActive(target)) + { + context->handleError(InvalidOperation() << "Other query is active"); + return false; + } + + Query *queryObject = context->getQuery(id, true, target); + + // check that name was obtained with glGenQueries + if (!queryObject) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), InvalidQueryId); + return false; + } + + // check for type mismatch + if (queryObject->getType() != target) + { + context->handleError(InvalidOperation() << "Query type does not match target"); + return false; + } + + return true; +} + +bool ValidateBeginQueryEXT(gl::Context *context, GLenum target, GLuint id) +{ + if (!context->getExtensions().occlusionQueryBoolean && + !context->getExtensions().disjointTimerQuery && !context->getExtensions().syncQuery) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), QueryExtensionNotEnabled); + return false; + } + + return ValidateBeginQueryBase(context, target, id); +} + +bool ValidateEndQueryBase(gl::Context *context, GLenum target) +{ + if (!ValidQueryType(context, target)) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidQueryType); + return false; + } + + const Query *queryObject = context->getGLState().getActiveQuery(target); + + if (queryObject == nullptr) + { + context->handleError(InvalidOperation() << "Query target not active"); + return false; + } + + return true; +} + +bool ValidateEndQueryEXT(gl::Context *context, GLenum target) +{ + if (!context->getExtensions().occlusionQueryBoolean && + !context->getExtensions().disjointTimerQuery && !context->getExtensions().syncQuery) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), QueryExtensionNotEnabled); + return false; + } + + return ValidateEndQueryBase(context, target); +} + +bool ValidateQueryCounterEXT(Context *context, GLuint id, GLenum target) +{ + if (!context->getExtensions().disjointTimerQuery) + { + context->handleError(InvalidOperation() << "Disjoint timer query not enabled"); + return false; + } + + if (target != GL_TIMESTAMP_EXT) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidQueryTarget); + return false; + } + + Query *queryObject = context->getQuery(id, true, target); + if (queryObject == nullptr) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), InvalidQueryId); + return false; + } + + if (context->getGLState().isQueryActive(queryObject)) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), QueryActive); + return false; + } + + return true; +} + +bool ValidateGetQueryivBase(Context *context, GLenum target, GLenum pname, GLsizei *numParams) +{ + if (numParams) + { + *numParams = 0; + } + + if (!ValidQueryType(context, target) && target != GL_TIMESTAMP_EXT) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidQueryType); + return false; + } + + switch (pname) + { + case GL_CURRENT_QUERY_EXT: + if (target == GL_TIMESTAMP_EXT) + { + context->handleError(InvalidEnum() << "Cannot use current query for timestamp"); + return false; + } + break; + case GL_QUERY_COUNTER_BITS_EXT: + if (!context->getExtensions().disjointTimerQuery || + (target != GL_TIMESTAMP_EXT && target != GL_TIME_ELAPSED_EXT)) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidPname); + return false; + } + break; + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidPname); + return false; + } + + if (numParams) + { + // All queries return only one value + *numParams = 1; + } + + return true; +} + +bool ValidateGetQueryivEXT(Context *context, GLenum target, GLenum pname, GLint *params) +{ + if (!context->getExtensions().occlusionQueryBoolean && + !context->getExtensions().disjointTimerQuery && !context->getExtensions().syncQuery) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ExtensionNotEnabled); + return false; + } + + return ValidateGetQueryivBase(context, target, pname, nullptr); +} + +bool ValidateGetQueryivRobustANGLE(Context *context, + GLenum target, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLint *params) +{ + if (!ValidateRobustEntryPoint(context, bufSize)) + { + return false; + } + + if (!ValidateGetQueryivBase(context, target, pname, length)) + { + return false; + } + + if (!ValidateRobustBufferSize(context, bufSize, *length)) + { + return false; + } + + return true; +} + +bool ValidateGetQueryObjectValueBase(Context *context, GLuint id, GLenum pname, GLsizei *numParams) +{ + if (numParams) + { + *numParams = 0; + } + + Query *queryObject = context->getQuery(id, false, GL_NONE); + + if (!queryObject) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), InvalidQueryId); + return false; + } + + if (context->getGLState().isQueryActive(queryObject)) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), QueryActive); + return false; + } + + switch (pname) + { + case GL_QUERY_RESULT_EXT: + case GL_QUERY_RESULT_AVAILABLE_EXT: + break; + + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), EnumNotSupported); + return false; + } + + if (numParams) + { + *numParams = 1; + } + + return true; +} + +bool ValidateGetQueryObjectivEXT(Context *context, GLuint id, GLenum pname, GLint *params) +{ + if (!context->getExtensions().disjointTimerQuery) + { + context->handleError(InvalidOperation() << "Timer query extension not enabled"); + return false; + } + return ValidateGetQueryObjectValueBase(context, id, pname, nullptr); +} + +bool ValidateGetQueryObjectivRobustANGLE(Context *context, + GLuint id, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLint *params) +{ + if (!context->getExtensions().disjointTimerQuery) + { + context->handleError(InvalidOperation() << "Timer query extension not enabled"); + return false; + } + + if (!ValidateRobustEntryPoint(context, bufSize)) + { + return false; + } + + if (!ValidateGetQueryObjectValueBase(context, id, pname, length)) + { + return false; + } + + if (!ValidateRobustBufferSize(context, bufSize, *length)) + { + return false; + } + + return true; +} + +bool ValidateGetQueryObjectuivEXT(Context *context, GLuint id, GLenum pname, GLuint *params) +{ + if (!context->getExtensions().disjointTimerQuery && + !context->getExtensions().occlusionQueryBoolean && !context->getExtensions().syncQuery) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ExtensionNotEnabled); + return false; + } + return ValidateGetQueryObjectValueBase(context, id, pname, nullptr); +} + +bool ValidateGetQueryObjectuivRobustANGLE(Context *context, + GLuint id, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLuint *params) +{ + if (!context->getExtensions().disjointTimerQuery && + !context->getExtensions().occlusionQueryBoolean && !context->getExtensions().syncQuery) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ExtensionNotEnabled); + return false; + } + + if (!ValidateRobustEntryPoint(context, bufSize)) + { + return false; + } + + if (!ValidateGetQueryObjectValueBase(context, id, pname, length)) + { + return false; + } + + if (!ValidateRobustBufferSize(context, bufSize, *length)) + { + return false; + } + + return true; +} + +bool ValidateGetQueryObjecti64vEXT(Context *context, GLuint id, GLenum pname, GLint64 *params) +{ + if (!context->getExtensions().disjointTimerQuery) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ExtensionNotEnabled); + return false; + } + return ValidateGetQueryObjectValueBase(context, id, pname, nullptr); +} + +bool ValidateGetQueryObjecti64vRobustANGLE(Context *context, + GLuint id, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLint64 *params) +{ + if (!context->getExtensions().disjointTimerQuery) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ExtensionNotEnabled); + return false; + } + + if (!ValidateRobustEntryPoint(context, bufSize)) + { + return false; + } + + if (!ValidateGetQueryObjectValueBase(context, id, pname, length)) + { + return false; + } + + if (!ValidateRobustBufferSize(context, bufSize, *length)) + { + return false; + } + + return true; +} + +bool ValidateGetQueryObjectui64vEXT(Context *context, GLuint id, GLenum pname, GLuint64 *params) +{ + if (!context->getExtensions().disjointTimerQuery) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ExtensionNotEnabled); + return false; + } + return ValidateGetQueryObjectValueBase(context, id, pname, nullptr); +} + +bool ValidateGetQueryObjectui64vRobustANGLE(Context *context, + GLuint id, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLuint64 *params) +{ + if (!context->getExtensions().disjointTimerQuery) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ExtensionNotEnabled); + return false; + } + + if (!ValidateRobustEntryPoint(context, bufSize)) + { + return false; + } + + if (!ValidateGetQueryObjectValueBase(context, id, pname, length)) + { + return false; + } + + if (!ValidateRobustBufferSize(context, bufSize, *length)) + { + return false; + } + + return true; +} + +bool ValidateUniformCommonBase(ValidationContext *context, + gl::Program *program, + GLint location, + GLsizei count, + const LinkedUniform **uniformOut) +{ + // TODO(Jiajia): Add image uniform check in future. + if (count < 0) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), NegativeCount); + return false; + } + + if (!program) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), InvalidProgramName); + return false; + } + + if (!program->isLinked()) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ProgramNotLinked); + return false; + } + + if (location == -1) + { + // Silently ignore the uniform command + return false; + } + + const auto &uniformLocations = program->getUniformLocations(); + size_t castedLocation = static_cast(location); + if (castedLocation >= uniformLocations.size()) + { + context->handleError(InvalidOperation() << "Invalid uniform location"); + return false; + } + + const auto &uniformLocation = uniformLocations[castedLocation]; + if (uniformLocation.ignored) + { + // Silently ignore the uniform command + return false; + } + + if (!uniformLocation.used()) + { + context->handleError(InvalidOperation()); + return false; + } + + const auto &uniform = program->getUniformByIndex(uniformLocation.index); + + // attempting to write an array to a non-array uniform is an INVALID_OPERATION + if (!uniform.isArray() && count > 1) + { + context->handleError(InvalidOperation()); + return false; + } + + *uniformOut = &uniform; + return true; +} + +bool ValidateUniform1ivValue(ValidationContext *context, + GLenum uniformType, + GLsizei count, + const GLint *value) +{ + // Value type is GL_INT, because we only get here from glUniform1i{v}. + // It is compatible with INT or BOOL. + // Do these cheap tests first, for a little extra speed. + if (GL_INT == uniformType || GL_BOOL == uniformType) + { + return true; + } + + if (IsSamplerType(uniformType)) + { + // Check that the values are in range. + const GLint max = context->getCaps().maxCombinedTextureImageUnits; + for (GLsizei i = 0; i < count; ++i) + { + if (value[i] < 0 || value[i] >= max) + { + context->handleError(InvalidValue() << "sampler uniform value out of range"); + return false; + } + } + return true; + } + + context->handleError(InvalidOperation() << "wrong type of value for uniform"); + return false; +} + +bool ValidateUniformValue(ValidationContext *context, GLenum valueType, GLenum uniformType) +{ + // Check that the value type is compatible with uniform type. + // Do the cheaper test first, for a little extra speed. + if (valueType == uniformType || VariableBoolVectorType(valueType) == uniformType) + { + return true; + } + + ANGLE_VALIDATION_ERR(context, InvalidOperation(), UniformSizeMismatch); + return false; +} + +bool ValidateUniformMatrixValue(ValidationContext *context, GLenum valueType, GLenum uniformType) +{ + // Check that the value type is compatible with uniform type. + if (valueType == uniformType) + { + return true; + } + + context->handleError(InvalidOperation() << "wrong type of value for uniform"); + return false; +} + +bool ValidateUniform(ValidationContext *context, GLenum valueType, GLint location, GLsizei count) +{ + const LinkedUniform *uniform = nullptr; + gl::Program *programObject = context->getGLState().getProgram(); + return ValidateUniformCommonBase(context, programObject, location, count, &uniform) && + ValidateUniformValue(context, valueType, uniform->type); +} + +bool ValidateUniform1iv(ValidationContext *context, + GLint location, + GLsizei count, + const GLint *value) +{ + const LinkedUniform *uniform = nullptr; + gl::Program *programObject = context->getGLState().getProgram(); + return ValidateUniformCommonBase(context, programObject, location, count, &uniform) && + ValidateUniform1ivValue(context, uniform->type, count, value); +} + +bool ValidateUniformMatrix(ValidationContext *context, + GLenum valueType, + GLint location, + GLsizei count, + GLboolean transpose) +{ + if (ConvertToBool(transpose) && context->getClientMajorVersion() < 3) + { + context->handleError(InvalidValue()); + return false; + } + + const LinkedUniform *uniform = nullptr; + gl::Program *programObject = context->getGLState().getProgram(); + return ValidateUniformCommonBase(context, programObject, location, count, &uniform) && + ValidateUniformMatrixValue(context, valueType, uniform->type); +} + +bool ValidateStateQuery(ValidationContext *context, + GLenum pname, + GLenum *nativeType, + unsigned int *numParams) +{ + if (!context->getQueryParameterInfo(pname, nativeType, numParams)) + { + context->handleError(InvalidEnum()); + 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->handleError(InvalidOperation()); + 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: + case GL_TEXTURE_BINDING_2D_MULTISAMPLE: + break; + case GL_TEXTURE_BINDING_RECTANGLE_ANGLE: + if (!context->getExtensions().textureRectangle) + { + context->handleError(InvalidEnum() + << "ANGLE_texture_rectangle extension not present"); + return false; + } + break; + case GL_TEXTURE_BINDING_EXTERNAL_OES: + if (!context->getExtensions().eglStreamConsumerExternal && + !context->getExtensions().eglImageExternal) + { + context->handleError(InvalidEnum() << "Neither NV_EGL_stream_consumer_external " + "nor GL_OES_EGL_image_external " + "extensions enabled"); + return false; + } + break; + + case GL_IMPLEMENTATION_COLOR_READ_TYPE: + case GL_IMPLEMENTATION_COLOR_READ_FORMAT: + { + if (context->getGLState().getReadFramebuffer()->checkStatus(context) != + GL_FRAMEBUFFER_COMPLETE) + { + context->handleError(InvalidOperation()); + return false; + } + + const Framebuffer *framebuffer = context->getGLState().getReadFramebuffer(); + ASSERT(framebuffer); + + if (framebuffer->getReadBufferState() == GL_NONE) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ReadBufferNone); + return false; + } + + const FramebufferAttachment *attachment = framebuffer->getReadColorbuffer(); + if (!attachment) + { + context->handleError(InvalidOperation()); + return false; + } + } + break; + + default: + break; + } + + // pname is valid, but there are no parameters to return + if (*numParams == 0) + { + return false; + } + + return true; +} + +bool ValidateRobustStateQuery(ValidationContext *context, + GLenum pname, + GLsizei bufSize, + GLenum *nativeType, + unsigned int *numParams) +{ + if (!ValidateRobustEntryPoint(context, bufSize)) + { + return false; + } + + if (!ValidateStateQuery(context, pname, nativeType, numParams)) + { + return false; + } + + if (!ValidateRobustBufferSize(context, bufSize, *numParams)) + { + return false; + } + + return true; +} + +bool ValidateCopyTexImageParametersBase(ValidationContext *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, + Format *textureFormatOut) +{ + if (xoffset < 0 || yoffset < 0 || zoffset < 0) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), NegativeOffset); + return false; + } + + if (width < 0 || height < 0) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), NegativeSize); + return false; + } + + if (std::numeric_limits::max() - xoffset < width || + std::numeric_limits::max() - yoffset < height) + { + context->handleError(InvalidValue()); + return false; + } + + if (border != 0) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), InvalidBorder); + return false; + } + + if (!ValidMipLevel(context, target, level)) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), InvalidMipLevel); + return false; + } + + const auto &state = context->getGLState(); + Framebuffer *readFramebuffer = state.getReadFramebuffer(); + if (readFramebuffer->checkStatus(context) != GL_FRAMEBUFFER_COMPLETE) + { + context->handleError(InvalidFramebufferOperation()); + return false; + } + + if (readFramebuffer->id() != 0 && readFramebuffer->getSamples(context) != 0) + { + context->handleError(InvalidOperation()); + return false; + } + + if (readFramebuffer->getReadBufferState() == GL_NONE) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ReadBufferNone); + return false; + } + + // WebGL 1.0 [Section 6.26] Reading From a Missing Attachment + // In OpenGL ES it is undefined what happens when an operation tries to read from a missing + // attachment and WebGL defines it to be an error. We do the check unconditionally as the + // situation is an application error that would lead to a crash in ANGLE. + const FramebufferAttachment *source = readFramebuffer->getReadColorbuffer(); + if (source == nullptr) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), MissingReadAttachment); + return false; + } + + // ANGLE_multiview spec, Revision 1: + // Calling CopyTexSubImage3D, CopyTexImage2D, or CopyTexSubImage2D will result in an + // INVALID_FRAMEBUFFER_OPERATION error if the multi-view layout of the current read framebuffer + // is not NONE. + if (source->getMultiviewLayout() != GL_NONE) + { + context->handleError(InvalidFramebufferOperation() + << "The active read framebuffer object has multiview attachments."); + 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_RECTANGLE_ANGLE: + maxDimension = caps.maxRectangleTextureSize; + break; + + case GL_TEXTURE_2D_ARRAY: + maxDimension = caps.max2DTextureSize; + break; + + case GL_TEXTURE_3D: + maxDimension = caps.max3DTextureSize; + break; + + default: + context->handleError(InvalidEnum()); + return false; + } + + gl::Texture *texture = + state.getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target); + if (!texture) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), TextureNotBound); + return false; + } + + if (texture->getImmutableFormat() && !isSubImage) + { + context->handleError(InvalidOperation()); + return false; + } + + const gl::InternalFormat &formatInfo = + isSubImage ? *texture->getFormat(target, level).info + : gl::GetInternalFormatInfo(internalformat, GL_UNSIGNED_BYTE); + + if (formatInfo.depthBits > 0 || formatInfo.compressed) + { + context->handleError(InvalidOperation()); + 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->handleError(InvalidValue()); + return false; + } + } + else + { + if (IsCubeMapTextureTarget(target) && width != height) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), CubemapIncomplete); + return false; + } + + if (!formatInfo.textureSupport(context->getClientVersion(), context->getExtensions())) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), EnumNotSupported); + return false; + } + + int maxLevelDimension = (maxDimension >> level); + if (static_cast(width) > maxLevelDimension || + static_cast(height) > maxLevelDimension) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), ResourceMaxTextureSize); + return false; + } + } + + if (textureFormatOut) + { + *textureFormatOut = texture->getFormat(target, level); + } + + // Detect texture copying feedback loops for WebGL. + if (context->getExtensions().webglCompatibility) + { + if (readFramebuffer->formsCopyingFeedbackLoopWith(texture->id(), level, zoffset)) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), FeedbackLoop); + return false; + } + } + + return true; +} + +bool ValidateDrawBase(ValidationContext *context, GLenum mode, GLsizei count) +{ + 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: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidDrawMode); + return false; + } + + if (count < 0) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), NegativeCount); + return false; + } + + const State &state = context->getGLState(); + + const Extensions &extensions = context->getExtensions(); + + // WebGL buffers cannot be mapped/unmapped because the MapBufferRange, FlushMappedBufferRange, + // and UnmapBuffer entry points are removed from the WebGL 2.0 API. + // https://www.khronos.org/registry/webgl/specs/latest/2.0/#5.14 + if (!extensions.webglCompatibility) + { + // Check for mapped buffers + // TODO(jmadill): Optimize this check for non - WebGL contexts. + if (state.hasMappedBuffer(BufferBinding::Array)) + { + context->handleError(InvalidOperation()); + return false; + } + } + + // Note: these separate values are not supported in WebGL, due to D3D's limitations. See + // Section 6.10 of the WebGL 1.0 spec. + Framebuffer *framebuffer = state.getDrawFramebuffer(); + if (context->getLimitations().noSeparateStencilRefsAndMasks || extensions.webglCompatibility) + { + const FramebufferAttachment *dsAttachment = + framebuffer->getStencilOrDepthStencilAttachment(); + GLuint stencilBits = dsAttachment ? dsAttachment->getStencilSize() : 0; + GLuint minimumRequiredStencilMask = (1 << stencilBits) - 1; + const DepthStencilState &depthStencilState = state.getDepthStencilState(); + + bool differentRefs = state.getStencilRef() != state.getStencilBackRef(); + bool differentWritemasks = + (depthStencilState.stencilWritemask & minimumRequiredStencilMask) != + (depthStencilState.stencilBackWritemask & minimumRequiredStencilMask); + bool differentMasks = (depthStencilState.stencilMask & minimumRequiredStencilMask) != + (depthStencilState.stencilBackMask & minimumRequiredStencilMask); + + if (differentRefs || differentWritemasks || differentMasks) + { + if (!extensions.webglCompatibility) + { + ERR() << "This ANGLE implementation does not support separate front/back stencil " + "writemasks, reference values, or stencil mask values."; + } + ANGLE_VALIDATION_ERR(context, InvalidOperation(), StencilReferenceMaskOrMismatch); + return false; + } + } + + if (framebuffer->checkStatus(context) != GL_FRAMEBUFFER_COMPLETE) + { + context->handleError(InvalidFramebufferOperation()); + return false; + } + + gl::Program *program = state.getProgram(); + if (!program) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ProgramNotBound); + return false; + } + + // In OpenGL ES spec for UseProgram at section 7.3, trying to render without + // vertex shader stage or fragment shader stage is a undefined behaviour. + // But ANGLE should clearly generate an INVALID_OPERATION error instead of + // produce undefined result. + if (program->isLinked() && + (!program->hasLinkedVertexShader() || !program->hasLinkedFragmentShader())) + { + context->handleError(InvalidOperation() << "It is a undefined behaviour to render without " + "vertex shader stage or fragment shader stage."); + return false; + } + + if (!program->validateSamplers(nullptr, context->getCaps())) + { + context->handleError(InvalidOperation()); + return false; + } + + if (extensions.multiview) + { + const int programNumViews = program->usesMultiview() ? program->getNumViews() : 1; + const int framebufferNumViews = framebuffer->getNumViews(); + if (framebufferNumViews != programNumViews) + { + context->handleError(InvalidOperation() << "The number of views in the active program " + "and draw framebuffer does not match."); + return false; + } + + const TransformFeedback *transformFeedbackObject = state.getCurrentTransformFeedback(); + if (transformFeedbackObject != nullptr && transformFeedbackObject->isActive() && + framebufferNumViews > 1) + { + context->handleError(InvalidOperation() + << "There is an active transform feedback object " + "when the number of views in the active draw " + "framebuffer is greater than 1."); + return false; + } + + if (extensions.disjointTimerQuery && framebufferNumViews > 1 && + state.isQueryActive(GL_TIME_ELAPSED_EXT)) + { + context->handleError(InvalidOperation() << "There is an active query for target " + "GL_TIME_ELAPSED_EXT when the number of " + "views in the active draw framebuffer is " + "greater than 1."); + return false; + } + } + + // Uniform buffer validation + for (unsigned int uniformBlockIndex = 0; + uniformBlockIndex < program->getActiveUniformBlockCount(); uniformBlockIndex++) + { + const gl::InterfaceBlock &uniformBlock = program->getUniformBlockByIndex(uniformBlockIndex); + GLuint blockBinding = program->getUniformBlockBinding(uniformBlockIndex); + const OffsetBindingPointer &uniformBuffer = + state.getIndexedUniformBuffer(blockBinding); + + if (uniformBuffer.get() == nullptr) + { + // undefined behaviour + context->handleError( + InvalidOperation() + << "It is undefined behaviour to have a used but unbound uniform buffer."); + return false; + } + + size_t uniformBufferSize = uniformBuffer.getSize(); + if (uniformBufferSize == 0) + { + // Bind the whole buffer. + uniformBufferSize = static_cast(uniformBuffer->getSize()); + } + + if (uniformBufferSize < uniformBlock.dataSize) + { + // undefined behaviour + context->handleError( + InvalidOperation() + << "It is undefined behaviour to use a uniform buffer that is too small."); + return false; + } + } + + // Do some additonal WebGL-specific validation + if (extensions.webglCompatibility) + { + // Detect rendering feedback loops for WebGL. + if (framebuffer->formsRenderingFeedbackLoopWith(state)) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), FeedbackLoop); + return false; + } + + // Detect that the vertex shader input types match the attribute types + if (!ValidateVertexShaderAttributeTypeMatch(context)) + { + return false; + } + + // Detect that the color buffer types match the fragment shader output types + if (!ValidateFragmentShaderColorBufferTypeMatch(context)) + { + return false; + } + } + + // No-op if zero count + return (count > 0); +} + +bool ValidateDrawArraysCommon(ValidationContext *context, + GLenum mode, + GLint first, + GLsizei count, + GLsizei primcount) +{ + if (first < 0) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), NegativeStart); + return false; + } + + const State &state = context->getGLState(); + gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback(); + if (curTransformFeedback && curTransformFeedback->isActive() && + !curTransformFeedback->isPaused() && curTransformFeedback->getPrimitiveMode() != 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) + ANGLE_VALIDATION_ERR(context, InvalidOperation(), InvalidDrawModeTransformFeedback); + return false; + } + + if (!ValidateDrawBase(context, mode, count)) + { + return false; + } + + // Check the computation of maxVertex doesn't overflow. + // - first < 0 or count < 0 have been checked as an error condition + // - count > 0 has been checked in ValidateDrawBase as it makes the call a noop + // From this we know maxVertex will be positive, and only need to check if it overflows GLint. + ASSERT(count > 0 && first >= 0); + int64_t maxVertex = static_cast(first) + static_cast(count) - 1; + if (maxVertex > static_cast(std::numeric_limits::max())) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), IntegerOverflow); + return false; + } + + if (!ValidateDrawAttribs(context, primcount, static_cast(maxVertex), count)) + { + return false; + } + + return true; +} + +bool ValidateDrawArraysInstancedANGLE(Context *context, + GLenum mode, + GLint first, + GLsizei count, + GLsizei primcount) +{ + if (!context->getExtensions().instancedArrays) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ExtensionNotEnabled); + return false; + } + + if (!ValidateDrawArraysInstancedBase(context, mode, first, count, primcount)) + { + return false; + } + + return ValidateDrawInstancedANGLE(context); +} + +bool ValidateDrawElementsBase(ValidationContext *context, GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + case GL_UNSIGNED_SHORT: + break; + case GL_UNSIGNED_INT: + if (context->getClientMajorVersion() < 3 && !context->getExtensions().elementIndexUint) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), TypeNotUnsignedShortByte); + return false; + } + break; + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), TypeNotUnsignedShortByte); + return false; + } + + const State &state = context->getGLState(); + + gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback(); + if (curTransformFeedback && curTransformFeedback->isActive() && + !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->handleError(InvalidOperation()); + return false; + } + + return true; +} + +bool ValidateDrawElementsCommon(ValidationContext *context, + GLenum mode, + GLsizei count, + GLenum type, + const void *indices, + GLsizei primcount) +{ + if (!ValidateDrawElementsBase(context, type)) + return false; + + const State &state = context->getGLState(); + + if (!ValidateDrawBase(context, mode, count)) + { + return false; + } + + // WebGL buffers cannot be mapped/unmapped because the MapBufferRange, FlushMappedBufferRange, + // and UnmapBuffer entry points are removed from the WebGL 2.0 API. + // https://www.khronos.org/registry/webgl/specs/latest/2.0/#5.14 + if (!context->getExtensions().webglCompatibility) + { + // Check for mapped buffers + // TODO(jmadill): Optimize this check for non - WebGL contexts. + if (state.hasMappedBuffer(gl::BufferBinding::ElementArray)) + { + context->handleError(InvalidOperation() << "Index buffer is mapped."); + return false; + } + } + + const gl::VertexArray *vao = state.getVertexArray(); + gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get(); + + GLuint typeBytes = gl::GetTypeInfo(type).bytes; + + if (context->getExtensions().webglCompatibility) + { + ASSERT(isPow2(typeBytes) && typeBytes > 0); + if ((reinterpret_cast(indices) & static_cast(typeBytes - 1)) != 0) + { + // [WebGL 1.0] Section 6.4 Buffer Offset and Stride Requirements + // The offset arguments to drawElements and [...], must be a multiple of the size of the + // data type passed to the call, or an INVALID_OPERATION error is generated. + ANGLE_VALIDATION_ERR(context, InvalidOperation(), OffsetMustBeMultipleOfType); + return false; + } + + // [WebGL 1.0] Section 6.4 Buffer Offset and Stride Requirements + // In addition the offset argument to drawElements must be non-negative or an INVALID_VALUE + // error is generated. + if (reinterpret_cast(indices) < 0) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), NegativeOffset); + return false; + } + } + + if (context->getExtensions().webglCompatibility || + !context->getGLState().areClientArraysEnabled()) + { + if (!elementArrayBuffer && count > 0) + { + // [WebGL 1.0] Section 6.2 No Client Side Arrays + // If drawElements is called with a count greater than zero, and no WebGLBuffer is bound + // to the ELEMENT_ARRAY_BUFFER binding point, an INVALID_OPERATION error is generated. + ANGLE_VALIDATION_ERR(context, InvalidOperation(), MustHaveElementArrayBinding); + return false; + } + } + + if (count > 0) + { + if (elementArrayBuffer) + { + // The max possible type size is 8 and count is on 32 bits so doing the multiplication + // in a 64 bit integer is safe. Also we are guaranteed that here count > 0. + static_assert(std::is_same::value, "GLsizei isn't the expected type"); + constexpr uint64_t kMaxTypeSize = 8; + constexpr uint64_t kIntMax = std::numeric_limits::max(); + constexpr uint64_t kUint64Max = std::numeric_limits::max(); + static_assert(kIntMax < kUint64Max / kMaxTypeSize, ""); + + uint64_t typeSize = typeBytes; + uint64_t elementCount = static_cast(count); + ASSERT(elementCount > 0 && typeSize <= kMaxTypeSize); + + // Doing the multiplication here is overflow-safe + uint64_t elementDataSizeNoOffset = typeSize * elementCount; + + // The offset can be any value, check for overflows + uint64_t offset = static_cast(reinterpret_cast(indices)); + if (elementDataSizeNoOffset > kUint64Max - offset) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), IntegerOverflow); + return false; + } + + uint64_t elementDataSizeWithOffset = elementDataSizeNoOffset + offset; + if (elementDataSizeWithOffset > static_cast(elementArrayBuffer->getSize())) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), InsufficientBufferSize); + return false; + } + + ASSERT(isPow2(typeSize) && typeSize > 0); + if ((elementArrayBuffer->getSize() & (typeSize - 1)) != 0) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), MismatchedByteCountType); + return false; + } + } + else if (!indices) + { + // This is an application error that would normally result in a crash, + // but we catch it and return an error + context->handleError(InvalidOperation() << "No element array buffer and no pointer."); + return false; + } + } + + if (context->getExtensions().robustBufferAccessBehavior) + { + // Here we use maxVertex = 0 and vertexCount = 1 to avoid retrieving IndexRange when robust + // access is enabled. + if (!ValidateDrawAttribs(context, primcount, 0, 1)) + { + return false; + } + } + else + { + // Use the parameter buffer to retrieve and cache the index range. + const auto ¶ms = context->getParams(); + const auto &indexRangeOpt = params.getIndexRange(); + if (!indexRangeOpt.valid()) + { + // Unexpected error. + return false; + } + + // If we use an index greater than our maximum supported index range, return an error. + // The ES3 spec does not specify behaviour here, it is undefined, but ANGLE should always + // return an error if possible here. + if (static_cast(indexRangeOpt.value().end) >= context->getCaps().maxElementIndex) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ExceedsMaxElement); + return false; + } + + if (!ValidateDrawAttribs(context, primcount, static_cast(indexRangeOpt.value().end), + static_cast(indexRangeOpt.value().vertexCount()))) + { + return false; + } + + // No op if there are no real indices in the index data (all are primitive restart). + return (indexRangeOpt.value().vertexIndexCount > 0); + } + + return true; +} + +bool ValidateDrawElementsInstancedCommon(ValidationContext *context, + GLenum mode, + GLsizei count, + GLenum type, + const void *indices, + GLsizei primcount) +{ + return ValidateDrawElementsInstancedBase(context, mode, count, type, indices, primcount); +} + +bool ValidateDrawElementsInstancedANGLE(Context *context, + GLenum mode, + GLsizei count, + GLenum type, + const void *indices, + GLsizei primcount) +{ + if (!context->getExtensions().instancedArrays) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ExtensionNotEnabled); + return false; + } + + if (!ValidateDrawElementsInstancedBase(context, mode, count, type, indices, primcount)) + { + return false; + } + + return ValidateDrawInstancedANGLE(context); +} + +bool ValidateFramebufferTextureBase(Context *context, + GLenum target, + GLenum attachment, + GLuint texture, + GLint level) +{ + if (!ValidFramebufferTarget(context, target)) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidFramebufferTarget); + return false; + } + + if (!ValidateAttachmentTarget(context, attachment)) + { + return false; + } + + if (texture != 0) + { + gl::Texture *tex = context->getTexture(texture); + + if (tex == NULL) + { + context->handleError(InvalidOperation()); + return false; + } + + if (level < 0) + { + context->handleError(InvalidValue()); + return false; + } + } + + const gl::Framebuffer *framebuffer = context->getGLState().getTargetFramebuffer(target); + ASSERT(framebuffer); + + if (framebuffer->id() == 0) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), DefaultFramebufferTarget); + return false; + } + + return true; +} + +bool ValidateGetUniformBase(Context *context, GLuint program, GLint location) +{ + if (program == 0) + { + context->handleError(InvalidValue()); + return false; + } + + gl::Program *programObject = GetValidProgram(context, program); + if (!programObject) + { + return false; + } + + if (!programObject || !programObject->isLinked()) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ProgramNotLinked); + return false; + } + + if (!programObject->isValidUniformLocation(location)) + { + context->handleError(InvalidOperation()); + return false; + } + + return true; +} + +static bool ValidateSizedGetUniform(Context *context, + GLuint program, + GLint location, + GLsizei bufSize, + GLsizei *length) +{ + if (length) + { + *length = 0; + } + + if (!ValidateGetUniformBase(context, program, location)) + { + return false; + } + + if (bufSize < 0) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), NegativeBufferSize); + return false; + } + + gl::Program *programObject = context->getProgram(program); + ASSERT(programObject); + + // sized queries -- ensure the provided buffer is large enough + const LinkedUniform &uniform = programObject->getUniformByLocation(location); + size_t requiredBytes = VariableExternalSize(uniform.type); + if (static_cast(bufSize) < requiredBytes) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), InsufficientBufferSize); + return false; + } + + if (length) + { + *length = VariableComponentCount(uniform.type); + } + + return true; +} + +bool ValidateGetnUniformfvEXT(Context *context, + GLuint program, + GLint location, + GLsizei bufSize, + GLfloat *params) +{ + return ValidateSizedGetUniform(context, program, location, bufSize, nullptr); +} + +bool ValidateGetnUniformivEXT(Context *context, + GLuint program, + GLint location, + GLsizei bufSize, + GLint *params) +{ + return ValidateSizedGetUniform(context, program, location, bufSize, nullptr); +} + +bool ValidateGetUniformfvRobustANGLE(Context *context, + GLuint program, + GLint location, + GLsizei bufSize, + GLsizei *length, + GLfloat *params) +{ + if (!ValidateRobustEntryPoint(context, bufSize)) + { + return false; + } + + // bufSize is validated in ValidateSizedGetUniform + return ValidateSizedGetUniform(context, program, location, bufSize, length); +} + +bool ValidateGetUniformivRobustANGLE(Context *context, + GLuint program, + GLint location, + GLsizei bufSize, + GLsizei *length, + GLint *params) +{ + if (!ValidateRobustEntryPoint(context, bufSize)) + { + return false; + } + + // bufSize is validated in ValidateSizedGetUniform + return ValidateSizedGetUniform(context, program, location, bufSize, length); +} + +bool ValidateGetUniformuivRobustANGLE(Context *context, + GLuint program, + GLint location, + GLsizei bufSize, + GLsizei *length, + GLuint *params) +{ + if (!ValidateRobustEntryPoint(context, bufSize)) + { + return false; + } + + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + // bufSize is validated in ValidateSizedGetUniform + return ValidateSizedGetUniform(context, program, location, bufSize, length); +} + +bool ValidateDiscardFramebufferBase(Context *context, + GLenum target, + GLsizei numAttachments, + const GLenum *attachments, + bool defaultFramebuffer) +{ + if (numAttachments < 0) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), NegativeAttachments); + return false; + } + + for (GLsizei i = 0; i < numAttachments; ++i) + { + if (attachments[i] >= GL_COLOR_ATTACHMENT0 && attachments[i] <= GL_COLOR_ATTACHMENT31) + { + if (defaultFramebuffer) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), DefaultFramebufferInvalidAttachment); + return false; + } + + if (attachments[i] >= GL_COLOR_ATTACHMENT0 + context->getCaps().maxColorAttachments) + { + context->handleError(InvalidOperation() << "Requested color attachment is " + "greater than the maximum supported " + "color attachments"); + return false; + } + } + else + { + switch (attachments[i]) + { + case GL_DEPTH_ATTACHMENT: + case GL_STENCIL_ATTACHMENT: + case GL_DEPTH_STENCIL_ATTACHMENT: + if (defaultFramebuffer) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), + DefaultFramebufferInvalidAttachment); + return false; + } + break; + case GL_COLOR: + case GL_DEPTH: + case GL_STENCIL: + if (!defaultFramebuffer) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), + DefaultFramebufferInvalidAttachment); + return false; + } + break; + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidAttachment); + return false; + } + } + } + + return true; +} + +bool ValidateInsertEventMarkerEXT(Context *context, GLsizei length, const char *marker) +{ + // Note that debug marker calls must not set error state + + if (length < 0) + { + return false; + } + + if (marker == nullptr) + { + return false; + } + + return true; +} + +bool ValidatePushGroupMarkerEXT(Context *context, GLsizei length, const char *marker) +{ + // Note that debug marker calls must not set error state + + if (length < 0) + { + return false; + } + + if (length > 0 && marker == nullptr) + { + return false; + } + + return true; +} + +bool ValidateEGLImageTargetTexture2DOES(Context *context, + GLenum target, + egl::Image *image) +{ + if (!context->getExtensions().eglImage && !context->getExtensions().eglImageExternal) + { + context->handleError(InvalidOperation()); + return false; + } + + switch (target) + { + case GL_TEXTURE_2D: + if (!context->getExtensions().eglImage) + { + context->handleError(InvalidEnum() + << "GL_TEXTURE_2D texture target requires GL_OES_EGL_image."); + } + break; + + case GL_TEXTURE_EXTERNAL_OES: + if (!context->getExtensions().eglImageExternal) + { + context->handleError(InvalidEnum() << "GL_TEXTURE_EXTERNAL_OES texture target " + "requires GL_OES_EGL_image_external."); + } + break; + + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidTextureTarget); + return false; + } + + ASSERT(context->getCurrentDisplay()); + if (!context->getCurrentDisplay()->isValidImage(image)) + { + context->handleError(InvalidValue() << "EGL image is not valid."); + return false; + } + + if (image->getSamples() > 0) + { + context->handleError(InvalidOperation() + << "cannot create a 2D texture from a multisampled EGL image."); + return false; + } + + const TextureCaps &textureCaps = + context->getTextureCaps().get(image->getFormat().info->sizedInternalFormat); + if (!textureCaps.texturable) + { + context->handleError(InvalidOperation() + << "EGL image internal format is not supported as a texture."); + return false; + } + + return true; +} + +bool ValidateEGLImageTargetRenderbufferStorageOES(Context *context, + GLenum target, + egl::Image *image) +{ + if (!context->getExtensions().eglImage) + { + context->handleError(InvalidOperation()); + return false; + } + + switch (target) + { + case GL_RENDERBUFFER: + break; + + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidRenderbufferTarget); + return false; + } + + ASSERT(context->getCurrentDisplay()); + if (!context->getCurrentDisplay()->isValidImage(image)) + { + context->handleError(InvalidValue() << "EGL image is not valid."); + return false; + } + + const TextureCaps &textureCaps = + context->getTextureCaps().get(image->getFormat().info->sizedInternalFormat); + if (!textureCaps.renderable) + { + context->handleError(InvalidOperation() + << "EGL image internal format is not supported as a renderbuffer."); + return false; + } + + return true; +} + +bool ValidateBindVertexArrayBase(Context *context, GLuint array) +{ + if (!context->isVertexArrayGenerated(array)) + { + // The default VAO should always exist + ASSERT(array != 0); + context->handleError(InvalidOperation()); + return false; + } + + return true; +} + +bool ValidateProgramBinaryBase(Context *context, + GLuint program, + GLenum binaryFormat, + const void *binary, + GLint length) +{ + Program *programObject = GetValidProgram(context, program); + if (programObject == nullptr) + { + return false; + } + + const std::vector &programBinaryFormats = context->getCaps().programBinaryFormats; + if (std::find(programBinaryFormats.begin(), programBinaryFormats.end(), binaryFormat) == + programBinaryFormats.end()) + { + context->handleError(InvalidEnum() << "Program binary format is not valid."); + return false; + } + + if (context->hasActiveTransformFeedback(program)) + { + // ES 3.0.4 section 2.15 page 91 + context->handleError(InvalidOperation() << "Cannot change program binary while program " + "is associated with an active transform " + "feedback object."); + return false; + } + + return true; +} + +bool ValidateGetProgramBinaryBase(Context *context, + GLuint program, + GLsizei bufSize, + GLsizei *length, + GLenum *binaryFormat, + void *binary) +{ + Program *programObject = GetValidProgram(context, program); + if (programObject == nullptr) + { + return false; + } + + if (!programObject->isLinked()) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ProgramNotLinked); + return false; + } + + if (context->getCaps().programBinaryFormats.empty()) + { + context->handleError(InvalidOperation() << "No program binary formats supported."); + return false; + } + + return true; +} + +bool ValidateDrawBuffersBase(ValidationContext *context, GLsizei n, const GLenum *bufs) +{ + // INVALID_VALUE is generated if n is negative or greater than value of MAX_DRAW_BUFFERS + if (n < 0) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), NegativeCount); + return false; + } + if (static_cast(n) > context->getCaps().maxDrawBuffers) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), IndexExceedsMaxDrawBuffer); + return false; + } + + ASSERT(context->getGLState().getDrawFramebuffer()); + GLuint frameBufferId = context->getGLState().getDrawFramebuffer()->id(); + GLuint maxColorAttachment = GL_COLOR_ATTACHMENT0_EXT + context->getCaps().maxColorAttachments; + + // This should come first before the check for the default frame buffer + // because when we switch to ES3.1+, invalid enums will return INVALID_ENUM + // rather than INVALID_OPERATION + for (int colorAttachment = 0; colorAttachment < n; colorAttachment++) + { + const GLenum attachment = GL_COLOR_ATTACHMENT0_EXT + colorAttachment; + + if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != GL_BACK && + (bufs[colorAttachment] < GL_COLOR_ATTACHMENT0 || + bufs[colorAttachment] > GL_COLOR_ATTACHMENT31)) + { + // Value in bufs is not NONE, BACK, or GL_COLOR_ATTACHMENTi + // The 3.0.4 spec says to generate GL_INVALID_OPERATION here, but this + // was changed to GL_INVALID_ENUM in 3.1, which dEQP also expects. + // 3.1 is still a bit ambiguous about the error, but future specs are + // expected to clarify that GL_INVALID_ENUM is the correct error. + context->handleError(InvalidEnum() << "Invalid buffer value"); + return false; + } + else if (bufs[colorAttachment] >= maxColorAttachment) + { + context->handleError(InvalidOperation() + << "Buffer value is greater than MAX_DRAW_BUFFERS"); + return false; + } + else if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != attachment && + frameBufferId != 0) + { + // INVALID_OPERATION-GL is bound to buffer and ith argument + // is not COLOR_ATTACHMENTi or NONE + context->handleError(InvalidOperation() + << "Ith value does not match COLOR_ATTACHMENTi or NONE"); + return false; + } + } + + // INVALID_OPERATION is generated if GL is bound to the default framebuffer + // and n is not 1 or bufs is bound to value other than BACK and NONE + if (frameBufferId == 0) + { + if (n != 1) + { + context->handleError(InvalidOperation() + << "n must be 1 when GL is bound to the default framebuffer"); + return false; + } + + if (bufs[0] != GL_NONE && bufs[0] != GL_BACK) + { + context->handleError( + InvalidOperation() + << "Only NONE or BACK are valid values when drawing to the default framebuffer"); + return false; + } + } + + return true; +} + +bool ValidateGetBufferPointervBase(Context *context, + BufferBinding target, + GLenum pname, + GLsizei *length, + void **params) +{ + if (length) + { + *length = 0; + } + + if (context->getClientMajorVersion() < 3 && !context->getExtensions().mapBuffer) + { + context->handleError( + InvalidOperation() + << "Context does not support OpenGL ES 3.0 or GL_OES_mapbuffer is not enabled."); + return false; + } + + if (!ValidBufferType(context, target)) + { + context->handleError(InvalidEnum() << "Buffer target not valid"); + return false; + } + + switch (pname) + { + case GL_BUFFER_MAP_POINTER: + break; + + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), EnumNotSupported); + return false; + } + + // GLES 3.0 section 2.10.1: "Attempts to attempts to modify or query buffer object state for a + // target bound to zero generate an INVALID_OPERATION error." + // GLES 3.1 section 6.6 explicitly specifies this error. + if (context->getGLState().getTargetBuffer(target) == nullptr) + { + context->handleError(InvalidOperation() + << "Can not get pointer for reserved buffer name zero."); + return false; + } + + if (length) + { + *length = 1; + } + + return true; +} + +bool ValidateUnmapBufferBase(Context *context, BufferBinding target) +{ + if (!ValidBufferType(context, target)) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidBufferTypes); + return false; + } + + Buffer *buffer = context->getGLState().getTargetBuffer(target); + + if (buffer == nullptr || !buffer->isMapped()) + { + context->handleError(InvalidOperation() << "Buffer not mapped."); + return false; + } + + return true; +} + +bool ValidateMapBufferRangeBase(Context *context, + BufferBinding target, + GLintptr offset, + GLsizeiptr length, + GLbitfield access) +{ + if (!ValidBufferType(context, target)) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidBufferTypes); return false; } - const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat); - if (!formatCaps.renderable) + if (offset < 0) { - context->recordError(Error(GL_INVALID_ENUM)); + ANGLE_VALIDATION_ERR(context, InvalidValue(), NegativeOffset); 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) + if (length < 0) { - context->recordError(Error(GL_INVALID_ENUM)); + ANGLE_VALIDATION_ERR(context, InvalidValue(), NegativeLength); return false; } - if (static_cast(std::max(width, height)) > context->getCaps().maxRenderbufferSize) + Buffer *buffer = context->getGLState().getTargetBuffer(target); + + if (!buffer) { - context->recordError(Error(GL_INVALID_VALUE)); + context->handleError(InvalidOperation() << "Attempted to map buffer object zero."); return false; } - GLuint handle = context->getState().getRenderbufferId(); - if (handle == 0) + // Check for buffer overflow + CheckedNumeric checkedOffset(offset); + auto checkedSize = checkedOffset + length; + + if (!checkedSize.IsValid() || checkedSize.ValueOrDie() > static_cast(buffer->getSize())) { - context->recordError(Error(GL_INVALID_OPERATION)); + context->handleError(InvalidValue() << "Mapped range does not fit into buffer dimensions."); 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); + // Check for invalid bits in the mask + GLbitfield allAccessBits = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT | + GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_FLUSH_EXPLICIT_BIT | + GL_MAP_UNSYNCHRONIZED_BIT; - // ANGLE_framebuffer_multisample states that the value of samples must be less than or equal - // to MAX_SAMPLES_ANGLE (Context::getCaps().maxSamples) otherwise GL_INVALID_VALUE is - // generated. - if (static_cast(samples) > context->getCaps().maxSamples) + if (access & ~(allAccessBits)) { - context->recordError(Error(GL_INVALID_VALUE)); + context->handleError(InvalidValue() + << "Invalid access bits: 0x" << std::hex << std::uppercase << access); 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. - // The TextureCaps::getMaxSamples method is only guarenteed to be valid when the context is ES3. - if (context->getClientVersion() >= 3) + if (length == 0) { - const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat); - if (static_cast(samples) > formatCaps.getMaxSamples()) - { - context->recordError(Error(GL_OUT_OF_MEMORY)); - return false; - } + context->handleError(InvalidOperation() << "Buffer mapping length is zero."); + 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)) + if (buffer->isMapped()) { - context->recordError(Error(GL_INVALID_ENUM)); + context->handleError(InvalidOperation() << "Buffer is already mapped."); return false; } - gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target); - - ASSERT(framebuffer); - if (framebuffer->id() == 0) + // Check for invalid bit combinations + if ((access & (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT)) == 0) { - context->recordError(Error(GL_INVALID_OPERATION, "Cannot change default FBO's attachments")); + context->handleError(InvalidOperation() + << "Need to map buffer for either reading or writing."); return false; } - if (!ValidateAttachmentTarget(context, attachment)) + GLbitfield writeOnlyBits = + GL_MAP_INVALIDATE_RANGE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_UNSYNCHRONIZED_BIT; + + if ((access & GL_MAP_READ_BIT) != 0 && (access & writeOnlyBits) != 0) { + context->handleError(InvalidOperation() + << "Invalid access bits when mapping buffer for reading: 0x" + << std::hex << std::uppercase << access); 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 ((access & GL_MAP_WRITE_BIT) == 0 && (access & GL_MAP_FLUSH_EXPLICIT_BIT) != 0) { - if (!context->getRenderbuffer(renderbuffer)) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } + context->handleError( + InvalidOperation() + << "The explicit flushing bit may only be set if the buffer is mapped for writing."); + return false; } - return true; + return ValidateMapBufferBase(context, target); } -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 ValidateFlushMappedBufferRangeBase(Context *context, + BufferBinding target, + GLintptr offset, + GLsizeiptr length) { - switch (filter) + if (offset < 0) { - case GL_NEAREST: - break; - case GL_LINEAR: - break; - default: - context->recordError(Error(GL_INVALID_ENUM)); + ANGLE_VALIDATION_ERR(context, InvalidValue(), NegativeOffset); return false; } - if ((mask & ~(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)) != 0) + if (length < 0) { - context->recordError(Error(GL_INVALID_VALUE)); + ANGLE_VALIDATION_ERR(context, InvalidValue(), NegativeLength); return false; } - if (mask == 0) + if (!ValidBufferType(context, target)) { - // ES3.0 spec, section 4.3.2 specifies that a mask of zero is valid and no - // buffers are copied. + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidBufferTypes); 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) + Buffer *buffer = context->getGLState().getTargetBuffer(target); + + if (buffer == nullptr) { - context->recordError(Error(GL_INVALID_OPERATION)); + context->handleError(InvalidOperation() << "Attempted to flush buffer object zero."); return false; } - if (context->getState().getReadFramebuffer()->id() == context->getState().getDrawFramebuffer()->id()) + if (!buffer->isMapped() || (buffer->getAccessFlags() & GL_MAP_FLUSH_EXPLICIT_BIT) == 0) { - context->recordError(Error(GL_INVALID_OPERATION)); + context->handleError(InvalidOperation() + << "Attempted to flush a buffer not mapped for explicit flushing."); return false; } - const gl::Framebuffer *readFramebuffer = context->getState().getReadFramebuffer(); - const gl::Framebuffer *drawFramebuffer = context->getState().getDrawFramebuffer(); + // Check for buffer overflow + CheckedNumeric checkedOffset(offset); + auto checkedSize = checkedOffset + length; - if (!readFramebuffer || !drawFramebuffer) + if (!checkedSize.IsValid() || + checkedSize.ValueOrDie() > static_cast(buffer->getMapLength())) { - context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION)); + context->handleError(InvalidValue() + << "Flushed range does not fit into buffer mapping dimensions."); return false; } - if (!readFramebuffer->checkStatus(context->getData())) + return true; +} + +bool ValidateGenOrDelete(Context *context, GLint n) +{ + if (n < 0) { - context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION)); + ANGLE_VALIDATION_ERR(context, InvalidValue(), NegativeCount); return false; } + return true; +} - if (!drawFramebuffer->checkStatus(context->getData())) +bool ValidateRobustEntryPoint(ValidationContext *context, GLsizei bufSize) +{ + if (!context->getExtensions().robustClientMemory) { - context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION)); + context->handleError(InvalidOperation() + << "GL_ANGLE_robust_client_memory is not available."); return false; } - if (drawFramebuffer->getSamples(context->getData()) != 0) + if (bufSize < 0) { - context->recordError(Error(GL_INVALID_OPERATION)); + ANGLE_VALIDATION_ERR(context, InvalidValue(), NegativeBufferSize); return false; } - bool sameBounds = srcX0 == dstX0 && srcY0 == dstY0 && srcX1 == dstX1 && srcY1 == dstY1; + return true; +} - if (mask & GL_COLOR_BUFFER_BIT) +bool ValidateRobustBufferSize(ValidationContext *context, GLsizei bufSize, GLsizei numParams) +{ + if (bufSize < numParams) { - const gl::FramebufferAttachment *readColorBuffer = readFramebuffer->getReadColorbuffer(); - const gl::FramebufferAttachment *drawColorBuffer = drawFramebuffer->getFirstColorbuffer(); - const Extensions &extensions = context->getExtensions(); - - if (readColorBuffer && drawColorBuffer) - { - GLenum readInternalFormat = readColorBuffer->getInternalFormat(); - const InternalFormat &readFormatInfo = GetInternalFormatInfo(readInternalFormat); - - for (size_t drawbufferIdx = 0; - drawbufferIdx < drawFramebuffer->getDrawbufferStateCount(); ++drawbufferIdx) - { - const FramebufferAttachment *attachment = - drawFramebuffer->getDrawBuffer(drawbufferIdx); - if (attachment) - { - GLenum drawInternalFormat = attachment->getInternalFormat(); - const InternalFormat &drawFormatInfo = GetInternalFormatInfo(drawInternalFormat); + context->handleError(InvalidOperation() << numParams << " parameters are required but " + << bufSize << " were provided."); + return false; + } - // 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 - // Changes with EXT_color_buffer_float: - // Case 1) is changed to fixed point OR floating point - GLenum readComponentType = readFormatInfo.componentType; - GLenum drawComponentType = drawFormatInfo.componentType; - bool readFixedPoint = (readComponentType == GL_UNSIGNED_NORMALIZED || - readComponentType == GL_SIGNED_NORMALIZED); - bool drawFixedPoint = (drawComponentType == GL_UNSIGNED_NORMALIZED || - drawComponentType == GL_SIGNED_NORMALIZED); + return true; +} - if (extensions.colorBufferFloat) - { - bool readFixedOrFloat = (readFixedPoint || readComponentType == GL_FLOAT); - bool drawFixedOrFloat = (drawFixedPoint || drawComponentType == GL_FLOAT); +bool ValidateGetFramebufferAttachmentParameterivBase(ValidationContext *context, + GLenum target, + GLenum attachment, + GLenum pname, + GLsizei *numParams) +{ + if (!ValidFramebufferTarget(context, target)) + { + context->handleError(InvalidEnum()); + return false; + } - if (readFixedOrFloat != drawFixedOrFloat) - { - context->recordError(Error(GL_INVALID_OPERATION, - "If the read buffer contains fixed-point or " - "floating-point values, the draw buffer " - "must as well.")); - return false; - } - } - else if (readFixedPoint != drawFixedPoint) - { - context->recordError(Error(GL_INVALID_OPERATION, - "If the read buffer contains fixed-point " - "values, the draw buffer must as well.")); - return false; - } + int clientVersion = context->getClientMajorVersion(); - if (readComponentType == GL_UNSIGNED_INT && - drawComponentType != GL_UNSIGNED_INT) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } + switch (pname) + { + case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE: + case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME: + case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL: + case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE: + break; - if (readComponentType == GL_INT && drawComponentType != GL_INT) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } + case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_NUM_VIEWS_ANGLE: + case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_MULTIVIEW_LAYOUT_ANGLE: + case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_BASE_VIEW_INDEX_ANGLE: + case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_VIEWPORT_OFFSETS_ANGLE: + if (clientVersion < 3 || !context->getExtensions().multiview) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), EnumNotSupported); + return false; + } + break; - if (readColorBuffer->getSamples() > 0 && (readInternalFormat != drawInternalFormat || !sameBounds)) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - } + case GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING: + if (clientVersion < 3 && !context->getExtensions().sRGB) + { + context->handleError(InvalidEnum()); + return false; } + break; - if ((readFormatInfo.componentType == GL_INT || readFormatInfo.componentType == GL_UNSIGNED_INT) && filter == GL_LINEAR) + case GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE: + case GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE: + case GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE: + case GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE: + case GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE: + case GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE: + case GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE: + case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER: + if (clientVersion < 3) { - context->recordError(Error(GL_INVALID_OPERATION)); + context->handleError(InvalidEnum()); return false; } - } + break; + + default: + context->handleError(InvalidEnum()); + 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++) + // Determine if the attachment is a valid enum + switch (attachment) { - if (mask & masks[i]) - { - const gl::FramebufferAttachment *readBuffer = readFramebuffer->getAttachment(attachments[i]); - const gl::FramebufferAttachment *drawBuffer = drawFramebuffer->getAttachment(attachments[i]); + case GL_BACK: + case GL_DEPTH: + case GL_STENCIL: + if (clientVersion < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidAttachment); + return false; + } + break; - if (readBuffer && drawBuffer) + case GL_DEPTH_STENCIL_ATTACHMENT: + if (clientVersion < 3 && !context->isWebGL1()) { - if (readBuffer->getInternalFormat() != drawBuffer->getInternalFormat()) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidAttachment); + return false; + } + break; - if (readBuffer->getSamples() > 0 && !sameBounds) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } + case GL_COLOR_ATTACHMENT0: + case GL_DEPTH_ATTACHMENT: + case GL_STENCIL_ATTACHMENT: + break; + + default: + if ((clientVersion < 3 && !context->getExtensions().drawBuffers) || + attachment < GL_COLOR_ATTACHMENT0_EXT || + (attachment - GL_COLOR_ATTACHMENT0_EXT) >= context->getCaps().maxColorAttachments) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidAttachment); + return false; } - } + break; } - return true; -} + const Framebuffer *framebuffer = context->getGLState().getTargetFramebuffer(target); + ASSERT(framebuffer); -bool ValidateGetVertexAttribParameters(Context *context, GLenum pname) -{ - switch (pname) + if (framebuffer->id() == 0) { - 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) + if (clientVersion < 3) { - context->recordError(Error(GL_INVALID_ENUM)); + ANGLE_VALIDATION_ERR(context, InvalidOperation(), DefaultFramebufferTarget); return false; } - return true; - default: - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } -} + switch (attachment) + { + case GL_BACK: + case GL_DEPTH: + case GL_STENCIL: + break; -bool ValidateTexParamParameters(gl::Context *context, GLenum pname, GLint param) -{ - switch (pname) + default: + ANGLE_VALIDATION_ERR(context, InvalidOperation(), InvalidAttachment); + return false; + } + } + else { - 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) + if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT) { - context->recordError(Error(GL_INVALID_ENUM)); - return false; + // Valid attachment query } - break; + else + { + switch (attachment) + { + case GL_DEPTH_ATTACHMENT: + case GL_STENCIL_ATTACHMENT: + break; + + case GL_DEPTH_STENCIL_ATTACHMENT: + if (!framebuffer->hasValidDepthStencil() && !context->isWebGL1()) + { + context->handleError(InvalidOperation()); + return false; + } + break; - default: break; + default: + ANGLE_VALIDATION_ERR(context, InvalidOperation(), InvalidAttachment); + return false; + } + } } - switch (pname) + const FramebufferAttachment *attachmentObject = framebuffer->getAttachment(attachment); + if (attachmentObject) { - 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; - } + ASSERT(attachmentObject->type() == GL_RENDERBUFFER || + attachmentObject->type() == GL_TEXTURE || + attachmentObject->type() == GL_FRAMEBUFFER_DEFAULT); - case GL_TEXTURE_MIN_FILTER: - switch (param) + switch (pname) { - 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_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME: + if (attachmentObject->type() != GL_RENDERBUFFER && + attachmentObject->type() != GL_TEXTURE) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), FramebufferIncompleteAttachment); + 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_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL: + if (attachmentObject->type() != GL_TEXTURE) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), FramebufferIncompleteAttachment); + 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_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE: + if (attachmentObject->type() != GL_TEXTURE) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), FramebufferIncompleteAttachment); + return false; + } + break; - case GL_TEXTURE_MAX_ANISOTROPY_EXT: - if (!context->getExtensions().textureFilterAnisotropic) - { - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } + case GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE: + if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), InvalidAttachment); + return false; + } + break; - // we assume the parameter passed to this validation method is truncated, not rounded - if (param < 1) - { - context->recordError(Error(GL_INVALID_VALUE)); - return false; + case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER: + if (attachmentObject->type() != GL_TEXTURE) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), FramebufferIncompleteAttachment); + return false; + } + break; + + default: + break; } - return true; + } + else + { + // ES 2.0.25 spec pg 127 states that if the value of FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE + // is NONE, then querying any other pname will generate INVALID_ENUM. - case GL_TEXTURE_MIN_LOD: - case GL_TEXTURE_MAX_LOD: - // any value is permissible - return true; + // ES 3.0.2 spec pg 235 states that if the attachment type is none, + // GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME will return zero and be an + // INVALID_OPERATION for all other pnames - case GL_TEXTURE_COMPARE_MODE: - // Acceptable mode parameters from GLES 3.0.2 spec, table 3.17 - switch (param) + switch (pname) { - case GL_NONE: - case GL_COMPARE_REF_TO_TEXTURE: - return true; - default: - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } - break; + case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE: + 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_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME: + if (clientVersion < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), + InvalidFramebufferAttachmentParameter); + 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; + default: + if (clientVersion < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), + InvalidFramebufferAttachmentParameter); + return false; + } + else + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), + InvalidFramebufferAttachmentParameter); + return false; + } } - break; + } - case GL_TEXTURE_BASE_LEVEL: - case GL_TEXTURE_MAX_LEVEL: - if (param < 0) + if (numParams) + { + if (pname == GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_VIEWPORT_OFFSETS_ANGLE) { - context->recordError(Error(GL_INVALID_VALUE)); - return false; + // Only when the viewport offsets are queried we can have a varying number of output + // parameters. + const int numViews = attachmentObject ? attachmentObject->getNumViews() : 1; + *numParams = numViews * 2; + } + else + { + // For all other queries we can have only one output parameter. + *numParams = 1; } - return true; - - default: - context->recordError(Error(GL_INVALID_ENUM)); - return false; } + + return true; } -bool ValidateSamplerObjectParameter(gl::Context *context, GLenum pname) +bool ValidateGetFramebufferAttachmentParameterivRobustANGLE(ValidationContext *context, + GLenum target, + GLenum attachment, + GLenum pname, + GLsizei bufSize, + GLsizei *numParams) { - switch (pname) + if (!ValidateRobustEntryPoint(context, bufSize)) { - 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 ValidateReadPixels(Context *context, - GLint x, - GLint y, - GLsizei width, - GLsizei height, - GLenum format, - GLenum type, - GLvoid *pixels) -{ - if (width < 0 || height < 0) + if (!ValidateGetFramebufferAttachmentParameterivBase(context, target, attachment, pname, + numParams)) { - context->recordError(Error(GL_INVALID_VALUE, "width and height must be positive")); return false; } - Framebuffer *framebuffer = context->getState().getReadFramebuffer(); - ASSERT(framebuffer); - - if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE) + if (!ValidateRobustBufferSize(context, bufSize, *numParams)) { - context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION)); return false; } - if (context->getState().getReadFramebuffer()->id() != 0 && - framebuffer->getSamples(context->getData()) != 0) + return true; +} + +bool ValidateGetBufferParameterivRobustANGLE(ValidationContext *context, + BufferBinding target, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLint *params) +{ + if (!ValidateRobustEntryPoint(context, bufSize)) { - context->recordError(Error(GL_INVALID_OPERATION)); return false; } - const FramebufferAttachment *readBuffer = framebuffer->getReadColorbuffer(); - if (!readBuffer) + if (!ValidateGetBufferParameterBase(context, target, pname, false, length)) { - 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) + if (!ValidateRobustBufferSize(context, bufSize, *length)) { - context->recordError(Error(GL_INVALID_OPERATION)); return false; } return true; } -bool ValidateReadnPixelsEXT(Context *context, - GLint x, - GLint y, - GLsizei width, - GLsizei height, - GLenum format, - GLenum type, - GLsizei bufSize, - GLvoid *pixels) +bool ValidateGetBufferParameteri64vRobustANGLE(ValidationContext *context, + BufferBinding target, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLint64 *params) { - if (bufSize < 0) + if (!ValidateRobustEntryPoint(context, bufSize)) { - context->recordError(Error(GL_INVALID_VALUE, "bufSize must be a positive number")); return false; } - GLenum sizedInternalFormat = GetSizedInternalFormat(format, type); - const InternalFormat &sizedFormatInfo = GetInternalFormatInfo(sizedInternalFormat); + if (!ValidateGetBufferParameterBase(context, target, pname, false, length)) + { + return false; + } - GLsizei outputPitch = - sizedFormatInfo.computeRowPitch(type, width, context->getState().getPackAlignment(), - context->getState().getPackRowLength()); - // sized query sanity check - int requiredSize = outputPitch * height; - if (requiredSize > bufSize) + if (!ValidateRobustBufferSize(context, bufSize, *length)) { - context->recordError(Error(GL_INVALID_OPERATION)); return false; } - return ValidateReadPixels(context, x, y, width, height, format, type, pixels); + return true; } -bool ValidateGenQueriesBase(gl::Context *context, GLsizei n, const GLuint *ids) +bool ValidateGetProgramivBase(ValidationContext *context, + GLuint program, + GLenum pname, + GLsizei *numParams) { - if (n < 0) + // Currently, all GetProgramiv queries return 1 parameter + if (numParams) + { + *numParams = 1; + } + + Program *programObject = GetValidProgram(context, program); + if (!programObject) { - context->recordError(Error(GL_INVALID_VALUE, "Query count < 0")); return false; } + switch (pname) + { + case GL_DELETE_STATUS: + case GL_LINK_STATUS: + case GL_VALIDATE_STATUS: + case GL_INFO_LOG_LENGTH: + case GL_ATTACHED_SHADERS: + case GL_ACTIVE_ATTRIBUTES: + case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH: + case GL_ACTIVE_UNIFORMS: + case GL_ACTIVE_UNIFORM_MAX_LENGTH: + break; + + case GL_PROGRAM_BINARY_LENGTH: + if (context->getClientMajorVersion() < 3 && !context->getExtensions().getProgramBinary) + { + context->handleError(InvalidEnum() << "Querying GL_PROGRAM_BINARY_LENGTH " + "requires GL_OES_get_program_binary or " + "ES 3.0."); + return false; + } + break; + + case GL_ACTIVE_UNIFORM_BLOCKS: + case GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH: + case GL_TRANSFORM_FEEDBACK_BUFFER_MODE: + case GL_TRANSFORM_FEEDBACK_VARYINGS: + case GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH: + case GL_PROGRAM_BINARY_RETRIEVABLE_HINT: + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), ES3Required); + return false; + } + break; + + case GL_PROGRAM_SEPARABLE: + case GL_COMPUTE_WORK_GROUP_SIZE: + case GL_ACTIVE_ATOMIC_COUNTER_BUFFERS: + if (context->getClientVersion() < Version(3, 1)) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), ES31Required); + return false; + } + break; + + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), EnumNotSupported); + return false; + } + return true; } -bool ValidateGenQueriesEXT(gl::Context *context, GLsizei n, const GLuint *ids) +bool ValidateGetProgramivRobustANGLE(Context *context, + GLuint program, + GLenum pname, + GLsizei bufSize, + GLsizei *numParams) { - if (!context->getExtensions().occlusionQueryBoolean && - !context->getExtensions().disjointTimerQuery) + if (!ValidateRobustEntryPoint(context, bufSize)) { - context->recordError(Error(GL_INVALID_OPERATION, "Query extension not enabled")); return false; } - return ValidateGenQueriesBase(context, n, ids); -} + if (!ValidateGetProgramivBase(context, program, pname, numParams)) + { + return false; + } -bool ValidateDeleteQueriesBase(gl::Context *context, GLsizei n, const GLuint *ids) -{ - if (n < 0) + if (!ValidateRobustBufferSize(context, bufSize, *numParams)) { - context->recordError(Error(GL_INVALID_VALUE, "Query count < 0")); return false; } return true; } -bool ValidateDeleteQueriesEXT(gl::Context *context, GLsizei n, const GLuint *ids) +bool ValidateGetRenderbufferParameterivRobustANGLE(Context *context, + GLenum target, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLint *params) { - if (!context->getExtensions().occlusionQueryBoolean && - !context->getExtensions().disjointTimerQuery) + if (!ValidateRobustEntryPoint(context, bufSize)) { - context->recordError(Error(GL_INVALID_OPERATION, "Query extension not enabled")); return false; } - return ValidateDeleteQueriesBase(context, n, ids); -} - -bool ValidateBeginQueryBase(gl::Context *context, GLenum target, GLuint id) -{ - if (!ValidQueryType(context, target)) + if (!ValidateGetRenderbufferParameterivBase(context, target, pname, length)) { - context->recordError(Error(GL_INVALID_ENUM, "Invalid query target")); return false; } - if (id == 0) + if (!ValidateRobustBufferSize(context, bufSize, *length)) { - context->recordError(Error(GL_INVALID_OPERATION, "Query id is 0")); 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. + return true; +} - // TODO(ewell): I think this needs to be changed for timer and occlusion queries to work at the - // same time - if (context->getState().isQueryActive()) +bool ValidateGetShaderivRobustANGLE(Context *context, + GLuint shader, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLint *params) +{ + if (!ValidateRobustEntryPoint(context, bufSize)) { - context->recordError(Error(GL_INVALID_OPERATION, "Other query is active")); return false; } - Query *queryObject = context->getQuery(id, true, target); - - // check that name was obtained with glGenQueries - if (!queryObject) + if (!ValidateGetShaderivBase(context, shader, pname, length)) { - context->recordError(Error(GL_INVALID_OPERATION, "Invalid query id")); return false; } - // check for type mismatch - if (queryObject->getType() != target) + if (!ValidateRobustBufferSize(context, bufSize, *length)) { - context->recordError(Error(GL_INVALID_OPERATION, "Query type does not match target")); return false; } return true; } -bool ValidateBeginQueryEXT(gl::Context *context, GLenum target, GLuint id) +bool ValidateGetTexParameterfvRobustANGLE(Context *context, + GLenum target, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLfloat *params) { - if (!context->getExtensions().occlusionQueryBoolean && - !context->getExtensions().disjointTimerQuery) + if (!ValidateRobustEntryPoint(context, bufSize)) { - context->recordError(Error(GL_INVALID_OPERATION, "Query extension not enabled")); return false; } - return ValidateBeginQueryBase(context, target, id); + if (!ValidateGetTexParameterBase(context, target, pname, length)) + { + return false; + } + + if (!ValidateRobustBufferSize(context, bufSize, *length)) + { + return false; + } + + return true; } -bool ValidateEndQueryBase(gl::Context *context, GLenum target) +bool ValidateGetTexParameterivRobustANGLE(Context *context, + GLenum target, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLint *params) { - if (!ValidQueryType(context, target)) + if (!ValidateRobustEntryPoint(context, bufSize)) { - context->recordError(Error(GL_INVALID_ENUM, "Invalid query target")); return false; } - const Query *queryObject = context->getState().getActiveQuery(target); + if (!ValidateGetTexParameterBase(context, target, pname, length)) + { + return false; + } - if (queryObject == nullptr) + if (!ValidateRobustBufferSize(context, bufSize, *length)) { - context->recordError(Error(GL_INVALID_OPERATION, "Query target not active")); return false; } return true; } -bool ValidateEndQueryEXT(gl::Context *context, GLenum target) +bool ValidateTexParameterfvRobustANGLE(Context *context, + GLenum target, + GLenum pname, + GLsizei bufSize, + const GLfloat *params) { - if (!context->getExtensions().occlusionQueryBoolean && - !context->getExtensions().disjointTimerQuery) + if (!ValidateRobustEntryPoint(context, bufSize)) { - context->recordError(Error(GL_INVALID_OPERATION, "Query extension not enabled")); return false; } - return ValidateEndQueryBase(context, target); + return ValidateTexParameterBase(context, target, pname, bufSize, params); } -bool ValidateQueryCounterEXT(Context *context, GLuint id, GLenum target) +bool ValidateTexParameterivRobustANGLE(Context *context, + GLenum target, + GLenum pname, + GLsizei bufSize, + const GLint *params) { - if (!context->getExtensions().disjointTimerQuery) + if (!ValidateRobustEntryPoint(context, bufSize)) { - context->recordError(Error(GL_INVALID_OPERATION, "Disjoint timer query not enabled")); return false; } - if (target != GL_TIMESTAMP_EXT) + return ValidateTexParameterBase(context, target, pname, bufSize, params); +} + +bool ValidateGetSamplerParameterfvRobustANGLE(Context *context, + GLuint sampler, + GLenum pname, + GLuint bufSize, + GLsizei *length, + GLfloat *params) +{ + if (!ValidateRobustEntryPoint(context, bufSize)) { - context->recordError(Error(GL_INVALID_ENUM, "Invalid query target")); return false; } - Query *queryObject = context->getQuery(id, true, target); - if (queryObject == nullptr) + if (!ValidateGetSamplerParameterBase(context, sampler, pname, length)) { - context->recordError(Error(GL_INVALID_OPERATION, "Invalid query id")); return false; } - if (context->getState().isQueryActive(queryObject)) + if (!ValidateRobustBufferSize(context, bufSize, *length)) { - context->recordError(Error(GL_INVALID_OPERATION, "Query is active")); return false; } return true; } -bool ValidateGetQueryivBase(Context *context, GLenum target, GLenum pname) +bool ValidateGetSamplerParameterivRobustANGLE(Context *context, + GLuint sampler, + GLenum pname, + GLuint bufSize, + GLsizei *length, + GLint *params) { - if (!ValidQueryType(context, target) && target != GL_TIMESTAMP_EXT) + if (!ValidateRobustEntryPoint(context, bufSize)) { - context->recordError(Error(GL_INVALID_ENUM, "Invalid query type")); return false; } - switch (pname) + if (!ValidateGetSamplerParameterBase(context, sampler, pname, length)) { - case GL_CURRENT_QUERY_EXT: - if (target == GL_TIMESTAMP_EXT) - { - context->recordError( - Error(GL_INVALID_ENUM, "Cannot use current query for timestamp")); - return false; - } - break; - case GL_QUERY_COUNTER_BITS_EXT: - if (!context->getExtensions().disjointTimerQuery || - (target != GL_TIMESTAMP_EXT && target != GL_TIME_ELAPSED_EXT)) - { - context->recordError(Error(GL_INVALID_ENUM, "Invalid pname")); - return false; - } - break; - default: - context->recordError(Error(GL_INVALID_ENUM, "Invalid pname")); - return false; + return false; + } + + if (!ValidateRobustBufferSize(context, bufSize, *length)) + { + return false; } return true; } -bool ValidateGetQueryivEXT(Context *context, GLenum target, GLenum pname, GLint *params) +bool ValidateSamplerParameterfvRobustANGLE(Context *context, + GLuint sampler, + GLenum pname, + GLsizei bufSize, + const GLfloat *params) { - if (!context->getExtensions().occlusionQueryBoolean && - !context->getExtensions().disjointTimerQuery) + if (!ValidateRobustEntryPoint(context, bufSize)) { - context->recordError(Error(GL_INVALID_OPERATION, "Query extension not enabled")); return false; } - return ValidateGetQueryivBase(context, target, pname); + return ValidateSamplerParameterBase(context, sampler, pname, bufSize, params); } -bool ValidateGetQueryObjectValueBase(Context *context, GLuint id, GLenum pname) +bool ValidateSamplerParameterivRobustANGLE(Context *context, + GLuint sampler, + GLenum pname, + GLsizei bufSize, + const GLint *params) { - Query *queryObject = context->getQuery(id, false, GL_NONE); - - if (!queryObject) + if (!ValidateRobustEntryPoint(context, bufSize)) { - context->recordError(Error(GL_INVALID_OPERATION, "Query does not exist")); return false; } - if (context->getState().isQueryActive(queryObject)) + return ValidateSamplerParameterBase(context, sampler, pname, bufSize, params); +} + +bool ValidateGetVertexAttribfvRobustANGLE(Context *context, + GLuint index, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLfloat *params) +{ + if (!ValidateRobustEntryPoint(context, bufSize)) { - context->recordError(Error(GL_INVALID_OPERATION, "Query currently active")); return false; } - switch (pname) + if (!ValidateGetVertexAttribBase(context, index, pname, length, false, false)) { - case GL_QUERY_RESULT_EXT: - case GL_QUERY_RESULT_AVAILABLE_EXT: - break; + return false; + } - default: - context->recordError(Error(GL_INVALID_ENUM, "Invalid pname enum")); - return false; + if (!ValidateRobustBufferSize(context, bufSize, *length)) + { + return false; } return true; } -bool ValidateGetQueryObjectivEXT(Context *context, GLuint id, GLenum pname, GLint *params) +bool ValidateGetVertexAttribivRobustANGLE(Context *context, + GLuint index, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLint *params) { - if (!context->getExtensions().disjointTimerQuery) + if (!ValidateRobustEntryPoint(context, bufSize)) { - context->recordError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled")); return false; } - return ValidateGetQueryObjectValueBase(context, id, pname); -} -bool ValidateGetQueryObjectuivEXT(Context *context, GLuint id, GLenum pname, GLuint *params) -{ - if (!context->getExtensions().disjointTimerQuery && - !context->getExtensions().occlusionQueryBoolean) + if (!ValidateGetVertexAttribBase(context, index, pname, length, false, false)) { - context->recordError(Error(GL_INVALID_OPERATION, "Query extension not enabled")); return false; } - return ValidateGetQueryObjectValueBase(context, id, pname); -} -bool ValidateGetQueryObjecti64vEXT(Context *context, GLuint id, GLenum pname, GLint64 *params) -{ - if (!context->getExtensions().disjointTimerQuery) + if (!ValidateRobustBufferSize(context, bufSize, *length)) { - context->recordError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled")); return false; } - return ValidateGetQueryObjectValueBase(context, id, pname); + + return true; } -bool ValidateGetQueryObjectui64vEXT(Context *context, GLuint id, GLenum pname, GLuint64 *params) +bool ValidateGetVertexAttribPointervRobustANGLE(Context *context, + GLuint index, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + void **pointer) { - if (!context->getExtensions().disjointTimerQuery) + if (!ValidateRobustEntryPoint(context, bufSize)) { - context->recordError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled")); return false; } - return ValidateGetQueryObjectValueBase(context, id, pname); -} -static bool ValidateUniformCommonBase(gl::Context *context, - GLenum targetUniformType, - GLint location, - GLsizei count, - const LinkedUniform **uniformOut) -{ - if (count < 0) + if (!ValidateGetVertexAttribBase(context, index, pname, length, true, false)) { - context->recordError(Error(GL_INVALID_VALUE)); return false; } - gl::Program *program = context->getState().getProgram(); - if (!program) + if (!ValidateRobustBufferSize(context, bufSize, *length)) { - context->recordError(Error(GL_INVALID_OPERATION)); return false; } - if (location == -1) + return true; +} + +bool ValidateGetVertexAttribIivRobustANGLE(Context *context, + GLuint index, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLint *params) +{ + if (!ValidateRobustEntryPoint(context, bufSize)) { - // Silently ignore the uniform command return false; } - if (!program->isValidUniformLocation(location)) + if (!ValidateGetVertexAttribBase(context, index, pname, length, false, true)) { - context->recordError(Error(GL_INVALID_OPERATION)); return false; } - const LinkedUniform &uniform = program->getUniformByLocation(location); - - // attempting to write an array to a non-array uniform is an INVALID_OPERATION - if (!uniform.isArray() && count > 1) + if (!ValidateRobustBufferSize(context, bufSize, *length)) { - context->recordError(Error(GL_INVALID_OPERATION)); return false; } - *uniformOut = &uniform; return true; } -bool ValidateUniform(gl::Context *context, GLenum uniformType, GLint location, GLsizei count) +bool ValidateGetVertexAttribIuivRobustANGLE(Context *context, + GLuint index, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLuint *params) { - // Check for ES3 uniform entry points - if (VariableComponentType(uniformType) == GL_UNSIGNED_INT && context->getClientVersion() < 3) + if (!ValidateRobustEntryPoint(context, bufSize)) { - context->recordError(Error(GL_INVALID_OPERATION)); return false; } - const LinkedUniform *uniform = nullptr; - if (!ValidateUniformCommonBase(context, uniformType, location, count, &uniform)) + if (!ValidateGetVertexAttribBase(context, index, pname, length, false, true)) { return false; } - GLenum targetBoolType = VariableBoolVectorType(uniformType); - bool samplerUniformCheck = (IsSamplerType(uniform->type) && uniformType == GL_INT); - if (!samplerUniformCheck && uniformType != uniform->type && targetBoolType != uniform->type) + if (!ValidateRobustBufferSize(context, bufSize, *length)) { - context->recordError(Error(GL_INVALID_OPERATION)); return false; } return true; } -bool ValidateUniformMatrix(gl::Context *context, GLenum matrixType, GLint location, GLsizei count, - GLboolean transpose) +bool ValidateGetActiveUniformBlockivRobustANGLE(Context *context, + GLuint program, + GLuint uniformBlockIndex, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLint *params) { - // Check for ES3 uniform entry points - int rows = VariableRowCount(matrixType); - int cols = VariableColumnCount(matrixType); - if (rows != cols && context->getClientVersion() < 3) + if (!ValidateRobustEntryPoint(context, bufSize)) { - context->recordError(Error(GL_INVALID_OPERATION)); return false; } - if (transpose != GL_FALSE && context->getClientVersion() < 3) + if (!ValidateGetActiveUniformBlockivBase(context, program, uniformBlockIndex, pname, length)) { - context->recordError(Error(GL_INVALID_VALUE)); return false; } - const LinkedUniform *uniform = nullptr; - if (!ValidateUniformCommonBase(context, matrixType, location, count, &uniform)) + if (!ValidateRobustBufferSize(context, bufSize, *length)) + { + return false; + } + + return true; +} + +bool ValidateGetInternalFormativRobustANGLE(Context *context, + GLenum target, + GLenum internalformat, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLint *params) +{ + if (!ValidateRobustEntryPoint(context, bufSize)) + { + return false; + } + + if (!ValidateGetInternalFormativBase(context, target, internalformat, pname, bufSize, length)) { return false; } - if (uniform->type != matrixType) + if (!ValidateRobustBufferSize(context, bufSize, *length)) { - context->recordError(Error(GL_INVALID_OPERATION)); return false; } return true; } -bool ValidateStateQuery(gl::Context *context, GLenum pname, GLenum *nativeType, unsigned int *numParams) +bool ValidateVertexFormatBase(ValidationContext *context, + GLuint attribIndex, + GLint size, + GLenum type, + GLboolean pureInteger) { - if (!context->getQueryParameterInfo(pname, nativeType, numParams)) + const Caps &caps = context->getCaps(); + if (attribIndex >= caps.maxVertexAttributes) { - context->recordError(Error(GL_INVALID_ENUM)); + ANGLE_VALIDATION_ERR(context, InvalidValue(), IndexExceedsMaxVertexAttribute); return false; } - const Caps &caps = context->getCaps(); - - if (pname >= GL_DRAW_BUFFER0 && pname <= GL_DRAW_BUFFER15) + if (size < 1 || size > 4) { - unsigned int colorAttachment = (pname - GL_DRAW_BUFFER0); - - if (colorAttachment >= caps.maxDrawBuffers) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } + ANGLE_VALIDATION_ERR(context, InvalidValue(), InvalidVertexAttrSize); + return false; } - switch (pname) + switch (type) { - 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_BYTE: + case GL_UNSIGNED_BYTE: + case GL_SHORT: + case GL_UNSIGNED_SHORT: + 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) + case GL_INT: + case GL_UNSIGNED_INT: + if (context->getClientMajorVersion() < 3) { - context->recordError(Error(GL_INVALID_OPERATION)); + context->handleError(InvalidEnum() + << "Vertex type not supported before OpenGL ES 3.0."); return false; } + break; - const FramebufferAttachment *attachment = framebuffer->getReadColorbuffer(); - if (!attachment) + case GL_FIXED: + case GL_FLOAT: + if (pureInteger) { - context->recordError(Error(GL_INVALID_OPERATION)); + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidTypePureInt); return false; } - } - break; + break; - default: - break; - } + case GL_HALF_FLOAT: + if (context->getClientMajorVersion() < 3) + { + context->handleError(InvalidEnum() + << "Vertex type not supported before OpenGL ES 3.0."); + return false; + } + if (pureInteger) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidTypePureInt); + return false; + } + break; - // pname is valid, but there are no parameters to return - if (numParams == 0) - { - return false; + case GL_INT_2_10_10_10_REV: + case GL_UNSIGNED_INT_2_10_10_10_REV: + if (context->getClientMajorVersion() < 3) + { + context->handleError(InvalidEnum() + << "Vertex type not supported before OpenGL ES 3.0."); + return false; + } + if (pureInteger) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidTypePureInt); + return false; + } + if (size != 4) + { + context->handleError(InvalidOperation() << "Type is INT_2_10_10_10_REV or " + "UNSIGNED_INT_2_10_10_10_REV and " + "size is not 4."); + return false; + } + break; + + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidType); + return false; } return true; } -bool ValidateCopyTexImageParametersBase(ValidationContext *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) +// Perform validation from WebGL 2 section 5.10 "Invalid Clears": +// In the WebGL 2 API, trying to perform a clear when there is a mismatch between the type of the +// specified clear value and the type of a buffer that is being cleared generates an +// INVALID_OPERATION error instead of producing undefined results +bool ValidateWebGLFramebufferAttachmentClearType(ValidationContext *context, + GLint drawbuffer, + const GLenum *validComponentTypes, + size_t validComponentTypeCount) { - if (level < 0 || xoffset < 0 || yoffset < 0 || zoffset < 0 || width < 0 || height < 0) + const FramebufferAttachment *attachment = + context->getGLState().getDrawFramebuffer()->getDrawBuffer(drawbuffer); + if (attachment) { - context->recordError(Error(GL_INVALID_VALUE)); - return false; + GLenum componentType = attachment->getFormat().info->componentType; + const GLenum *end = validComponentTypes + validComponentTypeCount; + if (std::find(validComponentTypes, end, componentType) == end) + { + context->handleError( + InvalidOperation() + << "No defined conversion between clear value and attachment format."); + return false; + } } - if (std::numeric_limits::max() - xoffset < width || std::numeric_limits::max() - yoffset < height) + return true; +} + +bool ValidateRobustCompressedTexImageBase(ValidationContext *context, + GLsizei imageSize, + GLsizei dataSize) +{ + if (!ValidateRobustEntryPoint(context, dataSize)) { - context->recordError(Error(GL_INVALID_VALUE)); return false; } - if (border != 0) + gl::Buffer *pixelUnpackBuffer = + context->getGLState().getTargetBuffer(BufferBinding::PixelUnpack); + if (pixelUnpackBuffer == nullptr) { - context->recordError(Error(GL_INVALID_VALUE)); - return false; + if (dataSize < imageSize) + { + context->handleError(InvalidOperation() << "dataSize must be at least " << imageSize); + } } + return true; +} - if (!ValidMipLevel(context, target, level)) +bool ValidateGetBufferParameterBase(ValidationContext *context, + BufferBinding target, + GLenum pname, + bool pointerVersion, + GLsizei *numParams) +{ + if (numParams) { - context->recordError(Error(GL_INVALID_VALUE)); - return false; + *numParams = 0; } - const gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer(); - if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE) + if (!ValidBufferType(context, target)) { - context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION)); + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidBufferTypes); return false; } - const auto &state = context->getState(); - if (state.getReadFramebuffer()->id() != 0 && framebuffer->getSamples(context->getData()) != 0) + const Buffer *buffer = context->getGLState().getTargetBuffer(target); + if (!buffer) { - context->recordError(Error(GL_INVALID_OPERATION)); + // A null buffer means that "0" is bound to the requested buffer target + ANGLE_VALIDATION_ERR(context, InvalidOperation(), BufferNotBound); return false; } - const gl::Caps &caps = context->getCaps(); + const Extensions &extensions = context->getExtensions(); - GLuint maxDimension = 0; - switch (target) + switch (pname) { - case GL_TEXTURE_2D: - maxDimension = caps.max2DTextureSize; - break; + case GL_BUFFER_USAGE: + case GL_BUFFER_SIZE: + 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_BUFFER_ACCESS_OES: + if (!extensions.mapBuffer) + { + context->handleError(InvalidEnum() + << "pname requires OpenGL ES 3.0 or GL_OES_mapbuffer."); + return false; + } + break; - case GL_TEXTURE_2D_ARRAY: - maxDimension = caps.max2DTextureSize; - break; + case GL_BUFFER_MAPPED: + static_assert(GL_BUFFER_MAPPED == GL_BUFFER_MAPPED_OES, "GL enums should be equal."); + if (context->getClientMajorVersion() < 3 && !extensions.mapBuffer && + !extensions.mapBufferRange) + { + context->handleError(InvalidEnum() << "pname requires OpenGL ES 3.0, " + "GL_OES_mapbuffer or " + "GL_EXT_map_buffer_range."); + return false; + } + break; - case GL_TEXTURE_3D: - maxDimension = caps.max3DTextureSize; - break; + case GL_BUFFER_MAP_POINTER: + if (!pointerVersion) + { + context->handleError( + InvalidEnum() + << "GL_BUFFER_MAP_POINTER can only be queried with GetBufferPointerv."); + return false; + } + break; - default: - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } + case GL_BUFFER_ACCESS_FLAGS: + case GL_BUFFER_MAP_OFFSET: + case GL_BUFFER_MAP_LENGTH: + if (context->getClientMajorVersion() < 3 && !extensions.mapBufferRange) + { + context->handleError(InvalidEnum() + << "pname requires OpenGL ES 3.0 or GL_EXT_map_buffer_range."); + return false; + } + break; - gl::Texture *texture = - state.getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target); - if (!texture) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), EnumNotSupported); + return false; } - if (texture->getImmutableFormat() && !isSubImage) + // All buffer parameter queries return one value. + if (numParams) { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; + *numParams = 1; } - const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat); + return true; +} - if (formatInfo.depthBits > 0) +bool ValidateGetRenderbufferParameterivBase(Context *context, + GLenum target, + GLenum pname, + GLsizei *length) +{ + if (length) { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; + *length = 0; } - if (formatInfo.compressed && !ValidCompressedImageSize(context, internalformat, width, height)) + if (target != GL_RENDERBUFFER) { - context->recordError(Error(GL_INVALID_OPERATION)); + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidRenderbufferTarget); return false; } - if (isSubImage) + Renderbuffer *renderbuffer = context->getGLState().getCurrentRenderbuffer(); + if (renderbuffer == nullptr) { - 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; - } + ANGLE_VALIDATION_ERR(context, InvalidOperation(), RenderbufferNotBound); + return false; } - else + + switch (pname) { - if (IsCubeMapTextureTarget(target) && width != height) - { - context->recordError(Error(GL_INVALID_VALUE)); - return false; - } + case GL_RENDERBUFFER_WIDTH: + case GL_RENDERBUFFER_HEIGHT: + case GL_RENDERBUFFER_INTERNAL_FORMAT: + case GL_RENDERBUFFER_RED_SIZE: + case GL_RENDERBUFFER_GREEN_SIZE: + case GL_RENDERBUFFER_BLUE_SIZE: + case GL_RENDERBUFFER_ALPHA_SIZE: + case GL_RENDERBUFFER_DEPTH_SIZE: + case GL_RENDERBUFFER_STENCIL_SIZE: + break; - if (!formatInfo.textureSupport(context->getClientVersion(), context->getExtensions())) - { - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } + case GL_RENDERBUFFER_SAMPLES_ANGLE: + if (!context->getExtensions().framebufferMultisample) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), ExtensionNotEnabled); + return false; + } + break; - int maxLevelDimension = (maxDimension >> level); - if (static_cast(width) > maxLevelDimension || static_cast(height) > maxLevelDimension) - { - context->recordError(Error(GL_INVALID_VALUE)); + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), EnumNotSupported); return false; - } } - *textureFormatOut = texture->getInternalFormat(target, level); + if (length) + { + *length = 1; + } return true; } -static bool ValidateDrawBase(ValidationContext *context, - GLenum mode, - GLsizei count, - GLsizei primcount) +bool ValidateGetShaderivBase(Context *context, GLuint shader, GLenum pname, GLsizei *length) { - switch (mode) + if (length) { - 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; + *length = 0; } - if (count < 0) + if (GetValidShader(context, shader) == nullptr) { - context->recordError(Error(GL_INVALID_VALUE)); return false; } - const State &state = context->getState(); - - // Check for mapped buffers - if (state.hasMappedBuffer(GL_ARRAY_BUFFER)) + switch (pname) { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; + case GL_SHADER_TYPE: + case GL_DELETE_STATUS: + case GL_COMPILE_STATUS: + case GL_INFO_LOG_LENGTH: + case GL_SHADER_SOURCE_LENGTH: + break; + + case GL_TRANSLATED_SHADER_SOURCE_LENGTH_ANGLE: + if (!context->getExtensions().translatedShaderSource) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), ExtensionNotEnabled); + return false; + } + break; + + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), EnumNotSupported); + return false; } - if (context->getLimitations().noSeparateStencilRefsAndMasks) + if (length) { - const Framebuffer *framebuffer = context->getState().getDrawFramebuffer(); - const FramebufferAttachment *stencilBuffer = framebuffer->getStencilbuffer(); - GLuint stencilBits = stencilBuffer ? stencilBuffer->getStencilSize() : 0; - GLuint minimumRequiredStencilMask = (1 << stencilBits) - 1; - const DepthStencilState &depthStencilState = state.getDepthStencilState(); - if ((depthStencilState.stencilWritemask & minimumRequiredStencilMask) != - (depthStencilState.stencilBackWritemask & minimumRequiredStencilMask) || - state.getStencilRef() != state.getStencilBackRef() || - (depthStencilState.stencilMask & minimumRequiredStencilMask) != - (depthStencilState.stencilBackMask & minimumRequiredStencilMask)) - { - // 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; - } + *length = 1; } + return true; +} - const gl::Framebuffer *fbo = state.getDrawFramebuffer(); - if (!fbo || fbo->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE) +bool ValidateGetTexParameterBase(Context *context, GLenum target, GLenum pname, GLsizei *length) +{ + if (length) { - context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION)); - return false; + *length = 0; } - gl::Program *program = state.getProgram(); - if (!program) + if (!ValidTextureTarget(context, target) && !ValidTextureExternalTarget(context, target)) { - context->recordError(Error(GL_INVALID_OPERATION)); + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidTextureTarget); return false; } - if (!program->validateSamplers(NULL, context->getCaps())) + if (context->getTargetTexture(target) == nullptr) { - context->recordError(Error(GL_INVALID_OPERATION)); + // Should only be possible for external textures + ANGLE_VALIDATION_ERR(context, InvalidEnum(), TextureNotBound); return false; } - // Uniform buffer validation - for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < program->getActiveUniformBlockCount(); uniformBlockIndex++) + switch (pname) { - const gl::UniformBlock &uniformBlock = program->getUniformBlockByIndex(uniformBlockIndex); - GLuint blockBinding = program->getUniformBlockBinding(uniformBlockIndex); - const OffsetBindingPointer &uniformBuffer = - state.getIndexedUniformBuffer(blockBinding); + case GL_TEXTURE_MAG_FILTER: + case GL_TEXTURE_MIN_FILTER: + case GL_TEXTURE_WRAP_S: + case GL_TEXTURE_WRAP_T: + break; - if (uniformBuffer.get() == nullptr) - { - // undefined behaviour - context->recordError(Error(GL_INVALID_OPERATION, "It is undefined behaviour to have a used but unbound uniform buffer.")); - return false; - } + case GL_TEXTURE_USAGE_ANGLE: + if (!context->getExtensions().textureUsage) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), ExtensionNotEnabled); + return false; + } + break; - size_t uniformBufferSize = uniformBuffer.getSize(); - if (uniformBufferSize == 0) - { - // Bind the whole buffer. - uniformBufferSize = static_cast(uniformBuffer->getSize()); - } + case GL_TEXTURE_MAX_ANISOTROPY_EXT: + if (!context->getExtensions().textureFilterAnisotropic) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), ExtensionNotEnabled); + return false; + } + break; - 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.")); + case GL_TEXTURE_IMMUTABLE_FORMAT: + if (context->getClientMajorVersion() < 3 && !context->getExtensions().textureStorage) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), ExtensionNotEnabled); + return false; + } + break; + + case GL_TEXTURE_WRAP_R: + case GL_TEXTURE_IMMUTABLE_LEVELS: + 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_MIN_LOD: + case GL_TEXTURE_MAX_LOD: + case GL_TEXTURE_COMPARE_MODE: + case GL_TEXTURE_COMPARE_FUNC: + if (context->getClientMajorVersion() < 3) + { + context->handleError(InvalidEnum() << "pname requires OpenGL ES 3.0."); + return false; + } + break; + + case GL_TEXTURE_SRGB_DECODE_EXT: + if (!context->getExtensions().textureSRGBDecode) + { + context->handleError(InvalidEnum() << "GL_EXT_texture_sRGB_decode is not enabled."); + return false; + } + break; + + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), EnumNotSupported); return false; - } } - // No-op if zero count - return (count > 0); + if (length) + { + *length = 1; + } + return true; } -bool ValidateDrawArrays(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount) +bool ValidateGetVertexAttribBase(Context *context, + GLuint index, + GLenum pname, + GLsizei *length, + bool pointer, + bool pureIntegerEntryPoint) { - if (first < 0) + if (length) + { + *length = 0; + } + + if (pureIntegerEntryPoint && context->getClientMajorVersion() < 3) + { + context->handleError(InvalidOperation() << "Context does not support OpenGL ES 3.0."); + return false; + } + + if (index >= context->getCaps().maxVertexAttributes) { - context->recordError(Error(GL_INVALID_VALUE)); + ANGLE_VALIDATION_ERR(context, InvalidValue(), IndexExceedsMaxVertexAttribute); return false; } - const State &state = context->getState(); - gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback(); - if (curTransformFeedback && curTransformFeedback->isActive() && !curTransformFeedback->isPaused() && - curTransformFeedback->getPrimitiveMode() != 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 (pointer) + { + if (pname != GL_VERTEX_ATTRIB_ARRAY_POINTER) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), EnumNotSupported); + return false; + } + } + else + { + 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: + break; + + case GL_VERTEX_ATTRIB_ARRAY_DIVISOR: + static_assert( + GL_VERTEX_ATTRIB_ARRAY_DIVISOR == GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE, + "ANGLE extension enums not equal to GL enums."); + if (context->getClientMajorVersion() < 3 && + !context->getExtensions().instancedArrays) + { + context->handleError(InvalidEnum() << "GL_VERTEX_ATTRIB_ARRAY_DIVISOR " + "requires OpenGL ES 3.0 or " + "GL_ANGLE_instanced_arrays."); + return false; + } + break; + + case GL_VERTEX_ATTRIB_ARRAY_INTEGER: + if (context->getClientMajorVersion() < 3) + { + context->handleError( + InvalidEnum() << "GL_VERTEX_ATTRIB_ARRAY_INTEGER requires OpenGL ES 3.0."); + return false; + } + break; + + case GL_VERTEX_ATTRIB_BINDING: + case GL_VERTEX_ATTRIB_RELATIVE_OFFSET: + if (context->getClientVersion() < ES_3_1) + { + context->handleError(InvalidEnum() + << "Vertex Attrib Bindings require OpenGL ES 3.1."); + return false; + } + break; - if (!ValidateDrawBase(context, mode, count, primcount)) - { - return false; + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), EnumNotSupported); + return false; + } } - if (!ValidateDrawAttribs(context, primcount, count)) + if (length) { - return false; + if (pname == GL_CURRENT_VERTEX_ATTRIB) + { + *length = 4; + } + else + { + *length = 1; + } } return true; } -bool ValidateDrawArraysInstanced(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount) +bool ValidateReadPixelsBase(Context *context, + GLint x, + GLint y, + GLsizei width, + GLsizei height, + GLenum format, + GLenum type, + GLsizei bufSize, + GLsizei *length, + GLsizei *columns, + GLsizei *rows, + void *pixels) { - if (primcount < 0) + if (length != nullptr) { - context->recordError(Error(GL_INVALID_VALUE)); - return false; + *length = 0; } - - if (!ValidateDrawArrays(context, mode, first, count, primcount)) + if (rows != nullptr) { - return false; + *rows = 0; + } + if (columns != nullptr) + { + *columns = 0; } - // 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 (size_t attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++) + if (width < 0 || height < 0) { - const VertexAttribute &attrib = vao->getVertexAttribute(attributeIndex); - if (program->isAttribLocationActive(attributeIndex) && attrib.divisor == 0) - { - return true; - } + ANGLE_VALIDATION_ERR(context, InvalidValue(), NegativeSize); + return false; } - context->recordError(Error(GL_INVALID_OPERATION, "ANGLE_instanced_arrays requires that at least one active attribute" - "has a divisor of zero.")); - return false; -} + Framebuffer *readFramebuffer = context->getGLState().getReadFramebuffer(); -bool ValidateDrawArraysInstancedANGLE(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount) -{ - if (!ValidateDrawInstancedANGLE(context)) + if (readFramebuffer->checkStatus(context) != GL_FRAMEBUFFER_COMPLETE) { + context->handleError(InvalidFramebufferOperation()); return false; } - return ValidateDrawArraysInstanced(context, mode, first, count, primcount); -} - -bool ValidateDrawElements(ValidationContext *context, - GLenum mode, - GLsizei count, - GLenum type, - const GLvoid *indices, - GLsizei primcount, - IndexRange *indexRangeOut) -{ - switch (type) + if (readFramebuffer->id() != 0 && readFramebuffer->getSamples(context) != 0) { - case GL_UNSIGNED_BYTE: - case GL_UNSIGNED_SHORT: - break; - case GL_UNSIGNED_INT: - if (context->getClientVersion() < 3 && !context->getExtensions().elementIndexUint) - { - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } - break; - default: - context->recordError(Error(GL_INVALID_ENUM)); + context->handleError(InvalidOperation()); return false; } - const State &state = context->getState(); + const Framebuffer *framebuffer = context->getGLState().getReadFramebuffer(); + ASSERT(framebuffer); - gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback(); - if (curTransformFeedback && curTransformFeedback->isActive() && !curTransformFeedback->isPaused()) + if (framebuffer->getReadBufferState() == GL_NONE) { - // 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)); + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ReadBufferNone); return false; } - // Check for mapped buffers - if (state.hasMappedBuffer(GL_ELEMENT_ARRAY_BUFFER)) + const FramebufferAttachment *readBuffer = framebuffer->getReadColorbuffer(); + // WebGL 1.0 [Section 6.26] Reading From a Missing Attachment + // In OpenGL ES it is undefined what happens when an operation tries to read from a missing + // attachment and WebGL defines it to be an error. We do the check unconditionnaly as the + // situation is an application error that would lead to a crash in ANGLE. + if (readBuffer == nullptr) { - context->recordError(Error(GL_INVALID_OPERATION)); + ANGLE_VALIDATION_ERR(context, InvalidOperation(), MissingReadAttachment); return false; } - const gl::VertexArray *vao = state.getVertexArray(); - gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get(); - if (!indices && !elementArrayBuffer) + // ANGLE_multiview, Revision 1: + // ReadPixels generates an INVALID_FRAMEBUFFER_OPERATION error if the multi-view layout of the + // current read framebuffer is not NONE. + if (readBuffer->getMultiviewLayout() != GL_NONE) { - context->recordError(Error(GL_INVALID_OPERATION)); + context->handleError(InvalidFramebufferOperation() + << "Attempting to read from a multi-view framebuffer."); return false; } - if (elementArrayBuffer) + if (context->getExtensions().webglCompatibility) { - 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())) + // The ES 2.0 spec states that the format must be "among those defined in table 3.4, + // excluding formats LUMINANCE and LUMINANCE_ALPHA.". This requires validating the format + // and type before validating the combination of format and type. However, the + // dEQP-GLES3.functional.negative_api.buffer.read_pixels passes GL_LUMINANCE as a format and + // verifies that GL_INVALID_OPERATION is generated. + // TODO(geofflang): Update this check to be done in all/no cases once this is resolved in + // dEQP/WebGL. + if (!ValidReadPixelsFormatEnum(context, format)) { - context->recordError(Error(GL_OUT_OF_MEMORY)); + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidFormat); return false; } - // Check for reading past the end of the bound buffer object - if (byteCount > elementArrayBuffer->getSize()) + if (!ValidReadPixelsTypeEnum(context, type)) { - context->recordError(Error(GL_INVALID_OPERATION)); + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidType); return false; } } - else if (!indices) - { - // Catch this programming error here - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - if (!ValidateDrawBase(context, mode, count, primcount)) - { - return false; - } + GLenum currentFormat = framebuffer->getImplementationColorReadFormat(context); + GLenum currentType = framebuffer->getImplementationColorReadType(context); + GLenum currentComponentType = readBuffer->getFormat().info->componentType; - // 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); - Error error = - elementArrayBuffer->getIndexRange(type, static_cast(offset), count, - state.isPrimitiveRestartEnabled(), indexRangeOut); - if (error.isError()) - { - context->recordError(error); - return false; - } - } - else - { - *indexRangeOut = ComputeIndexRange(type, indices, count, state.isPrimitiveRestartEnabled()); - } + bool validFormatTypeCombination = + ValidReadPixelsFormatType(context, currentComponentType, format, type); - // If we use an index greater than our maximum supported index range, return an error. - // The ES3 spec does not specify behaviour here, it is undefined, but ANGLE should always - // return an error if possible here. - if (static_cast(indexRangeOut->end) >= context->getCaps().maxElementIndex) + if (!(currentFormat == format && currentType == type) && !validFormatTypeCombination) { - context->recordError(Error(GL_INVALID_OPERATION, g_ExceedsMaxElementErrorMessage)); + ANGLE_VALIDATION_ERR(context, InvalidOperation(), MismatchedTypeAndFormat); return false; } - if (!ValidateDrawAttribs(context, primcount, static_cast(indexRangeOut->end))) + // Check for pixel pack buffer related API errors + gl::Buffer *pixelPackBuffer = context->getGLState().getTargetBuffer(BufferBinding::PixelPack); + if (pixelPackBuffer != nullptr && pixelPackBuffer->isMapped()) { + // ...the buffer object's data store is currently mapped. + context->handleError(InvalidOperation() << "Pixel pack buffer is mapped."); return false; } - // No op if there are no real indices in the index data (all are primitive restart). - return (indexRangeOut->vertexIndexCount > 0); -} + // .. the data would be packed to the buffer object such that the memory writes required + // would exceed the data store size. + const InternalFormat &formatInfo = GetInternalFormatInfo(format, type); + const gl::Extents size(width, height, 1); + const auto &pack = context->getGLState().getPackState(); -bool ValidateDrawElementsInstanced(Context *context, - GLenum mode, - GLsizei count, - GLenum type, - const GLvoid *indices, - GLsizei primcount, - IndexRange *indexRangeOut) -{ - if (primcount < 0) + auto endByteOrErr = formatInfo.computePackUnpackEndByte(type, size, pack, false); + if (endByteOrErr.isError()) { - context->recordError(Error(GL_INVALID_VALUE)); + context->handleError(endByteOrErr.getError()); return false; } - if (!ValidateDrawElements(context, mode, count, type, indices, primcount, indexRangeOut)) + size_t endByte = endByteOrErr.getResult(); + if (bufSize >= 0) { - return false; + if (pixelPackBuffer == nullptr && static_cast(bufSize) < endByte) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), InsufficientBufferSize); + 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, - IndexRange *indexRangeOut) -{ - if (!ValidateDrawInstancedANGLE(context)) + if (pixelPackBuffer != nullptr) { - return false; - } - - return ValidateDrawElementsInstanced(context, mode, count, type, indices, primcount, indexRangeOut); -} + CheckedNumeric checkedEndByte(endByte); + CheckedNumeric checkedOffset(reinterpret_cast(pixels)); + checkedEndByte += checkedOffset; -bool ValidateFramebufferTextureBase(Context *context, GLenum target, GLenum attachment, - GLuint texture, GLint level) -{ - if (!ValidFramebufferTarget(target)) - { - context->recordError(Error(GL_INVALID_ENUM)); - return false; + if (checkedEndByte.ValueOrDie() > static_cast(pixelPackBuffer->getSize())) + { + // Overflow past the end of the buffer + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ParamOverflow); + return false; + } } - if (!ValidateAttachmentTarget(context, attachment)) + if (pixelPackBuffer == nullptr && length != nullptr) { - return false; + if (endByte > static_cast(std::numeric_limits::max())) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), IntegerOverflow); + return false; + } + + *length = static_cast(endByte); } - if (texture != 0) - { - gl::Texture *tex = context->getTexture(texture); + auto getClippedExtent = [](GLint start, GLsizei length, int bufferSize) { + angle::CheckedNumeric clippedExtent(length); + if (start < 0) + { + // "subtract" the area that is less than 0 + clippedExtent += start; + } - if (tex == NULL) + const int readExtent = start + length; + if (readExtent > bufferSize) { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; + // Subtract the region to the right of the read buffer + clippedExtent -= (readExtent - bufferSize); } - if (level < 0) + if (!clippedExtent.IsValid()) { - context->recordError(Error(GL_INVALID_VALUE)); - return false; + return 0; } - } - const gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target); - ASSERT(framebuffer); + return std::max(clippedExtent.ValueOrDie(), 0); + }; - if (framebuffer->id() == 0) + if (columns != nullptr) { - context->recordError(Error(GL_INVALID_OPERATION, "Cannot change default FBO's attachments")); - return false; + *columns = getClippedExtent(x, width, readBuffer->getSize().width); + } + + if (rows != nullptr) + { + *rows = getClippedExtent(y, height, readBuffer->getSize().height); } return true; } -bool ValidateFramebufferTexture2D(Context *context, GLenum target, GLenum attachment, - GLenum textarget, GLuint texture, GLint level) +template +bool ValidateTexParameterBase(Context *context, + GLenum target, + GLenum pname, + GLsizei bufSize, + const ParamType *params) { - // Attachments are required to be bound to level 0 without ES3 or the GL_OES_fbo_render_mipmap extension - if (context->getClientVersion() < 3 && !context->getExtensions().fboRenderMipmap && level != 0) + if (!ValidTextureTarget(context, target) && !ValidTextureExternalTarget(context, target)) { - context->recordError(Error(GL_INVALID_VALUE)); + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidTextureTarget); return false; } - if (!ValidateFramebufferTextureBase(context, target, attachment, texture, level)) + if (context->getTargetTexture(target) == nullptr) { + // Should only be possible for external textures + ANGLE_VALIDATION_ERR(context, InvalidEnum(), TextureNotBound); return false; } - if (texture != 0) + const GLsizei minBufSize = 1; + if (bufSize >= 0 && bufSize < minBufSize) { - gl::Texture *tex = context->getTexture(texture); - ASSERT(tex); + ANGLE_VALIDATION_ERR(context, InvalidOperation(), InsufficientBufferSize); + return false; + } + + 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->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), ES3Required); + return false; + } + if (target == GL_TEXTURE_EXTERNAL_OES && + !context->getExtensions().eglImageExternalEssl3) + { + context->handleError(InvalidEnum() << "ES3 texture parameters are not " + "available without " + "GL_OES_EGL_image_external_essl3."); + return false; + } + break; - const gl::Caps &caps = context->getCaps(); + default: + break; + } - switch (textarget) + if (target == GL_TEXTURE_2D_MULTISAMPLE) + { + switch (pname) { - case GL_TEXTURE_2D: + 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: + context->handleError(InvalidEnum() + << "Invalid parameter for 2D multisampled textures."); + return false; + } + } + + switch (pname) + { + case GL_TEXTURE_WRAP_S: + case GL_TEXTURE_WRAP_T: + case GL_TEXTURE_WRAP_R: { - if (level > gl::log2(caps.max2DTextureSize)) + bool restrictedWrapModes = + target == GL_TEXTURE_EXTERNAL_OES || target == GL_TEXTURE_RECTANGLE_ANGLE; + if (!ValidateTextureWrapModeValue(context, params, restrictedWrapModes)) { - 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: + case GL_TEXTURE_MIN_FILTER: { - if (level > gl::log2(caps.maxCubeMapTextureSize)) - { - context->recordError(Error(GL_INVALID_VALUE)); - return false; - } - if (tex->getTarget() != GL_TEXTURE_CUBE_MAP) + bool restrictedMinFilter = + target == GL_TEXTURE_EXTERNAL_OES || target == GL_TEXTURE_RECTANGLE_ANGLE; + if (!ValidateTextureMinFilterValue(context, params, restrictedMinFilter)) { - 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; - } - - gl::Program *programObject = GetValidProgram(context, program); - if (!programObject) - { - return false; - } - - if (!programObject || !programObject->isLinked()) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - - if (!programObject->isValidUniformLocation(location)) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } + case GL_TEXTURE_MAG_FILTER: + if (!ValidateTextureMagFilterValue(context, params)) + { + return false; + } + break; - return true; -} + case GL_TEXTURE_USAGE_ANGLE: + if (!context->getExtensions().textureUsage) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), EnumNotSupported); + return false; + } -bool ValidateGetUniformfv(Context *context, GLuint program, GLint location, GLfloat* params) -{ - return ValidateGetUniformBase(context, program, location); -} + switch (ConvertToGLenum(params[0])) + { + case GL_NONE: + case GL_FRAMEBUFFER_ATTACHMENT_ANGLE: + break; -bool ValidateGetUniformiv(Context *context, GLuint program, GLint location, GLint* params) -{ - return ValidateGetUniformBase(context, program, location); -} + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), EnumNotSupported); + return false; + } + break; -static bool ValidateSizedGetUniform(Context *context, GLuint program, GLint location, GLsizei bufSize) -{ - if (!ValidateGetUniformBase(context, program, location)) - { - return false; - } + case GL_TEXTURE_MAX_ANISOTROPY_EXT: + if (!context->getExtensions().textureFilterAnisotropic) + { + context->handleError(InvalidEnum() << "GL_EXT_texture_anisotropic is not enabled."); + return false; + } - gl::Program *programObject = context->getProgram(program); - ASSERT(programObject); + // we assume the parameter passed to this validation method is truncated, not rounded + if (params[0] < 1) + { + context->handleError(InvalidValue() << "Max anisotropy must be at least 1."); + return false; + } + break; - // sized queries -- ensure the provided buffer is large enough - const LinkedUniform &uniform = programObject->getUniformByLocation(location); - size_t requiredBytes = VariableExternalSize(uniform.type); - if (static_cast(bufSize) < requiredBytes) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } + case GL_TEXTURE_MIN_LOD: + case GL_TEXTURE_MAX_LOD: + // any value is permissible + break; - return true; -} + case GL_TEXTURE_COMPARE_MODE: + if (!ValidateTextureCompareModeValue(context, params)) + { + return false; + } + break; -bool ValidateGetnUniformfvEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLfloat* params) -{ - return ValidateSizedGetUniform(context, program, location, bufSize); -} + case GL_TEXTURE_COMPARE_FUNC: + if (!ValidateTextureCompareFuncValue(context, params)) + { + return false; + } + break; -bool ValidateGetnUniformivEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLint* params) -{ - return ValidateSizedGetUniform(context, program, location, bufSize); -} + case GL_TEXTURE_SWIZZLE_R: + case GL_TEXTURE_SWIZZLE_G: + case GL_TEXTURE_SWIZZLE_B: + case GL_TEXTURE_SWIZZLE_A: + switch (ConvertToGLenum(params[0])) + { + case GL_RED: + case GL_GREEN: + case GL_BLUE: + case GL_ALPHA: + case GL_ZERO: + case GL_ONE: + break; + + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), EnumNotSupported); + return false; + } + break; -bool ValidateDiscardFramebufferBase(Context *context, GLenum target, GLsizei numAttachments, - const GLenum *attachments, bool defaultFramebuffer) -{ - if (numAttachments < 0) - { - context->recordError(Error(GL_INVALID_VALUE, "numAttachments must not be less than zero")); - return false; - } + case GL_TEXTURE_BASE_LEVEL: + if (ConvertToGLint(params[0]) < 0) + { + context->handleError(InvalidValue() << "Base level must be at least 0."); + return false; + } + if (target == GL_TEXTURE_EXTERNAL_OES && static_cast(params[0]) != 0) + { + context->handleError(InvalidOperation() + << "Base level must be 0 for external textures."); + return false; + } + if (target == GL_TEXTURE_2D_MULTISAMPLE && static_cast(params[0]) != 0) + { + context->handleError(InvalidOperation() + << "Base level must be 0 for multisampled textures."); + return false; + } + if (target == GL_TEXTURE_RECTANGLE_ANGLE && static_cast(params[0]) != 0) + { + context->handleError(InvalidOperation() + << "Base level must be 0 for rectangle textures."); + return false; + } + break; - for (GLsizei i = 0; i < numAttachments; ++i) - { - if (attachments[i] >= GL_COLOR_ATTACHMENT0 && attachments[i] <= GL_COLOR_ATTACHMENT15) - { - if (defaultFramebuffer) + case GL_TEXTURE_MAX_LEVEL: + if (ConvertToGLint(params[0]) < 0) { - context->recordError(Error(GL_INVALID_ENUM, "Invalid attachment when the default framebuffer is bound")); + ANGLE_VALIDATION_ERR(context, InvalidValue(), InvalidMipLevel); return false; } + break; - if (attachments[i] >= GL_COLOR_ATTACHMENT0 + context->getCaps().maxColorAttachments) + case GL_DEPTH_STENCIL_TEXTURE_MODE: + if (context->getClientVersion() < Version(3, 1)) { - context->recordError(Error(GL_INVALID_OPERATION, - "Requested color attachment is greater than the maximum supported color attachments")); + ANGLE_VALIDATION_ERR(context, InvalidEnum(), EnumRequiresGLES31); return false; } - } - else - { - switch (attachments[i]) + switch (ConvertToGLenum(params[0])) { - case GL_DEPTH_ATTACHMENT: - case GL_STENCIL_ATTACHMENT: - case GL_DEPTH_STENCIL_ATTACHMENT: - if (defaultFramebuffer) - { - context->recordError(Error(GL_INVALID_ENUM, "Invalid attachment when the default framebuffer is bound")); - return false; - } - break; - case GL_COLOR: - case GL_DEPTH: - case GL_STENCIL: - if (!defaultFramebuffer) - { - context->recordError(Error(GL_INVALID_ENUM, "Invalid attachment when the default framebuffer is not bound")); + case GL_DEPTH_COMPONENT: + case GL_STENCIL_INDEX: + break; + + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), EnumNotSupported); return false; - } - break; - default: - context->recordError(Error(GL_INVALID_ENUM, "Invalid attachment")); + } + break; + + case GL_TEXTURE_SRGB_DECODE_EXT: + if (!ValidateTextureSRGBDecodeValue(context, params)) + { return false; } - } + break; + + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), EnumNotSupported); + return false; } return true; } -bool ValidateInsertEventMarkerEXT(Context *context, GLsizei length, const char *marker) -{ - // Note that debug marker calls must not set error state - - if (length < 0) - { - return false; - } +template bool ValidateTexParameterBase(Context *, GLenum, GLenum, GLsizei, const GLfloat *); +template bool ValidateTexParameterBase(Context *, GLenum, GLenum, GLsizei, const GLint *); - if (marker == nullptr) +bool ValidateVertexAttribIndex(ValidationContext *context, GLuint index) +{ + if (index >= MAX_VERTEX_ATTRIBS) { + ANGLE_VALIDATION_ERR(context, InvalidValue(), IndexExceedsMaxVertexAttribute); return false; } return true; } -bool ValidatePushGroupMarkerEXT(Context *context, GLsizei length, const char *marker) +bool ValidateGetActiveUniformBlockivBase(Context *context, + GLuint program, + GLuint uniformBlockIndex, + GLenum pname, + GLsizei *length) { - // Note that debug marker calls must not set error state + if (length) + { + *length = 0; + } - if (length < 0) + if (context->getClientMajorVersion() < 3) { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); return false; } - if (length > 0 && marker == nullptr) + Program *programObject = GetValidProgram(context, program); + if (!programObject) { return false; } - return true; -} - -bool ValidateEGLImageTargetTexture2DOES(Context *context, - egl::Display *display, - GLenum target, - egl::Image *image) -{ - if (!context->getExtensions().eglImage && !context->getExtensions().eglImageExternal) + if (uniformBlockIndex >= programObject->getActiveUniformBlockCount()) { - context->recordError(Error(GL_INVALID_OPERATION)); + context->handleError(InvalidValue() + << "uniformBlockIndex exceeds active uniform block count."); return false; } - switch (target) + switch (pname) { - case GL_TEXTURE_2D: + case GL_UNIFORM_BLOCK_BINDING: + case GL_UNIFORM_BLOCK_DATA_SIZE: + case GL_UNIFORM_BLOCK_NAME_LENGTH: + case GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS: + case GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES: + case GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER: + case GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER: break; default: - context->recordError(Error(GL_INVALID_ENUM, "invalid texture target.")); + ANGLE_VALIDATION_ERR(context, InvalidEnum(), EnumNotSupported); return false; } - if (!display->isValidImage(image)) + if (length) { - context->recordError(Error(GL_INVALID_VALUE, "EGL image is not valid.")); - return false; + if (pname == GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES) + { + const InterfaceBlock &uniformBlock = + programObject->getUniformBlockByIndex(uniformBlockIndex); + *length = static_cast(uniformBlock.memberIndexes.size()); + } + else + { + *length = 1; + } } - if (image->getSamples() > 0) + return true; +} + +template +bool ValidateSamplerParameterBase(Context *context, + GLuint sampler, + GLenum pname, + GLsizei bufSize, + ParamType *params) +{ + if (context->getClientMajorVersion() < 3) { - context->recordError(Error(GL_INVALID_OPERATION, - "cannot create a 2D texture from a multisampled EGL image.")); + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); return false; } - const TextureCaps &textureCaps = context->getTextureCaps().get(image->getInternalFormat()); - if (!textureCaps.texturable) + if (!context->isSampler(sampler)) { - context->recordError(Error(GL_INVALID_OPERATION, - "EGL image internal format is not supported as a texture.")); + ANGLE_VALIDATION_ERR(context, InvalidOperation(), InvalidSampler); return false; } - return true; -} - -bool ValidateEGLImageTargetRenderbufferStorageOES(Context *context, - egl::Display *display, - GLenum target, - egl::Image *image) -{ - if (!context->getExtensions().eglImage) + const GLsizei minBufSize = 1; + if (bufSize >= 0 && bufSize < minBufSize) { - context->recordError(Error(GL_INVALID_OPERATION)); + ANGLE_VALIDATION_ERR(context, InvalidOperation(), InsufficientBufferSize); return false; } - switch (target) + switch (pname) { - case GL_RENDERBUFFER: + case GL_TEXTURE_WRAP_S: + case GL_TEXTURE_WRAP_T: + case GL_TEXTURE_WRAP_R: + if (!ValidateTextureWrapModeValue(context, params, false)) + { + return false; + } break; - default: - context->recordError(Error(GL_INVALID_ENUM, "invalid renderbuffer target.")); - return false; - } + case GL_TEXTURE_MIN_FILTER: + if (!ValidateTextureMinFilterValue(context, params, false)) + { + return false; + } + break; - if (!display->isValidImage(image)) - { - context->recordError(Error(GL_INVALID_VALUE, "EGL image is not valid.")); - return false; - } + case GL_TEXTURE_MAG_FILTER: + if (!ValidateTextureMagFilterValue(context, params)) + { + return false; + } + break; - const TextureCaps &textureCaps = context->getTextureCaps().get(image->getInternalFormat()); - if (!textureCaps.renderable) - { - context->recordError(Error( - GL_INVALID_OPERATION, "EGL image internal format is not supported as a renderbuffer.")); - return false; - } + case GL_TEXTURE_MIN_LOD: + case GL_TEXTURE_MAX_LOD: + // any value is permissible + break; - return true; -} + case GL_TEXTURE_COMPARE_MODE: + if (!ValidateTextureCompareModeValue(context, params)) + { + return false; + } + break; -bool ValidateBindVertexArrayBase(Context *context, GLuint array) -{ - if (!context->isVertexArrayGenerated(array)) - { - // The default VAO should always exist - ASSERT(array != 0); - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } + case GL_TEXTURE_COMPARE_FUNC: + if (!ValidateTextureCompareFuncValue(context, params)) + { + return false; + } + break; - return true; -} + case GL_TEXTURE_SRGB_DECODE_EXT: + if (!ValidateTextureSRGBDecodeValue(context, params)) + { + return false; + } + break; -bool ValidateDeleteVertexArraysBase(Context *context, GLsizei n) -{ - if (n < 0) - { - context->recordError(Error(GL_INVALID_VALUE)); - return false; + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), EnumNotSupported); + return false; } return true; } -bool ValidateGenVertexArraysBase(Context *context, GLsizei n) +template bool ValidateSamplerParameterBase(Context *, GLuint, GLenum, GLsizei, GLfloat *); +template bool ValidateSamplerParameterBase(Context *, GLuint, GLenum, GLsizei, GLint *); + +bool ValidateGetSamplerParameterBase(Context *context, + GLuint sampler, + GLenum pname, + GLsizei *length) { - if (n < 0) + if (length) { - context->recordError(Error(GL_INVALID_VALUE)); - return false; + *length = 0; } - return true; -} - -bool ValidateProgramBinaryBase(Context *context, - GLuint program, - GLenum binaryFormat, - const void *binary, - GLint length) -{ - Program *programObject = GetValidProgram(context, program); - if (programObject == nullptr) + if (context->getClientMajorVersion() < 3) { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); return false; } - const std::vector &programBinaryFormats = context->getCaps().programBinaryFormats; - if (std::find(programBinaryFormats.begin(), programBinaryFormats.end(), binaryFormat) == - programBinaryFormats.end()) + if (!context->isSampler(sampler)) { - context->recordError(Error(GL_INVALID_ENUM, "Program binary format is not valid.")); + ANGLE_VALIDATION_ERR(context, InvalidOperation(), InvalidSampler); return false; } - return true; -} - -bool ValidateGetProgramBinaryBase(Context *context, - GLuint program, - GLsizei bufSize, - GLsizei *length, - GLenum *binaryFormat, - void *binary) -{ - Program *programObject = GetValidProgram(context, program); - if (programObject == nullptr) + switch (pname) { - return false; + case GL_TEXTURE_WRAP_S: + case GL_TEXTURE_WRAP_T: + case GL_TEXTURE_WRAP_R: + case GL_TEXTURE_MIN_FILTER: + case GL_TEXTURE_MAG_FILTER: + case GL_TEXTURE_MIN_LOD: + case GL_TEXTURE_MAX_LOD: + case GL_TEXTURE_COMPARE_MODE: + case GL_TEXTURE_COMPARE_FUNC: + break; + + case GL_TEXTURE_SRGB_DECODE_EXT: + if (!context->getExtensions().textureSRGBDecode) + { + context->handleError(InvalidEnum() << "GL_EXT_texture_sRGB_decode is not enabled."); + return false; + } + break; + + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), EnumNotSupported); + return false; } - if (!programObject->isLinked()) + if (length) { - context->recordError(Error(GL_INVALID_OPERATION, "Program is not linked.")); - return false; + *length = 1; } - return true; } -bool ValidateCopyTexImage2D(ValidationContext *context, - GLenum target, - GLint level, - GLenum internalformat, - GLint x, - GLint y, - GLsizei width, - GLsizei height, - GLint border) +bool ValidateGetInternalFormativBase(Context *context, + GLenum target, + GLenum internalformat, + GLenum pname, + GLsizei bufSize, + GLsizei *numParams) { - if (context->getClientVersion() < 3) + if (numParams) { - return ValidateES2CopyTexImageParameters(context, target, level, internalformat, false, 0, - 0, x, y, width, height, border); + *numParams = 0; } - ASSERT(context->getClientVersion() == 3); - return ValidateES3CopyTexImage2DParameters(context, target, level, internalformat, false, 0, 0, - 0, x, y, width, height, border); -} - -bool ValidateFramebufferRenderbuffer(Context *context, - GLenum target, - GLenum attachment, - GLenum renderbuffertarget, - GLuint renderbuffer) -{ - if (!ValidFramebufferTarget(target) || - (renderbuffertarget != GL_RENDERBUFFER && renderbuffer != 0)) + if (context->getClientMajorVersion() < 3) { - context->recordError(Error(GL_INVALID_ENUM)); + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); return false; } - return ValidateFramebufferRenderbufferParameters(context, target, attachment, - renderbuffertarget, renderbuffer); -} - -bool ValidateDrawBuffersBase(ValidationContext *context, GLsizei n, const GLenum *bufs) -{ - // INVALID_VALUE is generated if n is negative or greater than value of MAX_DRAW_BUFFERS - if (n < 0 || static_cast(n) > context->getCaps().maxDrawBuffers) + const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat); + if (!formatCaps.renderable) { - context->recordError( - Error(GL_INVALID_VALUE, "n must be non-negative and no greater than MAX_DRAW_BUFFERS")); + context->handleError(InvalidEnum() << "Internal format is not renderable."); return false; } - ASSERT(context->getState().getDrawFramebuffer()); - GLuint frameBufferId = context->getState().getDrawFramebuffer()->id(); - GLuint maxColorAttachment = GL_COLOR_ATTACHMENT0_EXT + context->getCaps().maxColorAttachments; - - // This should come first before the check for the default frame buffer - // because when we switch to ES3.1+, invalid enums will return INVALID_ENUM - // rather than INVALID_OPERATION - for (int colorAttachment = 0; colorAttachment < n; colorAttachment++) + switch (target) { - const GLenum attachment = GL_COLOR_ATTACHMENT0_EXT + colorAttachment; + case GL_RENDERBUFFER: + break; - if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != GL_BACK && - (bufs[colorAttachment] < GL_COLOR_ATTACHMENT0_EXT || - bufs[colorAttachment] >= maxColorAttachment)) - { - // Value in bufs is not NONE, BACK, or GL_COLOR_ATTACHMENTi - // In the 3.0 specs, the error should return GL_INVALID_OPERATION. - // When we move to 3.1 specs, we should change the error to be GL_INVALID_ENUM - context->recordError(Error(GL_INVALID_OPERATION, "Invalid buffer value")); - return false; - } - else if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != attachment && - frameBufferId != 0) - { - // INVALID_OPERATION-GL is bound to buffer and ith argument - // is not COLOR_ATTACHMENTi or NONE - context->recordError( - Error(GL_INVALID_OPERATION, "Ith value does not match COLOR_ATTACHMENTi or NONE")); + case GL_TEXTURE_2D_MULTISAMPLE: + if (context->getClientVersion() < ES_3_1) + { + context->handleError(InvalidOperation() + << "Texture target requires at least OpenGL ES 3.1."); + return false; + } + break; + + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidTarget); return false; - } } - // INVALID_OPERATION is generated if GL is bound to the default framebuffer - // and n is not 1 or bufs is bound to value other than BACK and NONE - if (frameBufferId == 0) + if (bufSize < 0) { - if (n != 1) - { - context->recordError(Error(GL_INVALID_OPERATION, - "n must be 1 when GL is bound to the default framebuffer")); - return false; - } + ANGLE_VALIDATION_ERR(context, InvalidValue(), InsufficientBufferSize); + return false; + } - if (bufs[0] != GL_NONE && bufs[0] != GL_BACK) - { - context->recordError(Error( - GL_INVALID_OPERATION, - "Only NONE or BACK are valid values when drawing to the default framebuffer")); + GLsizei maxWriteParams = 0; + switch (pname) + { + case GL_NUM_SAMPLE_COUNTS: + maxWriteParams = 1; + break; + + case GL_SAMPLES: + maxWriteParams = static_cast(formatCaps.sampleCounts.size()); + break; + + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), EnumNotSupported); return false; - } } - return true; -} - -bool ValidateCopyTexSubImage2D(Context *context, - GLenum target, - GLint level, - GLint xoffset, - GLint yoffset, - GLint x, - GLint y, - GLsizei width, - GLsizei height) -{ - if (context->getClientVersion() < 3) + if (numParams) { - return ValidateES2CopyTexImageParameters(context, target, level, GL_NONE, true, xoffset, - yoffset, x, y, width, height, 0); + // glGetInternalFormativ will not overflow bufSize + *numParams = std::min(bufSize, maxWriteParams); } - return ValidateES3CopyTexImage2DParameters(context, target, level, GL_NONE, true, xoffset, - yoffset, 0, x, y, width, height, 0); + return true; } } // namespace gl diff --git a/src/3rdparty/angle/src/libANGLE/validationES.h b/src/3rdparty/angle/src/libANGLE/validationES.h index 5d8486a6ab..e29432b8c3 100644 --- a/src/3rdparty/angle/src/libANGLE/validationES.h +++ b/src/3rdparty/angle/src/libANGLE/validationES.h @@ -10,9 +10,11 @@ #define LIBANGLE_VALIDATION_ES_H_ #include "common/mathutil.h" +#include "libANGLE/PackedGLEnums.h" #include #include +#include namespace egl { @@ -23,21 +25,24 @@ class Image; namespace gl { class Context; +struct Format; +struct LinkedUniform; class Program; class Shader; class ValidationContext; -bool ValidCap(const Context *context, GLenum cap); bool ValidTextureTarget(const ValidationContext *context, GLenum target); bool ValidTexture2DTarget(const ValidationContext *context, GLenum target); bool ValidTexture3DTarget(const ValidationContext *context, GLenum target); +bool ValidTextureExternalTarget(const ValidationContext *context, GLenum target); bool ValidTexture2DDestinationTarget(const ValidationContext *context, GLenum target); bool ValidTexture3DDestinationTarget(const ValidationContext *context, GLenum target); -bool ValidFramebufferTarget(GLenum target); -bool ValidBufferTarget(const Context *context, GLenum target); -bool ValidBufferParameter(const Context *context, GLenum pname); +bool ValidTexLevelDestinationTarget(const ValidationContext *context, GLenum target); +bool ValidFramebufferTarget(const ValidationContext *context, GLenum target); +bool ValidBufferType(const ValidationContext *context, BufferBinding target); +bool ValidBufferParameter(const ValidationContext *context, GLenum pname, GLsizei *numParams); bool ValidMipLevel(const ValidationContext *context, GLenum target, GLint level); -bool ValidImageSizeParameters(const Context *context, +bool ValidImageSizeParameters(ValidationContext *context, GLenum target, GLint level, GLsizei width, @@ -46,30 +51,60 @@ bool ValidImageSizeParameters(const Context *context, bool isSubImage); bool ValidCompressedImageSize(const ValidationContext *context, GLenum internalFormat, + GLint level, GLsizei width, GLsizei height); +bool ValidCompressedSubImageSize(const ValidationContext *context, + GLenum internalFormat, + GLint xoffset, + GLint yoffset, + GLsizei width, + GLsizei height, + size_t textureWidth, + size_t textureHeight); +bool ValidImageDataSize(ValidationContext *context, + GLenum textureTarget, + GLsizei width, + GLsizei height, + GLsizei depth, + GLenum format, + GLenum type, + const void *pixels, + GLsizei imageSize); + bool ValidQueryType(const Context *context, GLenum queryType); +bool ValidateWebGLVertexAttribPointer(ValidationContext *context, + GLenum type, + GLboolean normalized, + GLsizei stride, + const void *ptr, + bool pureInteger); + // Returns valid program if id is a valid program name // Errors INVALID_OPERATION if valid shader is given and returns NULL // Errors INVALID_VALUE otherwise and returns NULL -Program *GetValidProgram(Context *context, GLuint id); +Program *GetValidProgram(ValidationContext *context, GLuint id); // Returns valid shader if id is a valid shader name // Errors INVALID_OPERATION if valid program is given and returns NULL // Errors INVALID_VALUE otherwise and returns NULL -Shader *GetValidShader(Context *context, GLuint id); +Shader *GetValidShader(ValidationContext *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, +bool ValidateRenderbufferStorageParametersBase(ValidationContext *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(ValidationContext *context, GLint srcX0, GLint srcY0, GLint srcX1, @@ -81,20 +116,30 @@ bool ValidateBlitFramebufferParameters(Context *context, GLbitfield mask, GLenum filter); -bool ValidateGetVertexAttribParameters(Context *context, GLenum pname); - -bool ValidateTexParamParameters(Context *context, GLenum pname, GLint param); - -bool ValidateSamplerObjectParameter(Context *context, GLenum pname); - -bool ValidateReadPixels(Context *context, - GLint x, - GLint y, - GLsizei width, - GLsizei height, - GLenum format, - GLenum type, - GLvoid *pixels); +bool ValidateReadPixelsBase(Context *context, + GLint x, + GLint y, + GLsizei width, + GLsizei height, + GLenum format, + GLenum type, + GLsizei bufSize, + GLsizei *length, + GLsizei *columns, + GLsizei *rows, + void *pixels); +bool ValidateReadPixelsRobustANGLE(Context *context, + GLint x, + GLint y, + GLsizei width, + GLsizei height, + GLenum format, + GLenum type, + GLsizei bufSize, + GLsizei *length, + GLsizei *columns, + GLsizei *rows, + void *pixels); bool ValidateReadnPixelsEXT(Context *context, GLint x, GLint y, @@ -103,30 +148,97 @@ bool ValidateReadnPixelsEXT(Context *context, GLenum format, GLenum type, GLsizei bufSize, - GLvoid *pixels); - -bool ValidateGenQueriesBase(gl::Context *context, GLsizei n, const GLuint *ids); -bool ValidateGenQueriesEXT(gl::Context *context, GLsizei n, const GLuint *ids); -bool ValidateDeleteQueriesBase(gl::Context *context, GLsizei n, const GLuint *ids); + void *pixels); +bool ValidateReadnPixelsRobustANGLE(Context *context, + GLint x, + GLint y, + GLsizei width, + GLsizei height, + GLenum format, + GLenum type, + GLsizei bufSize, + GLsizei *length, + GLsizei *columns, + GLsizei *rows, + void *data); + +bool ValidateGenQueriesEXT(gl::Context *context, GLsizei n, GLuint *ids); bool ValidateDeleteQueriesEXT(gl::Context *context, GLsizei n, const GLuint *ids); +bool ValidateIsQueryEXT(gl::Context *context, GLuint id); bool ValidateBeginQueryBase(Context *context, GLenum target, GLuint id); bool ValidateBeginQueryEXT(Context *context, GLenum target, GLuint id); bool ValidateEndQueryBase(Context *context, GLenum target); bool ValidateEndQueryEXT(Context *context, GLenum target); bool ValidateQueryCounterEXT(Context *context, GLuint id, GLenum target); -bool ValidateGetQueryivBase(Context *context, GLenum target, GLenum pname); +bool ValidateGetQueryivBase(Context *context, GLenum target, GLenum pname, GLsizei *numParams); bool ValidateGetQueryivEXT(Context *context, GLenum target, GLenum pname, GLint *params); -bool ValidateGetQueryObjectValueBase(Context *context, GLenum target, GLenum pname); +bool ValidateGetQueryivRobustANGLE(Context *context, + GLenum target, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLint *params); +bool ValidateGetQueryObjectValueBase(Context *context, + GLenum target, + GLenum pname, + GLsizei *numParams); bool ValidateGetQueryObjectivEXT(Context *context, GLuint id, GLenum pname, GLint *params); +bool ValidateGetQueryObjectivRobustANGLE(Context *context, + GLuint id, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLint *params); bool ValidateGetQueryObjectuivEXT(Context *context, GLuint id, GLenum pname, GLuint *params); +bool ValidateGetQueryObjectuivRobustANGLE(Context *context, + GLuint id, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLuint *params); bool ValidateGetQueryObjecti64vEXT(Context *context, GLuint id, GLenum pname, GLint64 *params); +bool ValidateGetQueryObjecti64vRobustANGLE(Context *context, + GLuint id, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLint64 *params); bool ValidateGetQueryObjectui64vEXT(Context *context, GLuint id, GLenum pname, GLuint64 *params); - -bool ValidateUniform(Context *context, GLenum uniformType, GLint location, GLsizei count); -bool ValidateUniformMatrix(Context *context, GLenum matrixType, GLint location, GLsizei count, +bool ValidateGetQueryObjectui64vRobustANGLE(Context *context, + GLuint id, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLuint64 *params); + +bool ValidateUniformCommonBase(ValidationContext *context, + gl::Program *program, + GLint location, + GLsizei count, + const LinkedUniform **uniformOut); +bool ValidateUniform1ivValue(ValidationContext *context, + GLenum uniformType, + GLsizei count, + const GLint *value); +bool ValidateUniformValue(ValidationContext *context, GLenum valueType, GLenum uniformType); +bool ValidateUniformMatrixValue(ValidationContext *context, GLenum valueType, GLenum uniformType); +bool ValidateUniform(ValidationContext *context, GLenum uniformType, GLint location, GLsizei count); +bool ValidateUniformMatrix(ValidationContext *context, + GLenum matrixType, + GLint location, + GLsizei count, GLboolean transpose); -bool ValidateStateQuery(Context *context, GLenum pname, GLenum *nativeType, unsigned int *numParams); +bool ValidateStateQuery(ValidationContext *context, + GLenum pname, + GLenum *nativeType, + unsigned int *numParams); + +bool ValidateRobustStateQuery(ValidationContext *context, + GLenum pname, + GLsizei bufSize, + GLenum *nativeType, + unsigned int *numParams); bool ValidateCopyTexImageParametersBase(ValidationContext *context, GLenum target, @@ -141,69 +253,99 @@ bool ValidateCopyTexImageParametersBase(ValidationContext *context, 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(ValidationContext *context, - GLenum mode, - GLsizei count, - GLenum type, - const GLvoid *indices, - GLsizei primcount, - IndexRange *indexRangeOut); - -bool ValidateDrawElementsInstanced(Context *context, - GLenum mode, - GLsizei count, - GLenum type, - const GLvoid *indices, - GLsizei primcount, - IndexRange *indexRangeOut); + Format *textureFormatOut); + +bool ValidateDrawBase(ValidationContext *context, GLenum mode, GLsizei count); +bool ValidateDrawArraysCommon(ValidationContext *context, + GLenum mode, + GLint first, + GLsizei count, + GLsizei primcount); +bool ValidateDrawArraysInstancedBase(Context *context, + GLenum mode, + GLint first, + GLsizei count, + GLsizei primcount); +bool ValidateDrawArraysInstancedANGLE(Context *context, + GLenum mode, + GLint first, + GLsizei count, + GLsizei primcount); + +bool ValidateDrawElementsBase(ValidationContext *context, GLenum type); +bool ValidateDrawElementsCommon(ValidationContext *context, + GLenum mode, + GLsizei count, + GLenum type, + const void *indices, + GLsizei primcount); + +bool ValidateDrawElementsInstancedCommon(ValidationContext *context, + GLenum mode, + GLsizei count, + GLenum type, + const void *indices, + GLsizei primcount); bool ValidateDrawElementsInstancedANGLE(Context *context, GLenum mode, GLsizei count, GLenum type, - const GLvoid *indices, - GLsizei primcount, - IndexRange *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 ValidateFramebufferRenderbuffer(Context *context, - GLenum target, - GLenum attachment, - GLenum renderbuffertarget, - GLuint renderbuffer); + const void *indices, + GLsizei primcount); -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); +bool ValidateFramebufferTextureBase(Context *context, + GLenum target, + GLenum attachment, + GLuint texture, + GLint level); -bool ValidateDiscardFramebufferBase(Context *context, GLenum target, GLsizei numAttachments, - const GLenum *attachments, bool defaultFramebuffer); +bool ValidateGetUniformBase(Context *context, GLuint program, GLint location); +bool ValidateGetnUniformfvEXT(Context *context, + GLuint program, + GLint location, + GLsizei bufSize, + GLfloat *params); +bool ValidateGetnUniformivEXT(Context *context, + GLuint program, + GLint location, + GLsizei bufSize, + GLint *params); +bool ValidateGetUniformfvRobustANGLE(Context *context, + GLuint program, + GLint location, + GLsizei bufSize, + GLsizei *length, + GLfloat *params); +bool ValidateGetUniformivRobustANGLE(Context *context, + GLuint program, + GLint location, + GLsizei bufSize, + GLsizei *length, + GLint *params); +bool ValidateGetUniformuivRobustANGLE(Context *context, + GLuint program, + GLint location, + GLsizei bufSize, + GLsizei *length, + GLuint *params); + +bool ValidateDiscardFramebufferBase(Context *context, + GLenum target, + GLsizei numAttachments, + const GLenum *attachments, + bool defaultFramebuffer); bool ValidateInsertEventMarkerEXT(Context *context, GLsizei length, const char *marker); bool ValidatePushGroupMarkerEXT(Context *context, GLsizei length, const char *marker); bool ValidateEGLImageTargetTexture2DOES(Context *context, - egl::Display *display, GLenum target, egl::Image *image); bool ValidateEGLImageTargetRenderbufferStorageOES(Context *context, - egl::Display *display, GLenum target, egl::Image *image); bool ValidateBindVertexArrayBase(Context *context, GLuint array); -bool ValidateDeleteVertexArraysBase(Context *context, GLsizei n); -bool ValidateGenVertexArraysBase(Context *context, GLsizei n); bool ValidateProgramBinaryBase(Context *context, GLuint program, @@ -217,28 +359,243 @@ bool ValidateGetProgramBinaryBase(Context *context, GLenum *binaryFormat, void *binary); -bool ValidateCopyTexImage2D(ValidationContext *context, - GLenum target, - GLint level, - GLenum internalformat, - GLint x, - GLint y, - GLsizei width, - GLsizei height, - GLint border); bool ValidateDrawBuffersBase(ValidationContext *context, GLsizei n, const GLenum *bufs); -bool ValidateCopyTexSubImage2D(Context *context, - GLenum target, - GLint level, - GLint xoffset, - GLint yoffset, - GLint x, - GLint y, - GLsizei width, - GLsizei height); - -// Error messages shared here for use in testing. -extern const char *g_ExceedsMaxElementErrorMessage; + +bool ValidateGetBufferPointervBase(Context *context, + BufferBinding target, + GLenum pname, + GLsizei *length, + void **params); +bool ValidateUnmapBufferBase(Context *context, BufferBinding target); +bool ValidateMapBufferRangeBase(Context *context, + BufferBinding target, + GLintptr offset, + GLsizeiptr length, + GLbitfield access); +bool ValidateFlushMappedBufferRangeBase(Context *context, + BufferBinding target, + GLintptr offset, + GLsizeiptr length); + +bool ValidateGenOrDelete(Context *context, GLint n); + +bool ValidateRobustEntryPoint(ValidationContext *context, GLsizei bufSize); +bool ValidateRobustBufferSize(ValidationContext *context, GLsizei bufSize, GLsizei numParams); + +bool ValidateGetFramebufferAttachmentParameterivBase(ValidationContext *context, + GLenum target, + GLenum attachment, + GLenum pname, + GLsizei *numParams); +bool ValidateGetFramebufferAttachmentParameterivRobustANGLE(ValidationContext *context, + GLenum target, + GLenum attachment, + GLenum pname, + GLsizei bufSize, + GLsizei *numParams); + +bool ValidateGetBufferParameterBase(ValidationContext *context, + BufferBinding target, + GLenum pname, + bool pointerVersion, + GLsizei *numParams); +bool ValidateGetBufferParameterivRobustANGLE(ValidationContext *context, + BufferBinding target, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLint *params); + +bool ValidateGetBufferParameteri64vRobustANGLE(ValidationContext *context, + BufferBinding target, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLint64 *params); + +bool ValidateGetProgramivBase(ValidationContext *context, + GLuint program, + GLenum pname, + GLsizei *numParams); +bool ValidateGetProgramivRobustANGLE(Context *context, + GLuint program, + GLenum pname, + GLsizei bufSize, + GLsizei *numParams); + +bool ValidateGetRenderbufferParameterivBase(Context *context, + GLenum target, + GLenum pname, + GLsizei *length); +bool ValidateGetRenderbufferParameterivRobustANGLE(Context *context, + GLenum target, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLint *params); + +bool ValidateGetShaderivBase(Context *context, GLuint shader, GLenum pname, GLsizei *length); +bool ValidateGetShaderivRobustANGLE(Context *context, + GLuint shader, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLint *params); + +bool ValidateGetTexParameterBase(Context *context, GLenum target, GLenum pname, GLsizei *length); +bool ValidateGetTexParameterfvRobustANGLE(Context *context, + GLenum target, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLfloat *params); +bool ValidateGetTexParameterivRobustANGLE(Context *context, + GLenum target, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLint *params); + +template +bool ValidateTexParameterBase(Context *context, + GLenum target, + GLenum pname, + GLsizei bufSize, + const ParamType *params); +bool ValidateTexParameterfvRobustANGLE(Context *context, + GLenum target, + GLenum pname, + GLsizei bufSize, + const GLfloat *params); +bool ValidateTexParameterivRobustANGLE(Context *context, + GLenum target, + GLenum pname, + GLsizei bufSize, + const GLint *params); + +bool ValidateGetSamplerParameterfvRobustANGLE(Context *context, + GLuint sampler, + GLenum pname, + GLuint bufSize, + GLsizei *length, + GLfloat *params); +bool ValidateGetSamplerParameterivRobustANGLE(Context *context, + GLuint sampler, + GLenum pname, + GLuint bufSize, + GLsizei *length, + GLint *params); + +bool ValidateSamplerParameterfvRobustANGLE(Context *context, + GLuint sampler, + GLenum pname, + GLsizei bufSize, + const GLfloat *params); +bool ValidateSamplerParameterivRobustANGLE(Context *context, + GLuint sampler, + GLenum pname, + GLsizei bufSize, + const GLint *params); + +bool ValidateGetVertexAttribBase(Context *context, + GLuint index, + GLenum pname, + GLsizei *length, + bool pointer, + bool pureIntegerEntryPoint); +bool ValidateGetVertexAttribfvRobustANGLE(Context *context, + GLuint index, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLfloat *params); + +bool ValidateGetVertexAttribivRobustANGLE(Context *context, + GLuint index, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLint *params); + +bool ValidateGetVertexAttribPointervRobustANGLE(Context *context, + GLuint index, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + void **pointer); + +bool ValidateGetVertexAttribIivRobustANGLE(Context *context, + GLuint index, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLint *params); + +bool ValidateGetVertexAttribIuivRobustANGLE(Context *context, + GLuint index, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLuint *params); + +bool ValidateGetActiveUniformBlockivRobustANGLE(Context *context, + GLuint program, + GLuint uniformBlockIndex, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLint *params); + +bool ValidateGetInternalFormativRobustANGLE(Context *context, + GLenum target, + GLenum internalformat, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLint *params); + +bool ValidateVertexFormatBase(ValidationContext *context, + GLuint attribIndex, + GLint size, + GLenum type, + GLboolean pureInteger); + +bool ValidateWebGLFramebufferAttachmentClearType(ValidationContext *context, + GLint drawbuffer, + const GLenum *validComponentTypes, + size_t validComponentTypeCount); + +bool ValidateRobustCompressedTexImageBase(ValidationContext *context, + GLsizei imageSize, + GLsizei dataSize); + +bool ValidateVertexAttribIndex(ValidationContext *context, GLuint index); + +bool ValidateGetActiveUniformBlockivBase(Context *context, + GLuint program, + GLuint uniformBlockIndex, + GLenum pname, + GLsizei *length); + +bool ValidateGetSamplerParameterBase(Context *context, + GLuint sampler, + GLenum pname, + GLsizei *length); + +template +bool ValidateSamplerParameterBase(Context *context, + GLuint sampler, + GLenum pname, + GLsizei bufSize, + ParamType *params); + +bool ValidateGetInternalFormativBase(Context *context, + GLenum target, + GLenum internalformat, + GLenum pname, + GLsizei bufSize, + GLsizei *numParams); + } // namespace gl -#endif // LIBANGLE_VALIDATION_ES_H_ +#endif // LIBANGLE_VALIDATION_ES_H_ diff --git a/src/3rdparty/angle/src/libANGLE/validationES2.cpp b/src/3rdparty/angle/src/libANGLE/validationES2.cpp index 2e5b955e99..5e505aa607 100644 --- a/src/3rdparty/angle/src/libANGLE/validationES2.cpp +++ b/src/3rdparty/angle/src/libANGLE/validationES2.cpp @@ -7,16 +7,24 @@ // validationES2.cpp: Validation functions for OpenGL ES 2.0 entry point parameters #include "libANGLE/validationES2.h" -#include "libANGLE/validationES.h" + +#include + +#include "common/mathutil.h" +#include "common/string_utils.h" +#include "common/utilities.h" #include "libANGLE/Context.h" -#include "libANGLE/Texture.h" +#include "libANGLE/ErrorStrings.h" #include "libANGLE/Framebuffer.h" +#include "libANGLE/FramebufferAttachment.h" #include "libANGLE/Renderbuffer.h" +#include "libANGLE/Shader.h" +#include "libANGLE/Texture.h" +#include "libANGLE/Uniform.h" +#include "libANGLE/VertexArray.h" #include "libANGLE/formatutils.h" -#include "libANGLE/FramebufferAttachment.h" - -#include "common/mathutil.h" -#include "common/utilities.h" +#include "libANGLE/validationES.h" +#include "libANGLE/validationES3.h" namespace gl { @@ -45,9 +53,9 @@ bool IsPartialBlit(gl::Context *context, return true; } - if (context->getState().isScissorTestEnabled()) + if (context->getGLState().isScissorTestEnabled()) { - const Rectangle &scissor = context->getState().getScissor(); + const Rectangle &scissor = context->getGLState().getScissor(); return scissor.x > 0 || scissor.y > 0 || scissor.width < writeSize.width || scissor.height < writeSize.height; } @@ -55,1702 +63,6289 @@ bool IsPartialBlit(gl::Context *context, return false; } -} // anonymous namespace +template +bool ValidatePathInstances(gl::Context *context, + GLsizei numPaths, + const void *paths, + GLuint pathBase) +{ + const auto *array = static_cast(paths); + + for (GLsizei i = 0; i < numPaths; ++i) + { + const GLuint pathName = array[i] + pathBase; + if (context->hasPath(pathName) && !context->hasPathData(pathName)) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), NoSuchPath); + return false; + } + } + return true; +} -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 ValidateInstancedPathParameters(gl::Context *context, + GLsizei numPaths, + GLenum pathNameType, + const void *paths, + GLuint pathBase, + GLenum transformType, + const GLfloat *transformValues) { - if (!ValidTexture2DDestinationTarget(context, target)) + if (!context->getExtensions().pathRendering) { - context->recordError(Error(GL_INVALID_ENUM)); + context->handleError(InvalidOperation() << "GL_CHROMIUM_path_rendering is not available."); return false; } - if (!ValidImageSizeParameters(context, target, level, width, height, 1, isSubImage)) + if (paths == nullptr) { - context->recordError(Error(GL_INVALID_VALUE)); + context->handleError(InvalidValue() << "No path name array."); return false; } - if (level < 0 || xoffset < 0 || - std::numeric_limits::max() - xoffset < width || - std::numeric_limits::max() - yoffset < height) + if (numPaths < 0) { - context->recordError(Error(GL_INVALID_VALUE)); + context->handleError(InvalidValue() << "Invalid (negative) numPaths."); return false; } - if (!isSubImage && !isCompressed && internalformat != format) + if (!angle::IsValueInRangeForNumericType(numPaths)) { - context->recordError(Error(GL_INVALID_OPERATION)); + ANGLE_VALIDATION_ERR(context, InvalidOperation(), IntegerOverflow); return false; } - const gl::Caps &caps = context->getCaps(); + std::uint32_t pathNameTypeSize = 0; + std::uint32_t componentCount = 0; - if (target == GL_TEXTURE_2D) + switch (pathNameType) { - if (static_cast(width) > (caps.max2DTextureSize >> level) || - static_cast(height) > (caps.max2DTextureSize >> level)) - { - context->recordError(Error(GL_INVALID_VALUE)); + case GL_UNSIGNED_BYTE: + pathNameTypeSize = sizeof(GLubyte); + if (!ValidatePathInstances(context, numPaths, paths, pathBase)) + return false; + break; + + case GL_BYTE: + pathNameTypeSize = sizeof(GLbyte); + if (!ValidatePathInstances(context, numPaths, paths, pathBase)) + return false; + break; + + case GL_UNSIGNED_SHORT: + pathNameTypeSize = sizeof(GLushort); + if (!ValidatePathInstances(context, numPaths, paths, pathBase)) + return false; + break; + + case GL_SHORT: + pathNameTypeSize = sizeof(GLshort); + if (!ValidatePathInstances(context, numPaths, paths, pathBase)) + return false; + break; + + case GL_UNSIGNED_INT: + pathNameTypeSize = sizeof(GLuint); + if (!ValidatePathInstances(context, numPaths, paths, pathBase)) + return false; + break; + + case GL_INT: + pathNameTypeSize = sizeof(GLint); + if (!ValidatePathInstances(context, numPaths, paths, pathBase)) + return false; + break; + + default: + context->handleError(InvalidEnum() << "Invalid path name type."); return false; - } } - else if (IsCubeMapTextureTarget(target)) + + switch (transformType) { - if (!isSubImage && width != height) - { - context->recordError(Error(GL_INVALID_VALUE)); + case GL_NONE: + componentCount = 0; + break; + case GL_TRANSLATE_X_CHROMIUM: + case GL_TRANSLATE_Y_CHROMIUM: + componentCount = 1; + break; + case GL_TRANSLATE_2D_CHROMIUM: + componentCount = 2; + break; + case GL_TRANSLATE_3D_CHROMIUM: + componentCount = 3; + break; + case GL_AFFINE_2D_CHROMIUM: + case GL_TRANSPOSE_AFFINE_2D_CHROMIUM: + componentCount = 6; + break; + case GL_AFFINE_3D_CHROMIUM: + case GL_TRANSPOSE_AFFINE_3D_CHROMIUM: + componentCount = 12; + break; + default: + context->handleError(InvalidEnum() << "Invalid transformation."); return false; - } + } + if (componentCount != 0 && transformValues == nullptr) + { + context->handleError(InvalidValue() << "No transform array given."); + return false; + } - if (static_cast(width) > (caps.maxCubeMapTextureSize >> level) || - static_cast(height) > (caps.maxCubeMapTextureSize >> level)) - { - context->recordError(Error(GL_INVALID_VALUE)); + angle::CheckedNumeric checkedSize(0); + checkedSize += (numPaths * pathNameTypeSize); + checkedSize += (numPaths * sizeof(GLfloat) * componentCount); + if (!checkedSize.IsValid()) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), IntegerOverflow); + return false; + } + + return true; +} + +bool IsValidCopyTextureSourceInternalFormatEnum(GLenum internalFormat) +{ + // Table 1.1 from the CHROMIUM_copy_texture spec + switch (GetUnsizedFormat(internalFormat)) + { + case GL_RED: + case GL_ALPHA: + case GL_LUMINANCE: + case GL_LUMINANCE_ALPHA: + case GL_RGB: + case GL_RGBA: + case GL_RGB8: + case GL_RGBA8: + case GL_BGRA_EXT: + case GL_BGRA8_EXT: + return true; + + default: return false; - } } - else +} + +bool IsValidCopySubTextureSourceInternalFormat(GLenum internalFormat) +{ + return IsValidCopyTextureSourceInternalFormatEnum(internalFormat); +} + +bool IsValidCopyTextureDestinationInternalFormatEnum(GLint internalFormat) +{ + // Table 1.0 from the CHROMIUM_copy_texture spec + switch (internalFormat) + { + case GL_RGB: + case GL_RGBA: + case GL_RGB8: + case GL_RGBA8: + case GL_BGRA_EXT: + case GL_BGRA8_EXT: + case GL_SRGB_EXT: + case GL_SRGB_ALPHA_EXT: + case GL_R8: + case GL_R8UI: + case GL_RG8: + case GL_RG8UI: + case GL_SRGB8: + case GL_RGB565: + case GL_RGB8UI: + case GL_RGB10_A2: + case GL_SRGB8_ALPHA8: + case GL_RGB5_A1: + case GL_RGBA4: + case GL_RGBA8UI: + case GL_RGB9_E5: + case GL_R16F: + case GL_R32F: + case GL_RG16F: + case GL_RG32F: + case GL_RGB16F: + case GL_RGB32F: + case GL_RGBA16F: + case GL_RGBA32F: + case GL_R11F_G11F_B10F: + case GL_LUMINANCE: + case GL_LUMINANCE_ALPHA: + case GL_ALPHA: + return true; + + default: + return false; + } +} + +bool IsValidCopySubTextureDestionationInternalFormat(GLenum internalFormat) +{ + return IsValidCopyTextureDestinationInternalFormatEnum(internalFormat); +} + +bool IsValidCopyTextureDestinationFormatType(Context *context, GLint internalFormat, GLenum type) +{ + if (!IsValidCopyTextureDestinationInternalFormatEnum(internalFormat)) { - context->recordError(Error(GL_INVALID_ENUM)); return false; } - gl::Texture *texture = context->getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target); - if (!texture) + if (!ValidES3FormatCombination(GetUnsizedFormat(internalFormat), type, internalFormat)) { - context->recordError(Error(GL_INVALID_OPERATION)); + context->handleError(InvalidOperation() + << "Invalid combination of type and internalFormat."); return false; } - if (isSubImage) + const InternalFormat &internalFormatInfo = GetInternalFormatInfo(internalFormat, type); + if (!internalFormatInfo.textureSupport(context->getClientVersion(), context->getExtensions())) { - if (format != GL_NONE) - { - if (gl::GetSizedInternalFormat(format, type) != texture->getInternalFormat(target, level)) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - } + 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 true; +} + +bool IsValidCopyTextureDestinationTargetEnum(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_RECTANGLE_ANGLE: + return context->getExtensions().textureRectangle; + + default: return false; - } + } +} + +bool IsValidCopyTextureDestinationTarget(Context *context, GLenum textureType, GLenum target) +{ + if (IsCubeMapTextureTarget(target)) + { + return textureType == GL_TEXTURE_CUBE_MAP; } else { - if (texture->getImmutableFormat()) - { - context->recordError(Error(GL_INVALID_OPERATION)); + return textureType == target; + } +} + +bool IsValidCopyTextureSourceTarget(Context *context, GLenum target) +{ + switch (target) + { + case GL_TEXTURE_2D: + return true; + case GL_TEXTURE_RECTANGLE_ANGLE: + return context->getExtensions().textureRectangle; + + // TODO(geofflang): accept GL_TEXTURE_EXTERNAL_OES if the texture_external extension is + // supported + + default: return false; - } } +} - // Verify zero border - if (border != 0) +bool IsValidCopyTextureSourceLevel(Context *context, GLenum target, GLint level) +{ + if (!ValidMipLevel(context, target, level)) { - context->recordError(Error(GL_INVALID_VALUE)); return false; } - if (isCompressed) + if (level > 0 && context->getClientVersion() < ES_3_0) { - GLenum actualInternalFormat = - isSubImage ? texture->getInternalFormat(target, level) : internalformat; - switch (actualInternalFormat) + return false; + } + + return true; +} + +bool IsValidCopyTextureDestinationLevel(Context *context, + GLenum target, + GLint level, + GLsizei width, + GLsizei height) +{ + if (!ValidMipLevel(context, target, level)) + { + return false; + } + + const Caps &caps = context->getCaps(); + if (target == GL_TEXTURE_2D) + { + if (static_cast(width) > (caps.max2DTextureSize >> level) || + static_cast(height) > (caps.max2DTextureSize >> level)) { - 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; - case GL_ETC1_RGB8_OES: - if (!context->getExtensions().compressedETC1RGB8Texture) - { - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } - break; - case GL_ETC1_RGB8_LOSSY_DECODE_ANGLE: - if (!context->getExtensions().lossyETCDecode) - { - context->recordError( - Error(GL_INVALID_ENUM, "ANGLE_lossy_etc_decode extension is not supported")); - return false; - } - break; - default: - context->recordError(Error( - GL_INVALID_ENUM, "internalformat is not a supported compressed internal format")); - return false; + return false; } - if (!ValidCompressedImageSize(context, actualInternalFormat, width, height)) + } + else if (target == GL_TEXTURE_RECTANGLE_ANGLE) + { + ASSERT(level == 0); + if (static_cast(width) > caps.maxRectangleTextureSize || + static_cast(height) > caps.maxRectangleTextureSize) { - context->recordError(Error(GL_INVALID_OPERATION)); return false; } } - else + else if (IsCubeMapTextureTarget(target)) { - // validate by itself (used as secondary key below) - switch (type) + if (static_cast(width) > (caps.maxCubeMapTextureSize >> level) || + static_cast(height) > (caps.maxCubeMapTextureSize >> level)) { - 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 true; +} + +bool IsValidStencilFunc(GLenum func) +{ + switch (func) + { + case GL_NEVER: + case GL_ALWAYS: + case GL_LESS: + case GL_LEQUAL: + case GL_EQUAL: + case GL_GEQUAL: + case GL_GREATER: + case GL_NOTEQUAL: + return true; + + default: 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)); +bool IsValidStencilFace(GLenum face) +{ + switch (face) + { + case GL_FRONT: + case GL_BACK: + case GL_FRONT_AND_BACK: + return true; + + default: + return false; + } +} + +bool IsValidStencilOp(GLenum op) +{ + switch (op) + { + case GL_ZERO: + case GL_KEEP: + case GL_REPLACE: + case GL_INCR: + case GL_DECR: + case GL_INVERT: + case GL_INCR_WRAP: + case GL_DECR_WRAP: + return true; + + default: + return false; + } +} + +bool ValidateES2CopyTexImageParameters(ValidationContext *context, + GLenum target, + GLint level, + GLenum internalformat, + bool isSubImage, + GLint xoffset, + GLint yoffset, + GLint x, + GLint y, + GLsizei width, + GLsizei height, + GLint border) +{ + if (!ValidTexture2DDestinationTarget(context, target)) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidTextureTarget); + return false; + } + + if (!ValidImageSizeParameters(context, target, level, width, height, 1, isSubImage)) + { + context->handleError(InvalidValue() << "Invalid texture dimensions."); + return false; + } + + Format textureFormat = Format::Invalid(); + if (!ValidateCopyTexImageParametersBase(context, target, level, internalformat, isSubImage, + xoffset, yoffset, 0, x, y, width, height, border, + &textureFormat)) + { + return false; + } + + const gl::Framebuffer *framebuffer = context->getGLState().getReadFramebuffer(); + GLenum colorbufferFormat = + framebuffer->getReadColorbuffer()->getFormat().info->sizedInternalFormat; + const auto &formatInfo = *textureFormat.info; + + // [OpenGL ES 2.0.24] table 3.9 + if (isSubImage) + { + switch (formatInfo.format) + { + case GL_ALPHA: + if (colorbufferFormat != GL_ALPHA8_EXT && colorbufferFormat != GL_RGBA4 && + colorbufferFormat != GL_RGB5_A1 && colorbufferFormat != GL_RGBA8_OES && + colorbufferFormat != GL_BGRA8_EXT && colorbufferFormat != GL_BGR5_A1_ANGLEX) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), InvalidFormat); + 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 && colorbufferFormat != GL_BGRA8_EXT && + colorbufferFormat != GL_BGR5_A1_ANGLEX) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), InvalidFormat); + 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 && colorbufferFormat != GL_BGRA8_EXT && + colorbufferFormat != GL_BGR5_A1_ANGLEX) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), InvalidFormat); + 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 && colorbufferFormat != GL_BGRA8_EXT && + colorbufferFormat != GL_BGR5_A1_ANGLEX) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), InvalidFormat); + 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 && colorbufferFormat != GL_BGRA8_EXT && + colorbufferFormat != GL_BGR5_A1_ANGLEX) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), InvalidFormat); + 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 && + colorbufferFormat != GL_BGRA8_EXT && colorbufferFormat != GL_BGR5_A1_ANGLEX) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), InvalidFormat); + 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: + case GL_ETC1_RGB8_OES: + case GL_ETC1_RGB8_LOSSY_DECODE_ANGLE: + case GL_COMPRESSED_RGB8_LOSSY_DECODE_ETC2_ANGLE: + case GL_COMPRESSED_SRGB8_LOSSY_DECODE_ETC2_ANGLE: + case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE: + case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE: + ANGLE_VALIDATION_ERR(context, InvalidOperation(), InvalidFormat); + return false; + case GL_DEPTH_COMPONENT: + case GL_DEPTH_STENCIL_OES: + ANGLE_VALIDATION_ERR(context, InvalidOperation(), InvalidFormat); + return false; + default: + ANGLE_VALIDATION_ERR(context, InvalidOperation(), InvalidFormat); + return false; + } + + if (formatInfo.type == GL_FLOAT && !context->getExtensions().textureFloat) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), InvalidFormat); + 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) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), InvalidFormat); + 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) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), InvalidFormat); + 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) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), InvalidFormat); + 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) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), InvalidFormat); + 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) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), InvalidFormat); + 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) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), InvalidFormat); + return false; + } + break; + case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: + if (context->getExtensions().textureCompressionDXT1) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), InvalidFormat); + return false; + } + else + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), EnumNotSupported); + return false; + } + break; + case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: + if (context->getExtensions().textureCompressionDXT3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), InvalidFormat); + return false; + } + else + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), EnumNotSupported); + return false; + } + break; + case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: + if (context->getExtensions().textureCompressionDXT5) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), InvalidFormat); + return false; + } + else + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), EnumNotSupported); + return false; + } + break; + case GL_ETC1_RGB8_OES: + if (context->getExtensions().compressedETC1RGB8Texture) + { + context->handleError(InvalidOperation()); + return false; + } + else + { + context->handleError(InvalidEnum()); + return false; + } + break; + case GL_ETC1_RGB8_LOSSY_DECODE_ANGLE: + case GL_COMPRESSED_RGB8_LOSSY_DECODE_ETC2_ANGLE: + case GL_COMPRESSED_SRGB8_LOSSY_DECODE_ETC2_ANGLE: + case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE: + case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE: + if (context->getExtensions().lossyETCDecode) + { + context->handleError(InvalidOperation() + << "ETC lossy decode formats can't be copied to."); + return false; + } + else + { + context->handleError(InvalidEnum() + << "ANGLE_lossy_etc_decode extension is not supported."); + 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->handleError(InvalidOperation()); + return false; + } + else + { + context->handleError(InvalidEnum()); + return false; + } + default: + context->handleError(InvalidEnum()); + 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 ValidCap(const Context *context, GLenum cap, bool queryOnly) +{ + switch (cap) + { + // EXT_multisample_compatibility + case GL_MULTISAMPLE_EXT: + case GL_SAMPLE_ALPHA_TO_ONE_EXT: + return context->getExtensions().multisampleCompatibility; + + 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->getClientMajorVersion() >= 3); + + case GL_DEBUG_OUTPUT_SYNCHRONOUS: + case GL_DEBUG_OUTPUT: + return context->getExtensions().debug; + + case GL_BIND_GENERATES_RESOURCE_CHROMIUM: + return queryOnly && context->getExtensions().bindGeneratesResource; + + case GL_CLIENT_ARRAYS_ANGLE: + return queryOnly && context->getExtensions().clientArrays; + + case GL_FRAMEBUFFER_SRGB_EXT: + return context->getExtensions().sRGBWriteControl; + + case GL_SAMPLE_MASK: + return context->getClientVersion() >= Version(3, 1); + + case GL_ROBUST_RESOURCE_INITIALIZATION_ANGLE: + return queryOnly && context->getExtensions().robustResourceInitialization; + + default: + return false; + } +} + +// Return true if a character belongs to the ASCII subset as defined in GLSL ES 1.0 spec section +// 3.1. +bool IsValidESSLCharacter(unsigned char c) +{ + // Printing characters are valid except " $ ` @ \ ' DEL. + if (c >= 32 && c <= 126 && c != '"' && c != '$' && c != '`' && c != '@' && c != '\\' && + c != '\'') + { + return true; + } + + // Horizontal tab, line feed, vertical tab, form feed, carriage return are also valid. + if (c >= 9 && c <= 13) + { + return true; + } + + return false; +} + +bool IsValidESSLString(const char *str, size_t len) +{ + for (size_t i = 0; i < len; i++) + { + if (!IsValidESSLCharacter(str[i])) + { + return false; + } + } + + return true; +} + +bool IsValidESSLShaderSourceString(const char *str, size_t len, bool lineContinuationAllowed) +{ + enum class ParseState + { + // Have not seen an ASCII non-whitespace character yet on + // this line. Possible that we might see a preprocessor + // directive. + BEGINING_OF_LINE, + + // Have seen at least one ASCII non-whitespace character + // on this line. + MIDDLE_OF_LINE, + + // Handling a preprocessor directive. Passes through all + // characters up to the end of the line. Disables comment + // processing. + IN_PREPROCESSOR_DIRECTIVE, + + // Handling a single-line comment. The comment text is + // replaced with a single space. + IN_SINGLE_LINE_COMMENT, + + // Handling a multi-line comment. Newlines are passed + // through to preserve line numbers. + IN_MULTI_LINE_COMMENT + }; + + ParseState state = ParseState::BEGINING_OF_LINE; + size_t pos = 0; + + while (pos < len) + { + char c = str[pos]; + char next = pos + 1 < len ? str[pos + 1] : 0; + + // Check for newlines + if (c == '\n' || c == '\r') + { + if (state != ParseState::IN_MULTI_LINE_COMMENT) + { + state = ParseState::BEGINING_OF_LINE; + } + + pos++; + continue; + } + + switch (state) + { + case ParseState::BEGINING_OF_LINE: + if (c == ' ') + { + // Maintain the BEGINING_OF_LINE state until a non-space is seen + pos++; + } + else if (c == '#') + { + state = ParseState::IN_PREPROCESSOR_DIRECTIVE; + pos++; + } + else + { + // Don't advance, re-process this character with the MIDDLE_OF_LINE state + state = ParseState::MIDDLE_OF_LINE; + } + break; + + case ParseState::MIDDLE_OF_LINE: + if (c == '/' && next == '/') + { + state = ParseState::IN_SINGLE_LINE_COMMENT; + pos++; + } + else if (c == '/' && next == '*') + { + state = ParseState::IN_MULTI_LINE_COMMENT; + pos++; + } + else if (lineContinuationAllowed && c == '\\' && (next == '\n' || next == '\r')) + { + // Skip line continuation characters + } + else if (!IsValidESSLCharacter(c)) + { + return false; + } + pos++; + break; + + case ParseState::IN_PREPROCESSOR_DIRECTIVE: + // Line-continuation characters may not be permitted. + // Otherwise, just pass it through. Do not parse comments in this state. + if (!lineContinuationAllowed && c == '\\') + { + return false; + } + pos++; + break; + + case ParseState::IN_SINGLE_LINE_COMMENT: + // Line-continuation characters are processed before comment processing. + // Advance string if a new line character is immediately behind + // line-continuation character. + if (c == '\\' && (next == '\n' || next == '\r')) + { + pos++; + } + pos++; + break; + + case ParseState::IN_MULTI_LINE_COMMENT: + if (c == '*' && next == '/') + { + state = ParseState::MIDDLE_OF_LINE; + pos++; + } + pos++; + break; + } + } + + return true; +} + +bool ValidateWebGLNamePrefix(ValidationContext *context, const GLchar *name) +{ + ASSERT(context->isWebGL()); + + // WebGL 1.0 [Section 6.16] GLSL Constructs + // Identifiers starting with "webgl_" and "_webgl_" are reserved for use by WebGL. + if (strncmp(name, "webgl_", 6) == 0 || strncmp(name, "_webgl_", 7) == 0) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), WebglBindAttribLocationReservedPrefix); + return false; + } + + return true; +} + +bool ValidateWebGLNameLength(ValidationContext *context, size_t length) +{ + ASSERT(context->isWebGL()); + + if (context->isWebGL1() && length > 256) + { + // WebGL 1.0 [Section 6.21] Maxmimum Uniform and Attribute Location Lengths + // WebGL imposes a limit of 256 characters on the lengths of uniform and attribute + // locations. + ANGLE_VALIDATION_ERR(context, InvalidValue(), WebglNameLengthLimitExceeded); + + return false; + } + else if (length > 1024) + { + // WebGL 2.0 [Section 4.3.2] WebGL 2.0 imposes a limit of 1024 characters on the lengths of + // uniform and attribute locations. + ANGLE_VALIDATION_ERR(context, InvalidValue(), Webgl2NameLengthLimitExceeded); + return false; + } + + return true; +} + +} // anonymous namespace + +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, + GLsizei imageSize, + const void *pixels) +{ + if (!ValidTexture2DDestinationTarget(context, target)) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidTextureTarget); + return false; + } + + if (!ValidImageSizeParameters(context, target, level, width, height, 1, isSubImage)) + { + context->handleError(InvalidValue()); + return false; + } + + if (!ValidMipLevel(context, target, level)) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), InvalidMipLevel); + return false; + } + + if (xoffset < 0 || std::numeric_limits::max() - xoffset < width || + std::numeric_limits::max() - yoffset < height) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), ResourceMaxTextureSize); + return false; + } + + // From GL_CHROMIUM_color_buffer_float_rgb[a]: + // GL_RGB[A] / GL_RGB[A]32F becomes an allowable format / internalformat parameter pair for + // TexImage2D. The restriction in section 3.7.1 of the OpenGL ES 2.0 spec that the + // internalformat parameter and format parameter of TexImage2D must match is lifted for this + // case. + bool nonEqualFormatsAllowed = + (internalformat == GL_RGB32F && context->getExtensions().colorBufferFloatRGB) || + (internalformat == GL_RGBA32F && context->getExtensions().colorBufferFloatRGBA); + + if (!isSubImage && !isCompressed && internalformat != format && !nonEqualFormatsAllowed) + { + context->handleError(InvalidOperation()); + 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->handleError(InvalidValue()); + return false; + } + } + else if (target == GL_TEXTURE_RECTANGLE_ANGLE) + { + ASSERT(level == 0); + if (static_cast(width) > caps.maxRectangleTextureSize || + static_cast(height) > caps.maxRectangleTextureSize) + { + context->handleError(InvalidValue()); + return false; + } + if (isCompressed) + { + context->handleError(InvalidEnum() + << "Rectangle texture cannot have a compressed format."); + return false; + } + } + else if (IsCubeMapTextureTarget(target)) + { + if (!isSubImage && width != height) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), CubemapFacesEqualDimensions); + return false; + } + + if (static_cast(width) > (caps.maxCubeMapTextureSize >> level) || + static_cast(height) > (caps.maxCubeMapTextureSize >> level)) + { + context->handleError(InvalidValue()); + return false; + } + } + else + { + context->handleError(InvalidEnum()); + return false; + } + + gl::Texture *texture = + context->getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target); + if (!texture) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), BufferNotBound); + return false; + } + + if (isSubImage) + { + const InternalFormat &textureInternalFormat = *texture->getFormat(target, level).info; + if (textureInternalFormat.internalFormat == GL_NONE) + { + context->handleError(InvalidOperation() << "Texture level does not exist."); + return false; + } + + if (format != GL_NONE) + { + if (GetInternalFormatInfo(format, type).sizedInternalFormat != + textureInternalFormat.sizedInternalFormat) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), TypeMismatch); + return false; + } + } + + if (static_cast(xoffset + width) > texture->getWidth(target, level) || + static_cast(yoffset + height) > texture->getHeight(target, level)) + { + context->handleError(InvalidValue()); + return false; + } + + if (width > 0 && height > 0 && pixels == nullptr && + context->getGLState().getTargetBuffer(gl::BufferBinding::PixelUnpack) == nullptr) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), PixelDataNull); + return false; + } + } + else + { + if (texture->getImmutableFormat()) + { + context->handleError(InvalidOperation()); + return false; + } + } + + // Verify zero border + if (border != 0) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), InvalidBorder); + return false; + } + + if (isCompressed) + { + GLenum actualInternalFormat = + isSubImage ? texture->getFormat(target, level).info->sizedInternalFormat + : internalformat; + switch (actualInternalFormat) + { + case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: + if (!context->getExtensions().textureCompressionDXT1) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidInternalFormat); + return false; + } + break; + case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: + if (!context->getExtensions().textureCompressionDXT3) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidInternalFormat); + return false; + } + break; + case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: + if (!context->getExtensions().textureCompressionDXT5) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidInternalFormat); + return false; + } + break; + case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT: + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT: + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT: + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT: + if (!context->getExtensions().textureCompressionS3TCsRGB) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidInternalFormat); + return false; + } + break; + case GL_ETC1_RGB8_OES: + if (!context->getExtensions().compressedETC1RGB8Texture) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidInternalFormat); + return false; + } + if (isSubImage) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), InvalidInternalFormat); + return false; + } + break; + case GL_ETC1_RGB8_LOSSY_DECODE_ANGLE: + case GL_COMPRESSED_RGB8_LOSSY_DECODE_ETC2_ANGLE: + case GL_COMPRESSED_SRGB8_LOSSY_DECODE_ETC2_ANGLE: + case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE: + case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE: + if (!context->getExtensions().lossyETCDecode) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidInternalFormat); + return false; + } + break; + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidInternalFormat); + return false; + } + + if (isSubImage) + { + if (!ValidCompressedSubImageSize(context, actualInternalFormat, xoffset, yoffset, width, + height, texture->getWidth(target, level), + texture->getHeight(target, level))) + { + context->handleError(InvalidOperation() << "Invalid compressed format dimension."); + return false; + } + + if (format != actualInternalFormat) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), InvalidFormat); + return false; + } + } + else + { + if (!ValidCompressedImageSize(context, actualInternalFormat, level, width, height)) + { + context->handleError(InvalidOperation() << "Invalid compressed format dimension."); + 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: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidType); + 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: + ANGLE_VALIDATION_ERR(context, InvalidOperation(), MismatchedTypeAndFormat); + return false; + } + break; + case GL_RED: + case GL_RG: + if (!context->getExtensions().textureRG) + { + context->handleError(InvalidEnum()); + return false; + } + switch (type) + { + case GL_UNSIGNED_BYTE: + break; + case GL_FLOAT: + case GL_HALF_FLOAT_OES: + if (!context->getExtensions().textureFloat) + { + context->handleError(InvalidEnum()); + return false; + } + break; + default: + ANGLE_VALIDATION_ERR(context, InvalidOperation(), MismatchedTypeAndFormat); + 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: + ANGLE_VALIDATION_ERR(context, InvalidOperation(), MismatchedTypeAndFormat); + 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: + ANGLE_VALIDATION_ERR(context, InvalidOperation(), MismatchedTypeAndFormat); + return false; + } + break; + case GL_BGRA_EXT: + if (!context->getExtensions().textureFormatBGRA8888) + { + context->handleError(InvalidEnum()); + return false; + } + switch (type) + { + case GL_UNSIGNED_BYTE: + break; + default: + ANGLE_VALIDATION_ERR(context, InvalidOperation(), MismatchedTypeAndFormat); + return false; + } + break; + case GL_SRGB_EXT: + case GL_SRGB_ALPHA_EXT: + if (!context->getExtensions().sRGB) + { + context->handleError(InvalidEnum()); + return false; + } + switch (type) + { + case GL_UNSIGNED_BYTE: + break; + default: + ANGLE_VALIDATION_ERR(context, InvalidOperation(), MismatchedTypeAndFormat); + 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: + ANGLE_VALIDATION_ERR(context, InvalidOperation(), MismatchedTypeAndFormat); + return false; + } + break; + case GL_DEPTH_STENCIL_OES: + switch (type) + { + case GL_UNSIGNED_INT_24_8_OES: + break; + default: + ANGLE_VALIDATION_ERR(context, InvalidOperation(), MismatchedTypeAndFormat); + return false; + } + break; + default: + context->handleError(InvalidEnum()); + return false; + } + + switch (format) + { + case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: + if (context->getExtensions().textureCompressionDXT1) + { + context->handleError(InvalidOperation()); + return false; + } + else + { + context->handleError(InvalidEnum()); + return false; + } + break; + case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: + if (context->getExtensions().textureCompressionDXT3) + { + context->handleError(InvalidOperation()); + return false; + } + else + { + context->handleError(InvalidEnum()); + return false; + } + break; + case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: + if (context->getExtensions().textureCompressionDXT5) + { + context->handleError(InvalidOperation()); + return false; + } + else + { + context->handleError(InvalidEnum()); + return false; + } + break; + case GL_ETC1_RGB8_OES: + if (context->getExtensions().compressedETC1RGB8Texture) + { + context->handleError(InvalidOperation()); + return false; + } + else + { + context->handleError(InvalidEnum()); + return false; + } + break; + case GL_ETC1_RGB8_LOSSY_DECODE_ANGLE: + case GL_COMPRESSED_RGB8_LOSSY_DECODE_ETC2_ANGLE: + case GL_COMPRESSED_SRGB8_LOSSY_DECODE_ETC2_ANGLE: + case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE: + case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE: + if (context->getExtensions().lossyETCDecode) + { + context->handleError(InvalidOperation() + << "ETC lossy decode formats can't work with this type."); + return false; + } + else + { + context->handleError(InvalidEnum() + << "ANGLE_lossy_etc_decode extension is not supported."); + return false; + } + break; + case GL_DEPTH_COMPONENT: + case GL_DEPTH_STENCIL_OES: + if (!context->getExtensions().depthTextures) + { + context->handleError(InvalidValue()); + return false; + } + if (target != GL_TEXTURE_2D) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), MismatchedTargetAndFormat); + return false; + } + // OES_depth_texture supports loading depth data and multiple levels, + // but ANGLE_depth_texture does not + if (pixels != nullptr) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), PixelDataNotNull); + return false; + } + if (level != 0) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), LevelNotZero); + return false; + } + break; + default: + break; + } + + if (!isSubImage) + { + switch (internalformat) + { + case GL_RGBA32F: + if (!context->getExtensions().colorBufferFloatRGBA) + { + context->handleError(InvalidValue() + << "Sized GL_RGBA32F internal format requires " + "GL_CHROMIUM_color_buffer_float_rgba"); + return false; + } + if (type != GL_FLOAT) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), MismatchedTypeAndFormat); + return false; + } + if (format != GL_RGBA) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), MismatchedTypeAndFormat); + return false; + } + break; + + case GL_RGB32F: + if (!context->getExtensions().colorBufferFloatRGB) + { + context->handleError(InvalidValue() + << "Sized GL_RGB32F internal format requires " + "GL_CHROMIUM_color_buffer_float_rgb"); + return false; + } + if (type != GL_FLOAT) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), MismatchedTypeAndFormat); + return false; + } + if (format != GL_RGB) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), MismatchedTypeAndFormat); + return false; + } + break; + + default: + break; + } + } + + if (type == GL_FLOAT) + { + if (!context->getExtensions().textureFloat) + { + context->handleError(InvalidEnum()); + return false; + } + } + else if (type == GL_HALF_FLOAT_OES) + { + if (!context->getExtensions().textureHalfFloat) + { + context->handleError(InvalidEnum()); + return false; + } + } + } + + GLenum sizeCheckFormat = isSubImage ? format : internalformat; + if (!ValidImageDataSize(context, target, width, height, 1, sizeCheckFormat, type, pixels, + imageSize)) + { + return false; + } + + return true; +} + +bool ValidateES2TexStorageParameters(Context *context, + GLenum target, + GLsizei levels, + GLenum internalformat, + GLsizei width, + GLsizei height) +{ + if (target != GL_TEXTURE_2D && target != GL_TEXTURE_CUBE_MAP && + target != GL_TEXTURE_RECTANGLE_ANGLE) + { + context->handleError(InvalidEnum()); + return false; + } + + if (width < 1 || height < 1 || levels < 1) + { + context->handleError(InvalidValue()); + return false; + } + + if (target == GL_TEXTURE_CUBE_MAP && width != height) + { + context->handleError(InvalidValue()); + return false; + } + + if (levels != 1 && levels != gl::log2(std::max(width, height)) + 1) + { + context->handleError(InvalidOperation()); + return false; + } + + const gl::InternalFormat &formatInfo = gl::GetSizedInternalFormatInfo(internalformat); + if (formatInfo.format == GL_NONE || formatInfo.type == GL_NONE) + { + context->handleError(InvalidEnum()); + 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->handleError(InvalidValue()); + return false; + } + break; + case GL_TEXTURE_RECTANGLE_ANGLE: + if (static_cast(width) > caps.maxRectangleTextureSize || + static_cast(height) > caps.maxRectangleTextureSize || levels != 1) + { + context->handleError(InvalidValue()); + return false; + } + if (formatInfo.compressed) + { + context->handleError(InvalidEnum() + << "Rectangle texture cannot have a compressed format."); + return false; + } + break; + case GL_TEXTURE_CUBE_MAP: + if (static_cast(width) > caps.maxCubeMapTextureSize || + static_cast(height) > caps.maxCubeMapTextureSize) + { + context->handleError(InvalidValue()); + return false; + } + break; + default: + context->handleError(InvalidEnum()); + return false; + } + + if (levels != 1 && !context->getExtensions().textureNPOT) + { + if (!gl::isPow2(width) || !gl::isPow2(height)) + { + context->handleError(InvalidOperation()); + return false; + } + } + + switch (internalformat) + { + case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: + if (!context->getExtensions().textureCompressionDXT1) + { + context->handleError(InvalidEnum()); + return false; + } + break; + case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: + if (!context->getExtensions().textureCompressionDXT3) + { + context->handleError(InvalidEnum()); + return false; + } + break; + case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: + if (!context->getExtensions().textureCompressionDXT5) + { + context->handleError(InvalidEnum()); + return false; + } + break; + case GL_ETC1_RGB8_OES: + if (!context->getExtensions().compressedETC1RGB8Texture) + { + context->handleError(InvalidEnum()); + return false; + } + break; + case GL_ETC1_RGB8_LOSSY_DECODE_ANGLE: + case GL_COMPRESSED_RGB8_LOSSY_DECODE_ETC2_ANGLE: + case GL_COMPRESSED_SRGB8_LOSSY_DECODE_ETC2_ANGLE: + case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE: + case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE: + if (!context->getExtensions().lossyETCDecode) + { + context->handleError(InvalidEnum() + << "ANGLE_lossy_etc_decode extension is not supported."); + 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->handleError(InvalidEnum()); + 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->handleError(InvalidEnum()); + return false; + } + break; + case GL_R8_EXT: + case GL_RG8_EXT: + if (!context->getExtensions().textureRG) + { + context->handleError(InvalidEnum()); + return false; + } + break; + case GL_R16F_EXT: + case GL_RG16F_EXT: + if (!context->getExtensions().textureRG || !context->getExtensions().textureHalfFloat) + { + context->handleError(InvalidEnum()); + return false; + } + break; + case GL_R32F_EXT: + case GL_RG32F_EXT: + if (!context->getExtensions().textureRG || !context->getExtensions().textureFloat) + { + context->handleError(InvalidEnum()); + return false; + } + break; + case GL_DEPTH_COMPONENT16: + case GL_DEPTH_COMPONENT32_OES: + case GL_DEPTH24_STENCIL8_OES: + if (!context->getExtensions().depthTextures) + { + context->handleError(InvalidEnum()); + return false; + } + if (target != GL_TEXTURE_2D) + { + context->handleError(InvalidOperation()); + return false; + } + // ANGLE_depth_texture only supports 1-level textures + if (levels != 1) + { + context->handleError(InvalidOperation()); + return false; + } + break; + default: + break; + } + + gl::Texture *texture = context->getTargetTexture(target); + if (!texture || texture->id() == 0) + { + context->handleError(InvalidOperation()); + return false; + } + + if (texture->getImmutableFormat()) + { + context->handleError(InvalidOperation()); + return false; + } + + return true; +} + +bool ValidateDiscardFramebufferEXT(Context *context, + GLenum target, + GLsizei numAttachments, + const GLenum *attachments) +{ + if (!context->getExtensions().discardFramebuffer) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ExtensionNotEnabled); + return false; + } + + bool defaultFramebuffer = false; + + switch (target) + { + case GL_FRAMEBUFFER: + defaultFramebuffer = + (context->getGLState().getTargetFramebuffer(GL_FRAMEBUFFER)->id() == 0); + break; + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidFramebufferTarget); + return false; + } + + return ValidateDiscardFramebufferBase(context, target, numAttachments, attachments, + defaultFramebuffer); +} + +bool ValidateBindVertexArrayOES(Context *context, GLuint array) +{ + if (!context->getExtensions().vertexArrayObject) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ExtensionNotEnabled); + return false; + } + + return ValidateBindVertexArrayBase(context, array); +} + +bool ValidateDeleteVertexArraysOES(Context *context, GLsizei n, const GLuint *arrays) +{ + if (!context->getExtensions().vertexArrayObject) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ExtensionNotEnabled); + return false; + } + + return ValidateGenOrDelete(context, n); +} + +bool ValidateGenVertexArraysOES(Context *context, GLsizei n, GLuint *arrays) +{ + if (!context->getExtensions().vertexArrayObject) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ExtensionNotEnabled); + return false; + } + + return ValidateGenOrDelete(context, n); +} + +bool ValidateIsVertexArrayOES(Context *context, GLuint array) +{ + if (!context->getExtensions().vertexArrayObject) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ExtensionNotEnabled); + return false; + } + + return true; +} + +bool ValidateProgramBinaryOES(Context *context, + GLuint program, + GLenum binaryFormat, + const void *binary, + GLint length) +{ + if (!context->getExtensions().getProgramBinary) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ExtensionNotEnabled); + return false; + } + + return ValidateProgramBinaryBase(context, program, binaryFormat, binary, length); +} + +bool ValidateGetProgramBinaryOES(Context *context, + GLuint program, + GLsizei bufSize, + GLsizei *length, + GLenum *binaryFormat, + void *binary) +{ + if (!context->getExtensions().getProgramBinary) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ExtensionNotEnabled); + return false; + } + + return ValidateGetProgramBinaryBase(context, program, bufSize, length, binaryFormat, binary); +} + +static bool ValidDebugSource(GLenum source, bool mustBeThirdPartyOrApplication) +{ + switch (source) + { + case GL_DEBUG_SOURCE_API: + case GL_DEBUG_SOURCE_SHADER_COMPILER: + case GL_DEBUG_SOURCE_WINDOW_SYSTEM: + case GL_DEBUG_SOURCE_OTHER: + // Only THIRD_PARTY and APPLICATION sources are allowed to be manually inserted + return !mustBeThirdPartyOrApplication; + + case GL_DEBUG_SOURCE_THIRD_PARTY: + case GL_DEBUG_SOURCE_APPLICATION: + return true; + + default: + return false; + } +} + +static bool ValidDebugType(GLenum type) +{ + switch (type) + { + case GL_DEBUG_TYPE_ERROR: + case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR: + case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR: + case GL_DEBUG_TYPE_PERFORMANCE: + case GL_DEBUG_TYPE_PORTABILITY: + case GL_DEBUG_TYPE_OTHER: + case GL_DEBUG_TYPE_MARKER: + case GL_DEBUG_TYPE_PUSH_GROUP: + case GL_DEBUG_TYPE_POP_GROUP: + return true; + + default: + return false; + } +} + +static bool ValidDebugSeverity(GLenum severity) +{ + switch (severity) + { + case GL_DEBUG_SEVERITY_HIGH: + case GL_DEBUG_SEVERITY_MEDIUM: + case GL_DEBUG_SEVERITY_LOW: + case GL_DEBUG_SEVERITY_NOTIFICATION: + return true; + + default: + return false; + } +} + +bool ValidateDebugMessageControlKHR(Context *context, + GLenum source, + GLenum type, + GLenum severity, + GLsizei count, + const GLuint *ids, + GLboolean enabled) +{ + if (!context->getExtensions().debug) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ExtensionNotEnabled); + return false; + } + + if (!ValidDebugSource(source, false) && source != GL_DONT_CARE) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidDebugSource); + return false; + } + + if (!ValidDebugType(type) && type != GL_DONT_CARE) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidDebugType); + return false; + } + + if (!ValidDebugSeverity(severity) && severity != GL_DONT_CARE) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidDebugSeverity); + return false; + } + + if (count > 0) + { + if (source == GL_DONT_CARE || type == GL_DONT_CARE) + { + context->handleError( + InvalidOperation() + << "If count is greater than zero, source and severity cannot be GL_DONT_CARE."); + return false; + } + + if (severity != GL_DONT_CARE) + { + context->handleError( + InvalidOperation() + << "If count is greater than zero, severity must be GL_DONT_CARE."); + return false; + } + } + + return true; +} + +bool ValidateDebugMessageInsertKHR(Context *context, + GLenum source, + GLenum type, + GLuint id, + GLenum severity, + GLsizei length, + const GLchar *buf) +{ + if (!context->getExtensions().debug) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ExtensionNotEnabled); + return false; + } + + if (!context->getGLState().getDebug().isOutputEnabled()) + { + // If the DEBUG_OUTPUT state is disabled calls to DebugMessageInsert are discarded and do + // not generate an error. + return false; + } + + if (!ValidDebugSeverity(severity)) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidDebugSource); + return false; + } + + if (!ValidDebugType(type)) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidDebugType); + return false; + } + + if (!ValidDebugSource(source, true)) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidDebugSource); + return false; + } + + size_t messageLength = (length < 0) ? strlen(buf) : length; + if (messageLength > context->getExtensions().maxDebugMessageLength) + { + context->handleError(InvalidValue() + << "Message length is larger than GL_MAX_DEBUG_MESSAGE_LENGTH."); + return false; + } + + return true; +} + +bool ValidateDebugMessageCallbackKHR(Context *context, + GLDEBUGPROCKHR callback, + const void *userParam) +{ + if (!context->getExtensions().debug) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ExtensionNotEnabled); + return false; + } + + return true; +} + +bool ValidateGetDebugMessageLogKHR(Context *context, + GLuint count, + GLsizei bufSize, + GLenum *sources, + GLenum *types, + GLuint *ids, + GLenum *severities, + GLsizei *lengths, + GLchar *messageLog) +{ + if (!context->getExtensions().debug) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ExtensionNotEnabled); + return false; + } + + if (bufSize < 0 && messageLog != nullptr) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), NegativeBufferSize); + return false; + } + + return true; +} + +bool ValidatePushDebugGroupKHR(Context *context, + GLenum source, + GLuint id, + GLsizei length, + const GLchar *message) +{ + if (!context->getExtensions().debug) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ExtensionNotEnabled); + return false; + } + + if (!ValidDebugSource(source, true)) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidDebugSource); + return false; + } + + size_t messageLength = (length < 0) ? strlen(message) : length; + if (messageLength > context->getExtensions().maxDebugMessageLength) + { + context->handleError(InvalidValue() + << "Message length is larger than GL_MAX_DEBUG_MESSAGE_LENGTH."); + return false; + } + + size_t currentStackSize = context->getGLState().getDebug().getGroupStackDepth(); + if (currentStackSize >= context->getExtensions().maxDebugGroupStackDepth) + { + context + ->handleError(StackOverflow() + << "Cannot push more than GL_MAX_DEBUG_GROUP_STACK_DEPTH debug groups."); + return false; + } + + return true; +} + +bool ValidatePopDebugGroupKHR(Context *context) +{ + if (!context->getExtensions().debug) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ExtensionNotEnabled); + return false; + } + + size_t currentStackSize = context->getGLState().getDebug().getGroupStackDepth(); + if (currentStackSize <= 1) + { + context->handleError(StackUnderflow() << "Cannot pop the default debug group."); + return false; + } + + return true; +} + +static bool ValidateObjectIdentifierAndName(Context *context, GLenum identifier, GLuint name) +{ + switch (identifier) + { + case GL_BUFFER: + if (context->getBuffer(name) == nullptr) + { + context->handleError(InvalidValue() << "name is not a valid buffer."); + return false; + } + return true; + + case GL_SHADER: + if (context->getShader(name) == nullptr) + { + context->handleError(InvalidValue() << "name is not a valid shader."); + return false; + } + return true; + + case GL_PROGRAM: + if (context->getProgram(name) == nullptr) + { + context->handleError(InvalidValue() << "name is not a valid program."); + return false; + } + return true; + + case GL_VERTEX_ARRAY: + if (context->getVertexArray(name) == nullptr) + { + context->handleError(InvalidValue() << "name is not a valid vertex array."); + return false; + } + return true; + + case GL_QUERY: + if (context->getQuery(name) == nullptr) + { + context->handleError(InvalidValue() << "name is not a valid query."); + return false; + } + return true; + + case GL_TRANSFORM_FEEDBACK: + if (context->getTransformFeedback(name) == nullptr) + { + context->handleError(InvalidValue() << "name is not a valid transform feedback."); + return false; + } + return true; + + case GL_SAMPLER: + if (context->getSampler(name) == nullptr) + { + context->handleError(InvalidValue() << "name is not a valid sampler."); + return false; + } + return true; + + case GL_TEXTURE: + if (context->getTexture(name) == nullptr) + { + context->handleError(InvalidValue() << "name is not a valid texture."); + return false; + } + return true; + + case GL_RENDERBUFFER: + if (context->getRenderbuffer(name) == nullptr) + { + context->handleError(InvalidValue() << "name is not a valid renderbuffer."); + return false; + } + return true; + + case GL_FRAMEBUFFER: + if (context->getFramebuffer(name) == nullptr) + { + context->handleError(InvalidValue() << "name is not a valid framebuffer."); + return false; + } + return true; + + default: + context->handleError(InvalidEnum() << "Invalid identifier."); + return false; + } +} + +static bool ValidateLabelLength(Context *context, GLsizei length, const GLchar *label) +{ + size_t labelLength = 0; + + if (length < 0) + { + if (label != nullptr) + { + labelLength = strlen(label); + } + } + else + { + labelLength = static_cast(length); + } + + if (labelLength > context->getExtensions().maxLabelLength) + { + context->handleError(InvalidValue() << "Label length is larger than GL_MAX_LABEL_LENGTH."); + return false; + } + + return true; +} + +bool ValidateObjectLabelKHR(Context *context, + GLenum identifier, + GLuint name, + GLsizei length, + const GLchar *label) +{ + if (!context->getExtensions().debug) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ExtensionNotEnabled); + return false; + } + + if (!ValidateObjectIdentifierAndName(context, identifier, name)) + { + return false; + } + + if (!ValidateLabelLength(context, length, label)) + { + return false; + } + + return true; +} + +bool ValidateGetObjectLabelKHR(Context *context, + GLenum identifier, + GLuint name, + GLsizei bufSize, + GLsizei *length, + GLchar *label) +{ + if (!context->getExtensions().debug) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ExtensionNotEnabled); + return false; + } + + if (bufSize < 0) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), NegativeBufferSize); + return false; + } + + if (!ValidateObjectIdentifierAndName(context, identifier, name)) + { + return false; + } + + return true; +} + +static bool ValidateObjectPtrName(Context *context, const void *ptr) +{ + if (context->getSync(reinterpret_cast(const_cast(ptr))) == nullptr) + { + context->handleError(InvalidValue() << "name is not a valid sync."); + return false; + } + + return true; +} + +bool ValidateObjectPtrLabelKHR(Context *context, + const void *ptr, + GLsizei length, + const GLchar *label) +{ + if (!context->getExtensions().debug) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ExtensionNotEnabled); + return false; + } + + if (!ValidateObjectPtrName(context, ptr)) + { + return false; + } + + if (!ValidateLabelLength(context, length, label)) + { + return false; + } + + return true; +} + +bool ValidateGetObjectPtrLabelKHR(Context *context, + const void *ptr, + GLsizei bufSize, + GLsizei *length, + GLchar *label) +{ + if (!context->getExtensions().debug) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ExtensionNotEnabled); + return false; + } + + if (bufSize < 0) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), NegativeBufferSize); + return false; + } + + if (!ValidateObjectPtrName(context, ptr)) + { + return false; + } + + return true; +} + +bool ValidateGetPointervKHR(Context *context, GLenum pname, void **params) +{ + if (!context->getExtensions().debug) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ExtensionNotEnabled); + return false; + } + + // TODO: represent this in Context::getQueryParameterInfo. + switch (pname) + { + case GL_DEBUG_CALLBACK_FUNCTION: + case GL_DEBUG_CALLBACK_USER_PARAM: + break; + + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), EnumNotSupported); + return false; + } + + return true; +} + +bool ValidateBlitFramebufferANGLE(Context *context, + GLint srcX0, + GLint srcY0, + GLint srcX1, + GLint srcY1, + GLint dstX0, + GLint dstY0, + GLint dstX1, + GLint dstY1, + GLbitfield mask, + GLenum filter) +{ + if (!context->getExtensions().framebufferBlit) + { + context->handleError(InvalidOperation() << "Blit extension not available."); + return false; + } + + if (srcX1 - srcX0 != dstX1 - dstX0 || srcY1 - srcY0 != dstY1 - dstY0) + { + // TODO(jmadill): Determine if this should be available on other implementations. + context->handleError(InvalidOperation() << "Scaling and flipping in " + "BlitFramebufferANGLE not supported by this " + "implementation."); + return false; + } + + if (filter == GL_LINEAR) + { + context->handleError(InvalidEnum() << "Linear blit not supported in this extension"); + return false; + } + + Framebuffer *readFramebuffer = context->getGLState().getReadFramebuffer(); + Framebuffer *drawFramebuffer = context->getGLState().getDrawFramebuffer(); + + if (mask & GL_COLOR_BUFFER_BIT) + { + const FramebufferAttachment *readColorAttachment = readFramebuffer->getReadColorbuffer(); + const FramebufferAttachment *drawColorAttachment = drawFramebuffer->getFirstColorbuffer(); + + if (readColorAttachment && drawColorAttachment) + { + if (!(readColorAttachment->type() == GL_TEXTURE && + readColorAttachment->getTextureImageIndex().type == GL_TEXTURE_2D) && + readColorAttachment->type() != GL_RENDERBUFFER && + readColorAttachment->type() != GL_FRAMEBUFFER_DEFAULT) + { + context->handleError(InvalidOperation()); + return false; + } + + for (size_t drawbufferIdx = 0; + drawbufferIdx < drawFramebuffer->getDrawbufferStateCount(); ++drawbufferIdx) + { + const FramebufferAttachment *attachment = + drawFramebuffer->getDrawBuffer(drawbufferIdx); + if (attachment) + { + if (!(attachment->type() == GL_TEXTURE && + attachment->getTextureImageIndex().type == GL_TEXTURE_2D) && + attachment->type() != GL_RENDERBUFFER && + attachment->type() != GL_FRAMEBUFFER_DEFAULT) + { + context->handleError(InvalidOperation()); + return false; + } + + // Return an error if the destination formats do not match + if (!Format::EquivalentForBlit(attachment->getFormat(), + readColorAttachment->getFormat())) + { + context->handleError(InvalidOperation()); + return false; + } + } + } + + if (readFramebuffer->getSamples(context) != 0 && + IsPartialBlit(context, readColorAttachment, drawColorAttachment, srcX0, srcY0, + srcX1, srcY1, dstX0, dstY0, dstX1, dstY1)) + { + context->handleError(InvalidOperation()); + 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]) + { + const FramebufferAttachment *readBuffer = + readFramebuffer->getAttachment(attachments[i]); + const FramebufferAttachment *drawBuffer = + drawFramebuffer->getAttachment(attachments[i]); + + if (readBuffer && drawBuffer) + { + if (IsPartialBlit(context, readBuffer, drawBuffer, srcX0, srcY0, srcX1, srcY1, + dstX0, dstY0, dstX1, dstY1)) + { + // only whole-buffer copies are permitted + context->handleError(InvalidOperation() << "Only whole-buffer depth and " + "stencil blits are supported by " + "this extension."); + return false; + } + + if (readBuffer->getSamples() != 0 || drawBuffer->getSamples() != 0) + { + context->handleError(InvalidOperation()); + return false; + } + } + } + } + + return ValidateBlitFramebufferParameters(context, srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, + dstX1, dstY1, mask, filter); +} + +bool ValidateClear(ValidationContext *context, GLbitfield mask) +{ + Framebuffer *fbo = context->getGLState().getDrawFramebuffer(); + if (fbo->checkStatus(context) != GL_FRAMEBUFFER_COMPLETE) + { + context->handleError(InvalidFramebufferOperation()); + return false; + } + + if ((mask & ~(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)) != 0) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), InvalidClearMask); + return false; + } + + if (context->getExtensions().webglCompatibility && (mask & GL_COLOR_BUFFER_BIT) != 0) + { + constexpr GLenum validComponentTypes[] = {GL_FLOAT, GL_UNSIGNED_NORMALIZED, + GL_SIGNED_NORMALIZED}; + + for (GLuint drawBufferIdx = 0; drawBufferIdx < fbo->getDrawbufferStateCount(); + drawBufferIdx++) + { + if (!ValidateWebGLFramebufferAttachmentClearType( + context, drawBufferIdx, validComponentTypes, ArraySize(validComponentTypes))) + { + return false; + } + } + } + + return true; +} + +bool ValidateDrawBuffersEXT(ValidationContext *context, GLsizei n, const GLenum *bufs) +{ + if (!context->getExtensions().drawBuffers) + { + context->handleError(InvalidOperation() << "Extension not supported."); + return false; + } + + return ValidateDrawBuffersBase(context, n, bufs); +} + +bool ValidateTexImage2D(Context *context, + GLenum target, + GLint level, + GLint internalformat, + GLsizei width, + GLsizei height, + GLint border, + GLenum format, + GLenum type, + const void *pixels) +{ + if (context->getClientMajorVersion() < 3) + { + return ValidateES2TexImageParameters(context, target, level, internalformat, false, false, + 0, 0, width, height, border, format, type, -1, pixels); + } + + ASSERT(context->getClientMajorVersion() >= 3); + return ValidateES3TexImage2DParameters(context, target, level, internalformat, false, false, 0, + 0, 0, width, height, 1, border, format, type, -1, + pixels); +} + +bool ValidateTexImage2DRobust(Context *context, + GLenum target, + GLint level, + GLint internalformat, + GLsizei width, + GLsizei height, + GLint border, + GLenum format, + GLenum type, + GLsizei bufSize, + const void *pixels) +{ + if (!ValidateRobustEntryPoint(context, bufSize)) + { + return false; + } + + if (context->getClientMajorVersion() < 3) + { + return ValidateES2TexImageParameters(context, target, level, internalformat, false, false, + 0, 0, width, height, border, format, type, bufSize, + pixels); + } + + ASSERT(context->getClientMajorVersion() >= 3); + return ValidateES3TexImage2DParameters(context, target, level, internalformat, false, false, 0, + 0, 0, width, height, 1, border, format, type, bufSize, + pixels); +} + +bool ValidateTexSubImage2D(Context *context, + GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLsizei width, + GLsizei height, + GLenum format, + GLenum type, + const void *pixels) +{ + + if (context->getClientMajorVersion() < 3) + { + return ValidateES2TexImageParameters(context, target, level, GL_NONE, false, true, xoffset, + yoffset, width, height, 0, format, type, -1, pixels); + } + + ASSERT(context->getClientMajorVersion() >= 3); + return ValidateES3TexImage2DParameters(context, target, level, GL_NONE, false, true, xoffset, + yoffset, 0, width, height, 1, 0, format, type, -1, + pixels); +} + +bool ValidateTexSubImage2DRobustANGLE(Context *context, + GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLsizei width, + GLsizei height, + GLenum format, + GLenum type, + GLsizei bufSize, + const void *pixels) +{ + if (!ValidateRobustEntryPoint(context, bufSize)) + { + return false; + } + + if (context->getClientMajorVersion() < 3) + { + return ValidateES2TexImageParameters(context, target, level, GL_NONE, false, true, xoffset, + yoffset, width, height, 0, format, type, bufSize, + pixels); + } + + ASSERT(context->getClientMajorVersion() >= 3); + return ValidateES3TexImage2DParameters(context, target, level, GL_NONE, false, true, xoffset, + yoffset, 0, width, height, 1, 0, format, type, bufSize, + pixels); +} + +bool ValidateCompressedTexImage2D(Context *context, + GLenum target, + GLint level, + GLenum internalformat, + GLsizei width, + GLsizei height, + GLint border, + GLsizei imageSize, + const void *data) +{ + if (context->getClientMajorVersion() < 3) + { + if (!ValidateES2TexImageParameters(context, target, level, internalformat, true, false, 0, + 0, width, height, border, GL_NONE, GL_NONE, -1, data)) + { + return false; + } + } + else + { + ASSERT(context->getClientMajorVersion() >= 3); + if (!ValidateES3TexImage2DParameters(context, target, level, internalformat, true, false, 0, + 0, 0, width, height, 1, border, GL_NONE, GL_NONE, -1, + data)) + { + return false; + } + } + + const InternalFormat &formatInfo = GetSizedInternalFormatInfo(internalformat); + auto blockSizeOrErr = formatInfo.computeCompressedImageSize(gl::Extents(width, height, 1)); + if (blockSizeOrErr.isError()) + { + context->handleError(blockSizeOrErr.getError()); + return false; + } + + if (imageSize < 0 || static_cast(imageSize) != blockSizeOrErr.getResult()) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), CompressedTextureDimensionsMustMatchData); + return false; + } + + if (target == GL_TEXTURE_RECTANGLE_ANGLE) + { + context->handleError(InvalidEnum() << "Rectangle texture cannot have a compressed format."); + return false; + } + + return true; +} + +bool ValidateCompressedTexImage2DRobustANGLE(Context *context, + GLenum target, + GLint level, + GLenum internalformat, + GLsizei width, + GLsizei height, + GLint border, + GLsizei imageSize, + GLsizei dataSize, + const void *data) +{ + if (!ValidateRobustCompressedTexImageBase(context, imageSize, dataSize)) + { + return false; + } + + return ValidateCompressedTexImage2D(context, target, level, internalformat, width, height, + border, imageSize, data); +} +bool ValidateCompressedTexSubImage2DRobustANGLE(Context *context, + GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLsizei width, + GLsizei height, + GLenum format, + GLsizei imageSize, + GLsizei dataSize, + const void *data) +{ + if (!ValidateRobustCompressedTexImageBase(context, imageSize, dataSize)) + { + return false; + } + + return ValidateCompressedTexSubImage2D(context, target, level, xoffset, yoffset, width, height, + format, imageSize, data); +} + +bool ValidateCompressedTexSubImage2D(Context *context, + GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLsizei width, + GLsizei height, + GLenum format, + GLsizei imageSize, + const void *data) +{ + if (context->getClientMajorVersion() < 3) + { + if (!ValidateES2TexImageParameters(context, target, level, GL_NONE, true, true, xoffset, + yoffset, width, height, 0, format, GL_NONE, -1, data)) + { + return false; + } + } + else + { + ASSERT(context->getClientMajorVersion() >= 3); + if (!ValidateES3TexImage2DParameters(context, target, level, GL_NONE, true, true, xoffset, + yoffset, 0, width, height, 1, 0, format, GL_NONE, -1, + data)) + { + return false; + } + } + + const InternalFormat &formatInfo = GetSizedInternalFormatInfo(format); + auto blockSizeOrErr = formatInfo.computeCompressedImageSize(gl::Extents(width, height, 1)); + if (blockSizeOrErr.isError()) + { + context->handleError(blockSizeOrErr.getError()); + return false; + } + + if (imageSize < 0 || static_cast(imageSize) != blockSizeOrErr.getResult()) + { + context->handleError(InvalidValue()); + return false; + } + + return true; +} + +bool ValidateGetBufferPointervOES(Context *context, + BufferBinding target, + GLenum pname, + void **params) +{ + return ValidateGetBufferPointervBase(context, target, pname, nullptr, params); +} + +bool ValidateMapBufferOES(Context *context, BufferBinding target, GLenum access) +{ + if (!context->getExtensions().mapBuffer) + { + context->handleError(InvalidOperation() << "Map buffer extension not available."); + return false; + } + + if (!ValidBufferType(context, target)) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidBufferTypes); + return false; + } + + Buffer *buffer = context->getGLState().getTargetBuffer(target); + + if (buffer == nullptr) + { + context->handleError(InvalidOperation() << "Attempted to map buffer object zero."); + return false; + } + + if (access != GL_WRITE_ONLY_OES) + { + context->handleError(InvalidEnum() << "Non-write buffer mapping not supported."); + return false; + } + + if (buffer->isMapped()) + { + context->handleError(InvalidOperation() << "Buffer is already mapped."); + return false; + } + + return ValidateMapBufferBase(context, target); +} + +bool ValidateUnmapBufferOES(Context *context, BufferBinding target) +{ + if (!context->getExtensions().mapBuffer) + { + context->handleError(InvalidOperation() << "Map buffer extension not available."); + return false; + } + + return ValidateUnmapBufferBase(context, target); +} + +bool ValidateMapBufferRangeEXT(Context *context, + BufferBinding target, + GLintptr offset, + GLsizeiptr length, + GLbitfield access) +{ + if (!context->getExtensions().mapBufferRange) + { + context->handleError(InvalidOperation() << "Map buffer range extension not available."); + return false; + } + + return ValidateMapBufferRangeBase(context, target, offset, length, access); +} + +bool ValidateMapBufferBase(Context *context, BufferBinding target) +{ + Buffer *buffer = context->getGLState().getTargetBuffer(target); + ASSERT(buffer != nullptr); + + // Check if this buffer is currently being used as a transform feedback output buffer + TransformFeedback *transformFeedback = context->getGLState().getCurrentTransformFeedback(); + if (transformFeedback != nullptr && transformFeedback->isActive()) + { + for (size_t i = 0; i < transformFeedback->getIndexedBufferCount(); i++) + { + const auto &transformFeedbackBuffer = transformFeedback->getIndexedBuffer(i); + if (transformFeedbackBuffer.get() == buffer) + { + context->handleError(InvalidOperation() + << "Buffer is currently bound for transform feedback."); + return false; + } + } + } + + return true; +} + +bool ValidateFlushMappedBufferRangeEXT(Context *context, + BufferBinding target, + GLintptr offset, + GLsizeiptr length) +{ + if (!context->getExtensions().mapBufferRange) + { + context->handleError(InvalidOperation() << "Map buffer range extension not available."); + return false; + } + + return ValidateFlushMappedBufferRangeBase(context, target, offset, length); +} + +bool ValidateBindTexture(Context *context, GLenum target, GLuint texture) +{ + Texture *textureObject = context->getTexture(texture); + if (textureObject && textureObject->getTarget() != target && texture != 0) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), TypeMismatch); + return false; + } + + if (!context->getGLState().isBindGeneratesResourceEnabled() && + !context->isTextureGenerated(texture)) + { + context->handleError(InvalidOperation() << "Texture was not generated"); + return false; + } + + switch (target) + { + case GL_TEXTURE_2D: + case GL_TEXTURE_CUBE_MAP: + break; + + case GL_TEXTURE_RECTANGLE_ANGLE: + if (!context->getExtensions().textureRectangle) + { + context->handleError(InvalidEnum() + << "Context does not support GL_ANGLE_texture_rectangle"); + return false; + } + break; + + case GL_TEXTURE_3D: + case GL_TEXTURE_2D_ARRAY: + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), ES3Required); + return false; + } + break; + + case GL_TEXTURE_2D_MULTISAMPLE: + if (context->getClientVersion() < Version(3, 1)) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), ES31Required); + return false; + } + break; + + case GL_TEXTURE_EXTERNAL_OES: + if (!context->getExtensions().eglImageExternal && + !context->getExtensions().eglStreamConsumerExternal) + { + context->handleError(InvalidEnum() << "External texture extension not enabled"); + return false; + } + break; + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidTextureTarget); + return false; + } + + return true; +} + +bool ValidateBindUniformLocationCHROMIUM(Context *context, + GLuint program, + GLint location, + const GLchar *name) +{ + if (!context->getExtensions().bindUniformLocation) + { + context->handleError(InvalidOperation() + << "GL_CHROMIUM_bind_uniform_location is not available."); + return false; + } + + Program *programObject = GetValidProgram(context, program); + if (!programObject) + { + return false; + } + + if (location < 0) + { + context->handleError(InvalidValue() << "Location cannot be less than 0."); + return false; + } + + const Caps &caps = context->getCaps(); + if (static_cast(location) >= + (caps.maxVertexUniformVectors + caps.maxFragmentUniformVectors) * 4) + { + context->handleError(InvalidValue() << "Location must be less than " + "(MAX_VERTEX_UNIFORM_VECTORS + " + "MAX_FRAGMENT_UNIFORM_VECTORS) * 4"); + return false; + } + + // The WebGL spec (section 6.20) disallows strings containing invalid ESSL characters for + // shader-related entry points + if (context->getExtensions().webglCompatibility && !IsValidESSLString(name, strlen(name))) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), InvalidNameCharacters); + return false; + } + + if (strncmp(name, "gl_", 3) == 0) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), NameBeginsWithGL); + return false; + } + + return true; +} + +bool ValidateCoverageModulationCHROMIUM(Context *context, GLenum components) +{ + if (!context->getExtensions().framebufferMixedSamples) + { + context->handleError(InvalidOperation() + << "GL_CHROMIUM_framebuffer_mixed_samples is not available."); + return false; + } + switch (components) + { + case GL_RGB: + case GL_RGBA: + case GL_ALPHA: + case GL_NONE: + break; + default: + context->handleError( + InvalidEnum() + << "GLenum components is not one of GL_RGB, GL_RGBA, GL_ALPHA or GL_NONE."); + return false; + } + + return true; +} + +// CHROMIUM_path_rendering + +bool ValidateMatrix(Context *context, GLenum matrixMode, const GLfloat *matrix) +{ + if (!context->getExtensions().pathRendering) + { + context->handleError(InvalidOperation() << "GL_CHROMIUM_path_rendering is not available."); + return false; + } + if (matrixMode != GL_PATH_MODELVIEW_CHROMIUM && matrixMode != GL_PATH_PROJECTION_CHROMIUM) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidMatrixMode); + return false; + } + if (matrix == nullptr) + { + context->handleError(InvalidOperation() << "Invalid matrix."); + return false; + } + return true; +} + +bool ValidateMatrixMode(Context *context, GLenum matrixMode) +{ + if (!context->getExtensions().pathRendering) + { + context->handleError(InvalidOperation() << "GL_CHROMIUM_path_rendering is not available."); + return false; + } + if (matrixMode != GL_PATH_MODELVIEW_CHROMIUM && matrixMode != GL_PATH_PROJECTION_CHROMIUM) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidMatrixMode); + return false; + } + return true; +} + +bool ValidateGenPaths(Context *context, GLsizei range) +{ + if (!context->getExtensions().pathRendering) + { + context->handleError(InvalidOperation() << "GL_CHROMIUM_path_rendering is not available."); + return false; + } + + // range = 0 is undefined in NV_path_rendering. + // we add stricter semantic check here and require a non zero positive range. + if (range <= 0) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), InvalidRange); + return false; + } + + if (!angle::IsValueInRangeForNumericType(range)) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), IntegerOverflow); + return false; + } + + return true; +} + +bool ValidateDeletePaths(Context *context, GLuint path, GLsizei range) +{ + if (!context->getExtensions().pathRendering) + { + context->handleError(InvalidOperation() << "GL_CHROMIUM_path_rendering is not available."); + return false; + } + + // range = 0 is undefined in NV_path_rendering. + // we add stricter semantic check here and require a non zero positive range. + if (range <= 0) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), InvalidRange); + return false; + } + + angle::CheckedNumeric checkedRange(path); + checkedRange += range; + + if (!angle::IsValueInRangeForNumericType(range) || !checkedRange.IsValid()) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), IntegerOverflow); + return false; + } + return true; +} + +bool ValidatePathCommands(Context *context, + GLuint path, + GLsizei numCommands, + const GLubyte *commands, + GLsizei numCoords, + GLenum coordType, + const void *coords) +{ + if (!context->getExtensions().pathRendering) + { + context->handleError(InvalidOperation() << "GL_CHROMIUM_path_rendering is not available."); + return false; + } + if (!context->hasPath(path)) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), NoSuchPath); + return false; + } + + if (numCommands < 0) + { + context->handleError(InvalidValue() << "Invalid number of commands."); + return false; + } + else if (numCommands > 0) + { + if (!commands) + { + context->handleError(InvalidValue() << "No commands array given."); + return false; + } + } + + if (numCoords < 0) + { + context->handleError(InvalidValue() << "Invalid number of coordinates."); + return false; + } + else if (numCoords > 0) + { + if (!coords) + { + context->handleError(InvalidValue() << "No coordinate array given."); + return false; + } + } + + std::uint32_t coordTypeSize = 0; + switch (coordType) + { + case GL_BYTE: + coordTypeSize = sizeof(GLbyte); + break; + + case GL_UNSIGNED_BYTE: + coordTypeSize = sizeof(GLubyte); + break; + + case GL_SHORT: + coordTypeSize = sizeof(GLshort); + break; + + case GL_UNSIGNED_SHORT: + coordTypeSize = sizeof(GLushort); + break; + + case GL_FLOAT: + coordTypeSize = sizeof(GLfloat); + break; + + default: + context->handleError(InvalidEnum() << "Invalid coordinate type."); + return false; + } + + angle::CheckedNumeric checkedSize(numCommands); + checkedSize += (coordTypeSize * numCoords); + if (!checkedSize.IsValid()) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), IntegerOverflow); + return false; + } + + // early return skips command data validation when it doesn't exist. + if (!commands) + return true; + + GLsizei expectedNumCoords = 0; + for (GLsizei i = 0; i < numCommands; ++i) + { + switch (commands[i]) + { + case GL_CLOSE_PATH_CHROMIUM: // no coordinates. + break; + case GL_MOVE_TO_CHROMIUM: + case GL_LINE_TO_CHROMIUM: + expectedNumCoords += 2; + break; + case GL_QUADRATIC_CURVE_TO_CHROMIUM: + expectedNumCoords += 4; + break; + case GL_CUBIC_CURVE_TO_CHROMIUM: + expectedNumCoords += 6; + break; + case GL_CONIC_CURVE_TO_CHROMIUM: + expectedNumCoords += 5; + break; + default: + context->handleError(InvalidEnum() << "Invalid command."); + return false; + } + } + if (expectedNumCoords != numCoords) + { + context->handleError(InvalidValue() << "Invalid number of coordinates."); + return false; + } + + return true; +} + +bool ValidateSetPathParameter(Context *context, GLuint path, GLenum pname, GLfloat value) +{ + if (!context->getExtensions().pathRendering) + { + context->handleError(InvalidOperation() << "GL_CHROMIUM_path_rendering is not available."); + return false; + } + if (!context->hasPath(path)) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), NoSuchPath); + return false; + } + + switch (pname) + { + case GL_PATH_STROKE_WIDTH_CHROMIUM: + if (value < 0.0f) + { + context->handleError(InvalidValue() << "Invalid stroke width."); + return false; + } + break; + case GL_PATH_END_CAPS_CHROMIUM: + switch (static_cast(value)) + { + case GL_FLAT_CHROMIUM: + case GL_SQUARE_CHROMIUM: + case GL_ROUND_CHROMIUM: + break; + default: + context->handleError(InvalidEnum() << "Invalid end caps."); + return false; + } + break; + case GL_PATH_JOIN_STYLE_CHROMIUM: + switch (static_cast(value)) + { + case GL_MITER_REVERT_CHROMIUM: + case GL_BEVEL_CHROMIUM: + case GL_ROUND_CHROMIUM: + break; + default: + context->handleError(InvalidEnum() << "Invalid join style."); + return false; + } + case GL_PATH_MITER_LIMIT_CHROMIUM: + if (value < 0.0f) + { + context->handleError(InvalidValue() << "Invalid miter limit."); + return false; + } + break; + + case GL_PATH_STROKE_BOUND_CHROMIUM: + // no errors, only clamping. + break; + + default: + context->handleError(InvalidEnum() << "Invalid path parameter."); + return false; + } + return true; +} + +bool ValidateGetPathParameter(Context *context, GLuint path, GLenum pname, GLfloat *value) +{ + if (!context->getExtensions().pathRendering) + { + context->handleError(InvalidOperation() << "GL_CHROMIUM_path_rendering is not available."); + return false; + } + + if (!context->hasPath(path)) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), NoSuchPath); + return false; + } + if (!value) + { + context->handleError(InvalidValue() << "No value array."); + return false; + } + + switch (pname) + { + case GL_PATH_STROKE_WIDTH_CHROMIUM: + case GL_PATH_END_CAPS_CHROMIUM: + case GL_PATH_JOIN_STYLE_CHROMIUM: + case GL_PATH_MITER_LIMIT_CHROMIUM: + case GL_PATH_STROKE_BOUND_CHROMIUM: + break; + + default: + context->handleError(InvalidEnum() << "Invalid path parameter."); + return false; + } + + return true; +} + +bool ValidatePathStencilFunc(Context *context, GLenum func, GLint ref, GLuint mask) +{ + if (!context->getExtensions().pathRendering) + { + context->handleError(InvalidOperation() << "GL_CHROMIUM_path_rendering is not available."); + return false; + } + + switch (func) + { + case GL_NEVER: + case GL_ALWAYS: + case GL_LESS: + case GL_LEQUAL: + case GL_EQUAL: + case GL_GEQUAL: + case GL_GREATER: + case GL_NOTEQUAL: + break; + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidStencil); + return false; + } + + return true; +} + +// Note that the spec specifies that for the path drawing commands +// if the path object is not an existing path object the command +// does nothing and no error is generated. +// However if the path object exists but has not been specified any +// commands then an error is generated. + +bool ValidateStencilFillPath(Context *context, GLuint path, GLenum fillMode, GLuint mask) +{ + if (!context->getExtensions().pathRendering) + { + context->handleError(InvalidOperation() << "GL_CHROMIUM_path_rendering is not available."); + return false; + } + if (context->hasPath(path) && !context->hasPathData(path)) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), NoSuchPath); + return false; + } + + switch (fillMode) + { + case GL_COUNT_UP_CHROMIUM: + case GL_COUNT_DOWN_CHROMIUM: + break; + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidFillMode); + return false; + } + + if (!isPow2(mask + 1)) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), InvalidStencilBitMask); + return false; + } + + return true; +} + +bool ValidateStencilStrokePath(Context *context, GLuint path, GLint reference, GLuint mask) +{ + if (!context->getExtensions().pathRendering) + { + context->handleError(InvalidOperation() << "GL_CHROMIUM_path_rendering is not available."); + return false; + } + if (context->hasPath(path) && !context->hasPathData(path)) + { + context->handleError(InvalidOperation() << "No such path or path has no data."); + return false; + } + + return true; +} + +bool ValidateCoverPath(Context *context, GLuint path, GLenum coverMode) +{ + if (!context->getExtensions().pathRendering) + { + context->handleError(InvalidOperation() << "GL_CHROMIUM_path_rendering is not available."); + return false; + } + if (context->hasPath(path) && !context->hasPathData(path)) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), NoSuchPath); + return false; + } + + switch (coverMode) + { + case GL_CONVEX_HULL_CHROMIUM: + case GL_BOUNDING_BOX_CHROMIUM: + break; + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidCoverMode); + return false; + } + return true; +} + +bool ValidateStencilThenCoverFillPath(Context *context, + GLuint path, + GLenum fillMode, + GLuint mask, + GLenum coverMode) +{ + return ValidateStencilFillPath(context, path, fillMode, mask) && + ValidateCoverPath(context, path, coverMode); +} + +bool ValidateStencilThenCoverStrokePath(Context *context, + GLuint path, + GLint reference, + GLuint mask, + GLenum coverMode) +{ + return ValidateStencilStrokePath(context, path, reference, mask) && + ValidateCoverPath(context, path, coverMode); +} + +bool ValidateIsPath(Context *context) +{ + if (!context->getExtensions().pathRendering) + { + context->handleError(InvalidOperation() << "GL_CHROMIUM_path_rendering is not available."); + return false; + } + return true; +} + +bool ValidateCoverFillPathInstanced(Context *context, + GLsizei numPaths, + GLenum pathNameType, + const void *paths, + GLuint pathBase, + GLenum coverMode, + GLenum transformType, + const GLfloat *transformValues) +{ + if (!ValidateInstancedPathParameters(context, numPaths, pathNameType, paths, pathBase, + transformType, transformValues)) + return false; + + switch (coverMode) + { + case GL_CONVEX_HULL_CHROMIUM: + case GL_BOUNDING_BOX_CHROMIUM: + case GL_BOUNDING_BOX_OF_BOUNDING_BOXES_CHROMIUM: + break; + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidCoverMode); + return false; + } + + return true; +} + +bool ValidateCoverStrokePathInstanced(Context *context, + GLsizei numPaths, + GLenum pathNameType, + const void *paths, + GLuint pathBase, + GLenum coverMode, + GLenum transformType, + const GLfloat *transformValues) +{ + if (!ValidateInstancedPathParameters(context, numPaths, pathNameType, paths, pathBase, + transformType, transformValues)) + return false; + + switch (coverMode) + { + case GL_CONVEX_HULL_CHROMIUM: + case GL_BOUNDING_BOX_CHROMIUM: + case GL_BOUNDING_BOX_OF_BOUNDING_BOXES_CHROMIUM: + break; + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidCoverMode); + return false; + } + + return true; +} + +bool ValidateStencilFillPathInstanced(Context *context, + GLsizei numPaths, + GLenum pathNameType, + const void *paths, + GLuint pathBase, + GLenum fillMode, + GLuint mask, + GLenum transformType, + const GLfloat *transformValues) +{ + + if (!ValidateInstancedPathParameters(context, numPaths, pathNameType, paths, pathBase, + transformType, transformValues)) + return false; + + switch (fillMode) + { + case GL_COUNT_UP_CHROMIUM: + case GL_COUNT_DOWN_CHROMIUM: + break; + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidFillMode); + return false; + } + if (!isPow2(mask + 1)) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), InvalidStencilBitMask); + return false; + } + return true; +} + +bool ValidateStencilStrokePathInstanced(Context *context, + GLsizei numPaths, + GLenum pathNameType, + const void *paths, + GLuint pathBase, + GLint reference, + GLuint mask, + GLenum transformType, + const GLfloat *transformValues) +{ + if (!ValidateInstancedPathParameters(context, numPaths, pathNameType, paths, pathBase, + transformType, transformValues)) + return false; + + // no more validation here. + + return true; +} + +bool ValidateStencilThenCoverFillPathInstanced(Context *context, + GLsizei numPaths, + GLenum pathNameType, + const void *paths, + GLuint pathBase, + GLenum fillMode, + GLuint mask, + GLenum coverMode, + GLenum transformType, + const GLfloat *transformValues) +{ + if (!ValidateInstancedPathParameters(context, numPaths, pathNameType, paths, pathBase, + transformType, transformValues)) + return false; + + switch (coverMode) + { + case GL_CONVEX_HULL_CHROMIUM: + case GL_BOUNDING_BOX_CHROMIUM: + case GL_BOUNDING_BOX_OF_BOUNDING_BOXES_CHROMIUM: + break; + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidCoverMode); + return false; + } + + switch (fillMode) + { + case GL_COUNT_UP_CHROMIUM: + case GL_COUNT_DOWN_CHROMIUM: + break; + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidFillMode); + return false; + } + if (!isPow2(mask + 1)) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), InvalidStencilBitMask); + return false; + } + + return true; +} + +bool ValidateStencilThenCoverStrokePathInstanced(Context *context, + GLsizei numPaths, + GLenum pathNameType, + const void *paths, + GLuint pathBase, + GLint reference, + GLuint mask, + GLenum coverMode, + GLenum transformType, + const GLfloat *transformValues) +{ + if (!ValidateInstancedPathParameters(context, numPaths, pathNameType, paths, pathBase, + transformType, transformValues)) + return false; + + switch (coverMode) + { + case GL_CONVEX_HULL_CHROMIUM: + case GL_BOUNDING_BOX_CHROMIUM: + case GL_BOUNDING_BOX_OF_BOUNDING_BOXES_CHROMIUM: + break; + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidCoverMode); + return false; + } + + return true; +} + +bool ValidateBindFragmentInputLocation(Context *context, + GLuint program, + GLint location, + const GLchar *name) +{ + if (!context->getExtensions().pathRendering) + { + context->handleError(InvalidOperation() << "GL_CHROMIUM_path_rendering is not available."); + return false; + } + + const GLint MaxLocation = context->getCaps().maxVaryingVectors * 4; + if (location >= MaxLocation) + { + context->handleError(InvalidValue() << "Location exceeds max varying."); + return false; + } + + const auto *programObject = context->getProgram(program); + if (!programObject) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ProgramNotBound); + return false; + } + + if (!name) + { + context->handleError(InvalidValue() << "No name given."); + return false; + } + + if (angle::BeginsWith(name, "gl_")) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), NameBeginsWithGL); + return false; + } + + return true; +} + +bool ValidateProgramPathFragmentInputGen(Context *context, + GLuint program, + GLint location, + GLenum genMode, + GLint components, + const GLfloat *coeffs) +{ + if (!context->getExtensions().pathRendering) + { + context->handleError(InvalidOperation() << "GL_CHROMIUM_path_rendering is not available."); + return false; + } + + const auto *programObject = context->getProgram(program); + if (!programObject || programObject->isFlaggedForDeletion()) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ProgramDoesNotExist); + return false; + } + + if (!programObject->isLinked()) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ProgramNotLinked); + return false; + } + + switch (genMode) + { + case GL_NONE: + if (components != 0) + { + context->handleError(InvalidValue() << "Invalid components."); return false; } break; - case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: - if (context->getExtensions().textureCompressionDXT3) + + case GL_OBJECT_LINEAR_CHROMIUM: + case GL_EYE_LINEAR_CHROMIUM: + case GL_CONSTANT_CHROMIUM: + if (components < 1 || components > 4) { - context->recordError(Error(GL_INVALID_OPERATION)); + context->handleError(InvalidValue() << "Invalid components."); return false; } - else + if (!coeffs) + { + context->handleError(InvalidValue() << "No coefficients array given."); + return false; + } + break; + + default: + context->handleError(InvalidEnum() << "Invalid gen mode."); + return false; + } + + // If the location is -1 then the command is silently ignored + // and no further validation is needed. + if (location == -1) + return true; + + const auto &binding = programObject->getFragmentInputBindingInfo(context, location); + + if (!binding.valid) + { + context->handleError(InvalidOperation() << "No such binding."); + return false; + } + + if (binding.type != GL_NONE) + { + GLint expectedComponents = 0; + switch (binding.type) + { + case GL_FLOAT: + expectedComponents = 1; + break; + case GL_FLOAT_VEC2: + expectedComponents = 2; + break; + case GL_FLOAT_VEC3: + expectedComponents = 3; + break; + case GL_FLOAT_VEC4: + expectedComponents = 4; + break; + default: + context->handleError( + InvalidOperation() + << "Fragment input type is not a floating point scalar or vector."); + return false; + } + if (expectedComponents != components && genMode != GL_NONE) + { + context->handleError(InvalidOperation() << "Unexpected number of components"); + return false; + } + } + return true; +} + +bool ValidateCopyTextureCHROMIUM(Context *context, + GLuint sourceId, + GLint sourceLevel, + GLenum destTarget, + GLuint destId, + GLint destLevel, + GLint internalFormat, + GLenum destType, + GLboolean unpackFlipY, + GLboolean unpackPremultiplyAlpha, + GLboolean unpackUnmultiplyAlpha) +{ + if (!context->getExtensions().copyTexture) + { + context->handleError(InvalidOperation() + << "GL_CHROMIUM_copy_texture extension not available."); + return false; + } + + const Texture *source = context->getTexture(sourceId); + if (source == nullptr) + { + context->handleError(InvalidValue() << "Source texture is not a valid texture object."); + return false; + } + + if (!IsValidCopyTextureSourceTarget(context, source->getTarget())) + { + context->handleError(InvalidValue() << "Source texture a valid texture type."); + return false; + } + + GLenum sourceTarget = source->getTarget(); + ASSERT(sourceTarget != GL_TEXTURE_CUBE_MAP); + + if (!IsValidCopyTextureSourceLevel(context, source->getTarget(), sourceLevel)) + { + context->handleError(InvalidValue() << "Source texture level is not valid."); + return false; + } + + GLsizei sourceWidth = static_cast(source->getWidth(sourceTarget, sourceLevel)); + GLsizei sourceHeight = static_cast(source->getHeight(sourceTarget, sourceLevel)); + if (sourceWidth == 0 || sourceHeight == 0) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), InvalidInternalFormat); + return false; + } + + const InternalFormat &sourceFormat = *source->getFormat(sourceTarget, sourceLevel).info; + if (!IsValidCopyTextureSourceInternalFormatEnum(sourceFormat.internalFormat)) + { + context->handleError(InvalidOperation() << "Source texture internal format is invalid."); + return false; + } + + if (!IsValidCopyTextureDestinationTargetEnum(context, destTarget)) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidTextureTarget); + return false; + } + + const Texture *dest = context->getTexture(destId); + if (dest == nullptr) + { + context->handleError(InvalidValue() + << "Destination texture is not a valid texture object."); + return false; + } + + if (!IsValidCopyTextureDestinationTarget(context, dest->getTarget(), destTarget)) + { + context->handleError(InvalidValue() << "Destination texture a valid texture type."); + return false; + } + + if (!IsValidCopyTextureDestinationLevel(context, destTarget, destLevel, sourceWidth, + sourceHeight)) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), InvalidMipLevel); + return false; + } + + if (!IsValidCopyTextureDestinationFormatType(context, internalFormat, destType)) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), MismatchedTypeAndFormat); + return false; + } + + if (IsCubeMapTextureTarget(destTarget) && sourceWidth != sourceHeight) + { + context->handleError( + InvalidValue() << "Destination width and height must be equal for cube map textures."); + return false; + } + + if (dest->getImmutableFormat()) + { + context->handleError(InvalidOperation() << "Destination texture is immutable."); + return false; + } + + return true; +} + +bool ValidateCopySubTextureCHROMIUM(Context *context, + GLuint sourceId, + GLint sourceLevel, + GLenum destTarget, + GLuint destId, + GLint destLevel, + GLint xoffset, + GLint yoffset, + GLint x, + GLint y, + GLsizei width, + GLsizei height, + GLboolean unpackFlipY, + GLboolean unpackPremultiplyAlpha, + GLboolean unpackUnmultiplyAlpha) +{ + if (!context->getExtensions().copyTexture) + { + context->handleError(InvalidOperation() + << "GL_CHROMIUM_copy_texture extension not available."); + return false; + } + + const Texture *source = context->getTexture(sourceId); + if (source == nullptr) + { + context->handleError(InvalidValue() << "Source texture is not a valid texture object."); + return false; + } + + if (!IsValidCopyTextureSourceTarget(context, source->getTarget())) + { + context->handleError(InvalidValue() << "Source texture a valid texture type."); + return false; + } + + GLenum sourceTarget = source->getTarget(); + ASSERT(sourceTarget != GL_TEXTURE_CUBE_MAP); + + if (!IsValidCopyTextureSourceLevel(context, source->getTarget(), sourceLevel)) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), InvalidMipLevel); + return false; + } + + if (source->getWidth(sourceTarget, sourceLevel) == 0 || + source->getHeight(sourceTarget, sourceLevel) == 0) + { + context->handleError(InvalidValue() + << "The source level of the source texture must be defined."); + return false; + } + + if (x < 0 || y < 0) + { + context->handleError(InvalidValue() << "x and y cannot be negative."); + return false; + } + + if (width < 0 || height < 0) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), NegativeSize); + return false; + } + + if (static_cast(x + width) > source->getWidth(sourceTarget, sourceLevel) || + static_cast(y + height) > source->getHeight(sourceTarget, sourceLevel)) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), SourceTextureTooSmall); + return false; + } + + const Format &sourceFormat = source->getFormat(sourceTarget, sourceLevel); + if (!IsValidCopySubTextureSourceInternalFormat(sourceFormat.info->internalFormat)) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), InvalidInternalFormat); + return false; + } + + if (!IsValidCopyTextureDestinationTargetEnum(context, destTarget)) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidTextureTarget); + return false; + } + + const Texture *dest = context->getTexture(destId); + if (dest == nullptr) + { + context->handleError(InvalidValue() + << "Destination texture is not a valid texture object."); + return false; + } + + if (!IsValidCopyTextureDestinationTarget(context, dest->getTarget(), destTarget)) + { + context->handleError(InvalidValue() << "Destination texture a valid texture type."); + return false; + } + + if (!IsValidCopyTextureDestinationLevel(context, destTarget, destLevel, width, height)) + { + context->handleError(InvalidValue() << "Destination texture level is not valid."); + return false; + } + + if (dest->getWidth(destTarget, destLevel) == 0 || dest->getHeight(destTarget, destLevel) == 0) + { + context + ->handleError(InvalidOperation() + << "The destination level of the destination texture must be defined."); + return false; + } + + const InternalFormat &destFormat = *dest->getFormat(destTarget, destLevel).info; + if (!IsValidCopySubTextureDestionationInternalFormat(destFormat.internalFormat)) + { + context->handleError(InvalidOperation() + << "Destination internal format and type combination is not valid."); + return false; + } + + if (xoffset < 0 || yoffset < 0) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), NegativeOffset); + return false; + } + + if (static_cast(xoffset + width) > dest->getWidth(destTarget, destLevel) || + static_cast(yoffset + height) > dest->getHeight(destTarget, destLevel)) + { + context->handleError(InvalidValue() << "Destination texture not large enough to copy to."); + return false; + } + + return true; +} + +bool ValidateCompressedCopyTextureCHROMIUM(Context *context, GLuint sourceId, GLuint destId) +{ + if (!context->getExtensions().copyCompressedTexture) + { + context->handleError(InvalidOperation() + << "GL_CHROMIUM_copy_compressed_texture extension not available."); + return false; + } + + const gl::Texture *source = context->getTexture(sourceId); + if (source == nullptr) + { + context->handleError(InvalidValue() << "Source texture is not a valid texture object."); + return false; + } + + if (source->getTarget() != GL_TEXTURE_2D) + { + context->handleError(InvalidValue() << "Source texture must be of type GL_TEXTURE_2D."); + return false; + } + + if (source->getWidth(GL_TEXTURE_2D, 0) == 0 || source->getHeight(GL_TEXTURE_2D, 0) == 0) + { + context->handleError(InvalidValue() << "Source texture must level 0 defined."); + return false; + } + + const gl::Format &sourceFormat = source->getFormat(GL_TEXTURE_2D, 0); + if (!sourceFormat.info->compressed) + { + context->handleError(InvalidOperation() + << "Source texture must have a compressed internal format."); + return false; + } + + const gl::Texture *dest = context->getTexture(destId); + if (dest == nullptr) + { + context->handleError(InvalidValue() + << "Destination texture is not a valid texture object."); + return false; + } + + if (dest->getTarget() != GL_TEXTURE_2D) + { + context->handleError(InvalidValue() + << "Destination texture must be of type GL_TEXTURE_2D."); + return false; + } + + if (dest->getImmutableFormat()) + { + context->handleError(InvalidOperation() << "Destination cannot be immutable."); + return false; + } + + return true; +} + +bool ValidateCreateShader(Context *context, GLenum type) +{ + switch (type) + { + case GL_VERTEX_SHADER: + case GL_FRAGMENT_SHADER: + break; + + case GL_COMPUTE_SHADER: + if (context->getClientVersion() < Version(3, 1)) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), ES31Required); + return false; + } + break; + + case GL_GEOMETRY_SHADER_EXT: + if (!context->getExtensions().geometryShader) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidShaderType); + return false; + } + break; + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidShaderType); + return false; + } + + return true; +} + +bool ValidateBufferData(ValidationContext *context, + BufferBinding target, + GLsizeiptr size, + const void *data, + BufferUsage usage) +{ + if (size < 0) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), NegativeSize); + return false; + } + + switch (usage) + { + case BufferUsage::StreamDraw: + case BufferUsage::StaticDraw: + case BufferUsage::DynamicDraw: + break; + + case BufferUsage::StreamRead: + case BufferUsage::StaticRead: + case BufferUsage::DynamicRead: + case BufferUsage::StreamCopy: + case BufferUsage::StaticCopy: + case BufferUsage::DynamicCopy: + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidBufferUsage); + return false; + } + break; + + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidBufferUsage); + return false; + } + + if (!ValidBufferType(context, target)) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidBufferTypes); + return false; + } + + Buffer *buffer = context->getGLState().getTargetBuffer(target); + + if (!buffer) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), BufferNotBound); + return false; + } + + return true; +} + +bool ValidateBufferSubData(ValidationContext *context, + BufferBinding target, + GLintptr offset, + GLsizeiptr size, + const void *data) +{ + if (size < 0) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), NegativeSize); + return false; + } + + if (offset < 0) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), NegativeOffset); + return false; + } + + if (!ValidBufferType(context, target)) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidBufferTypes); + return false; + } + + Buffer *buffer = context->getGLState().getTargetBuffer(target); + + if (!buffer) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), BufferNotBound); + return false; + } + + if (buffer->isMapped()) + { + context->handleError(InvalidOperation()); + return false; + } + + // Check for possible overflow of size + offset + angle::CheckedNumeric checkedSize(size); + checkedSize += offset; + if (!checkedSize.IsValid()) + { + context->handleError(OutOfMemory()); + return false; + } + + if (size + offset > buffer->getSize()) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), InsufficientBufferSize); + return false; + } + + return true; +} + +bool ValidateRequestExtensionANGLE(Context *context, const GLchar *name) +{ + if (!context->getExtensions().requestExtension) + { + context->handleError(InvalidOperation() << "GL_ANGLE_request_extension is not available."); + return false; + } + + if (!context->isExtensionRequestable(name)) + { + context->handleError(InvalidOperation() << "Extension " << name << " is not requestable."); + return false; + } + + return true; +} + +bool ValidateActiveTexture(ValidationContext *context, GLenum texture) +{ + if (texture < GL_TEXTURE0 || + texture > GL_TEXTURE0 + context->getCaps().maxCombinedTextureImageUnits - 1) + { + context->handleError(InvalidEnum()); + return false; + } + + return true; +} + +bool ValidateAttachShader(ValidationContext *context, GLuint program, GLuint shader) +{ + Program *programObject = GetValidProgram(context, program); + if (!programObject) + { + return false; + } + + Shader *shaderObject = GetValidShader(context, shader); + if (!shaderObject) + { + return false; + } + + switch (shaderObject->getType()) + { + case GL_VERTEX_SHADER: + { + if (programObject->getAttachedVertexShader()) { - context->recordError(Error(GL_INVALID_ENUM)); + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ShaderAttachmentHasShader); return false; } break; - case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: - if (context->getExtensions().textureCompressionDXT5) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - else + } + case GL_FRAGMENT_SHADER: + { + if (programObject->getAttachedFragmentShader()) { - context->recordError(Error(GL_INVALID_ENUM)); + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ShaderAttachmentHasShader); return false; } break; - case GL_ETC1_RGB8_OES: - if (context->getExtensions().compressedETC1RGB8Texture) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - else - { - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } - break; - case GL_ETC1_RGB8_LOSSY_DECODE_ANGLE: - if (context->getExtensions().lossyETCDecode) - { - context->recordError( - Error(GL_INVALID_OPERATION, - "ETC1_RGB8_LOSSY_DECODE_ANGLE can't work with this type.")); - return false; - } - else - { - context->recordError( - Error(GL_INVALID_ENUM, "ANGLE_lossy_etc_decode extension is not supported.")); - 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) + } + case GL_COMPUTE_SHADER: + { + if (programObject->getAttachedComputeShader()) { - context->recordError(Error(GL_INVALID_OPERATION)); + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ShaderAttachmentHasShader); return false; } - // OES_depth_texture supports loading depth data and multiple levels, - // but ANGLE_depth_texture does not - if (pixels != NULL || level != 0) + break; + } + case GL_GEOMETRY_SHADER_EXT: + { + if (programObject->getAttachedGeometryShader()) { - context->recordError(Error(GL_INVALID_OPERATION)); + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ShaderAttachmentHasShader); return false; } break; - default: - break; } + default: + UNREACHABLE(); + break; + } - if (type == GL_FLOAT) + return true; +} + +bool ValidateBindAttribLocation(ValidationContext *context, + GLuint program, + GLuint index, + const GLchar *name) +{ + if (index >= MAX_VERTEX_ATTRIBS) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), IndexExceedsMaxVertexAttribute); + return false; + } + + if (strncmp(name, "gl_", 3) == 0) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), NameBeginsWithGL); + return false; + } + + if (context->isWebGL()) + { + const size_t length = strlen(name); + + if (!IsValidESSLString(name, length)) { - if (!context->getExtensions().textureFloat) - { - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } + // The WebGL spec (section 6.20) disallows strings containing invalid ESSL characters + // for shader-related entry points + ANGLE_VALIDATION_ERR(context, InvalidValue(), InvalidNameCharacters); + return false; } - else if (type == GL_HALF_FLOAT_OES) + + if (!ValidateWebGLNameLength(context, length) || !ValidateWebGLNamePrefix(context, name)) { - if (!context->getExtensions().textureHalfFloat) - { - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } + return false; } } + return GetValidProgram(context, program) != nullptr; +} + +bool ValidateBindBuffer(ValidationContext *context, BufferBinding target, GLuint buffer) +{ + if (!ValidBufferType(context, target)) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidBufferTypes); + return false; + } + + if (!context->getGLState().isBindGeneratesResourceEnabled() && + !context->isBufferGenerated(buffer)) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ObjectNotGenerated); + return false; + } + return true; } -bool ValidateES2CopyTexImageParameters(ValidationContext *context, - GLenum target, - GLint level, - GLenum internalformat, - bool isSubImage, - GLint xoffset, - GLint yoffset, - GLint x, - GLint y, - GLsizei width, - GLsizei height, - GLint border) +bool ValidateBindFramebuffer(ValidationContext *context, GLenum target, GLuint framebuffer) { - GLenum textureInternalFormat = GL_NONE; + if (!ValidFramebufferTarget(context, target)) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidFramebufferTarget); + return false; + } - if (!ValidTexture2DDestinationTarget(context, target)) + if (!context->getGLState().isBindGeneratesResourceEnabled() && + !context->isFramebufferGenerated(framebuffer)) { - context->recordError(Error(GL_INVALID_ENUM, "Invalid texture target")); + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ObjectNotGenerated); return false; } - if (!ValidateCopyTexImageParametersBase(context, target, level, internalformat, isSubImage, - xoffset, yoffset, 0, x, y, width, height, border, &textureInternalFormat)) + return true; +} + +bool ValidateBindRenderbuffer(ValidationContext *context, GLenum target, GLuint renderbuffer) +{ + if (target != GL_RENDERBUFFER) { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidRenderbufferTarget); return false; } - const gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer(); - GLenum colorbufferFormat = framebuffer->getReadColorbuffer()->getInternalFormat(); - const auto &internalFormatInfo = gl::GetInternalFormatInfo(textureInternalFormat); - GLenum textureFormat = internalFormatInfo.format; + if (!context->getGLState().isBindGeneratesResourceEnabled() && + !context->isRenderbufferGenerated(renderbuffer)) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ObjectNotGenerated); + return false; + } - // [OpenGL ES 2.0.24] table 3.9 - if (isSubImage) + return true; +} + +static bool ValidBlendEquationMode(const ValidationContext *context, GLenum mode) +{ + switch (mode) { - 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: - case GL_ETC1_RGB8_OES: - case GL_ETC1_RGB8_LOSSY_DECODE_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)); + case GL_FUNC_ADD: + case GL_FUNC_SUBTRACT: + case GL_FUNC_REVERSE_SUBTRACT: + return true; + + case GL_MIN: + case GL_MAX: + return context->getClientVersion() >= ES_3_0 || context->getExtensions().blendMinMax; + + default: return false; - } } - else +} + +bool ValidateBlendColor(ValidationContext *context, + GLfloat red, + GLfloat green, + GLfloat blue, + GLfloat alpha) +{ + return true; +} + +bool ValidateBlendEquation(ValidationContext *context, GLenum mode) +{ + if (!ValidBlendEquationMode(context, mode)) { - switch (internalformat) + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidBlendEquation); + return false; + } + + return true; +} + +bool ValidateBlendEquationSeparate(ValidationContext *context, GLenum modeRGB, GLenum modeAlpha) +{ + if (!ValidBlendEquationMode(context, modeRGB)) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidBlendEquation); + return false; + } + + if (!ValidBlendEquationMode(context, modeAlpha)) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidBlendEquation); + return false; + } + + return true; +} + +bool ValidateBlendFunc(ValidationContext *context, GLenum sfactor, GLenum dfactor) +{ + return ValidateBlendFuncSeparate(context, sfactor, dfactor, sfactor, dfactor); +} + +static bool ValidSrcBlendFunc(GLenum srcBlend) +{ + switch (srcBlend) + { + case GL_ZERO: + case GL_ONE: + case GL_SRC_COLOR: + case GL_ONE_MINUS_SRC_COLOR: + case GL_DST_COLOR: + case GL_ONE_MINUS_DST_COLOR: + case GL_SRC_ALPHA: + case GL_ONE_MINUS_SRC_ALPHA: + case GL_DST_ALPHA: + case GL_ONE_MINUS_DST_ALPHA: + case GL_CONSTANT_COLOR: + case GL_ONE_MINUS_CONSTANT_COLOR: + case GL_CONSTANT_ALPHA: + case GL_ONE_MINUS_CONSTANT_ALPHA: + case GL_SRC_ALPHA_SATURATE: + return true; + + default: + return false; + } +} + +static bool ValidDstBlendFunc(GLenum dstBlend, GLint contextMajorVersion) +{ + switch (dstBlend) + { + case GL_ZERO: + case GL_ONE: + case GL_SRC_COLOR: + case GL_ONE_MINUS_SRC_COLOR: + case GL_DST_COLOR: + case GL_ONE_MINUS_DST_COLOR: + case GL_SRC_ALPHA: + case GL_ONE_MINUS_SRC_ALPHA: + case GL_DST_ALPHA: + case GL_ONE_MINUS_DST_ALPHA: + case GL_CONSTANT_COLOR: + case GL_ONE_MINUS_CONSTANT_COLOR: + case GL_CONSTANT_ALPHA: + case GL_ONE_MINUS_CONSTANT_ALPHA: + return true; + + case GL_SRC_ALPHA_SATURATE: + return (contextMajorVersion >= 3); + + default: + return false; + } +} + +bool ValidateBlendFuncSeparate(ValidationContext *context, + GLenum srcRGB, + GLenum dstRGB, + GLenum srcAlpha, + GLenum dstAlpha) +{ + if (!ValidSrcBlendFunc(srcRGB)) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidBlendFunction); + return false; + } + + if (!ValidDstBlendFunc(dstRGB, context->getClientMajorVersion())) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidBlendFunction); + return false; + } + + if (!ValidSrcBlendFunc(srcAlpha)) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidBlendFunction); + return false; + } + + if (!ValidDstBlendFunc(dstAlpha, context->getClientMajorVersion())) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidBlendFunction); + return false; + } + + if (context->getLimitations().noSimultaneousConstantColorAndAlphaBlendFunc || + context->getExtensions().webglCompatibility) + { + bool constantColorUsed = + (srcRGB == GL_CONSTANT_COLOR || srcRGB == GL_ONE_MINUS_CONSTANT_COLOR || + dstRGB == GL_CONSTANT_COLOR || dstRGB == GL_ONE_MINUS_CONSTANT_COLOR); + + bool constantAlphaUsed = + (srcRGB == GL_CONSTANT_ALPHA || srcRGB == GL_ONE_MINUS_CONSTANT_ALPHA || + dstRGB == GL_CONSTANT_ALPHA || dstRGB == GL_ONE_MINUS_CONSTANT_ALPHA); + + if (constantColorUsed && constantAlphaUsed) { - 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) + const char *msg; + if (context->getExtensions().webglCompatibility) { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; + msg = kErrorInvalidConstantColor; } else { - context->recordError(Error(GL_INVALID_ENUM)); - return false; + msg = + "Simultaneous use of GL_CONSTANT_ALPHA/GL_ONE_MINUS_CONSTANT_ALPHA and " + "GL_CONSTANT_COLOR/GL_ONE_MINUS_CONSTANT_COLOR not supported by this " + "implementation."; + ERR() << msg; } + context->handleError(InvalidOperation() << msg); + return false; + } + } + + return true; +} + +bool ValidateGetString(Context *context, GLenum name) +{ + switch (name) + { + case GL_VENDOR: + case GL_RENDERER: + case GL_VERSION: + case GL_SHADING_LANGUAGE_VERSION: + case GL_EXTENSIONS: break; - case GL_ETC1_RGB8_OES: - if (context->getExtensions().compressedETC1RGB8Texture) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - else + + case GL_REQUESTABLE_EXTENSIONS_ANGLE: + if (!context->getExtensions().requestExtension) { - context->recordError(Error(GL_INVALID_ENUM)); + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidName); return false; } break; - case GL_ETC1_RGB8_LOSSY_DECODE_ANGLE: - if (context->getExtensions().lossyETCDecode) - { - context->recordError(Error(GL_INVALID_OPERATION, - "ETC1_RGB8_LOSSY_DECODE_ANGLE can't be copied to.")); - return false; - } - else - { - context->recordError( - Error(GL_INVALID_ENUM, "ANGLE_lossy_etc_decode extension is not supported.")); - 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)); + + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidName); return false; - } } - // If width or height is zero, it is a no-op. Return false without setting an error. - return (width > 0 && height > 0); + return true; } -bool ValidateES2TexStorageParameters(Context *context, GLenum target, GLsizei levels, GLenum internalformat, - GLsizei width, GLsizei height) +bool ValidateLineWidth(ValidationContext *context, GLfloat width) { - if (target != GL_TEXTURE_2D && target != GL_TEXTURE_CUBE_MAP) + if (width <= 0.0f || isNaN(width)) { - context->recordError(Error(GL_INVALID_ENUM)); + ANGLE_VALIDATION_ERR(context, InvalidValue(), InvalidWidth); return false; } - if (width < 1 || height < 1 || levels < 1) + return true; +} + +bool ValidateVertexAttribPointer(ValidationContext *context, + GLuint index, + GLint size, + GLenum type, + GLboolean normalized, + GLsizei stride, + const void *ptr) +{ + if (!ValidateVertexFormatBase(context, index, size, type, false)) { - context->recordError(Error(GL_INVALID_VALUE)); return false; } - if (target == GL_TEXTURE_CUBE_MAP && width != height) + if (stride < 0) { - context->recordError(Error(GL_INVALID_VALUE)); + ANGLE_VALIDATION_ERR(context, InvalidValue(), NegativeStride); return false; } - if (levels != 1 && levels != gl::log2(std::max(width, height)) + 1) + const Caps &caps = context->getCaps(); + if (context->getClientVersion() >= ES_3_1) { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; + if (stride > caps.maxVertexAttribStride) + { + context->handleError(InvalidValue() + << "stride cannot be greater than MAX_VERTEX_ATTRIB_STRIDE."); + return false; + } + + if (index >= caps.maxVertexAttribBindings) + { + context->handleError(InvalidValue() + << "index must be smaller than MAX_VERTEX_ATTRIB_BINDINGS."); + return false; + } } - const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat); - if (formatInfo.format == GL_NONE || formatInfo.type == GL_NONE) + // [OpenGL ES 3.0.2] Section 2.8 page 24: + // An INVALID_OPERATION error is generated when a non-zero vertex array object + // is bound, zero is bound to the ARRAY_BUFFER buffer object binding point, + // and the pointer argument is not NULL. + bool nullBufferAllowed = context->getGLState().areClientArraysEnabled() && + context->getGLState().getVertexArray()->id() == 0; + if (!nullBufferAllowed && context->getGLState().getTargetBuffer(BufferBinding::Array) == 0 && + ptr != nullptr) { - context->recordError(Error(GL_INVALID_ENUM)); + context + ->handleError(InvalidOperation() + << "Client data cannot be used with a non-default vertex array object."); return false; } - const gl::Caps &caps = context->getCaps(); - - switch (target) + if (context->getExtensions().webglCompatibility) { - case GL_TEXTURE_2D: - if (static_cast(width) > caps.max2DTextureSize || - static_cast(height) > caps.max2DTextureSize) + // WebGL 1.0 [Section 6.14] Fixed point support + // The WebGL API does not support the GL_FIXED data type. + if (type == GL_FIXED) { - context->recordError(Error(GL_INVALID_VALUE)); + context->handleError(InvalidEnum() << "GL_FIXED is not supported in WebGL."); return false; } - break; - case GL_TEXTURE_CUBE_MAP: - if (static_cast(width) > caps.maxCubeMapTextureSize || - static_cast(height) > caps.maxCubeMapTextureSize) + + if (!ValidateWebGLVertexAttribPointer(context, type, normalized, stride, ptr, false)) { - context->recordError(Error(GL_INVALID_VALUE)); return false; } - break; - default: - context->recordError(Error(GL_INVALID_ENUM)); + } + + return true; +} + +bool ValidateDepthRangef(ValidationContext *context, GLfloat zNear, GLfloat zFar) +{ + if (context->getExtensions().webglCompatibility && zNear > zFar) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), InvalidDepthRange); return false; } - if (levels != 1 && !context->getExtensions().textureNPOT) + return true; +} + +bool ValidateRenderbufferStorage(ValidationContext *context, + GLenum target, + GLenum internalformat, + GLsizei width, + GLsizei height) +{ + return ValidateRenderbufferStorageParametersBase(context, target, 0, internalformat, width, + height); +} + +bool ValidateRenderbufferStorageMultisampleANGLE(ValidationContext *context, + GLenum target, + GLsizei samples, + GLenum internalformat, + GLsizei width, + GLsizei height) +{ + if (!context->getExtensions().framebufferMultisample) { - if (!gl::isPow2(width) || !gl::isPow2(height)) + context->handleError(InvalidOperation() + << "GL_ANGLE_framebuffer_multisample not available"); + return false; + } + + // ANGLE_framebuffer_multisample states that the value of samples must be less than or equal + // to MAX_SAMPLES_ANGLE (Context::getCaps().maxSamples) otherwise GL_INVALID_OPERATION is + // generated. + if (static_cast(samples) > context->getCaps().maxSamples) + { + context->handleError(InvalidValue()); + 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. + // The TextureCaps::getMaxSamples method is only guarenteed to be valid when the context is ES3. + if (context->getClientMajorVersion() >= 3) + { + const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat); + if (static_cast(samples) > formatCaps.getMaxSamples()) { - context->recordError(Error(GL_INVALID_OPERATION)); + context->handleError(OutOfMemory()); return false; } } - switch (internalformat) + return ValidateRenderbufferStorageParametersBase(context, target, samples, internalformat, + width, height); +} + +bool ValidateCheckFramebufferStatus(ValidationContext *context, GLenum target) +{ + if (!ValidFramebufferTarget(context, target)) { - case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: - case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: - if (!context->getExtensions().textureCompressionDXT1) - { - context->recordError(Error(GL_INVALID_ENUM)); + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidFramebufferTarget); + return false; + } + + return true; +} + +bool ValidateClearColor(ValidationContext *context, + GLfloat red, + GLfloat green, + GLfloat blue, + GLfloat alpha) +{ + return true; +} + +bool ValidateClearDepthf(ValidationContext *context, GLfloat depth) +{ + return true; +} + +bool ValidateClearStencil(ValidationContext *context, GLint s) +{ + return true; +} + +bool ValidateColorMask(ValidationContext *context, + GLboolean red, + GLboolean green, + GLboolean blue, + GLboolean alpha) +{ + return true; +} + +bool ValidateCompileShader(ValidationContext *context, GLuint shader) +{ + return true; +} + +bool ValidateCreateProgram(ValidationContext *context) +{ + return true; +} + +bool ValidateCullFace(ValidationContext *context, CullFaceMode mode) +{ + switch (mode) + { + case CullFaceMode::Front: + case CullFaceMode::Back: + case CullFaceMode::FrontAndBack: + break; + + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidCullMode); return false; - } - break; - case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: - if (!context->getExtensions().textureCompressionDXT3) + } + + return true; +} + +bool ValidateDeleteProgram(ValidationContext *context, GLuint program) +{ + if (program == 0) + { + return false; + } + + if (!context->getProgram(program)) + { + if (context->getShader(program)) { - context->recordError(Error(GL_INVALID_ENUM)); + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ExpectedProgramName); return false; } - break; - case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: - if (!context->getExtensions().textureCompressionDXT5) + else { - context->recordError(Error(GL_INVALID_ENUM)); + ANGLE_VALIDATION_ERR(context, InvalidValue(), InvalidProgramName); return false; } - break; - case GL_ETC1_RGB8_OES: - if (!context->getExtensions().compressedETC1RGB8Texture) + } + + return true; +} + +bool ValidateDeleteShader(ValidationContext *context, GLuint shader) +{ + if (shader == 0) + { + return false; + } + + if (!context->getShader(shader)) + { + if (context->getProgram(shader)) { - context->recordError(Error(GL_INVALID_ENUM)); + ANGLE_VALIDATION_ERR(context, InvalidOperation(), InvalidShaderName); return false; } - break; - case GL_ETC1_RGB8_LOSSY_DECODE_ANGLE: - if (!context->getExtensions().lossyETCDecode) - { - context->recordError( - Error(GL_INVALID_ENUM, "ANGLE_lossy_etc_decode extension is not supported.")); - 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) + else { - context->recordError(Error(GL_INVALID_ENUM)); + ANGLE_VALIDATION_ERR(context, InvalidValue(), ExpectedShaderName); 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 true; +} + +bool ValidateDepthFunc(ValidationContext *context, GLenum func) +{ + switch (func) + { + case GL_NEVER: + case GL_ALWAYS: + case GL_LESS: + case GL_LEQUAL: + case GL_EQUAL: + case GL_GREATER: + case GL_GEQUAL: + case GL_NOTEQUAL: + break; + + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), EnumNotSupported); 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) + } + + return true; +} + +bool ValidateDepthMask(ValidationContext *context, GLboolean flag) +{ + return true; +} + +bool ValidateDetachShader(ValidationContext *context, GLuint program, GLuint shader) +{ + Program *programObject = GetValidProgram(context, program); + if (!programObject) + { + return false; + } + + Shader *shaderObject = GetValidShader(context, shader); + if (!shaderObject) + { + return false; + } + + const Shader *attachedShader = nullptr; + + switch (shaderObject->getType()) + { + case GL_VERTEX_SHADER: { - context->recordError(Error(GL_INVALID_ENUM)); - return false; + attachedShader = programObject->getAttachedVertexShader(); + break; } - break; - case GL_DEPTH_COMPONENT16: - case GL_DEPTH_COMPONENT32_OES: - case GL_DEPTH24_STENCIL8_OES: - if (!context->getExtensions().depthTextures) + case GL_FRAGMENT_SHADER: { - context->recordError(Error(GL_INVALID_ENUM)); - return false; + attachedShader = programObject->getAttachedFragmentShader(); + break; } - if (target != GL_TEXTURE_2D) + case GL_COMPUTE_SHADER: { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; + attachedShader = programObject->getAttachedComputeShader(); + break; } - // ANGLE_depth_texture only supports 1-level textures - if (levels != 1) + case GL_GEOMETRY_SHADER_EXT: { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; + attachedShader = programObject->getAttachedGeometryShader(); + break; } - break; - default: - break; + default: + UNREACHABLE(); + return false; + } + + if (attachedShader != shaderObject) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ShaderToDetachMustBeAttached); + return false; + } + + return true; +} + +bool ValidateDisableVertexAttribArray(ValidationContext *context, GLuint index) +{ + if (index >= MAX_VERTEX_ATTRIBS) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), IndexExceedsMaxVertexAttribute); + return false; + } + + return true; +} + +bool ValidateEnableVertexAttribArray(ValidationContext *context, GLuint index) +{ + if (index >= MAX_VERTEX_ATTRIBS) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), IndexExceedsMaxVertexAttribute); + return false; + } + + return true; +} + +bool ValidateFinish(ValidationContext *context) +{ + return true; +} + +bool ValidateFlush(ValidationContext *context) +{ + return true; +} + +bool ValidateFrontFace(ValidationContext *context, GLenum mode) +{ + switch (mode) + { + case GL_CW: + case GL_CCW: + break; + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), EnumNotSupported); + return false; + } + + return true; +} + +bool ValidateGetActiveAttrib(ValidationContext *context, + GLuint program, + GLuint index, + GLsizei bufsize, + GLsizei *length, + GLint *size, + GLenum *type, + GLchar *name) +{ + if (bufsize < 0) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), NegativeBufferSize); + return false; + } + + Program *programObject = GetValidProgram(context, program); + + if (!programObject) + { + return false; + } + + if (index >= static_cast(programObject->getActiveAttributeCount())) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), IndexExceedsMaxActiveUniform); + return false; + } + + return true; +} + +bool ValidateGetActiveUniform(ValidationContext *context, + GLuint program, + GLuint index, + GLsizei bufsize, + GLsizei *length, + GLint *size, + GLenum *type, + GLchar *name) +{ + if (bufsize < 0) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), NegativeBufferSize); + return false; + } + + Program *programObject = GetValidProgram(context, program); + + if (!programObject) + { + return false; + } + + if (index >= static_cast(programObject->getActiveUniformCount())) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), IndexExceedsMaxActiveUniform); + return false; + } + + return true; +} + +bool ValidateGetAttachedShaders(ValidationContext *context, + GLuint program, + GLsizei maxcount, + GLsizei *count, + GLuint *shaders) +{ + if (maxcount < 0) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), NegativeMaxCount); + return false; + } + + Program *programObject = GetValidProgram(context, program); + + if (!programObject) + { + return false; + } + + return true; +} + +bool ValidateGetAttribLocation(ValidationContext *context, GLuint program, const GLchar *name) +{ + // The WebGL spec (section 6.20) disallows strings containing invalid ESSL characters for + // shader-related entry points + if (context->getExtensions().webglCompatibility && !IsValidESSLString(name, strlen(name))) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), InvalidNameCharacters); + return false; } - gl::Texture *texture = context->getTargetTexture(target); - if (!texture || texture->id() == 0) + Program *programObject = GetValidProgram(context, program); + + if (!programObject) { - context->recordError(Error(GL_INVALID_OPERATION)); + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ProgramNotBound); return false; } - if (texture->getImmutableFormat()) + if (!programObject->isLinked()) { - context->recordError(Error(GL_INVALID_OPERATION)); + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ProgramNotLinked); return false; } return true; } -// check for combinations of format and type that are valid for ReadPixels -bool ValidES2ReadFormatType(Context *context, GLenum format, GLenum type) +bool ValidateGetBooleanv(ValidationContext *context, GLenum pname, GLboolean *params) { - 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; + GLenum nativeType; + unsigned int numParams = 0; + return ValidateStateQuery(context, pname, &nativeType, &numParams); +} - default: - return false; - } +bool ValidateGetError(ValidationContext *context) +{ return true; } -bool ValidateDiscardFramebufferEXT(Context *context, GLenum target, GLsizei numAttachments, - const GLenum *attachments) +bool ValidateGetFloatv(ValidationContext *context, GLenum pname, GLfloat *params) { - if (!context->getExtensions().discardFramebuffer) + GLenum nativeType; + unsigned int numParams = 0; + return ValidateStateQuery(context, pname, &nativeType, &numParams); +} + +bool ValidateGetIntegerv(ValidationContext *context, GLenum pname, GLint *params) +{ + GLenum nativeType; + unsigned int numParams = 0; + return ValidateStateQuery(context, pname, &nativeType, &numParams); +} + +bool ValidateGetProgramInfoLog(ValidationContext *context, + GLuint program, + GLsizei bufsize, + GLsizei *length, + GLchar *infolog) +{ + if (bufsize < 0) { - context->recordError(Error(GL_INVALID_OPERATION, "Extension not enabled")); + ANGLE_VALIDATION_ERR(context, InvalidValue(), NegativeBufferSize); return false; } - bool defaultFramebuffer = false; - - switch (target) + Program *programObject = GetValidProgram(context, program); + if (!programObject) { - case GL_FRAMEBUFFER: - defaultFramebuffer = (context->getState().getTargetFramebuffer(GL_FRAMEBUFFER)->id() == 0); - break; - default: - context->recordError(Error(GL_INVALID_ENUM, "Invalid framebuffer target")); return false; } - return ValidateDiscardFramebufferBase(context, target, numAttachments, attachments, defaultFramebuffer); + return true; } -bool ValidateBindVertexArrayOES(Context *context, GLuint array) +bool ValidateGetShaderInfoLog(ValidationContext *context, + GLuint shader, + GLsizei bufsize, + GLsizei *length, + GLchar *infolog) { - if (!context->getExtensions().vertexArrayObject) + if (bufsize < 0) { - context->recordError(Error(GL_INVALID_OPERATION, "Extension not enabled")); + ANGLE_VALIDATION_ERR(context, InvalidValue(), NegativeBufferSize); return false; } - return ValidateBindVertexArrayBase(context, array); -} - -bool ValidateDeleteVertexArraysOES(Context *context, GLsizei n) -{ - if (!context->getExtensions().vertexArrayObject) + Shader *shaderObject = GetValidShader(context, shader); + if (!shaderObject) { - context->recordError(Error(GL_INVALID_OPERATION, "Extension not enabled")); return false; } - return ValidateDeleteVertexArraysBase(context, n); + return true; } -bool ValidateGenVertexArraysOES(Context *context, GLsizei n) +bool ValidateGetShaderPrecisionFormat(ValidationContext *context, + GLenum shadertype, + GLenum precisiontype, + GLint *range, + GLint *precision) { - if (!context->getExtensions().vertexArrayObject) + switch (shadertype) { - context->recordError(Error(GL_INVALID_OPERATION, "Extension not enabled")); - return false; + case GL_VERTEX_SHADER: + case GL_FRAGMENT_SHADER: + break; + case GL_COMPUTE_SHADER: + context->handleError(InvalidOperation() + << "compute shader precision not yet implemented."); + return false; + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidShaderType); + return false; + } + + switch (precisiontype) + { + case GL_LOW_FLOAT: + case GL_MEDIUM_FLOAT: + case GL_HIGH_FLOAT: + case GL_LOW_INT: + case GL_MEDIUM_INT: + case GL_HIGH_INT: + break; + + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidPrecision); + return false; } - return ValidateGenVertexArraysBase(context, n); + return true; } -bool ValidateIsVertexArrayOES(Context *context) +bool ValidateGetShaderSource(ValidationContext *context, + GLuint shader, + GLsizei bufsize, + GLsizei *length, + GLchar *source) { - if (!context->getExtensions().vertexArrayObject) + if (bufsize < 0) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), NegativeBufferSize); + return false; + } + + Shader *shaderObject = GetValidShader(context, shader); + if (!shaderObject) { - context->recordError(Error(GL_INVALID_OPERATION, "Extension not enabled")); return false; } return true; } -bool ValidateProgramBinaryOES(Context *context, - GLuint program, - GLenum binaryFormat, - const void *binary, - GLint length) +bool ValidateGetUniformLocation(ValidationContext *context, GLuint program, const GLchar *name) { - if (!context->getExtensions().getProgramBinary) + if (strstr(name, "gl_") == name) { - context->recordError(Error(GL_INVALID_OPERATION, "Extension not enabled")); return false; } - return ValidateProgramBinaryBase(context, program, binaryFormat, binary, length); -} + // The WebGL spec (section 6.20) disallows strings containing invalid ESSL characters for + // shader-related entry points + if (context->getExtensions().webglCompatibility && !IsValidESSLString(name, strlen(name))) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), InvalidNameCharacters); + return false; + } -bool ValidateGetProgramBinaryOES(Context *context, - GLuint program, - GLsizei bufSize, - GLsizei *length, - GLenum *binaryFormat, - void *binary) -{ - if (!context->getExtensions().getProgramBinary) + Program *programObject = GetValidProgram(context, program); + + if (!programObject) { - context->recordError(Error(GL_INVALID_OPERATION, "Extension not enabled")); return false; } - return ValidateGetProgramBinaryBase(context, program, bufSize, length, binaryFormat, binary); + if (!programObject->isLinked()) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ProgramNotLinked); + return false; + } + + return true; } -static bool ValidDebugSource(GLenum source, bool mustBeThirdPartyOrApplication) +bool ValidateHint(ValidationContext *context, GLenum target, GLenum mode) { - switch (source) + switch (mode) { - case GL_DEBUG_SOURCE_API: - case GL_DEBUG_SOURCE_SHADER_COMPILER: - case GL_DEBUG_SOURCE_WINDOW_SYSTEM: - case GL_DEBUG_SOURCE_OTHER: - // Only THIRD_PARTY and APPLICATION sources are allowed to be manually inserted - return !mustBeThirdPartyOrApplication; + case GL_FASTEST: + case GL_NICEST: + case GL_DONT_CARE: + break; - case GL_DEBUG_SOURCE_THIRD_PARTY: - case GL_DEBUG_SOURCE_APPLICATION: - return true; + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), EnumNotSupported); + return false; + } + + switch (target) + { + case GL_GENERATE_MIPMAP_HINT: + break; + + case GL_FRAGMENT_SHADER_DERIVATIVE_HINT: + if (context->getClientVersion() < ES_3_0 && + !context->getExtensions().standardDerivatives) + { + context->handleError(InvalidEnum() << "hint requires OES_standard_derivatives."); + return false; + } + break; default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), EnumNotSupported); return false; } + + return true; } -static bool ValidDebugType(GLenum type) +bool ValidateIsBuffer(ValidationContext *context, GLuint buffer) { - switch (type) + return true; +} + +bool ValidateIsFramebuffer(ValidationContext *context, GLuint framebuffer) +{ + return true; +} + +bool ValidateIsProgram(ValidationContext *context, GLuint program) +{ + return true; +} + +bool ValidateIsRenderbuffer(ValidationContext *context, GLuint renderbuffer) +{ + return true; +} + +bool ValidateIsShader(ValidationContext *context, GLuint shader) +{ + return true; +} + +bool ValidateIsTexture(ValidationContext *context, GLuint texture) +{ + return true; +} + +bool ValidatePixelStorei(ValidationContext *context, GLenum pname, GLint param) +{ + if (context->getClientMajorVersion() < 3) { - case GL_DEBUG_TYPE_ERROR: - case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR: - case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR: - case GL_DEBUG_TYPE_PERFORMANCE: - case GL_DEBUG_TYPE_PORTABILITY: - case GL_DEBUG_TYPE_OTHER: - case GL_DEBUG_TYPE_MARKER: - case GL_DEBUG_TYPE_PUSH_GROUP: - case GL_DEBUG_TYPE_POP_GROUP: - return true; + switch (pname) + { + case GL_UNPACK_IMAGE_HEIGHT: + case GL_UNPACK_SKIP_IMAGES: + context->handleError(InvalidEnum()); + return false; + + case GL_UNPACK_ROW_LENGTH: + case GL_UNPACK_SKIP_ROWS: + case GL_UNPACK_SKIP_PIXELS: + if (!context->getExtensions().unpackSubimage) + { + context->handleError(InvalidEnum()); + return false; + } + break; + + case GL_PACK_ROW_LENGTH: + case GL_PACK_SKIP_ROWS: + case GL_PACK_SKIP_PIXELS: + if (!context->getExtensions().packSubimage) + { + context->handleError(InvalidEnum()); + return false; + } + break; + } + } + + if (param < 0) + { + context->handleError(InvalidValue() << "Cannot use negative values in PixelStorei"); + return false; + } + + switch (pname) + { + case GL_UNPACK_ALIGNMENT: + if (param != 1 && param != 2 && param != 4 && param != 8) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), InvalidUnpackAlignment); + return false; + } + break; + + case GL_PACK_ALIGNMENT: + if (param != 1 && param != 2 && param != 4 && param != 8) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), InvalidUnpackAlignment); + return false; + } + break; + + case GL_PACK_REVERSE_ROW_ORDER_ANGLE: + if (!context->getExtensions().packReverseRowOrder) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), EnumNotSupported); + } + break; + + case GL_UNPACK_ROW_LENGTH: + case GL_UNPACK_IMAGE_HEIGHT: + case GL_UNPACK_SKIP_IMAGES: + case GL_UNPACK_SKIP_ROWS: + case GL_UNPACK_SKIP_PIXELS: + case GL_PACK_ROW_LENGTH: + case GL_PACK_SKIP_ROWS: + case GL_PACK_SKIP_PIXELS: + break; default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), EnumNotSupported); return false; } + + return true; } -static bool ValidDebugSeverity(GLenum severity) +bool ValidatePolygonOffset(ValidationContext *context, GLfloat factor, GLfloat units) { - switch (severity) + return true; +} + +bool ValidateReleaseShaderCompiler(ValidationContext *context) +{ + return true; +} + +bool ValidateSampleCoverage(ValidationContext *context, GLfloat value, GLboolean invert) +{ + return true; +} + +bool ValidateScissor(ValidationContext *context, GLint x, GLint y, GLsizei width, GLsizei height) +{ + if (width < 0 || height < 0) { - case GL_DEBUG_SEVERITY_HIGH: - case GL_DEBUG_SEVERITY_MEDIUM: - case GL_DEBUG_SEVERITY_LOW: - case GL_DEBUG_SEVERITY_NOTIFICATION: - return true; + ANGLE_VALIDATION_ERR(context, InvalidValue(), NegativeSize); + return false; + } - default: - return false; + return true; +} + +bool ValidateShaderBinary(ValidationContext *context, + GLsizei n, + const GLuint *shaders, + GLenum binaryformat, + const void *binary, + GLsizei length) +{ + const std::vector &shaderBinaryFormats = context->getCaps().shaderBinaryFormats; + if (std::find(shaderBinaryFormats.begin(), shaderBinaryFormats.end(), binaryformat) == + shaderBinaryFormats.end()) + { + context->handleError(InvalidEnum() << "Invalid shader binary format."); + return false; } + + return true; } -bool ValidateDebugMessageControlKHR(Context *context, - GLenum source, - GLenum type, - GLenum severity, - GLsizei count, - const GLuint *ids, - GLboolean enabled) +bool ValidateShaderSource(ValidationContext *context, + GLuint shader, + GLsizei count, + const GLchar *const *string, + const GLint *length) { - if (!context->getExtensions().debug) + if (count < 0) { - context->recordError(Error(GL_INVALID_OPERATION, "Extension not enabled")); + ANGLE_VALIDATION_ERR(context, InvalidValue(), NegativeCount); return false; } - if (!ValidDebugSource(source, false) && source != GL_DONT_CARE) + // The WebGL spec (section 6.20) disallows strings containing invalid ESSL characters for + // shader-related entry points + if (context->getExtensions().webglCompatibility) + { + for (GLsizei i = 0; i < count; i++) + { + size_t len = + (length && length[i] >= 0) ? static_cast(length[i]) : strlen(string[i]); + + // Backslash as line-continuation is allowed in WebGL 2.0. + if (!IsValidESSLShaderSourceString(string[i], len, + context->getClientVersion() >= ES_3_0)) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), ShaderSourceInvalidCharacters); + return false; + } + } + } + + Shader *shaderObject = GetValidShader(context, shader); + if (!shaderObject) + { + return false; + } + + return true; +} + +bool ValidateStencilFunc(ValidationContext *context, GLenum func, GLint ref, GLuint mask) +{ + if (!IsValidStencilFunc(func)) { - context->recordError(Error(GL_INVALID_ENUM, "Invalid debug source.")); + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidStencil); return false; } - if (!ValidDebugType(type) && type != GL_DONT_CARE) + return true; +} + +bool ValidateStencilFuncSeparate(ValidationContext *context, + GLenum face, + GLenum func, + GLint ref, + GLuint mask) +{ + if (!IsValidStencilFace(face)) { - context->recordError(Error(GL_INVALID_ENUM, "Invalid debug type.")); + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidStencil); return false; } - if (!ValidDebugSeverity(severity) && severity != GL_DONT_CARE) + if (!IsValidStencilFunc(func)) { - context->recordError(Error(GL_INVALID_ENUM, "Invalid debug severity.")); + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidStencil); return false; } - if (count > 0) - { - if (source == GL_DONT_CARE || type == GL_DONT_CARE) - { - context->recordError(Error( - GL_INVALID_OPERATION, - "If count is greater than zero, source and severity cannot be GL_DONT_CARE.")); - return false; - } - - if (severity != GL_DONT_CARE) - { - context->recordError( - Error(GL_INVALID_OPERATION, - "If count is greater than zero, severity must be GL_DONT_CARE.")); - return false; - } - } + return true; +} +bool ValidateStencilMask(ValidationContext *context, GLuint mask) +{ return true; } -bool ValidateDebugMessageInsertKHR(Context *context, - GLenum source, - GLenum type, - GLuint id, - GLenum severity, - GLsizei length, - const GLchar *buf) +bool ValidateStencilMaskSeparate(ValidationContext *context, GLenum face, GLuint mask) { - if (!context->getExtensions().debug) + if (!IsValidStencilFace(face)) { - context->recordError(Error(GL_INVALID_OPERATION, "Extension not enabled")); + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidStencil); return false; } - if (!context->getState().getDebug().isOutputEnabled()) + return true; +} + +bool ValidateStencilOp(ValidationContext *context, GLenum fail, GLenum zfail, GLenum zpass) +{ + if (!IsValidStencilOp(fail)) { - // If the DEBUG_OUTPUT state is disabled calls to DebugMessageInsert are discarded and do - // not generate an error. + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidStencil); return false; } - if (!ValidDebugSeverity(severity)) + if (!IsValidStencilOp(zfail)) { - context->recordError(Error(GL_INVALID_ENUM, "Invalid debug severity.")); + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidStencil); return false; } - if (!ValidDebugType(type)) + if (!IsValidStencilOp(zpass)) { - context->recordError(Error(GL_INVALID_ENUM, "Invalid debug type.")); + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidStencil); return false; } - if (!ValidDebugSource(source, true)) + return true; +} + +bool ValidateStencilOpSeparate(ValidationContext *context, + GLenum face, + GLenum fail, + GLenum zfail, + GLenum zpass) +{ + if (!IsValidStencilFace(face)) { - context->recordError(Error(GL_INVALID_ENUM, "Invalid debug source.")); + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidStencil); return false; } - size_t messageLength = (length < 0) ? strlen(buf) : length; - if (messageLength > context->getExtensions().maxDebugMessageLength) + return ValidateStencilOp(context, fail, zfail, zpass); +} + +bool ValidateUniform1f(ValidationContext *context, GLint location, GLfloat x) +{ + return ValidateUniform(context, GL_FLOAT, location, 1); +} + +bool ValidateUniform1fv(ValidationContext *context, GLint location, GLsizei count, const GLfloat *v) +{ + return ValidateUniform(context, GL_FLOAT, location, count); +} + +bool ValidateUniform1i(ValidationContext *context, GLint location, GLint x) +{ + return ValidateUniform1iv(context, location, 1, &x); +} + +bool ValidateUniform2f(ValidationContext *context, GLint location, GLfloat x, GLfloat y) +{ + return ValidateUniform(context, GL_FLOAT_VEC2, location, 1); +} + +bool ValidateUniform2fv(ValidationContext *context, GLint location, GLsizei count, const GLfloat *v) +{ + return ValidateUniform(context, GL_FLOAT_VEC2, location, count); +} + +bool ValidateUniform2i(ValidationContext *context, GLint location, GLint x, GLint y) +{ + return ValidateUniform(context, GL_INT_VEC2, location, 1); +} + +bool ValidateUniform2iv(ValidationContext *context, GLint location, GLsizei count, const GLint *v) +{ + return ValidateUniform(context, GL_INT_VEC2, location, count); +} + +bool ValidateUniform3f(ValidationContext *context, GLint location, GLfloat x, GLfloat y, GLfloat z) +{ + return ValidateUniform(context, GL_FLOAT_VEC3, location, 1); +} + +bool ValidateUniform3fv(ValidationContext *context, GLint location, GLsizei count, const GLfloat *v) +{ + return ValidateUniform(context, GL_FLOAT_VEC3, location, count); +} + +bool ValidateUniform3i(ValidationContext *context, GLint location, GLint x, GLint y, GLint z) +{ + return ValidateUniform(context, GL_INT_VEC3, location, 1); +} + +bool ValidateUniform3iv(ValidationContext *context, GLint location, GLsizei count, const GLint *v) +{ + return ValidateUniform(context, GL_INT_VEC3, location, count); +} + +bool ValidateUniform4f(ValidationContext *context, + GLint location, + GLfloat x, + GLfloat y, + GLfloat z, + GLfloat w) +{ + return ValidateUniform(context, GL_FLOAT_VEC4, location, 1); +} + +bool ValidateUniform4fv(ValidationContext *context, GLint location, GLsizei count, const GLfloat *v) +{ + return ValidateUniform(context, GL_FLOAT_VEC4, location, count); +} + +bool ValidateUniform4i(ValidationContext *context, + GLint location, + GLint x, + GLint y, + GLint z, + GLint w) +{ + return ValidateUniform(context, GL_INT_VEC4, location, 1); +} + +bool ValidateUniform4iv(ValidationContext *context, GLint location, GLsizei count, const GLint *v) +{ + return ValidateUniform(context, GL_INT_VEC4, location, count); +} + +bool ValidateUniformMatrix2fv(ValidationContext *context, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + return ValidateUniformMatrix(context, GL_FLOAT_MAT2, location, count, transpose); +} + +bool ValidateUniformMatrix3fv(ValidationContext *context, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + return ValidateUniformMatrix(context, GL_FLOAT_MAT3, location, count, transpose); +} + +bool ValidateUniformMatrix4fv(ValidationContext *context, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + return ValidateUniformMatrix(context, GL_FLOAT_MAT4, location, count, transpose); +} + +bool ValidateValidateProgram(ValidationContext *context, GLuint program) +{ + Program *programObject = GetValidProgram(context, program); + + if (!programObject) { - context->recordError( - Error(GL_INVALID_VALUE, "Message length is larger than GL_MAX_DEBUG_MESSAGE_LENGTH.")); return false; } return true; } -bool ValidateDebugMessageCallbackKHR(Context *context, - GLDEBUGPROCKHR callback, - const void *userParam) +bool ValidateVertexAttrib1f(ValidationContext *context, GLuint index, GLfloat x) { - if (!context->getExtensions().debug) + return ValidateVertexAttribIndex(context, index); +} + +bool ValidateVertexAttrib1fv(ValidationContext *context, GLuint index, const GLfloat *values) +{ + return ValidateVertexAttribIndex(context, index); +} + +bool ValidateVertexAttrib2f(ValidationContext *context, GLuint index, GLfloat x, GLfloat y) +{ + return ValidateVertexAttribIndex(context, index); +} + +bool ValidateVertexAttrib2fv(ValidationContext *context, GLuint index, const GLfloat *values) +{ + return ValidateVertexAttribIndex(context, index); +} + +bool ValidateVertexAttrib3f(ValidationContext *context, + GLuint index, + GLfloat x, + GLfloat y, + GLfloat z) +{ + return ValidateVertexAttribIndex(context, index); +} + +bool ValidateVertexAttrib3fv(ValidationContext *context, GLuint index, const GLfloat *values) +{ + return ValidateVertexAttribIndex(context, index); +} + +bool ValidateVertexAttrib4f(ValidationContext *context, + GLuint index, + GLfloat x, + GLfloat y, + GLfloat z, + GLfloat w) +{ + return ValidateVertexAttribIndex(context, index); +} + +bool ValidateVertexAttrib4fv(ValidationContext *context, GLuint index, const GLfloat *values) +{ + return ValidateVertexAttribIndex(context, index); +} + +bool ValidateViewport(ValidationContext *context, GLint x, GLint y, GLsizei width, GLsizei height) +{ + if (width < 0 || height < 0) { - context->recordError(Error(GL_INVALID_OPERATION, "Extension not enabled")); + ANGLE_VALIDATION_ERR(context, InvalidValue(), ViewportNegativeSize); return false; } return true; } -bool ValidateGetDebugMessageLogKHR(Context *context, - GLuint count, - GLsizei bufSize, - GLenum *sources, - GLenum *types, - GLuint *ids, - GLenum *severities, - GLsizei *lengths, - GLchar *messageLog) +bool ValidateDrawArrays(ValidationContext *context, GLenum mode, GLint first, GLsizei count) { - if (!context->getExtensions().debug) - { - context->recordError(Error(GL_INVALID_OPERATION, "Extension not enabled")); - return false; - } + return ValidateDrawArraysCommon(context, mode, first, count, 1); +} - if (bufSize < 0 && messageLog != nullptr) +bool ValidateDrawElements(ValidationContext *context, + GLenum mode, + GLsizei count, + GLenum type, + const void *indices) +{ + return ValidateDrawElementsCommon(context, mode, count, type, indices, 1); +} + +bool ValidateGetFramebufferAttachmentParameteriv(ValidationContext *context, + GLenum target, + GLenum attachment, + GLenum pname, + GLint *params) +{ + return ValidateGetFramebufferAttachmentParameterivBase(context, target, attachment, pname, + nullptr); +} + +bool ValidateGetProgramiv(ValidationContext *context, GLuint program, GLenum pname, GLint *params) +{ + return ValidateGetProgramivBase(context, program, pname, nullptr); +} + +bool ValidateCopyTexImage2D(ValidationContext *context, + GLenum target, + GLint level, + GLenum internalformat, + GLint x, + GLint y, + GLsizei width, + GLsizei height, + GLint border) +{ + if (context->getClientMajorVersion() < 3) { - context->recordError( - Error(GL_INVALID_VALUE, "bufSize must be positive if messageLog is not null.")); - return false; + return ValidateES2CopyTexImageParameters(context, target, level, internalformat, false, 0, + 0, x, y, width, height, border); } - return true; + ASSERT(context->getClientMajorVersion() == 3); + return ValidateES3CopyTexImage2DParameters(context, target, level, internalformat, false, 0, 0, + 0, x, y, width, height, border); } -bool ValidatePushDebugGroupKHR(Context *context, - GLenum source, - GLuint id, - GLsizei length, - const GLchar *message) +bool ValidateCopyTexSubImage2D(Context *context, + GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLint x, + GLint y, + GLsizei width, + GLsizei height) { - if (!context->getExtensions().debug) + if (context->getClientMajorVersion() < 3) { - context->recordError(Error(GL_INVALID_OPERATION, "Extension not enabled")); - return false; + return ValidateES2CopyTexImageParameters(context, target, level, GL_NONE, true, xoffset, + yoffset, x, y, width, height, 0); } - if (!ValidDebugSource(source, true)) + return ValidateES3CopyTexImage2DParameters(context, target, level, GL_NONE, true, xoffset, + yoffset, 0, x, y, width, height, 0); +} + +bool ValidateDeleteBuffers(Context *context, GLint n, const GLuint *) +{ + return ValidateGenOrDelete(context, n); +} + +bool ValidateDeleteFramebuffers(Context *context, GLint n, const GLuint *) +{ + return ValidateGenOrDelete(context, n); +} + +bool ValidateDeleteRenderbuffers(Context *context, GLint n, const GLuint *) +{ + return ValidateGenOrDelete(context, n); +} + +bool ValidateDeleteTextures(Context *context, GLint n, const GLuint *) +{ + return ValidateGenOrDelete(context, n); +} + +bool ValidateDisable(Context *context, GLenum cap) +{ + if (!ValidCap(context, cap, false)) { - context->recordError(Error(GL_INVALID_ENUM, "Invalid debug source.")); + ANGLE_VALIDATION_ERR(context, InvalidEnum(), EnumNotSupported); return false; } - size_t messageLength = (length < 0) ? strlen(message) : length; - if (messageLength > context->getExtensions().maxDebugMessageLength) + return true; +} + +bool ValidateEnable(Context *context, GLenum cap) +{ + if (!ValidCap(context, cap, false)) { - context->recordError( - Error(GL_INVALID_VALUE, "Message length is larger than GL_MAX_DEBUG_MESSAGE_LENGTH.")); + ANGLE_VALIDATION_ERR(context, InvalidEnum(), EnumNotSupported); return false; } - size_t currentStackSize = context->getState().getDebug().getGroupStackDepth(); - if (currentStackSize >= context->getExtensions().maxDebugGroupStackDepth) + if (context->getLimitations().noSampleAlphaToCoverageSupport && + cap == GL_SAMPLE_ALPHA_TO_COVERAGE) { - context->recordError( - Error(GL_STACK_OVERFLOW, - "Cannot push more than GL_MAX_DEBUG_GROUP_STACK_DEPTH debug groups.")); + const char *errorMessage = "Current renderer doesn't support alpha-to-coverage"; + context->handleError(InvalidOperation() << errorMessage); + + // We also output an error message to the debugger window if tracing is active, so that + // developers can see the error message. + ERR() << errorMessage; return false; } return true; } -bool ValidatePopDebugGroupKHR(Context *context) +bool ValidateFramebufferRenderbuffer(Context *context, + GLenum target, + GLenum attachment, + GLenum renderbuffertarget, + GLuint renderbuffer) { - if (!context->getExtensions().debug) + if (!ValidFramebufferTarget(context, target)) { - context->recordError(Error(GL_INVALID_OPERATION, "Extension not enabled")); + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidFramebufferTarget); return false; } - size_t currentStackSize = context->getState().getDebug().getGroupStackDepth(); - if (currentStackSize <= 1) + if (renderbuffertarget != GL_RENDERBUFFER && renderbuffer != 0) { - context->recordError(Error(GL_STACK_UNDERFLOW, "Cannot pop the default debug group.")); + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidRenderbufferTarget); return false; } - return true; + return ValidateFramebufferRenderbufferParameters(context, target, attachment, + renderbuffertarget, renderbuffer); } -static bool ValidateObjectIdentifierAndName(Context *context, GLenum identifier, GLuint name) +bool ValidateFramebufferTexture2D(Context *context, + GLenum target, + GLenum attachment, + GLenum textarget, + GLuint texture, + GLint level) { - switch (identifier) + // Attachments are required to be bound to level 0 without ES3 or the GL_OES_fbo_render_mipmap + // extension + if (context->getClientMajorVersion() < 3 && !context->getExtensions().fboRenderMipmap && + level != 0) { - case GL_BUFFER: - if (context->getBuffer(name) == nullptr) - { - context->recordError(Error(GL_INVALID_VALUE, "name is not a valid buffer.")); - return false; - } - return true; - - case GL_SHADER: - if (context->getShader(name) == nullptr) - { - context->recordError(Error(GL_INVALID_VALUE, "name is not a valid shader.")); - return false; - } - return true; + ANGLE_VALIDATION_ERR(context, InvalidValue(), InvalidFramebufferTextureLevel); + return false; + } - case GL_PROGRAM: - if (context->getProgram(name) == nullptr) - { - context->recordError(Error(GL_INVALID_VALUE, "name is not a valid program.")); - return false; - } - return true; + if (!ValidateFramebufferTextureBase(context, target, attachment, texture, level)) + { + return false; + } - case GL_VERTEX_ARRAY: - if (context->getVertexArray(name) == nullptr) - { - context->recordError(Error(GL_INVALID_VALUE, "name is not a valid vertex array.")); - return false; - } - return true; + if (texture != 0) + { + gl::Texture *tex = context->getTexture(texture); + ASSERT(tex); - case GL_QUERY: - if (context->getQuery(name) == nullptr) - { - context->recordError(Error(GL_INVALID_VALUE, "name is not a valid query.")); - return false; - } - return true; + const gl::Caps &caps = context->getCaps(); - case GL_TRANSFORM_FEEDBACK: - if (context->getTransformFeedback(name) == nullptr) + switch (textarget) + { + case GL_TEXTURE_2D: { - context->recordError( - Error(GL_INVALID_VALUE, "name is not a valid transform feedback.")); - return false; + if (level > gl::log2(caps.max2DTextureSize)) + { + context->handleError(InvalidValue()); + return false; + } + if (tex->getTarget() != GL_TEXTURE_2D) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), InvalidTextureTarget); + return false; + } } - return true; + break; - case GL_SAMPLER: - if (context->getSampler(name) == nullptr) + case GL_TEXTURE_RECTANGLE_ANGLE: { - context->recordError(Error(GL_INVALID_VALUE, "name is not a valid sampler.")); - return false; + if (level != 0) + { + context->handleError(InvalidValue()); + return false; + } + if (tex->getTarget() != GL_TEXTURE_RECTANGLE_ANGLE) + { + context->handleError(InvalidOperation() + << "Textarget must match the texture target type."); + return false; + } } - return true; + break; - case GL_TEXTURE: - if (context->getTexture(name) == nullptr) + 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: { - context->recordError(Error(GL_INVALID_VALUE, "name is not a valid texture.")); - return false; + if (level > gl::log2(caps.maxCubeMapTextureSize)) + { + context->handleError(InvalidValue()); + return false; + } + if (tex->getTarget() != GL_TEXTURE_CUBE_MAP) + { + context->handleError(InvalidOperation() + << "Textarget must match the texture target type."); + return false; + } } - return true; + break; - case GL_RENDERBUFFER: - if (context->getRenderbuffer(name) == nullptr) + case GL_TEXTURE_2D_MULTISAMPLE: { - context->recordError(Error(GL_INVALID_VALUE, "name is not a valid renderbuffer.")); - return false; + if (context->getClientVersion() < ES_3_1) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES31Required); + return false; + } + + if (level != 0) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), LevelNotZero); + return false; + } + if (tex->getTarget() != GL_TEXTURE_2D_MULTISAMPLE) + { + context->handleError(InvalidOperation() + << "Textarget must match the texture target type."); + return false; + } } - return true; + break; - case GL_FRAMEBUFFER: - if (context->getFramebuffer(name) == nullptr) - { - context->recordError(Error(GL_INVALID_VALUE, "name is not a valid framebuffer.")); + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidTextureTarget); return false; - } - return true; + } - default: - context->recordError(Error(GL_INVALID_ENUM, "Invalid identifier.")); + const Format &format = tex->getFormat(textarget, level); + if (format.info->compressed) + { + context->handleError(InvalidOperation()); return false; + } } return true; } -bool ValidateObjectLabelKHR(Context *context, - GLenum identifier, - GLuint name, - GLsizei length, - const GLchar *label) +bool ValidateGenBuffers(Context *context, GLint n, GLuint *) { - if (!context->getExtensions().debug) - { - context->recordError(Error(GL_INVALID_OPERATION, "Extension not enabled")); - return false; - } + return ValidateGenOrDelete(context, n); +} - if (!ValidateObjectIdentifierAndName(context, identifier, name)) +bool ValidateGenFramebuffers(Context *context, GLint n, GLuint *) +{ + return ValidateGenOrDelete(context, n); +} + +bool ValidateGenRenderbuffers(Context *context, GLint n, GLuint *) +{ + return ValidateGenOrDelete(context, n); +} + +bool ValidateGenTextures(Context *context, GLint n, GLuint *) +{ + return ValidateGenOrDelete(context, n); +} + +bool ValidateGenerateMipmap(Context *context, GLenum target) +{ + if (!ValidTextureTarget(context, target)) { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidTextureTarget); return false; } - size_t labelLength = (length < 0) ? strlen(label) : length; - if (labelLength > context->getExtensions().maxLabelLength) + Texture *texture = context->getTargetTexture(target); + + if (texture == nullptr) { - context->recordError( - Error(GL_INVALID_VALUE, "Label length is larger than GL_MAX_LABEL_LENGTH.")); + ANGLE_VALIDATION_ERR(context, InvalidOperation(), TextureNotBound); return false; } - return true; -} + const GLuint effectiveBaseLevel = texture->getTextureState().getEffectiveBaseLevel(); -bool ValidateGetObjectLabelKHR(Context *context, - GLenum identifier, - GLuint name, - GLsizei bufSize, - GLsizei *length, - GLchar *label) -{ - if (!context->getExtensions().debug) + // This error isn't spelled out in the spec in a very explicit way, but we interpret the spec so + // that out-of-range base level has a non-color-renderable / non-texture-filterable format. + if (effectiveBaseLevel >= gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) { - context->recordError(Error(GL_INVALID_OPERATION, "Extension not enabled")); + context->handleError(InvalidOperation()); return false; } - if (bufSize < 0) + GLenum baseTarget = (target == GL_TEXTURE_CUBE_MAP) ? GL_TEXTURE_CUBE_MAP_POSITIVE_X : target; + const auto &format = *(texture->getFormat(baseTarget, effectiveBaseLevel).info); + if (format.sizedInternalFormat == GL_NONE || format.compressed || format.depthBits > 0 || + format.stencilBits > 0) { - context->recordError(Error(GL_INVALID_VALUE, "bufSize cannot be negative.")); + ANGLE_VALIDATION_ERR(context, InvalidOperation(), GenerateMipmapNotAllowed); return false; } - if (!ValidateObjectIdentifierAndName(context, identifier, name)) + // GenerateMipmap accepts formats that are unsized or both color renderable and filterable. + bool formatUnsized = !format.sized; + bool formatColorRenderableAndFilterable = + format.filterSupport(context->getClientVersion(), context->getExtensions()) && + format.renderSupport(context->getClientVersion(), context->getExtensions()); + if (!formatUnsized && !formatColorRenderableAndFilterable) { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), GenerateMipmapNotAllowed); return false; } - // Can no-op if bufSize is zero. - return bufSize > 0; -} - -static bool ValidateObjectPtrName(Context *context, const void *ptr) -{ - if (context->getFenceSync(reinterpret_cast(const_cast(ptr))) == nullptr) + // GL_EXT_sRGB adds an unsized SRGB (no alpha) format which has explicitly disabled mipmap + // generation + if (format.colorEncoding == GL_SRGB && format.format == GL_RGB) { - context->recordError(Error(GL_INVALID_VALUE, "name is not a valid sync.")); + ANGLE_VALIDATION_ERR(context, InvalidOperation(), GenerateMipmapNotAllowed); return false; } - return true; -} - -bool ValidateObjectPtrLabelKHR(Context *context, - const void *ptr, - GLsizei length, - const GLchar *label) -{ - if (!context->getExtensions().debug) + // ES3 and WebGL grant mipmap generation for sRGBA (with alpha) textures but GL_EXT_sRGB does + // not. + bool supportsSRGBMipmapGeneration = + context->getClientVersion() >= ES_3_0 || context->getExtensions().webglCompatibility; + if (!supportsSRGBMipmapGeneration && format.colorEncoding == GL_SRGB) { - context->recordError(Error(GL_INVALID_OPERATION, "Extension not enabled")); + ANGLE_VALIDATION_ERR(context, InvalidOperation(), GenerateMipmapNotAllowed); return false; } - if (!ValidateObjectPtrName(context, ptr)) + // Non-power of 2 ES2 check + if (context->getClientVersion() < Version(3, 0) && !context->getExtensions().textureNPOT && + (!isPow2(static_cast(texture->getWidth(baseTarget, 0))) || + !isPow2(static_cast(texture->getHeight(baseTarget, 0))))) { + ASSERT(target == GL_TEXTURE_2D || target == GL_TEXTURE_RECTANGLE_ANGLE || + target == GL_TEXTURE_CUBE_MAP); + ANGLE_VALIDATION_ERR(context, InvalidOperation(), TextureNotPow2); return false; } - size_t labelLength = (length < 0) ? strlen(label) : length; - if (labelLength > context->getExtensions().maxLabelLength) + // Cube completeness check + if (target == GL_TEXTURE_CUBE_MAP && !texture->getTextureState().isCubeComplete()) { - context->recordError( - Error(GL_INVALID_VALUE, "Label length is larger than GL_MAX_LABEL_LENGTH.")); + ANGLE_VALIDATION_ERR(context, InvalidOperation(), CubemapIncomplete); return false; } return true; } -bool ValidateGetObjectPtrLabelKHR(Context *context, - const void *ptr, - GLsizei bufSize, - GLsizei *length, - GLchar *label) +bool ValidateGetBufferParameteriv(ValidationContext *context, + BufferBinding target, + GLenum pname, + GLint *params) { - if (!context->getExtensions().debug) - { - context->recordError(Error(GL_INVALID_OPERATION, "Extension not enabled")); - return false; - } + return ValidateGetBufferParameterBase(context, target, pname, false, nullptr); +} - if (bufSize < 0) - { - context->recordError(Error(GL_INVALID_VALUE, "bufSize cannot be negative.")); - return false; - } +bool ValidateGetRenderbufferParameteriv(Context *context, + GLenum target, + GLenum pname, + GLint *params) +{ + return ValidateGetRenderbufferParameterivBase(context, target, pname, nullptr); +} - if (!ValidateObjectPtrName(context, ptr)) - { - return false; - } +bool ValidateGetShaderiv(Context *context, GLuint shader, GLenum pname, GLint *params) +{ + return ValidateGetShaderivBase(context, shader, pname, nullptr); +} - // Can no-op if bufSize is zero. - return bufSize > 0; +bool ValidateGetTexParameterfv(Context *context, GLenum target, GLenum pname, GLfloat *params) +{ + return ValidateGetTexParameterBase(context, target, pname, nullptr); } -bool ValidateGetPointervKHR(Context *context, GLenum pname, void **params) +bool ValidateGetTexParameteriv(Context *context, GLenum target, GLenum pname, GLint *params) { - if (!context->getExtensions().debug) - { - context->recordError(Error(GL_INVALID_OPERATION, "Extension not enabled")); - return false; - } + return ValidateGetTexParameterBase(context, target, pname, nullptr); +} - // TODO: represent this in Context::getQueryParameterInfo. - switch (pname) - { - case GL_DEBUG_CALLBACK_FUNCTION: - case GL_DEBUG_CALLBACK_USER_PARAM: - break; +bool ValidateGetUniformfv(Context *context, GLuint program, GLint location, GLfloat *params) +{ + return ValidateGetUniformBase(context, program, location); +} - default: - context->recordError(Error(GL_INVALID_ENUM, "Invalid pname.")); - return false; - } +bool ValidateGetUniformiv(Context *context, GLuint program, GLint location, GLint *params) +{ + return ValidateGetUniformBase(context, program, location); +} - return true; +bool ValidateGetVertexAttribfv(Context *context, GLuint index, GLenum pname, GLfloat *params) +{ + return ValidateGetVertexAttribBase(context, index, pname, nullptr, false, false); } -bool ValidateBlitFramebufferANGLE(Context *context, - GLint srcX0, - GLint srcY0, - GLint srcX1, - GLint srcY1, - GLint dstX0, - GLint dstY0, - GLint dstX1, - GLint dstY1, - GLbitfield mask, - GLenum filter) +bool ValidateGetVertexAttribiv(Context *context, GLuint index, GLenum pname, GLint *params) { - if (!context->getExtensions().framebufferBlit) + return ValidateGetVertexAttribBase(context, index, pname, nullptr, false, false); +} + +bool ValidateGetVertexAttribPointerv(Context *context, GLuint index, GLenum pname, void **pointer) +{ + return ValidateGetVertexAttribBase(context, index, pname, nullptr, true, false); +} + +bool ValidateIsEnabled(Context *context, GLenum cap) +{ + if (!ValidCap(context, cap, true)) { - context->recordError(Error(GL_INVALID_OPERATION, "Blit extension not available.")); + ANGLE_VALIDATION_ERR(context, InvalidEnum(), EnumNotSupported); return false; } - if (srcX1 - srcX0 != dstX1 - dstX0 || srcY1 - srcY0 != dstY1 - dstY0) + return true; +} + +bool ValidateLinkProgram(Context *context, GLuint program) +{ + if (context->hasActiveTransformFeedback(program)) { - // TODO(jmadill): Determine if this should be available on other implementations. - context->recordError(Error( - GL_INVALID_OPERATION, - "Scaling and flipping in BlitFramebufferANGLE not supported by this implementation.")); + // ES 3.0.4 section 2.15 page 91 + context->handleError(InvalidOperation() << "Cannot link program while program is " + "associated with an active transform " + "feedback object."); return false; } - if (filter == GL_LINEAR) + Program *programObject = GetValidProgram(context, program); + if (!programObject) { - context->recordError(Error(GL_INVALID_ENUM, "Linear blit not supported in this extension")); return false; } - const Framebuffer *readFramebuffer = context->getState().getReadFramebuffer(); - const Framebuffer *drawFramebuffer = context->getState().getDrawFramebuffer(); + return true; +} - if (mask & GL_COLOR_BUFFER_BIT) - { - const FramebufferAttachment *readColorAttachment = readFramebuffer->getReadColorbuffer(); - const FramebufferAttachment *drawColorAttachment = drawFramebuffer->getFirstColorbuffer(); +bool ValidateReadPixels(Context *context, + GLint x, + GLint y, + GLsizei width, + GLsizei height, + GLenum format, + GLenum type, + void *pixels) +{ + return ValidateReadPixelsBase(context, x, y, width, height, format, type, -1, nullptr, nullptr, + nullptr, pixels); +} - if (readColorAttachment && drawColorAttachment) - { - if (!(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; - } +bool ValidateTexParameterf(Context *context, GLenum target, GLenum pname, GLfloat param) +{ + return ValidateTexParameterBase(context, target, pname, -1, ¶m); +} - for (size_t drawbufferIdx = 0; - drawbufferIdx < drawFramebuffer->getDrawbufferStateCount(); ++drawbufferIdx) - { - const FramebufferAttachment *attachment = - drawFramebuffer->getDrawBuffer(drawbufferIdx); - if (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; - } +bool ValidateTexParameterfv(Context *context, GLenum target, GLenum pname, const GLfloat *params) +{ + return ValidateTexParameterBase(context, target, pname, -1, params); +} - // Return an error if the destination formats do not match - if (attachment->getInternalFormat() != readColorAttachment->getInternalFormat()) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - } - } +bool ValidateTexParameteri(Context *context, GLenum target, GLenum pname, GLint param) +{ + return ValidateTexParameterBase(context, target, pname, -1, ¶m); +} - int readSamples = readFramebuffer->getSamples(context->getData()); +bool ValidateTexParameteriv(Context *context, GLenum target, GLenum pname, const GLint *params) +{ + return ValidateTexParameterBase(context, target, pname, -1, params); +} - if (readSamples != 0 && - IsPartialBlit(context, readColorAttachment, drawColorAttachment, srcX0, srcY0, - srcX1, srcY1, dstX0, dstY0, dstX1, dstY1)) +bool ValidateUseProgram(Context *context, GLuint program) +{ + if (program != 0) + { + Program *programObject = context->getProgram(program); + if (!programObject) + { + // ES 3.1.0 section 7.3 page 72 + if (context->getShader(program)) { - context->recordError(Error(GL_INVALID_OPERATION)); + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ExpectedProgramName); 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]) - { - const FramebufferAttachment *readBuffer = - readFramebuffer->getAttachment(attachments[i]); - const FramebufferAttachment *drawBuffer = - drawFramebuffer->getAttachment(attachments[i]); - - if (readBuffer && drawBuffer) + else { - if (IsPartialBlit(context, readBuffer, drawBuffer, srcX0, srcY0, srcX1, srcY1, - dstX0, dstY0, dstX1, dstY1)) - { - // only whole-buffer copies are permitted - ERR( - "Only whole-buffer depth and stencil blits are supported by this " - "implementation."); - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - - if (readBuffer->getSamples() != 0 || drawBuffer->getSamples() != 0) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } + ANGLE_VALIDATION_ERR(context, InvalidValue(), InvalidProgramName); + return false; } } + if (!programObject->isLinked()) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ProgramNotLinked); + return false; + } } - - return ValidateBlitFramebufferParameters(context, srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, - dstX1, dstY1, mask, filter); -} - -bool ValidateClear(ValidationContext *context, GLbitfield mask) -{ - const Framebuffer *framebufferObject = context->getState().getDrawFramebuffer(); - ASSERT(framebufferObject); - - if (framebufferObject->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE) - { - context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION)); - return false; - } - - if ((mask & ~(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)) != 0) + if (context->getGLState().isTransformFeedbackActiveUnpaused()) { - context->recordError(Error(GL_INVALID_VALUE)); + // ES 3.0.4 section 2.15 page 91 + context + ->handleError(InvalidOperation() + << "Cannot change active program while transform feedback is unpaused."); return false; } return true; } -bool ValidateDrawBuffersEXT(ValidationContext *context, GLsizei n, const GLenum *bufs) -{ - if (!context->getExtensions().drawBuffers) - { - context->recordError(Error(GL_INVALID_OPERATION, "Extension not supported.")); - return false; - } - - return ValidateDrawBuffersBase(context, n, bufs); -} - } // namespace gl diff --git a/src/3rdparty/angle/src/libANGLE/validationES2.h b/src/3rdparty/angle/src/libANGLE/validationES2.h index 1b2cf13f60..5dc09176a1 100644 --- a/src/3rdparty/angle/src/libANGLE/validationES2.h +++ b/src/3rdparty/angle/src/libANGLE/validationES2.h @@ -9,6 +9,8 @@ #ifndef LIBANGLE_VALIDATION_ES2_H_ #define LIBANGLE_VALIDATION_ES2_H_ +#include "libANGLE/PackedGLEnums.h" + #include #include @@ -17,37 +19,24 @@ namespace gl class Context; class ValidationContext; -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(ValidationContext *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); - -bool ValidateDiscardFramebufferEXT(Context *context, GLenum target, GLsizei numAttachments, +bool ValidateES2TexStorageParameters(Context *context, + GLenum target, + GLsizei levels, + GLenum internalformat, + GLsizei width, + GLsizei height); + +bool ValidateDiscardFramebufferEXT(Context *context, + GLenum target, + GLsizei numAttachments, const GLenum *attachments); bool ValidateDrawBuffersEXT(ValidationContext *context, GLsizei n, const GLenum *bufs); bool ValidateBindVertexArrayOES(Context *context, GLuint array); -bool ValidateDeleteVertexArraysOES(Context *context, GLsizei n); -bool ValidateGenVertexArraysOES(Context *context, GLsizei n); -bool ValidateIsVertexArrayOES(Context *context); +bool ValidateDeleteVertexArraysOES(Context *context, GLsizei n, const GLuint *arrays); +bool ValidateGenVertexArraysOES(Context *context, GLsizei n, GLuint *arrays); +bool ValidateIsVertexArrayOES(Context *context, GLuint array); bool ValidateProgramBinaryOES(Context *context, GLuint program, @@ -128,7 +117,571 @@ bool ValidateBlitFramebufferANGLE(Context *context, GLenum filter); bool ValidateClear(ValidationContext *context, GLbitfield mask); +bool ValidateTexImage2D(Context *context, + GLenum target, + GLint level, + GLint internalformat, + GLsizei width, + GLsizei height, + GLint border, + GLenum format, + GLenum type, + const void *pixels); +bool ValidateTexImage2DRobust(Context *context, + GLenum target, + GLint level, + GLint internalformat, + GLsizei width, + GLsizei height, + GLint border, + GLenum format, + GLenum type, + GLsizei bufSize, + const void *pixels); +bool ValidateTexSubImage2D(Context *context, + GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLsizei width, + GLsizei height, + GLenum format, + GLenum type, + const void *pixels); +bool ValidateTexSubImage2DRobustANGLE(Context *context, + GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLsizei width, + GLsizei height, + GLenum format, + GLenum type, + GLsizei bufSize, + const void *pixels); +bool ValidateCompressedTexImage2D(Context *context, + GLenum target, + GLint level, + GLenum internalformat, + GLsizei width, + GLsizei height, + GLint border, + GLsizei imageSize, + const void *data); +bool ValidateCompressedTexSubImage2D(Context *context, + GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLsizei width, + GLsizei height, + GLenum format, + GLsizei imageSize, + const void *data); +bool ValidateCompressedTexImage2DRobustANGLE(Context *context, + GLenum target, + GLint level, + GLenum internalformat, + GLsizei width, + GLsizei height, + GLint border, + GLsizei imageSize, + GLsizei dataSize, + const void *data); +bool ValidateCompressedTexSubImage2DRobustANGLE(Context *context, + GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLsizei width, + GLsizei height, + GLenum format, + GLsizei imageSize, + GLsizei dataSize, + const void *data); + +bool ValidateBindTexture(Context *context, GLenum target, GLuint texture); + +bool ValidateGetBufferPointervOES(Context *context, + BufferBinding target, + GLenum pname, + void **params); +bool ValidateMapBufferOES(Context *context, BufferBinding target, GLenum access); +bool ValidateUnmapBufferOES(Context *context, BufferBinding target); +bool ValidateMapBufferRangeEXT(Context *context, + BufferBinding target, + GLintptr offset, + GLsizeiptr length, + GLbitfield access); +bool ValidateMapBufferBase(Context *context, BufferBinding target); +bool ValidateFlushMappedBufferRangeEXT(Context *context, + BufferBinding target, + GLintptr offset, + GLsizeiptr length); + +bool ValidateBindUniformLocationCHROMIUM(Context *context, + GLuint program, + GLint location, + const GLchar *name); + +bool ValidateCoverageModulationCHROMIUM(Context *context, GLenum components); + +// CHROMIUM_path_rendering +bool ValidateMatrix(Context *context, GLenum matrixMode, const GLfloat *matrix); +bool ValidateMatrixMode(Context *context, GLenum matrixMode); +bool ValidateGenPaths(Context *context, GLsizei range); +bool ValidateDeletePaths(Context *context, GLuint first, GLsizei range); +bool ValidatePathCommands(Context *context, + GLuint path, + GLsizei numCommands, + const GLubyte *commands, + GLsizei numCoords, + GLenum coordType, + const void *coords); +bool ValidateSetPathParameter(Context *context, GLuint path, GLenum pname, GLfloat value); +bool ValidateGetPathParameter(Context *context, GLuint path, GLenum pname, GLfloat *value); +bool ValidatePathStencilFunc(Context *context, GLenum func, GLint ref, GLuint mask); +bool ValidateStencilFillPath(Context *context, GLuint path, GLenum fillMode, GLuint mask); +bool ValidateStencilStrokePath(Context *context, GLuint path, GLint reference, GLuint mask); +bool ValidateCoverPath(Context *context, GLuint path, GLenum coverMode); +bool ValidateStencilThenCoverFillPath(Context *context, + GLuint path, + GLenum fillMode, + GLuint mask, + GLenum coverMode); +bool ValidateStencilThenCoverStrokePath(Context *context, + GLuint path, + GLint reference, + GLuint mask, + GLenum coverMode); +bool ValidateIsPath(Context *context); +bool ValidateCoverFillPathInstanced(Context *context, + GLsizei numPaths, + GLenum pathNameType, + const void *paths, + GLuint pathBase, + GLenum coverMode, + GLenum transformType, + const GLfloat *transformValues); +bool ValidateCoverStrokePathInstanced(Context *context, + GLsizei numPaths, + GLenum pathNameType, + const void *paths, + GLuint pathBase, + GLenum coverMode, + GLenum transformType, + const GLfloat *transformValues); +bool ValidateStencilFillPathInstanced(Context *context, + GLsizei numPaths, + GLenum pathNameType, + const void *paths, + GLuint pathBAse, + GLenum fillMode, + GLuint mask, + GLenum transformType, + const GLfloat *transformValues); +bool ValidateStencilStrokePathInstanced(Context *context, + GLsizei numPaths, + GLenum pathNameType, + const void *paths, + GLuint pathBase, + GLint reference, + GLuint mask, + GLenum transformType, + const GLfloat *transformValues); +bool ValidateStencilThenCoverFillPathInstanced(Context *context, + GLsizei numPaths, + GLenum pathNameType, + const void *paths, + GLuint pathBase, + GLenum fillMode, + GLuint mask, + GLenum coverMode, + GLenum transformType, + const GLfloat *transformValues); +bool ValidateStencilThenCoverStrokePathInstanced(Context *context, + GLsizei numPaths, + GLenum pathNameType, + const void *paths, + GLuint pathBase, + GLint reference, + GLuint mask, + GLenum coverMode, + GLenum transformType, + const GLfloat *transformValues); +bool ValidateBindFragmentInputLocation(Context *context, + GLuint program, + GLint location, + const GLchar *name); +bool ValidateProgramPathFragmentInputGen(Context *context, + GLuint program, + GLint location, + GLenum genMode, + GLint components, + const GLfloat *coeffs); + +bool ValidateCopyTextureCHROMIUM(Context *context, + GLuint sourceId, + GLint sourceLevel, + GLenum destTarget, + GLuint destId, + GLint destLevel, + GLint internalFormat, + GLenum destType, + GLboolean unpackFlipY, + GLboolean unpackPremultiplyAlpha, + GLboolean unpackUnmultiplyAlpha); +bool ValidateCopySubTextureCHROMIUM(Context *context, + GLuint sourceId, + GLint sourceLevel, + GLenum destTarget, + GLuint destId, + GLint destLevel, + GLint xoffset, + GLint yoffset, + GLint x, + GLint y, + GLsizei width, + GLsizei height, + GLboolean unpackFlipY, + GLboolean unpackPremultiplyAlpha, + GLboolean unpackUnmultiplyAlpha); +bool ValidateCompressedCopyTextureCHROMIUM(Context *context, GLuint sourceId, GLuint destId); + +bool ValidateCreateShader(Context *context, GLenum type); +bool ValidateBufferData(ValidationContext *context, + BufferBinding target, + GLsizeiptr size, + const void *data, + BufferUsage usage); +bool ValidateBufferSubData(ValidationContext *context, + BufferBinding target, + GLintptr offset, + GLsizeiptr size, + const void *data); + +bool ValidateRequestExtensionANGLE(Context *context, const GLchar *name); + +bool ValidateActiveTexture(ValidationContext *context, GLenum texture); +bool ValidateAttachShader(ValidationContext *context, GLuint program, GLuint shader); +bool ValidateBindAttribLocation(ValidationContext *context, + GLuint program, + GLuint index, + const GLchar *name); +bool ValidateBindBuffer(ValidationContext *context, BufferBinding target, GLuint buffer); +bool ValidateBindFramebuffer(ValidationContext *context, GLenum target, GLuint framebuffer); +bool ValidateBindRenderbuffer(ValidationContext *context, GLenum target, GLuint renderbuffer); +bool ValidateBlendColor(ValidationContext *context, + GLclampf red, + GLclampf green, + GLclampf blue, + GLclampf alpha); +bool ValidateBlendEquation(ValidationContext *context, GLenum mode); +bool ValidateBlendEquationSeparate(ValidationContext *context, GLenum modeRGB, GLenum modeAlpha); +bool ValidateBlendFunc(ValidationContext *context, GLenum sfactor, GLenum dfactor); +bool ValidateBlendFuncSeparate(ValidationContext *context, + GLenum srcRGB, + GLenum dstRGB, + GLenum srcAlpha, + GLenum dstAlpha); + +bool ValidateGetString(Context *context, GLenum name); +bool ValidateLineWidth(ValidationContext *context, GLfloat width); +bool ValidateVertexAttribPointer(ValidationContext *context, + GLuint index, + GLint size, + GLenum type, + GLboolean normalized, + GLsizei stride, + const void *ptr); + +bool ValidateDepthRangef(ValidationContext *context, GLclampf zNear, GLclampf zFar); +bool ValidateRenderbufferStorage(ValidationContext *context, + GLenum target, + GLenum internalformat, + GLsizei width, + GLsizei height); +bool ValidateRenderbufferStorageMultisampleANGLE(ValidationContext *context, + GLenum target, + GLsizei samples, + GLenum internalformat, + GLsizei width, + GLsizei height); + +bool ValidateCheckFramebufferStatus(ValidationContext *context, GLenum target); +bool ValidateClearColor(ValidationContext *context, + GLclampf red, + GLclampf green, + GLclampf blue, + GLclampf alpha); +bool ValidateClearDepthf(ValidationContext *context, GLclampf depth); +bool ValidateClearStencil(ValidationContext *context, GLint s); +bool ValidateColorMask(ValidationContext *context, + GLboolean red, + GLboolean green, + GLboolean blue, + GLboolean alpha); +bool ValidateCompileShader(ValidationContext *context, GLuint shader); +bool ValidateCreateProgram(ValidationContext *context); +bool ValidateCullFace(ValidationContext *context, CullFaceMode mode); +bool ValidateDeleteProgram(ValidationContext *context, GLuint program); +bool ValidateDeleteShader(ValidationContext *context, GLuint shader); +bool ValidateDepthFunc(ValidationContext *context, GLenum func); +bool ValidateDepthMask(ValidationContext *context, GLboolean flag); +bool ValidateDetachShader(ValidationContext *context, GLuint program, GLuint shader); +bool ValidateDisableVertexAttribArray(ValidationContext *context, GLuint index); +bool ValidateEnableVertexAttribArray(ValidationContext *context, GLuint index); +bool ValidateFinish(ValidationContext *context); +bool ValidateFlush(ValidationContext *context); +bool ValidateFrontFace(ValidationContext *context, GLenum mode); +bool ValidateGetActiveAttrib(ValidationContext *context, + GLuint program, + GLuint index, + GLsizei bufsize, + GLsizei *length, + GLint *size, + GLenum *type, + GLchar *name); +bool ValidateGetActiveUniform(ValidationContext *context, + GLuint program, + GLuint index, + GLsizei bufsize, + GLsizei *length, + GLint *size, + GLenum *type, + GLchar *name); +bool ValidateGetAttachedShaders(ValidationContext *context, + GLuint program, + GLsizei maxcount, + GLsizei *count, + GLuint *shaders); +bool ValidateGetAttribLocation(ValidationContext *context, GLuint program, const GLchar *name); +bool ValidateGetBooleanv(ValidationContext *context, GLenum pname, GLboolean *params); +bool ValidateGetError(ValidationContext *context); +bool ValidateGetFloatv(ValidationContext *context, GLenum pname, GLfloat *params); +bool ValidateGetIntegerv(ValidationContext *context, GLenum pname, GLint *params); +bool ValidateGetProgramInfoLog(ValidationContext *context, + GLuint program, + GLsizei bufsize, + GLsizei *length, + GLchar *infolog); +bool ValidateGetShaderInfoLog(ValidationContext *context, + GLuint shader, + GLsizei bufsize, + GLsizei *length, + GLchar *infolog); +bool ValidateGetShaderPrecisionFormat(ValidationContext *context, + GLenum shadertype, + GLenum precisiontype, + GLint *range, + GLint *precision); +bool ValidateGetShaderSource(ValidationContext *context, + GLuint shader, + GLsizei bufsize, + GLsizei *length, + GLchar *source); +bool ValidateGetUniformLocation(ValidationContext *context, GLuint program, const GLchar *name); +bool ValidateHint(ValidationContext *context, GLenum target, GLenum mode); +bool ValidateIsBuffer(ValidationContext *context, GLuint buffer); +bool ValidateIsFramebuffer(ValidationContext *context, GLuint framebuffer); +bool ValidateIsProgram(ValidationContext *context, GLuint program); +bool ValidateIsRenderbuffer(ValidationContext *context, GLuint renderbuffer); +bool ValidateIsShader(ValidationContext *context, GLuint shader); +bool ValidateIsTexture(ValidationContext *context, GLuint texture); +bool ValidatePixelStorei(ValidationContext *context, GLenum pname, GLint param); +bool ValidatePolygonOffset(ValidationContext *context, GLfloat factor, GLfloat units); +bool ValidateReleaseShaderCompiler(ValidationContext *context); +bool ValidateSampleCoverage(ValidationContext *context, GLclampf value, GLboolean invert); +bool ValidateScissor(ValidationContext *context, GLint x, GLint y, GLsizei width, GLsizei height); +bool ValidateShaderBinary(ValidationContext *context, + GLsizei n, + const GLuint *shaders, + GLenum binaryformat, + const void *binary, + GLsizei length); +bool ValidateShaderSource(ValidationContext *context, + GLuint shader, + GLsizei count, + const GLchar *const *string, + const GLint *length); +bool ValidateStencilFunc(ValidationContext *context, GLenum func, GLint ref, GLuint mask); +bool ValidateStencilFuncSeparate(ValidationContext *context, + GLenum face, + GLenum func, + GLint ref, + GLuint mask); +bool ValidateStencilMask(ValidationContext *context, GLuint mask); +bool ValidateStencilMaskSeparate(ValidationContext *context, GLenum face, GLuint mask); +bool ValidateStencilOp(ValidationContext *context, GLenum fail, GLenum zfail, GLenum zpass); +bool ValidateStencilOpSeparate(ValidationContext *context, + GLenum face, + GLenum fail, + GLenum zfail, + GLenum zpass); +bool ValidateUniform1f(ValidationContext *context, GLint location, GLfloat x); +bool ValidateUniform1fv(ValidationContext *context, + GLint location, + GLsizei count, + const GLfloat *v); +bool ValidateUniform1i(ValidationContext *context, GLint location, GLint x); +bool ValidateUniform2f(ValidationContext *context, GLint location, GLfloat x, GLfloat y); +bool ValidateUniform2fv(ValidationContext *context, + GLint location, + GLsizei count, + const GLfloat *v); +bool ValidateUniform2i(ValidationContext *context, GLint location, GLint x, GLint y); +bool ValidateUniform2iv(ValidationContext *context, GLint location, GLsizei count, const GLint *v); +bool ValidateUniform3f(ValidationContext *context, GLint location, GLfloat x, GLfloat y, GLfloat z); +bool ValidateUniform3fv(ValidationContext *context, + GLint location, + GLsizei count, + const GLfloat *v); +bool ValidateUniform3i(ValidationContext *context, GLint location, GLint x, GLint y, GLint z); +bool ValidateUniform3iv(ValidationContext *context, GLint location, GLsizei count, const GLint *v); +bool ValidateUniform4f(ValidationContext *context, + GLint location, + GLfloat x, + GLfloat y, + GLfloat z, + GLfloat w); +bool ValidateUniform4fv(ValidationContext *context, + GLint location, + GLsizei count, + const GLfloat *v); +bool ValidateUniform4i(ValidationContext *context, + GLint location, + GLint x, + GLint y, + GLint z, + GLint w); +bool ValidateUniform4iv(ValidationContext *context, GLint location, GLsizei count, const GLint *v); +bool ValidateUniformMatrix2fv(ValidationContext *context, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value); +bool ValidateUniformMatrix3fv(ValidationContext *context, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value); +bool ValidateUniformMatrix4fv(ValidationContext *context, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value); +bool ValidateValidateProgram(ValidationContext *context, GLuint program); +bool ValidateVertexAttrib1f(ValidationContext *context, GLuint index, GLfloat x); +bool ValidateVertexAttrib1fv(ValidationContext *context, GLuint index, const GLfloat *values); +bool ValidateVertexAttrib2f(ValidationContext *context, GLuint index, GLfloat x, GLfloat y); +bool ValidateVertexAttrib2fv(ValidationContext *context, GLuint index, const GLfloat *values); +bool ValidateVertexAttrib3f(ValidationContext *context, + GLuint index, + GLfloat x, + GLfloat y, + GLfloat z); +bool ValidateVertexAttrib3fv(ValidationContext *context, GLuint index, const GLfloat *values); +bool ValidateVertexAttrib4f(ValidationContext *context, + GLuint index, + GLfloat x, + GLfloat y, + GLfloat z, + GLfloat w); +bool ValidateVertexAttrib4fv(ValidationContext *context, GLuint index, const GLfloat *values); +bool ValidateViewport(ValidationContext *context, GLint x, GLint y, GLsizei width, GLsizei height); +bool ValidateDrawElements(ValidationContext *context, + GLenum mode, + GLsizei count, + GLenum type, + const void *indices); + +bool ValidateDrawArrays(ValidationContext *context, GLenum mode, GLint first, GLsizei count); + +bool ValidateGetFramebufferAttachmentParameteriv(ValidationContext *context, + GLenum target, + GLenum attachment, + GLenum pname, + GLint *params); +bool ValidateGetProgramiv(ValidationContext *context, GLuint program, GLenum pname, GLint *params); + +bool ValidateCopyTexImage2D(ValidationContext *context, + GLenum target, + GLint level, + GLenum internalformat, + GLint x, + GLint y, + GLsizei width, + GLsizei height, + GLint border); + +bool ValidateCopyTexSubImage2D(Context *context, + GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLint x, + GLint y, + GLsizei width, + GLsizei height); + +bool ValidateDeleteBuffers(Context *context, GLint n, const GLuint *buffers); +bool ValidateDeleteFramebuffers(Context *context, GLint n, const GLuint *framebuffers); +bool ValidateDeleteRenderbuffers(Context *context, GLint n, const GLuint *renderbuffers); +bool ValidateDeleteTextures(Context *context, GLint n, const GLuint *textures); +bool ValidateDisable(Context *context, GLenum cap); +bool ValidateEnable(Context *context, GLenum cap); +bool ValidateFramebufferRenderbuffer(Context *context, + GLenum target, + GLenum attachment, + GLenum renderbuffertarget, + GLuint renderbuffer); +bool ValidateFramebufferTexture2D(Context *context, + GLenum target, + GLenum attachment, + GLenum textarget, + GLuint texture, + GLint level); +bool ValidateGenBuffers(Context *context, GLint n, GLuint *buffers); +bool ValidateGenerateMipmap(Context *context, GLenum target); +bool ValidateGenFramebuffers(Context *context, GLint n, GLuint *framebuffers); +bool ValidateGenRenderbuffers(Context *context, GLint n, GLuint *renderbuffers); +bool ValidateGenTextures(Context *context, GLint n, GLuint *textures); +bool ValidateGetBufferParameteriv(ValidationContext *context, + BufferBinding target, + GLenum pname, + GLint *params); +bool ValidateGetRenderbufferParameteriv(Context *context, + GLenum target, + GLenum pname, + GLint *params); +bool ValidateGetShaderiv(Context *context, GLuint shader, GLenum pname, GLint *params); +bool ValidateGetTexParameterfv(Context *context, GLenum target, GLenum pname, GLfloat *params); +bool ValidateGetTexParameteriv(Context *context, GLenum target, GLenum pname, GLint *params); +bool ValidateGetUniformfv(Context *context, GLuint program, GLint location, GLfloat *params); +bool ValidateGetUniformiv(Context *context, GLuint program, GLint location, GLint *params); +bool ValidateGetVertexAttribfv(Context *context, GLuint index, GLenum pname, GLfloat *params); +bool ValidateGetVertexAttribiv(Context *context, GLuint index, GLenum pname, GLint *params); +bool ValidateGetVertexAttribPointerv(Context *context, GLuint index, GLenum pname, void **pointer); +bool ValidateIsEnabled(Context *context, GLenum cap); +bool ValidateLinkProgram(Context *context, GLuint program); +bool ValidateReadPixels(Context *context, + GLint x, + GLint y, + GLsizei width, + GLsizei height, + GLenum format, + GLenum type, + void *pixels); +bool ValidateTexParameterf(Context *context, GLenum target, GLenum pname, GLfloat param); +bool ValidateTexParameterfv(Context *context, GLenum target, GLenum pname, const GLfloat *params); +bool ValidateTexParameteri(Context *context, GLenum target, GLenum pname, GLint param); +bool ValidateTexParameteriv(Context *context, GLenum target, GLenum pname, const GLint *params); +bool ValidateUniform1iv(ValidationContext *context, + GLint location, + GLsizei count, + const GLint *value); +bool ValidateUseProgram(Context *context, GLuint program); } // namespace gl -#endif // LIBANGLE_VALIDATION_ES2_H_ +#endif // LIBANGLE_VALIDATION_ES2_H_ diff --git a/src/3rdparty/angle/src/libANGLE/validationES3.cpp b/src/3rdparty/angle/src/libANGLE/validationES3.cpp index 2db64ec4cc..1aadfc876e 100644 --- a/src/3rdparty/angle/src/libANGLE/validationES3.cpp +++ b/src/3rdparty/angle/src/libANGLE/validationES3.cpp @@ -7,255 +7,190 @@ // validationES3.cpp: Validation functions for OpenGL ES 3.0 entry point parameters #include "libANGLE/validationES3.h" -#include "libANGLE/validationES.h" + +#include "anglebase/numerics/safe_conversions.h" +#include "common/mathutil.h" +#include "common/utilities.h" #include "libANGLE/Context.h" -#include "libANGLE/Texture.h" +#include "libANGLE/ErrorStrings.h" #include "libANGLE/Framebuffer.h" +#include "libANGLE/FramebufferAttachment.h" #include "libANGLE/Renderbuffer.h" +#include "libANGLE/Texture.h" #include "libANGLE/formatutils.h" -#include "libANGLE/FramebufferAttachment.h" +#include "libANGLE/validationES.h" -#include "common/mathutil.h" -#include "common/utilities.h" +using namespace angle; namespace gl { -struct ES3FormatCombination +namespace { - GLenum internalFormat; - GLenum format; - GLenum type; -}; +bool ValidateFramebufferTextureMultiviewBaseANGLE(Context *context, + GLenum target, + GLenum attachment, + GLuint texture, + GLint level, + GLsizei numViews) +{ + if (!context->getExtensions().multiview) + { + context->handleError(InvalidOperation() << "ANGLE_multiview is not available."); + return false; + } + + if (!ValidateFramebufferTextureBase(context, target, attachment, texture, level)) + { + return false; + } + + if (texture != 0 && numViews < 1) + { + context->handleError(InvalidValue() << "numViews cannot be less than 1."); + return false; + } + + const Extensions &extensions = context->getExtensions(); + if (static_cast(numViews) > extensions.maxViews) + { + context->handleError(InvalidValue() + << "numViews cannot be greater than GL_MAX_VIEWS_ANGLE."); + return false; + } + + return true; +} -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 ); - InsertES3FormatCombo(&set, GL_RG, GL_RG, GL_UNSIGNED_BYTE ); - InsertES3FormatCombo(&set, GL_RG, GL_RG, GL_FLOAT ); - InsertES3FormatCombo(&set, GL_RG, GL_RG, GL_HALF_FLOAT ); - InsertES3FormatCombo(&set, GL_RG, GL_RG, GL_HALF_FLOAT_OES ); - InsertES3FormatCombo(&set, GL_RED, GL_RED, GL_UNSIGNED_BYTE ); - InsertES3FormatCombo(&set, GL_RED, GL_RED, GL_FLOAT ); - InsertES3FormatCombo(&set, GL_RED, GL_RED, GL_HALF_FLOAT ); - InsertES3FormatCombo(&set, GL_RED, GL_RED, GL_HALF_FLOAT_OES ); - InsertES3FormatCombo(&set, GL_DEPTH_STENCIL, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8 ); - - // 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_RGBA, GL_RGBA, GL_FLOAT ); - InsertES3FormatCombo(&set, GL_RGB, GL_RGB, GL_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 ); - - return set; -} - -static bool ValidateTexImageFormatCombination(gl::Context *context, GLenum internalFormat, GLenum format, GLenum type) +bool ValidateFramebufferTextureMultiviewLevelAndFormat(Context *context, + Texture *texture, + GLint level) { - // For historical reasons, glTexImage2D and glTexImage3D pass in their internal format as a - // GLint instead of a GLenum. Therefor an invalid internal format gives a GL_INVALID_VALUE - // error instead of a GL_INVALID_ENUM error. As this validation function is only called in - // the validation codepaths for glTexImage2D/3D, we record a GL_INVALID_VALUE error. - const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat); - if (!formatInfo.textureSupport(context->getClientVersion(), context->getExtensions())) + GLenum texTarget = texture->getTarget(); + if (!ValidMipLevel(context, texTarget, level)) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), InvalidMipLevel); + return false; + } + + const auto &format = texture->getFormat(texTarget, level); + if (format.info->compressed) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), CompressedTexturesNotAttachable); + return false; + } + return true; +} + +bool ValidateUniformES3(Context *context, GLenum uniformType, GLint location, GLint count) +{ + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + return ValidateUniform(context, uniformType, location, count); +} + +bool ValidateUniformMatrixES3(Context *context, + GLenum valueType, + GLint location, + GLsizei count, + GLboolean transpose) +{ + // Check for ES3 uniform entry points + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + return ValidateUniformMatrix(context, valueType, location, count, transpose); +} + +bool ValidateGenOrDeleteES3(Context *context, GLint n) +{ + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + return ValidateGenOrDelete(context, n); +} + +bool ValidateGenOrDeleteCountES3(Context *context, GLint count) +{ + if (context->getClientMajorVersion() < 3) { - context->recordError(Error(GL_INVALID_VALUE)); + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); return false; } + if (count < 0) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), NegativeCount); + return false; + } + return true; +} + +} // anonymous namespace + +static bool ValidateTexImageFormatCombination(gl::Context *context, + GLenum target, + GLenum internalFormat, + GLenum format, + GLenum type) +{ // The type and format are valid if any supported internal format has that type and format - bool formatSupported = false; - bool typeSupported = false; + if (!ValidES3Format(format)) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidFormat); + return false; + } - static const ES3FormatCombinationSet es3FormatSet = BuildES3FormatSet(); - for (ES3FormatCombinationSet::const_iterator i = es3FormatSet.begin(); i != es3FormatSet.end(); i++) + if (!ValidES3Type(type)) { - 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; - } + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidType); + return false; + } - // Early-out if both type and format are supported now - if (typeSupported && formatSupported) - { - break; - } - } + // For historical reasons, glTexImage2D and glTexImage3D pass in their internal format as a + // GLint instead of a GLenum. Therefor an invalid internal format gives a GL_INVALID_VALUE + // error instead of a GL_INVALID_ENUM error. As this validation function is only called in + // the validation codepaths for glTexImage2D/3D, we record a GL_INVALID_VALUE error. + if (!ValidES3InternalFormat(internalFormat)) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), InvalidInternalFormat); + return false; } - if (!typeSupported || !formatSupported) + // From the ES 3.0 spec section 3.8.3: + // Textures with a base internal format of DEPTH_COMPONENT or DEPTH_STENCIL are supported by + // texture image specification commands only if target is TEXTURE_2D, TEXTURE_2D_ARRAY, or + // TEXTURE_CUBE_MAP.Using these formats in conjunction with any other target will result in an + // INVALID_OPERATION error. + if (target == GL_TEXTURE_3D && (format == GL_DEPTH_COMPONENT || format == GL_DEPTH_STENCIL)) { - context->recordError(Error(GL_INVALID_ENUM)); + context->handleError(InvalidOperation() << "Format cannot be GL_DEPTH_COMPONENT or " + "GL_DEPTH_STENCIL if target is " + "GL_TEXTURE_3D"); 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 (!ValidES3FormatCombination(format, type, internalFormat)) + { + context->handleError(InvalidOperation() + << "Invalid combination of format, type and internalFormat."); + return false; + } - if (es3FormatSet.find(searchFormat) == es3FormatSet.end()) + const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat, type); + if (!formatInfo.textureSupport(context->getClientVersion(), context->getExtensions())) { - context->recordError(Error(GL_INVALID_OPERATION)); + context->handleError(InvalidOperation() << "Unsupported internal format."); return false; } @@ -277,19 +212,20 @@ bool ValidateES3TexImageParametersBase(Context *context, GLint border, GLenum format, GLenum type, - const GLvoid *pixels) + GLsizei imageSize, + const void *pixels) { // Validate image size if (!ValidImageSizeParameters(context, target, level, width, height, depth, isSubImage)) { - context->recordError(Error(GL_INVALID_VALUE)); + context->handleError(InvalidValue()); return false; } // Verify zero border if (border != 0) { - context->recordError(Error(GL_INVALID_VALUE)); + context->handleError(InvalidValue()); return false; } @@ -298,7 +234,7 @@ bool ValidateES3TexImageParametersBase(Context *context, std::numeric_limits::max() - yoffset < height || std::numeric_limits::max() - zoffset < depth) { - context->recordError(Error(GL_INVALID_VALUE)); + context->handleError(InvalidValue()); return false; } @@ -306,112 +242,158 @@ bool ValidateES3TexImageParametersBase(Context *context, 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_2D: + if (static_cast(width) > (caps.max2DTextureSize >> level) || + static_cast(height) > (caps.max2DTextureSize >> level)) + { + context->handleError(InvalidValue()); + 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; - } + case GL_TEXTURE_RECTANGLE_ANGLE: + ASSERT(level == 0); + if (static_cast(width) > caps.maxRectangleTextureSize || + static_cast(height) > caps.maxRectangleTextureSize) + { + context->handleError(InvalidValue()); + return false; + } + if (isCompressed) + { + context->handleError(InvalidEnum() + << "Rectangle texture cannot have a compressed format."); + return false; + } + break; - if (static_cast(width) > (caps.maxCubeMapTextureSize >> 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->handleError(InvalidValue()); + return false; + } - 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; + if (static_cast(width) > (caps.maxCubeMapTextureSize >> level)) + { + context->handleError(InvalidValue()); + 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) - { - 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->handleError(InvalidValue()); + return false; + } + break; - default: - context->recordError(Error(GL_INVALID_ENUM)); - return false; + case GL_TEXTURE_2D_ARRAY: + if (static_cast(width) > (caps.max2DTextureSize >> level) || + static_cast(height) > (caps.max2DTextureSize >> level) || + static_cast(depth) > caps.maxArrayTextureLayers) + { + context->handleError(InvalidValue()); + return false; + } + break; + + default: + context->handleError(InvalidEnum()); + return false; } - gl::Texture *texture = context->getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target); + gl::Texture *texture = + context->getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target); if (!texture) { - context->recordError(Error(GL_INVALID_OPERATION)); + context->handleError(InvalidOperation()); return false; } if (texture->getImmutableFormat() && !isSubImage) { - context->recordError(Error(GL_INVALID_OPERATION)); + context->handleError(InvalidOperation()); return false; } // Validate texture formats - GLenum actualInternalFormat = isSubImage ? texture->getInternalFormat(target, level) : internalformat; - const gl::InternalFormat &actualFormatInfo = gl::GetInternalFormatInfo(actualInternalFormat); + GLenum actualInternalFormat = + isSubImage ? texture->getFormat(target, level).info->internalFormat : internalformat; + if (isSubImage && actualInternalFormat == GL_NONE) + { + context->handleError(InvalidOperation() << "Texture level does not exist."); + return false; + } + + const gl::InternalFormat &actualFormatInfo = isSubImage + ? *texture->getFormat(target, level).info + : GetInternalFormatInfo(internalformat, type); if (isCompressed) { if (!actualFormatInfo.compressed) { - context->recordError(Error( - GL_INVALID_ENUM, "internalformat is not a supported compressed internal format.")); + context->handleError( + InvalidEnum() << "internalformat is not a supported compressed internal format."); return false; } - if (!ValidCompressedImageSize(context, actualInternalFormat, width, height)) + if (isSubImage) { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; + if (!ValidCompressedSubImageSize( + context, actualFormatInfo.internalFormat, xoffset, yoffset, width, height, + texture->getWidth(target, level), texture->getHeight(target, level))) + { + context->handleError(InvalidOperation() << "Invalid compressed format dimension."); + return false; + } + + if (format != actualInternalFormat) + { + context->handleError(InvalidOperation() + << "Format must match the internal format of the texture."); + return false; + } + + if (actualInternalFormat == GL_ETC1_RGB8_OES) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), InvalidInternalFormat); + return false; + } + } + else + { + if (!ValidCompressedImageSize(context, actualInternalFormat, level, width, height)) + { + context->handleError(InvalidOperation() << "Invalid compressed format dimension."); + return false; + } } if (!actualFormatInfo.textureSupport(context->getClientVersion(), context->getExtensions())) { - context->recordError(Error(GL_INVALID_ENUM)); + context->handleError(InvalidEnum()); return false; } if (target == GL_TEXTURE_3D) { - context->recordError(Error(GL_INVALID_OPERATION)); + context->handleError(InvalidOperation()); return false; } } else { - if (!ValidateTexImageFormatCombination(context, actualInternalFormat, format, type)) - { - return false; - } - - if (target == GL_TEXTURE_3D && (format == GL_DEPTH_COMPONENT || format == GL_DEPTH_STENCIL)) + if (!ValidateTexImageFormatCombination(context, target, actualInternalFormat, format, type)) { - context->recordError(Error(GL_INVALID_OPERATION)); return false; } } @@ -421,18 +403,13 @@ bool ValidateES3TexImageParametersBase(Context *context, { if (isCompressed != actualFormatInfo.compressed) { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - - if (width == 0 || height == 0 || depth == 0) - { + context->handleError(InvalidOperation()); return false; } if (xoffset < 0 || yoffset < 0 || zoffset < 0) { - context->recordError(Error(GL_INVALID_VALUE)); + context->handleError(InvalidValue()); return false; } @@ -440,7 +417,7 @@ bool ValidateES3TexImageParametersBase(Context *context, std::numeric_limits::max() - yoffset < height || std::numeric_limits::max() - zoffset < depth) { - context->recordError(Error(GL_INVALID_VALUE)); + context->handleError(InvalidValue()); return false; } @@ -448,54 +425,42 @@ bool ValidateES3TexImageParametersBase(Context *context, static_cast(yoffset + height) > texture->getHeight(target, level) || static_cast(zoffset + depth) > texture->getDepth(target, level)) { - context->recordError(Error(GL_INVALID_VALUE)); + context->handleError(InvalidValue()); 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)) + if (width > 0 && height > 0 && depth > 0 && pixels == nullptr && + context->getGLState().getTargetBuffer(gl::BufferBinding::PixelUnpack) == nullptr) { - // Overflow past the end of the buffer - context->recordError(Error(GL_INVALID_OPERATION)); + ANGLE_VALIDATION_ERR(context, InvalidValue(), PixelDataNull); 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; - } + GLenum sizeCheckFormat = isSubImage ? format : internalformat; + if (!ValidImageDataSize(context, target, width, height, depth, sizeCheckFormat, type, pixels, + imageSize)) + { + return false; + } - // ...data is not evenly divisible into the number of bytes needed to store in memory a datum + // Check for pixel unpack buffer related API errors + gl::Buffer *pixelUnpackBuffer = + context->getGLState().getTargetBuffer(BufferBinding::PixelUnpack); + if (pixelUnpackBuffer != nullptr) + { + // ...data is not evenly divisible into the number of bytes needed to store in memory a + // datum // indicated by type. if (!isCompressed) { + size_t offset = reinterpret_cast(pixels); size_t dataBytesPerPixel = static_cast(gl::GetTypeInfo(type).bytes); if ((offset % dataBytesPerPixel) != 0) { - context->recordError(Error(GL_INVALID_OPERATION)); + context->handleError(InvalidOperation() + << "Reads would overflow the pixel unpack buffer."); return false; } } @@ -503,7 +468,7 @@ bool ValidateES3TexImageParametersBase(Context *context, // ...the buffer object's data store is currently mapped. if (pixelUnpackBuffer->isMapped()) { - context->recordError(Error(GL_INVALID_OPERATION)); + context->handleError(InvalidOperation() << "Pixel unpack buffer is mapped."); return false; } } @@ -526,17 +491,18 @@ bool ValidateES3TexImage2DParameters(Context *context, GLint border, GLenum format, GLenum type, - const GLvoid *pixels) + GLsizei imageSize, + const void *pixels) { if (!ValidTexture2DDestinationTarget(context, target)) { - context->recordError(Error(GL_INVALID_ENUM)); + context->handleError(InvalidEnum()); return false; } return ValidateES3TexImageParametersBase(context, target, level, internalformat, isCompressed, isSubImage, xoffset, yoffset, zoffset, width, height, - depth, border, format, type, pixels); + depth, border, format, type, imageSize, pixels); } bool ValidateES3TexImage3DParameters(Context *context, @@ -554,301 +520,260 @@ bool ValidateES3TexImage3DParameters(Context *context, GLint border, GLenum format, GLenum type, - const GLvoid *pixels) + GLsizei bufSize, + const void *pixels) { if (!ValidTexture3DDestinationTarget(context, target)) { - context->recordError(Error(GL_INVALID_ENUM)); + context->handleError(InvalidEnum()); return false; } return ValidateES3TexImageParametersBase(context, target, level, internalformat, isCompressed, isSubImage, xoffset, yoffset, zoffset, width, height, - depth, border, format, type, pixels); + depth, border, format, type, bufSize, pixels); } 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) {}; + GLenum effectiveFormat; + GLenum destFormat; + GLuint minRedBits; + GLuint maxRedBits; + GLuint minGreenBits; + GLuint maxGreenBits; + GLuint minBlueBits; + GLuint maxBlueBits; + GLuint minAlphaBits; + GLuint maxAlphaBits; }; -typedef std::vector EffectiveInternalFormatList; - -static EffectiveInternalFormatList BuildSizedEffectiveInternalFormatList() +static bool QueryEffectiveFormatList(const InternalFormat &srcFormat, + GLenum targetFormat, + const EffectiveInternalFormatInfo *list, + size_t size, + GLenum *outEffectiveFormat) { - 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)); + for (size_t curFormat = 0; curFormat < size; ++curFormat) + { + const EffectiveInternalFormatInfo &formatInfo = list[curFormat]; + if ((formatInfo.destFormat == targetFormat) && + (formatInfo.minRedBits <= srcFormat.redBits && + formatInfo.maxRedBits >= srcFormat.redBits) && + (formatInfo.minGreenBits <= srcFormat.greenBits && + formatInfo.maxGreenBits >= srcFormat.greenBits) && + (formatInfo.minBlueBits <= srcFormat.blueBits && + formatInfo.maxBlueBits >= srcFormat.blueBits) && + (formatInfo.minAlphaBits <= srcFormat.alphaBits && + formatInfo.maxAlphaBits >= srcFormat.alphaBits)) + { + *outEffectiveFormat = formatInfo.effectiveFormat; + return true; + } + } - return list; + *outEffectiveFormat = GL_NONE; + return false; } -static EffectiveInternalFormatList BuildUnsizedEffectiveInternalFormatList() +bool GetSizedEffectiveInternalFormatInfo(const InternalFormat &srcFormat, + GLenum *outEffectiveFormat) { - 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)); + // 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 | + // clang-format off + constexpr EffectiveInternalFormatInfo list[] = { + { GL_ALPHA8_EXT, GL_NONE, 0, 0, 0, 0, 0, 0, 1, 8 }, + { GL_R8, GL_NONE, 1, 8, 0, 0, 0, 0, 0, 0 }, + { GL_RG8, GL_NONE, 1, 8, 1, 8, 0, 0, 0, 0 }, + { GL_RGB565, GL_NONE, 1, 5, 1, 6, 1, 5, 0, 0 }, + { GL_RGB8, GL_NONE, 6, 8, 7, 8, 6, 8, 0, 0 }, + { GL_RGBA4, GL_NONE, 1, 4, 1, 4, 1, 4, 1, 4 }, + { GL_RGB5_A1, GL_NONE, 5, 5, 5, 5, 5, 5, 1, 1 }, + { GL_RGBA8, GL_NONE, 5, 8, 5, 8, 5, 8, 2, 8 }, + { GL_RGB10_A2, GL_NONE, 9, 10, 9, 10, 9, 10, 2, 2 }, + }; + // clang-format on + + return QueryEffectiveFormatList(srcFormat, GL_NONE, list, ArraySize(list), outEffectiveFormat); +} - return list; +bool GetUnsizedEffectiveInternalFormatInfo(const InternalFormat &srcFormat, + const InternalFormat &destFormat, + GLenum *outEffectiveFormat) +{ + constexpr GLuint umax = UINT_MAX; + + // OpenGL ES 3.0.3 Specification, Table 3.17, pg 141: + // Effective internal format coresponding to destination internal format andlinear source buffer + // component sizes. + // | Source channel min/max sizes | + // Effective Internal Format | Dest Format | R | G | B | A | + // clang-format off + constexpr EffectiveInternalFormatInfo list[] = { + { GL_ALPHA8_EXT, GL_ALPHA, 0, umax, 0, umax, 0, umax, 1, 8 }, + { GL_LUMINANCE8_EXT, GL_LUMINANCE, 1, 8, 0, umax, 0, umax, 0, umax }, + { GL_LUMINANCE8_ALPHA8_EXT, GL_LUMINANCE_ALPHA, 1, 8, 0, umax, 0, umax, 1, 8 }, + { GL_RGB565, GL_RGB, 1, 5, 1, 6, 1, 5, 0, umax }, + { GL_RGB8, GL_RGB, 6, 8, 7, 8, 6, 8, 0, umax }, + { GL_RGBA4, GL_RGBA, 1, 4, 1, 4, 1, 4, 1, 4 }, + { GL_RGB5_A1, GL_RGBA, 5, 5, 5, 5, 5, 5, 1, 1 }, + { GL_RGBA8, GL_RGBA, 5, 8, 5, 8, 5, 8, 5, 8 }, + }; + // clang-format on + + return QueryEffectiveFormatList(srcFormat, destFormat.format, list, ArraySize(list), + outEffectiveFormat); } -static bool GetEffectiveInternalFormat(const InternalFormat &srcFormat, const InternalFormat &destFormat, +static bool GetEffectiveInternalFormat(const InternalFormat &srcFormat, + const InternalFormat &destFormat, GLenum *outEffectiveFormat) { - const EffectiveInternalFormatList *list = NULL; - GLenum targetFormat = GL_NONE; - - if (destFormat.pixelBytes > 0) + if (destFormat.sized) { - static const EffectiveInternalFormatList sizedList = BuildSizedEffectiveInternalFormatList(); - list = &sizedList; + return GetSizedEffectiveInternalFormatInfo(srcFormat, outEffectiveFormat); } 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 GetUnsizedEffectiveInternalFormatInfo(srcFormat, destFormat, outEffectiveFormat); } +} - return false; +static bool EqualOrFirstZero(GLuint first, GLuint second) +{ + return first == 0 || first == second; } -struct CopyConversion +static bool IsValidES3CopyTexImageCombination(const InternalFormat &textureFormatInfo, + const InternalFormat &framebufferFormatInfo, + GLuint readBufferHandle) { - GLenum mTextureFormat; - GLenum mFramebufferFormat; + if (!ValidES3CopyConversion(textureFormatInfo.format, framebufferFormatInfo.format)) + { + return false; + } - CopyConversion(GLenum textureFormat, GLenum framebufferFormat) - : mTextureFormat(textureFormat), mFramebufferFormat(framebufferFormat) { } + // 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. - bool operator<(const CopyConversion& other) const + if ((textureFormatInfo.colorEncoding == GL_SRGB) != + (framebufferFormatInfo.colorEncoding == GL_SRGB)) { - return memcmp(this, &other, sizeof(CopyConversion)) < 0; + return false; } -}; -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 (((textureFormatInfo.componentType == GL_INT) != + (framebufferFormatInfo.componentType == GL_INT)) || + ((textureFormatInfo.componentType == GL_UNSIGNED_INT) != + (framebufferFormatInfo.componentType == GL_UNSIGNED_INT))) + { + return false; + } + + if ((textureFormatInfo.componentType == GL_UNSIGNED_NORMALIZED || + textureFormatInfo.componentType == GL_SIGNED_NORMALIZED || + textureFormatInfo.componentType == GL_FLOAT) && + !(framebufferFormatInfo.componentType == GL_UNSIGNED_NORMALIZED || + framebufferFormatInfo.componentType == GL_SIGNED_NORMALIZED || + framebufferFormatInfo.componentType == GL_FLOAT)) + { + return false; + } - if (((textureInternalFormatInfo.componentType == GL_INT) != (framebufferInternalFormatInfo.componentType == GL_INT )) || - ((textureInternalFormatInfo.componentType == GL_UNSIGNED_INT) != (framebufferInternalFormatInfo.componentType == GL_UNSIGNED_INT))) + // 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 = nullptr; + if (readBufferHandle != 0) + { + // Not the default framebuffer, therefore the read buffer must be a user-created texture or + // renderbuffer + if (framebufferFormatInfo.sized) { - return false; + sourceEffectiveFormat = &framebufferFormatInfo; } - - 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)) + else { - return false; + // 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. + sourceEffectiveFormat = + &GetSizedInternalFormatInfo(framebufferFormatInfo.sizedInternalFormat); } - - // 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. - InternalFormat sourceEffectiveFormat; - if (readBufferHandle != 0) + } + 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 (framebufferFormatInfo.colorEncoding == GL_LINEAR) { - // Not the default framebuffer, therefore the read buffer must be a user-created texture or renderbuffer - if (framebufferInternalFormatInfo.pixelBytes > 0) + GLenum effectiveFormat; + if (GetEffectiveInternalFormat(framebufferFormatInfo, textureFormatInfo, + &effectiveFormat)) { - sourceEffectiveFormat = framebufferInternalFormatInfo; + sourceEffectiveFormat = &GetSizedInternalFormatInfo(effectiveFormat); } 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); + return false; } } - else + else if (framebufferFormatInfo.colorEncoding == GL_SRGB) { - // 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) + // SRGB buffers can only be copied to sized format destinations according to table 3.18 + if (textureFormatInfo.sized && + (framebufferFormatInfo.redBits >= 1 && framebufferFormatInfo.redBits <= 8) && + (framebufferFormatInfo.greenBits >= 1 && framebufferFormatInfo.greenBits <= 8) && + (framebufferFormatInfo.blueBits >= 1 && framebufferFormatInfo.blueBits <= 8) && + (framebufferFormatInfo.alphaBits >= 1 && framebufferFormatInfo.alphaBits <= 8)) { - 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; - } + sourceEffectiveFormat = &GetSizedInternalFormatInfo(GL_SRGB8_ALPHA8); } else { - UNREACHABLE(); return false; } } - - if (textureInternalFormatInfo.pixelBytes > 0) + else { - // 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; - } + UNREACHABLE(); + return false; } + } - - return true; // A conversion function exists, and no rule in the specification has precluded conversion - // between these formats. + if (textureFormatInfo.sized) + { + // 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 the + // destination format exists. + if (!EqualOrFirstZero(textureFormatInfo.redBits, sourceEffectiveFormat->redBits) || + !EqualOrFirstZero(textureFormatInfo.greenBits, sourceEffectiveFormat->greenBits) || + !EqualOrFirstZero(textureFormatInfo.blueBits, sourceEffectiveFormat->blueBits) || + !EqualOrFirstZero(textureFormatInfo.alphaBits, sourceEffectiveFormat->alphaBits)) + { + return false; + } } - return false; + return true; // A conversion function exists, and no rule in the specification has precluded + // conversion between these formats. } bool ValidateES3CopyTexImageParametersBase(ValidationContext *context, @@ -865,48 +790,50 @@ bool ValidateES3CopyTexImageParametersBase(ValidationContext *context, GLsizei height, GLint border) { - GLenum textureInternalFormat; + Format textureFormat = Format::Invalid(); if (!ValidateCopyTexImageParametersBase(context, target, level, internalformat, isSubImage, - xoffset, yoffset, zoffset, x, y, width, height, - border, &textureInternalFormat)) + xoffset, yoffset, zoffset, x, y, width, height, border, + &textureFormat)) { return false; } + ASSERT(textureFormat.valid() || !isSubImage); - const auto &state = context->getState(); - const gl::Framebuffer *framebuffer = state.getReadFramebuffer(); - GLuint readFramebufferID = framebuffer->id(); + const auto &state = context->getGLState(); + gl::Framebuffer *framebuffer = state.getReadFramebuffer(); + GLuint readFramebufferID = framebuffer->id(); - if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE) + if (framebuffer->checkStatus(context) != GL_FRAMEBUFFER_COMPLETE) { - context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION)); + context->handleError(InvalidFramebufferOperation()); return false; } - if (readFramebufferID != 0 && framebuffer->getSamples(context->getData()) != 0) + if (readFramebufferID != 0 && framebuffer->getSamples(context) != 0) { - context->recordError(Error(GL_INVALID_OPERATION)); + context->handleError(InvalidOperation()); return false; } - const gl::FramebufferAttachment *source = framebuffer->getReadColorbuffer(); - GLenum colorbufferInternalFormat = source->getInternalFormat(); + const FramebufferAttachment *source = framebuffer->getReadColorbuffer(); if (isSubImage) { - if (!IsValidES3CopyTexImageCombination(textureInternalFormat, colorbufferInternalFormat, + if (!IsValidES3CopyTexImageCombination(*textureFormat.info, *source->getFormat().info, readFramebufferID)) { - context->recordError(Error(GL_INVALID_OPERATION)); + context->handleError(InvalidOperation()); return false; } } else { - if (!gl::IsValidES3CopyTexImageCombination(internalformat, colorbufferInternalFormat, - readFramebufferID)) + // Use format/type from the source FBO. (Might not be perfect for all cases?) + const InternalFormat &framebufferFormat = *source->getFormat().info; + const InternalFormat ©Format = GetInternalFormatInfo(internalformat, GL_UNSIGNED_BYTE); + if (!IsValidES3CopyTexImageCombination(copyFormat, framebufferFormat, readFramebufferID)) { - context->recordError(Error(GL_INVALID_OPERATION)); + context->handleError(InvalidOperation()); return false; } } @@ -931,7 +858,7 @@ bool ValidateES3CopyTexImage2DParameters(ValidationContext *context, { if (!ValidTexture2DDestinationTarget(context, target)) { - context->recordError(Error(GL_INVALID_ENUM)); + context->handleError(InvalidEnum()); return false; } @@ -956,7 +883,7 @@ bool ValidateES3CopyTexImage3DParameters(ValidationContext *context, { if (!ValidTexture3DDestinationTarget(context, target)) { - context->recordError(Error(GL_INVALID_ENUM)); + context->handleError(InvalidEnum()); return false; } @@ -975,7 +902,7 @@ bool ValidateES3TexStorageParametersBase(Context *context, { if (width < 1 || height < 1 || depth < 1 || levels < 1) { - context->recordError(Error(GL_INVALID_VALUE)); + context->handleError(InvalidValue()); return false; } @@ -987,7 +914,7 @@ bool ValidateES3TexStorageParametersBase(Context *context, if (levels > gl::log2(maxDim) + 1) { - context->recordError(Error(GL_INVALID_OPERATION)); + context->handleError(InvalidOperation()); return false; } @@ -995,85 +922,102 @@ bool ValidateES3TexStorageParametersBase(Context *context, switch (target) { - case GL_TEXTURE_2D: + case GL_TEXTURE_2D: { if (static_cast(width) > caps.max2DTextureSize || static_cast(height) > caps.max2DTextureSize) { - context->recordError(Error(GL_INVALID_VALUE)); + context->handleError(InvalidValue()); + return false; + } + } + break; + + case GL_TEXTURE_RECTANGLE_ANGLE: + { + if (static_cast(width) > caps.maxRectangleTextureSize || + static_cast(height) > caps.maxRectangleTextureSize || levels != 1) + { + context->handleError(InvalidValue()); return false; } } break; - case GL_TEXTURE_CUBE_MAP: + case GL_TEXTURE_CUBE_MAP: { if (width != height) { - context->recordError(Error(GL_INVALID_VALUE)); + context->handleError(InvalidValue()); return false; } if (static_cast(width) > caps.maxCubeMapTextureSize) { - context->recordError(Error(GL_INVALID_VALUE)); + context->handleError(InvalidValue()); return false; } } break; - case GL_TEXTURE_3D: + 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)); + context->handleError(InvalidValue()); return false; } } break; - case GL_TEXTURE_2D_ARRAY: + 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)); + context->handleError(InvalidValue()); return false; } } break; - default: - UNREACHABLE(); - return false; + default: + UNREACHABLE(); + return false; } gl::Texture *texture = context->getTargetTexture(target); if (!texture || texture->id() == 0) { - context->recordError(Error(GL_INVALID_OPERATION)); + context->handleError(InvalidOperation()); return false; } if (texture->getImmutableFormat()) { - context->recordError(Error(GL_INVALID_OPERATION)); + context->handleError(InvalidOperation()); return false; } - const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat); + const gl::InternalFormat &formatInfo = gl::GetSizedInternalFormatInfo(internalformat); if (!formatInfo.textureSupport(context->getClientVersion(), context->getExtensions())) { - context->recordError(Error(GL_INVALID_ENUM)); + context->handleError(InvalidEnum()); + return false; + } + + if (!formatInfo.sized) + { + context->handleError(InvalidEnum()); return false; } - if (formatInfo.pixelBytes == 0) + if (formatInfo.compressed && target == GL_TEXTURE_RECTANGLE_ANGLE) { - context->recordError(Error(GL_INVALID_ENUM)); + context->handleError(InvalidEnum() << "Rectangle texture cannot have a compressed format."); return false; } @@ -1090,7 +1034,7 @@ bool ValidateES3TexStorage2DParameters(Context *context, { if (!ValidTexture2DTarget(context, target)) { - context->recordError(Error(GL_INVALID_ENUM)); + context->handleError(InvalidEnum()); return false; } @@ -1108,7 +1052,7 @@ bool ValidateES3TexStorage3DParameters(Context *context, { if (!ValidTexture3DTarget(context, target)) { - context->recordError(Error(GL_INVALID_ENUM)); + context->handleError(InvalidEnum()); return false; } @@ -1116,33 +1060,11 @@ bool ValidateES3TexStorage3DParameters(Context *context, height, depth); } -bool ValidateGenQueries(gl::Context *context, GLsizei n, const GLuint *ids) -{ - if (context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_OPERATION, "GLES version < 3.0")); - return false; - } - - return ValidateGenQueriesBase(context, n, ids); -} - -bool ValidateDeleteQueries(gl::Context *context, GLsizei n, const GLuint *ids) -{ - if (context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_OPERATION, "GLES version < 3.0")); - return false; - } - - return ValidateDeleteQueriesBase(context, n, ids); -} - bool ValidateBeginQuery(gl::Context *context, GLenum target, GLuint id) { - if (context->getClientVersion() < 3) + if (context->getClientMajorVersion() < 3) { - context->recordError(Error(GL_INVALID_OPERATION, "GLES version < 3.0")); + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); return false; } @@ -1151,9 +1073,9 @@ bool ValidateBeginQuery(gl::Context *context, GLenum target, GLuint id) bool ValidateEndQuery(gl::Context *context, GLenum target) { - if (context->getClientVersion() < 3) + if (context->getClientMajorVersion() < 3) { - context->recordError(Error(GL_INVALID_OPERATION, "GLES version < 3.0")); + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); return false; } @@ -1162,38 +1084,36 @@ bool ValidateEndQuery(gl::Context *context, GLenum target) bool ValidateGetQueryiv(Context *context, GLenum target, GLenum pname, GLint *params) { - if (context->getClientVersion() < 3) + if (context->getClientMajorVersion() < 3) { - context->recordError(Error(GL_INVALID_OPERATION, "GLES version < 3.0")); + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); return false; } - return ValidateGetQueryivBase(context, target, pname); + return ValidateGetQueryivBase(context, target, pname, nullptr); } bool ValidateGetQueryObjectuiv(Context *context, GLuint id, GLenum pname, GLuint *params) { - if (context->getClientVersion() < 3) + if (context->getClientMajorVersion() < 3) { - context->recordError(Error(GL_INVALID_OPERATION, "GLES version < 3.0")); + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); return false; } - return ValidateGetQueryObjectValueBase(context, id, pname); + return ValidateGetQueryObjectValueBase(context, id, pname, nullptr); } -bool ValidateFramebufferTextureLayer(Context *context, GLenum target, GLenum attachment, - GLuint texture, GLint level, GLint layer) +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) + if (context->getClientMajorVersion() < 3) { - context->recordError(Error(GL_INVALID_VALUE)); + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); return false; } @@ -1205,52 +1125,58 @@ bool ValidateFramebufferTextureLayer(Context *context, GLenum target, GLenum att const gl::Caps &caps = context->getCaps(); if (texture != 0) { + if (layer < 0) + { + context->handleError(InvalidValue()); + return false; + } + gl::Texture *tex = context->getTexture(texture); ASSERT(tex); switch (tex->getTarget()) { - case GL_TEXTURE_2D_ARRAY: + case GL_TEXTURE_2D_ARRAY: { if (level > gl::log2(caps.max2DTextureSize)) { - context->recordError(Error(GL_INVALID_VALUE)); + context->handleError(InvalidValue()); return false; } if (static_cast(layer) >= caps.maxArrayTextureLayers) { - context->recordError(Error(GL_INVALID_VALUE)); + context->handleError(InvalidValue()); return false; } } break; - case GL_TEXTURE_3D: + case GL_TEXTURE_3D: { if (level > gl::log2(caps.max3DTextureSize)) { - context->recordError(Error(GL_INVALID_VALUE)); + context->handleError(InvalidValue()); return false; } if (static_cast(layer) >= caps.max3DTextureSize) { - context->recordError(Error(GL_INVALID_VALUE)); + context->handleError(InvalidValue()); return false; } } break; - default: - context->recordError(Error(GL_INVALID_OPERATION)); - return false; + default: + context->handleError(InvalidOperation()); + return false; } - const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(tex->getInternalFormat(tex->getTarget(), level)); - if (internalFormatInfo.compressed) + const auto &format = tex->getFormat(tex->getTarget(), level); + if (format.info->compressed) { - context->recordError(Error(GL_INVALID_OPERATION)); + context->handleError(InvalidOperation()); return false; } } @@ -1258,161 +1184,114 @@ bool ValidateFramebufferTextureLayer(Context *context, GLenum target, GLenum att return true; } -bool ValidES3ReadFormatType(Context *context, GLenum internalFormat, GLenum format, GLenum type) +bool ValidateInvalidateFramebuffer(Context *context, + GLenum target, + GLsizei numAttachments, + const GLenum *attachments) { - const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(internalFormat); + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + bool defaultFramebuffer = false; - switch (format) + switch (target) { - 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: + case GL_DRAW_FRAMEBUFFER: + case GL_FRAMEBUFFER: + defaultFramebuffer = context->getGLState().getDrawFramebuffer()->id() == 0; 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: + case GL_READ_FRAMEBUFFER: + defaultFramebuffer = context->getGLState().getReadFramebuffer()->id() == 0; break; default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidFramebufferTarget); return false; - } - break; - default: - return false; } - return true; + + return ValidateDiscardFramebufferBase(context, target, numAttachments, attachments, + defaultFramebuffer); } -bool ValidateES3RenderbufferStorageParameters(gl::Context *context, GLenum target, GLsizei samples, - GLenum internalformat, GLsizei width, GLsizei height) +bool ValidateInvalidateSubFramebuffer(Context *context, + GLenum target, + GLsizei numAttachments, + const GLenum *attachments, + GLint x, + GLint y, + GLsizei width, + GLsizei height) { - if (!ValidateRenderbufferStorageParametersBase(context, target, samples, internalformat, width, height)) - { - return false; - } + return ValidateInvalidateFramebuffer(context, target, numAttachments, attachments); +} - //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) +bool ValidateClearBuffer(ValidationContext *context) +{ + if (context->getClientMajorVersion() < 3) { - context->recordError(Error(GL_INVALID_OPERATION)); + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); 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()) + if (context->getGLState().getDrawFramebuffer()->checkStatus(context) != GL_FRAMEBUFFER_COMPLETE) { - context->recordError(Error(GL_INVALID_VALUE)); + context->handleError(InvalidFramebufferOperation()); return false; } return true; } -bool ValidateInvalidateFramebuffer(Context *context, GLenum target, GLsizei numAttachments, - const GLenum *attachments) +bool ValidateDrawRangeElements(Context *context, + GLenum mode, + GLuint start, + GLuint end, + GLsizei count, + GLenum type, + const void *indices) { - if (context->getClientVersion() < 3) + if (context->getClientMajorVersion() < 3) { - context->recordError(Error(GL_INVALID_OPERATION, "Operation only supported on ES 3.0 and above")); + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); return false; } - bool defaultFramebuffer = false; - - switch (target) + if (end < start) { - 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, "Invalid framebuffer target")); + context->handleError(InvalidValue() << "end < start"); return false; } - return ValidateDiscardFramebufferBase(context, target, numAttachments, attachments, defaultFramebuffer); -} - -bool ValidateClearBuffer(ValidationContext *context) -{ - if (context->getClientVersion() < 3) + if (!ValidateDrawElementsCommon(context, mode, count, type, indices, 0)) { - context->recordError(Error(GL_INVALID_OPERATION)); return false; } - const gl::Framebuffer *fbo = context->getState().getDrawFramebuffer(); - if (!fbo || fbo->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE) + // Use the parameter buffer to retrieve and cache the index range. + const auto ¶ms = context->getParams(); + const auto &indexRangeOpt = params.getIndexRange(); + if (!indexRangeOpt.valid()) { - context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION)); + // Unexpected error. return false; } + if (indexRangeOpt.value().end > end || indexRangeOpt.value().start < start) + { + // GL spec says that behavior in this case is undefined - generating an error is fine. + context->handleError(InvalidOperation() << "Indices are out of the start, end range."); + return false; + } return true; } -bool ValidateGetUniformuiv(Context *context, GLuint program, GLint location, GLuint* params) +bool ValidateGetUniformuiv(Context *context, GLuint program, GLint location, GLuint *params) { - if (context->getClientVersion() < 3) + if (context->getClientMajorVersion() < 3) { - context->recordError(Error(GL_INVALID_OPERATION)); + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); return false; } @@ -1421,17 +1300,17 @@ bool ValidateGetUniformuiv(Context *context, GLuint program, GLint location, GLu bool ValidateReadBuffer(Context *context, GLenum src) { - if (context->getClientVersion() < 3) + if (context->getClientMajorVersion() < 3) { - context->recordError(Error(GL_INVALID_OPERATION)); + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); return false; } - Framebuffer *readFBO = context->getState().getReadFramebuffer(); + const Framebuffer *readFBO = context->getGLState().getReadFramebuffer(); if (readFBO == nullptr) { - context->recordError(gl::Error(GL_INVALID_OPERATION, "No active read framebuffer.")); + context->handleError(InvalidOperation() << "No active read framebuffer."); return false; } @@ -1440,9 +1319,9 @@ bool ValidateReadBuffer(Context *context, GLenum src) return true; } - if (src != GL_BACK && (src < GL_COLOR_ATTACHMENT0 || src > GL_COLOR_ATTACHMENT15)) + if (src != GL_BACK && (src < GL_COLOR_ATTACHMENT0 || src > GL_COLOR_ATTACHMENT31)) { - context->recordError(gl::Error(GL_INVALID_ENUM, "Unknown enum for 'src' in ReadBuffer")); + context->handleError(InvalidEnum() << "Unknown enum for 'src' in ReadBuffer"); return false; } @@ -1450,8 +1329,9 @@ bool ValidateReadBuffer(Context *context, GLenum src) { 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)); + context->handleError( + InvalidOperation() + << "'src' must be GL_NONE or GL_BACK when reading from the default framebuffer."); return false; } } @@ -1461,8 +1341,7 @@ bool ValidateReadBuffer(Context *context, GLenum src) if (drawBuffer >= context->getCaps().maxDrawBuffers) { - const char *errorMsg = "'src' is greater than MAX_DRAW_BUFFERS."; - context->recordError(gl::Error(GL_INVALID_OPERATION, errorMsg)); + context->handleError(InvalidOperation() << "'src' is greater than MAX_DRAW_BUFFERS."); return false; } } @@ -1479,34 +1358,57 @@ bool ValidateCompressedTexImage3D(Context *context, GLsizei depth, GLint border, GLsizei imageSize, - const GLvoid *data) + const void *data) { - if (context->getClientVersion() < 3) + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + if (!ValidTextureTarget(context, target)) + { + context->handleError(InvalidEnum()); + return false; + } + + // Validate image size + if (!ValidImageSizeParameters(context, target, level, width, height, depth, false)) + { + context->handleError(InvalidValue()); + return false; + } + + const InternalFormat &formatInfo = GetSizedInternalFormatInfo(internalformat); + if (!formatInfo.compressed) { - context->recordError(Error(GL_INVALID_OPERATION)); + context->handleError(InvalidEnum() << "Not a valid compressed texture format"); return false; } - const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat); - if (imageSize < 0 || - static_cast(imageSize) != - formatInfo.computeBlockSize(GL_UNSIGNED_BYTE, width, height)) + auto blockSizeOrErr = formatInfo.computeCompressedImageSize(gl::Extents(width, height, depth)); + if (blockSizeOrErr.isError()) + { + context->handleError(InvalidValue()); + return false; + } + if (imageSize < 0 || static_cast(imageSize) != blockSizeOrErr.getResult()) { - context->recordError(Error(GL_INVALID_VALUE)); + context->handleError(InvalidValue()); return false; } // 3D texture target validation if (target != GL_TEXTURE_3D && target != GL_TEXTURE_2D_ARRAY) { - context->recordError( - Error(GL_INVALID_ENUM, "Must specify a valid 3D texture destination target")); + context->handleError(InvalidEnum() << "Must specify a valid 3D texture destination target"); return false; } // validateES3TexImageFormat sets the error code if there is an error if (!ValidateES3TexImage3DParameters(context, target, level, internalformat, true, false, 0, 0, - 0, width, height, depth, border, GL_NONE, GL_NONE, data)) + 0, width, height, depth, border, GL_NONE, GL_NONE, -1, + data)) { return false; } @@ -1514,59 +1416,207 @@ bool ValidateCompressedTexImage3D(Context *context, return true; } -bool ValidateBindVertexArray(Context *context, GLuint array) +bool ValidateCompressedTexImage3DRobustANGLE(Context *context, + GLenum target, + GLint level, + GLenum internalformat, + GLsizei width, + GLsizei height, + GLsizei depth, + GLint border, + GLsizei imageSize, + GLsizei dataSize, + const void *data) { - if (context->getClientVersion() < 3) + if (!ValidateRobustCompressedTexImageBase(context, imageSize, dataSize)) { - context->recordError(Error(GL_INVALID_OPERATION)); return false; } - return ValidateBindVertexArrayBase(context, array); + return ValidateCompressedTexImage3D(context, target, level, internalformat, width, height, + depth, border, imageSize, data); } -bool ValidateDeleteVertexArrays(Context *context, GLsizei n) +bool ValidateBindVertexArray(Context *context, GLuint array) { - if (context->getClientVersion() < 3) + if (context->getClientMajorVersion() < 3) { - context->recordError(Error(GL_INVALID_OPERATION)); + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); return false; } - return ValidateDeleteVertexArraysBase(context, n); + return ValidateBindVertexArrayBase(context, array); } -bool ValidateGenVertexArrays(Context *context, GLsizei n) +bool ValidateIsVertexArray(Context *context, GLuint array) { - if (context->getClientVersion() < 3) + if (context->getClientMajorVersion() < 3) { - context->recordError(Error(GL_INVALID_OPERATION)); + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); return false; } - return ValidateGenVertexArraysBase(context, n); + return true; } -bool ValidateIsVertexArray(Context *context) +static bool ValidateBindBufferCommon(Context *context, + BufferBinding target, + GLuint index, + GLuint buffer, + GLintptr offset, + GLsizeiptr size) { - if (context->getClientVersion() < 3) + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + if (buffer != 0 && offset < 0) + { + context->handleError(InvalidValue() << "buffer is non-zero and offset is negative."); + return false; + } + + if (!context->getGLState().isBindGeneratesResourceEnabled() && + !context->isBufferGenerated(buffer)) { - context->recordError(Error(GL_INVALID_OPERATION)); + context->handleError(InvalidOperation() << "Buffer was not generated."); return false; } + const Caps &caps = context->getCaps(); + switch (target) + { + case BufferBinding::TransformFeedback: + { + if (index >= caps.maxTransformFeedbackSeparateAttributes) + { + context->handleError(InvalidValue() << "index is greater than or equal to the " + "number of TRANSFORM_FEEDBACK_BUFFER " + "indexed binding points."); + return false; + } + if (buffer != 0 && ((offset % 4) != 0 || (size % 4) != 0)) + { + context->handleError(InvalidValue() << "offset and size must be multiple of 4."); + return false; + } + + TransformFeedback *curTransformFeedback = + context->getGLState().getCurrentTransformFeedback(); + if (curTransformFeedback && curTransformFeedback->isActive()) + { + context->handleError(InvalidOperation() + << "target is TRANSFORM_FEEDBACK_BUFFER and transform " + "feedback is currently active."); + return false; + } + break; + } + case BufferBinding::Uniform: + { + if (index >= caps.maxUniformBufferBindings) + { + context->handleError(InvalidValue() << "index is greater than or equal to the " + "number of UNIFORM_BUFFER indexed " + "binding points."); + return false; + } + + if (buffer != 0 && (offset % caps.uniformBufferOffsetAlignment) != 0) + { + context->handleError( + InvalidValue() + << "offset must be multiple of value of UNIFORM_BUFFER_OFFSET_ALIGNMENT."); + return false; + } + break; + } + case BufferBinding::AtomicCounter: + { + if (context->getClientVersion() < ES_3_1) + { + context->handleError(InvalidEnum() + << "ATOMIC_COUNTER_BUFFER is not supported before GLES 3.1"); + return false; + } + if (index >= caps.maxAtomicCounterBufferBindings) + { + context->handleError(InvalidValue() << "index is greater than or equal to the " + "number of ATOMIC_COUNTER_BUFFER " + "indexed binding points."); + return false; + } + if (buffer != 0 && (offset % 4) != 0) + { + context->handleError(InvalidValue() << "offset must be a multiple of 4."); + return false; + } + break; + } + case BufferBinding::ShaderStorage: + { + if (context->getClientVersion() < ES_3_1) + { + context->handleError(InvalidEnum() + << "SHADER_STORAGE_BUFFER is not supported in GLES3."); + return false; + } + if (index >= caps.maxShaderStorageBufferBindings) + { + context->handleError(InvalidValue() << "index is greater than or equal to the " + "number of SHADER_STORAGE_BUFFER " + "indexed binding points."); + return false; + } + if (buffer != 0 && (offset % caps.shaderStorageBufferOffsetAlignment) != 0) + { + context->handleError(InvalidValue() << "offset must be multiple of value of " + "SHADER_STORAGE_BUFFER_OFFSET_" + "ALIGNMENT."); + return false; + } + break; + } + default: + context->handleError(InvalidEnum() << "the target is not supported."); + return false; + } + return true; } +bool ValidateBindBufferBase(Context *context, BufferBinding target, GLuint index, GLuint buffer) +{ + return ValidateBindBufferCommon(context, target, index, buffer, 0, 0); +} + +bool ValidateBindBufferRange(Context *context, + BufferBinding target, + GLuint index, + GLuint buffer, + GLintptr offset, + GLsizeiptr size) +{ + if (buffer != 0 && size <= 0) + { + context->handleError(InvalidValue() + << "buffer is non-zero and size is less than or equal to zero."); + return false; + } + return ValidateBindBufferCommon(context, target, index, buffer, offset, size); +} + bool ValidateProgramBinary(Context *context, GLuint program, GLenum binaryFormat, const void *binary, GLint length) { - if (context->getClientVersion() < 3) + if (context->getClientMajorVersion() < 3) { - context->recordError(Error(GL_INVALID_OPERATION)); + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); return false; } @@ -1580,20 +1630,20 @@ bool ValidateGetProgramBinary(Context *context, GLenum *binaryFormat, void *binary) { - if (context->getClientVersion() < 3) + if (context->getClientMajorVersion() < 3) { - context->recordError(Error(GL_INVALID_OPERATION)); + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); return false; } return ValidateGetProgramBinaryBase(context, program, bufSize, length, binaryFormat, binary); } -bool ValidateProgramParameter(Context *context, GLuint program, GLenum pname, GLint value) +bool ValidateProgramParameteri(Context *context, GLuint program, GLenum pname, GLint value) { - if (context->getClientVersion() < 3) + if (context->getClientMajorVersion() < 3) { - context->recordError(Error(GL_INVALID_OPERATION)); + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); return false; } @@ -1605,10 +1655,33 @@ bool ValidateProgramParameter(Context *context, GLuint program, GLenum pname, GL switch (pname) { case GL_PROGRAM_BINARY_RETRIEVABLE_HINT: + if (value != GL_FALSE && value != GL_TRUE) + { + context->handleError(InvalidValue() + << "Invalid value, expected GL_FALSE or GL_TRUE: " << value); + return false; + } + break; + + case GL_PROGRAM_SEPARABLE: + if (context->getClientVersion() < ES_3_1) + { + context->handleError(InvalidEnum() + << "PROGRAM_SEPARABLE is not supported before GLES 3.1"); + return false; + } + + if (value != GL_FALSE && value != GL_TRUE) + { + context->handleError(InvalidValue() + << "Invalid value, expected GL_FALSE or GL_TRUE: " << value); + return false; + } break; default: - context->recordError(Error(GL_INVALID_ENUM, "Invalid pname: 0x%X", pname)); + context->handleError(InvalidEnum() + << "Invalid pname: 0x" << std::hex << std::uppercase << pname); return false; } @@ -1627,9 +1700,9 @@ bool ValidateBlitFramebuffer(Context *context, GLbitfield mask, GLenum filter) { - if (context->getClientVersion() < 3) + if (context->getClientMajorVersion() < 3) { - context->recordError(Error(GL_INVALID_OPERATION)); + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); return false; } @@ -1648,21 +1721,30 @@ bool ValidateClearBufferiv(ValidationContext *context, if (drawbuffer < 0 || static_cast(drawbuffer) >= context->getCaps().maxDrawBuffers) { - context->recordError(Error(GL_INVALID_VALUE)); + context->handleError(InvalidValue()); return false; } + if (context->getExtensions().webglCompatibility) + { + constexpr GLenum validComponentTypes[] = {GL_INT}; + if (!ValidateWebGLFramebufferAttachmentClearType( + context, drawbuffer, validComponentTypes, ArraySize(validComponentTypes))) + { + return false; + } + } break; case GL_STENCIL: if (drawbuffer != 0) { - context->recordError(Error(GL_INVALID_VALUE)); + context->handleError(InvalidValue()); return false; } break; default: - context->recordError(Error(GL_INVALID_ENUM)); + context->handleError(InvalidEnum()); return false; } @@ -1680,13 +1762,22 @@ bool ValidateClearBufferuiv(ValidationContext *context, if (drawbuffer < 0 || static_cast(drawbuffer) >= context->getCaps().maxDrawBuffers) { - context->recordError(Error(GL_INVALID_VALUE)); + context->handleError(InvalidValue()); return false; } + if (context->getExtensions().webglCompatibility) + { + constexpr GLenum validComponentTypes[] = {GL_UNSIGNED_INT}; + if (!ValidateWebGLFramebufferAttachmentClearType( + context, drawbuffer, validComponentTypes, ArraySize(validComponentTypes))) + { + return false; + } + } break; default: - context->recordError(Error(GL_INVALID_ENUM)); + context->handleError(InvalidEnum()); return false; } @@ -1704,21 +1795,31 @@ bool ValidateClearBufferfv(ValidationContext *context, if (drawbuffer < 0 || static_cast(drawbuffer) >= context->getCaps().maxDrawBuffers) { - context->recordError(Error(GL_INVALID_VALUE)); + context->handleError(InvalidValue()); return false; } + if (context->getExtensions().webglCompatibility) + { + constexpr GLenum validComponentTypes[] = {GL_FLOAT, GL_UNSIGNED_NORMALIZED, + GL_SIGNED_NORMALIZED}; + if (!ValidateWebGLFramebufferAttachmentClearType( + context, drawbuffer, validComponentTypes, ArraySize(validComponentTypes))) + { + return false; + } + } break; case GL_DEPTH: if (drawbuffer != 0) { - context->recordError(Error(GL_INVALID_VALUE)); + context->handleError(InvalidValue()); return false; } break; default: - context->recordError(Error(GL_INVALID_ENUM)); + context->handleError(InvalidEnum()); return false; } @@ -1736,13 +1837,13 @@ bool ValidateClearBufferfi(ValidationContext *context, case GL_DEPTH_STENCIL: if (drawbuffer != 0) { - context->recordError(Error(GL_INVALID_VALUE)); + context->handleError(InvalidValue()); return false; } break; default: - context->recordError(Error(GL_INVALID_ENUM)); + context->handleError(InvalidEnum()); return false; } @@ -1751,9 +1852,9 @@ bool ValidateClearBufferfi(ValidationContext *context, bool ValidateDrawBuffers(ValidationContext *context, GLsizei n, const GLenum *bufs) { - if (context->getClientVersion() < 3) + if (context->getClientMajorVersion() < 3) { - context->recordError(Error(GL_INVALID_OPERATION, "Context does not support GLES3.")); + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); return false; } @@ -1771,9 +1872,9 @@ bool ValidateCopyTexSubImage3D(Context *context, GLsizei width, GLsizei height) { - if (context->getClientVersion() < 3) + if (context->getClientMajorVersion() < 3) { - context->recordError(Error(GL_INVALID_OPERATION)); + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); return false; } @@ -1781,4 +1882,1821 @@ bool ValidateCopyTexSubImage3D(Context *context, yoffset, zoffset, x, y, width, height, 0); } +bool ValidateTexImage3D(Context *context, + GLenum target, + GLint level, + GLint internalformat, + GLsizei width, + GLsizei height, + GLsizei depth, + GLint border, + GLenum format, + GLenum type, + const void *pixels) +{ + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + return ValidateES3TexImage3DParameters(context, target, level, internalformat, false, false, 0, + 0, 0, width, height, depth, border, format, type, -1, + pixels); +} + +bool ValidateTexImage3DRobustANGLE(Context *context, + GLenum target, + GLint level, + GLint internalformat, + GLsizei width, + GLsizei height, + GLsizei depth, + GLint border, + GLenum format, + GLenum type, + GLsizei bufSize, + const void *pixels) +{ + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + if (!ValidateRobustEntryPoint(context, bufSize)) + { + return false; + } + + return ValidateES3TexImage3DParameters(context, target, level, internalformat, false, false, 0, + 0, 0, width, height, depth, border, format, type, + bufSize, pixels); +} + +bool ValidateTexSubImage3D(Context *context, + GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLint zoffset, + GLsizei width, + GLsizei height, + GLsizei depth, + GLenum format, + GLenum type, + const void *pixels) +{ + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + return ValidateES3TexImage3DParameters(context, target, level, GL_NONE, false, true, xoffset, + yoffset, zoffset, width, height, depth, 0, format, type, + -1, pixels); +} + +bool ValidateTexSubImage3DRobustANGLE(Context *context, + GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLint zoffset, + GLsizei width, + GLsizei height, + GLsizei depth, + GLenum format, + GLenum type, + GLsizei bufSize, + const void *pixels) +{ + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + if (!ValidateRobustEntryPoint(context, bufSize)) + { + return false; + } + + return ValidateES3TexImage3DParameters(context, target, level, GL_NONE, false, true, xoffset, + yoffset, zoffset, width, height, depth, 0, format, type, + bufSize, pixels); +} + +bool ValidateCompressedTexSubImage3D(Context *context, + GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLint zoffset, + GLsizei width, + GLsizei height, + GLsizei depth, + GLenum format, + GLsizei imageSize, + const void *data) +{ + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + const InternalFormat &formatInfo = GetSizedInternalFormatInfo(format); + if (!formatInfo.compressed) + { + context->handleError(InvalidEnum() << "Not a valid compressed texture format"); + return false; + } + + auto blockSizeOrErr = formatInfo.computeCompressedImageSize(gl::Extents(width, height, depth)); + if (blockSizeOrErr.isError()) + { + context->handleError(blockSizeOrErr.getError()); + return false; + } + if (imageSize < 0 || static_cast(imageSize) != blockSizeOrErr.getResult()) + { + context->handleError(InvalidValue()); + return false; + } + + if (!data) + { + context->handleError(InvalidValue()); + return false; + } + + return ValidateES3TexImage3DParameters(context, target, level, GL_NONE, true, true, xoffset, + yoffset, zoffset, width, height, depth, 0, format, + GL_NONE, -1, data); +} +bool ValidateCompressedTexSubImage3DRobustANGLE(Context *context, + GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLint zoffset, + GLsizei width, + GLsizei height, + GLsizei depth, + GLenum format, + GLsizei imageSize, + GLsizei dataSize, + const void *data) +{ + if (!ValidateRobustCompressedTexImageBase(context, imageSize, dataSize)) + { + return false; + } + + return ValidateCompressedTexSubImage3D(context, target, level, xoffset, yoffset, zoffset, width, + height, depth, format, imageSize, data); +} + +bool ValidateGenQueries(Context *context, GLint n, GLuint *) +{ + return ValidateGenOrDeleteES3(context, n); +} + +bool ValidateDeleteQueries(Context *context, GLint n, const GLuint *) +{ + return ValidateGenOrDeleteES3(context, n); +} + +bool ValidateGenSamplers(Context *context, GLint count, GLuint *) +{ + return ValidateGenOrDeleteCountES3(context, count); +} + +bool ValidateDeleteSamplers(Context *context, GLint count, const GLuint *) +{ + return ValidateGenOrDeleteCountES3(context, count); +} + +bool ValidateGenTransformFeedbacks(Context *context, GLint n, GLuint *) +{ + return ValidateGenOrDeleteES3(context, n); +} + +bool ValidateDeleteTransformFeedbacks(Context *context, GLint n, const GLuint *ids) +{ + if (!ValidateGenOrDeleteES3(context, n)) + { + return false; + } + for (GLint i = 0; i < n; ++i) + { + auto *transformFeedback = context->getTransformFeedback(ids[i]); + if (transformFeedback != nullptr && transformFeedback->isActive()) + { + // ES 3.0.4 section 2.15.1 page 86 + context->handleError(InvalidOperation() + << "Attempt to delete active transform feedback."); + return false; + } + } + return true; +} + +bool ValidateGenVertexArrays(Context *context, GLint n, GLuint *) +{ + return ValidateGenOrDeleteES3(context, n); +} + +bool ValidateDeleteVertexArrays(Context *context, GLint n, const GLuint *) +{ + return ValidateGenOrDeleteES3(context, n); +} + +bool ValidateBeginTransformFeedback(Context *context, GLenum primitiveMode) +{ + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + switch (primitiveMode) + { + case GL_TRIANGLES: + case GL_LINES: + case GL_POINTS: + break; + + default: + context->handleError(InvalidEnum() << "Invalid primitive mode."); + return false; + } + + TransformFeedback *transformFeedback = context->getGLState().getCurrentTransformFeedback(); + ASSERT(transformFeedback != nullptr); + + if (transformFeedback->isActive()) + { + context->handleError(InvalidOperation() << "Transform feedback is already active."); + return false; + } + + for (size_t i = 0; i < transformFeedback->getIndexedBufferCount(); i++) + { + const auto &buffer = transformFeedback->getIndexedBuffer(i); + if (buffer.get() && buffer->isMapped()) + { + context->handleError(InvalidOperation() << "Transform feedback has a mapped buffer."); + return false; + } + } + + Program *program = context->getGLState().getProgram(); + + if (!program) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ProgramNotBound); + return false; + } + + if (program->getTransformFeedbackVaryingCount() == 0) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), NoTransformFeedbackOutputVariables); + return false; + } + + return true; +} + +bool ValidateGetBufferPointerv(Context *context, BufferBinding target, GLenum pname, void **params) +{ + return ValidateGetBufferPointervBase(context, target, pname, nullptr, params); +} + +bool ValidateGetBufferPointervRobustANGLE(Context *context, + BufferBinding target, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + void **params) +{ + if (!ValidateRobustEntryPoint(context, bufSize)) + { + return false; + } + + if (!ValidateGetBufferPointervBase(context, target, pname, length, params)) + { + return false; + } + + if (!ValidateRobustBufferSize(context, bufSize, *length)) + { + return false; + } + + return true; +} + +bool ValidateUnmapBuffer(Context *context, BufferBinding target) +{ + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + return ValidateUnmapBufferBase(context, target); +} + +bool ValidateMapBufferRange(Context *context, + BufferBinding target, + GLintptr offset, + GLsizeiptr length, + GLbitfield access) +{ + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + return ValidateMapBufferRangeBase(context, target, offset, length, access); +} + +bool ValidateFlushMappedBufferRange(Context *context, + BufferBinding target, + GLintptr offset, + GLsizeiptr length) +{ + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + return ValidateFlushMappedBufferRangeBase(context, target, offset, length); +} + +bool ValidateIndexedStateQuery(ValidationContext *context, + GLenum pname, + GLuint index, + GLsizei *length) +{ + if (length) + { + *length = 0; + } + + GLenum nativeType; + unsigned int numParams; + if (!context->getIndexedQueryParameterInfo(pname, &nativeType, &numParams)) + { + context->handleError(InvalidEnum()); + return false; + } + + const Caps &caps = context->getCaps(); + switch (pname) + { + case GL_TRANSFORM_FEEDBACK_BUFFER_START: + case GL_TRANSFORM_FEEDBACK_BUFFER_SIZE: + case GL_TRANSFORM_FEEDBACK_BUFFER_BINDING: + if (index >= caps.maxTransformFeedbackSeparateAttributes) + { + context->handleError(InvalidValue()); + return false; + } + break; + + case GL_UNIFORM_BUFFER_START: + case GL_UNIFORM_BUFFER_SIZE: + case GL_UNIFORM_BUFFER_BINDING: + if (index >= caps.maxUniformBufferBindings) + { + context->handleError(InvalidValue()); + return false; + } + break; + + case GL_MAX_COMPUTE_WORK_GROUP_SIZE: + case GL_MAX_COMPUTE_WORK_GROUP_COUNT: + if (index >= 3u) + { + context->handleError(InvalidValue()); + return false; + } + break; + + case GL_ATOMIC_COUNTER_BUFFER_START: + case GL_ATOMIC_COUNTER_BUFFER_SIZE: + case GL_ATOMIC_COUNTER_BUFFER_BINDING: + if (context->getClientVersion() < ES_3_1) + { + context->handleError( + InvalidEnum() + << "Atomic Counter buffers are not supported in this version of GL"); + return false; + } + if (index >= caps.maxAtomicCounterBufferBindings) + { + context->handleError( + InvalidValue() + << "index is outside the valid range for GL_ATOMIC_COUNTER_BUFFER_BINDING"); + return false; + } + break; + + case GL_SHADER_STORAGE_BUFFER_START: + case GL_SHADER_STORAGE_BUFFER_SIZE: + case GL_SHADER_STORAGE_BUFFER_BINDING: + if (context->getClientVersion() < ES_3_1) + { + context->handleError( + InvalidEnum() + << "Shader storage buffers are not supported in this version of GL"); + return false; + } + if (index >= caps.maxShaderStorageBufferBindings) + { + context->handleError( + InvalidValue() + << "index is outside the valid range for GL_SHADER_STORAGE_BUFFER_BINDING"); + return false; + } + break; + + case GL_VERTEX_BINDING_BUFFER: + case GL_VERTEX_BINDING_DIVISOR: + case GL_VERTEX_BINDING_OFFSET: + case GL_VERTEX_BINDING_STRIDE: + if (context->getClientVersion() < ES_3_1) + { + context->handleError( + InvalidEnum() + << "Vertex Attrib Bindings are not supported in this version of GL"); + return false; + } + if (index >= caps.maxVertexAttribBindings) + { + context->handleError( + InvalidValue() + << "bindingindex must be smaller than MAX_VERTEX_ATTRIB_BINDINGS."); + return false; + } + break; + case GL_SAMPLE_MASK_VALUE: + if (context->getClientVersion() < ES_3_1) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), EnumRequiresGLES31); + return false; + } + if (index >= caps.maxSampleMaskWords) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), InvalidSampleMaskNumber); + return false; + } + break; + default: + context->handleError(InvalidEnum()); + return false; + } + + if (length) + { + *length = 1; + } + + return true; +} + +bool ValidateGetIntegeri_v(ValidationContext *context, GLenum target, GLuint index, GLint *data) +{ + if (context->getClientVersion() < ES_3_0) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + return ValidateIndexedStateQuery(context, target, index, nullptr); +} + +bool ValidateGetIntegeri_vRobustANGLE(ValidationContext *context, + GLenum target, + GLuint index, + GLsizei bufSize, + GLsizei *length, + GLint *data) +{ + if (context->getClientVersion() < ES_3_0) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + if (!ValidateRobustEntryPoint(context, bufSize)) + { + return false; + } + + if (!ValidateIndexedStateQuery(context, target, index, length)) + { + return false; + } + + if (!ValidateRobustBufferSize(context, bufSize, *length)) + { + return false; + } + + return true; +} + +bool ValidateGetInteger64i_v(ValidationContext *context, GLenum target, GLuint index, GLint64 *data) +{ + if (context->getClientVersion() < ES_3_0) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + return ValidateIndexedStateQuery(context, target, index, nullptr); +} + +bool ValidateGetInteger64i_vRobustANGLE(ValidationContext *context, + GLenum target, + GLuint index, + GLsizei bufSize, + GLsizei *length, + GLint64 *data) +{ + if (context->getClientVersion() < ES_3_0) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + if (!ValidateRobustEntryPoint(context, bufSize)) + { + return false; + } + + if (!ValidateIndexedStateQuery(context, target, index, length)) + { + return false; + } + + if (!ValidateRobustBufferSize(context, bufSize, *length)) + { + return false; + } + + return true; +} + +bool ValidateCopyBufferSubData(ValidationContext *context, + BufferBinding readTarget, + BufferBinding writeTarget, + GLintptr readOffset, + GLintptr writeOffset, + GLsizeiptr size) +{ + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + if (!ValidBufferType(context, readTarget) || !ValidBufferType(context, writeTarget)) + { + context->handleError(InvalidEnum() << "Invalid buffer target"); + return false; + } + + Buffer *readBuffer = context->getGLState().getTargetBuffer(readTarget); + Buffer *writeBuffer = context->getGLState().getTargetBuffer(writeTarget); + + if (!readBuffer || !writeBuffer) + { + context->handleError(InvalidOperation() << "No buffer bound to target"); + return false; + } + + // Verify that readBuffer and writeBuffer are not currently mapped + if (readBuffer->isMapped() || writeBuffer->isMapped()) + { + context->handleError(InvalidOperation() + << "Cannot call CopyBufferSubData on a mapped buffer"); + return false; + } + + CheckedNumeric checkedReadOffset(readOffset); + CheckedNumeric checkedWriteOffset(writeOffset); + CheckedNumeric checkedSize(size); + + auto checkedReadSum = checkedReadOffset + checkedSize; + auto checkedWriteSum = checkedWriteOffset + checkedSize; + + if (!checkedReadSum.IsValid() || !checkedWriteSum.IsValid() || + !IsValueInRangeForNumericType(readBuffer->getSize()) || + !IsValueInRangeForNumericType(writeBuffer->getSize())) + { + context->handleError(InvalidValue() << "Integer overflow when validating copy offsets."); + return false; + } + + if (readOffset < 0 || writeOffset < 0 || size < 0) + { + context->handleError(InvalidValue() + << "readOffset, writeOffset and size must all be non-negative"); + return false; + } + + if (checkedReadSum.ValueOrDie() > readBuffer->getSize() || + checkedWriteSum.ValueOrDie() > writeBuffer->getSize()) + { + context->handleError(InvalidValue() << "Buffer offset overflow in CopyBufferSubData"); + return false; + } + + if (readBuffer == writeBuffer) + { + auto checkedOffsetDiff = (checkedReadOffset - checkedWriteOffset).Abs(); + if (!checkedOffsetDiff.IsValid()) + { + // This shold not be possible. + UNREACHABLE(); + context->handleError(InvalidValue() + << "Integer overflow when validating same buffer copy."); + return false; + } + + if (checkedOffsetDiff.ValueOrDie() < size) + { + context->handleError(InvalidValue()); + return false; + } + } + + return true; +} + +bool ValidateGetStringi(Context *context, GLenum name, GLuint index) +{ + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + switch (name) + { + case GL_EXTENSIONS: + if (index >= context->getExtensionStringCount()) + { + context->handleError(InvalidValue() + << "index must be less than the number of extension strings."); + return false; + } + break; + + case GL_REQUESTABLE_EXTENSIONS_ANGLE: + if (!context->getExtensions().requestExtension) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidName); + return false; + } + if (index >= context->getRequestableExtensionStringCount()) + { + context->handleError( + InvalidValue() + << "index must be less than the number of requestable extension strings."); + return false; + } + break; + + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidName); + return false; + } + + return true; +} + +bool ValidateRenderbufferStorageMultisample(ValidationContext *context, + GLenum target, + GLsizei samples, + GLenum internalformat, + GLsizei width, + GLsizei height) +{ + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + 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::GetSizedInternalFormatInfo(internalformat); + if ((formatInfo.componentType == GL_UNSIGNED_INT || formatInfo.componentType == GL_INT) && + samples > 0) + { + context->handleError(InvalidOperation()); + 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->handleError( + InvalidOperation() + << "Samples must not be greater than maximum supported value for the format."); + return false; + } + + return true; +} + +bool ValidateVertexAttribIPointer(ValidationContext *context, + GLuint index, + GLint size, + GLenum type, + GLsizei stride, + const void *pointer) +{ + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + if (!ValidateVertexFormatBase(context, index, size, type, true)) + { + return false; + } + + if (stride < 0) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), NegativeStride); + return false; + } + + const Caps &caps = context->getCaps(); + if (context->getClientVersion() >= ES_3_1) + { + if (stride > caps.maxVertexAttribStride) + { + context->handleError(InvalidValue() + << "stride cannot be greater than MAX_VERTEX_ATTRIB_STRIDE."); + return false; + } + + // [OpenGL ES 3.1] Section 10.3.1 page 245: + // glVertexAttribBinding is part of the equivalent code of VertexAttribIPointer, so its + // validation should be inherited. + if (index >= caps.maxVertexAttribBindings) + { + context->handleError(InvalidValue() + << "index must be smaller than MAX_VERTEX_ATTRIB_BINDINGS."); + return false; + } + } + + // [OpenGL ES 3.0.2] Section 2.8 page 24: + // An INVALID_OPERATION error is generated when a non-zero vertex array object + // is bound, zero is bound to the ARRAY_BUFFER buffer object binding point, + // and the pointer argument is not NULL. + if (context->getGLState().getVertexArrayId() != 0 && + context->getGLState().getTargetBuffer(BufferBinding::Array) == 0 && pointer != nullptr) + { + context + ->handleError(InvalidOperation() + << "Client data cannot be used with a non-default vertex array object."); + return false; + } + + if (context->getExtensions().webglCompatibility) + { + if (!ValidateWebGLVertexAttribPointer(context, type, false, stride, pointer, true)) + { + return false; + } + } + + return true; +} + +bool ValidateGetSynciv(Context *context, + GLsync sync, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLint *values) +{ + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + if (bufSize < 0) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), NegativeBufferSize); + return false; + } + + Sync *syncObject = context->getSync(sync); + if (!syncObject) + { + context->handleError(InvalidValue() << "Invalid sync object."); + return false; + } + + switch (pname) + { + case GL_OBJECT_TYPE: + case GL_SYNC_CONDITION: + case GL_SYNC_FLAGS: + case GL_SYNC_STATUS: + break; + + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidPname); + return false; + } + + return true; +} + +bool ValidateDrawElementsInstanced(ValidationContext *context, + GLenum mode, + GLsizei count, + GLenum type, + const void *indices, + GLsizei instanceCount) +{ + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + return ValidateDrawElementsInstancedCommon(context, mode, count, type, indices, instanceCount); +} + +bool ValidateFramebufferTextureMultiviewLayeredANGLE(Context *context, + GLenum target, + GLenum attachment, + GLuint texture, + GLint level, + GLint baseViewIndex, + GLsizei numViews) +{ + + if (!ValidateFramebufferTextureMultiviewBaseANGLE(context, target, attachment, texture, level, + numViews)) + { + return false; + } + + if (texture != 0) + { + if (baseViewIndex < 0) + { + context->handleError(InvalidValue() << "baseViewIndex cannot be less than 0."); + return false; + } + + Texture *tex = context->getTexture(texture); + ASSERT(tex); + + switch (tex->getTarget()) + { + case GL_TEXTURE_2D_ARRAY: + { + const Caps &caps = context->getCaps(); + if (static_cast(baseViewIndex + numViews) > caps.maxArrayTextureLayers) + { + context->handleError(InvalidValue() << "baseViewIndex+numViews cannot be " + "greater than " + "GL_MAX_ARRAY_TEXTURE_LAYERS."); + return false; + } + } + break; + default: + context->handleError(InvalidOperation() + << "Texture's target must be GL_TEXTURE_2D_ARRAY."); + return false; + } + + if (!ValidateFramebufferTextureMultiviewLevelAndFormat(context, tex, level)) + { + return false; + } + } + + return true; +} + +bool ValidateFramebufferTextureMultiviewSideBySideANGLE(Context *context, + GLenum target, + GLenum attachment, + GLuint texture, + GLint level, + GLsizei numViews, + const GLint *viewportOffsets) +{ + if (!ValidateFramebufferTextureMultiviewBaseANGLE(context, target, attachment, texture, level, + numViews)) + { + return false; + } + + if (texture != 0) + { + const GLsizei numViewportOffsetValues = numViews * 2; + for (GLsizei i = 0; i < numViewportOffsetValues; ++i) + { + if (viewportOffsets[i] < 0) + { + context->handleError(InvalidValue() + << "viewportOffsets cannot contain negative values."); + return false; + } + } + + Texture *tex = context->getTexture(texture); + ASSERT(tex); + + switch (tex->getTarget()) + { + case GL_TEXTURE_2D: + break; + default: + context->handleError(InvalidOperation() + << "Texture's target must be GL_TEXTURE_2D."); + return false; + } + + if (!ValidateFramebufferTextureMultiviewLevelAndFormat(context, tex, level)) + { + return false; + } + } + + return true; +} + +bool ValidateUniform1ui(Context *context, GLint location, GLuint v0) +{ + return ValidateUniformES3(context, GL_UNSIGNED_INT, location, 1); +} + +bool ValidateUniform2ui(Context *context, GLint location, GLuint v0, GLuint v1) +{ + return ValidateUniformES3(context, GL_UNSIGNED_INT_VEC2, location, 1); +} + +bool ValidateUniform3ui(Context *context, GLint location, GLuint v0, GLuint v1, GLuint v2) +{ + return ValidateUniformES3(context, GL_UNSIGNED_INT_VEC3, location, 1); +} + +bool ValidateUniform4ui(Context *context, + GLint location, + GLuint v0, + GLuint v1, + GLuint v2, + GLuint v3) +{ + return ValidateUniformES3(context, GL_UNSIGNED_INT_VEC4, location, 1); +} + +bool ValidateUniform1uiv(Context *context, GLint location, GLsizei count, const GLuint *value) +{ + return ValidateUniformES3(context, GL_UNSIGNED_INT, location, count); +} + +bool ValidateUniform2uiv(Context *context, GLint location, GLsizei count, const GLuint *value) +{ + return ValidateUniformES3(context, GL_UNSIGNED_INT_VEC2, location, count); +} + +bool ValidateUniform3uiv(Context *context, GLint location, GLsizei count, const GLuint *value) +{ + return ValidateUniformES3(context, GL_UNSIGNED_INT_VEC3, location, count); +} + +bool ValidateUniform4uiv(Context *context, GLint location, GLsizei count, const GLuint *value) +{ + return ValidateUniformES3(context, GL_UNSIGNED_INT_VEC4, location, count); +} + +bool ValidateIsQuery(Context *context, GLuint id) +{ + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + return true; +} + +bool ValidateUniformMatrix2x3fv(Context *context, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + return ValidateUniformMatrixES3(context, GL_FLOAT_MAT2x3, location, count, transpose); +} + +bool ValidateUniformMatrix3x2fv(Context *context, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + return ValidateUniformMatrixES3(context, GL_FLOAT_MAT3x2, location, count, transpose); +} + +bool ValidateUniformMatrix2x4fv(Context *context, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + return ValidateUniformMatrixES3(context, GL_FLOAT_MAT2x4, location, count, transpose); +} + +bool ValidateUniformMatrix4x2fv(Context *context, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + return ValidateUniformMatrixES3(context, GL_FLOAT_MAT4x2, location, count, transpose); +} + +bool ValidateUniformMatrix3x4fv(Context *context, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + return ValidateUniformMatrixES3(context, GL_FLOAT_MAT3x4, location, count, transpose); +} + +bool ValidateUniformMatrix4x3fv(Context *context, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + return ValidateUniformMatrixES3(context, GL_FLOAT_MAT4x3, location, count, transpose); +} + +bool ValidateEndTransformFeedback(Context *context) +{ + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + TransformFeedback *transformFeedback = context->getGLState().getCurrentTransformFeedback(); + ASSERT(transformFeedback != nullptr); + + if (!transformFeedback->isActive()) + { + context->handleError(InvalidOperation()); + return false; + } + + return true; +} + +bool ValidateTransformFeedbackVaryings(Context *context, + GLuint program, + GLsizei count, + const GLchar *const *varyings, + GLenum bufferMode) +{ + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + if (count < 0) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), NegativeCount); + return false; + } + + switch (bufferMode) + { + case GL_INTERLEAVED_ATTRIBS: + break; + case GL_SEPARATE_ATTRIBS: + { + const Caps &caps = context->getCaps(); + if (static_cast(count) > caps.maxTransformFeedbackSeparateAttributes) + { + context->handleError(InvalidValue()); + return false; + } + break; + } + default: + context->handleError(InvalidEnum()); + return false; + } + + Program *programObject = GetValidProgram(context, program); + if (!programObject) + { + return false; + } + + return true; +} + +bool ValidateGetTransformFeedbackVarying(Context *context, + GLuint program, + GLuint index, + GLsizei bufSize, + GLsizei *length, + GLsizei *size, + GLenum *type, + GLchar *name) +{ + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + if (bufSize < 0) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), NegativeBufferSize); + return false; + } + + Program *programObject = GetValidProgram(context, program); + if (!programObject) + { + return false; + } + + if (index >= static_cast(programObject->getTransformFeedbackVaryingCount())) + { + context->handleError(InvalidValue()); + return false; + } + + return true; +} + +bool ValidateBindTransformFeedback(Context *context, GLenum target, GLuint id) +{ + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + switch (target) + { + case GL_TRANSFORM_FEEDBACK: + { + // Cannot bind a transform feedback object if the current one is started and not + // paused (3.0.2 pg 85 section 2.14.1) + TransformFeedback *curTransformFeedback = + context->getGLState().getCurrentTransformFeedback(); + if (curTransformFeedback && curTransformFeedback->isActive() && + !curTransformFeedback->isPaused()) + { + context->handleError(InvalidOperation()); + return false; + } + + // Cannot bind a transform feedback object that does not exist (3.0.2 pg 85 section + // 2.14.1) + if (!context->isTransformFeedbackGenerated(id)) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), TransformFeedbackDoesNotExist); + return false; + } + } + break; + + default: + context->handleError(InvalidEnum()); + return false; + } + + return true; +} + +bool ValidateIsTransformFeedback(Context *context, GLuint id) +{ + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + return true; +} + +bool ValidatePauseTransformFeedback(Context *context) +{ + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + TransformFeedback *transformFeedback = context->getGLState().getCurrentTransformFeedback(); + ASSERT(transformFeedback != nullptr); + + // Current transform feedback must be active and not paused in order to pause (3.0.2 pg 86) + if (!transformFeedback->isActive() || transformFeedback->isPaused()) + { + context->handleError(InvalidOperation()); + return false; + } + + return true; +} + +bool ValidateResumeTransformFeedback(Context *context) +{ + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + TransformFeedback *transformFeedback = context->getGLState().getCurrentTransformFeedback(); + ASSERT(transformFeedback != nullptr); + + // Current transform feedback must be active and paused in order to resume (3.0.2 pg 86) + if (!transformFeedback->isActive() || !transformFeedback->isPaused()) + { + context->handleError(InvalidOperation()); + return false; + } + + return true; +} + +bool ValidateVertexAttribI4i(Context *context, GLuint index, GLint x, GLint y, GLint z, GLint w) +{ + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + return ValidateVertexAttribIndex(context, index); +} + +bool ValidateVertexAttribI4ui(Context *context, + GLuint index, + GLuint x, + GLuint y, + GLuint z, + GLuint w) +{ + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + return ValidateVertexAttribIndex(context, index); +} + +bool ValidateVertexAttribI4iv(Context *context, GLuint index, const GLint *v) +{ + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + return ValidateVertexAttribIndex(context, index); +} + +bool ValidateVertexAttribI4uiv(Context *context, GLuint index, const GLuint *v) +{ + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + return ValidateVertexAttribIndex(context, index); +} + +bool ValidateGetFragDataLocation(Context *context, GLuint program, const GLchar *name) +{ + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + Program *programObject = GetValidProgram(context, program); + if (!programObject) + { + return false; + } + + if (!programObject->isLinked()) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ProgramNotLinked); + return false; + } + + return true; +} + +bool ValidateGetUniformIndices(Context *context, + GLuint program, + GLsizei uniformCount, + const GLchar *const *uniformNames, + GLuint *uniformIndices) +{ + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + if (uniformCount < 0) + { + context->handleError(InvalidValue()); + return false; + } + + Program *programObject = GetValidProgram(context, program); + if (!programObject) + { + return false; + } + + return true; +} + +bool ValidateGetActiveUniformsiv(Context *context, + GLuint program, + GLsizei uniformCount, + const GLuint *uniformIndices, + GLenum pname, + GLint *params) +{ + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + if (uniformCount < 0) + { + context->handleError(InvalidValue()); + return false; + } + + Program *programObject = GetValidProgram(context, program); + if (!programObject) + { + return false; + } + + switch (pname) + { + case GL_UNIFORM_TYPE: + case GL_UNIFORM_SIZE: + case GL_UNIFORM_NAME_LENGTH: + case GL_UNIFORM_BLOCK_INDEX: + case GL_UNIFORM_OFFSET: + case GL_UNIFORM_ARRAY_STRIDE: + case GL_UNIFORM_MATRIX_STRIDE: + case GL_UNIFORM_IS_ROW_MAJOR: + break; + + default: + context->handleError(InvalidEnum()); + return false; + } + + if (uniformCount > programObject->getActiveUniformCount()) + { + context->handleError(InvalidValue()); + return false; + } + + for (int uniformId = 0; uniformId < uniformCount; uniformId++) + { + const GLuint index = uniformIndices[uniformId]; + + if (index >= static_cast(programObject->getActiveUniformCount())) + { + context->handleError(InvalidValue()); + return false; + } + } + + return true; +} + +bool ValidateGetUniformBlockIndex(Context *context, GLuint program, const GLchar *uniformBlockName) +{ + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + Program *programObject = GetValidProgram(context, program); + if (!programObject) + { + return false; + } + + return true; +} + +bool ValidateGetActiveUniformBlockiv(Context *context, + GLuint program, + GLuint uniformBlockIndex, + GLenum pname, + GLint *params) +{ + return ValidateGetActiveUniformBlockivBase(context, program, uniformBlockIndex, pname, nullptr); +} + +bool ValidateGetActiveUniformBlockName(Context *context, + GLuint program, + GLuint uniformBlockIndex, + GLsizei bufSize, + GLsizei *length, + GLchar *uniformBlockName) +{ + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + Program *programObject = GetValidProgram(context, program); + if (!programObject) + { + return false; + } + + if (uniformBlockIndex >= programObject->getActiveUniformBlockCount()) + { + context->handleError(InvalidValue()); + return false; + } + + return true; +} + +bool ValidateUniformBlockBinding(Context *context, + GLuint program, + GLuint uniformBlockIndex, + GLuint uniformBlockBinding) +{ + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + if (uniformBlockBinding >= context->getCaps().maxUniformBufferBindings) + { + context->handleError(InvalidValue()); + return false; + } + + Program *programObject = GetValidProgram(context, program); + if (!programObject) + { + return false; + } + + // if never linked, there won't be any uniform blocks + if (uniformBlockIndex >= programObject->getActiveUniformBlockCount()) + { + context->handleError(InvalidValue()); + return false; + } + + return true; +} + +bool ValidateDrawArraysInstanced(Context *context, + GLenum mode, + GLint first, + GLsizei count, + GLsizei primcount) +{ + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + return ValidateDrawArraysInstancedBase(context, mode, first, count, primcount); +} + +bool ValidateFenceSync(Context *context, GLenum condition, GLbitfield flags) +{ + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + if (condition != GL_SYNC_GPU_COMMANDS_COMPLETE) + { + context->handleError(InvalidEnum()); + return false; + } + + if (flags != 0) + { + context->handleError(InvalidValue()); + return false; + } + + return true; +} + +bool ValidateIsSync(Context *context, GLsync sync) +{ + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + return true; +} + +bool ValidateDeleteSync(Context *context, GLsync sync) +{ + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + if (sync != static_cast(0) && !context->getSync(sync)) + { + context->handleError(InvalidValue()); + return false; + } + + return true; +} + +bool ValidateClientWaitSync(Context *context, GLsync sync, GLbitfield flags, GLuint64 timeout) +{ + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + if ((flags & ~(GL_SYNC_FLUSH_COMMANDS_BIT)) != 0) + { + context->handleError(InvalidValue()); + return false; + } + + Sync *clientWaitSync = context->getSync(sync); + if (!clientWaitSync) + { + context->handleError(InvalidValue()); + return false; + } + + return true; +} + +bool ValidateWaitSync(Context *context, GLsync sync, GLbitfield flags, GLuint64 timeout) +{ + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + if (flags != 0) + { + context->handleError(InvalidValue()); + return false; + } + + if (timeout != GL_TIMEOUT_IGNORED) + { + context->handleError(InvalidValue()); + return false; + } + + Sync *waitSync = context->getSync(sync); + if (!waitSync) + { + context->handleError(InvalidValue()); + return false; + } + + return true; +} + +bool ValidateGetInteger64v(Context *context, GLenum pname, GLint64 *params) +{ + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + GLenum nativeType = GL_NONE; + unsigned int numParams = 0; + if (!ValidateStateQuery(context, pname, &nativeType, &numParams)) + { + return false; + } + + return true; +} + +bool ValidateIsSampler(Context *context, GLuint sampler) +{ + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + return true; +} + +bool ValidateBindSampler(Context *context, GLuint unit, GLuint sampler) +{ + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + if (sampler != 0 && !context->isSampler(sampler)) + { + context->handleError(InvalidOperation()); + return false; + } + + if (unit >= context->getCaps().maxCombinedTextureImageUnits) + { + context->handleError(InvalidValue()); + return false; + } + + return true; +} + +bool ValidateVertexAttribDivisor(Context *context, GLuint index, GLuint divisor) +{ + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + return ValidateVertexAttribIndex(context, index); +} + +bool ValidateTexStorage2D(Context *context, + GLenum target, + GLsizei levels, + GLenum internalformat, + GLsizei width, + GLsizei height) +{ + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + if (!ValidateES3TexStorage2DParameters(context, target, levels, internalformat, width, height, + 1)) + { + return false; + } + + return true; +} + +bool ValidateTexStorage3D(Context *context, + GLenum target, + GLsizei levels, + GLenum internalformat, + GLsizei width, + GLsizei height, + GLsizei depth) +{ + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + if (!ValidateES3TexStorage3DParameters(context, target, levels, internalformat, width, height, + depth)) + { + return false; + } + + return true; +} + +bool ValidateGetBufferParameteri64v(ValidationContext *context, + BufferBinding target, + GLenum pname, + GLint64 *params) +{ + return ValidateGetBufferParameterBase(context, target, pname, false, nullptr); +} + +bool ValidateGetSamplerParameterfv(Context *context, GLuint sampler, GLenum pname, GLfloat *params) +{ + return ValidateGetSamplerParameterBase(context, sampler, pname, nullptr); +} + +bool ValidateGetSamplerParameteriv(Context *context, GLuint sampler, GLenum pname, GLint *params) +{ + return ValidateGetSamplerParameterBase(context, sampler, pname, nullptr); +} + +bool ValidateSamplerParameterf(Context *context, GLuint sampler, GLenum pname, GLfloat param) +{ + return ValidateSamplerParameterBase(context, sampler, pname, -1, ¶m); +} + +bool ValidateSamplerParameterfv(Context *context, + GLuint sampler, + GLenum pname, + const GLfloat *params) +{ + return ValidateSamplerParameterBase(context, sampler, pname, -1, params); +} + +bool ValidateSamplerParameteri(Context *context, GLuint sampler, GLenum pname, GLint param) +{ + return ValidateSamplerParameterBase(context, sampler, pname, -1, ¶m); +} + +bool ValidateSamplerParameteriv(Context *context, GLuint sampler, GLenum pname, const GLint *params) +{ + return ValidateSamplerParameterBase(context, sampler, pname, -1, params); +} + +bool ValidateGetVertexAttribIiv(Context *context, GLuint index, GLenum pname, GLint *params) +{ + return ValidateGetVertexAttribBase(context, index, pname, nullptr, false, true); +} + +bool ValidateGetVertexAttribIuiv(Context *context, GLuint index, GLenum pname, GLuint *params) +{ + return ValidateGetVertexAttribBase(context, index, pname, nullptr, false, true); +} + +bool ValidateGetInternalformativ(Context *context, + GLenum target, + GLenum internalformat, + GLenum pname, + GLsizei bufSize, + GLint *params) +{ + return ValidateGetInternalFormativBase(context, target, internalformat, pname, bufSize, + nullptr); +} + } // namespace gl diff --git a/src/3rdparty/angle/src/libANGLE/validationES3.h b/src/3rdparty/angle/src/libANGLE/validationES3.h index 7bc657790a..631b1ca43a 100644 --- a/src/3rdparty/angle/src/libANGLE/validationES3.h +++ b/src/3rdparty/angle/src/libANGLE/validationES3.h @@ -9,11 +9,14 @@ #ifndef LIBANGLE_VALIDATION_ES3_H_ #define LIBANGLE_VALIDATION_ES3_H_ +#include "libANGLE/PackedGLEnums.h" + #include namespace gl { class Context; +struct IndexRange; class ValidationContext; bool ValidateES3TexImageParametersBase(ValidationContext *context, @@ -31,7 +34,8 @@ bool ValidateES3TexImageParametersBase(ValidationContext *context, GLint border, GLenum format, GLenum type, - const GLvoid *pixels); + GLsizei imageSize, + const void *pixels); bool ValidateES3TexStorageParameters(Context *context, GLenum target, @@ -56,7 +60,8 @@ bool ValidateES3TexImage2DParameters(Context *context, GLint border, GLenum format, GLenum type, - const GLvoid *pixels); + GLsizei imageSize, + const void *pixels); bool ValidateES3TexImage3DParameters(Context *context, GLenum target, @@ -73,7 +78,8 @@ bool ValidateES3TexImage3DParameters(Context *context, GLint border, GLenum format, GLenum type, - const GLvoid *pixels); + GLsizei bufSize, + const void *pixels); bool ValidateES3CopyTexImageParametersBase(ValidationContext *context, GLenum target, @@ -141,10 +147,6 @@ bool ValidateES3TexStorage3DParameters(Context *context, GLsizei height, GLsizei depth); -bool ValidateGenQueries(Context *context, GLsizei n, const GLuint *ids); - -bool ValidateDeleteQueries(Context *context, GLsizei n, const GLuint *ids); - bool ValidateBeginQuery(Context *context, GLenum target, GLuint id); bool ValidateEndQuery(Context *context, GLenum target); @@ -153,20 +155,38 @@ bool ValidateGetQueryiv(Context *context, GLenum target, GLenum pname, GLint *pa bool ValidateGetQueryObjectuiv(Context *context, GLuint id, GLenum pname, GLuint *params); -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 ValidateFramebufferTextureLayer(Context *context, + GLenum target, + GLenum attachment, + GLuint texture, + GLint level, + GLint layer); -bool ValidateInvalidateFramebuffer(Context *context, GLenum target, GLsizei numAttachments, +bool ValidateInvalidateFramebuffer(Context *context, + GLenum target, + GLsizei numAttachments, const GLenum *attachments); +bool ValidateInvalidateSubFramebuffer(Context *context, + GLenum target, + GLsizei numAttachments, + const GLenum *attachments, + GLint x, + GLint y, + GLsizei width, + GLsizei height); + bool ValidateClearBuffer(ValidationContext *context); -bool ValidateGetUniformuiv(Context *context, GLuint program, GLint location, GLuint* params); +bool ValidateDrawRangeElements(Context *context, + GLenum mode, + GLuint start, + GLuint end, + GLsizei count, + GLenum type, + const void *indices); + +bool ValidateGetUniformuiv(Context *context, GLuint program, GLint location, GLuint *params); bool ValidateReadBuffer(Context *context, GLenum mode); @@ -179,12 +199,29 @@ bool ValidateCompressedTexImage3D(Context *context, GLsizei depth, GLint border, GLsizei imageSize, - const GLvoid *data); + const void *data); +bool ValidateCompressedTexImage3DRobustANGLE(Context *context, + GLenum target, + GLint level, + GLenum internalformat, + GLsizei width, + GLsizei height, + GLsizei depth, + GLint border, + GLsizei imageSize, + GLsizei dataSize, + const void *data); bool ValidateBindVertexArray(Context *context, GLuint array); -bool ValidateDeleteVertexArrays(Context *context, GLsizei n); -bool ValidateGenVertexArrays(Context *context, GLsizei n); -bool ValidateIsVertexArray(Context *context); +bool ValidateIsVertexArray(Context *context, GLuint array); + +bool ValidateBindBufferBase(Context *context, BufferBinding target, GLuint index, GLuint buffer); +bool ValidateBindBufferRange(Context *context, + BufferBinding target, + GLuint index, + GLuint buffer, + GLintptr offset, + GLsizeiptr size); bool ValidateProgramBinary(Context *context, GLuint program, @@ -197,7 +234,7 @@ bool ValidateGetProgramBinary(Context *context, GLsizei *length, GLenum *binaryFormat, void *binary); -bool ValidateProgramParameter(Context *context, GLuint program, GLenum pname, GLint value); +bool ValidateProgramParameteri(Context *context, GLuint program, GLenum pname, GLint value); bool ValidateBlitFramebuffer(Context *context, GLint srcX0, GLint srcY0, @@ -237,7 +274,341 @@ bool ValidateCopyTexSubImage3D(Context *context, GLint y, GLsizei width, GLsizei height); +bool ValidateTexImage3D(Context *context, + GLenum target, + GLint level, + GLint internalformat, + GLsizei width, + GLsizei height, + GLsizei depth, + GLint border, + GLenum format, + GLenum type, + const void *pixels); +bool ValidateTexImage3DRobustANGLE(Context *context, + GLenum target, + GLint level, + GLint internalformat, + GLsizei width, + GLsizei height, + GLsizei depth, + GLint border, + GLenum format, + GLenum type, + GLsizei bufSize, + const void *pixels); +bool ValidateTexSubImage3D(Context *context, + GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLint zoffset, + GLsizei width, + GLsizei height, + GLsizei depth, + GLenum format, + GLenum type, + const void *pixels); +bool ValidateTexSubImage3DRobustANGLE(Context *context, + GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLint zoffset, + GLsizei width, + GLsizei height, + GLsizei depth, + GLenum format, + GLenum type, + GLsizei bufSize, + const void *pixels); +bool ValidateCompressedTexSubImage3D(Context *context, + GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLint zoffset, + GLsizei width, + GLsizei height, + GLsizei depth, + GLenum format, + GLsizei imageSize, + const void *data); +bool ValidateCompressedTexSubImage3DRobustANGLE(Context *context, + GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLint zoffset, + GLsizei width, + GLsizei height, + GLsizei depth, + GLenum format, + GLsizei imageSize, + GLsizei dataSize, + const void *data); + +bool ValidateGenQueries(Context *context, GLint n, GLuint *ids); +bool ValidateDeleteQueries(Context *context, GLint n, const GLuint *ids); +bool ValidateGenSamplers(Context *context, GLint count, GLuint *samplers); +bool ValidateDeleteSamplers(Context *context, GLint count, const GLuint *samplers); +bool ValidateGenTransformFeedbacks(Context *context, GLint n, GLuint *ids); +bool ValidateDeleteTransformFeedbacks(Context *context, GLint n, const GLuint *ids); +bool ValidateGenVertexArrays(Context *context, GLint n, GLuint *arrays); +bool ValidateDeleteVertexArrays(Context *context, GLint n, const GLuint *arrays); + +bool ValidateBeginTransformFeedback(Context *context, GLenum primitiveMode); + +bool ValidateGetBufferPointerv(Context *context, BufferBinding target, GLenum pname, void **params); +bool ValidateGetBufferPointervRobustANGLE(Context *context, + BufferBinding target, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + void **params); +bool ValidateUnmapBuffer(Context *context, BufferBinding target); +bool ValidateMapBufferRange(Context *context, + BufferBinding target, + GLintptr offset, + GLsizeiptr length, + GLbitfield access); +bool ValidateFlushMappedBufferRange(Context *context, + BufferBinding target, + GLintptr offset, + GLsizeiptr length); + +bool ValidateIndexedStateQuery(ValidationContext *context, + GLenum pname, + GLuint index, + GLsizei *length); +bool ValidateGetIntegeri_v(ValidationContext *context, GLenum target, GLuint index, GLint *data); +bool ValidateGetIntegeri_vRobustANGLE(ValidationContext *context, + GLenum target, + GLuint index, + GLsizei bufSize, + GLsizei *length, + GLint *data); +bool ValidateGetInteger64i_v(ValidationContext *context, + GLenum target, + GLuint index, + GLint64 *data); +bool ValidateGetInteger64i_vRobustANGLE(ValidationContext *context, + GLenum target, + GLuint index, + GLsizei bufSize, + GLsizei *length, + GLint64 *data); + +bool ValidateCopyBufferSubData(ValidationContext *context, + BufferBinding readTarget, + BufferBinding writeTarget, + GLintptr readOffset, + GLintptr writeOffset, + GLsizeiptr size); + +bool ValidateGetStringi(Context *context, GLenum name, GLuint index); +bool ValidateRenderbufferStorageMultisample(ValidationContext *context, + GLenum target, + GLsizei samples, + GLenum internalformat, + GLsizei width, + GLsizei height); + +bool ValidateVertexAttribIPointer(ValidationContext *context, + GLuint index, + GLint size, + GLenum type, + GLsizei stride, + const void *pointer); + +bool ValidateGetSynciv(Context *context, + GLsync sync, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLint *values); + +bool ValidateDrawElementsInstanced(ValidationContext *context, + GLenum mode, + GLsizei count, + GLenum type, + const void *indices, + GLsizei instanceCount); + +bool ValidateFramebufferTextureMultiviewLayeredANGLE(Context *context, + GLenum target, + GLenum attachment, + GLuint texture, + GLint level, + GLint baseViewIndex, + GLsizei numViews); + +bool ValidateFramebufferTextureMultiviewSideBySideANGLE(Context *context, + GLenum target, + GLenum attachment, + GLuint texture, + GLint level, + GLsizei numViews, + const GLint *viewportOffsets); + +bool ValidateIsQuery(Context *context, GLuint id); + +bool ValidateUniform1ui(Context *context, GLint location, GLuint v0); +bool ValidateUniform2ui(Context *context, GLint location, GLuint v0, GLuint v1); +bool ValidateUniform3ui(Context *context, GLint location, GLuint v0, GLuint v1, GLuint v2); +bool ValidateUniform4ui(Context *context, + GLint location, + GLuint v0, + GLuint v1, + GLuint v2, + GLuint v3); + +bool ValidateUniform1uiv(Context *context, GLint location, GLsizei count, const GLuint *value); +bool ValidateUniform2uiv(Context *context, GLint location, GLsizei count, const GLuint *value); +bool ValidateUniform3uiv(Context *context, GLint location, GLsizei count, const GLuint *value); +bool ValidateUniform4uiv(Context *context, GLint location, GLsizei count, const GLuint *value); + +bool ValidateUniformMatrix2x3fv(Context *context, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value); +bool ValidateUniformMatrix3x2fv(Context *context, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value); +bool ValidateUniformMatrix2x4fv(Context *context, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value); +bool ValidateUniformMatrix4x2fv(Context *context, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value); +bool ValidateUniformMatrix3x4fv(Context *context, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value); +bool ValidateUniformMatrix4x3fv(Context *context, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value); + +bool ValidateEndTransformFeedback(Context *context); +bool ValidateTransformFeedbackVaryings(Context *context, + GLuint program, + GLsizei count, + const GLchar *const *varyings, + GLenum bufferMode); +bool ValidateGetTransformFeedbackVarying(Context *context, + GLuint program, + GLuint index, + GLsizei bufSize, + GLsizei *length, + GLsizei *size, + GLenum *type, + GLchar *name); +bool ValidateBindTransformFeedback(Context *context, GLenum target, GLuint id); +bool ValidateIsTransformFeedback(Context *context, GLuint id); +bool ValidatePauseTransformFeedback(Context *context); +bool ValidateResumeTransformFeedback(Context *context); +bool ValidateVertexAttribI4i(Context *context, GLuint index, GLint x, GLint y, GLint z, GLint w); +bool ValidateVertexAttribI4ui(Context *context, + GLuint index, + GLuint x, + GLuint y, + GLuint z, + GLuint w); +bool ValidateVertexAttribI4iv(Context *context, GLuint index, const GLint *v); +bool ValidateVertexAttribI4uiv(Context *context, GLuint index, const GLuint *v); +bool ValidateGetFragDataLocation(Context *context, GLuint program, const GLchar *name); +bool ValidateGetUniformIndices(Context *context, + GLuint program, + GLsizei uniformCount, + const GLchar *const *uniformNames, + GLuint *uniformIndices); +bool ValidateGetActiveUniformsiv(Context *context, + GLuint program, + GLsizei uniformCount, + const GLuint *uniformIndices, + GLenum pname, + GLint *params); +bool ValidateGetUniformBlockIndex(Context *context, GLuint program, const GLchar *uniformBlockName); +bool ValidateGetActiveUniformBlockiv(Context *context, + GLuint program, + GLuint uniformBlockIndex, + GLenum pname, + GLint *params); +bool ValidateGetActiveUniformBlockName(Context *context, + GLuint program, + GLuint uniformBlockIndex, + GLsizei bufSize, + GLsizei *length, + GLchar *uniformBlockName); +bool ValidateUniformBlockBinding(Context *context, + GLuint program, + GLuint uniformBlockIndex, + GLuint uniformBlockBinding); +bool ValidateDrawArraysInstanced(Context *context, + GLenum mode, + GLint first, + GLsizei count, + GLsizei primcount); + +bool ValidateFenceSync(Context *context, GLenum condition, GLbitfield flags); +bool ValidateIsSync(Context *context, GLsync sync); +bool ValidateDeleteSync(Context *context, GLsync sync); +bool ValidateClientWaitSync(Context *context, GLsync sync, GLbitfield flags, GLuint64 timeout); +bool ValidateWaitSync(Context *context, GLsync sync, GLbitfield flags, GLuint64 timeout); +bool ValidateGetInteger64v(Context *context, GLenum pname, GLint64 *params); + +bool ValidateIsSampler(Context *context, GLuint sampler); +bool ValidateBindSampler(Context *context, GLuint unit, GLuint sampler); +bool ValidateVertexAttribDivisor(Context *context, GLuint index, GLuint divisor); +bool ValidateTexStorage2D(Context *context, + GLenum target, + GLsizei levels, + GLenum internalformat, + GLsizei width, + GLsizei height); +bool ValidateTexStorage3D(Context *context, + GLenum target, + GLsizei levels, + GLenum internalformat, + GLsizei width, + GLsizei height, + GLsizei depth); + +bool ValidateGetVertexAttribIiv(Context *context, GLuint index, GLenum pname, GLint *params); +bool ValidateGetVertexAttribIuiv(Context *context, GLuint index, GLenum pname, GLuint *params); +bool ValidateGetBufferParameteri64v(ValidationContext *context, + BufferBinding target, + GLenum pname, + GLint64 *params); +bool ValidateSamplerParameteri(Context *context, GLuint sampler, GLenum pname, GLint param); +bool ValidateSamplerParameteriv(Context *context, + GLuint sampler, + GLenum pname, + const GLint *params); +bool ValidateSamplerParameterf(Context *context, GLuint sampler, GLenum pname, GLfloat param); +bool ValidateSamplerParameterfv(Context *context, + GLuint sampler, + GLenum pname, + const GLfloat *params); +bool ValidateGetSamplerParameteriv(Context *context, GLuint sampler, GLenum pname, GLint *params); +bool ValidateGetSamplerParameterfv(Context *context, GLuint sampler, GLenum pname, GLfloat *params); +bool ValidateGetInternalformativ(Context *context, + GLenum target, + GLenum internalformat, + GLenum pname, + GLsizei bufSize, + GLint *params); } // namespace gl -#endif // LIBANGLE_VALIDATION_ES3_H_ +#endif // LIBANGLE_VALIDATION_ES3_H_ diff --git a/src/3rdparty/angle/src/libANGLE/validationES31.cpp b/src/3rdparty/angle/src/libANGLE/validationES31.cpp new file mode 100644 index 0000000000..b1bdccacf7 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/validationES31.cpp @@ -0,0 +1,1786 @@ +// +// Copyright (c) 2016 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. +// + +// validationES31.cpp: Validation functions for OpenGL ES 3.1 entry point parameters + +#include "libANGLE/validationES31.h" + +#include "libANGLE/Context.h" +#include "libANGLE/ErrorStrings.h" +#include "libANGLE/Framebuffer.h" +#include "libANGLE/VertexArray.h" +#include "libANGLE/validationES.h" +#include "libANGLE/validationES2.h" +#include "libANGLE/validationES3.h" + +#include "common/utilities.h" + +using namespace angle; + +namespace gl +{ + +namespace +{ + +bool ValidateNamedProgramInterface(GLenum programInterface) +{ + switch (programInterface) + { + case GL_UNIFORM: + case GL_UNIFORM_BLOCK: + case GL_PROGRAM_INPUT: + case GL_PROGRAM_OUTPUT: + case GL_TRANSFORM_FEEDBACK_VARYING: + case GL_BUFFER_VARIABLE: + case GL_SHADER_STORAGE_BLOCK: + return true; + default: + return false; + } +} + +bool ValidateLocationProgramInterface(GLenum programInterface) +{ + switch (programInterface) + { + case GL_UNIFORM: + case GL_PROGRAM_INPUT: + case GL_PROGRAM_OUTPUT: + return true; + default: + return false; + } +} + +bool ValidateProgramInterface(GLenum programInterface) +{ + return (programInterface == GL_ATOMIC_COUNTER_BUFFER || + ValidateNamedProgramInterface(programInterface)); +} + +bool ValidateProgramResourceProperty(GLenum prop) +{ + switch (prop) + { + case GL_ACTIVE_VARIABLES: + case GL_BUFFER_BINDING: + case GL_NUM_ACTIVE_VARIABLES: + + case GL_ARRAY_SIZE: + + case GL_ARRAY_STRIDE: + case GL_BLOCK_INDEX: + case GL_IS_ROW_MAJOR: + case GL_MATRIX_STRIDE: + + case GL_ATOMIC_COUNTER_BUFFER_INDEX: + + case GL_BUFFER_DATA_SIZE: + + case GL_LOCATION: + + case GL_NAME_LENGTH: + + case GL_OFFSET: + + case GL_REFERENCED_BY_VERTEX_SHADER: + case GL_REFERENCED_BY_FRAGMENT_SHADER: + case GL_REFERENCED_BY_COMPUTE_SHADER: + + case GL_TOP_LEVEL_ARRAY_SIZE: + case GL_TOP_LEVEL_ARRAY_STRIDE: + + case GL_TYPE: + return true; + + default: + return false; + } +} + +// GLES 3.10 spec: Page 82 -- Table 7.2 +bool ValidateProgramResourcePropertyByInterface(GLenum prop, GLenum programInterface) +{ + switch (prop) + { + case GL_ACTIVE_VARIABLES: + case GL_BUFFER_BINDING: + case GL_NUM_ACTIVE_VARIABLES: + { + switch (programInterface) + { + case GL_ATOMIC_COUNTER_BUFFER: + case GL_SHADER_STORAGE_BLOCK: + case GL_UNIFORM_BLOCK: + return true; + default: + return false; + } + } + + case GL_ARRAY_SIZE: + { + switch (programInterface) + { + case GL_BUFFER_VARIABLE: + case GL_PROGRAM_INPUT: + case GL_PROGRAM_OUTPUT: + case GL_TRANSFORM_FEEDBACK_VARYING: + case GL_UNIFORM: + return true; + default: + return false; + } + } + + case GL_ARRAY_STRIDE: + case GL_BLOCK_INDEX: + case GL_IS_ROW_MAJOR: + case GL_MATRIX_STRIDE: + { + switch (programInterface) + { + case GL_BUFFER_VARIABLE: + case GL_UNIFORM: + return true; + default: + return false; + } + } + + case GL_ATOMIC_COUNTER_BUFFER_INDEX: + { + if (programInterface == GL_UNIFORM) + { + return true; + } + return false; + } + + case GL_BUFFER_DATA_SIZE: + { + switch (programInterface) + { + case GL_ATOMIC_COUNTER_BUFFER: + case GL_SHADER_STORAGE_BLOCK: + case GL_UNIFORM_BLOCK: + return true; + default: + return false; + } + } + + case GL_LOCATION: + { + return ValidateLocationProgramInterface(programInterface); + } + + case GL_NAME_LENGTH: + { + return ValidateNamedProgramInterface(programInterface); + } + + case GL_OFFSET: + { + switch (programInterface) + { + case GL_BUFFER_VARIABLE: + case GL_UNIFORM: + return true; + default: + return false; + } + } + + case GL_REFERENCED_BY_VERTEX_SHADER: + case GL_REFERENCED_BY_FRAGMENT_SHADER: + case GL_REFERENCED_BY_COMPUTE_SHADER: + { + switch (programInterface) + { + case GL_ATOMIC_COUNTER_BUFFER: + case GL_BUFFER_VARIABLE: + case GL_PROGRAM_INPUT: + case GL_PROGRAM_OUTPUT: + case GL_SHADER_STORAGE_BLOCK: + case GL_UNIFORM: + case GL_UNIFORM_BLOCK: + return true; + default: + return false; + } + } + + case GL_TOP_LEVEL_ARRAY_SIZE: + case GL_TOP_LEVEL_ARRAY_STRIDE: + { + if (programInterface == GL_BUFFER_VARIABLE) + { + return true; + } + return false; + } + + case GL_TYPE: + { + switch (programInterface) + { + case GL_BUFFER_VARIABLE: + case GL_PROGRAM_INPUT: + case GL_PROGRAM_OUTPUT: + case GL_TRANSFORM_FEEDBACK_VARYING: + case GL_UNIFORM: + return true; + default: + return false; + } + } + + default: + return false; + } +} + +bool ValidateProgramResourceIndex(const Program *programObject, + GLenum programInterface, + GLuint index) +{ + switch (programInterface) + { + case GL_PROGRAM_INPUT: + return (index < static_cast(programObject->getActiveAttributeCount())); + + case GL_PROGRAM_OUTPUT: + return (index < static_cast(programObject->getOutputResourceCount())); + + case GL_UNIFORM: + return (index < static_cast(programObject->getActiveUniformCount())); + + case GL_BUFFER_VARIABLE: + return (index < static_cast(programObject->getActiveBufferVariableCount())); + + case GL_SHADER_STORAGE_BLOCK: + return (index < static_cast(programObject->getActiveShaderStorageBlockCount())); + + case GL_UNIFORM_BLOCK: + return (index < programObject->getActiveUniformBlockCount()); + + case GL_ATOMIC_COUNTER_BUFFER: + return (index < programObject->getActiveAtomicCounterBufferCount()); + + // TODO(jie.a.chen@intel.com): more interfaces. + case GL_TRANSFORM_FEEDBACK_VARYING: + UNIMPLEMENTED(); + return false; + + default: + UNREACHABLE(); + return false; + } +} + +bool ValidateProgramUniform(gl::Context *context, + GLenum valueType, + GLuint program, + GLint location, + GLsizei count) +{ + // Check for ES31 program uniform entry points + if (context->getClientVersion() < Version(3, 1)) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES31Required); + return false; + } + + const LinkedUniform *uniform = nullptr; + gl::Program *programObject = GetValidProgram(context, program); + return ValidateUniformCommonBase(context, programObject, location, count, &uniform) && + ValidateUniformValue(context, valueType, uniform->type); +} + +bool ValidateProgramUniformMatrix(gl::Context *context, + GLenum valueType, + GLuint program, + GLint location, + GLsizei count, + GLboolean transpose) +{ + // Check for ES31 program uniform entry points + if (context->getClientVersion() < Version(3, 1)) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES31Required); + return false; + } + + const LinkedUniform *uniform = nullptr; + gl::Program *programObject = GetValidProgram(context, program); + return ValidateUniformCommonBase(context, programObject, location, count, &uniform) && + ValidateUniformMatrixValue(context, valueType, uniform->type); +} + +bool ValidateVertexAttribFormatCommon(ValidationContext *context, + GLuint attribIndex, + GLint size, + GLenum type, + GLuint relativeOffset, + GLboolean pureInteger) +{ + if (context->getClientVersion() < ES_3_1) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES31Required); + return false; + } + + const Caps &caps = context->getCaps(); + if (relativeOffset > static_cast(caps.maxVertexAttribRelativeOffset)) + { + context->handleError( + InvalidValue() + << "relativeOffset cannot be greater than MAX_VERTEX_ATTRIB_RELATIVE_OFFSET."); + return false; + } + + // [OpenGL ES 3.1] Section 10.3.1 page 243: + // An INVALID_OPERATION error is generated if the default vertex array object is bound. + if (context->getGLState().getVertexArrayId() == 0) + { + context->handleError(InvalidOperation() << "Default vertex array object is bound."); + return false; + } + + return ValidateVertexFormatBase(context, attribIndex, size, type, pureInteger); +} + +} // anonymous namespace + +bool ValidateGetBooleani_v(Context *context, GLenum target, GLuint index, GLboolean *data) +{ + if (context->getClientVersion() < ES_3_1) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES31Required); + return false; + } + + if (!ValidateIndexedStateQuery(context, target, index, nullptr)) + { + return false; + } + + return true; +} + +bool ValidateGetBooleani_vRobustANGLE(Context *context, + GLenum target, + GLuint index, + GLsizei bufSize, + GLsizei *length, + GLboolean *data) +{ + if (context->getClientVersion() < ES_3_1) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES31Required); + return false; + } + + if (!ValidateRobustEntryPoint(context, bufSize)) + { + return false; + } + + if (!ValidateIndexedStateQuery(context, target, index, length)) + { + return false; + } + + if (!ValidateRobustBufferSize(context, bufSize, *length)) + { + return false; + } + + return true; +} + +bool ValidateDrawIndirectBase(Context *context, GLenum mode, const void *indirect) +{ + if (context->getClientVersion() < ES_3_1) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES31Required); + return false; + } + + // Here the third parameter 1 is only to pass the count validation. + if (!ValidateDrawBase(context, mode, 1)) + { + return false; + } + + const State &state = context->getGLState(); + + // An INVALID_OPERATION error is generated if zero is bound to VERTEX_ARRAY_BINDING, + // DRAW_INDIRECT_BUFFER or to any enabled vertex array. + if (!state.getVertexArrayId()) + { + context->handleError(InvalidOperation() << "zero is bound to VERTEX_ARRAY_BINDING"); + return false; + } + + gl::Buffer *drawIndirectBuffer = state.getTargetBuffer(BufferBinding::DrawIndirect); + if (!drawIndirectBuffer) + { + context->handleError(InvalidOperation() << "zero is bound to DRAW_INDIRECT_BUFFER"); + return false; + } + + // An INVALID_VALUE error is generated if indirect is not a multiple of the size, in basic + // machine units, of uint. + GLint64 offset = reinterpret_cast(indirect); + if ((static_cast(offset) % sizeof(GLuint)) != 0) + { + context->handleError( + InvalidValue() + << "indirect is not a multiple of the size, in basic machine units, of uint"); + return false; + } + + // ANGLE_multiview spec, revision 1: + // An INVALID_OPERATION is generated by DrawArraysIndirect and DrawElementsIndirect if the + // number of views in the draw framebuffer is greater than 1. + const Framebuffer *drawFramebuffer = context->getGLState().getDrawFramebuffer(); + ASSERT(drawFramebuffer != nullptr); + if (drawFramebuffer->getNumViews() > 1) + { + context->handleError( + InvalidOperation() + << "The number of views in the active draw framebuffer is greater than 1."); + return false; + } + + return true; +} + +bool ValidateDrawArraysIndirect(Context *context, GLenum mode, const void *indirect) +{ + const State &state = context->getGLState(); + gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback(); + if (curTransformFeedback && curTransformFeedback->isActive() && + !curTransformFeedback->isPaused()) + { + // An INVALID_OPERATION error is generated if transform feedback is active and not paused. + context->handleError(InvalidOperation() << "transform feedback is active and not paused."); + return false; + } + + if (!ValidateDrawIndirectBase(context, mode, indirect)) + return false; + + gl::Buffer *drawIndirectBuffer = state.getTargetBuffer(BufferBinding::DrawIndirect); + CheckedNumeric checkedOffset(reinterpret_cast(indirect)); + // In OpenGL ES3.1 spec, session 10.5, it defines the struct of DrawArraysIndirectCommand + // which's size is 4 * sizeof(uint). + auto checkedSum = checkedOffset + 4 * sizeof(GLuint); + if (!checkedSum.IsValid() || + checkedSum.ValueOrDie() > static_cast(drawIndirectBuffer->getSize())) + { + context->handleError( + InvalidOperation() + << "the command would source data beyond the end of the buffer object."); + return false; + } + + return true; +} + +bool ValidateDrawElementsIndirect(Context *context, GLenum mode, GLenum type, const void *indirect) +{ + if (!ValidateDrawElementsBase(context, type)) + return false; + + const State &state = context->getGLState(); + const VertexArray *vao = state.getVertexArray(); + gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get(); + if (!elementArrayBuffer) + { + context->handleError(InvalidOperation() << "zero is bound to ELEMENT_ARRAY_BUFFER"); + return false; + } + + if (!ValidateDrawIndirectBase(context, mode, indirect)) + return false; + + gl::Buffer *drawIndirectBuffer = state.getTargetBuffer(BufferBinding::DrawIndirect); + CheckedNumeric checkedOffset(reinterpret_cast(indirect)); + // In OpenGL ES3.1 spec, session 10.5, it defines the struct of DrawElementsIndirectCommand + // which's size is 5 * sizeof(uint). + auto checkedSum = checkedOffset + 5 * sizeof(GLuint); + if (!checkedSum.IsValid() || + checkedSum.ValueOrDie() > static_cast(drawIndirectBuffer->getSize())) + { + context->handleError( + InvalidOperation() + << "the command would source data beyond the end of the buffer object."); + return false; + } + + return true; +} + +bool ValidateProgramUniform1i(Context *context, GLuint program, GLint location, GLint v0) +{ + return ValidateProgramUniform1iv(context, program, location, 1, &v0); +} + +bool ValidateProgramUniform2i(Context *context, GLuint program, GLint location, GLint v0, GLint v1) +{ + GLint xy[2] = {v0, v1}; + return ValidateProgramUniform2iv(context, program, location, 1, xy); +} + +bool ValidateProgramUniform3i(Context *context, + GLuint program, + GLint location, + GLint v0, + GLint v1, + GLint v2) +{ + GLint xyz[3] = {v0, v1, v2}; + return ValidateProgramUniform3iv(context, program, location, 1, xyz); +} + +bool ValidateProgramUniform4i(Context *context, + GLuint program, + GLint location, + GLint v0, + GLint v1, + GLint v2, + GLint v3) +{ + GLint xyzw[4] = {v0, v1, v2, v3}; + return ValidateProgramUniform4iv(context, program, location, 1, xyzw); +} + +bool ValidateProgramUniform1ui(Context *context, GLuint program, GLint location, GLuint v0) +{ + return ValidateProgramUniform1uiv(context, program, location, 1, &v0); +} + +bool ValidateProgramUniform2ui(Context *context, + GLuint program, + GLint location, + GLuint v0, + GLuint v1) +{ + GLuint xy[2] = {v0, v1}; + return ValidateProgramUniform2uiv(context, program, location, 1, xy); +} + +bool ValidateProgramUniform3ui(Context *context, + GLuint program, + GLint location, + GLuint v0, + GLuint v1, + GLuint v2) +{ + GLuint xyz[3] = {v0, v1, v2}; + return ValidateProgramUniform3uiv(context, program, location, 1, xyz); +} + +bool ValidateProgramUniform4ui(Context *context, + GLuint program, + GLint location, + GLuint v0, + GLuint v1, + GLuint v2, + GLuint v3) +{ + GLuint xyzw[4] = {v0, v1, v2, v3}; + return ValidateProgramUniform4uiv(context, program, location, 1, xyzw); +} + +bool ValidateProgramUniform1f(Context *context, GLuint program, GLint location, GLfloat v0) +{ + return ValidateProgramUniform1fv(context, program, location, 1, &v0); +} + +bool ValidateProgramUniform2f(Context *context, + GLuint program, + GLint location, + GLfloat v0, + GLfloat v1) +{ + GLfloat xy[2] = {v0, v1}; + return ValidateProgramUniform2fv(context, program, location, 1, xy); +} + +bool ValidateProgramUniform3f(Context *context, + GLuint program, + GLint location, + GLfloat v0, + GLfloat v1, + GLfloat v2) +{ + GLfloat xyz[3] = {v0, v1, v2}; + return ValidateProgramUniform3fv(context, program, location, 1, xyz); +} + +bool ValidateProgramUniform4f(Context *context, + GLuint program, + GLint location, + GLfloat v0, + GLfloat v1, + GLfloat v2, + GLfloat v3) +{ + GLfloat xyzw[4] = {v0, v1, v2, v3}; + return ValidateProgramUniform4fv(context, program, location, 1, xyzw); +} + +bool ValidateProgramUniform1iv(Context *context, + GLuint program, + GLint location, + GLsizei count, + const GLint *value) +{ + // Check for ES31 program uniform entry points + if (context->getClientVersion() < Version(3, 1)) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES31Required); + return false; + } + + const LinkedUniform *uniform = nullptr; + gl::Program *programObject = GetValidProgram(context, program); + return ValidateUniformCommonBase(context, programObject, location, count, &uniform) && + ValidateUniform1ivValue(context, uniform->type, count, value); +} + +bool ValidateProgramUniform2iv(Context *context, + GLuint program, + GLint location, + GLsizei count, + const GLint *value) +{ + return ValidateProgramUniform(context, GL_INT_VEC2, program, location, count); +} + +bool ValidateProgramUniform3iv(Context *context, + GLuint program, + GLint location, + GLsizei count, + const GLint *value) +{ + return ValidateProgramUniform(context, GL_INT_VEC3, program, location, count); +} + +bool ValidateProgramUniform4iv(Context *context, + GLuint program, + GLint location, + GLsizei count, + const GLint *value) +{ + return ValidateProgramUniform(context, GL_INT_VEC4, program, location, count); +} + +bool ValidateProgramUniform1uiv(Context *context, + GLuint program, + GLint location, + GLsizei count, + const GLuint *value) +{ + return ValidateProgramUniform(context, GL_UNSIGNED_INT, program, location, count); +} + +bool ValidateProgramUniform2uiv(Context *context, + GLuint program, + GLint location, + GLsizei count, + const GLuint *value) +{ + return ValidateProgramUniform(context, GL_UNSIGNED_INT_VEC2, program, location, count); +} + +bool ValidateProgramUniform3uiv(Context *context, + GLuint program, + GLint location, + GLsizei count, + const GLuint *value) +{ + return ValidateProgramUniform(context, GL_UNSIGNED_INT_VEC3, program, location, count); +} + +bool ValidateProgramUniform4uiv(Context *context, + GLuint program, + GLint location, + GLsizei count, + const GLuint *value) +{ + return ValidateProgramUniform(context, GL_UNSIGNED_INT_VEC4, program, location, count); +} + +bool ValidateProgramUniform1fv(Context *context, + GLuint program, + GLint location, + GLsizei count, + const GLfloat *value) +{ + return ValidateProgramUniform(context, GL_FLOAT, program, location, count); +} + +bool ValidateProgramUniform2fv(Context *context, + GLuint program, + GLint location, + GLsizei count, + const GLfloat *value) +{ + return ValidateProgramUniform(context, GL_FLOAT_VEC2, program, location, count); +} + +bool ValidateProgramUniform3fv(Context *context, + GLuint program, + GLint location, + GLsizei count, + const GLfloat *value) +{ + return ValidateProgramUniform(context, GL_FLOAT_VEC3, program, location, count); +} + +bool ValidateProgramUniform4fv(Context *context, + GLuint program, + GLint location, + GLsizei count, + const GLfloat *value) +{ + return ValidateProgramUniform(context, GL_FLOAT_VEC4, program, location, count); +} + +bool ValidateProgramUniformMatrix2fv(Context *context, + GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + return ValidateProgramUniformMatrix(context, GL_FLOAT_MAT2, program, location, count, + transpose); +} + +bool ValidateProgramUniformMatrix3fv(Context *context, + GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + return ValidateProgramUniformMatrix(context, GL_FLOAT_MAT3, program, location, count, + transpose); +} + +bool ValidateProgramUniformMatrix4fv(Context *context, + GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + return ValidateProgramUniformMatrix(context, GL_FLOAT_MAT4, program, location, count, + transpose); +} + +bool ValidateProgramUniformMatrix2x3fv(Context *context, + GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + return ValidateProgramUniformMatrix(context, GL_FLOAT_MAT2x3, program, location, count, + transpose); +} + +bool ValidateProgramUniformMatrix3x2fv(Context *context, + GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + return ValidateProgramUniformMatrix(context, GL_FLOAT_MAT3x2, program, location, count, + transpose); +} + +bool ValidateProgramUniformMatrix2x4fv(Context *context, + GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + return ValidateProgramUniformMatrix(context, GL_FLOAT_MAT2x4, program, location, count, + transpose); +} + +bool ValidateProgramUniformMatrix4x2fv(Context *context, + GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + return ValidateProgramUniformMatrix(context, GL_FLOAT_MAT4x2, program, location, count, + transpose); +} + +bool ValidateProgramUniformMatrix3x4fv(Context *context, + GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + return ValidateProgramUniformMatrix(context, GL_FLOAT_MAT3x4, program, location, count, + transpose); +} + +bool ValidateProgramUniformMatrix4x3fv(Context *context, + GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + return ValidateProgramUniformMatrix(context, GL_FLOAT_MAT4x3, program, location, count, + transpose); +} + +bool ValidateGetTexLevelParameterBase(Context *context, + GLenum target, + GLint level, + GLenum pname, + GLsizei *length) +{ + if (context->getClientVersion() < ES_3_1) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES31Required); + return false; + } + + if (length) + { + *length = 0; + } + + if (!ValidTexLevelDestinationTarget(context, target)) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidTextureTarget); + return false; + } + + if (context->getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target) == + nullptr) + { + context->handleError(InvalidEnum() << "No texture bound."); + return false; + } + + if (!ValidMipLevel(context, target, level)) + { + context->handleError(InvalidValue()); + return false; + } + + switch (pname) + { + case GL_TEXTURE_RED_TYPE: + case GL_TEXTURE_GREEN_TYPE: + case GL_TEXTURE_BLUE_TYPE: + case GL_TEXTURE_ALPHA_TYPE: + case GL_TEXTURE_DEPTH_TYPE: + break; + case GL_TEXTURE_RED_SIZE: + case GL_TEXTURE_GREEN_SIZE: + case GL_TEXTURE_BLUE_SIZE: + case GL_TEXTURE_ALPHA_SIZE: + case GL_TEXTURE_DEPTH_SIZE: + case GL_TEXTURE_STENCIL_SIZE: + case GL_TEXTURE_SHARED_SIZE: + break; + case GL_TEXTURE_INTERNAL_FORMAT: + case GL_TEXTURE_WIDTH: + case GL_TEXTURE_HEIGHT: + case GL_TEXTURE_DEPTH: + break; + case GL_TEXTURE_SAMPLES: + case GL_TEXTURE_FIXED_SAMPLE_LOCATIONS: + break; + case GL_TEXTURE_COMPRESSED: + break; + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidPname); + return false; + } + + if (length) + { + *length = 1; + } + return true; +} + +bool ValidateGetTexLevelParameterfv(Context *context, + GLenum target, + GLint level, + GLenum pname, + GLfloat *params) +{ + return ValidateGetTexLevelParameterBase(context, target, level, pname, nullptr); +} + +bool ValidateGetTexLevelParameteriv(Context *context, + GLenum target, + GLint level, + GLenum pname, + GLint *params) +{ + return ValidateGetTexLevelParameterBase(context, target, level, pname, nullptr); +} + +bool ValidateTexStorage2DMultisample(Context *context, + GLenum target, + GLsizei samples, + GLint internalFormat, + GLsizei width, + GLsizei height, + GLboolean fixedSampleLocations) +{ + if (context->getClientVersion() < ES_3_1) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES31Required); + return false; + } + + if (target != GL_TEXTURE_2D_MULTISAMPLE) + { + context->handleError(InvalidEnum() << "Target must be TEXTURE_2D_MULTISAMPLE."); + return false; + } + + if (width < 1 || height < 1) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), NegativeSize); + return false; + } + + const Caps &caps = context->getCaps(); + if (static_cast(width) > caps.max2DTextureSize || + static_cast(height) > caps.max2DTextureSize) + { + context + ->handleError(InvalidValue() + << "Width and height must be less than or equal to GL_MAX_TEXTURE_SIZE."); + return false; + } + + if (samples == 0) + { + context->handleError(InvalidValue() << "Samples may not be zero."); + return false; + } + + const TextureCaps &formatCaps = context->getTextureCaps().get(internalFormat); + if (!formatCaps.renderable) + { + context->handleError(InvalidEnum() << "SizedInternalformat must be color-renderable, " + "depth-renderable, or stencil-renderable."); + return false; + } + + // The ES3.1 spec(section 8.8) states that an INVALID_ENUM error is generated if internalformat + // is one of the unsized base internalformats listed in table 8.11. + const InternalFormat &formatInfo = GetSizedInternalFormatInfo(internalFormat); + if (formatInfo.internalFormat == GL_NONE) + { + context->handleError( + InvalidEnum() + << "Internalformat is one of the unsupported unsized base internalformats."); + return false; + } + + if (static_cast(samples) > formatCaps.getMaxSamples()) + { + context->handleError( + InvalidOperation() + << "Samples must not be greater than maximum supported value for the format."); + return false; + } + + Texture *texture = context->getTargetTexture(target); + if (!texture || texture->id() == 0) + { + context->handleError(InvalidOperation() << "Zero is bound to target."); + return false; + } + + if (texture->getImmutableFormat()) + { + context->handleError(InvalidOperation() << "The value of TEXTURE_IMMUTABLE_FORMAT for " + "the texture currently bound to target on " + "the active texture unit is true."); + return false; + } + + return true; +} + +bool ValidateGetMultisamplefv(Context *context, GLenum pname, GLuint index, GLfloat *val) +{ + if (context->getClientVersion() < ES_3_1) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES31Required); + return false; + } + + if (pname != GL_SAMPLE_POSITION) + { + context->handleError(InvalidEnum() << "Pname must be SAMPLE_POSITION."); + return false; + } + + Framebuffer *framebuffer = context->getGLState().getDrawFramebuffer(); + + if (index >= static_cast(framebuffer->getSamples(context))) + { + context->handleError(InvalidValue() << "Index must be less than the value of SAMPLES."); + return false; + } + + return true; +} + +bool ValidateFramebufferParameteri(Context *context, GLenum target, GLenum pname, GLint param) +{ + if (context->getClientVersion() < ES_3_1) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES31Required); + return false; + } + + if (!ValidFramebufferTarget(context, target)) + { + context->handleError(InvalidEnum() << "Invalid framebuffer target."); + return false; + } + + switch (pname) + { + case GL_FRAMEBUFFER_DEFAULT_WIDTH: + { + GLint maxWidth = context->getCaps().maxFramebufferWidth; + if (param < 0 || param > maxWidth) + { + context->handleError( + InvalidValue() + << "Params less than 0 or greater than GL_MAX_FRAMEBUFFER_WIDTH."); + return false; + } + break; + } + case GL_FRAMEBUFFER_DEFAULT_HEIGHT: + { + GLint maxHeight = context->getCaps().maxFramebufferHeight; + if (param < 0 || param > maxHeight) + { + context->handleError( + InvalidValue() + << "Params less than 0 or greater than GL_MAX_FRAMEBUFFER_HEIGHT."); + return false; + } + break; + } + case GL_FRAMEBUFFER_DEFAULT_SAMPLES: + { + GLint maxSamples = context->getCaps().maxFramebufferSamples; + if (param < 0 || param > maxSamples) + { + context->handleError( + InvalidValue() + << "Params less than 0 or greater than GL_MAX_FRAMEBUFFER_SAMPLES."); + return false; + } + break; + } + case GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS: + { + break; + } + default: + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidPname); + return false; + } + } + + const Framebuffer *framebuffer = context->getGLState().getTargetFramebuffer(target); + ASSERT(framebuffer); + if (framebuffer->id() == 0) + { + context->handleError(InvalidOperation() << "Default framebuffer is bound to target."); + return false; + } + return true; +} + +bool ValidateGetFramebufferParameteriv(Context *context, GLenum target, GLenum pname, GLint *params) +{ + if (context->getClientVersion() < ES_3_1) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES31Required); + return false; + } + + if (!ValidFramebufferTarget(context, target)) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidFramebufferTarget); + return false; + } + + switch (pname) + { + case GL_FRAMEBUFFER_DEFAULT_WIDTH: + case GL_FRAMEBUFFER_DEFAULT_HEIGHT: + case GL_FRAMEBUFFER_DEFAULT_SAMPLES: + case GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS: + break; + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidPname); + return false; + } + + const Framebuffer *framebuffer = context->getGLState().getTargetFramebuffer(target); + ASSERT(framebuffer); + + if (framebuffer->id() == 0) + { + context->handleError(InvalidOperation() << "Default framebuffer is bound to target."); + return false; + } + return true; +} + +bool ValidateGetProgramResourceIndex(Context *context, + GLuint program, + GLenum programInterface, + const GLchar *name) +{ + if (context->getClientVersion() < ES_3_1) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES31Required); + return false; + } + + Program *programObject = GetValidProgram(context, program); + if (programObject == nullptr) + { + return false; + } + + if (!ValidateNamedProgramInterface(programInterface)) + { + context->handleError(InvalidEnum() << "Invalid program interface: 0x" << std::hex + << std::uppercase << programInterface); + return false; + } + + return true; +} + +bool ValidateBindVertexBuffer(ValidationContext *context, + GLuint bindingIndex, + GLuint buffer, + GLintptr offset, + GLsizei stride) +{ + if (context->getClientVersion() < ES_3_1) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES31Required); + return false; + } + + if (!context->isBufferGenerated(buffer)) + { + context->handleError(InvalidOperation() << "Buffer is not generated."); + return false; + } + + const Caps &caps = context->getCaps(); + if (bindingIndex >= caps.maxVertexAttribBindings) + { + context->handleError(InvalidValue() + << "bindingindex must be smaller than MAX_VERTEX_ATTRIB_BINDINGS."); + return false; + } + + if (offset < 0) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), NegativeOffset); + return false; + } + + if (stride < 0 || stride > caps.maxVertexAttribStride) + { + context->handleError(InvalidValue() + << "stride must be between 0 and MAX_VERTEX_ATTRIB_STRIDE."); + return false; + } + + // [OpenGL ES 3.1] Section 10.3.1 page 244: + // An INVALID_OPERATION error is generated if the default vertex array object is bound. + if (context->getGLState().getVertexArrayId() == 0) + { + context->handleError(InvalidOperation() << "Default vertex array buffer is bound."); + return false; + } + + return true; +} + +bool ValidateVertexBindingDivisor(ValidationContext *context, GLuint bindingIndex, GLuint divisor) +{ + if (context->getClientVersion() < ES_3_1) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES31Required); + return false; + } + + const Caps &caps = context->getCaps(); + if (bindingIndex >= caps.maxVertexAttribBindings) + { + context->handleError(InvalidValue() + << "bindingindex must be smaller than MAX_VERTEX_ATTRIB_BINDINGS."); + return false; + } + + // [OpenGL ES 3.1] Section 10.3.1 page 243: + // An INVALID_OPERATION error is generated if the default vertex array object is bound. + if (context->getGLState().getVertexArrayId() == 0) + { + context->handleError(InvalidOperation() << "Default vertex array object is bound."); + return false; + } + + return true; +} + +bool ValidateVertexAttribFormat(ValidationContext *context, + GLuint attribindex, + GLint size, + GLenum type, + GLboolean normalized, + GLuint relativeoffset) +{ + return ValidateVertexAttribFormatCommon(context, attribindex, size, type, relativeoffset, + false); +} + +bool ValidateVertexAttribIFormat(ValidationContext *context, + GLuint attribindex, + GLint size, + GLenum type, + GLuint relativeoffset) +{ + return ValidateVertexAttribFormatCommon(context, attribindex, size, type, relativeoffset, true); +} + +bool ValidateVertexAttribBinding(ValidationContext *context, + GLuint attribIndex, + GLuint bindingIndex) +{ + if (context->getClientVersion() < ES_3_1) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES31Required); + return false; + } + + // [OpenGL ES 3.1] Section 10.3.1 page 243: + // An INVALID_OPERATION error is generated if the default vertex array object is bound. + if (context->getGLState().getVertexArrayId() == 0) + { + context->handleError(InvalidOperation() << "Default vertex array object is bound."); + return false; + } + + const Caps &caps = context->getCaps(); + if (attribIndex >= caps.maxVertexAttributes) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), IndexExceedsMaxVertexAttribute); + return false; + } + + if (bindingIndex >= caps.maxVertexAttribBindings) + { + context->handleError(InvalidValue() + << "bindingindex must be smaller than MAX_VERTEX_ATTRIB_BINDINGS"); + return false; + } + + return true; +} + +bool ValidateGetProgramResourceName(Context *context, + GLuint program, + GLenum programInterface, + GLuint index, + GLsizei bufSize, + GLsizei *length, + GLchar *name) +{ + if (context->getClientVersion() < ES_3_1) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES31Required); + return false; + } + + Program *programObject = GetValidProgram(context, program); + if (programObject == nullptr) + { + return false; + } + + if (!ValidateNamedProgramInterface(programInterface)) + { + context->handleError(InvalidEnum() << "Invalid program interface: 0x" << std::hex + << std::uppercase << programInterface); + return false; + } + + if (!ValidateProgramResourceIndex(programObject, programInterface, index)) + { + context->handleError(InvalidValue() << "Invalid index: " << index); + return false; + } + + if (bufSize < 0) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), NegativeBufferSize); + return false; + } + + return true; +} + +bool ValidateDispatchCompute(Context *context, + GLuint numGroupsX, + GLuint numGroupsY, + GLuint numGroupsZ) +{ + if (context->getClientVersion() < ES_3_1) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES31Required); + return false; + } + + const State &state = context->getGLState(); + Program *program = state.getProgram(); + + if (program == nullptr) + { + context->handleError(InvalidOperation() + << "No active program object for the compute shader stage."); + return false; + } + + if (!program->isLinked() || !program->hasLinkedComputeShader()) + { + context->handleError( + InvalidOperation() + << "Program has not been successfully linked, or program contains no compute shaders."); + return false; + } + + const Caps &caps = context->getCaps(); + if (numGroupsX > caps.maxComputeWorkGroupCount[0]) + { + context->handleError( + InvalidValue() << "num_groups_x cannot be greater than MAX_COMPUTE_WORK_GROUP_COUNT[0]=" + << caps.maxComputeWorkGroupCount[0]); + return false; + } + if (numGroupsY > caps.maxComputeWorkGroupCount[1]) + { + context->handleError( + InvalidValue() << "num_groups_y cannot be greater than MAX_COMPUTE_WORK_GROUP_COUNT[1]=" + << caps.maxComputeWorkGroupCount[1]); + return false; + } + if (numGroupsZ > caps.maxComputeWorkGroupCount[2]) + { + context->handleError( + InvalidValue() << "num_groups_z cannot be greater than MAX_COMPUTE_WORK_GROUP_COUNT[2]=" + << caps.maxComputeWorkGroupCount[2]); + return false; + } + + return true; +} + +bool ValidateDispatchComputeIndirect(Context *context, GLintptr indirect) +{ + UNIMPLEMENTED(); + return false; +} + +bool ValidateBindImageTexture(Context *context, + GLuint unit, + GLuint texture, + GLint level, + GLboolean layered, + GLint layer, + GLenum access, + GLenum format) +{ + GLuint maxImageUnits = context->getCaps().maxImageUnits; + if (unit >= maxImageUnits) + { + context->handleError(InvalidValue() + << "unit cannot be greater than or equal than MAX_IMAGE_UNITS = " + << maxImageUnits); + return false; + } + + if (level < 0) + { + context->handleError(InvalidValue() << "level is negative."); + return false; + } + + if (layer < 0) + { + context->handleError(InvalidValue() << "layer is negative."); + return false; + } + + if (access != GL_READ_ONLY && access != GL_WRITE_ONLY && access != GL_READ_WRITE) + { + context->handleError(InvalidEnum() << "access is not one of the supported tokens."); + return false; + } + + switch (format) + { + case GL_RGBA32F: + case GL_RGBA16F: + case GL_R32F: + case GL_RGBA32UI: + case GL_RGBA16UI: + case GL_RGBA8UI: + case GL_R32UI: + case GL_RGBA32I: + case GL_RGBA16I: + case GL_RGBA8I: + case GL_R32I: + case GL_RGBA8: + case GL_RGBA8_SNORM: + break; + default: + context->handleError(InvalidValue() + << "format is not one of supported image unit formats."); + return false; + } + + if (texture != 0) + { + Texture *tex = context->getTexture(texture); + + if (tex == nullptr) + { + context->handleError(InvalidValue() + << "texture is not the name of an existing texture object."); + return false; + } + + if (!tex->getImmutableFormat()) + { + context->handleError(InvalidOperation() + << "texture is not the name of an immutable texture object."); + return false; + } + } + + return true; +} + +bool ValidateGetProgramResourceLocation(Context *context, + GLuint program, + GLenum programInterface, + const GLchar *name) +{ + if (context->getClientVersion() < ES_3_1) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES31Required); + return false; + } + + Program *programObject = GetValidProgram(context, program); + if (programObject == nullptr) + { + return false; + } + + if (!programObject->isLinked()) + { + context->handleError(InvalidOperation() << "Program is not successfully linked."); + return false; + } + + if (!ValidateLocationProgramInterface(programInterface)) + { + context->handleError(InvalidEnum() << "Invalid program interface."); + return false; + } + return true; +} + +bool ValidateGetProgramResourceiv(Context *context, + GLuint program, + GLenum programInterface, + GLuint index, + GLsizei propCount, + const GLenum *props, + GLsizei bufSize, + GLsizei *length, + GLint *params) +{ + if (context->getClientVersion() < ES_3_1) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES31Required); + return false; + } + + Program *programObject = GetValidProgram(context, program); + if (programObject == nullptr) + { + return false; + } + if (!ValidateProgramInterface(programInterface)) + { + context->handleError(InvalidEnum() << "Invalid program interface."); + return false; + } + if (propCount <= 0) + { + context->handleError(InvalidValue() << "Invalid propCount."); + return false; + } + if (bufSize < 0) + { + context->handleError(InvalidValue() << "Invalid bufSize."); + return false; + } + if (!ValidateProgramResourceIndex(programObject, programInterface, index)) + { + context->handleError(InvalidValue() << "Invalid index: " << index); + return false; + } + for (GLsizei i = 0; i < propCount; i++) + { + if (!ValidateProgramResourceProperty(props[i])) + { + context->handleError(InvalidEnum() << "Invalid prop."); + return false; + } + if (!ValidateProgramResourcePropertyByInterface(props[i], programInterface)) + { + context->handleError(InvalidOperation() << "Not an allowed prop for interface"); + return false; + } + } + return true; +} + +bool ValidateGetProgramInterfaceiv(Context *context, + GLuint program, + GLenum programInterface, + GLenum pname, + GLint *params) +{ + if (context->getClientVersion() < ES_3_1) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES31Required); + return false; + } + + Program *programObject = GetValidProgram(context, program); + if (programObject == nullptr) + { + return false; + } + + if (!ValidateProgramInterface(programInterface)) + { + context->handleError(InvalidEnum() << "Invalid program interface."); + return false; + } + + switch (pname) + { + case GL_ACTIVE_RESOURCES: + case GL_MAX_NAME_LENGTH: + case GL_MAX_NUM_ACTIVE_VARIABLES: + break; + + default: + context->handleError(InvalidEnum() << "Unknown property of program interface."); + return false; + } + + if (pname == GL_MAX_NAME_LENGTH && programInterface == GL_ATOMIC_COUNTER_BUFFER) + { + context->handleError(InvalidOperation() + << "Active atomic counter resources are not assigned name strings."); + return false; + } + + if (pname == GL_MAX_NUM_ACTIVE_VARIABLES) + { + switch (programInterface) + { + case GL_ATOMIC_COUNTER_BUFFER: + case GL_SHADER_STORAGE_BLOCK: + case GL_UNIFORM_BLOCK: + break; + + default: + context->handleError( + InvalidOperation() + << "MAX_NUM_ACTIVE_VARIABLES requires a buffer or block interface."); + return false; + } + } + + return true; +} + +static bool ValidateGenOrDeleteES31(Context *context, GLint n) +{ + if (context->getClientVersion() < ES_3_1) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES31Required); + return false; + } + + return ValidateGenOrDelete(context, n); +} + +bool ValidateGenProgramPipelines(Context *context, GLint n, GLuint *) +{ + return ValidateGenOrDeleteES31(context, n); +} + +bool ValidateDeleteProgramPipelines(Context *context, GLint n, const GLuint *) +{ + return ValidateGenOrDeleteES31(context, n); +} + +bool ValidateBindProgramPipeline(Context *context, GLuint pipeline) +{ + if (context->getClientVersion() < ES_3_1) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES31Required); + return false; + } + + if (!context->isProgramPipelineGenerated(pipeline)) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ObjectNotGenerated); + return false; + } + + return true; +} + +bool ValidateIsProgramPipeline(Context *context, GLuint pipeline) +{ + if (context->getClientVersion() < ES_3_1) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES31Required); + return false; + } + + return true; +} + +bool ValidateUseProgramStages(Context *context, GLuint pipeline, GLbitfield stages, GLuint program) +{ + UNIMPLEMENTED(); + return false; +} + +bool ValidateActiveShaderProgram(Context *context, GLuint pipeline, GLuint program) +{ + UNIMPLEMENTED(); + return false; +} + +bool ValidateCreateShaderProgramv(Context *context, + GLenum type, + GLsizei count, + const GLchar *const *strings) +{ + UNIMPLEMENTED(); + return false; +} + +bool ValidateGetProgramPipelineiv(Context *context, GLuint pipeline, GLenum pname, GLint *params) +{ + UNIMPLEMENTED(); + return false; +} + +bool ValidateValidateProgramPipeline(Context *context, GLuint pipeline) +{ + UNIMPLEMENTED(); + return false; +} + +bool ValidateGetProgramPipelineInfoLog(Context *context, + GLuint pipeline, + GLsizei bufSize, + GLsizei *length, + GLchar *infoLog) +{ + UNIMPLEMENTED(); + return false; +} + +bool ValidateMemoryBarrier(Context *context, GLbitfield barriers) +{ + UNIMPLEMENTED(); + return false; +} + +bool ValidateMemoryBarrierByRegion(Context *context, GLbitfield barriers) +{ + UNIMPLEMENTED(); + return false; +} + +bool ValidateSampleMaski(Context *context, GLuint maskNumber, GLbitfield mask) +{ + if (context->getClientVersion() < ES_3_1) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES31Required); + return false; + } + + if (maskNumber >= context->getCaps().maxSampleMaskWords) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), InvalidSampleMaskNumber); + return false; + } + + return true; +} + +} // namespace gl diff --git a/src/3rdparty/angle/src/libANGLE/validationES31.h b/src/3rdparty/angle/src/libANGLE/validationES31.h new file mode 100644 index 0000000000..a0b76a5bcb --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/validationES31.h @@ -0,0 +1,325 @@ +// +// Copyright (c) 2016 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. +// + +// validationES31.h: Validation functions for OpenGL ES 3.1 entry point parameters + +#ifndef LIBANGLE_VALIDATION_ES31_H_ +#define LIBANGLE_VALIDATION_ES31_H_ + +#include + +namespace gl +{ +class Context; +class ValidationContext; + +bool ValidateGetBooleani_v(Context *context, GLenum target, GLuint index, GLboolean *data); +bool ValidateGetBooleani_vRobustANGLE(Context *context, + GLenum target, + GLuint index, + GLsizei bufSize, + GLsizei *length, + GLboolean *data); + +bool ValidateGetTexLevelParameterfv(Context *context, + GLenum target, + GLint level, + GLenum pname, + GLfloat *params); +bool ValidateGetTexLevelParameteriv(Context *context, + GLenum target, + GLint level, + GLenum pname, + GLint *param); + +bool ValidateTexStorage2DMultisample(Context *context, + GLenum target, + GLsizei samples, + GLint internalFormat, + GLsizei width, + GLsizei height, + GLboolean fixedSampleLocations); +bool ValidateGetMultisamplefv(Context *context, GLenum pname, GLuint index, GLfloat *val); + +bool ValidateDrawIndirectBase(Context *context, GLenum mode, const void *indirect); +bool ValidateDrawArraysIndirect(Context *context, GLenum mode, const void *indirect); +bool ValidateDrawElementsIndirect(Context *context, GLenum mode, GLenum type, const void *indirect); + +bool ValidateProgramUniform1i(Context *context, GLuint program, GLint location, GLint v0); +bool ValidateProgramUniform2i(Context *context, GLuint program, GLint location, GLint v0, GLint v1); +bool ValidateProgramUniform3i(Context *context, + GLuint program, + GLint location, + GLint v0, + GLint v1, + GLint v2); +bool ValidateProgramUniform4i(Context *context, + GLuint program, + GLint location, + GLint v0, + GLint v1, + GLint v2, + GLint v3); +bool ValidateProgramUniform1ui(Context *context, GLuint program, GLint location, GLuint v0); +bool ValidateProgramUniform2ui(Context *context, + GLuint program, + GLint location, + GLuint v0, + GLuint v1); +bool ValidateProgramUniform3ui(Context *context, + GLuint program, + GLint location, + GLuint v0, + GLuint v1, + GLuint v2); +bool ValidateProgramUniform4ui(Context *context, + GLuint program, + GLint location, + GLuint v0, + GLuint v1, + GLuint v2, + GLuint v3); +bool ValidateProgramUniform1f(Context *context, GLuint program, GLint location, GLfloat v0); +bool ValidateProgramUniform2f(Context *context, + GLuint program, + GLint location, + GLfloat v0, + GLfloat v1); +bool ValidateProgramUniform3f(Context *context, + GLuint program, + GLint location, + GLfloat v0, + GLfloat v1, + GLfloat v2); +bool ValidateProgramUniform4f(Context *context, + GLuint program, + GLint location, + GLfloat v0, + GLfloat v1, + GLfloat v2, + GLfloat v3); + +bool ValidateProgramUniform1iv(Context *context, + GLuint program, + GLint location, + GLsizei count, + const GLint *value); +bool ValidateProgramUniform2iv(Context *context, + GLuint program, + GLint location, + GLsizei count, + const GLint *value); +bool ValidateProgramUniform3iv(Context *context, + GLuint program, + GLint location, + GLsizei count, + const GLint *value); +bool ValidateProgramUniform4iv(Context *context, + GLuint program, + GLint location, + GLsizei count, + const GLint *value); +bool ValidateProgramUniform1uiv(Context *context, + GLuint program, + GLint location, + GLsizei count, + const GLuint *value); +bool ValidateProgramUniform2uiv(Context *context, + GLuint program, + GLint location, + GLsizei count, + const GLuint *value); +bool ValidateProgramUniform3uiv(Context *context, + GLuint program, + GLint location, + GLsizei count, + const GLuint *value); +bool ValidateProgramUniform4uiv(Context *context, + GLuint program, + GLint location, + GLsizei count, + const GLuint *value); +bool ValidateProgramUniform1fv(Context *context, + GLuint program, + GLint location, + GLsizei count, + const GLfloat *value); +bool ValidateProgramUniform2fv(Context *context, + GLuint program, + GLint location, + GLsizei count, + const GLfloat *value); +bool ValidateProgramUniform3fv(Context *context, + GLuint program, + GLint location, + GLsizei count, + const GLfloat *value); +bool ValidateProgramUniform4fv(Context *context, + GLuint program, + GLint location, + GLsizei count, + const GLfloat *value); +bool ValidateProgramUniformMatrix2fv(Context *context, + GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value); +bool ValidateProgramUniformMatrix2fv(Context *context, + GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value); +bool ValidateProgramUniformMatrix3fv(Context *context, + GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value); +bool ValidateProgramUniformMatrix4fv(Context *context, + GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value); +bool ValidateProgramUniformMatrix2x3fv(Context *context, + GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value); +bool ValidateProgramUniformMatrix3x2fv(Context *context, + GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value); +bool ValidateProgramUniformMatrix2x4fv(Context *context, + GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value); +bool ValidateProgramUniformMatrix4x2fv(Context *context, + GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value); +bool ValidateProgramUniformMatrix3x4fv(Context *context, + GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value); +bool ValidateProgramUniformMatrix4x3fv(Context *context, + GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value); + +bool ValidateFramebufferParameteri(Context *context, GLenum target, GLenum pname, GLint param); +bool ValidateGetFramebufferParameteriv(Context *context, + GLenum target, + GLenum pname, + GLint *params); + +bool ValidateGetProgramResourceIndex(Context *context, + GLuint program, + GLenum programInterface, + const GLchar *name); +bool ValidateGetProgramResourceName(Context *context, + GLuint program, + GLenum programInterface, + GLuint index, + GLsizei bufSize, + GLsizei *length, + GLchar *name); +bool ValidateGetProgramResourceLocation(Context *context, + GLuint program, + GLenum programInterface, + const GLchar *name); + +bool ValidateGetProgramResourceiv(Context *context, + GLuint program, + GLenum programInterface, + GLuint index, + GLsizei propCount, + const GLenum *props, + GLsizei bufSize, + GLsizei *length, + GLint *params); + +bool ValidateGetProgramInterfaceiv(Context *context, + GLuint program, + GLenum programInterface, + GLenum pname, + GLint *params); + +bool ValidateBindVertexBuffer(ValidationContext *context, + GLuint bindingIndex, + GLuint buffer, + GLintptr offset, + GLsizei stride); +bool ValidateVertexAttribFormat(ValidationContext *context, + GLuint attribindex, + GLint size, + GLenum type, + GLboolean normalized, + GLuint relativeoffset); +bool ValidateVertexAttribIFormat(ValidationContext *context, + GLuint attribindex, + GLint size, + GLenum type, + GLuint relativeoffset); +bool ValidateVertexAttribBinding(ValidationContext *context, + GLuint attribIndex, + GLuint bindingIndex); +bool ValidateVertexBindingDivisor(ValidationContext *context, GLuint bindingIndex, GLuint divisor); + +bool ValidateDispatchCompute(Context *context, + GLuint numGroupsX, + GLuint numGroupsY, + GLuint numGroupsZ); +bool ValidateDispatchComputeIndirect(Context *context, GLintptr indirect); + +bool ValidateBindImageTexture(Context *context, + GLuint unit, + GLuint texture, + GLint level, + GLboolean layered, + GLint layer, + GLenum access, + GLenum format); + +bool ValidateGenProgramPipelines(Context *context, GLint n, GLuint *pipelines); +bool ValidateDeleteProgramPipelines(Context *context, GLint n, const GLuint *pipelines); +bool ValidateBindProgramPipeline(Context *context, GLuint pipeline); +bool ValidateIsProgramPipeline(Context *context, GLuint pipeline); +bool ValidateUseProgramStages(Context *context, GLuint pipeline, GLbitfield stages, GLuint program); +bool ValidateActiveShaderProgram(Context *context, GLuint pipeline, GLuint program); +bool ValidateCreateShaderProgramv(Context *context, + GLenum type, + GLsizei count, + const GLchar *const *strings); +bool ValidateGetProgramPipelineiv(Context *context, GLuint pipeline, GLenum pname, GLint *params); +bool ValidateValidateProgramPipeline(Context *context, GLuint pipeline); +bool ValidateGetProgramPipelineInfoLog(Context *context, + GLuint pipeline, + GLsizei bufSize, + GLsizei *length, + GLchar *infoLog); + +bool ValidateMemoryBarrier(Context *context, GLbitfield barriers); +bool ValidateMemoryBarrierByRegion(Context *context, GLbitfield barriers); + +bool ValidateSampleMaski(Context *context, GLuint maskNumber, GLbitfield mask); + +} // namespace gl + +#endif // LIBANGLE_VALIDATION_ES31_H_ -- cgit v1.2.3